How do I stop a MonCash payment from being fulfilled twice?

posée 2 months ago662 vuesen

7

Sometimes an order gets marked paid twice and we ship twice: the customer refreshes the return page, and our background checker also finds the payment. How do I make fulfilment safe?

Diagnostic IA

Généré par IA. Ce n'est pas une réponse — la communauté ci-dessous le confirme ou le corrige. Vérifiez toujours avant de vous y fier.

1 réponse

3
✓
✓ Réponse acceptée

Make "mark as paid" idempotent at the database level, not just in application code. Two requests arriving at the same moment will both pass an if (order.status !== 'PAID') check.

1. Store the MonCash transaction id with a unique constraint

ALTER TABLE payments ADD CONSTRAINT payments_moncash_tx_unique UNIQUE (moncash_transaction_id);

2. Transition the order with a conditional update

async function markPaidOnce(orderId: string, transactionId: string) {
  return db.$transaction(async (tx) => {
    // only one caller can move PENDING → PAID
    const { count } = await tx.order.updateMany({
      where: { id: orderId, status: "PENDING" },
      data: { status: "PAID", paidAt: new Date() },
    });
    if (count === 0) return false; // someone else already did it
 
    await tx.payment.create({ data: { orderId, provider: "MONCASH", moncashTransactionId: transactionId } });
    return true;
  });
}

Only the caller that gets true sends the confirmation email or ships. Everyone else just shows "already paid".

3. Use one orderId per payment attempt. If a customer abandons and retries, create a new attempt with its own id that links back to the order. MonCash rejects a duplicate orderId, and you get a clean audit trail.

Connectez-vous pour dire si ça a marché.

answered 2 months ago

Sign in and verify your email to post an answer.