mirror of
https://github.com/grocy/grocy.git
synced 2026-07-01 03:59:04 -07:00
91d8eaeb74
Improve journal pages loading time (new date range filter) Various small style adjustments (meal plan page and others) Pulled German translations from Transifex Show the shopping list total value (closes #1309) Make it possible to copy recipes (closes #714) Implemented optional "auto decimal separator for price inputs" (closes #1345) Removed table grouped column fixed order restriction (closes #1402) Don't filter out style, class, id attributes of html text (closes #1298) Added product picture as column on the stock overview page (closes #1283) Added grocycodes also for chores and batteries (+ camera barcode scanning for /choretracking and /batterytracking, this now closes #221)
143 lines
5.2 KiB
PHP
143 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace Grocy\Services;
|
|
|
|
use LessQL\Result;
|
|
|
|
class RecipesService extends BaseService
|
|
{
|
|
const RECIPE_TYPE_MEALPLAN_DAY = 'mealplan-day'; // A recipe per meal plan day => name = YYYY-MM-DD
|
|
|
|
const RECIPE_TYPE_MEALPLAN_WEEK = 'mealplan-week'; // A recipe per meal plan week => name = YYYY-WW (week number)
|
|
|
|
const RECIPE_TYPE_MEALPLAN_SHADOW = 'mealplan-shadow'; // A recipe per meal plan recipe (for separated stock fulfillment checking) => name = YYYY-MM-DD#<meal_plan.id>
|
|
|
|
const RECIPE_TYPE_NORMAL = 'normal'; // Normal / manually created recipes
|
|
|
|
public function AddNotFulfilledProductsToShoppingList($recipeId, $excludedProductIds = null)
|
|
{
|
|
$recipe = $this->getDataBase()->recipes($recipeId);
|
|
$recipePositions = $this->GetRecipesPosResolved();
|
|
|
|
if ($excludedProductIds == null)
|
|
{
|
|
$excludedProductIds = [];
|
|
}
|
|
|
|
foreach ($recipePositions as $recipePosition)
|
|
{
|
|
if ($recipePosition->recipe_id == $recipeId && !in_array($recipePosition->product_id, $excludedProductIds))
|
|
{
|
|
$product = $this->getDataBase()->products($recipePosition->product_id);
|
|
$toOrderAmount = round(($recipePosition->missing_amount - $recipePosition->amount_on_shopping_list), 2);
|
|
|
|
if ($recipe->not_check_shoppinglist == 1)
|
|
{
|
|
$toOrderAmount = round($recipePosition->missing_amount, 2);
|
|
}
|
|
|
|
if ($toOrderAmount > 0)
|
|
{
|
|
$note = $this->getLocalizationService()->__t('Added for recipe %s', $recipe->name);
|
|
if (!empty($recipePosition->note))
|
|
{
|
|
$note .= "\n" . $recipePosition->note;
|
|
}
|
|
|
|
$shoppinglistRow = $this->getDataBase()->shopping_list()->createRow([
|
|
'product_id' => $recipePosition->product_id,
|
|
'amount' => $toOrderAmount,
|
|
'note' => $note
|
|
]);
|
|
$shoppinglistRow->save();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function ConsumeRecipe($recipeId)
|
|
{
|
|
if (!$this->RecipeExists($recipeId))
|
|
{
|
|
throw new \Exception('Recipe does not exist');
|
|
}
|
|
|
|
$transactionId = uniqid();
|
|
$recipePositions = $this->getDatabase()->recipes_pos_resolved()->where('recipe_id', $recipeId)->fetchAll();
|
|
|
|
foreach ($recipePositions as $recipePosition)
|
|
{
|
|
if ($recipePosition->only_check_single_unit_in_stock == 0)
|
|
{
|
|
$this->getStockService()->ConsumeProduct($recipePosition->product_id, $recipePosition->recipe_amount, false, StockService::TRANSACTION_TYPE_CONSUME, 'default', $recipeId, null, $transactionId, true, true);
|
|
}
|
|
}
|
|
|
|
$recipeRow = $this->getDatabase()->recipes()->where('id = :1', $recipeId)->fetch();
|
|
if (!empty($recipeRow->product_id))
|
|
{
|
|
$recipeResolvedRow = $this->getDatabase()->recipes_resolved()->where('recipe_id = :1', $recipeId)->fetch();
|
|
$this->getStockService()->AddProduct($recipeRow->product_id, floatval($recipeRow->desired_servings), null, StockService::TRANSACTION_TYPE_SELF_PRODUCTION, date('Y-m-d'), floatval($recipeResolvedRow->costs), null, null, $dummyTransactionId, 0, true);
|
|
}
|
|
}
|
|
|
|
public function GetRecipesPosResolved()
|
|
{
|
|
$sql = 'SELECT * FROM recipes_pos_resolved';
|
|
return $this->getDataBaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
|
}
|
|
|
|
public function GetRecipesResolved($customWhere = null): Result
|
|
{
|
|
if ($customWhere == null)
|
|
{
|
|
return $this->getDatabase()->recipes_resolved();
|
|
}
|
|
else
|
|
{
|
|
return $this->getDatabase()->recipes_resolved()->where($customWhere);
|
|
}
|
|
}
|
|
|
|
// The same as GetRecipesResolved but without the column "missing_products_count" to improve performance when this is not needed
|
|
public function GetRecipesResolved2($customWhere = null): Result
|
|
{
|
|
if ($customWhere == null)
|
|
{
|
|
return $this->getDatabase()->recipes_resolved2();
|
|
}
|
|
else
|
|
{
|
|
return $this->getDatabase()->recipes_resolved2()->where($customWhere);
|
|
}
|
|
}
|
|
|
|
public function CopyRecipe($recipeId)
|
|
{
|
|
if (!$this->RecipeExists($recipeId))
|
|
{
|
|
throw new \Exception('Recipe does not exist');
|
|
}
|
|
|
|
$newName = $this->getLocalizationService()->__t('Copy of %s', $this->getDataBase()->recipes($recipeId)->name);
|
|
|
|
$this->getDatabaseService()->ExecuteDbStatement('INSERT INTO recipes (name, description, picture_file_name, base_servings, desired_servings, not_check_shoppinglist, type, product_id) SELECT \'' . $newName . '\', description, picture_file_name, base_servings, desired_servings, not_check_shoppinglist, type, product_id FROM recipes WHERE id = ' . $recipeId);
|
|
$lastInsertId = $this->getDatabase()->lastInsertId();
|
|
$this->getDatabaseService()->ExecuteDbStatement('INSERT INTO recipes_pos (recipe_id, product_id, amount, note, qu_id, only_check_single_unit_in_stock, ingredient_group, not_check_stock_fulfillment, variable_amount, price_factor) SELECT ' . $lastInsertId . ', product_id, amount, note, qu_id, only_check_single_unit_in_stock, ingredient_group, not_check_stock_fulfillment, variable_amount, price_factor FROM recipes_pos WHERE recipe_id = ' . $recipeId);
|
|
$this->getDatabaseService()->ExecuteDbStatement('INSERT INTO recipes_nestings (recipe_id, includes_recipe_id, servings) SELECT ' . $lastInsertId . ', includes_recipe_id, servings FROM recipes_nestings WHERE recipe_id = ' . $recipeId);
|
|
|
|
return $lastInsertId;
|
|
}
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
}
|
|
|
|
private function RecipeExists($recipeId)
|
|
{
|
|
$recipeRow = $this->getDataBase()->recipes()->where('id = :1', $recipeId)->fetch();
|
|
return $recipeRow !== null;
|
|
}
|
|
}
|