This commit is contained in:
Aditya Siregar
2025-07-30 23:18:20 +07:00
parent 4a921df55d
commit a759e0f57c
57 changed files with 3633 additions and 190 deletions
+33 -100
View File
@@ -8,6 +8,7 @@ import (
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/mappers"
"apskel-pos-be/internal/models"
"apskel-pos-be/internal/repository"
"github.com/google/uuid"
)
@@ -62,6 +63,8 @@ type PaymentRepository interface {
RefundPayment(ctx context.Context, id uuid.UUID, refundAmount float64, reason string, refundedBy uuid.UUID) error
UpdateStatus(ctx context.Context, id uuid.UUID, status entities.PaymentTransactionStatus) error
GetTotalPaidByOrderID(ctx context.Context, orderID uuid.UUID) (float64, error)
CreatePaymentWithInventoryMovement(ctx context.Context, req *models.CreatePaymentRequest, order *entities.Order, totalPaid float64) (*entities.Payment, error)
RefundPaymentWithInventoryMovement(ctx context.Context, paymentID uuid.UUID, refundAmount float64, reason string, refundedBy uuid.UUID, order *entities.Payment) error
}
type PaymentMethodRepository interface {
@@ -89,15 +92,16 @@ func (r *SimplePaymentMethodRepository) GetByID(ctx context.Context, id uuid.UUI
}
type OrderProcessorImpl struct {
orderRepo OrderRepository
orderItemRepo OrderItemRepository
paymentRepo PaymentRepository
productRepo ProductRepository
paymentMethodRepo PaymentMethodRepository
inventoryRepo InventoryRepository
productVariantRepo ProductVariantRepository
outletRepo OutletRepository
customerRepo CustomerRepository
orderRepo OrderRepository
orderItemRepo OrderItemRepository
paymentRepo PaymentRepository
productRepo ProductRepository
paymentMethodRepo PaymentMethodRepository
inventoryRepo repository.InventoryRepository
inventoryMovementRepo repository.InventoryMovementRepository
productVariantRepo ProductVariantRepository
outletRepo OutletRepository
customerRepo CustomerRepository
}
func NewOrderProcessorImpl(
@@ -106,21 +110,23 @@ func NewOrderProcessorImpl(
paymentRepo PaymentRepository,
productRepo ProductRepository,
paymentMethodRepo PaymentMethodRepository,
inventoryRepo InventoryRepository,
inventoryRepo repository.InventoryRepository,
inventoryMovementRepo repository.InventoryMovementRepository,
productVariantRepo ProductVariantRepository,
outletRepo OutletRepository,
customerRepo CustomerRepository,
) *OrderProcessorImpl {
return &OrderProcessorImpl{
orderRepo: orderRepo,
orderItemRepo: orderItemRepo,
paymentRepo: paymentRepo,
productRepo: productRepo,
paymentMethodRepo: paymentMethodRepo,
inventoryRepo: inventoryRepo,
productVariantRepo: productVariantRepo,
outletRepo: outletRepo,
customerRepo: customerRepo,
orderRepo: orderRepo,
orderItemRepo: orderItemRepo,
paymentRepo: paymentRepo,
productRepo: productRepo,
paymentMethodRepo: paymentMethodRepo,
inventoryRepo: inventoryRepo,
inventoryMovementRepo: inventoryMovementRepo,
productVariantRepo: productVariantRepo,
outletRepo: outletRepo,
customerRepo: customerRepo,
}
}
@@ -619,7 +625,6 @@ func (p *OrderProcessorImpl) RefundOrder(ctx context.Context, id uuid.UUID, req
return fmt.Errorf("order not found: %w", err)
}
// Check if order can be refunded
if order.IsRefund {
return fmt.Errorf("order is already refunded")
}
@@ -738,69 +743,11 @@ func (p *OrderProcessorImpl) CreatePayment(ctx context.Context, req *models.Crea
return nil, fmt.Errorf("payment amount exceeds remaining balance")
}
payment := &entities.Payment{
OrderID: req.OrderID,
PaymentMethodID: req.PaymentMethodID,
Amount: req.Amount,
Status: entities.PaymentTransactionStatusCompleted,
TransactionID: req.TransactionID,
SplitNumber: req.SplitNumber,
SplitTotal: req.SplitTotal,
SplitDescription: req.SplitDescription,
Metadata: entities.Metadata(req.Metadata),
payment, err := p.paymentRepo.CreatePaymentWithInventoryMovement(ctx, req, order, totalPaid)
if err != nil {
return nil, err
}
if err := p.paymentRepo.Create(ctx, payment); err != nil {
return nil, fmt.Errorf("failed to create payment: %w", err)
}
if len(req.PaymentOrderItems) > 0 {
for _, itemPayment := range req.PaymentOrderItems {
paymentOrderItem := &entities.PaymentOrderItem{
PaymentID: payment.ID,
OrderItemID: itemPayment.OrderItemID,
Amount: itemPayment.Amount,
}
fmt.Println(paymentOrderItem)
// TODO: Create payment order item in database
// This would require a PaymentOrderItemRepository
}
}
// Update order payment status if fully paid
newTotalPaid := totalPaid + req.Amount
orderJustCompleted := false
if newTotalPaid >= order.TotalAmount {
if order.PaymentStatus != entities.PaymentStatusCompleted {
orderJustCompleted = true
}
if err := p.orderRepo.UpdatePaymentStatus(ctx, req.OrderID, entities.PaymentStatusCompleted); err != nil {
return nil, fmt.Errorf("failed to update order payment status: %w", err)
}
// Set order status to completed when fully paid
if err := p.orderRepo.UpdateStatus(ctx, req.OrderID, entities.OrderStatusCompleted); err != nil {
return nil, fmt.Errorf("failed to update order status: %w", err)
}
} else {
if err := p.orderRepo.UpdatePaymentStatus(ctx, req.OrderID, entities.PaymentStatusPartiallyRefunded); err != nil {
return nil, fmt.Errorf("failed to update order payment status: %w", err)
}
}
if orderJustCompleted {
orderItems, err := p.orderItemRepo.GetByOrderID(ctx, req.OrderID)
if err != nil {
return nil, fmt.Errorf("failed to get order items for inventory adjustment: %w", err)
}
for _, item := range orderItems {
if _, err := p.inventoryRepo.AdjustQuantity(ctx, item.ProductID, order.OutletID, -item.Quantity); err != nil {
return nil, fmt.Errorf("failed to adjust inventory for product %s: %w", item.ProductID, err)
}
}
}
// Get payment with relations for response
paymentWithRelations, err := p.paymentRepo.GetByID(ctx, payment.ID)
if err != nil {
return nil, fmt.Errorf("failed to retrieve created payment: %w", err)
@@ -810,14 +757,16 @@ 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 {
// Get payment
payment, err := p.paymentRepo.GetByID(ctx, paymentID)
if err != nil {
return fmt.Errorf("payment not found: %w", err)
}
// Check if payment can be refunded
if payment.Status != entities.PaymentTransactionStatusCompleted {
return fmt.Errorf("payment is not completed, cannot refund")
}
@@ -826,23 +775,7 @@ func (p *OrderProcessorImpl) RefundPayment(ctx context.Context, paymentID uuid.U
return fmt.Errorf("refund amount cannot exceed payment amount")
}
// Process refund
if err := p.paymentRepo.RefundPayment(ctx, paymentID, refundAmount, reason, refundedBy); err != nil {
return fmt.Errorf("failed to refund payment: %w", err)
}
// Update order refund amount
order, err := p.orderRepo.GetByID(ctx, payment.OrderID)
if err != nil {
return fmt.Errorf("failed to get order: %w", err)
}
order.RefundAmount += refundAmount
if err := p.orderRepo.Update(ctx, order); err != nil {
return fmt.Errorf("failed to update order refund amount: %w", err)
}
return nil
return p.paymentRepo.RefundPaymentWithInventoryMovement(ctx, paymentID, refundAmount, reason, refundedBy, payment)
}
func (p *OrderProcessorImpl) SetOrderCustomer(ctx context.Context, orderID uuid.UUID, req *models.SetOrderCustomerRequest, organizationID uuid.UUID) (*models.SetOrderCustomerResponse, error) {