Class: OutletPurchase::OpportunitySyncHandler

Inherits:
Object
  • Object
show all
Defined in:
app/subscribers/outlet_purchase/opportunity_sync_handler.rb

Overview

Subscribes to Events::OutletPurchaseVerified. Brings the opportunity into line
with an attribution a human has just accepted:

  • stamps the channel (purchase_outlet), so a project never hides WHERE the
    sale landed
  • corrects an opportunity we had already written off as lost or abandoned
    — the record was simply wrong once the customer turned out to have bought
  • recomputes value, because verified outlet revenue is actual money on the
    project alongside direct sales orders

Synchronous on purpose. The reviewer is redirected straight back to a page
that renders the opportunity's state and value; an async handler would show
them the pre-ruling figures and look like the click did nothing. The heavy,
retryable work — telling the ad platforms — is a separate handler.

One handler rather than three because all three touch the same opportunity
row, and splitting them across jobs would race on it.

Wired in config/initializers/event_store.rb.

Instance Method Summary collapse

Instance Method Details

#call(event) ⇒ void

This method returns an undefined value.

Parameters:

  • event (RubyEventStore::Event)


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'app/subscribers/outlet_purchase/opportunity_sync_handler.rb', line 25

def call(event)
  purchase = CustomerOutletPurchase.find_by(id: event.data[:customer_outlet_purchase_id])
  return unless purchase

  # The event is published AFTER commit, so a concurrent rejection can land
  # between that commit and this handler. Checking `attributed?` outside a
  # lock would let this re-attribute a row somebody has just rejected.
  # Re-read under the row lock and hold it across the writes.
  purchase.with_lock do
    purchase.reload
    next unless purchase.attributed? && purchase.opportunity

    purchase.stamp_purchase_outlet
    purchase.correct_a_written_off_opportunity
    purchase.opportunity.calculate_value
  end
rescue ActiveRecord::RecordNotFound
  # Deleted between the `find_by` and the lock — nothing left to sync.
  nil
end