feat(purchase): unwired unit convertions
This commit is contained in:
@@ -32,6 +32,9 @@ type PurchaseOrderProcessorImpl struct {
|
|||||||
categoryRepo CategoryRepository
|
categoryRepo CategoryRepository
|
||||||
unitRepo UnitRepository
|
unitRepo UnitRepository
|
||||||
fileRepo FileRepository
|
fileRepo FileRepository
|
||||||
|
// Kept wired but currently unused: purchase orders are a record of spending
|
||||||
|
// only, so nothing here moves stock or converts units. These stay so that
|
||||||
|
// tying purchases back to inventory is a change in one place.
|
||||||
inventoryMovementService InventoryMovementService
|
inventoryMovementService InventoryMovementService
|
||||||
unitConverterRepo IngredientUnitConverterRepository
|
unitConverterRepo IngredientUnitConverterRepository
|
||||||
}
|
}
|
||||||
@@ -438,73 +441,11 @@ func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrderStatus(ctx context.Conte
|
|||||||
|
|
||||||
fmt.Println("status:", po.Status)
|
fmt.Println("status:", po.Status)
|
||||||
|
|
||||||
// Check if status is changing to "received" and current status is not "received"
|
// A purchase order is a record of spending only. Receiving one does not move
|
||||||
if status == "received" && po.Status != "received" {
|
// ingredient stock, does not recalculate ingredient cost, and never converts
|
||||||
// Get purchase order with items for inventory update
|
// units: the quantity and unit on an item are kept exactly as the user
|
||||||
poWithItems, err := p.purchaseOrderRepo.GetByID(ctx, id)
|
// entered them. Raw material items are therefore treated the same way expense
|
||||||
if err != nil {
|
// items already were, and the ingredient on an item is just a reference.
|
||||||
return nil, fmt.Errorf("failed to get purchase order with items: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update inventory for each item
|
|
||||||
for _, item := range poWithItems.Items {
|
|
||||||
if item.PurchaseCategory != nil && item.PurchaseCategory.Type == entities.PurchaseCategoryTypeExpense {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if item.IngredientID == nil || item.UnitID == nil || item.Quantity == nil {
|
|
||||||
return nil, fmt.Errorf("purchase order item %s is missing raw material inventory fields", item.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get ingredient to find its base unit
|
|
||||||
ingredient, err := p.ingredientRepo.GetByID(ctx, *item.IngredientID, organizationID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get ingredient %s: %w", *item.IngredientID, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert quantity to ingredient's base unit if needed. An ingredient
|
|
||||||
// without a unit has no base unit to convert into, so the purchased
|
|
||||||
// quantity is taken as-is.
|
|
||||||
quantityToAdd := *item.Quantity
|
|
||||||
if ingredient.UnitID != nil && *item.UnitID != *ingredient.UnitID {
|
|
||||||
// Convert from purchase unit to ingredient's base unit
|
|
||||||
convertedQuantity, err := p.unitConverterRepo.ConvertQuantity(ctx, *item.IngredientID, *item.UnitID, *ingredient.UnitID, organizationID, *item.Quantity)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to convert quantity for ingredient %s from unit %s to %s: %w", *item.IngredientID, *item.UnitID, *ingredient.UnitID, err)
|
|
||||||
}
|
|
||||||
quantityToAdd = convertedQuantity
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate unit cost in ingredient's base unit
|
|
||||||
unitCost := 0.0
|
|
||||||
if quantityToAdd > 0 {
|
|
||||||
unitCost = calculatePurchaseOrderItemTotal(item.Quantity, item.Amount) / quantityToAdd
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create inventory movement for ingredient purchase
|
|
||||||
reason := fmt.Sprintf("Purchase order %s received", po.PONumber)
|
|
||||||
referenceType := entities.InventoryMovementReferenceTypePurchaseOrder
|
|
||||||
referenceID := &id
|
|
||||||
|
|
||||||
err = p.inventoryMovementService.CreateIngredientMovement(
|
|
||||||
ctx,
|
|
||||||
*item.IngredientID,
|
|
||||||
organizationID,
|
|
||||||
outletID,
|
|
||||||
userID,
|
|
||||||
entities.InventoryMovementTypePurchase,
|
|
||||||
quantityToAdd,
|
|
||||||
unitCost,
|
|
||||||
reason,
|
|
||||||
&referenceType,
|
|
||||||
referenceID,
|
|
||||||
&item.ID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create inventory movement for ingredient %s: %w", *item.IngredientID, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the purchase order status
|
// Update the purchase order status
|
||||||
statusOutletID := po.OutletID
|
statusOutletID := po.OutletID
|
||||||
|
|||||||
Reference in New Issue
Block a user