update orderflow
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/checkout"
|
||||
messages "git.k6n.net/mats/go-cart-actor/proto/checkout"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// settledPayment carries the provider-agnostic facts about an already-settled
|
||||
// payment. Each payment integration (Klarna push, Adyen CAPTURE notification,
|
||||
// …) fills this in from its own callback and hands it to
|
||||
// createOrderFromSettledCheckout, so the from-checkout request is identical
|
||||
// regardless of which provider settled the payment.
|
||||
type settledPayment struct {
|
||||
Provider string // "klarna" | "adyen"
|
||||
Reference string // processor / PSP reference
|
||||
Amount int64 // minor units, as charged
|
||||
Currency string
|
||||
Country string
|
||||
Locale string
|
||||
}
|
||||
|
||||
// buildOrderLinesFromGrain converts the checkout grain's cart items and delivery
|
||||
// selections into from-checkout order lines. Shared by every provider so the
|
||||
// order payload is built the same way no matter who settled the payment.
|
||||
func buildOrderLinesFromGrain(grain *checkout.CheckoutGrain) []OrderLine {
|
||||
lines := make([]OrderLine, 0, len(grain.CartState.Items)+len(grain.Deliveries))
|
||||
for _, it := range grain.CartState.Items {
|
||||
if it == nil {
|
||||
continue
|
||||
}
|
||||
lines = append(lines, OrderLine{
|
||||
Reference: it.Sku,
|
||||
Sku: it.Sku,
|
||||
Name: it.Meta.Name,
|
||||
Quantity: int32(it.Quantity),
|
||||
UnitPrice: it.Price.IncVat,
|
||||
TaxRate: int32(it.Tax),
|
||||
})
|
||||
}
|
||||
for _, d := range grain.Deliveries {
|
||||
if d == nil || d.Price.IncVat <= 0 {
|
||||
continue
|
||||
}
|
||||
lines = append(lines, OrderLine{
|
||||
Reference: d.Provider,
|
||||
Sku: d.Provider,
|
||||
Name: "Delivery",
|
||||
Quantity: 1,
|
||||
UnitPrice: d.Price.IncVat,
|
||||
TaxRate: 2500,
|
||||
})
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
// createOrderFromSettledCheckout sends the from-checkout request for a settled
|
||||
// checkout (any provider) and, on success, records the returned order id on the
|
||||
// checkout grain via the OrderCreated mutation so the backoffice can link
|
||||
// checkout → order.
|
||||
//
|
||||
// It is idempotent: the order service dedupes on "checkout-{checkoutId}", so
|
||||
// repeated provider callbacks (Klarna re-push, retried Adyen CAPTURE) return the
|
||||
// existing order rather than creating a duplicate. Callers should treat a
|
||||
// non-nil error as non-fatal and retry on the next callback.
|
||||
func createOrderFromSettledCheckout(ctx context.Context, s *CheckoutPoolServer, grain *checkout.CheckoutGrain, pay settledPayment) (*CreateOrderResult, error) {
|
||||
if grain.CartState == nil {
|
||||
return nil, fmt.Errorf("from-checkout: checkout %s has no cart state", grain.Id)
|
||||
}
|
||||
|
||||
var customerEmail, customerName string
|
||||
if grain.ContactDetails != nil {
|
||||
if grain.ContactDetails.Email != nil {
|
||||
customerEmail = *grain.ContactDetails.Email
|
||||
}
|
||||
if grain.ContactDetails.Name != nil {
|
||||
customerName = *grain.ContactDetails.Name
|
||||
}
|
||||
}
|
||||
|
||||
req := CreateOrderReq{
|
||||
CheckoutId: grain.Id.String(),
|
||||
IdempotencyKey: "checkout-" + grain.Id.String(),
|
||||
CartId: grain.CartId.String(),
|
||||
Currency: pay.Currency,
|
||||
Locale: pay.Locale,
|
||||
Country: pay.Country,
|
||||
CustomerEmail: customerEmail,
|
||||
CustomerName: customerName,
|
||||
Lines: buildOrderLinesFromGrain(grain),
|
||||
}
|
||||
req.Payment.Provider = pay.Provider
|
||||
req.Payment.Reference = pay.Reference
|
||||
req.Payment.Amount = pay.Amount
|
||||
|
||||
result, err := s.orderClient.CreateOrder(ctx, req, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_ = s.ApplyAnywhere(ctx, grain.Id, &messages.OrderCreated{
|
||||
OrderId: result.OrderId,
|
||||
Status: "completed",
|
||||
CreatedAt: timestamppb.Now(),
|
||||
})
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user