213 lines
5.6 KiB
Go
213 lines
5.6 KiB
Go
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 one‑way 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 in‑memory 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),
|
||
ItemId: int64(it.ItemId),
|
||
Sku: it.Sku,
|
||
Name: it.Name,
|
||
Price: it.Price,
|
||
Qty: 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,
|
||
Type: 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,
|
||
Items: itemIds,
|
||
PickupPoint: pp,
|
||
})
|
||
}
|
||
|
||
return &messages.CartState{
|
||
Id: 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.Id)
|
||
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.ItemId),
|
||
Sku: it.Sku,
|
||
Name: it.Name,
|
||
Price: it.Price,
|
||
Quantity: int(it.Qty),
|
||
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.Type,
|
||
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.Items))
|
||
for _, id := range d.Items {
|
||
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
|
||
}
|