wishlist and dashboard
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/voucher"
|
||||
cart_messages "git.k6n.net/mats/go-cart-actor/proto/cart"
|
||||
"git.k6n.net/mats/go-redis-inventory/pkg/inventory"
|
||||
)
|
||||
|
||||
@@ -136,6 +137,7 @@ type CartGrain struct {
|
||||
Language string `json:"language"`
|
||||
Version uint `json:"version"`
|
||||
InventoryReserved bool `json:"inventoryReserved"`
|
||||
Type cart_messages.CartType `json:"type,omitempty"`
|
||||
Id CartId `json:"id"`
|
||||
Items []*CartItem `json:"items"`
|
||||
TotalPrice *Price `json:"totalPrice"`
|
||||
@@ -298,6 +300,10 @@ func (c *CartGrain) UpdateTotals() {
|
||||
|
||||
}
|
||||
|
||||
if c.Type == cart_messages.CartType_WISHLIST || c.Type == cart_messages.CartType_OFFER {
|
||||
return
|
||||
}
|
||||
|
||||
for _, voucher := range c.Vouchers {
|
||||
_, ok := voucher.AppliesTo(c)
|
||||
voucher.Applied = false
|
||||
|
||||
@@ -87,6 +87,7 @@ func NewCartMultationRegistry(context *CartMutationContext) actor.MutationRegist
|
||||
actor.NewMutation(RemoveLineItemMarking),
|
||||
actor.NewMutation(SetLineItemCustomFields),
|
||||
actor.NewMutation(SubscriptionAdded),
|
||||
actor.NewMutation(context.SetCartType),
|
||||
// actor.NewMutation(SubscriptionRemoved),
|
||||
)
|
||||
return reg
|
||||
|
||||
@@ -64,7 +64,7 @@ func (c *CartMutationContext) AddItem(g *CartGrain, m *cart_messages.AddItem) er
|
||||
if !sameStore {
|
||||
continue
|
||||
}
|
||||
if c.UseReservations(existing) {
|
||||
if g.Type == cart_messages.CartType_REGULAR && c.UseReservations(existing) {
|
||||
if err := c.ReleaseItem(ctx, g.Id, existing.Sku, existing.StoreId); err != nil {
|
||||
log.Printf("failed to release item %d: %v", existing.Id, err)
|
||||
}
|
||||
@@ -152,7 +152,7 @@ func (c *CartMutationContext) AddItem(g *CartGrain, m *cart_messages.AddItem) er
|
||||
DropShip: m.DropShip,
|
||||
}
|
||||
|
||||
if needsReservation && c.UseReservations(cartItem) {
|
||||
if g.Type == cart_messages.CartType_REGULAR && needsReservation && c.UseReservations(cartItem) {
|
||||
endTime, err := c.ReserveItem(ctx, g.Id, m.Sku, m.StoreId, uint16(m.Quantity))
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package cart
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
cart_messages "git.k6n.net/mats/go-cart-actor/proto/cart"
|
||||
"git.k6n.net/mats/platform/inventory"
|
||||
)
|
||||
|
||||
type mockReservationPolicy struct {
|
||||
reserveCount int
|
||||
releaseCount int
|
||||
}
|
||||
|
||||
func (m *mockReservationPolicy) Reserve(ctx context.Context, req inventory.CartReserveRequest) error {
|
||||
m.reserveCount++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockReservationPolicy) Release(ctx context.Context, sku inventory.SKU, locationID inventory.LocationID, cartID inventory.CartID) error {
|
||||
m.releaseCount++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockReservationPolicy) Available(ctx context.Context, sku inventory.SKU, locationID inventory.LocationID) (int64, error) {
|
||||
return 100, nil
|
||||
}
|
||||
|
||||
func TestCartType_TransitionsAndReservations(t *testing.T) {
|
||||
mockPolicy := &mockReservationPolicy{}
|
||||
mutationCtx := NewCartMutationContext(mockPolicy)
|
||||
reg := NewCartMultationRegistry(mutationCtx)
|
||||
g := NewCartGrain(1, time.Now())
|
||||
ctx := context.Background()
|
||||
|
||||
// 1. Initially REGULAR, adding item should trigger reservation
|
||||
g.Type = cart_messages.CartType_REGULAR
|
||||
_, err := reg.Apply(ctx, g, &cart_messages.AddItem{
|
||||
ItemId: 101,
|
||||
Sku: "SKU-1",
|
||||
Quantity: 1,
|
||||
Price: 1000,
|
||||
InventoryTracked: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("AddItem (REGULAR) failed: %v", err)
|
||||
}
|
||||
if mockPolicy.reserveCount != 1 {
|
||||
t.Errorf("Expected 1 reserve call, got %d", mockPolicy.reserveCount)
|
||||
}
|
||||
|
||||
// 2. Set type to WISHLIST. This should release active reservations.
|
||||
_, err = reg.Apply(ctx, g, &cart_messages.SetCartType{
|
||||
Type: cart_messages.CartType_WISHLIST,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("SetCartType (WISHLIST) failed: %v", err)
|
||||
}
|
||||
if g.Type != cart_messages.CartType_WISHLIST {
|
||||
t.Errorf("Expected type to be WISHLIST, got %v", g.Type)
|
||||
}
|
||||
if mockPolicy.releaseCount != 1 {
|
||||
t.Errorf("Expected 1 release call during transition, got %d", mockPolicy.releaseCount)
|
||||
}
|
||||
|
||||
// 3. AddItem in WISHLIST should NOT trigger reservation
|
||||
_, err = reg.Apply(ctx, g, &cart_messages.AddItem{
|
||||
ItemId: 102,
|
||||
Sku: "SKU-2",
|
||||
Quantity: 1,
|
||||
Price: 2000,
|
||||
InventoryTracked: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("AddItem (WISHLIST) failed: %v", err)
|
||||
}
|
||||
if mockPolicy.reserveCount != 1 { // Should still be 1 from step 1
|
||||
t.Errorf("Expected reserve count to remain 1, got %d", mockPolicy.reserveCount)
|
||||
}
|
||||
|
||||
// 4. Verify simple price sum is updated, but vouchers are not applied
|
||||
g.Vouchers = append(g.Vouchers, &Voucher{
|
||||
Code: "DISCOUNT",
|
||||
Value: 500,
|
||||
Applied: false,
|
||||
})
|
||||
g.UpdateTotals()
|
||||
// Total price should be sum of 1000 + 2000 = 3000
|
||||
if g.TotalPrice.IncVat != 3000 {
|
||||
t.Errorf("Expected total price 3000, got %d", g.TotalPrice.IncVat)
|
||||
}
|
||||
if g.Vouchers[0].Applied {
|
||||
t.Errorf("Expected voucher to NOT be applied in WISHLIST")
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ func (c *CartMutationContext) ChangeQuantity(g *CartGrain, m *messages.ChangeQua
|
||||
if item == nil {
|
||||
return fmt.Errorf("ChangeQuantity: item id %d not found", m.Id)
|
||||
}
|
||||
if c.UseReservations(item) {
|
||||
if g.Type == messages.CartType_REGULAR && c.UseReservations(item) {
|
||||
if item.ReservationEndTime != nil {
|
||||
err := c.ReleaseItem(ctx, g.Id, item.Sku, item.StoreId)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package cart
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
messages "git.k6n.net/mats/go-cart-actor/proto/cart"
|
||||
)
|
||||
|
||||
func (c *CartMutationContext) SetCartType(g *CartGrain, m *messages.SetCartType) error {
|
||||
if m == nil {
|
||||
return fmt.Errorf("SetCartType: nil payload")
|
||||
}
|
||||
|
||||
oldType := g.Type
|
||||
newType := m.Type
|
||||
|
||||
if oldType == newType {
|
||||
return nil
|
||||
}
|
||||
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
|
||||
g.Type = newType
|
||||
|
||||
// If transitioning from regular to wishlist or offer, release any active reservations
|
||||
if oldType == messages.CartType_REGULAR && (newType == messages.CartType_WISHLIST || newType == messages.CartType_OFFER) {
|
||||
ctx := context.Background()
|
||||
for _, item := range g.Items {
|
||||
if item.ReservationEndTime != nil {
|
||||
_ = c.ReleaseItem(ctx, g.Id, item.Sku, item.StoreId)
|
||||
item.ReservationEndTime = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g.UpdateTotals()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user