Files
go-cart-actor/pkg/cart/mutation_add_item.go
Mats Törnberg afa79e7b56
All checks were successful
Build and Publish / BuildAndDeployAmd64 (push) Successful in 36s
Build and Publish / BuildAndDeployArm64 (push) Successful in 3m43s
handle limited quantity
2025-11-26 21:35:40 +01:00

121 lines
3.0 KiB
Go

package cart
import (
"fmt"
messages "git.k6n.net/go-cart-actor/pkg/messages"
)
// mutation_add_item.go
//
// Registers the AddItem cart mutation in the generic mutation registry.
// This replaces the legacy switch-based logic previously found in CartGrain.Apply.
//
// Behavior:
// * Validates quantity > 0
// * If an item with same SKU exists -> increases quantity
// * Else creates a new CartItem with computed tax amounts
// * Totals recalculated automatically via WithTotals()
//
// NOTE: Any future field additions in messages.AddItem that affect pricing / tax
// must keep this handler in sync.
func AddItem(g *CartGrain, m *messages.AddItem) error {
if m == nil {
return fmt.Errorf("AddItem: nil payload")
}
if m.Quantity < 1 {
return fmt.Errorf("AddItem: invalid quantity %d", m.Quantity)
}
// Merge with any existing item having same SKU and matching StoreId (including both nil).
for _, existing := range g.Items {
if existing.Sku != m.Sku {
continue
}
sameStore := (existing.StoreId == nil && m.StoreId == nil) ||
(existing.StoreId != nil && m.StoreId != nil && *existing.StoreId == *m.StoreId)
if !sameStore {
continue
}
if m.ReservationEndTime != nil {
t := m.ReservationEndTime.AsTime()
if existing.ReservationEndTime == nil || existing.ReservationEndTime.Before(m.ReservationEndTime.AsTime()) {
existing.ReservationEndTime = &t
existing.Quantity = int(m.Quantity)
} else {
existing.ReservationEndTime = &t
}
} else {
existing.Quantity += int(m.Quantity)
}
existing.Stock = uint16(m.Stock)
// If existing had nil store but new has one, adopt it.
if existing.StoreId == nil && m.StoreId != nil {
existing.StoreId = m.StoreId
}
return nil
}
g.mu.Lock()
defer g.mu.Unlock()
g.lastItemId++
taxRate := float32(25.0)
if m.Tax > 0 {
taxRate = float32(int(m.Tax) / 100)
}
pricePerItem := NewPriceFromIncVat(m.Price, taxRate)
cartItem := &CartItem{
Id: g.lastItemId,
ItemId: uint32(m.ItemId),
Quantity: int(m.Quantity),
Sku: m.Sku,
Tax: int(taxRate * 100),
Meta: &ItemMeta{
Name: m.Name,
Image: m.Image,
Brand: m.Brand,
Category: m.Category,
Category2: m.Category2,
Category3: m.Category3,
Category4: m.Category4,
Category5: m.Category5,
Outlet: m.Outlet,
SellerName: m.SellerName,
},
SellerId: m.SellerId,
Cgm: m.Cgm,
SaleStatus: m.SaleStatus,
ParentId: m.ParentId,
Price: *pricePerItem,
TotalPrice: *MultiplyPrice(*pricePerItem, int64(m.Quantity)),
Stock: uint16(m.Stock),
Disclaimer: m.Disclaimer,
OrgPrice: getOrgPrice(m.OrgPrice, taxRate),
ArticleType: m.ArticleType,
StoreId: m.StoreId,
}
if m.ReservationEndTime != nil {
t := m.ReservationEndTime.AsTime()
cartItem.ReservationEndTime = &t
}
g.Items = append(g.Items, cartItem)
g.UpdateTotals()
return nil
}
func getOrgPrice(orgPrice int64, taxRate float32) *Price {
if orgPrice <= 0 {
return nil
}
return NewPriceFromIncVat(orgPrice, taxRate)
}