diff --git a/enterprise/app/services/captain/lifecycle/event_resolver.rb b/enterprise/app/services/captain/lifecycle/event_resolver.rb new file mode 100644 index 000000000..376ed34d7 --- /dev/null +++ b/enterprise/app/services/captain/lifecycle/event_resolver.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class Captain::Lifecycle::EventResolver + UNSUPPORTED_IN_MVP = %w[checkin.detected checkout.detected].freeze + + def self.resolve(reservation, event_name) + return nil if UNSUPPORTED_IN_MVP.include?(event_name) + + case event_name + when 'reservation.confirmed' + reservation.updated_at + when 'checkin.scheduled_at' + reservation.check_in_at + when 'checkout.scheduled_at' + reservation.check_out_at + when 'reservation.cancelled' + reservation.updated_at if reservation.status.to_s == 'cancelled' + when 'reservation.no_show' + reservation.check_in_at&.+(1.hour) + else + raise ArgumentError, "unknown event: #{event_name.inspect}" + end + end +end diff --git a/spec/enterprise/services/captain/lifecycle/event_resolver_spec.rb b/spec/enterprise/services/captain/lifecycle/event_resolver_spec.rb new file mode 100644 index 000000000..aba865d7a --- /dev/null +++ b/spec/enterprise/services/captain/lifecycle/event_resolver_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Captain::Lifecycle::EventResolver do + let(:reservation) do + build(:captain_reservation, + check_in_at: Time.zone.parse('2026-04-20 22:00:00'), + check_out_at: Time.zone.parse('2026-04-21 12:00:00'), + updated_at: Time.zone.parse('2026-04-19 10:00:00')) + end + + describe '.resolve' do + it 'returns check_in_at for checkin.scheduled_at' do + expect(described_class.resolve(reservation, 'checkin.scheduled_at')) + .to eq(reservation.check_in_at) + end + + it 'returns check_out_at for checkout.scheduled_at' do + expect(described_class.resolve(reservation, 'checkout.scheduled_at')) + .to eq(reservation.check_out_at) + end + + it 'returns updated_at for reservation.confirmed' do + expect(described_class.resolve(reservation, 'reservation.confirmed')) + .to eq(reservation.updated_at) + end + + it 'returns nil for checkin.detected (not yet supported)' do + expect(described_class.resolve(reservation, 'checkin.detected')).to be_nil + end + + it 'returns nil for checkout.detected (not yet supported)' do + expect(described_class.resolve(reservation, 'checkout.detected')).to be_nil + end + + it 'raises for unknown event' do + expect { described_class.resolve(reservation, 'unknown.event') } + .to raise_error(ArgumentError, /unknown event/) + end + end +end