package util import ( "apskel-pos-be/internal/entities" "apskel-pos-be/internal/models" "fmt" "time" "github.com/google/uuid" ) // CalculateWasteQuantities calculates gross, net, and waste quantities for product ingredients func CalculateWasteQuantities(productIngredients []*entities.ProductIngredient, quantity float64) ([]*models.CreateOrderIngredientTransactionRequest, error) { if len(productIngredients) == 0 { return []*models.CreateOrderIngredientTransactionRequest{}, nil } transactions := make([]*models.CreateOrderIngredientTransactionRequest, 0, len(productIngredients)) for _, pi := range productIngredients { // Calculate net quantity (actual quantity needed for the product) netQty := pi.Quantity * quantity // Calculate gross quantity (including waste) wasteMultiplier := 1 + (pi.WastePercentage / 100) grossQty := netQty * wasteMultiplier // Calculate waste quantity wasteQty := grossQty - netQty // Get unit name from ingredient unitName := "unit" // default if pi.Ingredient != nil && pi.Ingredient.Unit != nil { unitName = pi.Ingredient.Unit.Name } transaction := &models.CreateOrderIngredientTransactionRequest{ IngredientID: pi.IngredientID, GrossQty: RoundToDecimalPlaces(grossQty, 3), NetQty: RoundToDecimalPlaces(netQty, 3), WasteQty: RoundToDecimalPlaces(wasteQty, 3), Unit: unitName, } transactions = append(transactions, transaction) } return transactions, nil } // CreateOrderIngredientTransactionsFromProduct creates order ingredient transactions for a product func CreateOrderIngredientTransactionsFromProduct( productID uuid.UUID, productVariantID *uuid.UUID, orderID uuid.UUID, orderItemID *uuid.UUID, quantity float64, productIngredients []*entities.ProductIngredient, organizationID, outletID, createdBy uuid.UUID, ) ([]*models.CreateOrderIngredientTransactionRequest, error) { // Calculate waste quantities wasteTransactions, err := CalculateWasteQuantities(productIngredients, quantity) if err != nil { return nil, fmt.Errorf("failed to calculate waste quantities: %w", err) } // Set common fields for all transactions for _, transaction := range wasteTransactions { transaction.OrderID = orderID transaction.OrderItemID = orderItemID transaction.ProductID = productID transaction.ProductVariantID = productVariantID transaction.TransactionDate = &time.Time{} *transaction.TransactionDate = time.Now() } return wasteTransactions, nil } // RoundToDecimalPlaces rounds a float64 to the specified number of decimal places func RoundToDecimalPlaces(value float64, places int) float64 { multiplier := 1.0 for i := 0; i < places; i++ { multiplier *= 10 } return float64(int(value*multiplier+0.5)) / multiplier }