Class: Payment::DailyIssuesDigestWorker
- Inherits:
-
Object
- Object
- Payment::DailyIssuesDigestWorker
- Includes:
- Sidekiq::Job, Workers::ErrorReportingConcern
- Defined in:
- app/workers/payment/daily_issues_digest_worker.rb
Overview
Sidekiq worker: nightly digest of payment issues that need accounting
attention. Replaces the per-event alerts that used to fire from four
different code paths with one consolidated email, so AR doesn't get a
stream of one-off messages interleaved with their inbox.
Scans recent activity for five classes of issue:
-
Orphan Stripe PaymentIntents (7-day window) — Stripe charged
but Heatwave has no matching Payment in state authorized/captured;
already-refunded charges are excluded. Detected by
walking each Stripe account's recent succeeded PIs and joining
against the local Payment table. (Previously emailed by the
standalone OrphanPaymentIntentReconciliationWorker.) -
Overcharged invoices — captured payments on an invoice exceed
the invoice total. Detected by scanning recently-created invoices
with attached captured payments and comparing
#total_captured againstInvoice#total. (Previously
emailed byPaymentCheckerWorker#detect_overcharged_invoices.) -
PayPal authorizations expired past the 29-day hard limit —
Paymenttransitioned to stateexpiredin the last 24 hours.
The state transition itself happens in
#attempt_paypal_reauthorization_if_needed during the
8-hourly PaymentCheckerWorker; this worker only reports. -
PayPal reauthorization failures — an
OrderTransactionwas
recorded with actionreauthorizationandsuccess=falsein the
last 24 hours. Same retrospective detection pattern as #3. -
Potential duplicate charges — two or more succeeded, unrefunded
Stripe PIs for the same Stripe customer + amount within the last
7 days. Catches the client-confirmed resubmit pattern (Stripe.js
charges BEFORE the server can block the duplicate — invoice
INV012603927 / pi_3Tw7ww, 2026-07-22) where the second charge has
no CRM row at all, so only a Stripe-side sweep can see it. Each
charge is annotated with its CRM payment/invoice or NO CRM RECORD.
Send is skipped entirely when all scans return empty — never
emails an "all clear."
Constant Summary collapse
- WINDOW =
Constant.
24.hours
- ORPHAN_WINDOW =
Orphans and duplicates look back a full week: an unresolved orphan keeps
reappearing daily until someone reconciles or refunds it, instead of
silently aging out of a 24h window (the Prestige orphan pi_3ToRZG sat
invisible for 4 weeks after its digest day passed). Duplicate pairs can
also straddle days, and refunds/reports lag the charge. 7.days
- DUPLICATE_WINDOW =
Currencies.
7.days
- CURRENCIES =
Constant.
%w[USD CAD].freeze
Instance Method Summary collapse
-
#perform ⇒ Object
Runs the job.
Methods included from Workers::ErrorReportingConcern
#report_worker_error, #report_worker_warning
Instance Method Details
#perform ⇒ Object
Runs the job.
65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'app/workers/payment/daily_issues_digest_worker.rb', line 65 def perform issues = { orphan_payment_intents: safely(:find_orphan_payment_intents), overcharged_invoices: safely(:find_overcharged_invoices), paypal_expired: safely(:find_paypal_expired_payments), paypal_reauth_failed: safely(:find_paypal_reauth_failures), potential_duplicates: safely(:find_potential_duplicate_charges) } return if issues.values.all?(&:empty?) PaymentReconciliationMailer.daily_issues_digest(issues: issues).deliver_later end |