feat(lifecycle): add Guards::Base e 3 guards simples (ReservationActive, OptOutLabel, MaxPerReservation)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f6aa39921a
commit
823008a1cd
4
enterprise/app/services/captain/lifecycle/guards.rb
Normal file
4
enterprise/app/services/captain/lifecycle/guards.rb
Normal file
@ -0,0 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Captain::Lifecycle::Guards
|
||||
end
|
||||
27
enterprise/app/services/captain/lifecycle/guards/base.rb
Normal file
27
enterprise/app/services/captain/lifecycle/guards/base.rb
Normal file
@ -0,0 +1,27 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Captain::Lifecycle::Guards::Base
|
||||
def initialize(delivery)
|
||||
@delivery = delivery
|
||||
@reservation = delivery.captain_reservation
|
||||
@account = delivery.account
|
||||
end
|
||||
|
||||
def check
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def pass
|
||||
{ action: :pass }
|
||||
end
|
||||
|
||||
def skip(reason)
|
||||
{ action: :skip, reason: reason }
|
||||
end
|
||||
|
||||
def reschedule(new_fire_at)
|
||||
{ action: :reschedule, fire_at: new_fire_at }
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Captain::Lifecycle::Guards::MaxPerReservation < Captain::Lifecycle::Guards::Base
|
||||
CAP = 5
|
||||
|
||||
def check
|
||||
count = Captain::Lifecycle::Delivery.count_sent_for_reservation(@reservation.id)
|
||||
return skip('max_reached') if count >= CAP
|
||||
|
||||
pass
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Captain::Lifecycle::Guards::OptOutLabel < Captain::Lifecycle::Guards::Base
|
||||
def check
|
||||
config = Captain::Lifecycle::Config.for_account(@account)
|
||||
label = config.opt_out_label
|
||||
return pass if label.blank?
|
||||
|
||||
contact = @reservation.contact
|
||||
return pass if contact.blank?
|
||||
|
||||
return skip('opt_out_label') if contact.label_list.include?(label.title)
|
||||
|
||||
pass
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Captain::Lifecycle::Guards::ReservationActive < Captain::Lifecycle::Guards::Base
|
||||
BLOCKING_STATUSES = %w[cancelled no_show].freeze
|
||||
|
||||
def check
|
||||
return skip('reservation_cancelled') if BLOCKING_STATUSES.include?(@reservation.status.to_s)
|
||||
|
||||
pass
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,38 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Lifecycle::Guards::MaxPerReservation do
|
||||
subject(:guard) { described_class.new(delivery) }
|
||||
|
||||
let(:reservation) { create(:captain_reservation) }
|
||||
let(:delivery) { create(:captain_lifecycle_delivery, captain_reservation: reservation) }
|
||||
|
||||
it 'passes with 0 sent deliveries' do
|
||||
expect(guard.check).to eq(action: :pass)
|
||||
end
|
||||
|
||||
it 'passes with 4 sent deliveries' do
|
||||
4.times do
|
||||
create(:captain_lifecycle_delivery,
|
||||
captain_reservation: reservation, status: 'sent', origin: 'scheduled_lifecycle')
|
||||
end
|
||||
expect(guard.check).to eq(action: :pass)
|
||||
end
|
||||
|
||||
it 'skips at 5 sent deliveries' do
|
||||
5.times do
|
||||
create(:captain_lifecycle_delivery,
|
||||
captain_reservation: reservation, status: 'sent', origin: 'scheduled_lifecycle')
|
||||
end
|
||||
expect(guard.check).to eq(action: :skip, reason: 'max_reached')
|
||||
end
|
||||
|
||||
it 'ignores concierge_reply origin' do
|
||||
10.times do
|
||||
create(:captain_lifecycle_delivery,
|
||||
captain_reservation: reservation, status: 'sent', origin: 'concierge_reply')
|
||||
end
|
||||
expect(guard.check).to eq(action: :pass)
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,32 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Lifecycle::Guards::OptOutLabel do
|
||||
subject(:guard) { described_class.new(delivery) }
|
||||
|
||||
let(:account) { create(:account) }
|
||||
let(:label) { create(:label, account: account, title: 'nao_mandar_auto') }
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
let(:reservation) { create(:captain_reservation, account: account, contact: contact) }
|
||||
let(:delivery) { create(:captain_lifecycle_delivery, account: account, captain_reservation: reservation) }
|
||||
|
||||
context 'when no config' do
|
||||
it 'passes' do
|
||||
expect(guard.check).to eq(action: :pass)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with config and opt_out_label configured' do
|
||||
before { create(:captain_lifecycle_config, account: account, opt_out_label: label) }
|
||||
|
||||
it 'passes when contact has no opt_out label' do
|
||||
expect(guard.check).to eq(action: :pass)
|
||||
end
|
||||
|
||||
it 'skips when contact has the configured label' do
|
||||
contact.update!(label_list: [label.title])
|
||||
expect(guard.check).to eq(action: :skip, reason: 'opt_out_label')
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Lifecycle::Guards::ReservationActive do
|
||||
subject(:guard) { described_class.new(delivery) }
|
||||
|
||||
let(:reservation) { create(:captain_reservation, status: 'confirmed') }
|
||||
let(:delivery) { create(:captain_lifecycle_delivery, captain_reservation: reservation) }
|
||||
|
||||
it 'returns pass for active reservation' do
|
||||
expect(guard.check).to eq(action: :pass)
|
||||
end
|
||||
|
||||
it 'returns skip for cancelled reservation' do
|
||||
reservation.update!(status: 'cancelled')
|
||||
expect(guard.check).to eq(action: :skip, reason: 'reservation_cancelled')
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue
Block a user