add product ingredients

This commit is contained in:
Aditya Siregar
2025-09-12 15:37:19 +07:00
parent efe09c21e4
commit 3a04990ec8
35 changed files with 2572 additions and 357 deletions
+3 -4
View File
@@ -8,7 +8,6 @@ import (
"path/filepath"
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/processor"
"github.com/google/uuid"
)
@@ -35,8 +34,8 @@ type AccountTemplate struct {
}
func CreateDefaultChartOfAccounts(ctx context.Context,
chartOfAccountProcessor processor.ChartOfAccountProcessor,
accountProcessor processor.AccountProcessor,
chartOfAccountProcessor interface{}, // Use interface{} to avoid import cycle
accountProcessor interface{}, // Use interface{} to avoid import cycle
organizationID uuid.UUID,
outletID *uuid.UUID) error {
@@ -100,7 +99,7 @@ func loadDefaultChartOfAccountsTemplate() (*DefaultChartOfAccount, error) {
return &template, nil
}
func getChartOfAccountTypeMap(ctx context.Context, chartOfAccountProcessor processor.ChartOfAccountProcessor) (map[string]uuid.UUID, error) {
func getChartOfAccountTypeMap(ctx context.Context, chartOfAccountProcessor interface{}) (map[string]uuid.UUID, error) {
// This is a placeholder - in a real implementation, you would call the processor
// to get all chart of account types and create a map of code -> ID
return map[string]uuid.UUID{
+87
View File
@@ -0,0 +1,87 @@
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
}