Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paying again for the order is too complicated #753

Closed
s3m3n opened this issue Mar 9, 2021 · 10 comments
Closed

Paying again for the order is too complicated #753

s3m3n opened this issue Mar 9, 2021 · 10 comments
Assignees
Labels
type: bug 🐛 Something isn't working

Comments

@s3m3n
Copy link

s3m3n commented Mar 9, 2021

In our case customer fails with payment of any reason - he could have no battery on smartphone to approve transaction on time. We want him to try again right away, he's paying customer, he's gold for us.

Unfortunately Vendure is not easy on developer to support this simple scenario as ShopApi does not allow to add payment to historical Order, only the active one known from session. Additionally there is Order state ArrangingAdditionalPayment available, seems to be perfect in such situation but it's not available in natural flow, you must reach Modifying state first which is typical for Admin and then transition to ArrangingAdditionalPayment.

Our ideas how to achieve this:

  1. We must add custom order flow to allow transition from PaymentAuthorised to ArrangingAdditionalPayment. When our payment controller receives info that the payment is declined it would transition the Order to the new state right away. Front knows exactly what to do with such order.
  2. We must write extra GQL mutation for ShopApi to either:
  • change active order in user session to historical order and then allow store frontend to call natural addPaymentToOrder OR
  • write responsible method of adding payment to historical Order and have stress each time Vendure is updated if we follow all required steps.

I think this should be easier as we all want Vendure to be the best e-commerce engine ever!

@s3m3n s3m3n added the type: bug 🐛 Something isn't working label Mar 9, 2021
@s3m3n
Copy link
Author

s3m3n commented Mar 11, 2021

It seems that state ArrangingAdditionalPayment is also unusable in our case, as OrderService.addPaymentToOrder is checking for status in the first lines and it can be only ArrangingPayment.

const order = await this.getOrderOrThrow(ctx, orderId);
        if (order.state !== 'ArrangingPayment') {
            return new OrderPaymentStateError();
        }

In this case we will hop to ArrangingPayment after the payment is declined to use ShopAPI addPaymentToOrder on frontend.

@michaelbromley
Copy link
Member

Did you take a look at the addManualPaymentToOrder method?

async addManualPaymentToOrder(

This may be useful to you since it expects the order to be in the ArrangingAdditionalPayment state.

@s3m3n
Copy link
Author

s3m3n commented Mar 11, 2021

OK, but this method is not exposed via GQL to frontend. As we discussed on Slack we took the most safe way to do it - we are changing active order in session and then move on with typical addPaymentToOrder.

@stefanvanherwijnen
Copy link
Contributor

How did you change the active order in the session?

@michaelbromley
Would it be feasible to add an orderId to PaymentInput?
Also, is there a reason AddManualPaymentToOrder is limited to ArrangingAdditionalPayment and not for ArrangimgPayment and PaymentAuthorized (I.e. orders has not been paid yet)?
This would make it easier for example to use it for orders which are picked up and paid with cash or pin (if for whatever reason it has not been paid for yet) .
Just looking for some feedback before I try to implement a solution.

@michaelbromley
Copy link
Member

Would it be feasible to add an orderId to PaymentInput?

The whole order/checkout flow assumes that there is always a single active order. Adding an orderId field to the input sounds simple but I suspect it will imply a whole load of additional complexity which I'd like to avoid.

Also, is there a reason AddManualPaymentToOrder is limited to ArrangingAdditionalPayment and not for ArrangimgPayment and PaymentAuthorized (I.e. orders has not been paid yet)?

This is because if the Order is in the ArrangingPayment state, then this implies that there is not yet a completed payment for that order. Therefore "additional" payment does not make sense. Additional payments are intended for when the order total changes after payment due to order modifications being made.

This would make it easier for example to use it for orders which are picked up and paid with cash or pin (if for whatever reason it has not been paid for yet) .

In this scenario, are you talking about when a customer places an order, then comes to pick it up and decides at that point to modify the order?

@stefanvanherwijnen
Copy link
Contributor

Thanks,

I understand the way you designed the order flow and overall it works great. What I mean is e.g:
Customer places an order. Everything seems to go fine, but the payment fails due to insufficient funds. Customer is unaware and already on his way to pick up his order.
On arrival the order status is still in ArrangimgPayment. This scenario should not occur in theory, but my experience is that in practice it definitely will.

In the simplest terms: if an order has not been paid yet there should always be an option for the administrator to fulfill the payment (which as you said is not self-evident due to the order design)

@michaelbromley
Copy link
Member

OK, thanks for the clarification. Yes - reality indeed has a habit of not conforming to our perfect designs 😆

This is something we should support. I plan to add this functionality.

@s3m3n
Copy link
Author

s3m3n commented Jun 1, 2021

Sorry @stefanvanherwijnen missed your question.

How did you change the active order in the session?

We exposed new gql mutation in ShopApi:

@VendurePlugin({
    imports: [
        PluginCommonModule
    ],
    shopApiExtensions: {
        schema: gql`
            extend type Mutation {
                setActiveOrder(id: ID!): Boolean
            }
        `,
        resolvers: [
            ActiveOrderResolver
        ]
    }
})

Which does simple job:

@Mutation()
    @Allow(Permission.Authenticated)
    setActiveOrder(@Ctx() ctx: RequestContext, @Args('id') orderId: number): Promise<boolean> {
        if (!ctx?.activeUserId) {
            return Promise.resolve(false);
        }
        return this.orderService.findOne(ctx, orderId).then((order) => {
            if (order && order.customer?.user?.id === ctx.activeUserId
                && (
                    order.state === 'ArrangingAdditionalPayment' ||
                    order.state === 'ArrangingPayment'
                )
            ) {
                order.active = true;
                return this.orderRepository.save(order).then(() => {
                    return true;
                })
            }
            return false;
        })
    }

Front calls it on invalid payment order (user is clicking "pay once again") and then adds new payment to this order.

@michaelbromley
Copy link
Member

Hi all,

I'm finally revisiting this to wrap it up and make sure we have all cases handled. I just implemented a couple of changes which will allow the Administrator to manually add a payment, as requested by @stefanvanherwijnen:

admin-manual-payment.mp4

The concrete change is that the addManualPaymentToOrder can now also be executed from the ArrangingPayment state, not just the ArrangingAdditionalPayment state.

Now I want to make sure I fully understand the original issue from @s3m3n:

Unfortunately Vendure is not easy on developer to support this simple scenario as ShopApi does not allow to add payment to historical Order, only the active one known from session

I am not 100% clear on how the order gets into the state which causes the issue. Can you lay out step-by-step instructions of how to recreate the bad state?

@martijnvdbrug
Copy link
Collaborator

This issue seems to be fixed with this comment. For additional issues I propose opening a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug 🐛 Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants