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 + +
+ @foreach($recipesFulfillment as $recipePos) + @if(in_array($recipePos->recipe_id, $includedRecipeIdsAbsolute)) + +
+ +
+ {{ FindObjectInArrayByPropertyValue($products, 'id', $recipePos->product_id)->name }} +
+ @endif + @endforeach +
@stop