better results
This commit is contained in:
+24
-53
@@ -202,59 +202,17 @@ func main() {
|
||||
actor.NewMutationProcessor(func(ctx context.Context, g *cart.CartGrain) error {
|
||||
_, span := tracer.Start(ctx, "Totals and promotions")
|
||||
defer span.End()
|
||||
|
||||
// Clear bypass flags first
|
||||
for _, v := range g.Vouchers {
|
||||
if v != nil {
|
||||
v.BypassedByPromotions = false
|
||||
}
|
||||
}
|
||||
|
||||
g.UpdateTotals()
|
||||
promotionCtx := promotions.NewContextFromCart(g, promotions.WithNow(time.Now()))
|
||||
results, _ := promotionService.EvaluateAll(promotionStore.Snapshot(), promotionCtx)
|
||||
|
||||
// Check if any qualified promotion rule has a coupon_code condition matching our vouchers
|
||||
hasBypassed := false
|
||||
for _, res := range results {
|
||||
if res.Applicable {
|
||||
promotions.WalkConditions(res.Rule.Conditions, func(c promotions.Condition) bool {
|
||||
if bc, ok := c.(promotions.BaseCondition); ok && bc.Type == promotions.CondCouponCode {
|
||||
var codes []string
|
||||
if s, ok := bc.Value.AsString(); ok {
|
||||
codes = append(codes, strings.ToLower(s))
|
||||
} else if arr, ok := bc.Value.AsStringSlice(); ok {
|
||||
for _, s := range arr {
|
||||
codes = append(codes, strings.ToLower(s))
|
||||
}
|
||||
}
|
||||
for _, code := range codes {
|
||||
for _, v := range g.Vouchers {
|
||||
if v != nil && strings.ToLower(v.Code) == code {
|
||||
if !v.BypassedByPromotions {
|
||||
v.BypassedByPromotions = true
|
||||
hasBypassed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if hasBypassed {
|
||||
// Re-evaluate with bypassed vouchers
|
||||
g.UpdateTotals()
|
||||
promotionCtx = promotions.NewContextFromCart(g, promotions.WithNow(time.Now()))
|
||||
results, _ = promotionService.EvaluateAll(promotionStore.Snapshot(), promotionCtx)
|
||||
}
|
||||
|
||||
// ApplyResults applies qualifying actions in priority order and records
|
||||
// every effect — both applied discounts and pending "spend X more for ..."
|
||||
// nudges with their progress — in g.AppliedPromotions.
|
||||
promotionService.ApplyResults(g, results, promotionCtx)
|
||||
// Canonical promotion pipeline — same call site as the
|
||||
// /promotions/evaluate-with-cart preview handler in
|
||||
// promotions_evaluate.go. Going through the shared
|
||||
// PromotionService.EvaluateAndApply means the bypass
|
||||
// loop, the re-eval trigger, and ApplyResults stay in
|
||||
// lockstep with the preview so a what-if always matches
|
||||
// post-add behavior (including the coupon+promotion-
|
||||
// overlap edge case). If you find yourself adding
|
||||
// promotion logic here, add it to EvaluateAndApply
|
||||
// instead — the preview must follow.
|
||||
promotionService.EvaluateAndApply(promotionStore.Snapshot(), g, promotions.WithNow(time.Now()))
|
||||
g.Version++
|
||||
return nil
|
||||
}),
|
||||
@@ -490,6 +448,19 @@ func main() {
|
||||
// without creating or mutating a real cart.
|
||||
mux.HandleFunc("POST /promotions/evaluate", newPromotionEvaluateHandler(promotionStore, promotionService))
|
||||
|
||||
// Cart-aware promotion evaluation: reads the cartid cookie the storefront
|
||||
// already maintains, fetches the actual cart grain (cross-pod via
|
||||
// GetAnywhere), merges with the request's items (the items the user is
|
||||
// considering adding), and runs the engine on the merged line list. The
|
||||
// cart is the source of truth (vouchers, customer segment, customer
|
||||
// lifetime value, total) so a serialised copy from the browser can race
|
||||
// the live cart — letting the backend read the cookie + fetch the grain
|
||||
// means exactly one source of truth and no race. Missing cookie or fetch
|
||||
// failure gracefully degrades to a stateless evaluation of the request
|
||||
// items alone. See newPromotionEvaluateWithCartHandler in
|
||||
// promotions_evaluate.go for the full contract.
|
||||
mux.HandleFunc("POST /promotions/evaluate-with-cart", newPromotionEvaluateWithCartHandler(promotionStore, promotionService, syncedServer))
|
||||
|
||||
// only for local
|
||||
mux.HandleFunc("GET /add/remote/{host}", func(w http.ResponseWriter, r *http.Request) {
|
||||
pool.AddRemote(r.PathValue("host"))
|
||||
|
||||
Reference in New Issue
Block a user