ホスト用カレンダーで設定した内容が検索結果や予約カレンダーに反映するようにします。
記述更新 app\controllers\pages_controller.rb
48行目から53行目の内容を以下の記述に更新します。
not_available_in_calendar = Calendar.where( "room_id = ? AND status = ? AND day <= ? AND day >= ?", room.id, 1, end_date, start_date ).limit(1) if not_available.length > 0 || not_available_in_calendar.length > 0 @arrRooms.delete(room) end
app\controllers\pages_controller.rb
class PagesController < ApplicationController def home @rooms = Room.where(active: true).limit(3) end def search # ステップ 1 if params[:search].present? && params[:search].strip != "" session[:loc_search] = params[:search] end arrResult = Array.new # ステップ 2 if session[:loc_search] && session[:loc_search] != "" @rooms_address = Room.where(active: true).near(session[:loc_search], 5, order: 'distance') else @rooms_address = Room.where(active: true).all end # ステップ 3 @search = @rooms_address.ransack(params[:q]) @rooms = @search.result @arrRooms = @rooms.to_a # ステップ 4 if (params[:start_date] && params[:end_date] && !params[:start_date].empty? && !params[:end_date].empty?) start_date = Date.parse(params[:start_date]) end_date = Date.parse(params[:end_date]) @rooms.each do |room| not_available = room.reservations.where( "((? <= start_date AND start_date <= ?) OR (? <= end_date AND end_date <= ?) OR (start_date < ? AND ? < end_date)) AND status = ?", start_date, end_date, start_date, end_date, start_date, end_date, 1 ).limit(1) not_available_in_calendar = Calendar.where( "room_id = ? AND status = ? AND day <= ? AND day >= ?", room.id, 1, end_date, start_date ).limit(1) if not_available.length > 0 || not_available_in_calendar.length > 0 @arrRooms.delete(room) end end end end end
記述更新1 app\controllers\rooms_controller.rb
66行目の「preload()」メソッドの内容を以下の記述に更新します。
def preload today = Date.today reservations = @room.reservations.where("(start_date >= ? OR end_date >= ?) AND status = ?", today, today, 1) unavailable_dates = @room.calendars.where("status = ? AND day > ?", 1, today) special_dates = @room.calendars.where("status = ? AND day > ? AND price <> ?",0, today, @room.price) render json: { reservations: reservations, unavailable_dates: unavailable_dates, special_dates: special_dates } end
記述更新2 app\controllers\rooms_controller.rb
91行目のプライベートメソッド「is_conflict()」の内容を以下の記述に変更しています。
def is_conflict(start_date, end_date, room) check = room.reservations.where("(? < start_date AND end_date < ?) AND status = ?", start_date, end_date, 1) check_2 = room.calendars.where("day BETWEEN ? AND ? AND status = ?", start_date, end_date, 1).limit(1) check.size > 0 || check_2.size > 0 ? true : false end
app\controllers\rooms_controller.rb
class RoomsController < ApplicationController before_action :set_room, except: [:index, :new, :create] before_action :authenticate_user!, except: [:show] before_action :is_authorised, only: [:listing, :pricing, :description, :photo_upload, :amenities, :location, :update] def index @rooms = current_user.rooms end def new @room = current_user.rooms.build end def create if !current_user.is_active_host return redirect_to payout_method_path, alert: "振込口座の登録を先に行ってください。" end @room = current_user.rooms.build(room_params) if @room.save redirect_to listing_room_path(@room), notice: "保存しました。" else flash[:alert] = "問題が発生しました。" render :new end end def show @photos = @room.photos @guest_reviews = @room.guest_reviews end def listing end def pricing end def description end def photo_upload @photos = @room.photos end def amenities end def location end def update new_params = room_params new_params = room_params.merge(active: true) if is_ready_room if @room.update(new_params) flash[:notice] = "保存しました。" else flash[:alert] = "問題が発生しました。" end redirect_back(fallback_location: request.referer) end # 予約 開始日のAJAX def preload today = Date.today reservations = @room.reservations.where("(start_date >= ? OR end_date >= ?) AND status = ?", today, today, 1) unavailable_dates = @room.calendars.where("status = ? AND day > ?", 1, today) special_dates = @room.calendars.where("status = ? AND day > ? AND price <> ?",0, today, @room.price) render json: { reservations: reservations, unavailable_dates: unavailable_dates, special_dates: special_dates } end # 予約 終了日のAJAX def preview start_date = Date.parse(params[:start_date]) end_date = Date.parse(params[:end_date]) output = { conflict: is_conflict(start_date, end_date, @room) } render json: output end private # 予約 プライベートメソッド def is_conflict(start_date, end_date, room) check = room.reservations.where("(? < start_date AND end_date < ?) AND status = ?", start_date, end_date, 1) check_2 = room.calendars.where("day BETWEEN ? AND ? AND status = ?", start_date, end_date, 1).limit(1) check.size > 0 || check_2.size > 0 ? true : false end def set_room @room = Room.find(params[:id]) end def is_authorised redirect_to root_path, alert: "権限がありません。" unless current_user.id == @room.user_id end def is_ready_room !@room.active && !@room.price.blank? && !@room.listing_name.blank? && !@room.photos.blank? && !@room.address.blank? end def room_params params.require(:room).permit(:home_type, :room_type, :accommodate, :bed_room, :bath_room, :listing_name, :summary, :address, :is_tv, :is_kitchen, :is_air, :is_heating, :is_internet, :price, :active, :instant) end end
記述追加 app\controllers\reservations_controller.rb
21行目と35行目に記述を追加し、32行目をコメントアウトしています。
コードをコピーしてファイルを置き換えて下さい。
class ReservationsController < ApplicationController before_action :authenticate_user! before_action :set_reservation, only: [:approve, :decline] def create room = Room.find(params[:room_id]) if current_user == room.user flash[:alert] = "オーナーが予約することはできません。" elsif current_user.stripe_id.blank? flash[:alert] = "予約する前にクレジットカードを登録する必要があります。" return redirect_to payment_method_path else start_date = Date.parse(reservation_params[:start_date]) end_date = Date.parse(reservation_params[:end_date]) days = (end_date - start_date).to_i special_dates = room.calendars.where( "status = ? AND day BETWEEN ? AND ? AND price <> ?", 0, start_date, end_date, room.price ) if days == 0 flash[:alert] = "宿泊日数が1泊以上でなければ予約することはできません。" else @reservation = current_user.reservations.build(reservation_params) @reservation.room = room @reservation.price = room.price #@reservation.total = room.price * days #@reservation.save @reservation.total = room.price * (days - special_dates.count) special_dates.each do |date| @reservation.total += date.price end if @reservation.Waiting! if room.Request? flash[:notice] = "予約承認申請を送信しました。予約が承認されるまでしばらくお待ち下さい。" else charge(room, @reservation) end else flash[:alert] = "ご予約できません!" end end end redirect_to room end # 宿泊者用予約確認 def your_trips @trips = current_user.reservations.order(start_date: :asc) end #ホスト用予約確認 def your_reservations @rooms = current_user.rooms end def approve charge(@reservation.room, @reservation) redirect_to your_reservations_path end def decline @reservation.Declined! redirect_to your_reservations_path end private def send_sms(room, reservation) @client = Twilio::REST::Client.new @client.messages.create( from: '+12056565281', to: room.user.phone_number, body: "#{reservation.user.fullname}様、#{room.listing_name}を予約しました。" ) end def charge(room, reservation) host_amount = (reservation.total * 0.8).to_i # 売上の80%がホストに入る if !reservation.user.stripe_id.blank? customer = Stripe::Customer.retrieve(reservation.user.stripe_id) charge = Stripe::Charge.create( :customer => customer.id, :amount => reservation.total, :description => room.listing_name, :currency => "jpy", transfer_data: { amount: host_amount, destination: room.user.merchant_id, # ホストのストライプID }, ) if charge reservation.Approved! send_sms(room, reservation) if reservation.user.setting.enable_sms ReservationMailer.send_email_to_guest(reservation.user, room, reservation).deliver_later if reservation.user.setting.enable_email flash[:notice] = "お支払い手続きが完了し、ご予約されました。お越しをお待ちしております!" else reservation.Declined! flash[:notice] = "お支払い手続きができません。予約ができませんでした。" end end rescue Stripe::CardError => e reservation.declined! flash[:alert] = e.message end def set_reservation @reservation = Reservation.find(params[:id]) end def reservation_params params.require(:reservation).permit(:start_date, :end_date) end end
記述更新 app\views\reservations\_form.html.erb
32行目に記述を追加しています。
55行目からのスクリプトを大幅に変更しています。
コードをコピーしてファイルを置き換えてください。
<div class="panel panel-default"> <div class="panel-heading"> <!-- 承認制の場合はアイコンを表示しない --> <span><% if @room.Instant? %><i class="fa fa-bolt" style="color: #ffb400"></i><% end %></span> <span class="pull-right">1泊 <%= number_to_currency(@room.price) %></span> <br/> </div> <div class="panel-body"> <%= form_for([@room, @room.reservations.new]) do |f| %> <div class="row"> <div class="col-md-6"> <label>チェックイン</label> <%= f.text_field :start_date, readonly: true, placeholder: "チェックイン日", class: "form-control datepicker" %> </div> <div class="col-md-6"> <label>チェックアウト</label> <%= f.text_field :end_date, readonly: true, placeholder: "チェックアウト日", class: "form-control datepicker", disabled: true %> </div> </div> <h4 class="message-alert text-center"><span id="message"></span></h4> <div id="preview" style="display: none"> <table class="reservation-table"> <tbody> <tr> <td>宿泊費用</td> <td class="text-right", style="white-space: nowrap"><%= number_to_currency(@room.price) %></td> </tr> <tr> <td>宿泊日数</td> <td class="text-right"><span id="reservation_nights"></span>泊</td> </tr> <tr id="special_details"> <td colspan="2" class="total"> 特別価格<br/> <ul id="special_list"></ul> </td> </tr> <tr> <td class="total">合計金額</td> <td class="text-right", style="white-space: nowrap"><span id="reservation_total"></span>円</td> </tr> </tbody> </table> </div> <br/> <% if @room.Instant? %> <%= f.submit "予約する", id: "btn_book", class: "btn btn-normal btn-block", disabled: true %> <% else %> <%= f.submit "予約承認申請を送る", id: "btn_book", class: "btn btn-normal btn-block", disabled: true %> <% end %> <% end %> </div> </div> <script> function checkDate(date) { dmy = date.getDate() + "-" + (date.getMonth() + 1) + "-" + date.getFullYear(); return [$.inArray(dmy, unavailableDates) == -1]; } $(function() { unavailableDates = []; specialDates = []; function specialCheck() { var start_date = $('#reservation_start_date').datepicker('getDate'); var end_date = $('#reservation_end_date').datepicker('getDate'); //2日選択すると1泊になる var nights = (end_date - start_date)/1000/60/60/24 var input = { 'start_date': start_date, 'end_date': end_date } $.ajax({ url: '<%= preview_room_path(@room) %>', data: input, success: function (data) { if (data.conflict) { $('#message').text("この日付はご利用できません。"); $('#preview').hide(); $('#btn_book').attr('disabled', true); } else { $('#message').text(""); $('#preview').show(); $('#btn_book').attr('disabled', false); //----------- 更新 始まり $('#special_list').empty(); var selectedDates = []; // ステップ 1: 選択した日付の配列を作成します while (start_date <= end_date) { selectedDates.push($.datepicker.formatDate('d-m-yy', new Date(start_date))); start_date.setDate(start_date.getDate() + 1); }; // ステップ 2: 特別な日付の配列を作成します var selectedSpecialDate = specialDates.filter(function(sDate){ var d = $.datepicker.formatDate('d-m-yy',new Date(sDate.day)); return selectedDates.indexOf(d) !== -1; }); var total = (nights - selectedSpecialDate.length) * <%= @room.price %>; if (selectedSpecialDate.length > 0) { $('#special_details').show(); selectedSpecialDate.map(function (date) { total += date.price $('#special_list').append('<li class="text-right">('+ date.day + '): ' + date.price +'円</li>') }); } else { $('#special_details').hide(); } //----------- 更新 終わり $('#reservation_nights').text(nights); $('#reservation_total').text(total); } } }); } $.ajax({ url: '<%= preload_room_path(@room) %>', dateTyp: 'json', success: function(data) { specialDates = data.special_dates; $.each(data.reservations, function(arrID, arrValue) { for(var d = new Date(arrValue.start_date); d <= new Date(arrValue.end_date); d.setDate(d.getDate() + 1)) { unavailableDates.push($.datepicker.formatDate('d-m-yy', d)); } }); $.each(data.unavailable_dates, function (arrID, arrValue) { unavailableDates.push($.datepicker.formatDate('d-m-yy', new Date(arrValue.day))); }); $('#reservation_start_date').datepicker({ dateFormat: 'dd-mm-yy', //今日から3ヶ月先まで予約可能 minDate: 0, maxDate: '3m', beforeShowDay: checkDate, onSelect: function(selected) { $('#reservation_end_date').datepicker("option", "minDate", selected); $('#reservation_end_date').attr("disabled", false); specialCheck(); } }); $('#reservation_end_date').datepicker({ dateFormat: 'dd-mm-yy', //今日から3ヶ月先まで予約可能 minDate: 0, maxDate: '3m', beforeShowDay: checkDate, onSelect: function(selected) { $('#reservation_start_date').datepicker("option", "maxDate", selected); specialCheck(); } }); } }); }); </script>
ブラウザ確認
http://localhost:3000/host_calendar
ホスト用カレンダーで特別価格や利用不可を設定します。
予約カレンダーの連動を確認します。
特別価格の反映を確認します。