cart and checkout
Build and Publish / BuildAndDeployAmd64 (push) Failing after 4s
Build and Publish / BuildAndDeployArm64 (push) Failing after 6s

This commit is contained in:
2026-06-27 19:49:00 +02:00
parent 492f54ff45
commit 528c59bfd3
67 changed files with 3618 additions and 1031 deletions
+146 -4
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"os"
"time"
"git.k6n.net/mats/go-cart-actor/pkg/flow"
@@ -100,7 +101,7 @@ type fulfillReq struct {
}
func (s *server) handleFulfill(w http.ResponseWriter, r *http.Request) {
id, _, ok := s.loadOrder(w, r)
id, g, ok := s.loadOrder(w, r)
if !ok {
return
}
@@ -110,11 +111,72 @@ func (s *server) handleFulfill(w http.ResponseWriter, r *http.Request) {
return
}
fid, _ := order.NewOrderId()
carrier := req.Carrier
trackingNumber := req.TrackingNumber
trackingURI := req.TrackingURI
// Integration with go-shipping:
if carrier == "" && g.CartId != "" {
shippingURL := os.Getenv("SHIPPING_URL")
if shippingURL == "" {
shippingURL = "http://localhost:8080"
}
// Query go-shipping for cached options
url := fmt.Sprintf("%s/api/shipping-options/%s", shippingURL, g.CartId)
ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
defer cancel()
httpReq, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err == nil {
resp, err := http.DefaultClient.Do(httpReq)
if err == nil && resp.StatusCode == http.StatusOK {
var groups []struct {
Type string `json:"type"`
DefaultOption *struct {
BookingInstructions struct {
DeliveryOptionID string `json:"deliveryOptionId"`
ServiceCode string `json:"serviceCode"`
} `json:"bookingInstructions"`
DescriptiveTexts struct {
Checkout struct {
Title string `json:"title"`
} `json:"checkout"`
} `json:"descriptiveTexts"`
} `json:"defaultOption"`
}
if json.NewDecoder(resp.Body).Decode(&groups) == nil && len(groups) > 0 {
g0 := groups[0]
carrier = g0.Type
if g0.DefaultOption != nil {
opt := g0.DefaultOption
if opt.DescriptiveTexts.Checkout.Title != "" {
carrier = opt.DescriptiveTexts.Checkout.Title
}
trackingNumber = "SE-" + opt.BookingInstructions.DeliveryOptionID
trackingURI = "https://www.postnord.se/en/our-tools/track-and-trace?shipmentId=" + trackingNumber
}
}
resp.Body.Close()
}
}
}
if carrier == "" {
carrier = "postnord"
}
if trackingNumber == "" {
trackingNumber = "mock-track-" + fid.String()
}
if trackingURI == "" {
trackingURI = "https://tracking.postnord.com/?id=" + trackingNumber
}
msg := &messages.CreateFulfillment{
Id: "f_" + fid.String(),
Carrier: req.Carrier,
TrackingNumber: req.TrackingNumber,
TrackingUri: req.TrackingURI,
Carrier: carrier,
TrackingNumber: trackingNumber,
TrackingUri: trackingURI,
AtMs: nowMs(),
}
for _, l := range req.Lines {
@@ -123,6 +185,86 @@ func (s *server) handleFulfill(w http.ResponseWriter, r *http.Request) {
s.applyAndRespond(w, r, id, msg)
}
type exchangeReq struct {
Reason string `json:"reason,omitempty"`
ReturnLines []struct {
Reference string `json:"reference"`
Quantity int32 `json:"quantity"`
} `json:"returnLines"`
NewLines []struct {
Reference string `json:"reference"`
Sku string `json:"sku"`
Name string `json:"name"`
Quantity int32 `json:"quantity"`
UnitPrice int64 `json:"unitPrice"`
TaxRate int32 `json:"taxRate"`
TotalAmount int64 `json:"totalAmount"`
TotalTax int64 `json:"totalTax"`
} `json:"newLines"`
}
func (s *server) handleExchange(w http.ResponseWriter, r *http.Request) {
id, _, ok := s.loadOrder(w, r)
if !ok {
return
}
var req exchangeReq
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeErr(w, http.StatusBadRequest, err)
return
}
exId, _ := order.NewOrderId()
retId, _ := order.NewOrderId()
msg := &messages.RequestExchange{
Id: "ex_" + exId.String(),
ReturnId: "r_" + retId.String(),
Reason: req.Reason,
AtMs: nowMs(),
}
for _, l := range req.ReturnLines {
msg.ReturnLines = append(msg.ReturnLines, &messages.FulfillmentLine{Reference: l.Reference, Quantity: l.Quantity})
}
for _, l := range req.NewLines {
msg.NewLines = append(msg.NewLines, &messages.OrderLine{
Reference: l.Reference,
Sku: l.Sku,
Name: l.Name,
Quantity: l.Quantity,
UnitPrice: l.UnitPrice,
TaxRate: l.TaxRate,
TotalAmount: l.TotalAmount,
TotalTax: l.TotalTax,
})
}
s.applyAndRespond(w, r, id, msg)
}
type editDetailsReq struct {
ShippingAddress json.RawMessage `json:"shippingAddress,omitempty"`
BillingAddress json.RawMessage `json:"billingAddress,omitempty"`
ShippingPrice int64 `json:"shippingPrice,omitempty"`
}
func (s *server) handleEditDetails(w http.ResponseWriter, r *http.Request) {
id, _, ok := s.loadOrder(w, r)
if !ok {
return
}
var req editDetailsReq
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeErr(w, http.StatusBadRequest, err)
return
}
msg := &messages.EditOrderDetails{
ShippingAddress: req.ShippingAddress,
BillingAddress: req.BillingAddress,
ShippingPrice: req.ShippingPrice,
AtMs: nowMs(),
}
s.applyAndRespond(w, r, id, msg)
}
func (s *server) handleComplete(w http.ResponseWriter, r *http.Request) {
id, _, ok := s.loadOrder(w, r)
if !ok {