Consume any subproduct when consuming a recipe ingredient which is not in stock (fixes #446)

This commit is contained in:
Bernd Bestel
2020-01-27 22:14:11 +01:00
parent dceed6759a
commit e84c7063d3
6 changed files with 41 additions and 20 deletions

View File

@@ -67,12 +67,13 @@ class RecipesService extends BaseService
throw new \Exception('Recipe does not exist');
}
$transactionId = uniqid();
$recipePositions = $this->Database->recipes_pos_resolved()->where('recipe_id', $recipeId)->fetchAll();
foreach ($recipePositions as $recipePosition)
{
if ($recipePosition->only_check_single_unit_in_stock == 0)
{
$this->StockService->ConsumeProduct($recipePosition->product_id, $recipePosition->recipe_amount, false, StockService::TRANSACTION_TYPE_CONSUME, 'default', $recipeId);
$this->StockService->ConsumeProduct($recipePosition->product_id, $recipePosition->recipe_amount, false, StockService::TRANSACTION_TYPE_CONSUME, 'default', $recipeId, null, $transactionId, true);
}
}

View File

@@ -184,24 +184,29 @@ class StockService extends BaseService
return $this->Database->stock()->where('id', $entryId)->fetch();
}
public function GetProductStockEntries($productId, $excludeOpened = false)
public function GetProductStockEntries($productId, $excludeOpened = false, $allowSubproductSubstitution = false)
{
// In order of next use:
// First expiring first, then first in first out
$sqlWhereProductId = 'product_id = :1';
if ($allowSubproductSubstitution)
{
$sqlWhereProductId = '(product_id IN (SELECT sub_product_id FROM products_resolved WHERE parent_product_id = :1) OR product_id = :1)';
}
$sqlOpenAndWhere = 'AND open IN (0, 1)';
if ($excludeOpened)
{
return $this->Database->stock()->where('product_id = :1 AND open = 0', $productId)->orderBy('best_before_date', 'ASC')->orderBy('purchased_date', 'ASC')->fetchAll();
}
else
{
return $this->Database->stock()->where('product_id', $productId)->orderBy('best_before_date', 'ASC')->orderBy('purchased_date', 'ASC')->fetchAll();
$sqlOpenAndWhere = 'AND open = 0';
}
return $this->Database->stock()->where($sqlWhereProductId . ' ' . $sqlOpenAndWhere, $productId)->orderBy('best_before_date', 'ASC')->orderBy('purchased_date', 'ASC')->fetchAll();
}
public function GetProductStockEntriesForLocation($productId, $locationId, $excludeOpened = false)
public function GetProductStockEntriesForLocation($productId, $locationId, $excludeOpened = false, $allowSubproductSubstitution = false)
{
$stockEntries = $this->GetProductStockEntries($productId, $excludeOpened);
$stockEntries = $this->GetProductStockEntries($productId, $excludeOpened, $allowSubproductSubstitution);
return FindAllObjectsInArrayByPropertyValue($stockEntries, 'location_id', $locationId);
}
@@ -286,14 +291,14 @@ class StockService extends BaseService
}
}
public function ConsumeProduct(int $productId, float $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default', $recipeId = null, $locationId = null, &$transactionId = null)
public function ConsumeProduct(int $productId, float $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default', $recipeId = null, $locationId = null, &$transactionId = null, $allowSubproductSubstitution = false)
{
if (!$this->ProductExists($productId))
{
throw new \Exception('Product does not exist');
}
if ($locationId !== null & !$this->LocationExists($locationId))
if ($locationId !== null && !$this->LocationExists($locationId))
{
throw new \Exception('Location does not exist');
}
@@ -316,15 +321,14 @@ class StockService extends BaseService
{
if ($locationId === null) // Consume from any location
{
$productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
$potentialStockEntries = $this->GetProductStockEntries($productId);
$potentialStockEntries = $this->GetProductStockEntries($productId, false, $allowSubproductSubstitution);
}
else // Consume only from the supplied location
{
$productStockAmount = $this->Database->stock()->where('product_id = :1 AND location_id = :2', $productId, $locationId)->sum('amount');
$potentialStockEntries = $this->GetProductStockEntriesForLocation($productId, $locationId);
$potentialStockEntries = $this->GetProductStockEntriesForLocation($productId, $locationId, false, $allowSubproductSubstitution);
}
$productStockAmount = SumArrayValue($potentialStockEntries, 'amount');
if ($amount > $productStockAmount)
{
throw new \Exception('Amount to be consumed cannot be > current stock amount (if supplied, at the desired location)');