Add order items
This commit is contained in:
@@ -74,6 +74,7 @@ type PaymentOrderItemRepository interface {
|
||||
Create(ctx context.Context, paymentOrderItem *entities.PaymentOrderItem) error
|
||||
GetByID(ctx context.Context, id uuid.UUID) (*entities.PaymentOrderItem, error)
|
||||
GetByPaymentID(ctx context.Context, paymentID uuid.UUID) ([]*entities.PaymentOrderItem, error)
|
||||
GetPaidQuantitiesByOrderID(ctx context.Context, orderID uuid.UUID) (map[uuid.UUID]int, error)
|
||||
Update(ctx context.Context, paymentOrderItem *entities.PaymentOrderItem) error
|
||||
Delete(ctx context.Context, id uuid.UUID) error
|
||||
}
|
||||
@@ -110,6 +111,7 @@ type OrderProcessorImpl struct {
|
||||
productVariantRepo repository.ProductVariantRepository
|
||||
outletRepo OutletRepository
|
||||
customerRepo CustomerRepository
|
||||
splitBillProcessor SplitBillProcessor
|
||||
}
|
||||
|
||||
func NewOrderProcessorImpl(
|
||||
@@ -137,6 +139,7 @@ func NewOrderProcessorImpl(
|
||||
productVariantRepo: productVariantRepo,
|
||||
outletRepo: outletRepo,
|
||||
customerRepo: customerRepo,
|
||||
splitBillProcessor: NewSplitBillProcessorImpl(orderRepo, orderItemRepo, paymentRepo, paymentOrderItemRepo, outletRepo),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -800,10 +803,6 @@ func (p *OrderProcessorImpl) CreatePayment(ctx context.Context, req *models.Crea
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func stringPtr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
func (p *OrderProcessorImpl) RefundPayment(ctx context.Context, paymentID uuid.UUID, refundAmount float64, reason string, refundedBy uuid.UUID) error {
|
||||
payment, err := p.paymentRepo.GetByID(ctx, paymentID)
|
||||
if err != nil {
|
||||
@@ -910,200 +909,14 @@ func (p *OrderProcessorImpl) SplitBill(ctx context.Context, req *models.SplitBil
|
||||
|
||||
var response *models.SplitBillResponse
|
||||
if req.IsAmount() {
|
||||
response, err = p.splitBillByAmount(ctx, req, order, payment, customer)
|
||||
response, err = p.splitBillProcessor.SplitByAmount(ctx, req, order, payment, customer)
|
||||
} else if req.IsItem() {
|
||||
response, err = p.splitBillByItem(ctx, req, order, payment, customer)
|
||||
response, err = p.splitBillProcessor.SplitByItem(ctx, req, order, payment, customer)
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid split type: must be AMOUNT or ITEM")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (p *OrderProcessorImpl) splitBillByAmount(ctx context.Context, req *models.SplitBillRequest, order *entities.Order, payment *entities.PaymentMethod, customer *entities.Customer) (*models.SplitBillResponse, error) {
|
||||
totalPaid, err := p.paymentRepo.GetTotalPaidByOrderID(ctx, req.OrderID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get total paid amount: %w", err)
|
||||
}
|
||||
|
||||
remainingBalance := order.TotalAmount - totalPaid
|
||||
if req.Amount > remainingBalance {
|
||||
return nil, fmt.Errorf("split amount %.2f cannot exceed remaining balance %.2f", req.Amount, remainingBalance)
|
||||
}
|
||||
|
||||
existingPayments, err := p.paymentRepo.GetByOrderID(ctx, req.OrderID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get existing payments: %w", err)
|
||||
}
|
||||
|
||||
splitNumber := len(existingPayments) + 1
|
||||
splitTotal := splitNumber + 1
|
||||
|
||||
splitType := entities.SplitTypeAmount
|
||||
splitPayment := &entities.Payment{
|
||||
OrderID: req.OrderID,
|
||||
PaymentMethodID: payment.ID,
|
||||
Amount: req.Amount,
|
||||
Status: entities.PaymentTransactionStatusCompleted,
|
||||
SplitNumber: splitNumber,
|
||||
SplitTotal: splitTotal,
|
||||
SplitType: &splitType,
|
||||
SplitDescription: stringPtr(fmt.Sprint("Split payment for customer")),
|
||||
Metadata: entities.Metadata{
|
||||
"split_type": "AMOUNT",
|
||||
},
|
||||
}
|
||||
|
||||
if err := p.paymentRepo.Create(ctx, splitPayment); err != nil {
|
||||
return nil, fmt.Errorf("failed to create split payment: %w", err)
|
||||
}
|
||||
|
||||
if order.Metadata == nil {
|
||||
order.Metadata = make(entities.Metadata)
|
||||
}
|
||||
|
||||
order.Metadata["last_split_payment_id"] = splitPayment.ID.String()
|
||||
order.Metadata["last_split_customer_id"] = req.CustomerID.String()
|
||||
order.Metadata["last_split_amount"] = req.Amount
|
||||
order.Metadata["last_split_type"] = "AMOUNT"
|
||||
|
||||
newTotalPaid := totalPaid + req.Amount
|
||||
order.RemainingAmount = order.TotalAmount - newTotalPaid
|
||||
|
||||
if newTotalPaid >= order.TotalAmount {
|
||||
order.PaymentStatus = entities.PaymentStatusCompleted
|
||||
order.Status = entities.OrderStatusCompleted
|
||||
order.RemainingAmount = 0
|
||||
} else {
|
||||
order.PaymentStatus = entities.PaymentStatusPartial
|
||||
}
|
||||
|
||||
if err := p.orderRepo.Update(ctx, order); err != nil {
|
||||
return nil, fmt.Errorf("failed to update order: %w", err)
|
||||
}
|
||||
|
||||
return &models.SplitBillResponse{
|
||||
PaymentID: splitPayment.ID,
|
||||
OrderID: req.OrderID,
|
||||
CustomerID: req.CustomerID,
|
||||
Type: "AMOUNT",
|
||||
Amount: req.Amount,
|
||||
Message: fmt.Sprintf("Successfully split payment by amount %.2f for customer %s. Remaining balance: %.2f", req.Amount, customer.Name, order.RemainingAmount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *OrderProcessorImpl) splitBillByItem(ctx context.Context, req *models.SplitBillRequest, order *entities.Order, payment *entities.PaymentMethod, customer *entities.Customer) (*models.SplitBillResponse, error) {
|
||||
totalSplitAmount := float64(0)
|
||||
for _, item := range req.Items {
|
||||
totalSplitAmount += item.Amount
|
||||
}
|
||||
|
||||
totalPaid, err := p.paymentRepo.GetTotalPaidByOrderID(ctx, req.OrderID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get total paid amount: %w", err)
|
||||
}
|
||||
|
||||
remainingBalance := order.TotalAmount - totalPaid
|
||||
|
||||
if totalSplitAmount > remainingBalance {
|
||||
return nil, fmt.Errorf("split amount %.2f cannot exceed remaining balance %.2f", totalSplitAmount, remainingBalance)
|
||||
}
|
||||
|
||||
for _, item := range req.Items {
|
||||
orderItem, err := p.orderItemRepo.GetByID(ctx, item.OrderItemID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("order item not found: %w", err)
|
||||
}
|
||||
if orderItem.OrderID != req.OrderID {
|
||||
return nil, fmt.Errorf("order item does not belong to this order")
|
||||
}
|
||||
}
|
||||
|
||||
existingPayments, err := p.paymentRepo.GetByOrderID(ctx, req.OrderID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get existing payments: %w", err)
|
||||
}
|
||||
|
||||
splitNumber := len(existingPayments) + 1
|
||||
splitTotal := splitNumber + 1
|
||||
|
||||
splitType := entities.SplitTypeItem
|
||||
splitPayment := &entities.Payment{
|
||||
OrderID: req.OrderID,
|
||||
PaymentMethodID: payment.ID,
|
||||
Amount: totalSplitAmount,
|
||||
Status: entities.PaymentTransactionStatusCompleted,
|
||||
SplitNumber: splitNumber,
|
||||
SplitTotal: splitTotal,
|
||||
SplitType: &splitType,
|
||||
SplitDescription: stringPtr(fmt.Sprintf("Split payment by items for customer: %s", customer.Name)),
|
||||
Metadata: entities.Metadata{
|
||||
"split_type": "ITEM",
|
||||
"customer_id": req.CustomerID.String(),
|
||||
"customer_name": customer.Name,
|
||||
},
|
||||
}
|
||||
|
||||
if err := p.paymentRepo.Create(ctx, splitPayment); err != nil {
|
||||
return nil, fmt.Errorf("failed to create split payment: %w", err)
|
||||
}
|
||||
|
||||
for _, item := range req.Items {
|
||||
paymentOrderItem := &entities.PaymentOrderItem{
|
||||
PaymentID: splitPayment.ID,
|
||||
OrderItemID: item.OrderItemID,
|
||||
Amount: item.Amount,
|
||||
}
|
||||
|
||||
if err := p.paymentOrderItemRepo.Create(ctx, paymentOrderItem); err != nil {
|
||||
return nil, fmt.Errorf("failed to create payment order item: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if order.Metadata == nil {
|
||||
order.Metadata = make(entities.Metadata)
|
||||
}
|
||||
|
||||
order.Metadata["last_split_payment_id"] = splitPayment.ID.String()
|
||||
order.Metadata["last_split_customer_id"] = req.CustomerID.String()
|
||||
order.Metadata["last_split_customer_name"] = customer.Name
|
||||
order.Metadata["last_split_amount"] = totalSplitAmount
|
||||
order.Metadata["last_split_type"] = "ITEM"
|
||||
|
||||
newTotalPaid := totalPaid + totalSplitAmount
|
||||
order.RemainingAmount = order.TotalAmount - newTotalPaid
|
||||
|
||||
if newTotalPaid >= order.TotalAmount {
|
||||
order.PaymentStatus = entities.PaymentStatusCompleted
|
||||
order.Status = entities.OrderStatusCompleted
|
||||
order.RemainingAmount = 0
|
||||
} else {
|
||||
order.PaymentStatus = entities.PaymentStatusPartial
|
||||
}
|
||||
|
||||
if err := p.orderRepo.Update(ctx, order); err != nil {
|
||||
return nil, fmt.Errorf("failed to update order: %w", err)
|
||||
}
|
||||
|
||||
responseItems := make([]models.SplitBillItemResponse, len(req.Items))
|
||||
for i, item := range req.Items {
|
||||
responseItems[i] = models.SplitBillItemResponse{
|
||||
OrderItemID: item.OrderItemID,
|
||||
Amount: item.Amount,
|
||||
}
|
||||
}
|
||||
|
||||
return &models.SplitBillResponse{
|
||||
PaymentID: splitPayment.ID,
|
||||
OrderID: req.OrderID,
|
||||
CustomerID: req.CustomerID,
|
||||
Type: "ITEM",
|
||||
Amount: totalSplitAmount,
|
||||
Items: responseItems,
|
||||
Message: fmt.Sprintf("Successfully split payment by items (%.2f) for customer %s. Remaining balance: %.2f", totalSplitAmount, customer.Name, order.RemainingAmount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user