class Property include Mongoid::Document include Mongoid::Timestamps include OrbitTag::Taggable include OrbitCategory::Categorizable include Slug FIELDSNAME=["hiring_person_email","hiring_person_number","hiring_person_name","reason_for_hire","note_for_hire","organization" ,"person_in_charge" ,"tel_of_person_in_charge" ,"department" ,"contact_person" ,"tel_of_contact_person" , "mobile_phone_of_contact_person" ,"contact_person_Email" ,"contact_person_department"] field :need_change_tmp_reason, type: Boolean, default: false field :need_hire_before, type: Integer, default: 0 #0代表沒有限制 field :need_hire_before_unit, type: String, default: "day" #month, day, hour, minute field :custom_calendar_type, type: Integer, default: 0 #0=>預設, 1=> 顯示, 2=> 不顯示 field :custom_carousel_image_width, type: String, default: "" field :display_img, :type => Boolean, :default => false field :image_display_class, type: String, default: "full-size-img" #3 choices: full-size-img , pull-left , pull-right field :order_position, type: Integer, default: -1 field :title, as: :slug_title, :localize => true field :property_usage, :localize => true field :note, :localize => true field :property_number field :can_be_hired, type: Boolean, default: true field :purchase_date, type: DateTime field :owners, type: Array, :default => [] field :other_owner field :owner_email field :owner_phone field :price field :other_location field :p_hire_start_time, type: DateTime field :p_hire_end_time, type: DateTime field :p_open_start_time, type: DateTime field :p_open_end_time, type: DateTime field :recurring_enable, type: Boolean, :default => false mount_uploader :image, ImageUploader # unavailibility fields field :can_hire_before_months, type: Integer, default: 0 field :set_availability, type: Boolean, default: false field :set_unavailibility, type: Boolean, default: false field :start_time field :end_time field :weekdays, type: Array, default: [] field :special_unavailable_dates, type: Array, default: [] field :special_unavailable_dates_title, type: Array, default: [] field :start_date, type: DateTime field :end_date, type: DateTime field :description, :localize => true field :unavailibility_note, :localize => true field :hiring_person_email, type: Hash, default: {"enable"=>"1","required"=>"true"} field :hiring_person_number, type: Hash, default: {"enable"=>"1","required"=>"true"} field :hiring_person_name, type: Hash, default: {"enable"=>"1","required"=>"true"} field :reason_for_hire, type: Hash, default: {"enable"=>"1","required"=>"true"} field :note_for_hire, type: Hash, default: {"enable"=>"1","required"=>"false"} field :organization, type: Hash, default: {"enable"=>"1","required"=>"false"} field :person_in_charge, type: Hash, default: {"enable"=>"1","required"=>"false"} field :tel_of_person_in_charge, type: Hash, default: {"enable"=>"1","required"=>"false"} field :department, type: Hash, default: {"enable"=>"1","required"=>"false"} field :contact_person, type: Hash, default: {"enable"=>"1","required"=>"false"} field :tel_of_contact_person, type: Hash, default: {"enable"=>"1","required"=>"false"} field :mobile_phone_of_contact_person, type: Hash, default: {"enable"=>"1","required"=>"false"} field :contact_person_Email, type: Hash, default: {"enable"=>"1","required"=>"false"} field :contact_person_department, type: Hash, default: {"enable"=>"1","required"=>"false"} field :enable_notes_selector , type: Boolean, default: false field :notes_selector ,type: Hash, default: {} field :enable_fields_sort , type: Boolean, default: false field :custom_field_names, type: Array field :default_field_names, type: Array field :copy_id field :except_clone_relations, :type=>Array, :default => [] belongs_to :property_location has_many :p_hires has_many :hire_email_sets, :autosave => true, :dependent => :destroy, :inverse_of => :property accepts_nested_attributes_for :hire_email_sets, :allow_destroy => true has_many :p_hire_fields, :autosave => true, :dependent => :destroy accepts_nested_attributes_for :p_hire_fields, :allow_destroy => true has_many :property_field_sets, :autosave => true, :dependent => :destroy accepts_nested_attributes_for :property_field_sets, :allow_destroy => true has_many :property_day_settings, :autosave => true, :dependent => :destroy accepts_nested_attributes_for :property_day_settings, :allow_destroy => true has_many :property_carousel_images, :autosave => true, :dependent => :destroy accepts_nested_attributes_for :property_carousel_images, :allow_destroy => true has_many :property_files, :autosave => true, :dependent => :destroy accepts_nested_attributes_for :property_files, :allow_destroy => true has_many :property_links, :autosave => true, :dependent => :destroy accepts_nested_attributes_for :property_links, :allow_destroy => true scope :sort_order, ->{order_by([:created_at,:desc],[:order_position,:asc])} scope :can_display, ->{any_of({:p_hire_start_time.lt=>Time.now, :p_hire_end_time.gt=>Time.now},{:p_hire_start_time.lt=>Time.now, :p_hire_end_time=>nil},{:p_hire_start_time=>nil, :p_hire_end_time=>nil})} WEEKDAYS = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ] CAlENDARTYPE = ["default","display","not_display"] after_initialize do unless self.new_record? save_flag = false @no_validate = true if self.default_field_names.nil? self.default_field_names = self.get_all_fields(true) save_flag = true end if self.custom_field_names.nil? self.custom_field_names = self.get_all_fields(true) save_flag = true end if save_flag self.save end end end before_create do max_position = self.class.max(:order_position) max_position = -1 if max_position.nil? self.order_position = max_position + 1 @no_validate = true if self.copy_id.present? self.clone_new(true) self.created_at = DateTime.now self.updated_at = DateTime.now else self.default_field_names = self.get_all_fields(true) self.custom_field_names = self.get_all_fields(true) end end before_save do unless @no_validate || self.new_record? self.custom_field_names = [] if self.custom_field_names.nil? self.default_field_names = self.get_all_fields(true) self.class::FIELDSNAME.each do |f| if((self.send(f)["enable"] == "1" rescue true) && !(self.custom_field_names.include?(f))) self.custom_field_names << f end end end end after_save do self.change_day_setting_status end def can_reserve start_time = self.p_hire_start_time || Time.now end_time = self.p_hire_end_time || Time.now return Time.now >= start_time && end_time >= Time.now end def p_hire_fields_enabled self.p_hire_fields.where(disabled: false) end def all_day_settings self.property_day_settings.asc(:key).group_by(&:day) end def change_day_setting_status if self.property_day_settings.count != 0 if self.set_unavailibility && self.weekdays.count != 0 self.property_day_settings.where(:day.nin=>self.weekdays).update_all(:enable=>true) tmp_start_time = self.start_time.blank? ? "00:00" : self.start_time tmp_end_time = self.end_time.blank? ? "24:00" : self.end_time self.property_day_settings.where(:day.in=>self.weekdays).each do |setting| if setting.end_time < tmp_start_time || setting.start_time > tmp_end_time setting.enable = true else setting.enable = false end setting.save end else self.property_day_settings.update_all(:enable=>true) end end end def calendar_type (self.custom_calendar_type == 0 ? (PropertyHireSetting.first.calendar_type rescue 0) : (self.custom_calendar_type - 1)) end def self.init_class_variables setting = PropertyHireSetting.first if setting @@disable_content_page = setting.disable_content_page rescue false @@disable_view_calendar_page = setting.disable_view_calendar_page rescue false @@disable_no_logins_view_calendar = setting.disable_no_logins_view_calendar rescue false else @@disable_content_page = false @@disable_view_calendar_page = false @@disable_no_logins_view_calendar = false end end init_class_variables def disable_content_page @@disable_content_page end def disable_view_calendar_page @@disable_view_calendar_page end def disable_no_logins_view_calendar @@disable_no_logins_view_calendar end def custom_text(field_name,type="name",locale=nil) locale = locale || I18n.locale default_text = I18n.with_locale(locale){I18n.t("property_hire.#{field_name}")} if (self.send(field_name)[type][locale.to_s].present? rescue false) self.send(field_name)[type][locale.to_s] else default_text end end def render_unavailable_message message = "" property = self weekdays_options = self.class::WEEKDAYS weekdays_options = weekdays_options.map do |weekday| trans = I18n.t("property_hire.#{weekday}", :default=>'') if trans != "" trans else weekday end end if property.set_unavailibility if property.weekdays.length > 0 translation_missing = (I18n.t('property_hire.unavailable_hint1', {:default => ''}) == "") str1 = (!property.start_date.nil? ? (I18n.t("property_hire.from",:default=>" from ") + property.start_date.strftime("%Y-%m-%d")) : "") str2 = (!property.end_date.nil? ? (I18n.t("property_hire.to",:default=>" to ") + property.end_date.strftime("%Y-%m-%d")) : "") if str1 == "" && str2 != "" str1 = I18n.t("property_hire.from_now_on") end if str1 != "" || str2 != "" str2 += I18n.t("property_hire.of",:default=>"") else str2 += I18n.t("property_hire.at",:default=>"") end week_str = "" if translation_missing week_str += "every " else week_str += I18n.t("property_hire.every") end dot_trans = I18n.t("property_hire.dot",:default=>", ") property.weekdays.each_with_index do |d,i| if i < (property.weekdays.count - 1) week_str += (weekdays_options[d.to_i] + dot_trans) else week_str += weekdays_options[d.to_i] end end str3 = "" if property.end_time.blank? if property.start_time.blank? str3 = "." if translation_missing else str3 = I18n.t("property_hire.from_time",{:time=>property.start_time,:default=>" from #{property.start_time}."}) end else if I18n.locale.to_s != "zh_tw" str3 = " between #{property.start_time} & #{property.end_time}." else str3 = I18n.t("property_hire.time1_to_time2",{:time1=>property.start_time,:time2=>property.end_time}) end end if str3 != "" str3 = I18n.t("property_hire.of",:default=>"") + str3 end hint1 = I18n.t('property_hire.unavailable_hint1', {:str1=>str1,:str2=>str2,:week_str=>week_str,:str3=>str3, :default => ''}) if hint1 == "" message += "This property is unavaliable#{str1}#{str2} #{week_str}#{str3}" else message += hint1 end end if property.special_unavailable_dates.count > 1 message += " And on " + property.special_unavailable_dates.join(", ") end if property.need_hire_before != 0 if message != "" message += "
" end default_msg = "This property must be reserved #{property.need_hire_before} #{property.need_hire_before_unit}s in advance." message += I18n.t("property_hire.unavailable_hint3",{:month=>property.need_hire_before,:unit=>I18n.t("property_hire._#{property.need_hire_before_unit}",:default=>property.need_hire_before_unit),:default=>default_msg}) end if property.can_hire_before_months != 0 if message != "" message += "
" end default_msg = "This property is unavaliable to reserved before #{property.can_hire_before_months} month ago." message += I18n.t("property_hire.unavailable_hint2",{:month=>property.can_hire_before_months,:default=>default_msg}) end end return message.html_safe end def get_location_name return self.property_location.nil? ? self.other_location : self.property_location.title end def owner_profiles MemberProfile.find(self.owners) rescue [] end def is_available_for_hire?(stime, etime, interval = nil, recurring_end_date = nil, time_setting_id = nil) available = 0 return 1 if self.set_unavailibility == false return 1 if self.weekdays.empty? && self.can_hire_before_months == 0 time_now = Time.now.to_datetime if self.can_hire_before_months != 0 return 2 if ((stime - (self.can_hire_before_months).month) > time_now) end if self.need_hire_before != 0 return 3 if (time_now + (self.need_hire_before).send(self.need_hire_before_unit) > stime) end self.special_unavailable_dates.each do |dt| unavailable_date = Date.parse(dt) cd = (stime..etime) & (unavailable_date..unavailable_date) if !cd.nil? return 0 end end startt = self.start_date.nil? ? stime : self.start_date endt = self.end_date.nil? ? etime : self.end_date available = 1 if (startt > stime && endt > etime) available = 1 if (endt < stime) weekdays = self.weekdays.collect{|w| w.to_i} if !startt.nil? if available == 0 common_dates = (startt..endt) & (stime..etime) available = 1 if common_dates.nil? if available == 0 time_weekdays = [] Property.time_iterate(common_dates.min, common_dates.max, 1.day) do |t| time_weekdays << t.wday end time_weekdays.uniq! weekdays = weekdays & time_weekdays if weekdays.blank? available = 1 else startt = DateTime.parse(stime.strftime("%Y-%m-%d " + (self.start_time.blank? ? "00:00" : self.start_time) + Time.zone.to_s)) endt = DateTime.parse(etime.strftime("%Y-%m-%d " + (self.end_time.blank? ? "23:59" : self.end_time) + Time.zone.to_s)) common_dates = (startt..endt) & (stime..etime) available = common_dates.nil? ? 1 : 0 end end end if available == 1 if !recurring_end_date.blank? case interval when 'week' d_step = 1.week when 'month' d_step = 1.month else d_step = 0 end if d_step != 0 if etime >= stime Property.time_iterate(etime,recurring_end_date,d_step).each do |date_time| new_etime = date_time new_stime = stime + (new_etime - etime) available = self.is_available_for_hire?(new_stime, new_etime, nil, nil) break if available != 1 end else available = 0 end end end return available else return available end end end def not_yet_hired?(stime, etime, interval, recurring_end_date,phire_id=nil,time_setting_id=nil) phires = self.p_hires stime = stime.utc etime = etime.utc bookings_count = 0 reservation_limit = 0 if time_setting_id time_setting = PropertyDaySetting.find(time_setting_id) etime = stime + 1.day etime = etime.utc reservation_limit = time_setting.reservation_limit if reservation_limit == 0 return true end bookings_count = phires.where(:start_time.lte => stime,:end_time.gte => stime,:recurring => false,:id.ne=>phire_id,:property_day_setting_id=>time_setting_id).count + phires.where(:start_time.gte => stime,:end_time.lte => etime,:recurring => false,:id.ne=>phire_id,:property_day_setting_id=>time_setting_id).count +phires.where(:start_time.lte => etime,:end_time.gte => etime,:recurring => false,:id.ne=>phire_id,:property_day_setting_id=>time_setting_id).count if bookings_count < reservation_limit bookings_count = 0 end else bookings_count = phires.where(:start_time.lte => stime,:end_time.gte => stime,:recurring => false,:id.ne=>phire_id).count + phires.where(:start_time.gte => stime,:end_time.lte => etime,:recurring => false,:id.ne=>phire_id).count +phires.where(:start_time.lte => etime,:end_time.gte => etime,:recurring => false,:id.ne=>phire_id).count end available = true if bookings_count != 0 available = false end if available recurring_bookings = phires.where(:recurring_end_date.gte => stime, :recurring => true,:id.ne=>phire_id) bookings = phires.where(:recurring => false,:recurring_end_date => nil,:id.ne=>phire_id) case interval when 'week' d_step = 1.week when 'month' d_step = 1.month else d_step = 0 end not_in_ids = bookings.any_of([{:end_time.lt=>stime},{:start_time.gt=>etime}]).pluck(:id) bookings = bookings.where(:id.nin=>not_in_ids) if time_setting_id recurring_bookings = recurring_bookings.where(:property_day_setting_id=>time_setting_id) bookings = recurring_bookings.where(:property_day_setting_id=>time_setting_id) end if true#d_step != 0 bookings += recurring_bookings end if time_setting_id tmp = {} stime_date = stime.strftime("%Y-%m-%d") bookings = bookings.each_with_index do |booking,i| if booking.date.wday != stime.wday next end b_interval = booking.recurring_interval b_recurring_end_date = booking.recurring_end_date ? booking.recurring_end_date.utc : nil booking_date = booking.start_time.utc.strftime("%Y-%m-%d") if (b_interval == 'month' || b_interval == 'week') && (booking.recurring_end_date.nil? || !booking.recurring) b_interval = nil end if stime_date == booking_date if tmp[booking_date].nil? tmp[booking_date] = 0 end tmp[booking_date] += 1 available = false if tmp[booking_date] > reservation_limit end break if available == false if b_interval.present? b_interval = (1).send(b_interval) b_sdata = booking.start_time.utc b_datas = Property.time_iterate(b_sdata,b_recurring_end_date,b_interval) all_stime_datas = Property.time_iterate(stime,b_recurring_end_date,b_interval).map{|t| t.utc.strftime("%Y-%m-%d")} b_datas.each do |b_data| booking_date = b_data.utc.strftime("%Y-%m-%d") if all_stime_datas.include?(booking_date) if tmp[booking_date].nil? tmp[booking_date] = 0 end tmp[booking_date] += 1 available = false if tmp[booking_date] > reservation_limit end break if available == false end end break if available == false end else bookings.each_with_index do |booking,i| stime_tp = stime.clone etime_tp = etime.clone b_interval = booking.recurring_interval b_recurring_end_date = booking.recurring_end_date ? booking.recurring_end_date.utc : nil b_sdata = booking.start_time.utc b_edata = booking.end_time.utc b_delta = b_edata - b_sdata if (b_interval == 'month' || b_interval == 'week') && (booking.recurring_end_date.nil? || !booking.recurring) b_interval = nil end b_datas = [] if b_interval.present? b_interval = (1).send(b_interval) b_datas = Property.time_iterate(b_edata,b_recurring_end_date,b_interval) b_datas = b_datas.map{|b_end| [b_end-b_delta,b_end]} start_index = b_datas.count b_datas.each_with_index do |(b_start,b_end),i| if b_start >= stime_tp || b_end <= etime_tp start_index = i break end end b_datas = b_datas[start_index..-1].to_a.map{|b_start,b_end| (b_start..b_end)} else b_datas = [b_sdata..b_edata] end while b_datas.present? available = b_datas.find{|b_range| b_range & (stime_tp..etime_tp)}.nil? stime_tp = stime_tp + d_step etime_tp = etime_tp + d_step break if !available || recurring_end_date.blank? || d_step==0 start_index = b_datas.find_index{|b_range| b_range.first >= stime_tp} if start_index b_datas = b_datas[start_index..-1] else b_datas = [] end end break if available == false end end end return available end def check_require_fields(booking_p) fields_name = self.get_all_fields has_p_hire_fields = self.p_hire_fields_enabled.count != 0 p_hire_fields = {} if has_p_hire_fields p_hire_fields = self.p_hire_fields_enabled.map{|rf| [rf.id.to_s,rf]}.to_h end error_messages = "" form_index = 0 cross_lang_types = ['select','date','radio_button','checkbox'] unfilled_text = I18n.t('property_hire.unfilled') available_locales = I18n.available_locales available_locales_trans = available_locales.map{|l| [l, I18n.t(l)]}.to_h fields_name.each do |field_name| if has_p_hire_fields && field_name.include?("p_hire_fields") rf = p_hire_fields[field_name.sub("p_hire_fields.",'')] if rf && rf.markup != 'hint_text' && rf.to_require v = booking_p["p_hire_field_values_attributes"][form_index.to_s]['value'] if cross_lang_types.include?(rf.markup) || rf.get_data["cross_lang"] == "true" if v.blank? error_messages += "#{rf.title}: #{unfilled_text}\n" end else available_locales.each do |l| if (v[l].blank? rescue true) error_messages += "#{rf.title}(#{available_locales_trans[l]}): #{unfilled_text}\n" end end end end form_index = form_index +1 else field_setting = self.send(field_name) if field_setting && field_setting["required"] == "true" && booking_p[field_name].blank? error_messages += "#{self.custom_text(field_name,"name")}: #{unfilled_text}\n" end end end error_messages end def self.time_iterate(start_time, end_time, step, &block) times = [] if block_given? begin times << start_time yield(start_time, end_time) end while (start_time += step) <= end_time else start_time = start_time.clone begin times << start_time end while (start_time += step) <= end_time end times end def carousel_image_width (self.custom_carousel_image_width.blank? ? PropertyHireSetting.first.carousel_image_width : self.custom_carousel_image_width) rescue "75%" end def get_attribute_value(attribute_field, p_hire_id) PHireFieldValue.find_by(p_hire_field_id: attribute_field.id, p_hire_id: p_hire_id) end def get_attribute_values(attribute_type=nil) @attribute_values = attribute_type.p_hire_field_values rescue nil end def get_value_from_field_id(field_id,attribute_type=nil) values = get_attribute_values(attribute_type) value = values.detect {|value| value.p_hire_field_id == field_id} rescue nil value ? value : nil end def get_basic_fields basic_fields = self.class::FIELDSNAME basic_fields = basic_fields.select{|f| (self.send(f)["enable"] == "1" rescue true)} end def get_all_fields(get_default=false) @default_field_names = nil if @default_field_names.nil? if get_default if @default_field_names.nil? basic_fields = self.get_basic_fields custom_fields = [] self.p_hire_fields_enabled.each do |p_hire_field| unless p_hire_field.disabled custom_fields << "p_hire_fields.#{p_hire_field.id}" end end @default_field_names = basic_fields + custom_fields end return @default_field_names else self.enable_fields_sort ? self.custom_field_names : self.default_field_names end end def can_be_hired_frontend user = OrbitHelper.current_user self.can_be_hired || (user && (user.is_admin? || (self.owners && self.owners.include?(user.member_profile_id)))) end def can_be_show_frontend user = OrbitHelper.current_user (!disable_no_logins_view_calendar && self.can_be_hired) || user end def clone_new(clone_mode=false) @records_all = {} if clone_mode clone_target = self.class.find(object.copy_id) rescue nil else clone_target = self end property,clone_target = clone_new_for_object(self,clone_target,clone_mode) property end def fix_uploader(clone_relation, r, f) return r.send(f).blank? if !@clone_mode || (clone_relation[f].blank? && clone_relation.send(f).blank?) clone_relation[f] = r[f] if @clone_mode clone_relation.send(f).retrieve_from_store!(r[f]) else org_id = clone_relation.id clone_relation.id = r.id clone_relation.send(f).retrieve_from_store!(r[f]) clone_relation.id = org_id end source_filepath = r.send(f).file.file if @clone_mode dest_filepath = clone_relation.send(f).file.file FileUtils.mkdir_p(File.dirname(dest_filepath)) FileUtils.cp(source_filepath,dest_filepath) end elsif (clone_relation.send(f).file rescue nil) clone_relation[f] = File.basename(clone_relation.send(f).file.file.to_s) end end def clone_new_for_object(object,clone_target=nil,clone_mode=false,fix_only=false) @except_clone_relations ||= self.except_clone_relations if clone_mode || fix_only new_object = object clone_target = object.class.find(object.copy_id) rescue nil if clone_target.nil? else clone_target = object if clone_target.nil? new_object = object.dup end return if @except_clone_relations.include?(new_object.class.to_s.underscore) @records_all["#{new_object.class.to_s.underscore}_ids"] = {} if @records_all["#{new_object.class.to_s.underscore}_ids"].nil? begin @records_all["#{new_object.class.to_s.underscore}_ids"][clone_target.id] = new_object rescue nil end if !clone_target.nil? && !new_object.nil? unless fix_only if clone_mode initialize_fields = [] if new_object.fields.keys.include?("uid") new_object.generate_uid end else initialize_fields = ["uid","created_at","updated_at"] end initialize_fields.each do |f| new_object.send("#{f}=",nil) if new_object.fields.keys.include?(f) end end relations_fields = clone_target.relations.except("impressions").keys all_fields = clone_target.fields.keys - relations_fields all_fields = all_fields - relations_fields.map{|k| "#{k}_id"} all_fields = all_fields - relations_fields.map{|k| "#{k.singularize}_ids"} new_object_class_name = new_object.class.to_s.underscore unless @parent_level unsort_relation_keys = clone_target.relations.keys - ['taggings'] fields_to_delete = [new_object_class_name] tmp_relations_fields = [new_object_class_name] while relations_fields.count > 0 tmp_singularize_relations_fields = tmp_relations_fields.map{|f| f.singularize} approve_append = nil relations_fields.each do |k| belongs_to_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro == :belongs_to}.keys has_many_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro.to_s.start_with?('has') }.keys if (belongs_to_class - tmp_singularize_relations_fields).count == 0 other_has_many_class = (has_many_class - unsort_relation_keys) if other_has_many_class.count == 0 tmp_relations_fields << k else org_k = k.to_s result = other_has_many_class.map do |k| belongs_to_class = k.classify.constantize.relations.select{|kk,v| v.macro == :belongs_to}.keys has_many_class = k.classify.constantize.relations.select{|kk,v| v.macro.to_s.start_with?('has') }.keys if (belongs_to_class - tmp_singularize_relations_fields - [org_k]).count == 0 true else fields_to_delete = fields_to_delete.concat(belongs_to_class) tmp_relations_fields.concat(belongs_to_class) false end end if result.select{|t| !t}.count == 0 if (fields_to_delete.map{|f| f.pluralize} - tmp_relations_fields).count == 0 tmp_relations_fields << k elsif clone_target.relations[k].class_name.constantize.fields.keys.include?("key") tmp_relations_fields << k elsif (clone_target.relations[k].class_name.constantize.relations.keys.map{|f| f.singularize} & fields_to_delete).count != 0 approve_append = k end end end elsif !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore) && !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore.pluralize) tmp_relations_fields << k end end tmp_relations_fields << approve_append if approve_append.present? approve_append = nil relations_fields = relations_fields - tmp_relations_fields relations_fields -= @relations_fields if @relations_fields end relations_fields = tmp_relations_fields fields_to_delete.each{|f| relations_fields.delete(f)} end if @parent_level relations_fields -= @relations_fields else @clone_mode = clone_mode @relations_fields = relations_fields end @parent_level = true if clone_mode all_fields.each do |f| next if f == "uid" unless new_object.send("#{f}_changed?") && new_object.send("#{f}_changed_from_default?") unless fix_only new_object.send("#{f}=",clone_target.send(f)) end if new_object.class.uploaders.include?(f.to_sym) fix_uploader(new_object, clone_target, f) end end end else all_fields.each do |f| if new_object.class.uploaders.include?(f.to_sym) fix_uploader(new_object, clone_target, f) end end end relations_fields.each do |f| no_dup_flag = false if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].macro == :has_one no_dup_flag = new_object.send(f).present? elsif clone_target.relations[f].macro == :has_many || clone_target.relations[f].macro == :has_and_belongs_to_many no_dup_flag = new_object.send(f).to_a.count != 0 elsif clone_target.relations[f].macro == :embeds_many #Fix localize fields if new_object.send(f).to_a.count != 0 need_fix_fields = new_object.send(f).to_a[0].fields.select{|k,v| (v.options[:localize] rescue false)}.keys locale = I18n.locale.to_s embeded_records = new_object.send(f).map do |embeded_record| need_fix_fields.each do |f| if (embeded_record[f][locale].class != String rescue false) embeded_record.send("#{f}_translations=",embeded_record[f][locale]) else embeded_record.send("#{f}_translations=",embeded_record[f]) end end embeded_record end new_object.send("#{f}=",embeded_records) end end if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].class_name == "MemberProfile" if f == 'taggable' map_f = @taggable_name else map_f = f end if @records_all["#{map_f}_ids"].nil? new_object.send("#{f}_id=",clone_target.send("#{f}_id")) else obj = @records_all["#{map_f}_ids"][clone_target.send("#{f}_id")] if obj new_object.send("#{f}_id=", obj.id) new_object.send("#{f}=", obj) end end elsif clone_target.relations[f].macro == :has_one next if @except_clone_relations.include?(f) need_clone_relation = clone_target.send(f) next if need_clone_relation.nil? clone_relation = new_object.send(f) if clone_relation.nil? clone_relation, need_clone_relation = clone_new_for_object(need_clone_relation.dup, need_clone_relation, clone_mode, fix_only) else clone_relation, r = clone_new_for_object(clone_relation, r, clone_mode, true) end new_object.send("#{f}=",clone_relation) elsif clone_target.relations[f].macro == :has_many || clone_target.relations[f].macro == :has_and_belongs_to_many next if @except_clone_relations.include?(f) clone_relations = [] need_clone_relations = clone_target.send(f).asc(:_id).to_a file_flag = false if f == 'taggings' @taggable_name = new_object.class.to_s.underscore end need_clone_relations.each_with_index do |r,i| clone_relation = new_object.send(f)[i] if clone_relation.nil? clone_relation, r = clone_new_for_object(r.dup, r, clone_mode, fix_only) else clone_relation, r = clone_new_for_object(clone_relation, r, clone_mode, true) end clone_relations << clone_relation end if !no_dup_flag || (no_dup_flag && file_flag) new_object_relations = new_object.send(f).to_a new_object_relations_count = new_object_relations.count if new_object_relations_count != 0 if clone_relations.count > new_object_relations_count clone_relations = clone_relations[0...new_object_relations_count] else clone_relations = clone_relations.concat(new_object.send(f)[clone_relations.count...new_object_relations_count]) end new_object.send("#{f}=",clone_relations) else new_object.send("#{f}=",clone_relations) end end end end new_object.copy_id = clone_target.id if new_object.fields.keys.include?("copy_id") return new_object, clone_target end end end