updates for property hire

This commit is contained in:
rulingcom 2024-10-23 15:33:50 +08:00
parent e190f1e23c
commit f71fcdcefa
21 changed files with 400 additions and 122 deletions

17
Gemfile.lock Normal file
View File

@ -0,0 +1,17 @@
PATH
remote: .
specs:
property_hire (0.0.1)
GEM
remote: https://rubygems.org/
specs:
PLATFORMS
ruby
DEPENDENCIES
property_hire!
BUNDLED WITH
1.17.3

File diff suppressed because one or more lines are too long

View File

@ -104,9 +104,10 @@ window.getDateString = function(date, format,is_chinese) {
} }
return formattedDate; return formattedDate;
}; };
var Calendar = function(dom, property_id, valid_range, currentView, display_hire_event){ var Calendar = function(dom, property_id, valid_range, currentView, display_hire_event, locale = "en"){
var c = this; var c = this;
display_hire_event = (display_hire_event == undefined ? true : display_hire_event); display_hire_event = (display_hire_event == undefined ? true : display_hire_event);
this.locale = locale.replace("_","-");
this.title = $("#current_title"); this.title = $("#current_title");
this.calendar_dom = $(dom); this.calendar_dom = $(dom);
this.nextBtn = $("#next_month_btn"); this.nextBtn = $("#next_month_btn");
@ -136,6 +137,7 @@ var Calendar = function(dom, property_id, valid_range, currentView, display_hire
selectable: true, selectable: true,
width: "100%", width: "100%",
validRange: valid_range, validRange: valid_range,
locale: c.locale,
events: function(args, success_callback, fail_callback) { events: function(args, success_callback, fail_callback) {
var start = args.start; var start = args.start;
var end = args.end; var end = args.end;
@ -345,14 +347,17 @@ var EventDialog = function(calendar,event){
event_quick_view = $('<div class="calendar-modal" style="display:none;"></div>'); event_quick_view = $('<div class="calendar-modal" style="display:none;"></div>');
template = '<div class="modal-content">' + template = '<div class="modal-content">' +
'<div class="modal-header">' + '<div class="modal-header">' +
'<div class="property_title">' + _event.property_title + '</div>' +
'<button type="button" class="close event-close-btn" data-dismiss="modal" aria-hidden="true">&times;</button>' + '<button type="button" class="close event-close-btn" data-dismiss="modal" aria-hidden="true">&times;</button>' +
'<h3>' + _event.title + '</h3>' + '<h3>' + _event.title + '</h3>' +
'</div>' + '</div>' +
'<div class="modal-body">' + '<div class="modal-body">' +
'<div class="event_summary">' + time_string + '</br>' + _event.hiring_person_name + '</div>' + _event.note + '<div class="event_summary">' + time_string + '</br>' + _event.hiring_person_name + '</div>' + _event.note +
(_event.error_message ? ("<br><span style=\"color: #FC4040;\">" + _event.error_message + "</span>") : "") (_event.error_message ? ("<br><span style=\"color: #FC4040;\">" + _event.error_message + "</span>") : "") +
'</div>' + '</div>' +
'<div class="modal-footer" />' + '<div class="modal-footer">' +
(_event.view_button ? '<a href="' + _event.view_path + '" class="btn view-btn">'+ _event.view_path_name +'</a>' : "") +
'</div>'
'</div>'; '</div>';
} }

View File

@ -73,7 +73,7 @@ class Admin::PropertyHiresController < OrbitAdminController
end end
def show def show
@table_fields = ["property_hire.hiring_person_name", "property_hire.reason_for_hire", "property_hire.hiring_person_number", "property_hire.period", "property_hire.passed", :actions] @table_fields = ["property_hire.hiring_person_name", "property_hire.reason_for_hire", "property_hire.hiring_person_number", "property_hire.period", "property_hire.passed", "property_hire.actions"]
@property = Property.where(:uid => params[:id].split("-").last).first rescue nil @property = Property.where(:uid => params[:id].split("-").last).first rescue nil
@bookings = @property.p_hires.desc(:created_at).page(params[:page]).per(10) @bookings = @property.p_hires.desc(:created_at).page(params[:page]).per(10)
end end
@ -255,6 +255,24 @@ class Admin::PropertyHiresController < OrbitAdminController
@attribute_type = 'property' @attribute_type = 'property'
@class = 'properties' @class = 'properties'
end end
def checkforthread
running = !File.exists?("public/uploads/reservation_export/#{params[:property_id]}/#{params[:property_title]}.xlsx")
render :json => {"status" => running}.to_json
end
def export_reservation_data
property = Property.find(params[:id])
title = property.title.gsub(/[ "'*@#$%^&()+=;:.,?>|\\\/<~_!:,、。!?;「」〈〉【】/]/,'')
f = "public/uploads/reservation_export/#{property.id}/#{title}.xlsx"
File.delete(f) if File.exists?(f)
url = request.host_with_port
Thread.new do
system("rake property_hire_tasks:prepare_download[#{property.id},#{url}] >> #{Rails.root}/log/rake.log &")
end
render :json => {"success" => true, "title" => title}.to_json
end
private private
def settings_params def settings_params

View File

@ -5,6 +5,11 @@ class PropertyHiresController < ApplicationController
properties = Property.can_display.filter_by_categories.sort_order properties = Property.can_display.filter_by_categories.sort_order
url = "/#{I18n.locale}#{OrbitHelper.page.get_url}" url = "/#{I18n.locale}#{OrbitHelper.page.get_url}"
data = index_data(properties, url) data = index_data(properties, url)
filterprops = data.dup
filterprops.insert(0,{
"title" => t("property_hire.all_properties"),
"id" => "all&page_id=" + OrbitHelper.page.id.to_s
})
headers = [ headers = [
{ {
"column" => t("property_hire.title") "column" => t("property_hire.title")
@ -21,9 +26,15 @@ class PropertyHiresController < ApplicationController
] ]
{ {
"properties" => data, "properties" => data,
"filterprops" => filterprops,
"headers" => headers, "headers" => headers,
"extras" => { "extras" => {
"first_property_id" => data.first["id"] "first_property_id" => filterprops.first["id"],
"today" => t("property_hire.today"),
"day" => t("property_hire.day"),
"week" => t("property_hire.week"),
"month" => t("property_hire.month"),
"language" => OrbitHelper.get_site_locale
}, },
"manage_booking_btn" => (OrbitHelper.current_user.nil? ? false : true), "manage_booking_btn" => (OrbitHelper.current_user.nil? ? false : true),
"manage_booking" => t("property_hire.manage_booking"), "manage_booking" => t("property_hire.manage_booking"),
@ -33,8 +44,7 @@ class PropertyHiresController < ApplicationController
end end
def index_data(properties, url) def index_data(properties, url)
ma = ModuleApp.find_by_key("property_hire") is_user_manager = check_if_user_is_manager?
is_user_manager = OrbitHelper.current_user && (OrbitHelper.current_user.is_admin? || OrbitHelper.current_user.is_manager?(ma) || OrbitHelper.current_user.is_sub_manager?(ma))
data = properties.collect do |property| data = properties.collect do |property|
actions = [] actions = []
url_to_show = "#{url}/#{property.to_param}?method=hire" url_to_show = "#{url}/#{property.to_param}?method=hire"
@ -333,8 +343,7 @@ class PropertyHiresController < ApplicationController
end end
allow_no_logins_user = PropertyHireSetting.first.allow_no_logins_user allow_no_logins_user = PropertyHireSetting.first.allow_no_logins_user
all_day_settings = property.all_day_settings.map{|d,settings| [d,settings.map{|s| [s.id.to_s,s.title]}]}.to_h all_day_settings = property.all_day_settings.map{|d,settings| [d,settings.map{|s| [s.id.to_s,s.title]}]}.to_h
ma = ModuleApp.find_by_key("property_hire") is_user_manager = check_if_user_is_manager?
is_user_manager = OrbitHelper.current_user && (OrbitHelper.current_user.is_admin? || OrbitHelper.current_user.is_manager?(ma) || OrbitHelper.current_user.is_sub_manager?(ma))
{ {
"hire" => hire, "hire" => hire,
"property" => property, "property" => property,
@ -344,7 +353,8 @@ class PropertyHiresController < ApplicationController
"allow_no_logins_user" => allow_no_logins_user, "allow_no_logins_user" => allow_no_logins_user,
"carousel_display_style" => "width: #{property.carousel_image_width};", "carousel_display_style" => "width: #{property.carousel_image_width};",
"all_day_settings" => all_day_settings, "all_day_settings" => all_day_settings,
"recover" => recover "recover" => recover,
"language" => OrbitHelper.get_site_locale
} }
end end
@ -354,61 +364,22 @@ class PropertyHiresController < ApplicationController
render :json => data.to_json render :json => data.to_json
end end
def get_bookings def get_bookings
events =[] events =[]
allevents = [] allevents = []
property = @property = Property.find(params[:property_id]) rescue nil if params[:property_id] == "all"
unless property.nil? categories = Page.find(params["page_id"]).categories rescue []
if params[:start].present? && params[:end].present? properties = Property.where(:category_id.in => categories)
sdt = Time.at(params[:start].to_i) properties.each do |property|
edt = Time.at(params[:end].to_i) allevents += get_each_booking(property)
events = PHire.monthly_event(sdt,edt,params[:property_id],property.set_availability)
re = PHire.recurring_event(sdt,edt,params[:property_id],property.set_availability)
events = events.map{|e| e.as_json}
allevents = events.inject(re, :<<)
allevents = allevents.sort_by{|e| e[:start]}
@need_check_events = allevents.map{|e| [e[:date],e[:s_id]]}
@special_unavailable_dates = property.special_unavailable_dates.map{|dt| Date.parse(dt)}
ma = ModuleApp.find_by_key("property_hire")
is_user_manager = OrbitHelper.current_user && (OrbitHelper.current_user.is_admin? || OrbitHelper.current_user.is_manager?(ma) || OrbitHelper.current_user.is_sub_manager?(ma))
if property.set_availability && params[:display_hire_event] == "true"
check_setting = property.set_unavailibility && (property.property_day_settings.where(:enable=>false).count != 0)
@check_start_time = property.start_time.blank? ? "00:00" : property.start_time
@check_end_time = property.end_time.blank? ? "24:00" : property.end_time
@check_start_date = property.start_date ? property.start_date.to_date : nil
@check_end_date = property.end_date ? property.end_date.to_date : nil
if check_setting
if (@check_start_date && @check_start_date > edt) || (@check_end_date && @check_end_date < sdt)
check_setting = false
end
end
all_day_settings = property.all_day_settings.map{|d,settings| [d,settings.map{|s| [s.start_time,s.end_time,s.id.to_s,s.title,s.reservation_limit,s.enable]}]}.to_h
if all_day_settings.count != 0
time_now = Time.zone.now
if is_user_manager
get_start_time = property.p_open_start_time
get_end_time = property.p_open_end_time
else
get_start_time = [sdt,time_now].max
get_end_time = edt
end
if property.set_unavailibility
if property.can_hire_before_months != 0
get_end_time = [time_now + (property.can_hire_before_months).send("month"),edt].min
end
end
if property.can_reserve || is_user_manager
allevents += generate_all_reserve_buttons(get_start_time,get_end_time,all_day_settings,check_setting)
end
end
end
if @special_unavailable_dates.count > 0
allevents += special_unavailable_dates_labels(property)
end
end end
else
property = Property.find(params[:property_id]) rescue nil
allevents = get_each_booking(property)
end end
respond_to do |format| respond_to do |format|
format.html { render json: allevents.to_json }# index.html.erb format.html { render json: allevents.to_json }# index.html.erb
format.json { render json: allevents.to_json } format.json { render json: allevents.to_json }
@ -428,10 +399,7 @@ class PropertyHiresController < ApplicationController
if @special_unavailable_dates.include?(date) if @special_unavailable_dates.include?(date)
available = false available = false
end end
if DateTime.now >= (@property.start_date || DateTime.now - 1.day) && DateTime.now <= (@property.end_date || DateTime.now + 1.month)
need_check_unavailable = (@check_start_date.nil? || date >= @check_start_date) && (@check_end_date.nil? || date <= @check_end_date)
if need_check_unavailable
if @property.hours_restriction > 0 && @is_user_manager === false if @property.hours_restriction > 0 && @is_user_manager === false
check = false check = false
sd = nil sd = nil
@ -463,7 +431,7 @@ class PropertyHiresController < ApplicationController
end end
if available if available
if need_check_unavailable if DateTime.now >= (@property.start_date || DateTime.now - 1.day) && DateTime.now <= (@property.end_date || DateTime.now + 1.month)
available = date > (DateTime.now + (@property.need_hire_before).send(@property.need_hire_before_unit)) available = date > (DateTime.now + (@property.need_hire_before).send(@property.need_hire_before_unit))
end end
end end
@ -510,8 +478,7 @@ class PropertyHiresController < ApplicationController
@endt = endt @endt = endt
@weeknumber = 0 @weeknumber = 0
@monthnumber = 0 @monthnumber = 0
ma = ModuleApp.find_by_key("property_hire") @is_user_manager = check_if_user_is_manager?
@is_user_manager = OrbitHelper.current_user && (OrbitHelper.current_user.is_admin? || OrbitHelper.current_user.is_manager?(ma) || OrbitHelper.current_user.is_sub_manager?(ma))
def generate_events(start_wday,end_wday,type=0,start_validate=false) def generate_events(start_wday,end_wday,type=0,start_validate=false)
if type == 0 if type == 0
(start_wday..end_wday).each_with_index do |wday,i| (start_wday..end_wday).each_with_index do |wday,i|
@ -536,6 +503,7 @@ class PropertyHiresController < ApplicationController
end end
@need_check_events = @need_check_events[(i+1)..-1] @need_check_events = @need_check_events[(i+1)..-1]
settings = @all_day_settings[wday_str] settings = @all_day_settings[wday_str]
if check_events.count != 0 if check_events.count != 0
settings = settings.select do |s| settings = settings.select do |s|
flag = true flag = true
@ -558,6 +526,7 @@ class PropertyHiresController < ApplicationController
if settings.count != 0 if settings.count != 0
@allevents << reserve_calendar_event(@start_date,@display_title,settings) @allevents << reserve_calendar_event(@start_date,@display_title,settings)
end end
end end
@start_date += 1.day @start_date += 1.day
if @start_date > @end_date if @start_date > @end_date
@ -640,4 +609,62 @@ class PropertyHiresController < ApplicationController
return p_hire_params return p_hire_params
end end
def get_each_booking(property)
events =[]
allevents = []
@property = property
unless property.nil?
if params[:start].present? && params[:end].present?
sdt = Time.at(params[:start].to_i)
edt = Time.at(params[:end].to_i)
events = PHire.monthly_event(sdt,edt,property.id.to_s,property.set_availability)
re = PHire.recurring_event(sdt,edt,property.id.to_s,property.set_availability)
events = events.map{|e| e.as_json}
allevents = events.inject(re, :<<)
allevents = allevents.sort_by{|e| e[:start]}
@need_check_events = allevents.map{|e| [e[:date],e[:s_id]]}
@special_unavailable_dates = property.special_unavailable_dates.map{|dt| Date.parse(dt)}
is_user_manager = check_if_user_is_manager?
if property.set_availability && params[:display_hire_event] == "true"
check_setting = property.set_unavailibility && (property.property_day_settings.where(:enable=>false).count != 0)
@check_start_time = property.start_time.blank? ? "00:00" : property.start_time
@check_end_time = property.end_time.blank? ? "24:00" : property.end_time
@check_start_date = property.start_date.to_date rescue nil
@check_end_date = property.end_date.to_date rescue nil
if check_setting
if (@check_start_date > edt rescue false) || (@check_end_date < sdt rescue false)
check_setting = false
end
end
all_day_settings = property.all_day_settings.map{|d,settings| [d,settings.map{|s| [s.start_time,s.end_time,s.id.to_s,s.title,s.reservation_limit,s.enable]}]}.to_h
if all_day_settings.count != 0
time_now = Time.zone.now
if is_user_manager
get_start_time = property.p_open_start_time
get_end_time = property.p_open_end_time
else
get_start_time = [sdt,time_now].max
get_end_time = edt
end
if property.set_unavailibility
if property.can_hire_before_months != 0
get_end_time = [time_now + (property.can_hire_before_months).send("month"),edt].min
end
end
if property.can_reserve || is_user_manager
allevents += generate_all_reserve_buttons(get_start_time,get_end_time,all_day_settings,check_setting)
end
end
end
if @special_unavailable_dates.count > 0
allevents += special_unavailable_dates_labels(property)
end
end
end
return allevents
end
end end

View File

@ -35,7 +35,8 @@ module Admin::PropertyHiresHelper
return {"success" => false, "msg" => I18n.t("property_hire.starting_time_cannot_be_greater_than_ending_time")} return {"success" => false, "msg" => I18n.t("property_hire.starting_time_cannot_be_greater_than_ending_time")}
end end
end end
available_flag = property.is_available_for_hire?(stime, etime, interval, recurring_end_date, time_setting_id, OrbitHelper.current_user.member_profile) mp = OrbitHelper.current_user.member_profile rescue nil
available_flag = property.is_available_for_hire?(stime, etime, interval, recurring_end_date, time_setting_id, mp)
if available_flag == 1 if available_flag == 1
if property.not_yet_hired?(stime, etime, interval, recurring_end_date,params[:phire_id], time_setting_id) if property.not_yet_hired?(stime, etime, interval, recurring_end_date,params[:phire_id], time_setting_id)
data = {"success" => true} data = {"success" => true}
@ -83,6 +84,15 @@ module Admin::PropertyHiresHelper
</div>" </div>"
text.html_safe text.html_safe
end end
def check_if_user_is_manager?
ma = ModuleApp.find_by_key("property_hire")
if OrbitHelper.current_user.nil?
is_user_manager = false
else
is_user_manager = (OrbitHelper.current_user.is_admin? || OrbitHelper.current_user.is_manager?(ma) || OrbitHelper.current_user.is_sub_manager?(ma))
end
return is_user_manager
end
module HireMethod module HireMethod
extend ActionView::Helpers::UrlHelper extend ActionView::Helpers::UrlHelper
extend ActionView::Helpers::TagHelper extend ActionView::Helpers::TagHelper

View File

@ -41,6 +41,8 @@ class PHire
endt = self.end_time endt = self.end_time
recurring = false recurring = false
datet = self.date datet = self.date
classNames = []
viewButton = false
if options[:startt] if options[:startt]
startt = options[:startt] startt = options[:startt]
end end
@ -53,10 +55,17 @@ class PHire
if options[:recurring] if options[:recurring]
recurring = options[:recurring] recurring = options[:recurring]
end end
if !OrbitHelper.current_user.nil?
if OrbitHelper.current_user.member_profile.id.to_s == self.hiring_person_id
classNames = ["mybooking"]
viewButton = true
end
end
title = startt.strftime("%H:%M") + " ~ " + endt.strftime("%H:%M") + " " + self.hiring_person_name title = startt.strftime("%H:%M") + " ~ " + endt.strftime("%H:%M") + " " + self.hiring_person_name
{ {
:id => self.id.to_s, :id => self.id.to_s,
# :title => (self.reason_for_hire.to_s + " "+ self.tmp_reason_for_hire.to_s).html_safe, # :title => (self.reason_for_hire.to_s + " "+ self.tmp_reason_for_hire.to_s).html_safe,
:property_title => self.property.title,
:title => title, :title => title,
:hiring_person_id => self.hiring_person_id, :hiring_person_id => self.hiring_person_id,
:hiring_person_name => self.hiring_person_name, :hiring_person_name => self.hiring_person_name,
@ -69,7 +78,11 @@ class PHire
:error_message => (self.passed ? nil : "Not approved"), :error_message => (self.passed ? nil : "Not approved"),
:s_id=>self.property_day_setting_id.to_s, :s_id=>self.property_day_setting_id.to_s,
:date=>datet, :date=>datet,
:recurring=>recurring :recurring=>recurring,
:classNames => classNames,
:view_button => viewButton,
:view_path => "/#{OrbitHelper.get_site_locale}/admin/property_hires/#{self.id.to_s}/show_booking_details",
:view_path_name => I18n.t("property_hire.view")
} }
end end

View File

@ -148,10 +148,9 @@ class Property
end end
def can_reserve def can_reserve
now = Time.now start_time = self.p_hire_start_time || Time.now
start_time = self.p_hire_start_time || now end_time = self.p_hire_end_time || (Time.now + 1.month)
end_time = self.p_hire_end_time || now return Time.now >= start_time && end_time >= Time.now
return now >= start_time && end_time >= now
end end
def p_hire_fields_enabled def p_hire_fields_enabled
@ -307,7 +306,9 @@ class Property
MemberProfile.find(self.owners) rescue [] MemberProfile.find(self.owners) rescue []
end end
def get_user_total_user_hired_hours(member_profile_id, start_time, end_time) def get_user_total_user_hired_hours(start_time, end_time)
member_profile_id = OrbitHelper.current_user.member_profile.id.to_s rescue nil
return 0 if member_profile_id.nil?
hires = self.p_hires.where(:hiring_person_id => member_profile_id, :start_time.gte => start_time, :end_time.lte => end_time) hires = self.p_hires.where(:hiring_person_id => member_profile_id, :start_time.gte => start_time, :end_time.lte => end_time)
total_hours = 0.0 total_hours = 0.0
hires.each do |hire| hires.each do |hire|
@ -319,9 +320,7 @@ class Property
def is_available_for_hire?(stime, etime, interval = nil, recurring_end_date = nil, time_setting_id = nil, member_profile) def is_available_for_hire?(stime, etime, interval = nil, recurring_end_date = nil, time_setting_id = nil, member_profile)
available = 0 available = 0
ma = ModuleApp.find_by_key("property_hire") is_user_manager = Admin::PropertyHiresController.helpers.check_if_user_is_manager?
user = member_profile.user
is_user_manager = (user.is_admin? || user.is_manager?(ma) || user.is_sub_manager?(ma))
return 1 if is_user_manager == true return 1 if is_user_manager == true
return 1 if self.set_unavailibility == false return 1 if self.set_unavailibility == false
return 1 if self.weekdays.empty? && self.can_hire_before_months == 0 return 1 if self.weekdays.empty? && self.can_hire_before_months == 0
@ -339,11 +338,7 @@ class Property
return 0 return 0
end end
end end
if DateTime.now >= (self.start_date || DateTime.now - 1.day) && DateTime.now <= (self.end_date || DateTime.now + 1.month)
startt = self.start_date.nil? ? stime : self.start_date
endt = self.end_date.nil? ? etime : self.end_date
if (stime >= startt) && (etime <= endt)
if self.hours_restriction > 0 && !user.nil? if self.hours_restriction > 0 && !user.nil?
sd = nil sd = nil
edd = nil edd = nil
@ -355,7 +350,7 @@ class Property
sd = Date.new(stime.year, stime.month, 1) sd = Date.new(stime.year, stime.month, 1)
edd = sd.next_month.prev_day edd = sd.next_month.prev_day
end end
if self.get_user_total_user_hired_hours(member_profile.id.to_s, sd, edd) >= self.hours_restriction if self.get_user_total_user_hired_hours(sd, edd) >= self.hours_restriction
return 0 return 0
end end
end end
@ -642,8 +637,12 @@ class Property
end end
end end
def can_be_hired_frontend def can_be_hired_frontend
user = OrbitHelper.current_user if PropertyHireSetting.first.allow_no_logins_user
self.can_be_hired || (user && (user.is_admin? || (self.owners && self.owners.include?(user.member_profile_id)))) return true
else
user = OrbitHelper.current_user
return self.can_be_hired || (user && (user.is_admin? || (self.owners && self.owners.include?(user.member_profile_id))))
end
end end
def can_be_show_frontend def can_be_show_frontend
user = OrbitHelper.current_user user = OrbitHelper.current_user

View File

@ -18,6 +18,7 @@
<li><a href="<%= copy_admin_property_hire_path(property, :page => params[:page]) %>"><%= t("property_hire.copy") %></a></li> <li><a href="<%= copy_admin_property_hire_path(property, :page => params[:page]) %>"><%= t("property_hire.copy") %></a></li>
<li><a href="<%= custom_fields_admin_property_hire_path(property) %>"><%= t("property_hire.custom_fields") %></a></li> <li><a href="<%= custom_fields_admin_property_hire_path(property) %>"><%= t("property_hire.custom_fields") %></a></li>
<li><a href="<%= fields_display_order_admin_property_hire_path(property) %>"><%= t("property_hire.fields_display_order") %></a></li> <li><a href="<%= fields_display_order_admin_property_hire_path(property) %>"><%= t("property_hire.fields_display_order") %></a></li>
<li><a href="<%= export_reservation_data_admin_property_hire_path(property.id) %>" class="export-xls" data-property-id="<%= property.id.to_s %>"><%= t("property_hire.export_reservation_data") %></a></li>
<li><a href="<%= admin_property_hire_path(property.id, :page => params[:page]) %>" data-method="delete" data-confirm="Are you sure?"><%= t(:delete_) %></a></li> <li><a href="<%= admin_property_hire_path(property.id, :page => params[:page]) %>" data-method="delete" data-confirm="Are you sure?"><%= t(:delete_) %></a></li>
</ul> </ul>
</div> </div>

View File

@ -1,4 +1,74 @@
<%= render_filter @filter_fields, "index_table" %> <%= render_filter @filter_fields, "index_table" %>
<span id="index_table"> <span id="index_table">
<%= render 'index'%> <%= render 'index'%>
</span> </span>
<div id="downloadModal" data-backdrop="static" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="downloadModalLabel" aria-hidden="true">
<div class="modal-header">
<h3 id="downloadModalLabel">Download</h3>
</div>
<div class="modal-body">
<p id="wait-zone" style="text-align: center;">
Please wait while we prepare your download. This may take a while.
<br />
<img src="/assets/spin.gif" />
</p>
<p id="link-zone" style="display: none; text-align: center;">
Please click the link below to download.
<br />
<a href="" id="download-link" target="_blank">Download</a>
</p>
</div>
<div class="modal-footer">
<button class="btn" id="modal-close-btn" style="display:none;" data-dismiss="modal" aria-hidden="true">Close</button>
</div>
</div>
<script type="text/javascript" src="/assets/lib/process.manager.js"></script>
<script type="text/javascript">
var downloadModal = $("#downloadModal"),
checkForThread = null,
waitZone = $("#wait-zone"),
linkZone = $("#link-zone"),
downloadLink = $("a#download-link"),
modalBtn = $("#modal-close-btn"),
processManager = new ProcessManager();
$(document).on("click", ".export-xls", function(){
var link = $(this).attr("href"),
title = null,
id = $(this).data("property-id");
linkZone.hide();
waitZone.show();
modalBtn.hide();
$.ajax({
url : link,
type : "get",
dataType : "json"
}).done(function(data){
title = data.title;
checkForThread = new Process(function(){
$.ajax({
url : "/admin/property_hires/checkforthread",
type : "get",
data : {"property_id" : id, "property_title" : title},
dataType : "json"
}).done(function(data){
if(!data.status){
downloadLink.attr("href", "/uploads/reservation_export/" + id + "/" + title + ".xlsx");
waitZone.hide();
linkZone.show();
modalBtn.show();
checkForThread.kill();
}
})
})
checkForThread.setTimeInterval(1000);
checkForThread.setRepeat(Process.CONSTANTS.REPEAT_INFINITE);
processManager.queue(checkForThread);
})
downloadModal.modal("show");
return false;
})
</script>

View File

@ -33,11 +33,11 @@
<% end %> <% end %>
</td> </td>
<td> <td>
<%
=begin%>
<a href="<%= show_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-info">View</a> <a href="<%= show_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-info">View</a>
<%
=end%>
<a href="<%= delete_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">Delete</a> <a href="<%= delete_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">Delete</a>
</td> </td>
</tr> </tr>

View File

@ -1,7 +1,7 @@
<%= csrf_meta_tag %> <%= csrf_meta_tag %>
<div class="pull-right"> <div class="pull-right">
<a href="?type=" class="btn <%= 'active' if params[:type] != 'Calendar' %>">Table</a> <a href="?type=" class="btn <%= 'active' if params[:type] != 'Calendar' %>"><%= t("property_hire.table") %></a>
<a href="?type=Calendar" class="btn <%= 'active' if params[:type] == 'Calendar' %>">Calendar</a> <a href="?type=Calendar" class="btn <%= 'active' if params[:type] == 'Calendar' %>"><%= t("property_hire.calendar") %></a>
</div> </div>
<hr> <hr>
<% if params[:type] == "Calendar" %> <% if params[:type] == "Calendar" %>
@ -123,14 +123,14 @@
</td> </td>
<td> <td>
<% if can_edit_or_delete?(p_hire.property) %> <% if can_edit_or_delete?(p_hire.property) %>
<a href="<%= edit_hire_admin_property_hire_path(p_hire) %>" class="btn btn-info">Edit</a> <a href="<%= edit_hire_admin_property_hire_path(p_hire) %>" class="btn btn-info"><%= t("property_hire.edit") %></a>
<a href="<%= show_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-info">View</a> <a href="<%= show_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-info"><%= t("property_hire.view") %></a>
<% if p_hire.passed %> <% if p_hire.passed %>
<a href="<%= pass_booking_admin_property_hire_path(p_hire, :page => params[:page], :status => "reject", :ref => "index") %>" class="btn btn-warning">Reject</a> <a href="<%= pass_booking_admin_property_hire_path(p_hire, :page => params[:page], :status => "reject", :ref => "index") %>" class="btn btn-warning"><%= t("property_hire.reject") %></a>
<% else %> <% else %>
<a href="<%= pass_booking_admin_property_hire_path(p_hire, :page => params[:page], :status => "accept", :ref => "index") %>" class="btn btn-success">Accept</a> <a href="<%= pass_booking_admin_property_hire_path(p_hire, :page => params[:page], :status => "accept", :ref => "index") %>" class="btn btn-success"><%= t("property_hire.accept") %></a>
<% end %> <% end %>
<a href="<%= delete_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">Delete</a> <a href="<%= delete_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?"><%= t("property_hire.delete") %></a>
<% end %> <% end %>
</td> </td>
</tr> </tr>

View File

@ -69,13 +69,13 @@
</table> </table>
<a href="" onclick="window.history.back();return false;" class="btn btn-warning">Back</a> <a href="" onclick="window.history.back();return false;" class="btn btn-warning">Back</a>
<% if can_edit_or_delete?(@booking.property) %> <% if can_edit_or_delete?(@booking.property) %>
<a href="<%= edit_hire_admin_property_hire_path(@booking) %>" class="btn btn-info">Edit</a> <a href="<%= edit_hire_admin_property_hire_path(@booking) %>" class="btn btn-info"><%= t("property_hire.edit") %></a>
<% if @booking.passed %> <% if @booking.passed %>
<a href="<%= pass_booking_admin_property_hire_path(@booking, :status => "reject") %>" class="btn btn-warning">Reject</a> <a href="<%= pass_booking_admin_property_hire_path(@booking, :status => "reject") %>" class="btn btn-warning"><%= t("property_hire.reject") %></a>
<% else %> <% else %>
<a href="<%= pass_booking_admin_property_hire_path(@booking, :status => "accept") %>" class="btn btn-success">Accept</a> <a href="<%= pass_booking_admin_property_hire_path(@booking, :status => "accept") %>" class="btn btn-success"><%= t("property_hire.accept") %></a>
<% end %> <% end %>
<a href="<%= delete_booking_details_admin_property_hire_path(@booking, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">Delete</a> <a href="<%= delete_booking_details_admin_property_hire_path(@booking, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?"><%= t("property_hire.delete") %></a>
<% end %> <% end %>

View File

@ -0,0 +1,51 @@
# encoding: utf-8
wb = xlsx_package.workbook
wb.add_worksheet(name: "Reservations") do |sheet|
heading = sheet.styles.add_style(:b => true, :locked => true)
type = sheet.styles.add_style(:i => true)
wrap = sheet.styles.add_style alignment: {wrap_text: true}
row = [
t("property_hire.hiring_person_name"),
t("property_hire.hiring_person_number"),
t("property_hire.hiring_person_email"),
t("property_hire.period"),
t("property_hire.recurring_interval"),
t("property_hire.recurring_end_date"),
t("property_hire.reason_for_hire"),
t("property_hire.note_for_hire")
]
fields_name = ["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"]
fields_name.each do |field_name|
if(property[field_name]["enable"] == "1" rescue false)
row << property.custom_text(field_name,"name")
end
end
sheet.add_row row, :style => heading
property.p_hires.asc(:created_at).each do |entry|
row = [
entry.hirer_name,
entry.hiring_person_number,
entry.hiring_person_email,
entry.period,
entry.recurring_interval,
entry.recurring_end_date,
entry.reason_for_hire,
entry.note_for_hire.html_safe
]
entry.p_hire_field_values.each do |v|
field_info = v.get_field_value rescue {}
if field_info["title"].present? && !field_info["value"].nil? && !field_info["hint"]
row << field_info["title"] + ":&nbsp;" + field_info["value"]
end
end
sheet.add_row row, style: wrap
end
end

View File

@ -3,6 +3,8 @@
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script> <script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script> <script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script> <script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
<script type="text/javascript" src="/assets/locale-all.min.js"></script>
<%= javascript_include_tag "basic/jquery.nanoscroller.js" %> <%= javascript_include_tag "basic/jquery.nanoscroller.js" %>
<% <%
data = action_data data = action_data
@ -14,6 +16,7 @@
allow_no_logins_user = data["allow_no_logins_user"] allow_no_logins_user = data["allow_no_logins_user"]
all_day_settings = data["all_day_settings"] all_day_settings = data["all_day_settings"]
recover = data["recover"] recover = data["recover"]
locale = data["language"]
calendar_type = property.calendar_type.to_i rescue 0 calendar_type = property.calendar_type.to_i rescue 0
right_col = 12 right_col = 12
label_col = 2 label_col = 2
@ -271,7 +274,7 @@
<div class="btn-toolbar" id="navigation"> <div class="btn-toolbar" id="navigation">
<div id="calendar-nav"> <div id="calendar-nav">
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-default btn-sm" id="today_btn">Today</button> <button class="btn btn-default btn-sm" id="today_btn"><%= t("property_hire.today") %></button>
</div> </div>
</div> </div>
</div> </div>
@ -279,9 +282,9 @@
</div> </div>
<div id='sec3' class="btn-toolbar"> <div id='sec3' class="btn-toolbar">
<div class="btn-group calendar_mode"> <div class="btn-group calendar_mode">
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" >day</button> <button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" ><%= t("property_hire.day") %></button>
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" >week</button> <button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" ><%= t("property_hire.week") %></button>
<button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" >month</button> <button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" ><%= t("property_hire.month") %></button>
</div> </div>
<button id="refresh_btn" class="btn btn-default btn-sm"> <button id="refresh_btn" class="btn btn-default btn-sm">
<i class="icons-cycle"></i> <i class="icons-cycle"></i>
@ -328,7 +331,7 @@
<% if property.p_open_end_time %> <% if property.p_open_end_time %>
valid_range["end"] = "<%= (property.p_open_end_time + 1.day).strftime("%Y-%m-%d") %>" valid_range["end"] = "<%= (property.p_open_end_time + 1.day).strftime("%Y-%m-%d") %>"
<% end %> <% end %>
var calendar = new Calendar("#calendar", property_id, valid_range); var calendar = new Calendar("#calendar", property_id, valid_range,"",true, "<%= locale %>");
function pick_hire_date(date,allow_times){ function pick_hire_date(date,allow_times){
if(window.processing_hire) if(window.processing_hire)
return; return;
@ -472,10 +475,10 @@
<% if property_day_setting %> <% if property_day_setting %>
<%= select_tag "#{f.object_name}[time]", options_for_select([[t("property_hire.please_select"),""],[property_day_setting.title,property_day_setting.id.to_s]],hire.property_day_setting_id), :required=>"required" %> <%= select_tag "#{f.object_name}[time]", options_for_select([[t("property_hire.please_select"),""],[property_day_setting.title,property_day_setting.id.to_s]],hire.property_day_setting_id), :required=>"required" %>
<% else %> <% else %>
<% if calendar_type == 0 %> <% if property.calendar_type == 0 %>
<%= f.text_field :time, :value=>t("property_hire.please_choose_date"),:readonly=>"",:onclick=>"goto_calendar()" %> <%= f.text_field :time, :value=>t("property_hire.please_choose_date"),:readonly=>"",:onclick=>"goto_calendar()" %>
<% else %> <% else %>
<%= select_tag "#{f.object_name}[time]", options_for_select([[t("property_hire.please_choose_date"),""]]), :required=>"required" %> <%= select_tag "#{f.object_name}[time]", options_for_select([[t("property_hire.please_choose_date"),""]]), :required=>"required" %>
<% end %> <% end %>
<% end %> <% end %>
</div> </div>

View File

@ -1,6 +1,7 @@
<% OrbitHelper.render_css_in_head(["property_hire_fullcalendar.css","property_hire_calendar"]) %> <% OrbitHelper.render_css_in_head(["property_hire_fullcalendar.css","property_hire_calendar"]) %>
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script> <script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script> <script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
<script type="text/javascript" src="/assets/locale-all.min.js"></script>
<% data = action_data %> <% data = action_data %>
<% if data["manage_booking_btn"] %> <% if data["manage_booking_btn"] %>
<div class="pull-right"> <div class="pull-right">

View File

@ -25,7 +25,7 @@
<button class="btn btn-default btn-sm" id="next_month_btn"> <button class="btn btn-default btn-sm" id="next_month_btn">
<i class="icon-chevron-right"></i> <i class="icon-chevron-right"></i>
</button> </button>
<button class="btn btn-default btn-sm" id="today_btn">Today</button> <button class="btn btn-default btn-sm" id="today_btn"><%= t("property_hire.today") %></button>
</div> </div>
</div> </div>
</div> </div>
@ -33,9 +33,9 @@
</div> </div>
<div id='sec3' class="btn-toolbar"> <div id='sec3' class="btn-toolbar">
<div class="btn-group calendar_mode"> <div class="btn-group calendar_mode">
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" >day</button> <button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" ><%= t("property_hire.day") %></button>
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" >week</button> <button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" ><%= t("property_hire.week") %></button>
<button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" >month</button> <button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" ><%= t("property_hire.month") %></button>
</div> </div>
<button id="refresh_btn" class="btn btn-default btn-sm"> <button id="refresh_btn" class="btn btn-default btn-sm">
<i class="icons-cycle"></i> <i class="icons-cycle"></i>

View File

@ -194,3 +194,16 @@ en:
hours_restriction_message: "This property can only be hired for %{no_of_hours} hours every %{duration}" hours_restriction_message: "This property can only be hired for %{no_of_hours} hours every %{duration}"
time_period_note: Time period user can use reservation service time_period_note: Time period user can use reservation service
available_time_note: Available time period available_time_note: Available time period
calendar: Calendar
table: Table
view: View
reject: Reject
edit: Edit
delete: Delete
accept: Accept
today: Today
day: Day
week: Week
month: Month
all_properties: All Properties
export_reservation_data: Export data

View File

@ -135,11 +135,11 @@ zh_tw:
month: month:
week: week:
recurring_end_date: 週期結束時間 recurring_end_date: 週期結束時間
save: Save save: 送出
my_bookings: My Bookings my_bookings: 我的預約記錄
settings: 設定 settings: 設定
property_hire: 預約 property_hire: 預約
manage_locations: Manage Locations manage_locations: 管理位置
location: 位置 location: 位置
auto_approve: Auto approve auto_approve: Auto approve
property_count: Property Count property_count: Property Count
@ -177,7 +177,7 @@ zh_tw:
hire: 線上預約 hire: 線上預約
view_calendar: 查詢目前預約狀況 view_calendar: 查詢目前預約狀況
image: Property Image image: Property Image
actions: actions:
limit_start_time: 限制開始時間 limit_start_time: 限制開始時間
limit_end_time: 限制結束時間 limit_end_time: 限制結束時間
start_time: 預約開始時間 start_time: 預約開始時間
@ -187,7 +187,7 @@ zh_tw:
hiring_person_name: 預約人姓名 hiring_person_name: 預約人姓名
reason_for_hire: 使用用途 reason_for_hire: 使用用途
note_for_hire: 備註 note_for_hire: 備註
period: Period period: 預約時段
passed: 允許預約 passed: 允許預約
'yes': 'yes':
'no': 'no':
@ -216,3 +216,16 @@ zh_tw:
hours_restriction_message: "每 %{duration}限制僅能預約 %{no_of_hours}" hours_restriction_message: "每 %{duration}限制僅能預約 %{no_of_hours}"
time_period_note: 使用者可以進行預約 time_period_note: 使用者可以進行預約
available_time_note: 可供預約的日期區間 available_time_note: 可供預約的日期區間
calendar: 日曆
table: 列表
view: 查看
reject: 拒絕
edit: 編輯
delete: 刪除
accept: 同意
today: 今天
day: 日模式
week: 週模式
month: 月模式
all_properties: All Properties
export_reservation_data: Export data

View File

@ -7,7 +7,8 @@ Rails.application.routes.draw do
patch "/xhr/property_hires/make_booking" => "property_hires#make_booking" patch "/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
resources :property_hires do get "property_hires/checkforthread", to: "property_hires#checkforthread"
resources :property_hires do
member do member do
get 'copy' get 'copy'
get "edit_location" get "edit_location"
@ -20,10 +21,11 @@ Rails.application.routes.draw do
patch "update_hire" patch "update_hire"
get "custom_fields" get "custom_fields"
get "fields_display_order" get "fields_display_order"
get "export_reservation_data"
post "update_fields_display_order" post "update_fields_display_order"
patch "update_fields_display_order" patch "update_fields_display_order"
end end
collection do collection do
get "my_bookings" get "my_bookings"
get "settings" get "settings"
patch "settings" patch "settings"

View File

@ -2,3 +2,26 @@
# task :property_hire do # task :property_hire do
# # Task goes here # # Task goes here
# end # end
namespace :property_hire_tasks do
task :prepare_download,[:property_id, :url] => :environment do |task,args|
id = args.property_id
I18n.locale = :zh_tw
property = Property.find(id)
ac = ActionController::Base.new()
host_url = Site.first.root_url
if host_url == "http://"
host_url = "http://#{args.url}"
end
xlsx = ac.render_to_string handlers: [:axlsx], formats: [:xlsx], template: "property_hire_export/export", locals: {property: property, site_in_use_locales: Site.first.in_use_locales, url: host_url}
dirname = "public/uploads/reservation_export/#{id}"
FileUtils.mkdir_p(dirname) unless File.exist?(dirname)
f = "#{dirname}/#{property.title.gsub(/[ "'*@#$%^&()+=;:.,?>|\\\/<~_!:,、。!?;「」〈〉【】/]/,'')}.xlsx"
if File.exist?(f)
File.delete(f)
end
file = File.open(f, "w")
xlsx.force_encoding("utf-8")
file.write(xlsx)
end
end