Co-authored-by: matst80 <mats.tornberg@gmail.com> Reviewed-on: https://git.tornberg.me/mats/go-cart-actor/pulls/6 Co-authored-by: Mats Törnberg <mats@tornberg.me> Co-committed-by: Mats Törnberg <mats@tornberg.me>
97 lines
2.8 KiB
Go
97 lines
2.8 KiB
Go
package cart
|
||
|
||
import (
|
||
"fmt"
|
||
"slices"
|
||
|
||
messages "git.tornberg.me/go-cart-actor/pkg/messages"
|
||
)
|
||
|
||
// mutation_set_delivery.go
|
||
//
|
||
// Registers the SetDelivery mutation.
|
||
//
|
||
// Semantics (mirrors legacy switch logic):
|
||
// - If the payload specifies an explicit list of item IDs (payload.Items):
|
||
// - Each referenced cart line must exist.
|
||
// - None of the referenced items may already belong to a delivery.
|
||
// - Only those items are associated with the new delivery.
|
||
// - If payload.Items is empty:
|
||
// - All items currently without any delivery are associated with the new delivery.
|
||
// - A new delivery line is created with:
|
||
// - Auto-incremented delivery ID (cart-local)
|
||
// - Provider from payload
|
||
// - Fixed price (currently hard-coded: 4900 minor units) – adjust as needed
|
||
// - Optional PickupPoint copied from payload
|
||
// - Cart totals are recalculated (WithTotals)
|
||
//
|
||
// Error cases:
|
||
// - Referenced item does not exist
|
||
// - Referenced item already has a delivery
|
||
// - No items qualify (resulting association set empty) -> returns error (prevents creating empty delivery)
|
||
//
|
||
// Concurrency:
|
||
// - Uses g.mu to protect lastDeliveryId increment and append to Deliveries slice.
|
||
// Item scans are read-only and performed outside the lock for simplicity;
|
||
// if stricter guarantees are needed, widen the lock section.
|
||
//
|
||
// Future extension points:
|
||
// - Variable delivery pricing (based on weight, distance, provider, etc.)
|
||
// - Validation of provider codes
|
||
// - Multi-currency delivery pricing
|
||
|
||
func SetDelivery(g *CartGrain, m *messages.SetDelivery) error {
|
||
if m == nil {
|
||
return fmt.Errorf("SetDelivery: nil payload")
|
||
}
|
||
if m.Provider == "" {
|
||
return fmt.Errorf("SetDelivery: provider is empty")
|
||
}
|
||
|
||
withDelivery := g.ItemsWithDelivery()
|
||
targetItems := make([]uint32, 0)
|
||
|
||
if len(m.Items) == 0 {
|
||
// Use every item currently without a delivery
|
||
targetItems = append(targetItems, g.ItemsWithoutDelivery()...)
|
||
} else {
|
||
// Validate explicit list
|
||
for _, id64 := range m.Items {
|
||
id := uint32(id64)
|
||
found := false
|
||
for _, it := range g.Items {
|
||
if it.Id == id {
|
||
found = true
|
||
break
|
||
}
|
||
}
|
||
if !found {
|
||
return fmt.Errorf("SetDelivery: item id %d not found", id)
|
||
}
|
||
if slices.Contains(withDelivery, id) {
|
||
return fmt.Errorf("SetDelivery: item id %d already has a delivery", id)
|
||
}
|
||
targetItems = append(targetItems, id)
|
||
}
|
||
}
|
||
|
||
if len(targetItems) == 0 {
|
||
return fmt.Errorf("SetDelivery: no eligible items to attach")
|
||
}
|
||
|
||
// Append new delivery
|
||
g.mu.Lock()
|
||
g.lastDeliveryId++
|
||
newId := g.lastDeliveryId
|
||
g.Deliveries = append(g.Deliveries, &CartDelivery{
|
||
Id: newId,
|
||
Provider: m.Provider,
|
||
PickupPoint: m.PickupPoint,
|
||
Price: *NewPriceFromIncVat(4900, 25.0),
|
||
Items: targetItems,
|
||
})
|
||
g.mu.Unlock()
|
||
|
||
return nil
|
||
}
|