apskel-pos-backend/internal/repository/order_item_repository.go
aditya.siregar 4f5950543e init
2025-07-18 20:10:29 +07:00

137 lines
4.8 KiB
Go

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
}