package repository import ( "context" "time" "apskel-pos-be/internal/entities" "github.com/google/uuid" "gorm.io/gorm" ) type OrderItemRepository interface { Create(ctx context.Context, orderItem *entities.OrderItem) error GetByID(ctx context.Context, id uuid.UUID) (*entities.OrderItem, error) GetByOrderID(ctx context.Context, orderID uuid.UUID) ([]*entities.OrderItem, error) Update(ctx context.Context, orderItem *entities.OrderItem) error Delete(ctx context.Context, id uuid.UUID) error RefundOrderItem(ctx context.Context, id uuid.UUID, refundQuantity int, refundAmount float64, reason string, refundedBy uuid.UUID) error VoidOrderItem(ctx context.Context, id uuid.UUID, voidQuantity int, reason string, voidedBy uuid.UUID) error UpdateStatus(ctx context.Context, id uuid.UUID, status entities.OrderItemStatus) error } type OrderItemRepositoryImpl struct { db *gorm.DB } func NewOrderItemRepositoryImpl(db *gorm.DB) *OrderItemRepositoryImpl { return &OrderItemRepositoryImpl{ db: db, } } func (r *OrderItemRepositoryImpl) Create(ctx context.Context, orderItem *entities.OrderItem) error { return r.db.WithContext(ctx).Create(orderItem).Error } func (r *OrderItemRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.OrderItem, error) { var orderItem entities.OrderItem err := r.db.WithContext(ctx).First(&orderItem, "id = ?", id).Error if err != nil { return nil, err } return &orderItem, nil } func (r *OrderItemRepositoryImpl) GetByOrderID(ctx context.Context, orderID uuid.UUID) ([]*entities.OrderItem, error) { var orderItems []*entities.OrderItem err := r.db.WithContext(ctx). Preload("Product"). Preload("ProductVariant"). Where("order_id = ?", orderID). Find(&orderItems).Error return orderItems, err } func (r *OrderItemRepositoryImpl) Update(ctx context.Context, orderItem *entities.OrderItem) error { return r.db.WithContext(ctx).Save(orderItem).Error } func (r *OrderItemRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error { return r.db.WithContext(ctx).Delete(&entities.OrderItem{}, "id = ?", id).Error } func (r *OrderItemRepositoryImpl) RefundOrderItem(ctx context.Context, id uuid.UUID, refundQuantity int, refundAmount float64, reason string, refundedBy uuid.UUID) error { now := time.Now() // Get current order item var orderItem entities.OrderItem if err := r.db.WithContext(ctx).First(&orderItem, "id = ?", id).Error; err != nil { return err } // Calculate new refund quantities and amounts newRefundQuantity := orderItem.RefundQuantity + refundQuantity newRefundAmount := orderItem.RefundAmount + refundAmount // Determine if fully or partially refunded isFullyRefunded := newRefundQuantity >= orderItem.Quantity isPartiallyRefunded := newRefundQuantity > 0 && newRefundQuantity < orderItem.Quantity updates := map[string]interface{}{ "refund_quantity": newRefundQuantity, "refund_amount": newRefundAmount, "is_partially_refunded": isPartiallyRefunded, "is_fully_refunded": isFullyRefunded, "refund_reason": reason, "refunded_at": now, "refunded_by": refundedBy, } return r.db.WithContext(ctx).Model(&entities.OrderItem{}). Where("id = ?", id). Updates(updates).Error } func (r *OrderItemRepositoryImpl) UpdateStatus(ctx context.Context, id uuid.UUID, status entities.OrderItemStatus) error { return r.db.WithContext(ctx).Model(&entities.OrderItem{}). Where("id = ?", id). Update("status", status).Error } func (r *OrderItemRepositoryImpl) VoidOrderItem(ctx context.Context, id uuid.UUID, voidQuantity int, reason string, voidedBy uuid.UUID) error { now := time.Now() // Get current order item var orderItem entities.OrderItem if err := r.db.WithContext(ctx).First(&orderItem, "id = ?", id).Error; err != nil { return err } // Calculate new voided quantity newVoidedQuantity := orderItem.RefundQuantity + voidQuantity // Using refund_quantity field for voided quantity // Determine if fully or partially voided isFullyVoided := newVoidedQuantity >= orderItem.Quantity isPartiallyVoided := newVoidedQuantity > 0 && newVoidedQuantity < orderItem.Quantity // Calculate voided amount voidedAmount := float64(voidQuantity) * orderItem.UnitPrice updates := map[string]interface{}{ "refund_quantity": newVoidedQuantity, // Reusing refund_quantity field for voided quantity "refund_amount": orderItem.RefundAmount + voidedAmount, "is_partially_refunded": isPartiallyVoided, // Reusing refunded flags for voided status "is_fully_refunded": isFullyVoided, "refund_reason": reason, "refunded_at": now, "refunded_by": voidedBy, "status": entities.OrderItemStatusCancelled, // Mark as cancelled when voided } return r.db.WithContext(ctx).Model(&entities.OrderItem{}). Where("id = ?", id). Updates(updates).Error }