This commit is contained in:
mats committed 2026-06-28 17:52:49 +02:00
1 parent e706f7d907
commit 21bcb63440
42 files changed
+5903

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
// Package order is the platform's shared order seam: the exported wire shape of
// the `order.created` domain event (B4.1). It is the contract between the order
// service (producer) and every reactor — inventory commit, fulfillment
// allocation, loyalty, ERP sync — none of which the order service knows about.
//
// Like platform/catalog and platform/inventory, it holds only the wire value
// types + encode/decode, and imports only the stdlib.
//
// `order.created` is a FACT, not a request: by the time it is emitted the order
// is placed and paid. Reactors must be idempotent (the transport is
// at-least-once) and must not assume they can refuse it — the sale already
// happened. Oversell on commit is reconciled downstream (backorder), not
// prevented here.
package order
import "encoding/json"
// Line is one ordered line item, reduced to what reactors need: the SKU, how
// many units sold, and the inventory location to commit against. Pricing/tax
// live in the order grain, not on this seam.
type Line struct {
SKU string `json:"sku"`
Quantity int `json:"quantity"`
// Location is the inventory location / store id to decrement. Empty means
// "use the order's Country" (central stock) — see Created.Country.
Location string `json:"location,omitempty"`
}
// Created is the payload of an event.OrderCreated envelope.
//
// Country is the default inventory location for the commit (central stock). A
// Line may override it with its own Location (store id); when a line's Location
// is empty the commit falls back to Country. See docs/inventory-shape.md.
type Created struct {
OrderID string `json:"order_id"`
OrderReference string `json:"order_reference,omitempty"`
CartID string `json:"cart_id,omitempty"`
Country string `json:"country"`
Currency string `json:"currency,omitempty"`
CustomerEmail string `json:"customer_email,omitempty"`
Lines []Line `json:"lines"`
PlacedAtMs int64 `json:"placed_at_ms,omitempty"`
}
// Encode serialises the payload for event.Event.Payload.
func (c Created) Encode() ([]byte, error) { return json.Marshal(c) }
// Decode parses an order.created payload — the consumer side of Encode.
func Decode(raw []byte) (Created, error) {
var c Created
err := json.Unmarshal(raw, &c)
return c, err
}
+30
View File
@@ -0,0 +1,30 @@
package order
import "testing"
func TestCreatedRoundTrip(t *testing.T) {
in := Created{
OrderID: "ord-1",
OrderReference: "REF-1",
CartID: "cart-9",
Country: "se",
Currency: "SEK",
CustomerEmail: "a@b.c",
Lines: []Line{{SKU: "ABC", Quantity: 2, Location: "store-7"}, {SKU: "DEF", Quantity: 1}},
PlacedAtMs: 123,
}
raw, err := in.Encode()
if err != nil {
t.Fatalf("encode: %v", err)
}
out, err := Decode(raw)
if err != nil {
t.Fatalf("decode: %v", err)
}
if out.OrderID != in.OrderID || out.Country != in.Country || len(out.Lines) != 2 {
t.Fatalf("round-trip mismatch: got %+v, want %+v", out, in)
}
if out.Lines[0].SKU != "ABC" || out.Lines[0].Quantity != 2 || out.Lines[0].Location != "store-7" {
t.Errorf("line[0] mismatch: %+v", out.Lines[0])
}
}