2018-07-14 18:23:41 +02:00
< ? php
namespace Grocy\Services ;
2020-09-01 19:59:40 +02:00
use LessQL\Result ;
2018-07-14 18:23:41 +02:00
class RecipesService extends BaseService
{
2021-07-10 12:32:29 +02:00
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
2018-07-14 22:49:42 +02:00
2019-03-03 14:49:46 +01:00
public function AddNotFulfilledProductsToShoppingList ( $recipeId , $excludedProductIds = null )
2018-07-14 22:49:42 +02:00
{
2020-03-01 23:47:47 +07:00
$recipe = $this -> getDataBase () -> recipes ( $recipeId );
2019-03-05 23:45:04 +01:00
$recipePositions = $this -> GetRecipesPosResolved ();
2020-08-31 20:40:31 +02:00
2021-07-10 19:56:35 +02:00
if ( $excludedProductIds == null )
{
$excludedProductIds = [];
}
2018-07-14 22:49:42 +02:00
foreach ( $recipePositions as $recipePosition )
{
2020-08-31 20:40:31 +02:00
if ( $recipePosition -> recipe_id == $recipeId && ! in_array ( $recipePosition -> product_id , $excludedProductIds ))
2018-07-14 22:49:42 +02:00
{
2020-03-01 23:47:47 +07:00
$product = $this -> getDataBase () -> products ( $recipePosition -> product_id );
2020-11-13 17:30:57 +01:00
$toOrderAmount = round (( $recipePosition -> missing_amount - $recipePosition -> amount_on_shopping_list ), 2 );
2020-08-31 20:40:31 +02:00
2019-03-03 15:23:39 +01:00
if ( $recipe -> not_check_shoppinglist == 1 )
{
2020-11-13 17:30:57 +01:00
$toOrderAmount = round ( $recipePosition -> missing_amount , 2 );
2019-03-03 15:23:39 +01:00
}
2020-03-01 23:47:47 +07:00
2022-01-23 13:56:41 +01:00
// When the recipe ingredient option "Only check if any amount is in stock" is enabled,
// any QU can be used and the amount is not based on qu_stock then
// => Do the unit conversion here (if any)
if ( $recipePosition -> only_check_single_unit_in_stock == 1 )
{
$conversion = $this -> getDatabase () -> quantity_unit_conversions_resolved () -> where ( 'product_id = :1 AND from_qu_id = :2 AND to_qu_id = :3' , $recipePosition -> product_id , $recipePosition -> qu_id , $product -> qu_id_stock ) -> fetch ();
if ( $conversion != null )
{
2023-02-06 20:22:10 +01:00
$toOrderAmount = $toOrderAmount * $conversion -> factor ;
2022-01-23 13:56:41 +01:00
}
}
2020-08-31 20:40:31 +02:00
if ( $toOrderAmount > 0 )
2018-07-14 22:49:42 +02:00
{
2021-07-06 20:19:50 +02:00
$note = $this -> getLocalizationService () -> __t ( 'Added for recipe %s' , $recipe -> name );
if ( ! empty ( $recipePosition -> note ))
{
$note .= " \n " . $recipePosition -> note ;
}
2020-08-31 20:40:31 +02:00
$shoppinglistRow = $this -> getDataBase () -> shopping_list () -> createRow ([
2018-07-14 22:49:42 +02:00
'product_id' => $recipePosition -> product_id ,
'amount' => $toOrderAmount ,
2021-07-06 20:19:50 +02:00
'note' => $note
2020-08-31 20:40:31 +02:00
]);
2018-07-14 22:49:42 +02:00
$shoppinglistRow -> save ();
}
}
}
}
2018-08-11 11:48:25 +02:00
public function ConsumeRecipe ( $recipeId )
{
if ( ! $this -> RecipeExists ( $recipeId ))
{
throw new \Exception ( 'Recipe does not exist' );
}
2022-02-12 22:08:10 +01:00
$recipeResolved = $this -> getDatabase () -> recipes_resolved () -> where ( 'recipe_id' , $recipeId ) -> fetch ();
if ( $recipeResolved -> need_fulfilled == 0 )
{
throw new \Exception ( 'Recipe need is not fulfilled, consuming not possible' );
}
2020-01-27 22:14:11 +01:00
$transactionId = uniqid ();
2021-07-16 17:32:08 +02:00
$recipePositions = $this -> getDatabase () -> recipes_pos_resolved () -> where ( 'recipe_id' , $recipeId ) -> fetchAll ();
2022-08-27 00:08:23 +02:00
$this -> getDatabaseService () -> GetDbConnectionRaw () -> beginTransaction ();
try
2018-08-11 11:48:25 +02:00
{
2022-08-27 00:08:23 +02:00
foreach ( $recipePositions as $recipePosition )
2018-08-11 11:48:25 +02:00
{
2022-08-27 00:08:23 +02:00
if ( $recipePosition -> only_check_single_unit_in_stock == 0 )
{
2022-08-27 14:25:55 +02:00
$this -> getStockService () -> ConsumeProduct ( $recipePosition -> product_id , $recipePosition -> recipe_amount , false , StockService :: TRANSACTION_TYPE_CONSUME , 'default' , $recipeId , null , $transactionId , true , true );
2022-08-27 00:08:23 +02:00
}
2018-08-11 11:48:25 +02:00
}
}
2023-03-12 22:45:04 +01:00
catch ( \Exception $ex )
2022-08-27 00:08:23 +02:00
{
$this -> getDatabaseService () -> GetDbConnectionRaw () -> rollback ();
throw $ex ;
}
$this -> getDatabaseService () -> GetDbConnectionRaw () -> commit ();
2020-01-21 20:45:34 +01:00
2023-03-12 16:35:18 +01:00
$recipe = $this -> getDatabase () -> recipes () -> where ( 'id = :1' , $recipeId ) -> fetch ();
$productId = $recipe -> product_id ;
2023-03-12 22:45:04 +01:00
$amount = $recipe -> desired_servings ;
2023-03-12 16:35:18 +01:00
if ( $recipe -> type == self :: RECIPE_TYPE_MEALPLAN_SHADOW )
2020-01-21 20:45:34 +01:00
{
2023-03-12 16:35:18 +01:00
// Use "Produces product" of the original recipe
$mealPlanEntry = $this -> getDatabase () -> meal_plan () -> where ( 'id = :1' , explode ( '#' , $recipe -> name )[ 1 ]) -> fetch ();
2023-03-12 22:45:04 +01:00
$recipe = $this -> getDatabase () -> recipes () -> where ( 'id = :1' , $mealPlanEntry -> recipe_id ) -> fetch ();
$productId = $recipe -> product_id ;
$amount = $mealPlanEntry -> recipe_servings ;
2023-03-12 16:35:18 +01:00
}
if ( ! empty ( $productId ))
{
$product = $this -> getDatabase () -> products () -> where ( 'id = :1' , $productId ) -> fetch ();
2020-03-01 23:47:47 +07:00
$recipeResolvedRow = $this -> getDatabase () -> recipes_resolved () -> where ( 'recipe_id = :1' , $recipeId ) -> fetch ();
2023-03-12 22:45:04 +01:00
$this -> getStockService () -> AddProduct ( $productId , $amount , null , StockService :: TRANSACTION_TYPE_SELF_PRODUCTION , date ( 'Y-m-d' ), $recipeResolvedRow -> costs_per_serving , null , null , $dummyTransactionId , $product -> default_stock_label_type , true );
2020-01-21 20:45:34 +01:00
}
2020-08-31 20:40:31 +02:00
}
public function GetRecipesPosResolved ()
{
$sql = 'SELECT * FROM recipes_pos_resolved' ;
return $this -> getDataBaseService () -> ExecuteDbQuery ( $sql ) -> fetchAll ( \PDO :: FETCH_OBJ );
}
2021-07-10 22:56:39 +02:00
public function GetRecipesResolved ( $customWhere = null ) : Result
2020-08-31 20:40:31 +02:00
{
2021-07-10 22:56:39 +02:00
if ( $customWhere == null )
{
return $this -> getDatabase () -> recipes_resolved ();
}
else
{
return $this -> getDatabase () -> recipes_resolved () -> where ( $customWhere );
}
}
2021-07-13 19:29:23 +02:00
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 ;
}
2018-08-11 11:48:25 +02:00
private function RecipeExists ( $recipeId )
{
2020-03-01 23:47:47 +07:00
$recipeRow = $this -> getDataBase () -> recipes () -> where ( 'id = :1' , $recipeId ) -> fetch ();
2018-08-11 11:48:25 +02:00
return $recipeRow !== null ;
}
2018-07-14 18:23:41 +02:00
}