package order import ( "context" "encoding/json" "time" "git.k6n.net/mats/go-cart-actor/pkg/flow" "git.k6n.net/mats/platform/event" contract "git.k6n.net/mats/platform/order" ) // RegisterOrderCreatedEmit registers the "emit_order_created" flow hook: it // publishes an event.OrderCreated envelope (payload contract.Created) for the // order, reading the grain via app and publishing durably via pub. // // It is a HOOK, not an action, on purpose: hook errors are logged, never abort // the flow. The order is already placed and paid by the time this fires, so a // transient publish hiccup must not roll it back — and pub is the durable outbox // (a local fsync'd append), so "failure" here means disk error, then the relay // retries delivery on its own. With a nil publisher (dev without AMQP) it is a // no-op. Attach it to the "after" hooks of the final paid step, e.g. capture. func RegisterOrderCreatedEmit(reg *flow.Registry, app Applier, pub Publisher, exchange, source string) { reg.Hook("emit_order_created", func(ctx context.Context, st *flow.State, _ flow.HookInfo, _ json.RawMessage) error { if pub == nil { return nil // no broker configured (dev) } o, err := app.Get(ctx, st.ID) if err != nil { return err } created := buildOrderCreated(o) if len(created.Lines) == 0 { return nil // nothing for a reactor to act on } payload, err := created.Encode() if err != nil { return err } ev := event.Event{ ID: "order-created-" + created.OrderID, Type: event.OrderCreated, Source: source, Subject: created.OrderID, Payload: payload, Time: time.Now(), Meta: map[string]string{"country": created.Country}, } body, err := json.Marshal(ev) if err != nil { return err } return pub.Publish(exchange, string(event.OrderCreated), body) }) } // buildOrderCreated projects the grain onto the exported order.created contract. // Lines carry only SKU + quantity (what reactors need); inventory commits at the // order's Country location. func buildOrderCreated(o *OrderGrain) contract.Created { lines := make([]contract.Line, 0, len(o.Lines)) for _, l := range o.Lines { if l.Sku == "" || l.Quantity <= 0 { continue } lines = append(lines, contract.Line{SKU: l.Sku, Quantity: l.Quantity, Location: l.Location}) } return contract.Created{ OrderID: OrderId(o.Id).String(), OrderReference: o.OrderReference, CartID: o.CartId, Country: o.Country, Currency: o.Currency, CustomerEmail: o.CustomerEmail, Lines: lines, PlacedAtMs: nowMs(), } }