diff --git a/controllers/BaseController.php b/controllers/BaseController.php index 806235e8..b05adf14 100644 --- a/controllers/BaseController.php +++ b/controllers/BaseController.php @@ -49,6 +49,16 @@ class BaseController } $container->view->set('embedded', $embedded); + $constants = get_defined_constants(); + foreach ($constants as $constant => $value) + { + if (substr($constant, 0, 19) !== 'GROCY_FEATURE_FLAG_') + { + unset($constants[$constant]); + } + } + $container->view->set('featureFlags', $constants); + try { $usersService = new UsersService(); diff --git a/controllers/StockApiController.php b/controllers/StockApiController.php index 6205a49d..5f8ff54d 100644 --- a/controllers/StockApiController.php +++ b/controllers/StockApiController.php @@ -121,7 +121,13 @@ class StockApiController extends BaseApiController $specificStockEntryId = $requestBody['stock_entry_id']; } - $bookingId = $this->StockService->ConsumeProduct($args['productId'], $requestBody['amount'], $spoiled, $transactionType, $specificStockEntryId); + $recipeId = null; + if (array_key_exists('recipe_id', $requestBody) && is_numeric($requestBody['recipe_id'])) + { + $recipeId = $requestBody['recipe_id']; + } + + $bookingId = $this->StockService->ConsumeProduct($args['productId'], $requestBody['amount'], $spoiled, $transactionType, $specificStockEntryId, $recipeId); return $this->ApiResponse(array('booking_id' => $bookingId)); } catch (\Exception $ex) diff --git a/controllers/StockController.php b/controllers/StockController.php index 7c283320..3224fe07 100644 --- a/controllers/StockController.php +++ b/controllers/StockController.php @@ -40,7 +40,8 @@ class StockController extends BaseController public function Consume(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) { return $this->AppContainer->view->render($response, 'consume', [ - 'products' => $this->Database->products()->orderBy('name') + 'products' => $this->Database->products()->orderBy('name'), + 'recipes' => $this->Database->recipes()->orderBy('name') ]); } diff --git a/grocy.openapi.json b/grocy.openapi.json index 0bf9faea..75e2a2d9 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -1115,6 +1115,11 @@ "stock_entry_id": { "type": "string", "description": "A specific stock entry id to consume, if used, the amount has to be 1" + }, + "recipe_id": { + "type": "number", + "format": "integer", + "description": "A valid recipe id for which this product was used (for statistical purposes only)" } }, "example": { diff --git a/localization/en/strings.php b/localization/en/strings.php index de9b0f72..a751f9c6 100644 --- a/localization/en/strings.php +++ b/localization/en/strings.php @@ -333,5 +333,7 @@ return array( 'Do not check against the shopping list when adding missing items to it' => 'Do not check against the shopping list when adding missing items to it', 'By default the amount to be added to the shopping list is "needed amount - stock amount - shopping list amount" - when this is enabled, it is only checked against the stock amount, not against what is already on the shopping list' => 'By default the amount to be added to the shopping list is "needed amount - stock amount - shopping list amount" - when this is enabled, it is only checked against the stock amount, not against what is already on the shopping list', 'Picture' => 'Picture', - 'Uncheck ingredients to not put them on the shopping list' => 'Uncheck ingredients to not put them on the shopping list' + 'Uncheck ingredients to not put them on the shopping list' => 'Uncheck ingredients to not put them on the shopping list', + 'This is for statistical purposes only' => 'This is for statistical purposes only', + 'You have to select a recipe' => 'You have to select a recipe' ); diff --git a/migrations/0055.sql b/migrations/0055.sql new file mode 100644 index 00000000..da5bf8c7 --- /dev/null +++ b/migrations/0055.sql @@ -0,0 +1,2 @@ +ALTER TABLE stock_log +ADD recipe_id INTEGER; diff --git a/public/viewjs/components/recipepicker.js b/public/viewjs/components/recipepicker.js new file mode 100644 index 00000000..296bf0ee --- /dev/null +++ b/public/viewjs/components/recipepicker.js @@ -0,0 +1,55 @@ +Grocy.Components.RecipePicker = { }; + +Grocy.Components.RecipePicker.GetPicker = function() +{ + return $('#recipe_id'); +} + +Grocy.Components.RecipePicker.GetInputElement = function() +{ + return $('#recipe_id_text_input'); +} + +Grocy.Components.RecipePicker.GetValue = function() +{ + return $('#recipe_id').val(); +} + +Grocy.Components.RecipePicker.SetValue = function(value) +{ + Grocy.Components.RecipePicker.GetInputElement().val(value); + Grocy.Components.RecipePicker.GetInputElement().trigger('change'); +} + +$('.recipe-combobox').combobox({ + appendId: '_text_input', + bsVersion: '4', + clearIfNoMatch: true +}); + +var prefillByName = Grocy.Components.RecipePicker.GetPicker().parent().data('prefill-by-name').toString(); +if (typeof prefillByName !== "undefined") +{ + possibleOptionElement = $("#recipe_id option:contains('" + prefillByName + "')").first(); + + if (possibleOptionElement.length > 0) + { + $('#recipe_id').val(possibleOptionElement.val()); + $('#recipe_id').data('combobox').refresh(); + $('#recipe_id').trigger('change'); + + var nextInputElement = $(Grocy.Components.RecipePicker.GetPicker().parent().data('next-input-selector').toString()); + nextInputElement.focus(); + } +} + +var prefillById = Grocy.Components.RecipePicker.GetPicker().parent().data('prefill-by-id').toString(); +if (typeof prefillById !== "undefined") +{ + $('#recipe_id').val(prefillById); + $('#recipe_id').data('combobox').refresh(); + $('#recipe_id').trigger('change'); + + var nextInputElement = $(Grocy.Components.RecipePicker.GetPicker().parent().data('next-input-selector').toString()); + nextInputElement.focus(); +} diff --git a/public/viewjs/consume.js b/public/viewjs/consume.js index ecfaee0a..4491dcd8 100644 --- a/public/viewjs/consume.js +++ b/public/viewjs/consume.js @@ -21,6 +21,11 @@ jsonData.stock_entry_id = jsonForm.specific_stock_entry; } + if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_RECIPES && Grocy.Components.RecipePicker.GetValue().toString().length > 0) + { + jsonData.recipe_id = Grocy.Components.RecipePicker.GetValue(); + } + Grocy.Api.Get('stock/products/' + jsonForm.product_id, function(productDetails) { @@ -38,6 +43,10 @@ $('#amount').val(1); Grocy.Components.ProductPicker.SetValue(''); + if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_RECIPES) + { + Grocy.Components.RecipePicker.SetValue(''); + } Grocy.Components.ProductPicker.GetInputElement().focus(); Grocy.FrontendHelpers.ValidateForm('consume-form'); }, diff --git a/services/RecipesService.php b/services/RecipesService.php index cfebf8b8..647d1128 100644 --- a/services/RecipesService.php +++ b/services/RecipesService.php @@ -68,7 +68,7 @@ class RecipesService extends BaseService { if ($recipePosition->only_check_single_unit_in_stock == 0) { - $this->StockService->ConsumeProduct($recipePosition->product_id, $recipePosition->amount, false, StockService::TRANSACTION_TYPE_CONSUME); + $this->StockService->ConsumeProduct($recipePosition->product_id, $recipePosition->amount, false, StockService::TRANSACTION_TYPE_CONSUME, 'default', $recipeId); } } } diff --git a/services/StockService.php b/services/StockService.php index 923172d3..7965d6c1 100644 --- a/services/StockService.php +++ b/services/StockService.php @@ -165,7 +165,7 @@ class StockService extends BaseService } } - public function ConsumeProduct(int $productId, float $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default') + public function ConsumeProduct(int $productId, float $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default', $recipeId = null) { if (!$this->ProductExists($productId)) { @@ -206,7 +206,8 @@ class StockService extends BaseService 'stock_id' => $stockEntry->stock_id, 'transaction_type' => $transactionType, 'price' => $stockEntry->price, - 'opened_date' => $stockEntry->opened_date + 'opened_date' => $stockEntry->opened_date, + 'recipe_id' => $recipeId )); $logRow->save(); @@ -228,7 +229,8 @@ class StockService extends BaseService 'stock_id' => $stockEntry->stock_id, 'transaction_type' => $transactionType, 'price' => $stockEntry->price, - 'opened_date' => $stockEntry->opened_date + 'opened_date' => $stockEntry->opened_date, + 'recipe_id' => $recipeId )); $logRow->save(); diff --git a/views/components/recipepicker.blade.php b/views/components/recipepicker.blade.php new file mode 100644 index 00000000..b1f09e69 --- /dev/null +++ b/views/components/recipepicker.blade.php @@ -0,0 +1,19 @@ +@push('componentScripts') + +@endpush + +@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp +@php if(empty($prefillById)) { $prefillById = ''; } @endphp +@php if(!isset($isRequired)) { $isRequired = true; } @endphp +@php if(empty($hint)) { $hint = ''; } @endphp + +
+ + +
{{ $L('You have to select a recipe') }}
+
diff --git a/views/consume.blade.php b/views/consume.blade.php index f6521491..9b2cb522 100644 --- a/views/consume.blade.php +++ b/views/consume.blade.php @@ -42,6 +42,14 @@ + @if (GROCY_FEATURE_FLAG_RECIPES) + @include('components.recipepicker', array( + 'recipes' => $recipes, + 'isRequired' => false, + 'hint' => $L('This is for statistical purposes only') + )) + @endif + diff --git a/views/layout/default.blade.php b/views/layout/default.blade.php index 3b081dff..11c52822 100644 --- a/views/layout/default.blade.php +++ b/views/layout/default.blade.php @@ -54,6 +54,7 @@ Grocy.Culture = '{{ GROCY_CULTURE }}'; Grocy.Currency = '{{ GROCY_CURRENCY }}'; Grocy.UserSettings = {!! json_encode($userSettings) !!}; + Grocy.FeatureFlags = {!! json_encode($featureFlags) !!};