Add Inventory Report
This commit is contained in:
@@ -3,6 +3,7 @@ package processor
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
@@ -25,7 +26,7 @@ type InventoryProcessor interface {
|
||||
AdjustQuantity(ctx context.Context, productID, outletID, organizationID uuid.UUID, delta int) (*models.InventoryResponse, error)
|
||||
SetQuantity(ctx context.Context, productID, outletID, organizationID uuid.UUID, quantity int) (*models.InventoryResponse, error)
|
||||
UpdateReorderLevel(ctx context.Context, id uuid.UUID, reorderLevel int, organizationID uuid.UUID) error
|
||||
GetInventoryReportSummary(ctx context.Context, outletID, organizationID uuid.UUID) (*models.InventoryReportSummary, error)
|
||||
GetInventoryReportSummary(ctx context.Context, outletID, organizationID uuid.UUID, dateFrom, dateTo *time.Time) (*models.InventoryReportSummary, error)
|
||||
GetInventoryReportDetails(ctx context.Context, filter *models.InventoryReportFilter, organizationID uuid.UUID) (*models.InventoryReportDetail, error)
|
||||
}
|
||||
|
||||
@@ -257,9 +258,7 @@ func (p *InventoryProcessorImpl) GetZeroStock(ctx context.Context, outletID, org
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
// GetInventoryReportSummary returns summary statistics for inventory report
|
||||
func (p *InventoryProcessorImpl) GetInventoryReportSummary(ctx context.Context, outletID, organizationID uuid.UUID) (*models.InventoryReportSummary, error) {
|
||||
// Verify outlet belongs to organization
|
||||
func (p *InventoryProcessorImpl) GetInventoryReportSummary(ctx context.Context, outletID, organizationID uuid.UUID, dateFrom, dateTo *time.Time) (*models.InventoryReportSummary, error) {
|
||||
outlet, err := p.outletRepo.GetByID(ctx, outletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("outlet not found: %w", err)
|
||||
@@ -268,7 +267,7 @@ func (p *InventoryProcessorImpl) GetInventoryReportSummary(ctx context.Context,
|
||||
return nil, fmt.Errorf("outlet does not belong to the organization")
|
||||
}
|
||||
|
||||
summary, err := p.inventoryRepo.GetInventoryReportSummary(ctx, outletID)
|
||||
summary, err := p.inventoryRepo.GetInventoryReportSummary(ctx, outletID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get inventory report summary: %w", err)
|
||||
}
|
||||
@@ -282,7 +281,6 @@ func (p *InventoryProcessorImpl) GetInventoryReportDetails(ctx context.Context,
|
||||
return nil, fmt.Errorf("outlet_id is required for inventory report")
|
||||
}
|
||||
|
||||
// Verify outlet belongs to organization
|
||||
outlet, err := p.outletRepo.GetByID(ctx, *filter.OutletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("outlet not found: %w", err)
|
||||
|
||||
@@ -1334,18 +1334,8 @@ type ingredientRecipeData struct {
|
||||
|
||||
// prepareIngredientRecipeData prepares ingredient recipe data without making database calls
|
||||
func (p *OrderProcessorImpl) prepareIngredientRecipeData(ctx context.Context, item *entities.OrderItem, order *entities.Order, payment *entities.Payment) (*ingredientRecipeData, error) {
|
||||
// Check if the product has ingredients
|
||||
product, err := p.productRepo.GetByID(ctx, item.ProductID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get product: %w", err)
|
||||
}
|
||||
|
||||
if !product.HasIngredients {
|
||||
return &ingredientRecipeData{}, nil // Product doesn't have ingredients
|
||||
}
|
||||
|
||||
// Get product recipes based on variant (if any)
|
||||
var recipes []*entities.ProductRecipe
|
||||
var err error
|
||||
if item.ProductVariantID != nil {
|
||||
recipes, err = p.productRecipeRepo.GetByProductAndVariantID(ctx, item.ProductID, item.ProductVariantID, order.OrganizationID)
|
||||
} else {
|
||||
@@ -1363,7 +1353,6 @@ func (p *OrderProcessorImpl) prepareIngredientRecipeData(ctx context.Context, it
|
||||
var ingredientUpdates []*entities.Ingredient
|
||||
var movements []*entities.InventoryMovement
|
||||
|
||||
// Process each ingredient in the recipe
|
||||
for _, recipe := range recipes {
|
||||
ingredientData, err := p.prepareIngredientRecipeItem(ctx, recipe, item, order, payment)
|
||||
if err != nil {
|
||||
@@ -1388,20 +1377,15 @@ type ingredientRecipeItem struct {
|
||||
|
||||
// prepareIngredientRecipeItem prepares data for a single ingredient recipe without making database calls
|
||||
func (p *OrderProcessorImpl) prepareIngredientRecipeItem(ctx context.Context, recipe *entities.ProductRecipe, item *entities.OrderItem, order *entities.Order, payment *entities.Payment) (*ingredientRecipeItem, error) {
|
||||
// Calculate total ingredient quantity needed
|
||||
totalIngredientQuantity := recipe.Quantity * float64(item.Quantity)
|
||||
|
||||
// Get current ingredient details
|
||||
currentIngredient, err := p.ingredientRepo.GetByID(ctx, recipe.IngredientID, order.OrganizationID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get ingredient: %w", err)
|
||||
}
|
||||
|
||||
// For ingredients, we typically don't track quantity in the ingredient entity itself
|
||||
// Instead, we create inventory movement records to track consumption
|
||||
// The ingredient entity remains unchanged, but we track the movement
|
||||
currentIngredient.Stock -= totalIngredientQuantity
|
||||
|
||||
// Prepare movement record
|
||||
movement := &entities.InventoryMovement{
|
||||
OrganizationID: order.OrganizationID,
|
||||
OutletID: order.OutletID,
|
||||
@@ -1409,8 +1393,8 @@ func (p *OrderProcessorImpl) prepareIngredientRecipeItem(ctx context.Context, re
|
||||
ItemType: "INGREDIENT",
|
||||
MovementType: entities.InventoryMovementTypeIngredient,
|
||||
Quantity: -totalIngredientQuantity,
|
||||
PreviousQuantity: 0, // We don't track current quantity in ingredient entity
|
||||
NewQuantity: 0, // We don't track current quantity in ingredient entity
|
||||
PreviousQuantity: 0,
|
||||
NewQuantity: 0,
|
||||
UnitCost: currentIngredient.Cost,
|
||||
TotalCost: totalIngredientQuantity * currentIngredient.Cost,
|
||||
ReferenceType: func() *entities.InventoryMovementReferenceType {
|
||||
|
||||
Reference in New Issue
Block a user