added recurring hiring.

This commit is contained in:
Harry Bomrah 2018-01-24 16:29:28 +08:00
parent 0e655ebb61
commit 93ac6d254e
8 changed files with 165 additions and 14 deletions

View File

@ -145,7 +145,7 @@ class PropertyHiresController < ApplicationController
def make_booking def make_booking
booking_p = booking_params 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 property = Property.find(booking_p[:property_id]) rescue nil
if data["success"] == true if data["success"] == true
hire = PHire.new(booking_p) hire = PHire.new(booking_p)
@ -176,7 +176,7 @@ class PropertyHiresController < ApplicationController
end end
def check_availability 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 render :json => data.to_json
end end
@ -188,11 +188,13 @@ class PropertyHiresController < ApplicationController
sdt = Time.at(params[:start].to_i) sdt = Time.at(params[:start].to_i)
edt = Time.at(params[:end].to_i) edt = Time.at(params[:end].to_i)
events = PHire.monthly_event(sdt,edt,params[:property_id]) events = PHire.monthly_event(sdt,edt,params[:property_id])
re = PHire.recurring_event(sdt,edt)
allevents = events.inject(re, :<<)
end end
end end
respond_to do |format| respond_to do |format|
format.html # index.html.erb format.html # index.html.erb
format.json { render json: events.to_json } format.json { render json: allevents.to_json }
end end
end end

View File

@ -1,14 +1,15 @@
module Admin::PropertyHiresHelper 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) property = Property.find(pid)
return {"success" => false, "msg" => "Values are not ok."} if property.nil? || stime.blank? || etime.blank? 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 stime = DateTime.parse(stime + Time.zone.to_s) rescue nil
etime = DateTime.parse(etime + 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 = {} data = {}
return {"success" => false, "msg" => "Starting time cannot be greater than ending time."} if stime > etime 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_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} data = {"success" => true}
else else
data = {"success" => false, "msg" => "Property is already hired during this time."} data = {"success" => false, "msg" => "Property is already hired during this time."}

View File

@ -2,6 +2,8 @@ class PHire
include Mongoid::Document include Mongoid::Document
include Mongoid::Timestamps include Mongoid::Timestamps
INTERVALS = ["week", "month"]
field :start_time, type: DateTime field :start_time, type: DateTime
field :end_time, type: DateTime field :end_time, type: DateTime
field :hiring_person_email field :hiring_person_email
@ -11,6 +13,9 @@ class PHire
field :reason_for_hire field :reason_for_hire
field :note_for_hire field :note_for_hire
field :passed, type: Boolean, default: false field :passed, type: Boolean, default: false
field :recurring, type: Boolean, :default => false
field :recurring_end_date, type: DateTime
field :recurring_interval
belongs_to :property belongs_to :property
@ -39,7 +44,59 @@ class PHire
end end
def self.monthly_event(start_date,end_date,property_id) 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
end end

View File

@ -81,8 +81,8 @@ class Property
end end
end end
def is_already_hired?(stime, etime) def is_already_hired?(stime, etime, interval, recurring_end_date)
bookings = self.p_hires.where(:end_time.gte => stime) bookings = self.p_hires.where(:end_time.gte => stime, :recurring => false)
available = true available = true
bookings.each do |booking| bookings.each do |booking|
common_time = (booking.start_time..booking.end_time) & (stime..etime) common_time = (booking.start_time..booking.end_time) & (stime..etime)
@ -91,12 +91,36 @@ class Property
break break
end end
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 return available
end end
def self.time_iterate(start_time, end_time, step, &block) def self.time_iterate(start_time, end_time, step, &block)
begin begin
yield(start_time) yield(start_time, end_time)
end while (start_time += step) <= end_time end while (start_time += step) <= end_time
end end

View File

@ -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.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;"} %>
</div> </div>
</div> </div>
<!-- ############# recurring ############# -->
<div class="form-group">
<%= f.label :recurring, t("property_hires.recurring"), :class => "col-sm-2 control-label" %>
<div class="col-sm-1">
<%= f.check_box :recurring %>
</div>
</div>
<div id="recurring-block" <%= hire.recurring ? "" : "style=display:none;" %>>
<div class="form-group">
<%= f.label :recurring_interval, t("property_hires.recurring_interval"), :class => "col-sm-2 control-label" %>
<div class="col-sm-1">
<%= 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;"}} %>
</div>
</div>
<div class="form-group">
<%= f.label :recurring_end_date, t("property_hires.recurring_end_date"), :class => "col-sm-2 control-label" %>
<div class="col-sm-10">
<%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %>
</div>
</div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-5"> <div class="col-sm-offset-2 col-sm-5">
<div id="property-avaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-success" role="alert"><b>Hooray! </b>This property is available.</div> <div id="property-avaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-success" role="alert"><b>Hooray! </b>This property is available.</div>
<div id="property-unavaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-danger" role="alert"><b>Sorry! </b><span> This property is available.</span></div> <div id="property-unavaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-danger" role="alert"><b>Sorry! </b><span> This property is available.</span></div>
<div id="values-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-warning" role="alert"><b>Please! </b><span> Select an interval time and recurring event end date.</span></div>
</div> </div>
<% if property.set_unavailibility %> <% if property.set_unavailibility %>
<div class="col-sm-offset-2 col-sm-5"> <div class="col-sm-offset-2 col-sm-5">
@ -116,13 +140,29 @@
var el = $(this), var el = $(this),
url = $(this).attr("href"), url = $(this).attr("href"),
spinner = $("#spinner"); spinner = $("#spinner");
el.hide();
spinner.show();
$(".alert").hide(); $(".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({ $.ajax({
"url" : url, "url" : url,
"type" : "post", "type" : "get",
"data" : {"stime" : $("#p_hire_start_time").val(), "etime" : $("#p_hire_end_time").val(), "property_id" : property_id}, "data" : data,
"dataType" : "json" "dataType" : "json"
}).done(function(data){ }).done(function(data){
if(data.success){ if(data.success){
@ -146,6 +186,21 @@
hireForm.validate_functions.checkForDates = function(value,element){ hireForm.validate_functions.checkForDates = function(value,element){
return value == "1"; 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();
}
})
</script> </script>
<% end %> <% end %>

View File

@ -1,5 +1,11 @@
en: en:
property_hire: property_hire:
recurring: Recurring
recurring_interval: Recurring Interval
recurring_interval_types:
month: Month
week: Week
recurring_end_date: Recurring End Date
save: Save save: Save
property_hire: Property property_hire: Property
manage_locations: Manage Locations manage_locations: Manage Locations

View File

@ -1,5 +1,11 @@
zh_tw: zh_tw:
property_hire: property_hire:
recurring: Recurring
recurring_interval: Recurring Interval
recurring_interval_types:
month: Month
week: Week
recurring_end_date: Recurring End Date
save: Save save: Save
property_hire: Property property_hire: Property
manage_locations: Manage Locations manage_locations: Manage Locations

View File

@ -2,7 +2,7 @@ Rails.application.routes.draw do
locales = Site.find_by(site_active: true).in_use_locales rescue I18n.available_locales locales = Site.find_by(site_active: true).in_use_locales rescue I18n.available_locales
scope "(:locale)", locale: Regexp.new(locales.join("|")) do 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" post "/xhr/property_hires/make_booking" => "property_hires#make_booking"
get "/xhr/property_hires/get_bookings" => "property_hires#get_bookings" get "/xhr/property_hires/get_bookings" => "property_hires#get_bookings"
namespace :admin do namespace :admin do