mirror of
https://github.com/grocy/grocy.git
synced 2026-04-07 13:26:14 +02:00
Fixes #761 and #762: Add "Remove exact amount" for products with tare weight handling and use it for recipe-consumption.
This commit is contained in:
parent
a7e7e6d407
commit
165abdeccb
|
|
@ -263,7 +263,15 @@ class StockApiController extends BaseApiController
|
||||||
$recipeId = $requestBody['recipe_id'];
|
$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));
|
return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId));
|
||||||
}
|
}
|
||||||
catch (\Exception $ex)
|
catch (\Exception $ex)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
var jsonData = {};
|
var jsonData = {};
|
||||||
jsonData.amount = jsonForm.amount;
|
jsonData.amount = jsonForm.amount;
|
||||||
|
jsonData.exact_amount = (jsonForm.exact_amount == "on");
|
||||||
jsonData.spoiled = $('#spoiled').is(':checked');
|
jsonData.spoiled = $('#spoiled').is(':checked');
|
||||||
|
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked"))
|
||||||
|
|
@ -70,7 +71,7 @@
|
||||||
$("#use_specific_stock_entry").click();
|
$("#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) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse.transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
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) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse.transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
||||||
}
|
}
|
||||||
|
|
@ -177,11 +178,11 @@ $('#save-mark-as-open-button').on('click', function(e)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
var sumValue = 0;
|
||||||
$("#location_id").on('change', function(e)
|
$("#location_id").on('change', function(e)
|
||||||
{
|
{
|
||||||
var locationId = $(e.target).val();
|
var locationId = $(e.target).val();
|
||||||
var sumValue = 0;
|
sumValue = 0;
|
||||||
var stockId = null;
|
var stockId = null;
|
||||||
|
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
|
|
@ -228,37 +229,8 @@ $("#location_id").on('change', function(e)
|
||||||
Grocy.Api.Get('stock/products/' + Grocy.Components.ProductPicker.GetValue(),
|
Grocy.Api.Get('stock/products/' + Grocy.Components.ProductPicker.GetValue(),
|
||||||
function(productDetails)
|
function(productDetails)
|
||||||
{
|
{
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
current_productDetails = productDetails;
|
||||||
{
|
RefreshForm();
|
||||||
$("#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'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
|
|
@ -447,7 +419,7 @@ $("#specific_stock_entry").on("change", function(e)
|
||||||
{
|
{
|
||||||
if ($(e.target).val() == "")
|
if ($(e.target).val() == "")
|
||||||
{
|
{
|
||||||
var sumValue = 0;
|
sumValue = 0;
|
||||||
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries',
|
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries',
|
||||||
function(stockEntries)
|
function(stockEntries)
|
||||||
{
|
{
|
||||||
|
|
@ -572,3 +544,49 @@ $("#scan-mode-button").on("click", function(e)
|
||||||
$("#scan-mode-status").text(__t("off"));
|
$("#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'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ class RecipesService extends BaseService
|
||||||
{
|
{
|
||||||
if ($recipePosition->only_check_single_unit_in_stock == 0)
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,7 @@ class StockService extends BaseService
|
||||||
$this->getDatabase()->shopping_list()->where('shopping_list_id = :1', $listId)->delete();
|
$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))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
|
|
@ -230,6 +230,10 @@ class StockService extends BaseService
|
||||||
|
|
||||||
if ($productDetails->product->enable_tare_weight_handling == 1)
|
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))
|
if ($amount < floatval($productDetails->product->tare_weight))
|
||||||
{
|
{
|
||||||
throw new \Exception('The amount cannot be lower than the defined tare weight');
|
throw new \Exception('The amount cannot be lower than the defined tare weight');
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,10 @@
|
||||||
'nextInputSelector' => '#amount',
|
'nextInputSelector' => '#amount',
|
||||||
'disallowAddProductWorkflows' => true
|
'disallowAddProductWorkflows' => true
|
||||||
))
|
))
|
||||||
|
<label for="consume-exact-amount" class="d-none">
|
||||||
|
<input type="checkbox" id="consume-exact-amount" name="exact_amount">
|
||||||
|
{{ $__t('Consume exact amount') }}
|
||||||
|
</label>
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', array(
|
||||||
'id' => 'amount',
|
'id' => 'amount',
|
||||||
'label' => 'Amount',
|
'label' => 'Amount',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user