package repository import ( "context" "apskel-pos-be/internal/entities" "github.com/google/uuid" "gorm.io/gorm" ) type InventoryMovementRepository interface { Create(ctx context.Context, movement *entities.InventoryMovement) error GetByID(ctx context.Context, id uuid.UUID) (*entities.InventoryMovement, error) GetWithRelations(ctx context.Context, id uuid.UUID) (*entities.InventoryMovement, error) List(ctx context.Context, filters map[string]interface{}, limit, offset int) ([]*entities.InventoryMovement, int64, error) GetByProductAndOutlet(ctx context.Context, productID, outletID uuid.UUID, limit, offset int) ([]*entities.InventoryMovement, int64, error) GetByOrderID(ctx context.Context, orderID uuid.UUID) ([]*entities.InventoryMovement, error) GetByPaymentID(ctx context.Context, paymentID uuid.UUID) ([]*entities.InventoryMovement, error) Count(ctx context.Context, filters map[string]interface{}) (int64, error) CreateWithTransaction(tx *gorm.DB, movement *entities.InventoryMovement) error CreateInBatches(ctx context.Context, movements []*entities.InventoryMovement, batchSize int) error } type InventoryMovementRepositoryImpl struct { db *gorm.DB } func NewInventoryMovementRepositoryImpl(db *gorm.DB) *InventoryMovementRepositoryImpl { return &InventoryMovementRepositoryImpl{ db: db, } } func (r *InventoryMovementRepositoryImpl) Create(ctx context.Context, movement *entities.InventoryMovement) error { return r.db.WithContext(ctx).Create(movement).Error } func (r *InventoryMovementRepositoryImpl) CreateWithTransaction(tx *gorm.DB, movement *entities.InventoryMovement) error { return tx.Create(movement).Error } func (r *InventoryMovementRepositoryImpl) CreateInBatches(ctx context.Context, movements []*entities.InventoryMovement, batchSize int) error { if len(movements) == 0 { return nil } return r.db.WithContext(ctx).CreateInBatches(movements, batchSize).Error } func (r *InventoryMovementRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.InventoryMovement, error) { var movement entities.InventoryMovement err := r.db.WithContext(ctx).First(&movement, "id = ?", id).Error if err != nil { return nil, err } return &movement, nil } func (r *InventoryMovementRepositoryImpl) GetWithRelations(ctx context.Context, id uuid.UUID) (*entities.InventoryMovement, error) { var movement entities.InventoryMovement err := r.db.WithContext(ctx). Preload("Organization"). Preload("Outlet"). Preload("Product"). Preload("Product.Category"). Preload("Order"). Preload("Payment"). Preload("User"). First(&movement, "id = ?", id).Error if err != nil { return nil, err } return &movement, nil } func (r *InventoryMovementRepositoryImpl) List(ctx context.Context, filters map[string]interface{}, limit, offset int) ([]*entities.InventoryMovement, int64, error) { var movements []*entities.InventoryMovement var total int64 query := r.db.WithContext(ctx).Model(&entities.InventoryMovement{}). Preload("Product"). Preload("Product.Category"). Preload("Outlet"). Preload("Order"). Preload("Payment"). Preload("User") for key, value := range filters { switch key { case "search": searchValue := "%" + value.(string) + "%" query = query.Joins("JOIN products ON inventory_movements.product_id = products.id"). Where("products.name ILIKE ? OR inventory_movements.reason ILIKE ?", searchValue, searchValue) case "date_from": query = query.Where("created_at >= ?", value) case "date_to": query = query.Where("created_at <= ?", value) case "movement_type": query = query.Where("movement_type = ?", value) case "reference_type": query = query.Where("reference_type = ?", value) default: query = query.Where(key+" = ?", value) } } if err := query.Count(&total).Error; err != nil { return nil, 0, err } err := query.Order("created_at DESC").Limit(limit).Offset(offset).Find(&movements).Error return movements, total, err } func (r *InventoryMovementRepositoryImpl) GetByProductAndOutlet(ctx context.Context, productID, outletID uuid.UUID, limit, offset int) ([]*entities.InventoryMovement, int64, error) { var movements []*entities.InventoryMovement var total int64 query := r.db.WithContext(ctx).Model(&entities.InventoryMovement{}). Preload("Product"). Preload("Product.Category"). Preload("Order"). Preload("Payment"). Preload("User"). Where("product_id = ? AND outlet_id = ?", productID, outletID) if err := query.Count(&total).Error; err != nil { return nil, 0, err } err := query.Order("created_at DESC").Limit(limit).Offset(offset).Find(&movements).Error return movements, total, err } func (r *InventoryMovementRepositoryImpl) GetByOrderID(ctx context.Context, orderID uuid.UUID) ([]*entities.InventoryMovement, error) { var movements []*entities.InventoryMovement err := r.db.WithContext(ctx). Preload("Product"). Preload("Product.Category"). Where("order_id = ?", orderID). Order("created_at DESC"). Find(&movements).Error return movements, err } func (r *InventoryMovementRepositoryImpl) GetByPaymentID(ctx context.Context, paymentID uuid.UUID) ([]*entities.InventoryMovement, error) { var movements []*entities.InventoryMovement err := r.db.WithContext(ctx). Preload("Product"). Preload("Product.Category"). Where("payment_id = ?", paymentID). Order("created_at DESC"). Find(&movements).Error return movements, err } func (r *InventoryMovementRepositoryImpl) GetByReference(ctx context.Context, referenceType entities.InventoryMovementReferenceType, referenceID uuid.UUID) ([]*entities.InventoryMovement, error) { var movements []*entities.InventoryMovement err := r.db.WithContext(ctx). Preload("Product"). Preload("Product.Category"). Where("reference_type = ? AND reference_id = ?", referenceType, referenceID). Order("created_at DESC"). Find(&movements).Error return movements, err } func (r *InventoryMovementRepositoryImpl) Count(ctx context.Context, filters map[string]interface{}) (int64, error) { var count int64 query := r.db.WithContext(ctx).Model(&entities.InventoryMovement{}) for key, value := range filters { switch key { case "search": searchValue := "%" + value.(string) + "%" query = query.Joins("JOIN products ON inventory_movements.product_id = products.id"). Where("products.name ILIKE ? OR inventory_movements.reason ILIKE ?", searchValue, searchValue) case "date_from": query = query.Where("created_at >= ?", value) case "date_to": query = query.Where("created_at <= ?", value) case "movement_type": query = query.Where("movement_type = ?", value) case "reference_type": query = query.Where("reference_type = ?", value) default: query = query.Where(key+" = ?", value) } } err := query.Count(&count).Error return count, err }