diff --git a/app/controllers/public/api/v1/captain/public_reservations_controller.rb b/app/controllers/public/api/v1/captain/public_reservations_controller.rb index 6b707b673..a93eda6e5 100644 --- a/app/controllers/public/api/v1/captain/public_reservations_controller.rb +++ b/app/controllers/public/api/v1/captain/public_reservations_controller.rb @@ -5,12 +5,104 @@ class Public::Api::V1::Captain::PublicReservationsController < ActionController::API before_action :authenticate_reserva_token! - def create - render json: { error: 'not_implemented' }, status: :not_implemented + def create # rubocop:disable Metrics/AbcSize,Metrics/MethodLength + unit = Captain::Unit.find_by(id: params[:chatwoot_unit_id]) + return render(json: { error: 'unit_not_found' }, status: :not_found) if unit.nil? + return render(json: { error: 'unit_has_no_inbox' }, status: :unprocessable_entity) if unit.inbox_id.blank? + return render(json: { error: 'unit_missing_inter_credentials' }, status: :unprocessable_entity) unless unit.inter_credentials_present? + + customer = params[:customer] || {} + return render(json: { error: 'customer_required' }, status: :unprocessable_entity) if customer[:name].blank? + + account = unit.account + inbox = Inbox.find(unit.inbox_id) + + contact_inbox = ::ContactInboxWithContactBuilder.new( + source_id: "reserva1001-#{SecureRandom.uuid}", + inbox: inbox, + contact_attributes: { + name: customer[:name], + phone_number: customer[:phone].presence, + email: customer[:email].presence, + additional_attributes: { + cpf: customer[:cpf].presence, + origem: 'reserva-1001' + }.compact + } + ).perform + + conversation = ConversationBuilder.new( + params: ActionController::Parameters.new( + additional_attributes: { + source: 'reserva-1001', + reserva_category: params[:category], + reserva_stay_type: params[:stay_type], + reserva_checkin_at: params[:checkin_at] + } + ), + contact_inbox: contact_inbox + ).perform + + initial_note = build_initial_note(params) + + Messages::MessageBuilder.new( + nil, + conversation, + { content: initial_note, message_type: 'outgoing', private: true } + ).perform + + reservation = Captain::Reservation.create!( + account: account, + inbox: inbox, + contact: contact_inbox.contact, + contact_inbox: contact_inbox, + conversation: conversation, + unit: unit, + suite_identifier: "#{params[:category]} · #{params[:stay_type]}", + check_in_at: params[:checkin_at], + check_out_at: checkout_from(params[:checkin_at], params[:stay_type]), + status: :draft, + payment_status: 'pending', + total_amount: (params[:total_cents].to_i / 100.0), + metadata: { + origem: 'reserva-1001', + category: params[:category], + stay_type: params[:stay_type], + deposit_cents: params[:deposit_cents].to_i, + notes: params[:notes] + } + ) + + deposit_amount = (params[:deposit_cents].to_i / 100.0) + charge = Captain::Inter::CobService.new(reservation, amount: deposit_amount).call + reservation.update!(status: :pending_payment) + + render json: { + reservation_id: reservation.id, + conversation_id: conversation.id, + pix: { + txid: charge.txid, + copia_e_cola: charge.pix_copia_e_cola, + qrcode_base64: nil, + expires_at: (Time.current + Captain::PixCharge::EXPIRATION_SECONDS.seconds).iso8601 + } + }, status: :created + rescue ActiveRecord::RecordInvalid => e + Rails.logger.error("[PublicReservations] validation error: #{e.message}") + render json: { error: 'validation_failed', details: e.record.errors.full_messages }, status: :unprocessable_entity + rescue StandardError => e + Rails.logger.error("[PublicReservations] unexpected error: #{e.class} - #{e.message}") + render json: { error: 'internal_error', message: e.message }, status: :internal_server_error end def status - render json: { error: 'not_implemented' }, status: :not_implemented + reservation = Captain::Reservation.find_by(id: params[:id]) + return render(json: { error: 'not_found' }, status: :not_found) if reservation.nil? + + render json: { + reservation_id: reservation.id, + status: reservation.payment_status + } end private @@ -28,4 +120,28 @@ class Public::Api::V1::Captain::PublicReservationsController < ActionController: render json: { error: 'unauthorized' }, status: :unauthorized end + + def build_initial_note(payload) + <<~NOTE.strip + Nova reserva via reserva.1001 + Categoria: #{payload[:category]} + Permanencia: #{payload[:stay_type]} + Check-in: #{payload[:checkin_at]} + Total: R$ #{format('%.2f', payload[:total_cents].to_i / 100.0)} + Entrada (PIX 50%): R$ #{format('%.2f', payload[:deposit_cents].to_i / 100.0)} + Observacao: #{payload[:notes].presence || '-'} + NOTE + end + + def checkout_from(checkin_iso, stay_type) + checkin = Time.zone.parse(checkin_iso.to_s) + hours = case stay_type.to_s.downcase + when '2hrs' then 2 + when '3hrs' then 3 + when 'pernoite' then 12 + when 'diaria', 'diária' then 24 + else 4 # default: 4hrs (inclui '4hrs' e qualquer outro valor) + end + checkin + hours.hours + end end