180 lines
5.1 KiB
Go

package processor
import (
"context"
"fmt"
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/models"
"apskel-pos-be/internal/repository"
"github.com/google/uuid"
)
type HPPProcessor interface {
GetStandardHPP(ctx context.Context, req *models.StandardHPPRequest) (*models.StandardHPPResponse, error)
GetRealHPP(ctx context.Context, req *models.RealHPPRequest) (*models.RealHPPResponse, error)
}
type HPPProcessorImpl struct {
hppRepo repository.HPPRepository
}
func NewHPPProcessorImpl(hppRepo repository.HPPRepository) *HPPProcessorImpl {
return &HPPProcessorImpl{
hppRepo: hppRepo,
}
}
func (p *HPPProcessorImpl) GetStandardHPP(ctx context.Context, req *models.StandardHPPRequest) (*models.StandardHPPResponse, error) {
products, err := p.hppRepo.GetStandardHPP(ctx, req.OrganizationID, req.ProductID, req.CategoryID)
if err != nil {
return nil, fmt.Errorf("failed to get standard HPP: %w", err)
}
productIDs := make([]uuid.UUID, 0)
for _, pp := range products {
if pp.HasRecipe {
productIDs = append(productIDs, pp.ProductID)
}
}
ingredients, err := p.hppRepo.GetStandardHPPIngredients(ctx, req.OrganizationID, productIDs)
if err != nil {
return nil, fmt.Errorf("failed to get standard HPP ingredients: %w", err)
}
productData := make([]models.StandardHPPProduct, 0, len(products))
var totalHPP float64
var hppCount int64
for _, pp := range products {
productData = append(productData, models.StandardHPPProduct{
ProductID: pp.ProductID,
ProductName: pp.ProductName,
ProductSku: pp.ProductSku,
CategoryID: pp.CategoryID,
CategoryName: pp.CategoryName,
SellingPrice: pp.SellingPrice,
ProductCost: pp.ProductCost,
StandardCost: pp.StandardCost,
StandardHPPPercentage: pp.StandardHPPPercentage,
HasRecipe: pp.HasRecipe,
})
if pp.HasRecipe {
totalHPP += pp.StandardHPPPercentage
hppCount++
}
}
ingredientData := make([]models.StandardHPPIngredient, 0, len(ingredients))
for _, ing := range ingredients {
ingredientData = append(ingredientData, models.StandardHPPIngredient{
ProductID: ing.ProductID,
IngredientID: ing.IngredientID,
IngredientName: ing.IngredientName,
Quantity: ing.Quantity,
UnitName: ing.UnitName,
CostPerUnit: ing.CostPerUnit,
WastePercentage: ing.WastePercentage,
TotalCost: ing.TotalCost,
})
}
var avgHPP float64
if hppCount > 0 {
avgHPP = totalHPP / float64(hppCount)
}
return &models.StandardHPPResponse{
OrganizationID: req.OrganizationID,
Summary: models.HPPSummary{
AverageStandardHPP: avgHPP,
AverageRealHPP: 0,
HPPVariance: 0,
TotalProducts: int64(len(products)),
},
Products: productData,
Ingredients: ingredientData,
}, nil
}
func (p *HPPProcessorImpl) GetRealHPP(ctx context.Context, req *models.RealHPPRequest) (*models.RealHPPResponse, error) {
if req.DateFrom.After(req.DateTo) {
return nil, fmt.Errorf("date_from cannot be after date_to")
}
if req.GroupBy == "" {
req.GroupBy = "day"
}
products, err := p.hppRepo.GetRealHPP(ctx, req.OrganizationID, req.OutletID, req.ProductID, req.CategoryID, req.DateFrom, req.DateTo)
if err != nil {
return nil, fmt.Errorf("failed to get real HPP: %w", err)
}
var timeSeries []*entities.RealHPPTimeSeries
if req.GroupBy != "" {
timeSeries, err = p.hppRepo.GetRealHPPTimeSeries(ctx, req.OrganizationID, req.OutletID, req.ProductID, req.CategoryID, req.DateFrom, req.DateTo, req.GroupBy)
if err != nil {
return nil, fmt.Errorf("failed to get real HPP time series: %w", err)
}
}
productData := make([]models.RealHPPProduct, 0, len(products))
var totalHPP float64
var totalRevenue float64
var hppCount int64
for _, pp := range products {
productData = append(productData, models.RealHPPProduct{
ProductID: pp.ProductID,
ProductName: pp.ProductName,
ProductSku: pp.ProductSku,
CategoryID: pp.CategoryID,
CategoryName: pp.CategoryName,
SellingPrice: pp.SellingPrice,
RealTotalCost: pp.RealTotalCost,
RealTotalRevenue: pp.RealTotalRevenue,
RealHPPPercentage: pp.RealHPPPercentage,
TotalQuantitySold: pp.TotalQuantitySold,
TotalOrders: pp.TotalOrders,
})
if pp.RealTotalRevenue > 0 {
totalHPP += pp.RealHPPPercentage
totalRevenue += pp.RealTotalRevenue
hppCount++
}
}
var avgHPP float64
if hppCount > 0 {
avgHPP = totalHPP / float64(hppCount)
}
tsData := make([]models.RealHPPTimeSeries, 0, len(timeSeries))
for _, ts := range timeSeries {
tsData = append(tsData, models.RealHPPTimeSeries{
Date: ts.Date,
RealTotalCost: ts.RealTotalCost,
RealTotalRevenue: ts.RealTotalRevenue,
RealHPPPercentage: ts.RealHPPPercentage,
TotalOrders: ts.TotalOrders,
})
}
return &models.RealHPPResponse{
OrganizationID: req.OrganizationID,
OutletID: req.OutletID,
DateFrom: req.DateFrom,
DateTo: req.DateTo,
GroupBy: req.GroupBy,
Summary: models.HPPSummary{
AverageRealHPP: avgHPP,
TotalProducts: int64(len(products)),
},
Products: productData,
TimeSeries: tsData,
}, nil
}