update
All checks were successful
Build and Publish / BuildAndDeployAmd64 (push) Successful in 35s
Build and Publish / BuildAndDeployArm64 (push) Successful in 3m45s

This commit is contained in:
matst80
2025-11-27 12:45:34 +01:00
parent c2a137d8d4
commit aea168160e
14 changed files with 335 additions and 335 deletions

View File

@@ -41,7 +41,7 @@ type CartItem struct {
Cgm string `json:"cgm,omitempty"`
Tax int
Stock uint16 `json:"stock"`
Quantity int `json:"qty"`
Quantity uint16 `json:"qty"`
Discount *Price `json:"discount,omitempty"`
Disclaimer string `json:"disclaimer,omitempty"`
ArticleType string `json:"type,omitempty"`

View File

@@ -2,6 +2,7 @@ package cart
import (
"context"
"time"
"git.k6n.net/go-cart-actor/pkg/actor"
messages "git.k6n.net/go-cart-actor/pkg/messages"
@@ -12,32 +13,48 @@ type CartMutationContext struct {
reservationService inventory.CartReservationService
}
func NewCartMutationContext(reservationService inventory.CartReservationService) CartMutationContext {
return CartMutationContext{
func NewCartMutationContext(reservationService inventory.CartReservationService) *CartMutationContext {
return &CartMutationContext{
reservationService: reservationService,
}
}
func (c *CartMutationContext) ReserveItem(ctx context.Context, cartId CartId, sku string, locationId string, quantity int) error {
func (c *CartMutationContext) ReserveItem(ctx context.Context, cartId CartId, sku string, locationId *string, quantity uint16) (*time.Time, error) {
if quantity <= 0 || c.reservationService == nil {
return nil
return nil, nil
}
return c.reservationService.ReserveForCart(ctx, inventory.CartReserveRequest{
l := inventory.LocationID("se")
if locationId != nil {
l = inventory.LocationID(*locationId)
}
ttl := time.Minute * 15
endTime := time.Now().Add(ttl)
err := c.reservationService.ReserveForCart(ctx, inventory.CartReserveRequest{
CartID: inventory.CartID(cartId.String()),
InventoryReference: &inventory.InventoryReference{
SKU: inventory.SKU(sku),
LocationID: inventory.LocationID(locationId),
LocationID: l,
},
TTL: ttl,
Quantity: uint32(quantity),
})
if err != nil {
return nil, err
}
return &endTime, nil
}
func (c *CartMutationContext) ReleaseItem(ctx context.Context, cartId CartId, sku string, locationId string) error {
func (c *CartMutationContext) ReleaseItem(ctx context.Context, cartId CartId, sku string, locationId *string) error {
if c.reservationService == nil {
return nil
}
return c.reservationService.ReleaseForCart(ctx, inventory.SKU(sku), inventory.LocationID(locationId), inventory.CartID(cartId.String()))
l := inventory.LocationID("se")
if locationId != nil {
l = inventory.LocationID(*locationId)
}
return c.reservationService.ReleaseForCart(ctx, inventory.SKU(sku), l, inventory.CartID(cartId.String()))
}
func NewCartMultationRegistry(context *CartMutationContext) actor.MutationRegistry {

View File

@@ -1,7 +1,9 @@
package cart
import (
"context"
"fmt"
"log"
messages "git.k6n.net/go-cart-actor/pkg/messages"
)
@@ -21,6 +23,7 @@ import (
// must keep this handler in sync.
func (c *CartMutationContext) AddItem(g *CartGrain, m *messages.AddItem) error {
ctx := context.Background()
if m == nil {
return fmt.Errorf("AddItem: nil payload")
}
@@ -38,18 +41,15 @@ func (c *CartMutationContext) AddItem(g *CartGrain, m *messages.AddItem) error {
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)
if err := c.ReleaseItem(ctx, g.Id, existing.Sku, existing.StoreId); err != nil {
log.Printf("failed to release item %d: %v", existing.Id, err)
}
endTime, err := c.ReserveItem(ctx, g.Id, existing.Sku, existing.StoreId, existing.Quantity+uint16(m.Quantity))
if err != nil {
return err
}
existing.ReservationEndTime = endTime
existing.Quantity += uint16(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 {
@@ -69,10 +69,15 @@ func (c *CartMutationContext) AddItem(g *CartGrain, m *messages.AddItem) error {
}
pricePerItem := NewPriceFromIncVat(m.Price, taxRate)
endTime, err := c.ReserveItem(ctx, g.Id, m.Sku, m.StoreId, uint16(m.Quantity))
if err != nil {
return err
}
cartItem := &CartItem{
Id: g.lastItemId,
ItemId: uint32(m.ItemId),
Quantity: int(m.Quantity),
Quantity: uint16(m.Quantity),
Sku: m.Sku,
Tax: int(taxRate * 100),
Meta: &ItemMeta{
@@ -101,12 +106,10 @@ func (c *CartMutationContext) AddItem(g *CartGrain, m *messages.AddItem) error {
OrgPrice: getOrgPrice(m.OrgPrice, taxRate),
ArticleType: m.ArticleType,
StoreId: m.StoreId,
}
if m.ReservationEndTime != nil {
t := m.ReservationEndTime.AsTime()
cartItem.ReservationEndTime = &t
StoreId: m.StoreId,
ReservationEndTime: endTime,
}
g.Items = append(g.Items, cartItem)
g.UpdateTotals()
return nil

View File

@@ -1,7 +1,9 @@
package cart
import (
"context"
"fmt"
"log"
messages "git.k6n.net/go-cart-actor/pkg/messages"
)
@@ -30,6 +32,7 @@ func (c *CartMutationContext) ChangeQuantity(g *CartGrain, m *messages.ChangeQua
if m == nil {
return fmt.Errorf("ChangeQuantity: nil payload")
}
ctx := context.Background()
foundIndex := -1
for i, it := range g.Items {
@@ -44,6 +47,11 @@ func (c *CartMutationContext) ChangeQuantity(g *CartGrain, m *messages.ChangeQua
if m.Quantity <= 0 {
// Remove the item
itemToRemove := g.Items[foundIndex]
err := c.ReleaseItem(ctx, g.Id, itemToRemove.Sku, itemToRemove.StoreId)
if err != nil {
log.Printf("unable to release reservation for %s in location: %v", itemToRemove.Sku, itemToRemove.StoreId)
}
g.Items = append(g.Items[:foundIndex], g.Items[foundIndex+1:]...)
g.UpdateTotals()
return nil
@@ -53,10 +61,19 @@ func (c *CartMutationContext) ChangeQuantity(g *CartGrain, m *messages.ChangeQua
return fmt.Errorf("ChangeQuantity: item id %d not found", m.Id)
}
if item.ReservationEndTime != nil {
return fmt.Errorf("ChangeQuantity: cannot change quantity of reserved item id %d", m.Id)
} else {
item.Quantity = int(m.Quantity)
g.UpdateTotals()
err := c.ReleaseItem(ctx, g.Id, item.Sku, item.StoreId)
if err != nil {
log.Printf("unable to release reservation for %s in location: %v", item.Sku, item.StoreId)
}
}
endTime, err := c.ReserveItem(ctx, g.Id, item.Sku, item.StoreId, uint16(m.Quantity))
if err != nil {
return err
}
item.ReservationEndTime = endTime
item.Quantity = uint16(m.Quantity)
g.UpdateTotals()
return nil
}

View File

@@ -1,8 +1,22 @@
package cart
import "git.k6n.net/go-cart-actor/pkg/messages"
import (
"context"
"log"
"time"
"git.k6n.net/go-cart-actor/pkg/messages"
)
func (c *CartMutationContext) InventoryReserved(g *CartGrain, m *messages.InventoryReserved) error {
for _, item := range g.Items {
if item.ReservationEndTime != nil && item.ReservationEndTime.After(time.Now()) {
err := c.ReleaseItem(context.Background(), g.Id, item.Sku, item.StoreId)
if err != nil {
log.Printf("unable to release item reservation")
}
}
}
g.InventoryReserved = true
return nil
}

View File

@@ -1,7 +1,10 @@
package cart
import (
"context"
"fmt"
"log"
"time"
messages "git.k6n.net/go-cart-actor/pkg/messages"
)
@@ -39,6 +42,14 @@ func (c *CartMutationContext) RemoveItem(g *CartGrain, m *messages.RemoveItem) e
return fmt.Errorf("RemoveItem: item id %d not found", m.Id)
}
item := g.Items[index]
if item.ReservationEndTime != nil && item.ReservationEndTime.After(time.Now()) {
err := c.ReleaseItem(context.Background(), g.Id, item.Sku, item.StoreId)
if err != nil {
log.Printf("unable to release item reservation")
}
}
g.Items = append(g.Items[:index], g.Items[index+1:]...)
g.UpdateTotals()
return nil

View File

@@ -37,15 +37,25 @@ func (m *MockReservationService) ReleaseForCart(ctx context.Context, sku invento
return nil
}
func (m *MockReservationService) GetAvailableInventory(ctx context.Context, sku inventory.SKU, locationID inventory.LocationID) (uint32, error) {
func (m *MockReservationService) GetAvailableInventory(ctx context.Context, sku inventory.SKU, locationID inventory.LocationID) (int64, error) {
return 1000, nil
}
func (m *MockReservationService) GetReservationExpiry(ctx context.Context, sku inventory.SKU, locationID inventory.LocationID, cartID inventory.CartID) (time.Time, error) {
return time.Time{}, nil
}
func (m *MockReservationService) GetReservationStatus(ctx context.Context, sku inventory.SKU, locationID inventory.LocationID, cartID inventory.CartID) (*inventory.ReservationStatus, error) {
return nil, nil
}
func (m *MockReservationService) GetReservationSummary(ctx context.Context, sku inventory.SKU, locationID inventory.LocationID) (*inventory.ReservationSummary, error) {
return nil, nil
}
func newRegistry() actor.MutationRegistry {
cartCtx := &CartMutationContext{
reservationService: &MockReservationService{
reservations: []messages.Reservation{},
},
reservationService: &MockReservationService{},
}
return NewCartMultationRegistry(cartCtx)
}