Skip to content

Order#outstanding_balance implementation limits Refund usage #1254

@jordan-brough

Description

@jordan-brough

Executive Summary

The current implementation of Order#outstanding_balance limits Refund usage to certain use cases. This is mostly the fault of one person who shall remain nameless, but his initials are J.B. and it is me.

In a nutshell, Refunds are being treated as "Order adjustment + Return of money on a payment", and they probably should only be "Return of money on a payment". That was the original intention of Refund.

Long-winded explanation

Currently Order#outstanding_balance is defined as:

total - payment_total - refund_total

where payment_total is defined as payments.completed.sum(:amount) - refund_total.

So outstanding_balance expands to:

total - (payments.completed.sum(:amount) - refund_total) - refund_total

which reduces to:

total - payments.completed.sum(:amount)

This means that "outstanding balance" is "the order total minus your completed payment total, regardless of whether those payments have been refunded or not".

Another way to think of it is that a Refund effectively adjusts the order total. It is saying that you got returned X amount of money and the order should consider it as counting toward the payment total.

This works fine for common scenarios like:
  • User completes an order for widget A ($10) and widget B ($20) and submits payment
  • User receives their shipment and reports that widget B is broken
  • Admin provides a refund for the broken widget B

In this case outstanding_balance is correctly $0.

It does not work for scenarios where the order is modified after payment is complete:
  • User completes an order for widget A ($10) and widget B ($20) and submits payment
  • User asks to have widget B cancelled, and admin deletes widget B's line item from the order and grants a refund for widget B.

In this case the outstanding balance will end up being -$20 (it appears that we owe them money) because the raw payment total is $30 but the order total has gone down to $10.

It also does not work for scenarios where a refund is issued for some other reason:
  • User completes an order for widget A ($10) and submits payment
  • User says "oops, I need to pay using a different account. Can you refund me and let me pay with a different card?"
  • Admin grants a refund and the user submits a new payment

In this case the outstanding balance will end up being -$10 (it appears that we owe them money) because the raw payment total is $20 (the sum of both completed payments) but the order total is still only $10.

Potential solution

It feels like the right fix could be:

  1. Change outstanding_balance to be simply total - payment_total
  2. When generating a refund for scenarios like "widget is broken", we also generate a negative adjustment on the order (or line item) to represent the order total .

That would allow Refund to just represent the return of money on a payment, and allow it to be used in various scenarios. That might be a hard thing to do and maintain backward compatibility, however. :(

Thoughts? Have others run into this and solved it in different ways?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions