2017-01-20 09:02:50 +00:00
|
|
|
class Property
|
|
|
|
include Mongoid::Document
|
|
|
|
include Mongoid::Timestamps
|
|
|
|
include OrbitTag::Taggable
|
|
|
|
include OrbitCategory::Categorizable
|
|
|
|
include Slug
|
|
|
|
|
|
|
|
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
|
2018-01-03 05:47:55 +00:00
|
|
|
field :owners, type: Array, :default => []
|
2017-01-20 09:02:50 +00:00
|
|
|
field :other_owner
|
|
|
|
field :owner_email
|
|
|
|
field :owner_phone
|
|
|
|
field :price
|
|
|
|
field :other_location
|
|
|
|
|
|
|
|
mount_uploader :image, ImageUploader
|
|
|
|
|
|
|
|
# unavailibility fields
|
2021-07-05 10:05:49 +00:00
|
|
|
field :can_hire_before_months, type: Integer, default: 0
|
2017-01-20 09:02:50 +00:00
|
|
|
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
|
2020-07-02 14:56:03 +00:00
|
|
|
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
|
2020-07-22 10:13:50 +00:00
|
|
|
field :enable_notes_selector , type: Boolean, default: false
|
|
|
|
field :notes_selector ,type: Hash, default: {}
|
2017-01-20 09:02:50 +00:00
|
|
|
belongs_to :property_location
|
|
|
|
has_many :p_hires
|
2020-03-23 17:26:52 +00:00
|
|
|
has_many :hire_email_sets, :autosave => true, :dependent => :destroy, :inverse_of => :property
|
|
|
|
accepts_nested_attributes_for :hire_email_sets, :allow_destroy => true
|
2017-01-20 09:02:50 +00:00
|
|
|
WEEKDAYS = [
|
|
|
|
"Sunday",
|
|
|
|
"Monday",
|
|
|
|
"Tuesday",
|
|
|
|
"Wednesday",
|
|
|
|
"Thursday",
|
|
|
|
"Friday",
|
|
|
|
"Saturday"
|
|
|
|
]
|
2021-07-05 10:05:49 +00:00
|
|
|
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.can_hire_before_months != 0
|
|
|
|
if message != ""
|
|
|
|
message += "<br>"
|
|
|
|
end
|
|
|
|
default_msg = "This property is unavaliable to hire 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
|
2017-01-20 09:02:50 +00:00
|
|
|
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
|
|
|
|
|
2020-09-18 16:32:56 +00:00
|
|
|
def is_available_for_hire?(stime, etime, interval = nil, recurring_end_date = nil)
|
|
|
|
available = false
|
2017-01-20 09:02:50 +00:00
|
|
|
return true if self.set_unavailibility == false
|
2021-07-05 10:05:49 +00:00
|
|
|
return true if self.weekdays.empty? && self.can_hire_before_months == 0
|
|
|
|
if self.can_hire_before_months != 0
|
|
|
|
return nil if (((stime - Time.now.to_datetime) * 1.day) > (self.can_hire_before_months).month)
|
|
|
|
end
|
|
|
|
startt = self.start_date.nil? ? stime : self.start_date
|
|
|
|
endt = self.end_date.nil? ? etime : self.end_date
|
|
|
|
available = true if (startt > stime && endt > etime)
|
|
|
|
available = true if (endt < stime)
|
2017-01-20 09:02:50 +00:00
|
|
|
weekdays = self.weekdays.collect{|w| w.to_i}
|
|
|
|
if !startt.nil?
|
2020-09-18 16:32:56 +00:00
|
|
|
if !available
|
|
|
|
common_dates = (startt..endt) & (stime..etime)
|
|
|
|
return true if common_dates.nil?
|
|
|
|
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
|
|
|
|
return true if weekdays.blank?
|
2021-07-05 10:05:49 +00:00
|
|
|
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))
|
2020-09-18 16:32:56 +00:00
|
|
|
common_dates = (startt..endt) & (stime..etime)
|
|
|
|
available = common_dates.nil?
|
2017-01-20 09:02:50 +00:00
|
|
|
end
|
2020-09-18 16:32:56 +00:00
|
|
|
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
|
|
|
|
(etime.to_i..recurring_end_date.to_i).step(d_step).to_a.each_with_index do|time_integer,index|
|
|
|
|
date_time = Time.at(time_integer).to_datetime
|
|
|
|
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
|
|
|
|
end
|
|
|
|
else
|
|
|
|
available = false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return available
|
2017-01-20 09:02:50 +00:00
|
|
|
else
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-07-05 10:05:49 +00:00
|
|
|
def not_yet_hired?(stime, etime, interval, recurring_end_date,phire_id=nil)
|
2020-05-19 16:28:21 +00:00
|
|
|
phires = self.p_hires
|
2021-07-05 10:05:49 +00:00
|
|
|
stime = stime.utc
|
|
|
|
etime = etime.utc
|
|
|
|
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
|
2017-01-20 09:02:50 +00:00
|
|
|
available = true
|
2020-05-19 16:28:21 +00:00
|
|
|
if bookings_count != 0
|
2020-05-19 14:50:45 +00:00
|
|
|
available = false
|
2017-01-20 09:02:50 +00:00
|
|
|
end
|
2021-07-05 10:05:49 +00:00
|
|
|
puts ["phire_id",phire_id]
|
2018-01-24 08:29:28 +00:00
|
|
|
if available
|
2021-07-05 10:05:49 +00:00
|
|
|
recurring_bookings = phires.where(:recurring_end_date.gte => stime, :recurring => true,:id.ne=>phire_id)
|
|
|
|
bookings = phires.where(:recurring => false,:recurring_end_date => nil)
|
2020-05-19 15:07:06 +00:00
|
|
|
case interval
|
|
|
|
when 'week'
|
|
|
|
d_step = 1.week
|
2020-05-19 15:17:25 +00:00
|
|
|
when 'month'
|
|
|
|
d_step = 1.month
|
2020-05-19 15:07:06 +00:00
|
|
|
else
|
|
|
|
d_step = 0
|
|
|
|
end
|
2021-07-05 10:05:49 +00:00
|
|
|
if true#d_step != 0
|
|
|
|
bookings += recurring_bookings
|
|
|
|
end
|
|
|
|
bookings.each_with_index do |booking,i|
|
|
|
|
stime_tp = stime.clone
|
|
|
|
etime_tp = etime.clone
|
2020-05-19 15:07:06 +00:00
|
|
|
b_interval = booking.recurring_interval
|
2021-07-05 10:05:49 +00:00
|
|
|
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)
|
2020-05-25 04:09:19 +00:00
|
|
|
b_interval = nil
|
|
|
|
end
|
2021-07-05 10:05:49 +00:00
|
|
|
b_datas = []
|
|
|
|
if b_interval.present?
|
|
|
|
b_interval = (1).send(b_interval)
|
|
|
|
b_datas = (b_edata..b_recurring_end_date).step(b_interval).to_a
|
|
|
|
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
|
2020-05-26 14:15:45 +00:00
|
|
|
end
|
2020-05-19 15:07:06 +00:00
|
|
|
end
|
2021-07-05 10:05:49 +00:00
|
|
|
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?
|
2020-05-26 14:15:45 +00:00
|
|
|
sdata = stime_tp
|
|
|
|
edata = etime_tp
|
2021-07-05 10:05:49 +00:00
|
|
|
available = b_datas.find{|b_range| b_range & (stime_tp..etime_tp)}.nil?
|
2020-05-19 15:17:25 +00:00
|
|
|
stime_tp = stime_tp + d_step
|
|
|
|
etime_tp = etime_tp + d_step
|
2021-07-05 10:05:49 +00:00
|
|
|
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
|
2020-05-19 14:50:45 +00:00
|
|
|
break if available == false
|
2018-01-24 08:29:28 +00:00
|
|
|
end
|
|
|
|
end
|
2017-01-20 09:02:50 +00:00
|
|
|
return available
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.time_iterate(start_time, end_time, step, &block)
|
|
|
|
begin
|
2018-01-24 08:29:28 +00:00
|
|
|
yield(start_time, end_time)
|
2017-01-20 09:02:50 +00:00
|
|
|
end while (start_time += step) <= end_time
|
|
|
|
end
|
|
|
|
|
2020-05-19 16:28:21 +00:00
|
|
|
end
|