Hey folks, just a quick intro: my name's Nathaniel, I'm one of the
co-founders of
http://spreedly.com. Since my work at Spreedly involves
working with so many different gateways - I've added one gateway from
scratch so far, and done the work to merge a couple more - the Shopify
folks invited me to dig in and help out with the ongoing work on
ActiveMerchant. At this point my focus is pretty much exclusively on
Gateways; I haven't done anything with Integrations to date.
As part of rolling some of our work at Spreedly back in to trunk, I
want to get some opinions on how to clean up the #credit API across
the various gateways. By way of background, there are two types of
crediting that gateways support: referenced and general. A referenced
credit allows the return of some or all of the funds for a specific
transaction, while a general credit allows putting an arbitrary amount
of funds on to a payment source regardless of whether there are any
transactions against it. Referenced credits are far and away the most
common type supported by gateways, but some gateways support general
credits as well.
Most of the gateways that support both referenced and general credits
simply provide the #credit method, and if the payment source passed in
is a String they do a referenced credit, otherwise they assume it's a
full payment method and do a general credit. This is OK, but I'm not
real fond of switching on the type of the argument provided (more on
that below).
The real problem arises in that the SmartPsGateway (subclassed by
BraintreeOrangeGateway and TransaxGateway) and the
BraintreeBlueGateway both provide two methods for these two types of
credits: #refund and #credit. #refund does a referenced credit, and
#credit does a general credit. This breaks the API expectations for
the #credit method since the most common behavior for #credit is a
referenced credit.
Here are a few options I've come up with to handle these two types of
#credit more consistently:
1. Do nothing, leaving these three gateways with different API behavior.
Pro: doesn't break those already implemented against these three gateways.
Con: means anyone switching from another gateway to these gateways
will get a surprise when they try to do a referenced #credit as per
the usual API expectation.
Con: requires implementors that credit against a lot of gateways (i.e.
Shopify, Spreedly, etc.) to special case these three gateways.
2. Switch these three gateways to only have #credit, and if the
payment source is a string, do a referenced credit, otherwise do a
general credit.
Pro: only impacts these three gateways.
Con: Braintree also allows doing a general credit against a vaulted
card, and that won't work any longer since the vault id is a String.
Con: switching behavior based on parameter type seems like a bad
long-term design decision (see previous Con).
Con: will break those who have already implemented any of these three gateways.
3. Provide one #credit method, and choose reference vs. general based
on an option parameter. A reference credit is the default, but passing
:general => true does a general credit.
Pro: makes referenced credit vs. general credit explicit.
Pro: unchanged API for the most common case (reference credit).
Con: breaks the API for those doing general credits (could mitigate by
still having a parameter type check with a deprecation warning).
Con: introduces a "magic option" to the #credit API.
Would love to hear feedback on these options, as well as any
additional options you see. Thanks!
--
Nathaniel Talbott
<:((><