Revert purchase order

This commit is contained in:
2026-06-15 13:52:08 +07:00
parent 7a7ac25dcf
commit 657a201fc0
10 changed files with 185 additions and 157 deletions
+44 -84
View File
@@ -67,40 +67,20 @@ func (p *PurchaseOrderProcessorImpl) CreatePurchaseOrder(ctx context.Context, or
return nil, fmt.Errorf("purchase order with PO number %s already exists in this organization", req.PONumber)
}
// Validate categories and inventory fields per item type.
// Purchase orders are raw-material only because they affect ingredient stock.
for i, item := range req.Items {
category, err := p.validatePurchaseCategory(ctx, item.PurchaseCategoryID, organizationID, i)
if err != nil {
if err := p.validateRawMaterialPurchaseCategory(ctx, item.PurchaseCategoryID, organizationID, i); err != nil {
return nil, err
}
switch category.Type {
case entities.PurchaseCategoryTypeRawMaterial:
if item.IngredientID == nil {
return nil, fmt.Errorf("ingredient_id is required for raw_material item %d", i)
}
if item.Quantity == nil {
return nil, fmt.Errorf("quantity is required for raw_material item %d", i)
}
if item.UnitID == nil {
return nil, fmt.Errorf("unit_id is required for raw_material item %d", i)
}
_, err := p.ingredientRepo.GetByID(ctx, item.IngredientID, organizationID)
if err != nil {
return nil, fmt.Errorf("ingredient not found for item %d: %w", i, err)
}
_, err := p.ingredientRepo.GetByID(ctx, *item.IngredientID, organizationID)
if err != nil {
return nil, fmt.Errorf("ingredient not found for item %d: %w", i, err)
}
_, err = p.unitRepo.GetByID(ctx, *item.UnitID, organizationID)
if err != nil {
return nil, fmt.Errorf("unit not found for item %d: %w", i, err)
}
case entities.PurchaseCategoryTypeExpense:
if item.IngredientID != nil || item.Quantity != nil || item.UnitID != nil {
return nil, fmt.Errorf("ingredient_id, quantity, and unit_id must be empty for expense item %d", i)
}
default:
return nil, fmt.Errorf("purchase category for item %d has unsupported type %s", i, category.Type)
_, err = p.unitRepo.GetByID(ctx, item.UnitID, organizationID)
if err != nil {
return nil, fmt.Errorf("unit not found for item %d: %w", i, err)
}
}
@@ -224,48 +204,38 @@ func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrder(ctx context.Context, id
return nil, fmt.Errorf("purchase_category_id is required for item %d", i)
}
ingredientID := itemReq.IngredientID
if itemReq.IngredientID == nil {
return nil, fmt.Errorf("ingredient_id is required for raw_material item %d", i)
}
if itemReq.Quantity == nil {
return nil, fmt.Errorf("quantity is required for raw_material item %d", i)
}
if itemReq.UnitID == nil {
return nil, fmt.Errorf("unit_id is required for raw_material item %d", i)
}
ingredientID := *itemReq.IngredientID
purchaseCategoryID := *itemReq.PurchaseCategoryID
unitID := itemReq.UnitID
quantity := itemReq.Quantity
unitID := *itemReq.UnitID
quantity := *itemReq.Quantity
amount := 0.0
if itemReq.Amount != nil {
amount = *itemReq.Amount
}
description := itemReq.Description
category, err := p.validatePurchaseCategory(ctx, purchaseCategoryID, organizationID, i)
if err != nil {
if err := p.validateRawMaterialPurchaseCategory(ctx, purchaseCategoryID, organizationID, i); err != nil {
return nil, err
}
switch category.Type {
case entities.PurchaseCategoryTypeRawMaterial:
if ingredientID == nil {
return nil, fmt.Errorf("ingredient_id is required for raw_material item %d", i)
}
if quantity == nil {
return nil, fmt.Errorf("quantity is required for raw_material item %d", i)
}
if unitID == nil {
return nil, fmt.Errorf("unit_id is required for raw_material item %d", i)
}
_, err := p.ingredientRepo.GetByID(ctx, ingredientID, organizationID)
if err != nil {
return nil, fmt.Errorf("ingredient not found: %w", err)
}
_, err := p.ingredientRepo.GetByID(ctx, *ingredientID, organizationID)
if err != nil {
return nil, fmt.Errorf("ingredient not found: %w", err)
}
_, err = p.unitRepo.GetByID(ctx, *unitID, organizationID)
if err != nil {
return nil, fmt.Errorf("unit not found: %w", err)
}
case entities.PurchaseCategoryTypeExpense:
if ingredientID != nil || quantity != nil || unitID != nil {
return nil, fmt.Errorf("ingredient_id, quantity, and unit_id must be empty for expense item %d", i)
}
default:
return nil, fmt.Errorf("purchase category for item %d has unsupported type %s", i, category.Type)
_, err = p.unitRepo.GetByID(ctx, unitID, organizationID)
if err != nil {
return nil, fmt.Errorf("unit not found: %w", err)
}
items[i] = &entities.PurchaseOrderItem{
@@ -407,8 +377,6 @@ func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrderStatus(ctx context.Conte
return nil, fmt.Errorf("purchase order not found: %w", err)
}
fmt.Println("status:", po.Status)
// Check if status is changing to "received" and current status is not "received"
if status == "received" && po.Status != "received" {
// Get purchase order with items for inventory update
@@ -419,27 +387,19 @@ func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrderStatus(ctx context.Conte
// 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)
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)
return nil, fmt.Errorf("failed to get ingredient %s: %w", item.IngredientID, err)
}
// Convert quantity to ingredient's base unit if needed
quantityToAdd := *item.Quantity
if *item.UnitID != ingredient.UnitID {
quantityToAdd := item.Quantity
if 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)
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)
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
}
@@ -457,7 +417,7 @@ func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrderStatus(ctx context.Conte
err = p.inventoryMovementService.CreateIngredientMovement(
ctx,
*item.IngredientID,
item.IngredientID,
organizationID,
outletID,
userID,
@@ -470,7 +430,7 @@ func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrderStatus(ctx context.Conte
&item.ID,
)
if err != nil {
return nil, fmt.Errorf("failed to create inventory movement for ingredient %s: %w", *item.IngredientID, err)
return nil, fmt.Errorf("failed to create inventory movement for ingredient %s: %w", item.IngredientID, err)
}
}
}
@@ -490,19 +450,19 @@ func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrderStatus(ctx context.Conte
return mappers.PurchaseOrderEntityToResponse(updatedPO), nil
}
func (p *PurchaseOrderProcessorImpl) validatePurchaseCategory(ctx context.Context, categoryID, organizationID uuid.UUID, itemIndex int) (*entities.PurchaseCategory, error) {
func (p *PurchaseOrderProcessorImpl) validateRawMaterialPurchaseCategory(ctx context.Context, categoryID, organizationID uuid.UUID, itemIndex int) error {
category, err := p.purchaseCategoryRepo.GetByIDAndOrganizationID(ctx, categoryID, organizationID)
if err != nil {
return nil, fmt.Errorf("purchase category not found for item %d: %w", itemIndex, err)
return fmt.Errorf("purchase category not found for item %d: %w", itemIndex, err)
}
if !category.IsActive {
return nil, fmt.Errorf("purchase category for item %d is inactive", itemIndex)
return fmt.Errorf("purchase category for item %d is inactive", itemIndex)
}
if category.Type != entities.PurchaseCategoryTypeRawMaterial && category.Type != entities.PurchaseCategoryTypeExpense {
return nil, fmt.Errorf("purchase category for item %d must be raw_material or expense", itemIndex)
if category.Type != entities.PurchaseCategoryTypeRawMaterial {
return fmt.Errorf("purchase category for item %d must be raw_material", itemIndex)
}
return category, nil
return nil
}