update orderflow
Build and Publish / BuildAndDeployArm64 (push) Failing after 6s
Build and Publish / BuildAndDeployAmd64 (push) Has been cancelled

This commit is contained in:
2026-06-21 23:26:37 +02:00
parent 1a365de071
commit 716a66562e
10 changed files with 651 additions and 29 deletions
+53 -5
View File
@@ -1,6 +1,7 @@
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
@@ -124,6 +125,14 @@ func (s *CheckoutPoolServer) AdyenHookHandler(w http.ResponseWriter, r *http.Req
}
//}
// CAPTURE is the moment the Adyen payment is fully settled — the
// Adyen analogue of the Klarna push. Create the event-sourced
// order now (mirrors KlarnaPushHandler). Idempotent on
// "checkout-{checkoutId}", so a retried CAPTURE won't duplicate.
if isSuccess && s.orderClient != nil {
s.createAdyenOrder(r.Context(), *checkoutId, item)
}
case "AUTHORISATION":
isSuccess := item.Success == "true"
@@ -176,11 +185,11 @@ func (s *CheckoutPoolServer) AdyenHookHandler(w http.ResponseWriter, r *http.Req
if err != nil {
log.Printf("Error capturing payment: %v", err)
} else {
log.Printf("Payment captured successfully: %+v", res)
s.ApplyAnywhere(r.Context(), *checkoutId, &messages.OrderCreated{
OrderId: res.PaymentPspReference,
Status: item.EventCode,
})
// Capture requested. The order is NOT created here — we
// only have a PSP reference, not an order. Adyen sends a
// CAPTURE notification once the capture settles, and the
// CAPTURE branch above creates the event-sourced order.
log.Printf("Payment capture requested successfully: %+v", res)
}
}
default:
@@ -209,6 +218,45 @@ func (s *CheckoutPoolServer) AdyenHookHandler(w http.ResponseWriter, r *http.Req
}
// createAdyenOrder turns a settled (captured) Adyen payment into an
// event-sourced order, mirroring KlarnaPushHandler. The Adyen webhook carries
// the charged amount + currency but not the shopper's country/locale, so those
// are derived from the currency. Failures are logged and left for the next
// CAPTURE notification to retry — the from-checkout endpoint is idempotent on
// "checkout-{checkoutId}".
func (s *CheckoutPoolServer) createAdyenOrder(ctx context.Context, checkoutId cart.CartId, item webhook.NotificationRequestItem) {
grain, err := s.GetAnywhere(ctx, checkoutId)
if err != nil {
log.Printf("from-checkout: could not load checkout grain %s: %v", checkoutId.String(), err)
return
}
// Reserve inventory once, guarded by the grain flag so a retried CAPTURE
// does not decrement stock twice. (Same as the Klarna path.)
if s.inventoryService != nil && grain.CartState != nil && !grain.InventoryReserved {
if rerr := s.inventoryService.ReserveInventory(ctx, getInventoryRequests(grain.CartState.Items)...); rerr != nil {
log.Printf("from-checkout: inventory reservation failed for %s: %v", checkoutId.String(), rerr)
} else {
s.Apply(ctx, uint64(grain.Id), &messages.InventoryReserved{
Id: grain.Id.String(),
Status: "success",
})
}
}
country := getCountryFromCurrency(item.Amount.Currency)
if _, oerr := createOrderFromSettledCheckout(ctx, s, grain, settledPayment{
Provider: "adyen",
Reference: item.PspReference,
Amount: item.Amount.Value,
Currency: item.Amount.Currency,
Country: country,
Locale: getLocale(country),
}); oerr != nil {
log.Printf("from-checkout failed for checkout %s; will retry on next CAPTURE: %v", checkoutId.String(), oerr)
}
}
func (s *CheckoutPoolServer) AdyenReturnHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Redirect received")