platform
This commit is contained in:
1 parent
e706f7d907
commit
21bcb63440
42 files changed
+5903
No files matched your search
@@ -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
|
||||
}
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user