add giftcards
This commit is contained in:
@@ -89,17 +89,29 @@ type Marking struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type GiftcardItem struct {
|
||||
Id uint32 `json:"id"`
|
||||
Value Price `json:"value"`
|
||||
DeliveryDate string `json:"deliveryDate"`
|
||||
Recipient string `json:"recipient"`
|
||||
RecipientType string `json:"recipientType"`
|
||||
Message string `json:"message"`
|
||||
DesignConfig json.RawMessage `json:"designConfig,omitempty"`
|
||||
}
|
||||
|
||||
type CartGrain struct {
|
||||
mu sync.RWMutex
|
||||
lastItemId uint32
|
||||
lastDeliveryId uint32
|
||||
lastVoucherId uint32
|
||||
lastGiftcardId uint32
|
||||
lastAccess time.Time
|
||||
lastChange time.Time // unix seconds of last successful mutation (replay sets from event ts)
|
||||
userId string
|
||||
InventoryReserved bool `json:"inventoryReserved"`
|
||||
Id CartId `json:"id"`
|
||||
Items []*CartItem `json:"items"`
|
||||
Giftcards []*GiftcardItem `json:"giftcards,omitempty"`
|
||||
TotalPrice *Price `json:"totalPrice"`
|
||||
TotalDiscount *Price `json:"totalDiscount"`
|
||||
Deliveries []*CartDelivery `json:"deliveries,omitempty"`
|
||||
@@ -185,11 +197,13 @@ func NewCartGrain(id uint64, ts time.Time) *CartGrain {
|
||||
lastItemId: 0,
|
||||
lastDeliveryId: 0,
|
||||
lastVoucherId: 0,
|
||||
lastGiftcardId: 0,
|
||||
lastAccess: ts,
|
||||
lastChange: ts,
|
||||
TotalDiscount: NewPrice(),
|
||||
Vouchers: []*Voucher{},
|
||||
Deliveries: []*CartDelivery{},
|
||||
Giftcards: []*GiftcardItem{},
|
||||
Id: CartId(id),
|
||||
Items: []*CartItem{},
|
||||
TotalPrice: NewPrice(),
|
||||
@@ -337,6 +351,9 @@ func (c *CartGrain) UpdateTotals() {
|
||||
for _, delivery := range c.Deliveries {
|
||||
c.TotalPrice.Add(delivery.Price)
|
||||
}
|
||||
for _, giftcard := range c.Giftcards {
|
||||
c.TotalPrice.Add(giftcard.Value)
|
||||
}
|
||||
for _, voucher := range c.Vouchers {
|
||||
_, ok := voucher.AppliesTo(c)
|
||||
voucher.Applied = false
|
||||
|
||||
@@ -72,6 +72,12 @@ func NewCartMultationRegistry() actor.MutationRegistry {
|
||||
actor.NewMutation(CreateCheckoutOrder, func() *messages.CreateCheckoutOrder {
|
||||
return &messages.CreateCheckoutOrder{}
|
||||
}),
|
||||
actor.NewMutation(AddGiftcard, func() *messages.AddGiftcard {
|
||||
return &messages.AddGiftcard{}
|
||||
}),
|
||||
actor.NewMutation(RemoveGiftcard, func() *messages.RemoveGiftcard {
|
||||
return &messages.RemoveGiftcard{}
|
||||
}),
|
||||
)
|
||||
return reg
|
||||
|
||||
|
||||
41
pkg/cart/mutation_add_giftcard.go
Normal file
41
pkg/cart/mutation_add_giftcard.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package cart
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
messages "git.tornberg.me/go-cart-actor/pkg/messages"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func AddGiftcard(grain *CartGrain, req *messages.AddGiftcard) error {
|
||||
if req.Giftcard == nil {
|
||||
return fmt.Errorf("giftcard cannot be nil")
|
||||
}
|
||||
if req.Giftcard.Value <= 0 {
|
||||
return fmt.Errorf("giftcard value must be positive")
|
||||
}
|
||||
grain.lastGiftcardId++
|
||||
designConfig := json.RawMessage{}
|
||||
if req.Giftcard.DesignConfig != nil {
|
||||
// Convert Any to RawMessage
|
||||
data, err := proto.Marshal(req.Giftcard.DesignConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal designConfig: %w", err)
|
||||
}
|
||||
designConfig = data
|
||||
}
|
||||
value := NewPriceFromIncVat(req.Giftcard.Value, 25) // Assuming 25% tax; adjust as needed
|
||||
item := &GiftcardItem{
|
||||
Id: grain.lastGiftcardId,
|
||||
Value: *value,
|
||||
DeliveryDate: req.Giftcard.DeliveryDate,
|
||||
Recipient: req.Giftcard.Recipient,
|
||||
RecipientType: req.Giftcard.RecipientType,
|
||||
Message: req.Giftcard.Message,
|
||||
DesignConfig: designConfig,
|
||||
}
|
||||
grain.Giftcards = append(grain.Giftcards, item)
|
||||
grain.UpdateTotals()
|
||||
return nil
|
||||
}
|
||||
18
pkg/cart/mutation_remove_giftcard.go
Normal file
18
pkg/cart/mutation_remove_giftcard.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package cart
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
messages "git.tornberg.me/go-cart-actor/pkg/messages"
|
||||
)
|
||||
|
||||
func RemoveGiftcard(grain *CartGrain, req *messages.RemoveGiftcard) error {
|
||||
for i, item := range grain.Giftcards {
|
||||
if item.Id == req.Id {
|
||||
grain.Giftcards = append(grain.Giftcards[:i], grain.Giftcards[i+1:]...)
|
||||
grain.UpdateTotals()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("giftcard with ID %d not found", req.Id)
|
||||
}
|
||||
@@ -113,6 +113,23 @@ func msgCreateCheckoutOrder(terms, country string) *messages.CreateCheckoutOrder
|
||||
return &messages.CreateCheckoutOrder{Terms: terms, Country: country}
|
||||
}
|
||||
|
||||
func msgAddGiftcard(value int64, deliveryDate, recipient, recipientType, message string, designConfig *anypb.Any) *messages.AddGiftcard {
|
||||
return &messages.AddGiftcard{
|
||||
Giftcard: &messages.GiftcardItem{
|
||||
Value: value,
|
||||
DeliveryDate: deliveryDate,
|
||||
Recipient: recipient,
|
||||
RecipientType: recipientType,
|
||||
Message: message,
|
||||
DesignConfig: designConfig,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func msgRemoveGiftcard(id uint32) *messages.RemoveGiftcard {
|
||||
return &messages.RemoveGiftcard{Id: id}
|
||||
}
|
||||
|
||||
func ptr[T any](v T) *T { return &v }
|
||||
|
||||
// ----------------------
|
||||
@@ -181,6 +198,8 @@ func TestMutationRegistryCoverage(t *testing.T) {
|
||||
"PaymentDeclined",
|
||||
"ConfirmationViewed",
|
||||
"CreateCheckoutOrder",
|
||||
"AddGiftcard",
|
||||
"RemoveGiftcard",
|
||||
}
|
||||
|
||||
names := reg.(*actor.ProtoMutationRegistry).RegisteredMutations()
|
||||
@@ -675,7 +694,7 @@ func TestConfirmationViewed(t *testing.T) {
|
||||
|
||||
// Initial state
|
||||
if g.Confirmation != nil {
|
||||
t.Fatalf("confirmation should be nil, got %d", g.Confirmation)
|
||||
t.Fatalf("confirmation should be nil, got %v", g.Confirmation)
|
||||
}
|
||||
|
||||
// First view
|
||||
@@ -717,3 +736,43 @@ func TestCreateCheckoutOrder(t *testing.T) {
|
||||
// Terms not accepted
|
||||
applyErrorContains(t, reg, g, msgCreateCheckoutOrder("no", ""), "terms must be accepted")
|
||||
}
|
||||
|
||||
func TestAddGiftcard(t *testing.T) {
|
||||
reg := newRegistry()
|
||||
g := newTestGrain()
|
||||
|
||||
designConfig, _ := anypb.New(&messages.AddItem{}) // example
|
||||
applyOK(t, reg, g, msgAddGiftcard(5000, "2023-12-25", "John", "email", "Happy Birthday!", designConfig))
|
||||
|
||||
if len(g.Giftcards) != 1 {
|
||||
t.Fatalf("expected 1 giftcard, got %d", len(g.Giftcards))
|
||||
}
|
||||
gc := g.Giftcards[0]
|
||||
if gc.Value.IncVat != 5000 || gc.DeliveryDate != "2023-12-25" || gc.Recipient != "John" || gc.RecipientType != "email" || gc.Message != "Happy Birthday!" {
|
||||
t.Fatalf("giftcard not set correctly: %+v", gc)
|
||||
}
|
||||
if g.TotalPrice.IncVat != 5000 {
|
||||
t.Fatalf("total price not updated, got %d", g.TotalPrice.IncVat)
|
||||
}
|
||||
|
||||
// Test invalid value
|
||||
applyErrorContains(t, reg, g, msgAddGiftcard(0, "", "", "", "", nil), "must be positive")
|
||||
}
|
||||
|
||||
func TestRemoveGiftcard(t *testing.T) {
|
||||
reg := newRegistry()
|
||||
g := newTestGrain()
|
||||
|
||||
applyOK(t, reg, g, msgAddGiftcard(1000, "2023-01-01", "Jane", "sms", "Cheers!", nil))
|
||||
id := g.Giftcards[0].Id
|
||||
|
||||
applyOK(t, reg, g, msgRemoveGiftcard(id))
|
||||
if len(g.Giftcards) != 0 {
|
||||
t.Fatalf("giftcard not removed")
|
||||
}
|
||||
if g.TotalPrice.IncVat != 0 {
|
||||
t.Fatalf("total price not updated after removal, got %d", g.TotalPrice.IncVat)
|
||||
}
|
||||
|
||||
applyErrorContains(t, reg, g, msgRemoveGiftcard(id), "not found")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user