apskel-pos-backend/internal/processor/ingredient_processor.go
2025-08-03 23:55:51 +07:00

239 lines
7.3 KiB
Go

package processor
import (
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/mappers"
"apskel-pos-be/internal/models"
"context"
"time"
"github.com/google/uuid"
)
type IngredientProcessorImpl struct {
ingredientRepo IngredientRepository
unitRepo UnitRepository
}
func NewIngredientProcessor(ingredientRepo IngredientRepository, unitRepo UnitRepository) *IngredientProcessorImpl {
return &IngredientProcessorImpl{
ingredientRepo: ingredientRepo,
unitRepo: unitRepo,
}
}
func (p *IngredientProcessorImpl) CreateIngredient(ctx context.Context, req *models.CreateIngredientRequest) (*models.IngredientResponse, error) {
// Validate unit exists
_, err := p.unitRepo.GetByID(ctx, req.UnitID, req.OrganizationID)
if err != nil {
return nil, err
}
// Create ingredient entity
ingredient := &entities.Ingredient{
ID: uuid.New(),
OrganizationID: req.OrganizationID,
OutletID: req.OutletID,
Name: req.Name,
UnitID: req.UnitID,
Cost: req.Cost,
Stock: req.Stock,
IsSemiFinished: req.IsSemiFinished,
IsActive: req.IsActive,
Metadata: req.Metadata,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// Save to database
err = p.ingredientRepo.Create(ctx, ingredient)
if err != nil {
return nil, err
}
// Get with relations
ingredientWithUnit, err := p.ingredientRepo.GetByID(ctx, ingredient.ID, req.OrganizationID)
if err != nil {
return nil, err
}
// Map to response
ingredientModel := mappers.MapIngredientEntityToModel(ingredientWithUnit)
response := &models.IngredientResponse{
ID: ingredientModel.ID,
OrganizationID: ingredientModel.OrganizationID,
OutletID: ingredientModel.OutletID,
Name: ingredientModel.Name,
UnitID: ingredientModel.UnitID,
Cost: ingredientModel.Cost,
Stock: ingredientModel.Stock,
IsSemiFinished: ingredientModel.IsSemiFinished,
IsActive: ingredientModel.IsActive,
Metadata: ingredientModel.Metadata,
CreatedAt: ingredientModel.CreatedAt,
UpdatedAt: ingredientModel.UpdatedAt,
Unit: ingredientModel.Unit,
}
return response, nil
}
func (p *IngredientProcessorImpl) GetIngredientByID(ctx context.Context, id uuid.UUID) (*models.IngredientResponse, error) {
// For now, we'll need to get organizationID from context or request
// This is a limitation of the current interface design
organizationID := uuid.Nil // This should come from context
ingredient, err := p.ingredientRepo.GetByID(ctx, id, organizationID)
if err != nil {
return nil, err
}
ingredientModel := mappers.MapIngredientEntityToModel(ingredient)
response := &models.IngredientResponse{
ID: ingredientModel.ID,
OrganizationID: ingredientModel.OrganizationID,
OutletID: ingredientModel.OutletID,
Name: ingredientModel.Name,
UnitID: ingredientModel.UnitID,
Cost: ingredientModel.Cost,
Stock: ingredientModel.Stock,
IsSemiFinished: ingredientModel.IsSemiFinished,
IsActive: ingredientModel.IsActive,
Metadata: ingredientModel.Metadata,
CreatedAt: ingredientModel.CreatedAt,
UpdatedAt: ingredientModel.UpdatedAt,
Unit: ingredientModel.Unit,
}
return response, nil
}
func (p *IngredientProcessorImpl) ListIngredients(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, page, limit int, search string) (*models.PaginatedResponse[models.IngredientResponse], error) {
// Set default values
if page < 1 {
page = 1
}
if limit < 1 {
limit = 10
}
if limit > 100 {
limit = 100
}
ingredients, total, err := p.ingredientRepo.GetAll(ctx, organizationID, outletID, page, limit, search, nil)
if err != nil {
return nil, err
}
// Map to response models
ingredientModels := mappers.MapIngredientEntitiesToModels(ingredients)
ingredientResponses := make([]models.IngredientResponse, len(ingredientModels))
for i, ingredientModel := range ingredientModels {
ingredientResponses[i] = models.IngredientResponse{
ID: ingredientModel.ID,
OrganizationID: ingredientModel.OrganizationID,
OutletID: ingredientModel.OutletID,
Name: ingredientModel.Name,
UnitID: ingredientModel.UnitID,
Cost: ingredientModel.Cost,
Stock: ingredientModel.Stock,
IsSemiFinished: ingredientModel.IsSemiFinished,
IsActive: ingredientModel.IsActive,
Metadata: ingredientModel.Metadata,
CreatedAt: ingredientModel.CreatedAt,
UpdatedAt: ingredientModel.UpdatedAt,
Unit: ingredientModel.Unit,
}
}
// Create paginated response
paginatedResponse := &models.PaginatedResponse[models.IngredientResponse]{
Data: ingredientResponses,
Pagination: models.Pagination{
Page: page,
Limit: limit,
Total: int64(total),
TotalPages: (total + limit - 1) / limit,
},
}
return paginatedResponse, nil
}
func (p *IngredientProcessorImpl) UpdateIngredient(ctx context.Context, id uuid.UUID, req *models.UpdateIngredientRequest) (*models.IngredientResponse, error) {
// For now, we'll need to get organizationID from context or request
// This is a limitation of the current interface design
organizationID := uuid.Nil // This should come from context
// Get existing ingredient
existingIngredient, err := p.ingredientRepo.GetByID(ctx, id, organizationID)
if err != nil {
return nil, err
}
// Validate unit exists if changed
if req.UnitID != existingIngredient.UnitID {
_, err := p.unitRepo.GetByID(ctx, req.UnitID, organizationID)
if err != nil {
return nil, err
}
}
// Update fields
existingIngredient.OutletID = req.OutletID
existingIngredient.Name = req.Name
existingIngredient.UnitID = req.UnitID
existingIngredient.Cost = req.Cost
existingIngredient.Stock = req.Stock
existingIngredient.IsSemiFinished = req.IsSemiFinished
existingIngredient.IsActive = req.IsActive
existingIngredient.Metadata = req.Metadata
existingIngredient.UpdatedAt = time.Now()
// Save to database
err = p.ingredientRepo.Update(ctx, existingIngredient)
if err != nil {
return nil, err
}
// Get with relations
ingredientWithUnit, err := p.ingredientRepo.GetByID(ctx, id, organizationID)
if err != nil {
return nil, err
}
// Map to response
ingredientModel := mappers.MapIngredientEntityToModel(ingredientWithUnit)
response := &models.IngredientResponse{
ID: ingredientModel.ID,
OrganizationID: ingredientModel.OrganizationID,
OutletID: ingredientModel.OutletID,
Name: ingredientModel.Name,
UnitID: ingredientModel.UnitID,
Cost: ingredientModel.Cost,
Stock: ingredientModel.Stock,
IsSemiFinished: ingredientModel.IsSemiFinished,
IsActive: ingredientModel.IsActive,
Metadata: ingredientModel.Metadata,
CreatedAt: ingredientModel.CreatedAt,
UpdatedAt: ingredientModel.UpdatedAt,
Unit: ingredientModel.Unit,
}
return response, nil
}
func (p *IngredientProcessorImpl) DeleteIngredient(ctx context.Context, id uuid.UUID) error {
// For now, we'll need to get organizationID from context or request
// This is a limitation of the current interface design
organizationID := uuid.Nil // This should come from context
err := p.ingredientRepo.Delete(ctx, id, organizationID)
if err != nil {
return err
}
return nil
}