question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

New payment state - Pending

See original GitHub issue

Is your feature request related to a problem? Please describe. Looking at vendure’s payment plugins I see that current payment workflow is:

  1. Client call createStripePaymentIntent through shop-ai or some method, which creates an entity in payment gateway.
  2. Client make a payment through payment form.
  3. An incoming webhook informs vendure about successfull payment.
  4. Vendure calls addPaymentToOrder, which calls createPayment method on appropriate payment handler.

Basically, this scheme is okay, but problem arises when client want to specify more than one payments in the order. Say an order has total - 100$.

  1. Client adds a gift card or bonus payment to an order - 20$. It does not cover order’s total.
  2. Client creates a stripe payment intent through createStripePaymentIntent. But stripe payment plugin force order.totalWithTax field as amount, so amount result is 100$.
  3. Client see 100$ amount in payment form, which is wrong.

What I would like to see:

  1. Client adds a gift card or bonus payment to an order - 20$. It does not cover order’s total.
  2. Client adds a stripe payment intent through classical addPaymentToOrder, with amount 80$, because it calculates by formula: order.totalWithTax - all authorized/settled payments.
  3. createPayment handler returns an object, like { state: ‘pending or created’, metadata: { url: ‘stripe payment url’ } }
  4. Client uses an url from metadata to go to payment page, where amount to pay is 80$, which is right.
  5. An incoming webhook informs vendure about successfull payment.
  6. Vendure calls transitionPaymentToState which automatically transit a payment as well as an order to appropriate state.

I understand that I am completely able to implement this, thanks to vendure’s extensible mechanisms, but it’s cool to have a solid pattern here.

Describe the solution you’d like

  1. Do not add new mutations, like createStripePaymentIntent. It generates an additional logic on storefront side. Imagine you have 3-4 connected payment plugins - your storefront or multiple storefronts should support every mutation for every provider.
  2. Use traditional addPaymentToOrder to add new payments. It worth to place payment url into predefined field for that, not to metadata directly. Any of your storefront will be able to pay with any payment provider without an additional logic in unified way.
  3. Consider adding new payment state ‘Pending’. Right after payment creation, payment handler may transit to state ‘Pending’ (Created -> Pending), so it means payment plugin waits user to be paid with payment url/form.

Describe alternatives you’ve considered @vrosa doesn’t that depend on the implementation of this additional payment, e.g. gift card? I would expect the order.totalWithTax to be $80 by the time createStripePaymentIntent is called because that’s what the customer is going to be charged. Other platforms, e.g. Shopify, also consider subTotal or total to the be amount after the gift card has been applied. Not sure how Vendure’s paid gift card plugin will behave but I would expect it to subtract the amount from the order’s total.

Additional context @michaelbromley The gift card plugin I’m working on actually treats gift cards/store credit as a payment method, in the way described by Alexander. One reason for this is to do with the issue of how to deal with something like a return - if I buy 2 t-shirts @ $20 each, and then use a Promotion-style discount to make the order total $0, then Vendure is actually treating each OrderItem as having a value of $0 - i.e. the value of OrderItem.proratedUnitPrice will be 0. So for the purposes of returns & refunds, this indicates that the amount to refund would be $0, which is not correct. Treating the gift card as a payment method allows us to model the actual transaction values more accurately - i.e. if I use a gift card to “pay” for the above order, then a return of 1 t-shirt implies a refund/re-credit of $20. So I think it does make sense to take into account any existing payments on this line when creating the Stripe payment intent.

Slack thread: https://vendure-ecommerce.slack.com/archives/CKYMF0ZTJ/p1656064741229719

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:8 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
ashitikovcommented, Jul 19, 2022

To me, Created state already used in order state machine, and in fact, normally you will not be able to get an order somehow in this state, because on creation order transit to AddingItems state immediately. I guess this is done to get proper event OrderStateChangedEvent after order creation. So, getting Created state means that something went wrong, and I think the same rule should be applied to payment state machine also. Consider adding new state Pending instead of using existing Created to have similar behavior with other state machines.

1reaction
michaelbromleycommented, Jul 19, 2022

I’ve been working on the StripePlugin over the past couple of days, improving on some edge cases and security holes that were descovered. I now tend to agree that it would be best to unify the payment flows with calls to addPaymentToOrder.

At this point, we can create a Payment in the Created state and attach the payment intent client_secret to the Payment’s public metadata, so that it can be used in the frontend part. I’d prefer not to change the return type of addPaymentToOrder (which on success returns Order), but in any case the Payment metadata is easily retrievable from the Order type.

Doing it this way also has the following advantage: when we create the Payment, we can add the Stripe payment intent ID to the Payment’s metadata. Then we can implement a CustomOrderProcess onTransitionEnd hook and catch transitions from ArrangingPayment -> AddingItems. When this occurs, we can look up the Payment and use the payment intent ID to cancel the payment intent with Stripe.

This would give use a more robust and auditable sequence of events for each order.

Read more comments on GitHub >

github_iconTop Results From Across the Web

LEO - What does "processed-pending payment" mean?
Your certification has been received and is being processed. Payment processing is generally completed the next business day (this does not include holidays...
Read more >
What does “Pending” mean? Is there a problem?
According to our documentation on payment statuses, Pending means: This is a payment that has begun, but is not complete. An example of...
Read more >
Claim Status: Pending Payment - EDD - CA.gov
If you received at least one payment on your claim, but your payments have been pending for more than two weeks because of...
Read more >
New pending mutation in Payments Apps API 2022-04 release
The pending payments feature is now officially available for payments apps. You can mark a payment as pending if the payment can't be...
Read more >
Checking the status of pending payments - IBM
You can also manually check the status of a payment. You might want to do this in the scenario where an automated payment...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found