0

I have a shopping cart with a checkout page. On the checkout page is a payment button which takes them to a stripe payment form.

I've read some books on building eCommerce shopping carts in which the order is created when the user clicks the payment button and the order id is passed to the payment gateway. In this scenario if the user abandons the payment form then they are left with an unpaid order linked to their account.

So my question is what is preferable. Do you create the order only after a successful payment charge is made or would you create the order before the payment is made?

I suppose the only benefit to creating an order before the payment is made is that the site becomes more flexible in the sense that offline orders could be made as well i.e. and invoiced order.

* UPDATE *

An example of how an order can be created after payment charge has been made.

 public function checkout(Request $request)
{
    $token = $request->input('stripeToken');

    //Retriieve cart information
    $cart = Cart::where('user_id',Auth::user()->id)->first();
    $items = $cart->cartItems;
    $total=0;
    foreach($items as $item){
        $total+=$item->product->price;
    }
    if(
        Auth::user()->charge($total*100, [
        'source' => $token,
        'receipt_email' => Auth::user()->email,
    ])){

        $order = new Order();
        $order->total_paid= $total;
        $order->user_id=Auth::user()->id;
        $order->save();

        foreach($items as $item){
            $orderItem = new OrderItem();
            $orderItem->order_id=$order->id;
            $orderItem->product_id=$item->product->id;
            $orderItem->file_id=$item->product->file->id;
            $orderItem->save();

            CartItem::destroy($item->id);
    }
        return redirect('/order/'.$order->id);

    }else{
        return redirect('/cart');
    }

}
  • A "Cart" object and a "save for later" option ala Amazon could easily replace the need for creating an "Order" object before the customer attempts to checkout. – Nex Terren May 27 '16 at 20:49
  • 1
    The answer to the question "which is preferable" depends entirely on what sort of behavior you want from the application. Some websites store incomplete orders; you can't do that if the order only gets created when the payment is submitted. – Robert Harvey May 27 '16 at 20:53
  • Almost all payment processing providers require a unique identifier from you so that they can tell the buyer what the payment is for. In that case, even if you don't actually create an order in advance, you'll still have to create its unique identifier and make sure it's never reused. At that point, it is often simpler to just go ahead and create the order already than to keep straight which IDs have been used or not. – Kilian Foth May 27 '16 at 21:45
  • @KilianFoth not necessarily - see above code of how an order can be created after payment is made. – adam78 May 27 '16 at 22:56
  • If you create the order Before pay. How it affect the stock management? Is there any sort of units that may end being reserved? If you lock stock. Are you punishing possible orders that would be paid at the moment (instead of an uncertain future) bc stock is locked/reserved? – Laiv May 28 '16 at 9:39
2

Could there be a way to dodge this issue by turning "order" from a possibly transient object into an action performed by an object whose state you have more direct control over?

Let's assume four object types (classes or prototypes, depending on what you're working with): Customer, Product, Cart, and Receipt.

For clarity's sake, instance objects are lower_snake_case and classes are in StudlyCaps. I'm coming at this from a Ruby and JavaScript perspective, so translate as needed...

  • A customer is a user shopping on your site.
  • A product is an item for sale in your store.
  • A cart is an object representing all the products in a customer's shopping cart. Each customer has only one cart (for now: see below). That single cart per customer may contain many products, and has an order_id property that defaults to null. A cart's methods could include content manipulations like empty, add([skus]), remove([skus]), increment(sku), and decrement(sku). And then there's checkout, which populates order_id with an identifier that doesn't collide with other extant order IDs (perhaps generated based on the current cart state, customer ID, and time) and sends that order ID and other relevant info to the payment processor. Upon confirmation from the payment processor of a successful transaction, the pay method converts that cart's data into a Receipt instance and empties the shopping cart.
  • A receipt is like a cart preserved in its final paid state. A list of receipts is what a customer sees when looking at her order history. Each one has some new properties like tracking_number, and methods like refund([skus]).

Here's how I see this working in practice:

  • If the payment processor responds that the transaction failed, inform the user and revert order_id to null.
  • If the user abandons the payment process, the presence of a non-null order_id on their cart will indicate an incomplete transaction. Inform the user in the UI, along with links to complete checkout or view their cart.
  • If the user abandons payment, returns to the site, and alters the contents of their cart then nullify order_id -- this is effectively a different order.

The nice things about this approach:

  • No orphan orders hanging around.
  • You now have a structure that you can use to add additional functionality. For example, you could save a cart to turn it into a "shopping list" or "wishlist." This would empty the current active cart that the user thinks of as "their shopping cart," but preserve the data for display elsewhere in the UI. Those saved carts could then have a "Buy This List" button that jumps straight to checkout with those items, or an "Add to Cart" button that merges the list's contents with the active cart.
  • So for every item row in the cart the same order_id would have to be repeated? – adam78 May 27 '16 at 23:24
  • If you mean in the database, no. The way I imagine it, order_id would be a field in the carts table for each cart. Tracking which items are in which carts could be handled by a join table (say, carts_orders) that has, for each row, a quantity field and foreign keys for cart and product. Disclaimer: I'm recently arrived on the back-end after over a decade in front-end design & development. At this point my back-end architecture ideas my still be half-baked, and I'm happy to get feedback if they are. :) – Adam Messinger May 28 '16 at 1:14
1

I'll answer your question with two questions:

  1. Is it a bad thing to have to delete an order object?
  2. Is an order object invalid if it's supposed to be paid for (i.e., not merely waiting to be paid and picked up) but the payment hasn't come through?

If the answer to both questions is "yes," then you don't have a choice. A failed payment will leave you in a state that requires you to delete the order object, which your architecture discourages.

It seems like good practice to refrain from creating objects that you don't know you're going to use (thus restriction 0) and it seems almost axiomatic that you don't want bogus orders in your system that will never be completed (thus restriction 1). So the best answer is that you should create an order after executing payment.

0

one way of approaching this problem is to consider the various states of an order as separate entities. so, you might have (in a simple example) something like OrderUnpaid, OrderPaid, OrderPaymentFailed, OrderCancelled, OrderApproved, OrderUnfulfilled , OrderFulfilled, OrderComplete. this can be useful because it allows intuitive and clear separation of responsibilities based on the immediate needs of the order process.

  • Why not an enumerate column Order.state_id fk -> OrderState? – Andre Figueiredo Dec 2 '16 at 18:36
0

I think another way of doing this will be to enumerize the order. So the order can be uncompleted, paid or what event sates you would want if your architecture supports it.

  • 1
    We don't know what "enumerize" means. Can you edit this answer to use a different word instead? – Tanner Swett Nov 5 '18 at 15:44
0

Customarily in business, an order could exist in any one of several states:

  • Now being constructed.
  • Abandoned.
  • Parked by the user who someday plans to return to it and finish it.
  • Submitted but not yet paid for.
  • Paid for.
  • Awaiting purchase-order; purchase-order accepted; purchase-order refused.
  • Fulfilled.

Orders are sometimes accepted, fulfilled, and delivered based on a customer's credit with the company, or the presence of a purchase-order which serves to legally promise payment at a future date, and so on. Commonly, the financial transactions associated with an order are handled entirely separately from the order itself. The decision to put an order into active-fulfillment state is sometimes performed by software; sometimes only by human staff.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.