From 7995fedbd381cb855383f29826605dd32051b7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Tue, 1 Sep 2026 14:26:57 +0200 Subject: [PATCH] more auth --- event/event.go | 5 +++++ order/order.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/event/event.go b/event/event.go index 9d90b12..fec3300 100644 --- a/event/event.go +++ b/event/event.go @@ -87,6 +87,11 @@ const ( // 261x D per rate), idempotent per refund id. Invoice orders reverse via // credit notes (invoice.credited), so RefundIssued never fires for them. RefundIssued Type = "refund.issued" + // OfferAccepted is emitted when a B2B offer (offert) is accepted — it + // becomes the agreement (avtal). The ledger consumes it (durable queue + // ledger-offer-contracts) and creates/activates a Contract carrying the + // offer's line items. Payload is an order.OfferAccepted (platform/order). + OfferAccepted Type = "offer.accepted" // Scheduling (go-cart-actor cmd/scheduling). Emitted when timeslots are // confirmed from an order capture or cancelled. diff --git a/order/order.go b/order/order.go index b5f0023..065221d 100644 --- a/order/order.go +++ b/order/order.go @@ -145,6 +145,44 @@ func DecodeInvoiceCredited(raw []byte) (InvoiceCredited, error) { return c, err } +// OfferLine is one line of an accepted offer — the quotation row the ledger +// contract carries. UnitPriceIncVat is öre; TaxRateBp is basis points +// (2500 = 25 %). +type OfferLine struct { + Sku string `json:"sku,omitempty"` + Name string `json:"name"` + Quantity int `json:"quantity"` + UnitPriceIncVat int64 `json:"unit_price_inc_vat,omitempty"` + TaxRateBp int `json:"tax_rate_bp,omitempty"` +} + +// OfferAccepted is the payload of an event.OfferAccepted envelope: a B2B +// offer (offert) was accepted and becomes the agreement (avtal). The payload +// carries the offer identity, the buyer company, and the offer's line items +// so the consumer — the ledger's offer reactor — can create/activate the +// contract exactly as offered. Lines may be empty defensively; reactors must +// still record the acceptance as an agreement covering the referenced offer. +type OfferAccepted struct { + OrderID string `json:"order_id"` + OfferNumber string `json:"offer_number"` + CompanyID string `json:"company_id,omitempty"` + CompanyName string `json:"company_name,omitempty"` + OrgNumber string `json:"org_number,omitempty"` + CustomerEmail string `json:"customer_email,omitempty"` + ValidUntil string `json:"valid_until,omitempty"` + AcceptedAtMs int64 `json:"accepted_at_ms"` + Notes string `json:"notes,omitempty"` + Lines []OfferLine `json:"lines,omitempty"` +} + +func (o OfferAccepted) Encode() ([]byte, error) { return json.Marshal(o) } + +func DecodeOfferAccepted(raw []byte) (OfferAccepted, error) { + var o OfferAccepted + err := json.Unmarshal(raw, &o) + return o, err +} + // SalePaid is the payload of an event.SalePaid envelope: a consumer (PSP) // order was captured. It is the accounting fact for shop sales — the ledger // aggregates captured sales into the daily SHOP- voucher (clearing D /