diff --git a/controllers/RecipesApiController.php b/controllers/RecipesApiController.php
index a9c12635..5cfa1ce2 100644
--- a/controllers/RecipesApiController.php
+++ b/controllers/RecipesApiController.php
@@ -16,7 +16,15 @@ class RecipesApiController extends BaseApiController
public function AddNotFulfilledProductsToShoppingList(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
{
- $this->RecipesService->AddNotFulfilledProductsToShoppingList($args['recipeId']);
+ $requestBody = $request->getParsedBody();
+ $excludedProductIds = null;
+
+ if ($requestBody !== null && array_key_exists('excludedProductIds', $requestBody))
+ {
+ $excludedProductIds = $requestBody['excludedProductIds'];
+ }
+
+ $this->RecipesService->AddNotFulfilledProductsToShoppingList($args['recipeId'], $excludedProductIds);
return $this->EmptyApiResponse($response);
}
diff --git a/controllers/RecipesController.php b/controllers/RecipesController.php
index 54e0987a..b9cebc0e 100644
--- a/controllers/RecipesController.php
+++ b/controllers/RecipesController.php
@@ -50,6 +50,13 @@ class RecipesController extends BaseController
$selectedSubRecipePosition->amount = $selectedSubRecipePosition->amount * ($selectedRecipe->desired_servings / $selectedRecipe->base_servings);
}
+ $includedRecipeIdsAbsolute = array();
+ $includedRecipeIdsAbsolute[] = $selectedRecipe->id;
+ foreach($selectedRecipeSubRecipes as $subRecipe)
+ {
+ $includedRecipeIdsAbsolute[] = $subRecipe->id;
+ }
+
return $this->AppContainer->view->render($response, 'recipes', [
'recipes' => $recipes,
'recipesFulfillment' => $this->RecipesService->GetRecipesFulfillment(),
@@ -59,7 +66,8 @@ class RecipesController extends BaseController
'products' => $this->Database->products(),
'quantityunits' => $this->Database->quantity_units(),
'selectedRecipeSubRecipes' => $selectedRecipeSubRecipes,
- 'selectedRecipeSubRecipesPositions' => $selectedRecipeSubRecipesPositions
+ 'selectedRecipeSubRecipesPositions' => $selectedRecipeSubRecipesPositions,
+ 'includedRecipeIdsAbsolute' => $includedRecipeIdsAbsolute
]);
}
diff --git a/grocy.openapi.json b/grocy.openapi.json
index 0ca90fc3..0bf9faea 100644
--- a/grocy.openapi.json
+++ b/grocy.openapi.json
@@ -1404,6 +1404,26 @@
}
}
],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "excludedProductIds": {
+ "type": "array",
+ "items":{
+ "type": "number",
+ "format": "integer"
+ },
+ "description": "An optional array of product ids to exclude them from being put on the shopping list"
+ }
+ }
+ }
+ }
+ }
+ },
"responses": {
"204": {
"description": "The operation was successful"
diff --git a/public/viewjs/recipes.js b/public/viewjs/recipes.js
index 3370db15..0b3b0a9a 100644
--- a/public/viewjs/recipes.js
+++ b/public/viewjs/recipes.js
@@ -84,7 +84,7 @@ $(document).on('click', '.recipe-order-missing-button', function(e)
var objectId = $(e.currentTarget).attr('data-recipe-id');
bootbox.confirm({
- message: L('Are you sure to put all missing ingredients for recipe "#1" on the shopping list?', objectName),
+ message: L('Are you sure to put all missing ingredients for recipe "#1" on the shopping list?', objectName) + "
" + L("Uncheck ingredients to not put them on the shopping list.") + $("#missing-recipe-pos-list")[0].outerHTML.replace("d-none", ""),
buttons: {
confirm: {
label: L('Yes'),
@@ -101,7 +101,13 @@ $(document).on('click', '.recipe-order-missing-button', function(e)
{
Grocy.FrontendHelpers.BeginUiBusy();
- Grocy.Api.Post('recipes/' + objectId + '/add-not-fulfilled-products-to-shoppinglist', { },
+ var excludedProductIds = new Array();
+ $(".missing-recipe-pos-product-checkbox:checkbox:not(:checked)").each(function()
+ {
+ excludedProductIds.push($(this).data("product-id"));
+ });
+
+ Grocy.Api.Post('recipes/' + objectId + '/add-not-fulfilled-products-to-shoppinglist', { "excludedProductIds": excludedProductIds },
function(result)
{
window.location.href = U('/recipes');
@@ -195,6 +201,16 @@ $('#servings-scale').keyup(function(event)
);
});
+$(document).on("click", ".missing-recipe-pos-select-button", function(e)
+{
+ e.preventDefault();
+
+ var checkbox = $(this).find(".form-check-input");
+ checkbox.prop("checked", !checkbox.prop("checked"));
+
+ $(this).toggleClass("list-group-item-primary");
+});
+
if (window.location.hash === "#fullscreen")
{
$("#selectedRecipeToggleFullscreenButton").click();
diff --git a/services/RecipesService.php b/services/RecipesService.php
index 1f31154a..a371b1bd 100644
--- a/services/RecipesService.php
+++ b/services/RecipesService.php
@@ -26,14 +26,14 @@ class RecipesService extends BaseService
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
}
- public function AddNotFulfilledProductsToShoppingList($recipeId)
+ public function AddNotFulfilledProductsToShoppingList($recipeId, $excludedProductIds = null)
{
$recipe = $this->Database->recipes($recipeId);
$recipePositions = $this->GetRecipesFulfillment();
foreach ($recipePositions as $recipePosition)
{
- if($recipePosition->recipe_id == $recipeId)
+ if($recipePosition->recipe_id == $recipeId && !in_array($recipePosition->product_id, $excludedProductIds))
{
$product = $this->Database->products($recipePosition->product_id);
diff --git a/views/recipes.blade.php b/views/recipes.blade.php
index 5ef5f650..a897d56f 100644
--- a/views/recipes.blade.php
+++ b/views/recipes.blade.php
@@ -162,4 +162,17 @@
@endif
+
+