diff --git a/event/event.go b/event/event.go index 0630359..35bf269 100644 --- a/event/event.go +++ b/event/event.go @@ -61,6 +61,13 @@ const ( // Payload is an order.Created (platform/order). See docs/inventory-shape.md // and docs/fulfillment-stance.md. OrderCreated Type = "order.created" + // InvoiceIssued is emitted when an order is invoiced (pay-later placement or + // manual invoice issuance). Payload is an order.InvoiceIssued (platform/order). + InvoiceIssued Type = "invoice.issued" + // InvoicePaid is emitted when an invoiced order payment status crosses to paid. + // Payload is an order.InvoicePaid (platform/order). + InvoicePaid Type = "invoice.paid" + // Analytics (tracking). Replaces the integer enum 0–6 that finder and // slask-tracking use on the `tracking` topic today. Producer: slask-finder diff --git a/order/order.go b/order/order.go index c3cb79a..d171e76 100644 --- a/order/order.go +++ b/order/order.go @@ -58,3 +58,41 @@ func Decode(raw []byte) (Created, error) { err := json.Unmarshal(raw, &c) return c, err } + +// InvoiceIssued is the payload of an event.InvoiceIssued envelope. +type InvoiceIssued struct { + OrderID string `json:"order_id"` + InvoiceNumber string `json:"invoice_number"` + CompanyID string `json:"company_id,omitempty"` + CustomerEmail string `json:"customer_email,omitempty"` + AmountIncVat int64 `json:"amount_inc_vat"` + DueDate string `json:"due_date"` + OCRReference string `json:"ocr_reference"` + IssuedAtMs int64 `json:"issued_at_ms"` +} + +func (i InvoiceIssued) Encode() ([]byte, error) { return json.Marshal(i) } + +func DecodeInvoiceIssued(raw []byte) (InvoiceIssued, error) { + var i InvoiceIssued + err := json.Unmarshal(raw, &i) + return i, err +} + +// InvoicePaid is the payload of an event.InvoicePaid envelope. +type InvoicePaid struct { + OrderID string `json:"order_id"` + InvoiceNumber string `json:"invoice_number"` + CompanyID string `json:"company_id,omitempty"` + AmountPaid int64 `json:"amount_paid"` + PaidAtMs int64 `json:"paid_at_ms"` +} + +func (i InvoicePaid) Encode() ([]byte, error) { return json.Marshal(i) } + +func DecodeInvoicePaid(raw []byte) (InvoicePaid, error) { + var i InvoicePaid + err := json.Unmarshal(raw, &i) + return i, err +} + diff --git a/order/order_test.go b/order/order_test.go index 8a0ebf1..b32d46b 100644 --- a/order/order_test.go +++ b/order/order_test.go @@ -28,3 +28,49 @@ func TestCreatedRoundTrip(t *testing.T) { t.Errorf("line[0] mismatch: %+v", out.Lines[0]) } } + +func TestInvoiceIssuedRoundTrip(t *testing.T) { + in := InvoiceIssued{ + OrderID: "ord-1", + InvoiceNumber: "INV-000001", + CompanyID: "comp-1", + CustomerEmail: "a@b.c", + AmountIncVat: 14995, + DueDate: "2026-09-15", + OCRReference: "00000139", + IssuedAtMs: 1234567890, + } + raw, err := in.Encode() + if err != nil { + t.Fatalf("encode: %v", err) + } + out, err := DecodeInvoiceIssued(raw) + if err != nil { + t.Fatalf("decode: %v", err) + } + if out.InvoiceNumber != in.InvoiceNumber || out.OCRReference != in.OCRReference || out.AmountIncVat != in.AmountIncVat { + t.Fatalf("round-trip mismatch: got %+v, want %+v", out, in) + } +} + +func TestInvoicePaidRoundTrip(t *testing.T) { + in := InvoicePaid{ + OrderID: "ord-1", + InvoiceNumber: "INV-000001", + CompanyID: "comp-1", + AmountPaid: 14995, + PaidAtMs: 1234567990, + } + raw, err := in.Encode() + if err != nil { + t.Fatalf("encode: %v", err) + } + out, err := DecodeInvoicePaid(raw) + if err != nil { + t.Fatalf("decode: %v", err) + } + if out.InvoiceNumber != in.InvoiceNumber || out.AmountPaid != in.AmountPaid { + t.Fatalf("round-trip mismatch: got %+v, want %+v", out, in) + } +} +