more changes

This commit is contained in:
matst80
2025-10-10 09:34:40 +00:00
parent b97eb8f285
commit e7c67fbb9b
25 changed files with 1888 additions and 3689 deletions

211
cart_state_mapper.go Normal file
View File

@@ -0,0 +1,211 @@
package main
import (
messages "git.tornberg.me/go-cart-actor/proto"
)
// cart_state_mapper.go
//
// Utilities to translate between internal CartGrain state and the gRPC
// (typed) protobuf representation CartState. This replaces the previous
// JSON blob framing and enables type-safe replies over gRPC, as well as
// internal reuse for HTTP handlers without an extra marshal / unmarshal
// hop (you can marshal CartState directly for JSON responses if desired).
//
// Only the oneway mapping (CartGrain -> CartState) is strictly required
// for mutation / state replies. A reverse helper is included in case
// future features (e.g. snapshot import, replay, or migration) need it.
// ToCartState converts the inmemory CartGrain into a protobuf CartState.
func ToCartState(c *CartGrain) *messages.CartState {
if c == nil {
return nil
}
items := make([]*messages.CartItemState, 0, len(c.Items))
for _, it := range c.Items {
if it == nil {
continue
}
itemDiscountPerUnit := max(0, it.OrgPrice-it.Price)
itemTotalDiscount := itemDiscountPerUnit * int64(it.Quantity)
items = append(items, &messages.CartItemState{
Id: int64(it.Id),
SourceItemId: int64(it.ItemId),
Sku: it.Sku,
Name: it.Name,
UnitPrice: it.Price,
Quantity: int32(it.Quantity),
TotalPrice: it.TotalPrice,
TotalTax: it.TotalTax,
OrgPrice: it.OrgPrice,
TaxRate: int32(it.TaxRate),
TotalDiscount: itemTotalDiscount,
Brand: it.Brand,
Category: it.Category,
Category2: it.Category2,
Category3: it.Category3,
Category4: it.Category4,
Category5: it.Category5,
Image: it.Image,
ArticleType: it.ArticleType,
SellerId: it.SellerId,
SellerName: it.SellerName,
Disclaimer: it.Disclaimer,
Outlet: deref(it.Outlet),
StoreId: deref(it.StoreId),
Stock: int32(it.Stock),
})
}
deliveries := make([]*messages.DeliveryState, 0, len(c.Deliveries))
for _, d := range c.Deliveries {
if d == nil {
continue
}
itemIds := make([]int64, 0, len(d.Items))
for _, id := range d.Items {
itemIds = append(itemIds, int64(id))
}
var pp *messages.PickupPoint
if d.PickupPoint != nil {
// Copy to avoid accidental shared mutation (proto points are fine but explicit).
pp = &messages.PickupPoint{
Id: d.PickupPoint.Id,
Name: d.PickupPoint.Name,
Address: d.PickupPoint.Address,
City: d.PickupPoint.City,
Zip: d.PickupPoint.Zip,
Country: d.PickupPoint.Country,
}
}
deliveries = append(deliveries, &messages.DeliveryState{
Id: int64(d.Id),
Provider: d.Provider,
Price: d.Price,
ItemIds: itemIds,
PickupPoint: pp,
})
}
return &messages.CartState{
CartId: c.Id.String(),
Items: items,
TotalPrice: c.TotalPrice,
TotalTax: c.TotalTax,
TotalDiscount: c.TotalDiscount,
Deliveries: deliveries,
PaymentInProgress: c.PaymentInProgress,
OrderReference: c.OrderReference,
PaymentStatus: c.PaymentStatus,
}
}
// FromCartState merges a protobuf CartState into an existing CartGrain.
// This is optional and primarily useful for snapshot import or testing.
func FromCartState(cs *messages.CartState, g *CartGrain) *CartGrain {
if cs == nil {
return g
}
if g == nil {
g = &CartGrain{}
}
g.Id = ToCartId(cs.CartId)
g.TotalPrice = cs.TotalPrice
g.TotalTax = cs.TotalTax
g.TotalDiscount = cs.TotalDiscount
g.PaymentInProgress = cs.PaymentInProgress
g.OrderReference = cs.OrderReference
g.PaymentStatus = cs.PaymentStatus
// Items
g.Items = g.Items[:0]
for _, it := range cs.Items {
if it == nil {
continue
}
outlet := toPtr(it.Outlet)
storeId := toPtr(it.StoreId)
g.Items = append(g.Items, &CartItem{
Id: int(it.Id),
ItemId: int(it.SourceItemId),
Sku: it.Sku,
Name: it.Name,
Price: it.UnitPrice,
Quantity: int(it.Quantity),
TotalPrice: it.TotalPrice,
TotalTax: it.TotalTax,
OrgPrice: it.OrgPrice,
TaxRate: int(it.TaxRate),
Brand: it.Brand,
Category: it.Category,
Category2: it.Category2,
Category3: it.Category3,
Category4: it.Category4,
Category5: it.Category5,
Image: it.Image,
ArticleType: it.ArticleType,
SellerId: it.SellerId,
SellerName: it.SellerName,
Disclaimer: it.Disclaimer,
Outlet: outlet,
StoreId: storeId,
Stock: StockStatus(it.Stock),
// Tax, TaxRate already set via Price / Totals if needed
})
if it.Id > int64(g.lastItemId) {
g.lastItemId = int(it.Id)
}
}
// Deliveries
g.Deliveries = g.Deliveries[:0]
for _, d := range cs.Deliveries {
if d == nil {
continue
}
intIds := make([]int, 0, len(d.ItemIds))
for _, id := range d.ItemIds {
intIds = append(intIds, int(id))
}
var pp *messages.PickupPoint
if d.PickupPoint != nil {
pp = &messages.PickupPoint{
Id: d.PickupPoint.Id,
Name: d.PickupPoint.Name,
Address: d.PickupPoint.Address,
City: d.PickupPoint.City,
Zip: d.PickupPoint.Zip,
Country: d.PickupPoint.Country,
}
}
g.Deliveries = append(g.Deliveries, &CartDelivery{
Id: int(d.Id),
Provider: d.Provider,
Price: d.Price,
Items: intIds,
PickupPoint: pp,
})
if d.Id > int64(g.lastDeliveryId) {
g.lastDeliveryId = int(d.Id)
}
}
return g
}
// Helper to safely de-reference optional string pointers to value or "".
func deref(p *string) string {
if p == nil {
return ""
}
return *p
}
func toPtr(s string) *string {
if s == "" {
return nil
}
return &s
}