feat(lifecycle): wire Captain::Reservation lifecycle hooks

Add after_commit callbacks to call Captain::Lifecycle::Scheduler on
create, status change (cancelled/no_show), and check_in_at change.
Each handler wraps in rescue StandardError to preserve existing behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Rodribm10 2026-04-15 01:37:23 -03:00
parent bb4631f427
commit 8e0a06246b
2 changed files with 69 additions and 0 deletions

View File

@ -90,6 +90,9 @@ class Captain::Reservation < ApplicationRecord
after_commit :sync_conversation_marker_snapshot
after_create_commit :update_contact_reservation_metadata
after_create_commit :post_internal_reservation_note
after_create_commit :schedule_lifecycle_rules
after_update_commit :handle_lifecycle_status_change, if: :saved_change_to_status?
after_update_commit :handle_lifecycle_checkin_change, if: :saved_change_to_check_in_at?
def ui_status
Captain::Reservations::MarkerBuilder.ui_status(status)
@ -160,6 +163,26 @@ class Captain::Reservation < ApplicationRecord
end
# rubocop:enable Metrics/AbcSize,Metrics/MethodLength
def schedule_lifecycle_rules
Captain::Lifecycle::Scheduler.schedule_for(self)
rescue StandardError => e
Rails.logger.error("[Lifecycle] schedule_for failed for reservation #{id}: #{e.class} #{e.message}")
end
def handle_lifecycle_status_change
return unless %w[cancelled no_show].include?(status.to_s)
Captain::Lifecycle::Scheduler.cancel_pending(self)
rescue StandardError => e
Rails.logger.error("[Lifecycle] cancel_pending failed for reservation #{id}: #{e.class} #{e.message}")
end
def handle_lifecycle_checkin_change
Captain::Lifecycle::Scheduler.reschedule_for_checkin_change(self)
rescue StandardError => e
Rails.logger.error("[Lifecycle] reschedule failed for reservation #{id}: #{e.class} #{e.message}")
end
# Atualiza campos visiveis no painel lateral do Chatwoot (custom_attributes)
# pra que a recepcionista veja num relance:
# ultima_suite, ultima_permanencia, ultima_reserva_em, total_reservas

View File

@ -0,0 +1,46 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Captain::Reservation, '#lifecycle_hooks' do
let(:account) { create(:account) }
let(:brand) { create(:captain_brand, account: account) }
let(:unit) { Captain::Unit.create!(account: account, name: 'Test', brand: brand) }
describe 'after create' do
it 'calls Scheduler.schedule_for' do
expect(Captain::Lifecycle::Scheduler).to receive(:schedule_for).with(kind_of(described_class))
create(:captain_reservation,
account: account, unit: unit,
check_in_at: 2.hours.from_now, check_out_at: 10.hours.from_now)
end
end
describe 'after update (status → cancelled)' do
let(:reservation) do
allow(Captain::Lifecycle::Scheduler).to receive(:schedule_for)
create(:captain_reservation,
account: account, unit: unit,
check_in_at: 2.hours.from_now, check_out_at: 10.hours.from_now)
end
it 'cancels pending deliveries' do
expect(Captain::Lifecycle::Scheduler).to receive(:cancel_pending).with(reservation)
reservation.update!(status: 'cancelled')
end
end
describe 'after update (check_in_at changed)' do
let(:reservation) do
allow(Captain::Lifecycle::Scheduler).to receive(:schedule_for)
create(:captain_reservation,
account: account, unit: unit,
check_in_at: 2.hours.from_now, check_out_at: 10.hours.from_now)
end
it 'reschedules checkin-based deliveries' do
expect(Captain::Lifecycle::Scheduler).to receive(:reschedule_for_checkin_change).with(reservation)
reservation.update!(check_in_at: 3.hours.from_now)
end
end
end