apskel-pos-backend/internal/repository/ingredient_unit_converter_repository.go
2025-09-12 01:12:11 +07:00

177 lines
7.0 KiB
Go

package repository
import (
"apskel-pos-be/internal/entities"
"context"
"fmt"
"github.com/google/uuid"
"gorm.io/gorm"
)
type IngredientUnitConverterRepository interface {
Create(ctx context.Context, converter *entities.IngredientUnitConverter) error
GetByID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error)
GetByIDAndOrganizationID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error)
Update(ctx context.Context, converter *entities.IngredientUnitConverter) error
Delete(ctx context.Context, id, organizationID uuid.UUID) error
List(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, page, limit int) ([]*entities.IngredientUnitConverter, int, error)
GetByIngredientAndUnits(ctx context.Context, ingredientID, fromUnitID, toUnitID, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error)
GetConvertersForIngredient(ctx context.Context, ingredientID, organizationID uuid.UUID) ([]*entities.IngredientUnitConverter, error)
GetActiveConverters(ctx context.Context, organizationID uuid.UUID) ([]*entities.IngredientUnitConverter, error)
ConvertQuantity(ctx context.Context, ingredientID, fromUnitID, toUnitID, organizationID uuid.UUID, quantity float64) (float64, error)
}
type IngredientUnitConverterRepositoryImpl struct {
db *gorm.DB
}
func NewIngredientUnitConverterRepositoryImpl(db *gorm.DB) IngredientUnitConverterRepository {
return &IngredientUnitConverterRepositoryImpl{
db: db,
}
}
func (r *IngredientUnitConverterRepositoryImpl) Create(ctx context.Context, converter *entities.IngredientUnitConverter) error {
return r.db.WithContext(ctx).Create(converter).Error
}
func (r *IngredientUnitConverterRepositoryImpl) GetByID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error) {
var converter entities.IngredientUnitConverter
err := r.db.WithContext(ctx).
Where("id = ? AND organization_id = ?", id, organizationID).
Preload("Ingredient").
Preload("FromUnit").
Preload("ToUnit").
Preload("CreatedByUser").
Preload("UpdatedByUser").
First(&converter).Error
if err != nil {
return nil, err
}
return &converter, nil
}
func (r *IngredientUnitConverterRepositoryImpl) GetByIDAndOrganizationID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error) {
return r.GetByID(ctx, id, organizationID)
}
func (r *IngredientUnitConverterRepositoryImpl) Update(ctx context.Context, converter *entities.IngredientUnitConverter) error {
return r.db.WithContext(ctx).Save(converter).Error
}
func (r *IngredientUnitConverterRepositoryImpl) Delete(ctx context.Context, id, organizationID uuid.UUID) error {
return r.db.WithContext(ctx).
Where("id = ? AND organization_id = ?", id, organizationID).
Delete(&entities.IngredientUnitConverter{}).Error
}
func (r *IngredientUnitConverterRepositoryImpl) List(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, page, limit int) ([]*entities.IngredientUnitConverter, int, error) {
var converters []*entities.IngredientUnitConverter
var total int64
query := r.db.WithContext(ctx).
Model(&entities.IngredientUnitConverter{}).
Where("organization_id = ?", organizationID)
// Apply filters
if ingredientID, ok := filters["ingredient_id"].(uuid.UUID); ok {
query = query.Where("ingredient_id = ?", ingredientID)
}
if fromUnitID, ok := filters["from_unit_id"].(uuid.UUID); ok {
query = query.Where("from_unit_id = ?", fromUnitID)
}
if toUnitID, ok := filters["to_unit_id"].(uuid.UUID); ok {
query = query.Where("to_unit_id = ?", toUnitID)
}
if isActive, ok := filters["is_active"].(bool); ok {
query = query.Where("is_active = ?", isActive)
}
if search, ok := filters["search"].(string); ok && search != "" {
query = query.Joins("LEFT JOIN ingredients ON ingredient_unit_converters.ingredient_id = ingredients.id").
Joins("LEFT JOIN units AS from_units ON ingredient_unit_converters.from_unit_id = from_units.id").
Joins("LEFT JOIN units AS to_units ON ingredient_unit_converters.to_unit_id = to_units.id").
Where("ingredients.name ILIKE ? OR from_units.name ILIKE ? OR to_units.name ILIKE ?",
"%"+search+"%", "%"+search+"%", "%"+search+"%")
}
// Get total count
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// Apply pagination and get results
offset := (page - 1) * limit
err := query.
Preload("Ingredient").
Preload("FromUnit").
Preload("ToUnit").
Preload("CreatedByUser").
Preload("UpdatedByUser").
Order("created_at DESC").
Offset(offset).
Limit(limit).
Find(&converters).Error
return converters, int(total), err
}
func (r *IngredientUnitConverterRepositoryImpl) GetByIngredientAndUnits(ctx context.Context, ingredientID, fromUnitID, toUnitID, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error) {
var converter entities.IngredientUnitConverter
err := r.db.WithContext(ctx).
Where("ingredient_id = ? AND from_unit_id = ? AND to_unit_id = ? AND organization_id = ? AND is_active = ?",
ingredientID, fromUnitID, toUnitID, organizationID, true).
Preload("Ingredient").
Preload("FromUnit").
Preload("ToUnit").
First(&converter).Error
if err != nil {
return nil, err
}
return &converter, nil
}
func (r *IngredientUnitConverterRepositoryImpl) GetConvertersForIngredient(ctx context.Context, ingredientID, organizationID uuid.UUID) ([]*entities.IngredientUnitConverter, error) {
var converters []*entities.IngredientUnitConverter
err := r.db.WithContext(ctx).
Where("ingredient_id = ? AND organization_id = ? AND is_active = ?", ingredientID, organizationID, true).
Preload("FromUnit").
Preload("ToUnit").
Find(&converters).Error
return converters, err
}
func (r *IngredientUnitConverterRepositoryImpl) GetActiveConverters(ctx context.Context, organizationID uuid.UUID) ([]*entities.IngredientUnitConverter, error) {
var converters []*entities.IngredientUnitConverter
err := r.db.WithContext(ctx).
Where("organization_id = ? AND is_active = ?", organizationID, true).
Preload("Ingredient").
Preload("FromUnit").
Preload("ToUnit").
Find(&converters).Error
return converters, err
}
func (r *IngredientUnitConverterRepositoryImpl) ConvertQuantity(ctx context.Context, ingredientID, fromUnitID, toUnitID, organizationID uuid.UUID, quantity float64) (float64, error) {
// If from and to units are the same, return the same quantity
if fromUnitID == toUnitID {
return quantity, nil
}
// Try to find direct converter
converter, err := r.GetByIngredientAndUnits(ctx, ingredientID, fromUnitID, toUnitID, organizationID)
if err == nil {
return quantity * converter.ConversionFactor, nil
}
// If direct converter not found, try to find reverse converter
reverseConverter, err := r.GetByIngredientAndUnits(ctx, ingredientID, toUnitID, fromUnitID, organizationID)
if err == nil {
return quantity / reverseConverter.ConversionFactor, nil
}
// If no converter found, return error
return 0, fmt.Errorf("no conversion found between units %s and %s for ingredient %s", fromUnitID, toUnitID, ingredientID)
}