From 93ac6d254e6de05d64c3aa6371aef246173c6553 Mon Sep 17 00:00:00 2001 From: Harry Bomrah Date: Wed, 24 Jan 2018 16:29:28 +0800 Subject: [PATCH] added recurring hiring. --- app/controllers/property_hires_controller.rb | 8 ++- app/helpers/admin/property_hires_helper.rb | 5 +- app/models/p_hire.rb | 59 +++++++++++++++++- app/models/property.rb | 30 +++++++++- app/views/property_hires/hire.html.erb | 63 ++++++++++++++++++-- config/locales/en.yml | 6 ++ config/locales/zh_tw.yml | 6 ++ config/routes.rb | 2 +- 8 files changed, 165 insertions(+), 14 deletions(-) diff --git a/app/controllers/property_hires_controller.rb b/app/controllers/property_hires_controller.rb index ca567b3..f8126bb 100644 --- a/app/controllers/property_hires_controller.rb +++ b/app/controllers/property_hires_controller.rb @@ -145,7 +145,7 @@ class PropertyHiresController < ApplicationController def make_booking booking_p = booking_params - data = check_for_availability(booking_p[:start_time],booking_p[:end_time],booking_p[:property_id]) + data = check_for_availability(booking_p[:start_time],booking_p[:end_time],booking_p[:property_id], booking_p[:recurring_interval], booking_p[:recurring_end_date]) property = Property.find(booking_p[:property_id]) rescue nil if data["success"] == true hire = PHire.new(booking_p) @@ -176,7 +176,7 @@ class PropertyHiresController < ApplicationController end def check_availability - data = check_for_availability params[:stime], params[:etime], params[:property_id] + data = check_for_availability params[:stime], params[:etime], params[:property_id], params[:interval], params[:recurring_end_date] render :json => data.to_json end @@ -188,11 +188,13 @@ class PropertyHiresController < ApplicationController sdt = Time.at(params[:start].to_i) edt = Time.at(params[:end].to_i) events = PHire.monthly_event(sdt,edt,params[:property_id]) + re = PHire.recurring_event(sdt,edt) + allevents = events.inject(re, :<<) end end respond_to do |format| format.html # index.html.erb - format.json { render json: events.to_json } + format.json { render json: allevents.to_json } end end diff --git a/app/helpers/admin/property_hires_helper.rb b/app/helpers/admin/property_hires_helper.rb index 749208b..f51613a 100644 --- a/app/helpers/admin/property_hires_helper.rb +++ b/app/helpers/admin/property_hires_helper.rb @@ -1,14 +1,15 @@ module Admin::PropertyHiresHelper - def check_for_availability(stime, etime, pid) + def check_for_availability(stime, etime, pid, interval, recurring_end_date) property = Property.find(pid) return {"success" => false, "msg" => "Values are not ok."} if property.nil? || stime.blank? || etime.blank? stime = DateTime.parse(stime + Time.zone.to_s) rescue nil etime = DateTime.parse(etime + Time.zone.to_s) rescue nil + recurring_end_date = DateTime.parse(recurring_end_date + Time.zone.to_s) rescue nil data = {} return {"success" => false, "msg" => "Starting time cannot be greater than ending time."} if stime > etime if property.is_available_for_hire?(stime, etime) - if property.is_already_hired?(stime, etime) + if property.is_already_hired?(stime, etime, interval, recurring_end_date) data = {"success" => true} else data = {"success" => false, "msg" => "Property is already hired during this time."} diff --git a/app/models/p_hire.rb b/app/models/p_hire.rb index 9f6cdd0..f737f0b 100644 --- a/app/models/p_hire.rb +++ b/app/models/p_hire.rb @@ -2,6 +2,8 @@ class PHire include Mongoid::Document include Mongoid::Timestamps + INTERVALS = ["week", "month"] + field :start_time, type: DateTime field :end_time, type: DateTime field :hiring_person_email @@ -11,6 +13,9 @@ class PHire field :reason_for_hire field :note_for_hire field :passed, type: Boolean, default: false + field :recurring, type: Boolean, :default => false + field :recurring_end_date, type: DateTime + field :recurring_interval belongs_to :property @@ -39,7 +44,59 @@ class PHire end def self.monthly_event(start_date,end_date,property_id) - self.where(:property_id => property_id).any_of(:start_time.gte => start_date, :end_time.gte => start_date).and(:start_time.lte => end_date).asc(:start_time) + self.where(:property_id => property_id, :recurring => false).any_of(:start_time.gte => start_date, :end_time.gte => start_date).and(:start_time.lte => end_date).asc(:start_time) + end + + def self.recurring_event(start_date,end_date) + @recurring_events = self.where(:recurring => true) + @recurring = [] + @recurring_events.each do |re| + case re.recurring_interval + when "week" + @start_date = re.start_time + @end_date = re.end_time + @i = TimeDifference.between(re.start_time,end_date).in_weeks.to_i + (0..@i).each do |i| + if i > 0 + @start_date += 7 + @end_date += 7 + end + if @start_date < re.recurring_end_date + @recurring << {:id => re.id.to_s, :title=>re.reason_for_hire, :note=>re.reason_for_hire, :start=>@start_date, :end => @end_date, :allDay => false, :recurring => re.recurring, :color => "#FC4040"} + end + end + when "month" + # if !(start_date..end_date).cover?(re.start_time) + sd = re.start_time + ed = re.end_time + @i = TimeDifference.between(re.start_time,end_date).in_months.to_i + @start_date = sd + # debugger + sd = sd >> @i + ed = ed >> @i + if sd < re.recurring_end_date + @recurring << {:id => re.id.to_s, :title=>re.reason_for_hire, :note=>re.reason_for_hire, :start=>sd, :end => ed, :allDay => false, :recurring => re.recurring, :color => "#FC4040"} + end + # end + end + end + @recurring + end + + def time_iterate(&block) + start_time = self.start_time + end_time = self.end_time + recurring_end_date = self.recurring_end_date + case self.recurring_interval + when "week" + step_interval = 1.week + when "month" + step_interval = 1.month + end + begin + yield(start_time, end_time) + end_time += step_interval + end while (start_time += step_interval) <= recurring_end_date end end \ No newline at end of file diff --git a/app/models/property.rb b/app/models/property.rb index 8569a8e..59306d5 100644 --- a/app/models/property.rb +++ b/app/models/property.rb @@ -81,8 +81,8 @@ class Property end end - def is_already_hired?(stime, etime) - bookings = self.p_hires.where(:end_time.gte => stime) + def is_already_hired?(stime, etime, interval, recurring_end_date) + bookings = self.p_hires.where(:end_time.gte => stime, :recurring => false) available = true bookings.each do |booking| common_time = (booking.start_time..booking.end_time) & (stime..etime) @@ -91,12 +91,36 @@ class Property break end end + if available + case interval + when "week" + stepu = 1.week + when "month" + stepu = 1.month + end + bookings = self.p_hires.where(:recurring_end_date.gte => stime, :recurring => true) + bookings.each do |booking| + booking.time_iterate do |st,et| + tst = stime + tet = etime + begin + common_time = (tst..tet) & (st..et) + available = false if !common_time.nil? + tet += stepu + break if !available + break if tst > st + end while (tst += stepu) <= recurring_end_date + break if !available + end + break if !available + end + end return available end def self.time_iterate(start_time, end_time, step, &block) begin - yield(start_time) + yield(start_time, end_time) end while (start_time += step) <= end_time end diff --git a/app/views/property_hires/hire.html.erb b/app/views/property_hires/hire.html.erb index 63a83a8..4a157ec 100644 --- a/app/views/property_hires/hire.html.erb +++ b/app/views/property_hires/hire.html.erb @@ -39,10 +39,34 @@ <%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record?, :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> + +
+ <%= f.label :recurring, t("property_hires.recurring"), :class => "col-sm-2 control-label" %> +
+ <%= f.check_box :recurring %> +
+
+
> +
+ <%= f.label :recurring_interval, t("property_hires.recurring_interval"), :class => "col-sm-2 control-label" %> +
+ <%= f.select :recurring_interval, PHire::INTERVALS.collect{|int| [t("property_hire.recurring_interval_types.#{int}"), int] }, {:prompt => "Select interval"}, {:data => {"fv-validation" => "requiredifrecurring;" , "fv-messages" => "Cannot be empty;"}} %> +
+
+ +
+ <%= f.label :recurring_end_date, t("property_hires.recurring_end_date"), :class => "col-sm-2 control-label" %> +
+ <%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %> +
+
+
+
+
<% if property.set_unavailibility %>
@@ -116,13 +140,29 @@ var el = $(this), url = $(this).attr("href"), spinner = $("#spinner"); - el.hide(); - spinner.show(); + $(".alert").hide(); + data = { + "stime" : $("#p_hire_start_time").val(), + "etime" : $("#p_hire_end_time").val(), + "property_id" : property_id + } + if($("#p_hire_recurring").is(":checked")){ + var interval = $("#p_hire_recurring_interval").val(), + recurring_end_date = $("#p_hire_recurring_end_date").val(); + if(interval == "" || recurring_end_date == ""){ + $("#values-alert").show(); + return false; + } + data["interval"] = interval; + data["recurring_end_date"] = recurring_end_date; + } + spinner.show(); + el.hide(); $.ajax({ "url" : url, - "type" : "post", - "data" : {"stime" : $("#p_hire_start_time").val(), "etime" : $("#p_hire_end_time").val(), "property_id" : property_id}, + "type" : "get", + "data" : data, "dataType" : "json" }).done(function(data){ if(data.success){ @@ -146,6 +186,21 @@ hireForm.validate_functions.checkForDates = function(value,element){ return value == "1"; } + hireForm.validate_functions.requiredifrecurring = function(value, element){ + if($("#p_hire_recurring").is(":checked")){ + return value != ""; + }else{ + return true; + } + } + + $("#p_hire_recurring").on("click",function(){ + if($(this).is(":checked")){ + $("#recurring-block").slideDown(); + }else{ + $("#recurring-block").slideUp(); + } + }) <% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index d1f79cc..a8aa436 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,5 +1,11 @@ en: property_hire: + recurring: Recurring + recurring_interval: Recurring Interval + recurring_interval_types: + month: Month + week: Week + recurring_end_date: Recurring End Date save: Save property_hire: Property manage_locations: Manage Locations diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index 2a7c8ed..7f32786 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -1,5 +1,11 @@ zh_tw: property_hire: + recurring: Recurring + recurring_interval: Recurring Interval + recurring_interval_types: + month: Month + week: Week + recurring_end_date: Recurring End Date save: Save property_hire: Property manage_locations: Manage Locations diff --git a/config/routes.rb b/config/routes.rb index 2f5dead..b28d960 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,7 @@ Rails.application.routes.draw do locales = Site.find_by(site_active: true).in_use_locales rescue I18n.available_locales scope "(:locale)", locale: Regexp.new(locales.join("|")) do - post "/xhr/property_hires/check_availability" => "property_hires#check_availability" + get "/xhr/property_hires/check_availability" => "property_hires#check_availability" post "/xhr/property_hires/make_booking" => "property_hires#make_booking" get "/xhr/property_hires/get_bookings" => "property_hires#get_bookings" namespace :admin do