diff --git a/enterprise/app/services/captain/lifecycle/context_builder.rb b/enterprise/app/services/captain/lifecycle/context_builder.rb new file mode 100644 index 000000000..f78d9f95b --- /dev/null +++ b/enterprise/app/services/captain/lifecycle/context_builder.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +class Captain::Lifecycle::ContextBuilder + def self.build(reservation) + new(reservation).build + end + + def initialize(reservation) + @reservation = reservation + @contact = reservation.contact + @unit = reservation.unit + end + + def build + { + 'customer' => customer_context, + 'reservation' => reservation_context, + 'hotel' => hotel_context + } + end + + private + + def customer_context + name = @contact&.name.to_s + { + 'name' => name, + 'first_name' => name.split.first.to_s, + 'phone' => @contact&.phone_number.to_s, + 'cpf' => @contact&.custom_attributes.to_h['cpf'].to_s + } + end + + def reservation_context + { + 'suite' => @reservation.suite_identifier.to_s, + 'unit_name' => @unit&.name.to_s, + 'check_in_at' => format_datetime(@reservation.check_in_at), + 'check_out_at' => format_datetime(@reservation.check_out_at), + 'amount' => format_money(@reservation.total_amount), + 'permanencia' => @reservation.metadata.to_h['permanencia'].to_s + } + end + + def hotel_context + (@unit&.concierge_variables || {}).stringify_keys + end + + def format_datetime(value) + return '' unless value + + value.in_time_zone('America/Sao_Paulo').strftime('%d/%m/%Y %H:%M') + end + + def format_money(value) + ActiveSupport::NumberHelper.number_to_currency( + value.to_f, + unit: 'R$ ', + separator: ',', + delimiter: '.' + ) + end +end diff --git a/spec/enterprise/services/captain/lifecycle/context_builder_spec.rb b/spec/enterprise/services/captain/lifecycle/context_builder_spec.rb new file mode 100644 index 000000000..6584e6247 --- /dev/null +++ b/spec/enterprise/services/captain/lifecycle/context_builder_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Captain::Lifecycle::ContextBuilder do + let(:account) { create(:account) } + let(:brand) { create(:captain_brand, account: account) } + let(:unit) do + Captain::Unit.create!( + account: account, + brand: brand, + name: 'Águas Lindas', + concierge_config: { + 'persona_name' => 'Sofia', + 'variables' => { 'wifi_password' => 'hotel1001', 'menu_link' => 'https://menu.x' } + } + ) + end + let(:contact) { create(:contact, account: account, name: 'João Silva', phone_number: '+5561999999999') } + let(:reservation) do + create(:captain_reservation, + account: account, + unit: unit, + contact: contact, + suite_identifier: 'Alexa', + total_amount: 160.0, + check_in_at: Time.zone.parse('2026-04-20 22:00:00'), + check_out_at: Time.zone.parse('2026-04-21 12:00:00'), + metadata: { 'permanencia' => 'Pernoite' }) + end + + describe '.build' do + subject(:ctx) { described_class.build(reservation) } + + it 'includes customer.name and first_name' do + expect(ctx['customer']['name']).to eq('João Silva') + expect(ctx['customer']['first_name']).to eq('João') + end + + it 'includes customer.phone' do + expect(ctx['customer']['phone']).to eq('+5561999999999') + end + + it 'includes reservation.suite' do + expect(ctx['reservation']['suite']).to eq('Alexa') + end + + it 'includes reservation.unit_name' do + expect(ctx['reservation']['unit_name']).to eq('Águas Lindas') + end + + it 'formats reservation.amount as BRL' do + expect(ctx['reservation']['amount']).to include('R$') + expect(ctx['reservation']['amount']).to include('160') + end + + it 'includes reservation.permanencia' do + expect(ctx['reservation']['permanencia']).to eq('Pernoite') + end + + it 'includes hotel.wifi_password from unit variables' do + expect(ctx['hotel']['wifi_password']).to eq('hotel1001') + end + + it 'includes hotel.menu_link from unit variables' do + expect(ctx['hotel']['menu_link']).to eq('https://menu.x') + end + end +end