Order 181 (and potentially others) failed to auto-capture properly, resulting in repeated failed capture attempts.
Symptoms:
Bug in app/models/order.rb line 197-201:
def has_uncaptured_authorization?
payment_transactions
.where(transaction_type: "auth_only", status: "approved")
.exists? # ❌ BUG: Doesn't check captured_at!
end
This method returned true for already-captured authorizations because:
transaction_type: "auth_only" and status: "approved"captured_at was NULLcaptured_at gets set, but status stays "approved"| Date | Event | What Happened |
|---|---|---|
| Oct 25 | Order created | TX 35: authorization successful |
| Oct 26 8:24am | Manual capture | TX 35 captured (capture_source: "manual_fix")captured_at set to Oct 26P1 marked as "paid" ❌ Order payment_status NOT updated |
| Nov 22 8am | Auto-capture P2 | has_uncaptured_authorization? returns true (WRONG!)Tried to re-capture TX 35 → FAILED Error: "Payment declined" (already captured) |
| Nov 22 9:29am | Retry attempt | Same failure |
| Nov 23 8am | Retry attempt | Same failure |
has_uncaptured_authorization? MethodBefore:
def has_uncaptured_authorization?
payment_transactions
.where(transaction_type: "auth_only", status: "approved")
.exists?
end
After:
def has_uncaptured_authorization?
payment_transactions
.where(transaction_type: "auth_only", status: "approved")
.where(captured_at: nil) # ✅ Only truly uncaptured auths
.exists?
end
Updated payment_status from "failed" to "paid" to reflect that P1 is paid.
Order.find(181).update_column(:payment_status, "paid")
Verification on Order 181:
o = Order.find(181)
o.has_uncaptured_authorization? # Returns false (correct!)
# TX 35 has captured_at set, so it's excluded
What Happens Next:
This bug likely affected other orders where:
To find potentially affected orders:
# Orders with manually-captured first period
affected = PaymentTransaction
.where(capture_source: "manual_fix")
.joins(:order)
.where(orders: { is_recurring: true })
.distinct
.pluck(:order_id)
Order.where(id: affected).each do |order|
puts "Order #{order.id} (#{order.order_number})"
puts " payment_status: #{order.payment_status}"
puts " has_uncaptured_authorization?: #{order.has_uncaptured_authorization?}"
end
This fix prevents:
The system now correctly distinguishes between:
auth_only + approved + captured_at IS NULLauth_only + approved + captured_at NOT NULLapp/models/order.rb - Fixed has_uncaptured_authorization? method (line 200)payment_status to "paid"This fix has been applied to production:
app/models/order.rbNo other orders currently affected (verified via production check).