Implementing non-credit card checkout service

Issue #47 closed
Josh Berry
created an issue

I need to add a checkout option that does not use credit cards. In this particular case, it's payment based on department codes, but I could see other non-credit card payment options being useful in certain cases as well (COD for example).

For the most part, this has been a relatively easy exercise. I've implemented my own ICheckoutService and a custom controller to handle the collection of shipping and payment details. I've been able to do all this in my own module.

The issue I'm running into is that the OrderService (and StripeService) expects to deal with a CreditCardCharge object but my payment information doesn't fit that mold. I've played around with extracting a common interface that could serve additional charge types and it's working so far. Here's what it looks like:

public interface ICharge : IDependency {
    string TransactionId { get; set; }
    string ChargeText { get; set; }
    string TransactionUrl { get; set; }
    CheckoutError Error { get; set; }

The biggest change is that the charge description (ChargeText is what I called it) is generated by the checkout service upfront instead of being dynamically built from the credit card details when an order is retrieved. You lose the ability to access credit card details separately, but as far as I can tell, the only time they were ever used was to construct the charge description anyway.

I'm interested in your thoughts on this approach. Is there a better or alternative way to do it? Also, is this something you would consider as a pull request? I'd really like to keep my implementation as close to the official repo as possible.

The only other option I came up with would be to stuff my payment details into the CreditCardCharge class. This does work, but seems ugly and I'd probably have to hack at the order views so the payment details displayed in a reasonable way to customers.

Comments (8)

  1. Bertrand Le Roy repo owner

    If you can get it in with 100% compatibility with the current model, I'll take it in. One way to do that could be by having the credit card charge be an implementation of ICharge, that would behave exactly the way it currently does.

  2. Josh Berry reporter

    Cool. That's pretty much what I've done. The stripe feature didn't need to change at all. The persistence of the charge details on the order changed a bit, but that seems necessary since only the common interface data cab be saved and retrieved. Is that what you were thinking?

    I'll clean thing up and send a PR for you to take a look at. Thanks!

  3. Josh Berry reporter

    I've updated the Charge method of OrderPart to return an ICharge instead of a CreditCardCharge. Within the get accessor, I check if the xml document uses the previous storage method and handle that so existing data continues to work.

    public ICharge Charge {
        get {
            var chargeElement = ContentDocument.Element(ChargeName);
            if (chargeElement == null) {
                // Check for legacy data structure, prior to ICharge
                var cardElement = ContentDocument.Element(CardName);
                if (cardElement == null) return null;
                return cardElement.With(new CreditCardCharge())
                    .FromAttr(c => c.TransactionId)
                    .FromAttr(c => c.Last4)
                    .FromAttr(c => c.ExpirationMonth)
                    .FromAttr(c => c.ExpirationYear)
            return chargeElement.With(new Charge())
                .FromAttr(c => c.TransactionId)
                .FromAttr(c => c.ChargeText)
                .FromAttr(c => c.TransactionUrl)

    Does that seem like a reasonable approach to you?

  4. Log in to comment