addd inventory movement
This commit is contained in:
parent
3a0c262c77
commit
07b3eda263
@ -99,7 +99,8 @@ type InventoryProductDetailResponse struct {
|
|||||||
ReorderLevel int `json:"reorder_level"`
|
ReorderLevel int `json:"reorder_level"`
|
||||||
UnitCost float64 `json:"unit_cost"`
|
UnitCost float64 `json:"unit_cost"`
|
||||||
TotalValue float64 `json:"total_value"`
|
TotalValue float64 `json:"total_value"`
|
||||||
TotalSold float64 `json:"total_sold"`
|
TotalIn float64 `json:"total_in"`
|
||||||
|
TotalOut float64 `json:"total_out"`
|
||||||
IsLowStock bool `json:"is_low_stock"`
|
IsLowStock bool `json:"is_low_stock"`
|
||||||
IsZeroStock bool `json:"is_zero_stock"`
|
IsZeroStock bool `json:"is_zero_stock"`
|
||||||
UpdatedAt string `json:"updated_at"`
|
UpdatedAt string `json:"updated_at"`
|
||||||
@ -114,7 +115,8 @@ type InventoryIngredientDetailResponse struct {
|
|||||||
ReorderLevel int `json:"reorder_level"`
|
ReorderLevel int `json:"reorder_level"`
|
||||||
UnitCost float64 `json:"unit_cost"`
|
UnitCost float64 `json:"unit_cost"`
|
||||||
TotalValue float64 `json:"total_value"`
|
TotalValue float64 `json:"total_value"`
|
||||||
TotalSold float64 `json:"total_sold"`
|
TotalIn float64 `json:"total_in"`
|
||||||
|
TotalOut float64 `json:"total_out"`
|
||||||
IsLowStock bool `json:"is_low_stock"`
|
IsLowStock bool `json:"is_low_stock"`
|
||||||
IsZeroStock bool `json:"is_zero_stock"`
|
IsZeroStock bool `json:"is_zero_stock"`
|
||||||
UpdatedAt string `json:"updated_at"`
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
|||||||
@ -92,7 +92,8 @@ type InventoryProductDetail struct {
|
|||||||
ReorderLevel int `json:"reorder_level"`
|
ReorderLevel int `json:"reorder_level"`
|
||||||
UnitCost float64 `json:"unit_cost"`
|
UnitCost float64 `json:"unit_cost"`
|
||||||
TotalValue float64 `json:"total_value"`
|
TotalValue float64 `json:"total_value"`
|
||||||
TotalSold float64 `json:"total_sold"`
|
TotalIn float64 `json:"total_in"`
|
||||||
|
TotalOut float64 `json:"total_out"`
|
||||||
IsLowStock bool `json:"is_low_stock"`
|
IsLowStock bool `json:"is_low_stock"`
|
||||||
IsZeroStock bool `json:"is_zero_stock"`
|
IsZeroStock bool `json:"is_zero_stock"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
@ -107,7 +108,8 @@ type InventoryIngredientDetail struct {
|
|||||||
ReorderLevel int `json:"reorder_level"`
|
ReorderLevel int `json:"reorder_level"`
|
||||||
UnitCost float64 `json:"unit_cost"`
|
UnitCost float64 `json:"unit_cost"`
|
||||||
TotalValue float64 `json:"total_value"`
|
TotalValue float64 `json:"total_value"`
|
||||||
TotalSold float64 `json:"total_sold"`
|
TotalIn float64 `json:"total_in"`
|
||||||
|
TotalOut float64 `json:"total_out"`
|
||||||
IsLowStock bool `json:"is_low_stock"`
|
IsLowStock bool `json:"is_low_stock"`
|
||||||
IsZeroStock bool `json:"is_zero_stock"`
|
IsZeroStock bool `json:"is_zero_stock"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
|||||||
@ -513,27 +513,39 @@ func (r *InventoryRepositoryImpl) getInventoryProductsDetails(ctx context.Contex
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now get total sold for each product
|
// Now get total in and out for each product
|
||||||
var products []*models.InventoryProductDetail
|
var products []*models.InventoryProductDetail
|
||||||
for _, result := range baseResults {
|
for _, result := range baseResults {
|
||||||
var totalSold float64
|
var totalIn, totalOut float64
|
||||||
|
|
||||||
// Query total sold for this specific product
|
// Query total in (positive movements) for this specific product
|
||||||
soldQuery := r.db.WithContext(ctx).Model(&entities.InventoryMovement{}).
|
inQuery := r.db.WithContext(ctx).Model(&entities.InventoryMovement{}).
|
||||||
|
Select("COALESCE(SUM(quantity), 0)").
|
||||||
|
Where("item_id = ? AND outlet_id = ? AND item_type = ? AND quantity > 0",
|
||||||
|
result.ProductID, filter.OutletID, "PRODUCT")
|
||||||
|
|
||||||
|
// Query total out (negative movements) for this specific product
|
||||||
|
outQuery := r.db.WithContext(ctx).Model(&entities.InventoryMovement{}).
|
||||||
Select("COALESCE(SUM(ABS(quantity)), 0)").
|
Select("COALESCE(SUM(ABS(quantity)), 0)").
|
||||||
Where("item_id = ? AND outlet_id = ? AND item_type = ? AND movement_type = ? AND quantity < 0",
|
Where("item_id = ? AND outlet_id = ? AND item_type = ? AND quantity < 0",
|
||||||
result.ProductID, filter.OutletID, "PRODUCT", entities.InventoryMovementTypeSale)
|
result.ProductID, filter.OutletID, "PRODUCT")
|
||||||
|
|
||||||
// Apply date filters if provided
|
// Apply date filters if provided
|
||||||
if filter.DateFrom != nil {
|
if filter.DateFrom != nil {
|
||||||
soldQuery = soldQuery.Where("created_at >= ?", *filter.DateFrom)
|
inQuery = inQuery.Where("created_at >= ?", *filter.DateFrom)
|
||||||
|
outQuery = outQuery.Where("created_at >= ?", *filter.DateFrom)
|
||||||
}
|
}
|
||||||
if filter.DateTo != nil {
|
if filter.DateTo != nil {
|
||||||
soldQuery = soldQuery.Where("created_at <= ?", *filter.DateTo)
|
inQuery = inQuery.Where("created_at <= ?", *filter.DateTo)
|
||||||
|
outQuery = outQuery.Where("created_at <= ?", *filter.DateTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := soldQuery.Scan(&totalSold).Error; err != nil {
|
if err := inQuery.Scan(&totalIn).Error; err != nil {
|
||||||
return nil, fmt.Errorf("failed to get total sold for product %s: %w", result.ProductID, err)
|
return nil, fmt.Errorf("failed to get total in for product %s: %w", result.ProductID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := outQuery.Scan(&totalOut).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get total out for product %s: %w", result.ProductID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
categoryName := ""
|
categoryName := ""
|
||||||
@ -550,7 +562,8 @@ func (r *InventoryRepositoryImpl) getInventoryProductsDetails(ctx context.Contex
|
|||||||
ReorderLevel: result.ReorderLevel,
|
ReorderLevel: result.ReorderLevel,
|
||||||
UnitCost: result.UnitCost,
|
UnitCost: result.UnitCost,
|
||||||
TotalValue: result.TotalValue,
|
TotalValue: result.TotalValue,
|
||||||
TotalSold: totalSold,
|
TotalIn: totalIn,
|
||||||
|
TotalOut: totalOut,
|
||||||
IsLowStock: result.Quantity <= result.ReorderLevel && result.Quantity > 0,
|
IsLowStock: result.Quantity <= result.ReorderLevel && result.Quantity > 0,
|
||||||
IsZeroStock: result.Quantity == 0,
|
IsZeroStock: result.Quantity == 0,
|
||||||
UpdatedAt: result.UpdatedAt,
|
UpdatedAt: result.UpdatedAt,
|
||||||
@ -617,22 +630,35 @@ func (r *InventoryRepositoryImpl) getInventoryIngredientsDetails(ctx context.Con
|
|||||||
|
|
||||||
var ingredients []*models.InventoryIngredientDetail
|
var ingredients []*models.InventoryIngredientDetail
|
||||||
for _, result := range baseResults {
|
for _, result := range baseResults {
|
||||||
var totalSold float64
|
var totalIn, totalOut float64
|
||||||
|
|
||||||
soldQuery := r.db.WithContext(ctx).Model(&entities.InventoryMovement{}).
|
// Query total in (positive movements) for this specific ingredient
|
||||||
|
inQuery := r.db.WithContext(ctx).Model(&entities.InventoryMovement{}).
|
||||||
|
Select("COALESCE(SUM(quantity), 0)").
|
||||||
|
Where("item_id = ? AND outlet_id = ? AND item_type = ? AND quantity > 0",
|
||||||
|
result.IngredientID, filter.OutletID, "INGREDIENT")
|
||||||
|
|
||||||
|
// Query total out (negative movements) for this specific ingredient
|
||||||
|
outQuery := r.db.WithContext(ctx).Model(&entities.InventoryMovement{}).
|
||||||
Select("COALESCE(SUM(ABS(quantity)), 0)").
|
Select("COALESCE(SUM(ABS(quantity)), 0)").
|
||||||
Where("item_id = ? AND outlet_id = ? AND item_type = ? AND movement_type = ? AND quantity < 0",
|
Where("item_id = ? AND outlet_id = ? AND item_type = ? AND quantity < 0",
|
||||||
result.IngredientID, filter.OutletID, "INGREDIENT", entities.InventoryMovementTypeSale)
|
result.IngredientID, filter.OutletID, "INGREDIENT")
|
||||||
|
|
||||||
if filter.DateFrom != nil {
|
if filter.DateFrom != nil {
|
||||||
soldQuery = soldQuery.Where("created_at >= ?", *filter.DateFrom)
|
inQuery = inQuery.Where("created_at >= ?", *filter.DateFrom)
|
||||||
|
outQuery = outQuery.Where("created_at >= ?", *filter.DateFrom)
|
||||||
}
|
}
|
||||||
if filter.DateTo != nil {
|
if filter.DateTo != nil {
|
||||||
soldQuery = soldQuery.Where("created_at <= ?", *filter.DateTo)
|
inQuery = inQuery.Where("created_at <= ?", *filter.DateTo)
|
||||||
|
outQuery = outQuery.Where("created_at <= ?", *filter.DateTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := soldQuery.Scan(&totalSold).Error; err != nil {
|
if err := inQuery.Scan(&totalIn).Error; err != nil {
|
||||||
return nil, fmt.Errorf("failed to get total sold for ingredient %s: %w", result.IngredientID, err)
|
return nil, fmt.Errorf("failed to get total in for ingredient %s: %w", result.IngredientID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := outQuery.Scan(&totalOut).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get total out for ingredient %s: %w", result.IngredientID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
unitName := ""
|
unitName := ""
|
||||||
@ -649,7 +675,8 @@ func (r *InventoryRepositoryImpl) getInventoryIngredientsDetails(ctx context.Con
|
|||||||
ReorderLevel: result.ReorderLevel,
|
ReorderLevel: result.ReorderLevel,
|
||||||
UnitCost: result.UnitCost,
|
UnitCost: result.UnitCost,
|
||||||
TotalValue: result.TotalValue,
|
TotalValue: result.TotalValue,
|
||||||
TotalSold: totalSold,
|
TotalIn: totalIn,
|
||||||
|
TotalOut: totalOut,
|
||||||
IsLowStock: result.Quantity <= 0 && result.Quantity > 0,
|
IsLowStock: result.Quantity <= 0 && result.Quantity > 0,
|
||||||
IsZeroStock: result.Quantity == 0,
|
IsZeroStock: result.Quantity == 0,
|
||||||
UpdatedAt: result.UpdatedAt,
|
UpdatedAt: result.UpdatedAt,
|
||||||
|
|||||||
@ -247,7 +247,8 @@ func (s *InventoryServiceImpl) GetInventoryReportDetails(ctx context.Context, fi
|
|||||||
ReorderLevel: product.ReorderLevel,
|
ReorderLevel: product.ReorderLevel,
|
||||||
UnitCost: product.UnitCost,
|
UnitCost: product.UnitCost,
|
||||||
TotalValue: product.TotalValue,
|
TotalValue: product.TotalValue,
|
||||||
TotalSold: product.TotalSold,
|
TotalIn: product.TotalIn,
|
||||||
|
TotalOut: product.TotalOut,
|
||||||
IsLowStock: product.IsLowStock,
|
IsLowStock: product.IsLowStock,
|
||||||
IsZeroStock: product.IsZeroStock,
|
IsZeroStock: product.IsZeroStock,
|
||||||
UpdatedAt: product.UpdatedAt.Format(time.RFC3339),
|
UpdatedAt: product.UpdatedAt.Format(time.RFC3339),
|
||||||
@ -266,7 +267,8 @@ func (s *InventoryServiceImpl) GetInventoryReportDetails(ctx context.Context, fi
|
|||||||
ReorderLevel: ingredient.ReorderLevel,
|
ReorderLevel: ingredient.ReorderLevel,
|
||||||
UnitCost: ingredient.UnitCost,
|
UnitCost: ingredient.UnitCost,
|
||||||
TotalValue: ingredient.TotalValue,
|
TotalValue: ingredient.TotalValue,
|
||||||
TotalSold: ingredient.TotalSold,
|
TotalIn: ingredient.TotalIn,
|
||||||
|
TotalOut: ingredient.TotalOut,
|
||||||
IsLowStock: ingredient.IsLowStock,
|
IsLowStock: ingredient.IsLowStock,
|
||||||
IsZeroStock: ingredient.IsZeroStock,
|
IsZeroStock: ingredient.IsZeroStock,
|
||||||
UpdatedAt: ingredient.UpdatedAt.Format(time.RFC3339),
|
UpdatedAt: ingredient.UpdatedAt.Format(time.RFC3339),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user