199 lines
5.7 KiB
Go
199 lines
5.7 KiB
Go
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"`
|
|
PostalCode *string `json:"zip,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
|
|
}
|