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
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 :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
field :organization
field :person_in_charge
field :tel_of_person_in_charge
field :department
field :contact_person
field :tel_of_contact_person
field :mobile_phone_of_contact_person
field :contact_person_Email
field :contact_person_department
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
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([:order_position,:asc],[:created_at,:desc])}
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
self.default_field_names = self.get_all_fields(true)
self.custom_field_names = self.get_all_fields(true)
end
before_save do
unless @no_validate
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 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.last.calendar_type rescue 0) : (self.custom_calendar_type - 1))
end
def self.init_class_variables
setting = PropertyHireSetting.last
if setting
@@disable_content_page = setting.disable_content_page rescue false
@@disable_view_calendar_page = setting.disable_view_calendar_page rescue false
else
@@disable_content_page = false
@@disable_view_calendar_page = 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 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.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)
available = 1
end
if self.need_hire_before != 0
return 3 if (time_now + (self.need_hire_before).send(self.need_hire_before_unit) > stime)
available = 1
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
available = 1 if weekdays.blank?
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?
end
end
if available
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
bookings = bookings.any_of([{:start_time.gte => etime},{:end_time.gte => etime}])
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 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.last.carousel_image_width : self.custom_carousel_image_width) rescue "75%"
end
def get_attribute_value(attribute_field, signup_id)
SeminarSignupValue.find_by(seminar_signup_field_id: attribute_field.id, seminar_signup_id: signup_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.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
end