diff --git a/controllers/StockApiController.php b/controllers/StockApiController.php index 8e54aae2..24d6a84d 100644 --- a/controllers/StockApiController.php +++ b/controllers/StockApiController.php @@ -263,7 +263,15 @@ class StockApiController extends BaseApiController $recipeId = $requestBody['recipe_id']; } - $bookingId = $this->getStockService()->ConsumeProduct($args['productId'], $requestBody['amount'], $spoiled, $transactionType, $specificStockEntryId, $recipeId, $locationId); + $consumeExact = false; + + if (array_key_exists('exact_amount', $requestBody)) + { + $consumeExact = $requestBody['exact_amount']; + } + $transactionId = null; + + $bookingId = $this->getStockService()->ConsumeProduct($args['productId'], $requestBody['amount'], $spoiled, $transactionType, $specificStockEntryId, $recipeId, $locationId, $transactionId, false, $consumeExact); return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId)); } catch (\Exception $ex) diff --git a/public/viewjs/consume.js b/public/viewjs/consume.js index e007dc55..69e772be 100644 --- a/public/viewjs/consume.js +++ b/public/viewjs/consume.js @@ -9,6 +9,7 @@ var jsonData = {}; jsonData.amount = jsonForm.amount; + jsonData.exact_amount = (jsonForm.exact_amount == "on"); jsonData.spoiled = $('#spoiled').is(':checked'); if ($("#use_specific_stock_entry").is(":checked")) @@ -70,7 +71,7 @@ $("#use_specific_stock_entry").click(); } - if (productDetails.product.enable_tare_weight_handling == 1) + if (productDetails.product.enable_tare_weight_handling == 1 && !jsonData.exact_amount) { var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount - (parseFloat(productDetails.product.tare_weight) + parseFloat(productDetails.stock_amount))) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name) + '
' + __t("Undo") + ''; } @@ -177,11 +178,11 @@ $('#save-mark-as-open-button').on('click', function(e) } ); }); - +var sumValue = 0; $("#location_id").on('change', function(e) { var locationId = $(e.target).val(); - var sumValue = 0; + sumValue = 0; var stockId = null; $("#specific_stock_entry").find("option").remove().end().append(""); @@ -228,37 +229,8 @@ $("#location_id").on('change', function(e) Grocy.Api.Get('stock/products/' + Grocy.Components.ProductPicker.GetValue(), function(productDetails) { - if (productDetails.product.enable_tare_weight_handling == 1) - { - $("#amount").attr("min", productDetails.product.tare_weight); - $('#amount').attr('max', sumValue + parseFloat(productDetails.product.tare_weight)); - $("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', parseFloat(productDetails.product.tare_weight).toLocaleString(), (parseFloat(productDetails.stock_amount) + parseFloat(productDetails.product.tare_weight)).toLocaleString())); - $("#tare-weight-handling-info").removeClass("d-none"); - } - else - { - $("#tare-weight-handling-info").addClass("d-none"); - - if (productDetails.product.allow_partial_units_in_stock == 1) - { - $("#amount").attr("min", "0.01"); - $("#amount").attr("step", "0.01"); - $("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', 0.01.toLocaleString(), parseFloat(productDetails.stock_amount).toLocaleString())); - } - else - { - $("#amount").attr("min", "1"); - $("#amount").attr("step", "1"); - $("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', "1", parseFloat(productDetails.stock_amount).toLocaleString())); - } - - $('#amount').attr('max', sumValue); - - if (sumValue == 0) - { - $("#amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location')); - } - } + current_productDetails = productDetails; + RefreshForm(); }, function(xhr) { @@ -447,7 +419,7 @@ $("#specific_stock_entry").on("change", function(e) { if ($(e.target).val() == "") { - var sumValue = 0; + sumValue = 0; Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries', function(stockEntries) { @@ -572,3 +544,49 @@ $("#scan-mode-button").on("click", function(e) $("#scan-mode-status").text(__t("off")); } }); + +$('#consume-exact-amount').on('change', RefreshForm); +var current_productDetails; +function RefreshForm() +{ + var productDetails = current_productDetails; + if (productDetails.product.enable_tare_weight_handling == 1) + { + $("#consume-exact-amount").parent().removeClass("d-none"); + } + else + { + $("#consume-exact-amount").parent().addClass("d-none"); + } + if (productDetails.product.enable_tare_weight_handling == 1 && !$('#consume-exact-amount').is(':checked')) + { + $("#amount").attr("min", productDetails.product.tare_weight); + $('#amount').attr('max', sumValue + parseFloat(productDetails.product.tare_weight)); + $("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', parseFloat(productDetails.product.tare_weight).toLocaleString(), (parseFloat(productDetails.stock_amount) + parseFloat(productDetails.product.tare_weight)).toLocaleString())); + $("#tare-weight-handling-info").removeClass("d-none"); + } + else + { + $("#tare-weight-handling-info").addClass("d-none"); + + if (productDetails.product.allow_partial_units_in_stock == 1) + { + $("#amount").attr("min", "0.01"); + $("#amount").attr("step", "0.01"); + $("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', 0.01.toLocaleString(), parseFloat(productDetails.stock_amount).toLocaleString())); + } + else + { + $("#amount").attr("min", "1"); + $("#amount").attr("step", "1"); + $("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', "1", parseFloat(productDetails.stock_amount).toLocaleString())); + } + + $('#amount').attr('max', sumValue); + + if (sumValue == 0) + { + $("#amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location')); + } + } +} diff --git a/services/RecipesService.php b/services/RecipesService.php index 697ecde9..5e5e53bb 100644 --- a/services/RecipesService.php +++ b/services/RecipesService.php @@ -58,7 +58,7 @@ class RecipesService extends BaseService { 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); + $this->getStockService()->ConsumeProduct($recipePosition->product_id, $recipePosition->recipe_amount, false, StockService::TRANSACTION_TYPE_CONSUME, 'default', $recipeId, null, $transactionId, true, true); } } diff --git a/services/StockService.php b/services/StockService.php index 5c660fdf..210a0c2a 100644 --- a/services/StockService.php +++ b/services/StockService.php @@ -210,7 +210,7 @@ class StockService extends BaseService $this->getDatabase()->shopping_list()->where('shopping_list_id = :1', $listId)->delete(); } - public function ConsumeProduct(int $productId, float $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default', $recipeId = null, $locationId = null, &$transactionId = null, $allowSubproductSubstitution = false) + public function ConsumeProduct(int $productId, float $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default', $recipeId = null, $locationId = null, &$transactionId = null, $allowSubproductSubstitution = false, $consumeExactAmount = false) { if (!$this->ProductExists($productId)) { @@ -230,6 +230,10 @@ class StockService extends BaseService if ($productDetails->product->enable_tare_weight_handling == 1) { + if($consumeExactAmount) + { + $amount = floatval($productDetails->stock_amount) + floatval($productDetails->product->tare_weight) - $amount; + } if ($amount < floatval($productDetails->product->tare_weight)) { throw new \Exception('The amount cannot be lower than the defined tare weight'); diff --git a/views/consume.blade.php b/views/consume.blade.php index 4009369c..82bb1c8b 100644 --- a/views/consume.blade.php +++ b/views/consume.blade.php @@ -43,7 +43,10 @@ 'nextInputSelector' => '#amount', 'disallowAddProductWorkflows' => true )) - + @include('components.numberpicker', array( 'id' => 'amount', 'label' => 'Amount',