package checkout import ( "encoding/json" "sync" "time" "git.k6n.net/go-cart-actor/pkg/cart" ) // CheckoutId is the same as CartId for simplicity type CheckoutId = cart.CartId type PickupPoint struct { DeliveryId uint32 `json:"deliveryId,omitempty"` Id string `json:"id"` Name *string `json:"name,omitempty"` Address *string `json:"address,omitempty"` City *string `json:"city,omitempty"` Zip *string `json:"zip,omitempty"` Country *string `json:"country,omitempty"` } type CheckoutDelivery struct { Id uint32 `json:"id"` Provider string `json:"provider"` Price cart.Price `json:"price"` Items []uint32 `json:"items"` PickupPoint *PickupPoint `json:"pickupPoint,omitempty"` } type PaymentStatus string type CheckoutPaymentStatus PaymentStatus const ( PaymentStatusPending PaymentStatus = "pending" PaymentStatusFailed PaymentStatus = "failed" PaymentStatusSuccess PaymentStatus = "success" CheckoutPaymentStatusPending CheckoutPaymentStatus = "pending" CheckoutPaymentStatusFailed CheckoutPaymentStatus = "failed" CheckoutPaymentStatusSuccess CheckoutPaymentStatus = "success" CheckoutPaymentStatusCancelled CheckoutPaymentStatus = "partial" ) type Payment struct { PaymentId string `json:"paymentId"` Status PaymentStatus `json:"status"` Amount int64 `json:"amount"` Currency string `json:"currency"` Provider string `json:"provider,omitempty"` Method *string `json:"method,omitempty"` SessionData *json.RawMessage `json:"sessionData,omitempty"` Events []PaymentEvent `json:"events,omitempty"` ProcessorReference *string `json:"processorReference,omitempty"` StartedAt *time.Time `json:"startedAt,omitempty"` CompletedAt *time.Time `json:"completedAt,omitempty"` } type PaymentEvent struct { Name string `json:"name"` Success bool `json:"success"` Data json.RawMessage `json:"data"` } func (p *Payment) IsSettled() bool { if p == nil { return false } switch p.Status { case PaymentStatusSuccess: return true default: return false } } type ContactDetails struct { Email *string `json:"email,omitempty"` Phone *string `json:"phone,omitempty"` Name *string `json:"name,omitempty"` } type ConfirmationStatus struct { Code *string `json:"code,omitempty"` ViewCount int `json:"viewCount"` LastViewedAt time.Time `json:"lastViewedAt"` } type CheckoutGrain struct { mu sync.RWMutex lastDeliveryId uint32 lastGiftcardId uint32 lastAccess time.Time lastChange time.Time Version uint32 `json:"version"` Id CheckoutId `json:"id"` CartId cart.CartId `json:"cartId"` CartVersion uint64 `json:"cartVersion"` CartState *cart.CartGrain `json:"cartState"` // snapshot of items CartTotalPrice *cart.Price `json:"cartTotalPrice"` OrderId *string `json:"orderId"` Deliveries []*CheckoutDelivery `json:"deliveries,omitempty"` PaymentInProgress uint16 `json:"paymentInProgress"` AmountInCentsRemaining int64 `json:"amountRemaining"` AmountInCentsStarted int64 `json:"amountActive"` InventoryReserved bool `json:"inventoryReserved"` Confirmation *ConfirmationStatus `json:"confirmationViewed,omitempty"` Payments []*Payment `json:"payments,omitempty"` ContactDetails *ContactDetails `json:"contactDetails,omitempty"` } func NewCheckoutGrain(id uint64, cartId cart.CartId, cartVersion uint64, ts time.Time, cartState *cart.CartGrain) *CheckoutGrain { r := &CheckoutGrain{ lastDeliveryId: 0, lastGiftcardId: 0, lastAccess: ts, lastChange: ts, Id: CheckoutId(id), CartId: cartId, CartVersion: cartVersion, Deliveries: []*CheckoutDelivery{}, Payments: []*Payment{}, } if cartState != nil { r.CartState = cartState r.CartTotalPrice = cartState.TotalPrice } return r } func (c *CheckoutGrain) GetId() uint64 { return uint64(c.Id) } func (c *CheckoutGrain) GetLastChange() time.Time { return c.lastChange } func (c *CheckoutGrain) GetLastAccess() time.Time { return c.lastAccess } func (c *CheckoutGrain) GetCurrentState() (*CheckoutGrain, error) { c.lastAccess = time.Now() return c, nil } func (c *CheckoutGrain) GetState() ([]byte, error) { return json.Marshal(c) } func (c *CheckoutGrain) FindPayment(paymentId string) (*Payment, bool) { if paymentId == "" { return nil, false } for _, payment := range c.Payments { if payment != nil && payment.PaymentId == paymentId { return payment, true } } return nil, false } func (c *CheckoutGrain) SettledPayments() []*Payment { if len(c.Payments) == 0 { return nil } settled := make([]*Payment, 0, len(c.Payments)) for _, payment := range c.Payments { if payment != nil && payment.IsSettled() { settled = append(settled, payment) } } if len(settled) == 0 { return nil } return settled } func (c *CheckoutGrain) OpenPayments() []*Payment { if len(c.Payments) == 0 { return nil } pending := make([]*Payment, 0, len(c.Payments)) for _, payment := range c.Payments { if payment == nil { continue } if !payment.IsSettled() { pending = append(pending, payment) } } if len(pending) == 0 { return nil } return pending }