mirror of
https://github.com/grocy/grocy.git
synced 2026-10-17 13:19:19 +02:00
Compare commits
No commits in common. "master" and "v4.7.1" have entirely different histories.
|
|
@ -1,57 +0,0 @@
|
||||||
> ⚠️ xxxBREAKING CHANGESxxx
|
|
||||||
|
|
||||||
> ❗ xxxImportant upgrade informationXXX
|
|
||||||
|
|
||||||
> 💡 xxxMinor upgrade informationXXX
|
|
||||||
|
|
||||||
### New Feature: xxxx
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Stock
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Shopping list
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Recipes
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Meal plan
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Chores
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Calendar
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Batteries
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Equipment
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### Userfields
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### General
|
|
||||||
|
|
||||||
- xxx
|
|
||||||
|
|
||||||
### API
|
|
||||||
|
|
||||||
- The API endpoints `/stock/products/{productId}/open` and `/stock/products/by-barcode/{barcode}/open` now support a new (optional) `location_id` request body parameter (to only open stock entries at that location)
|
|
||||||
|
|
@ -555,12 +555,6 @@ class StockApiController extends BaseApiController
|
||||||
throw new \Exception('An amount is required');
|
throw new \Exception('An amount is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
$locationId = null;
|
|
||||||
if (array_key_exists('location_id', $requestBody) && !empty($requestBody['location_id']) && is_numeric($requestBody['location_id']))
|
|
||||||
{
|
|
||||||
$locationId = $requestBody['location_id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$specificStockEntryId = 'default';
|
$specificStockEntryId = 'default';
|
||||||
if (array_key_exists('stock_entry_id', $requestBody) && !empty($requestBody['stock_entry_id']))
|
if (array_key_exists('stock_entry_id', $requestBody) && !empty($requestBody['stock_entry_id']))
|
||||||
{
|
{
|
||||||
|
|
@ -574,7 +568,7 @@ class StockApiController extends BaseApiController
|
||||||
}
|
}
|
||||||
|
|
||||||
$transactionId = null;
|
$transactionId = null;
|
||||||
$transactionId = StockService::GetInstance()->OpenProduct($args['productId'], $requestBody['amount'], $locationId, $specificStockEntryId, $transactionId, $allowSubproductSubstitution);
|
$transactionId = StockService::GetInstance()->OpenProduct($args['productId'], $requestBody['amount'], $specificStockEntryId, $transactionId, $allowSubproductSubstitution);
|
||||||
$args['transactionId'] = $transactionId;
|
$args['transactionId'] = $transactionId;
|
||||||
return $this->StockTransactions($request, $response, $args);
|
return $this->StockTransactions($request, $response, $args);
|
||||||
}
|
}
|
||||||
|
|
@ -654,7 +648,7 @@ class StockApiController extends BaseApiController
|
||||||
$allowSubproductSubstitution = true;
|
$allowSubproductSubstitution = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->FilteredApiResponse($response, StockService::GetInstance()->GetProductStockEntries($args['productId'], null, false, $allowSubproductSubstitution), $request->getQueryParams());
|
return $this->FilteredApiResponse($response, StockService::GetInstance()->GetProductStockEntries($args['productId'], false, $allowSubproductSubstitution), $request->getQueryParams());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function LocationStockEntries(Request $request, Response $response, array $args)
|
public function LocationStockEntries(Request $request, Response $response, array $args)
|
||||||
|
|
|
||||||
|
|
@ -2255,10 +2255,6 @@
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`true` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
"description": "`true` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
||||||
},
|
|
||||||
"location_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"description": "A valid location id (if supplied, only stock at the given location is considered, if ommitted, stock of any location is considered)"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
|
|
@ -2603,7 +2599,7 @@
|
||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`true` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
"description": "`rue` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
|
|
@ -2826,11 +2822,7 @@
|
||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`true` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
"description": "`rue` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
||||||
},
|
|
||||||
"location_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"description": "A valid location id (if supplied, only stock at the given location is considered, if ommitted, stock of any location is considered)"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
$('#save-consume-button').on('click', function (e)
|
$('#save-consume-button').on('click', function(e)
|
||||||
{
|
{
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
|
@ -40,10 +40,10 @@
|
||||||
|
|
||||||
var bookingResponse = null;
|
var bookingResponse = null;
|
||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function (productDetails)
|
function(productDetails)
|
||||||
{
|
{
|
||||||
Grocy.Api.Post(apiUrl, jsonData,
|
Grocy.Api.Post(apiUrl, jsonData,
|
||||||
function (result)
|
function(result)
|
||||||
{
|
{
|
||||||
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled))
|
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled))
|
||||||
{
|
{
|
||||||
|
|
@ -59,14 +59,14 @@
|
||||||
jsonDataBarcode.product_id = jsonForm.product_id;
|
jsonDataBarcode.product_id = jsonForm.product_id;
|
||||||
|
|
||||||
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function (result)
|
function(result)
|
||||||
{
|
{
|
||||||
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
||||||
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
||||||
$('#barcode-lookup-hint').removeClass('d-none');
|
$('#barcode-lookup-hint').removeClass('d-none');
|
||||||
window.history.replaceState({}, document.title, U("/consume"));
|
window.history.replaceState({}, document.title, U("/consume"));
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
|
|
@ -130,7 +130,7 @@
|
||||||
$("#consume-exact-amount-group").addClass("d-none");
|
$("#consume-exact-amount-group").addClass("d-none");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
|
|
@ -138,7 +138,7 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
|
|
@ -146,7 +146,7 @@
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#save-mark-as-open-button').on('click', function (e)
|
$('#save-mark-as-open-button').on('click', function(e)
|
||||||
{
|
{
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
|
@ -168,7 +168,6 @@ $('#save-mark-as-open-button').on('click', function (e)
|
||||||
jsonData = {};
|
jsonData = {};
|
||||||
jsonData.amount = jsonForm.amount;
|
jsonData.amount = jsonForm.amount;
|
||||||
jsonData.allow_subproduct_substitution = true;
|
jsonData.allow_subproduct_substitution = true;
|
||||||
jsonData.location_id = jsonForm.location_id;
|
|
||||||
|
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked"))
|
||||||
{
|
{
|
||||||
|
|
@ -176,10 +175,10 @@ $('#save-mark-as-open-button').on('click', function (e)
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function (productDetails)
|
function(productDetails)
|
||||||
{
|
{
|
||||||
Grocy.Api.Post(apiUrl, jsonData,
|
Grocy.Api.Post(apiUrl, jsonData,
|
||||||
function (result)
|
function(result)
|
||||||
{
|
{
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked"))
|
||||||
|
|
@ -207,17 +206,16 @@ $('#save-mark-as-open-button').on('click', function (e)
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
Grocy.Components.ProductPicker.Clear();
|
Grocy.Components.ProductPicker.Clear();
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.GetInputElement().focus();
|
||||||
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
|
|
@ -225,8 +223,7 @@ $('#save-mark-as-open-button').on('click', function (e)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
var sumValue = 0;
|
var sumValue = 0;
|
||||||
var sumValueOpened = 0;
|
$("#location_id").on('change', function(e)
|
||||||
$("#location_id").on('change', function (e)
|
|
||||||
{
|
{
|
||||||
var locationId = $(e.target).val();
|
var locationId = $(e.target).val();
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
|
|
@ -248,12 +245,12 @@ $("#location_id").on('change', function (e)
|
||||||
if (gc.length == 4)
|
if (gc.length == 4)
|
||||||
{
|
{
|
||||||
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?query[]=stock_id=' + gc[3],
|
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?query[]=stock_id=' + gc[3],
|
||||||
function (stockEntries)
|
function(stockEntries)
|
||||||
{
|
{
|
||||||
OnLocationChange(stockEntries[0].location_id, gc[3]);
|
OnLocationChange(stockEntries[0].location_id, gc[3]);
|
||||||
$('#display_amount').val(stockEntries[0].amount);
|
$('#display_amount').val(stockEntries[0].amount);
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
|
|
@ -274,7 +271,6 @@ $("#location_id").on('change', function (e)
|
||||||
function OnLocationChange(locationId, stockId)
|
function OnLocationChange(locationId, stockId)
|
||||||
{
|
{
|
||||||
sumValue = 0;
|
sumValue = 0;
|
||||||
sumValueOpened = 0;
|
|
||||||
|
|
||||||
if (locationId)
|
if (locationId)
|
||||||
{
|
{
|
||||||
|
|
@ -284,7 +280,7 @@ function OnLocationChange(locationId, stockId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?include_sub_products=true',
|
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?include_sub_products=true',
|
||||||
function (stockEntries)
|
function(stockEntries)
|
||||||
{
|
{
|
||||||
stockEntries.forEach(stockEntry =>
|
stockEntries.forEach(stockEntry =>
|
||||||
{
|
{
|
||||||
|
|
@ -311,11 +307,6 @@ function OnLocationChange(locationId, stockId)
|
||||||
|
|
||||||
sumValue = sumValue + (stockEntry.amount || 0);
|
sumValue = sumValue + (stockEntry.amount || 0);
|
||||||
|
|
||||||
if (BoolVal(stockEntry.open))
|
|
||||||
{
|
|
||||||
sumValueOpened = sumValueOpened + (stockEntry.amount || 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stockEntry.stock_id == stockId)
|
if (stockEntry.stock_id == stockId)
|
||||||
{
|
{
|
||||||
$("#use_specific_stock_entry").click();
|
$("#use_specific_stock_entry").click();
|
||||||
|
|
@ -324,15 +315,13 @@ function OnLocationChange(locationId, stockId)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + Grocy.Components.ProductPicker.GetValue(),
|
Grocy.Api.Get('stock/products/' + Grocy.Components.ProductPicker.GetValue(),
|
||||||
function (productDetails)
|
function(productDetails)
|
||||||
{
|
{
|
||||||
current_productDetails = productDetails;
|
current_productDetails = productDetails;
|
||||||
RefreshForm();
|
RefreshForm();
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
|
|
@ -343,7 +332,7 @@ function OnLocationChange(locationId, stockId)
|
||||||
ScanModeSubmit();
|
ScanModeSubmit();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
|
|
@ -351,7 +340,7 @@ function OnLocationChange(locationId, stockId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function (e)
|
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
{
|
{
|
||||||
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled))
|
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled))
|
||||||
{
|
{
|
||||||
|
|
@ -372,7 +361,7 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function (e)
|
||||||
Grocy.Components.ProductCard.Refresh(productId);
|
Grocy.Components.ProductCard.Refresh(productId);
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function (productDetails)
|
function(productDetails)
|
||||||
{
|
{
|
||||||
current_productDetails = productDetails;
|
current_productDetails = productDetails;
|
||||||
|
|
||||||
|
|
@ -397,7 +386,7 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function (e)
|
||||||
|
|
||||||
$("#location_id").find("option").remove().end().append("<option></option>");
|
$("#location_id").find("option").remove().end().append("<option></option>");
|
||||||
Grocy.Api.Get("stock/products/" + productId + '/locations?include_sub_products=true',
|
Grocy.Api.Get("stock/products/" + productId + '/locations?include_sub_products=true',
|
||||||
function (stockLocations)
|
function(stockLocations)
|
||||||
{
|
{
|
||||||
var setDefault = 0;
|
var setDefault = 0;
|
||||||
var stockAmountAtDefaultLocation = 0;
|
var stockAmountAtDefaultLocation = 0;
|
||||||
|
|
@ -447,7 +436,7 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function (e)
|
||||||
if (document.getElementById("product_id").getAttribute("barcode") != "null")
|
if (document.getElementById("product_id").getAttribute("barcode") != "null")
|
||||||
{
|
{
|
||||||
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
||||||
function (barcodeResult)
|
function(barcodeResult)
|
||||||
{
|
{
|
||||||
if (barcodeResult != null)
|
if (barcodeResult != null)
|
||||||
{
|
{
|
||||||
|
|
@ -473,14 +462,14 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function (e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
|
|
@ -500,12 +489,21 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function (e)
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.HideCustomError();
|
Grocy.Components.ProductPicker.HideCustomError();
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
setTimeout(function ()
|
setTimeout(function()
|
||||||
{
|
{
|
||||||
$('#display_amount').focus();
|
$('#display_amount').focus();
|
||||||
}, Grocy.FormFocusDelay);
|
}, Grocy.FormFocusDelay);
|
||||||
|
|
||||||
|
if (productDetails.stock_amount == productDetails.stock_amount_opened || productDetails.product.enable_tare_weight_handling == 1 || productDetails.product.disable_open == 1)
|
||||||
|
{
|
||||||
|
$("#save-mark-as-open-button").addClass("disabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$("#save-mark-as-open-button").removeClass("disabled");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
|
|
@ -517,44 +515,28 @@ $('#display_amount').val(Grocy.UserSettings.stock_default_consume_amount);
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
|
|
||||||
$('#display_amount').on('focus', function (e)
|
$('#display_amount').on('focus', function(e)
|
||||||
{
|
{
|
||||||
$(this).select();
|
$(this).select();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#price').on('focus', function (e)
|
$('#price').on('focus', function(e)
|
||||||
{
|
{
|
||||||
$(this).select();
|
$(this).select();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#consume-form input').keyup(function (event)
|
|
||||||
|
$('#consume-form input').keyup(function(event)
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#consume-form select').change(function (event)
|
$('#consume-form select').change(function(event)
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#display_amount").on("keyup", function (e)
|
$('#consume-form input').keydown(function(event)
|
||||||
{
|
|
||||||
if (!current_productDetails)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($("#display_amount").val() > sumValue - sumValueOpened || current_productDetails.product.enable_tare_weight_handling == 1 || current_productDetails.product.disable_open == 1)
|
|
||||||
{
|
|
||||||
$("#save-mark-as-open-button").addClass("disabled");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#save-mark-as-open-button").removeClass("disabled");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#consume-form input').keydown(function (event)
|
|
||||||
{
|
{
|
||||||
if (event.keyCode === 13) // Enter
|
if (event.keyCode === 13) // Enter
|
||||||
{
|
{
|
||||||
|
|
@ -571,45 +553,28 @@ $('#consume-form input').keydown(function (event)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#specific_stock_entry").on("change", function (e)
|
$("#specific_stock_entry").on("change", function(e)
|
||||||
{
|
{
|
||||||
if ($(e.target).val() == "")
|
if ($(e.target).val() == "")
|
||||||
{
|
{
|
||||||
sumValue = 0;
|
sumValue = 0;
|
||||||
sumValueOpened = 0;
|
|
||||||
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?include_sub_products=true',
|
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?include_sub_products=true',
|
||||||
function (stockEntries)
|
function(stockEntries)
|
||||||
{
|
{
|
||||||
stockEntries.forEach(stockEntry =>
|
stockEntries.forEach(stockEntry =>
|
||||||
{
|
{
|
||||||
if (stockEntry.location_id == $("#location_id").val() || stockEntry.location_id == "")
|
if (stockEntry.location_id == $("#location_id").val() || stockEntry.location_id == "")
|
||||||
{
|
{
|
||||||
sumValue = sumValue + (stockEntry.amount || 0);
|
sumValue = sumValue + stockEntry.amount_aggregated;
|
||||||
|
|
||||||
if (BoolVal(stockEntry.open))
|
|
||||||
{
|
|
||||||
sumValueOpened = sumValueOpened + (stockEntry.amount || 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#display_amount").attr("max", sumValue.toFixed(Grocy.UserSettings.stock_decimal_places_amounts));
|
$("#display_amount").attr("max", sumValue.toFixed(Grocy.UserSettings.stock_decimal_places_amounts));
|
||||||
|
|
||||||
if (sumValue == 0)
|
if (sumValue == 0)
|
||||||
{
|
{
|
||||||
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sumValue == sumValueOpened || current_productDetails.product.enable_tare_weight_handling == 1 || current_productDetails.product.disable_open == 1)
|
|
||||||
{
|
|
||||||
$("#save-mark-as-open-button").addClass("disabled");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#save-mark-as-open-button").removeClass("disabled");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
|
|
@ -621,7 +586,7 @@ $("#specific_stock_entry").on("change", function (e)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#use_specific_stock_entry").on("change", function ()
|
$("#use_specific_stock_entry").on("change", function()
|
||||||
{
|
{
|
||||||
var value = $(this).is(":checked");
|
var value = $(this).is(":checked");
|
||||||
|
|
||||||
|
|
@ -640,7 +605,7 @@ $("#use_specific_stock_entry").on("change", function ()
|
||||||
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#qu_id").on("change", function ()
|
$("#qu_id").on("change", function()
|
||||||
{
|
{
|
||||||
RefreshForm();
|
RefreshForm();
|
||||||
});
|
});
|
||||||
|
|
@ -648,11 +613,11 @@ $("#qu_id").on("change", function ()
|
||||||
function UndoStockBooking(bookingId)
|
function UndoStockBooking(bookingId)
|
||||||
{
|
{
|
||||||
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
||||||
function (result)
|
function(result)
|
||||||
{
|
{
|
||||||
toastr.success(__t("Booking successfully undone"));
|
toastr.success(__t("Booking successfully undone"));
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
|
|
@ -662,11 +627,11 @@ function UndoStockBooking(bookingId)
|
||||||
function UndoStockTransaction(transactionId)
|
function UndoStockTransaction(transactionId)
|
||||||
{
|
{
|
||||||
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
||||||
function (result)
|
function(result)
|
||||||
{
|
{
|
||||||
toastr.success(__t("Transaction successfully undone"));
|
toastr.success(__t("Transaction successfully undone"));
|
||||||
},
|
},
|
||||||
function (xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
|
|
@ -692,12 +657,12 @@ if (GetUriParam("embedded") !== undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default input field
|
// Default input field
|
||||||
setTimeout(function ()
|
setTimeout(function()
|
||||||
{
|
{
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.GetInputElement().focus();
|
||||||
}, Grocy.FormFocusDelay);
|
}, Grocy.FormFocusDelay);
|
||||||
|
|
||||||
$(document).on("change", "#scan-mode", function (e)
|
$(document).on("change", "#scan-mode", function(e)
|
||||||
{
|
{
|
||||||
if ($(this).prop("checked"))
|
if ($(this).prop("checked"))
|
||||||
{
|
{
|
||||||
|
|
@ -705,7 +670,7 @@ $(document).on("change", "#scan-mode", function (e)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#scan-mode-button").on("click", function (e)
|
$("#scan-mode-button").on("click", function(e)
|
||||||
{
|
{
|
||||||
$("#scan-mode").click();
|
$("#scan-mode").click();
|
||||||
$("#scan-mode-button").toggleClass("btn-success").toggleClass("btn-danger");
|
$("#scan-mode-button").toggleClass("btn-success").toggleClass("btn-danger");
|
||||||
|
|
@ -762,15 +727,6 @@ function RefreshForm()
|
||||||
$("#display_amount").removeAttr("max");
|
$("#display_amount").removeAttr("max");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sumValue == sumValueOpened || productDetails.product.enable_tare_weight_handling == 1 || productDetails.product.disable_open == 1)
|
|
||||||
{
|
|
||||||
$("#save-mark-as-open-button").addClass("disabled");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#save-mark-as-open-button").removeClass("disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -400,24 +400,26 @@ class StockService extends BaseService
|
||||||
|
|
||||||
if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION)
|
if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION)
|
||||||
{
|
{
|
||||||
$potentialStockEntries = $this->GetProductStockEntries($productId, $locationId, false, $allowSubproductSubstitution);
|
if ($locationId === null)
|
||||||
|
{
|
||||||
|
// Consume from any location
|
||||||
|
$potentialStockEntries = $this->GetProductStockEntries($productId, false, $allowSubproductSubstitution);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Consume only from the supplied location
|
||||||
|
$potentialStockEntries = $this->GetProductStockEntriesForLocation($productId, $locationId, false, $allowSubproductSubstitution);
|
||||||
|
}
|
||||||
|
|
||||||
if ($specificStockEntryId !== 'default')
|
if ($specificStockEntryId !== 'default')
|
||||||
{
|
{
|
||||||
$potentialStockEntries = FindAllObjectsInArrayByPropertyValue($potentialStockEntries, 'stock_id', $specificStockEntryId);
|
$potentialStockEntries = FindAllObjectsInArrayByPropertyValue($potentialStockEntries, 'stock_id', $specificStockEntryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($locationId === null)
|
$productStockAmount = $productDetails->stock_amount_aggregated;
|
||||||
|
if (round($amount, 2) > round($productStockAmount, 2))
|
||||||
{
|
{
|
||||||
$productStockAmountTotal = $this->DB->stock()->where('product_id = :1', $productId)->sum('amount');
|
throw new \Exception('Amount to be consumed cannot be > current stock amount (if supplied, at the desired location)');
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$productStockAmountTotal = $this->DB->stock()->where('product_id = :1 AND location_id = :2', $productId, $locationId)->sum('amount');
|
|
||||||
}
|
|
||||||
if ($amount > $productStockAmountTotal)
|
|
||||||
{
|
|
||||||
throw new \Exception('Amount to be consumed cannot be > current unopened stock amount (if supplied, at the desired location)');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($transactionId === null)
|
if ($transactionId === null)
|
||||||
|
|
@ -863,7 +865,7 @@ class StockService extends BaseService
|
||||||
return $returnData;
|
return $returnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetProductStockEntries(int $productId, $locationId = null, $excludeOpened = false, $allowSubproductSubstitution = false)
|
public function GetProductStockEntries(int $productId, $excludeOpened = false, $allowSubproductSubstitution = false)
|
||||||
{
|
{
|
||||||
$sqlWhereProductId = 'product_id = ' . $productId;
|
$sqlWhereProductId = 'product_id = ' . $productId;
|
||||||
if ($allowSubproductSubstitution)
|
if ($allowSubproductSubstitution)
|
||||||
|
|
@ -877,13 +879,7 @@ class StockService extends BaseService
|
||||||
$sqlWhereAndOpen = 'AND open = 0';
|
$sqlWhereAndOpen = 'AND open = 0';
|
||||||
}
|
}
|
||||||
|
|
||||||
$sqlWhereAndLocationId = '';
|
return $this->DB->stock_next_use()->where($sqlWhereProductId . ' ' . $sqlWhereAndOpen);
|
||||||
if ($locationId !== null)
|
|
||||||
{
|
|
||||||
$sqlWhereAndLocationId = 'AND location_id = ' . $locationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->DB->stock_next_use()->where($sqlWhereProductId . ' ' . $sqlWhereAndOpen . ' ' . $sqlWhereAndLocationId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetLocationStockEntries($locationId)
|
public function GetLocationStockEntries($locationId)
|
||||||
|
|
@ -896,6 +892,12 @@ class StockService extends BaseService
|
||||||
return $this->DB->stock()->where('location_id', $locationId);
|
return $this->DB->stock()->where('location_id', $locationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function GetProductStockEntriesForLocation($productId, $locationId, $excludeOpened = false, $allowSubproductSubstitution = false)
|
||||||
|
{
|
||||||
|
$stockEntries = $this->GetProductStockEntries($productId, $excludeOpened, $allowSubproductSubstitution);
|
||||||
|
return FindAllObjectsInArrayByPropertyValue($stockEntries, 'location_id', $locationId);
|
||||||
|
}
|
||||||
|
|
||||||
public function GetProductStockLocations(int $productId, $allowSubproductSubstitution = false)
|
public function GetProductStockLocations(int $productId, $allowSubproductSubstitution = false)
|
||||||
{
|
{
|
||||||
$sqlWhereProductId = 'product_id = ' . $productId;
|
$sqlWhereProductId = 'product_id = ' . $productId;
|
||||||
|
|
@ -976,7 +978,7 @@ class StockService extends BaseService
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function OpenProduct(int $productId, float $amount, $locationId = null, $specificStockEntryId = 'default', &$transactionId = null, $allowSubproductSubstitution = false)
|
public function OpenProduct(int $productId, float $amount, $specificStockEntryId = 'default', &$transactionId = null, $allowSubproductSubstitution = false)
|
||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
|
|
@ -991,24 +993,17 @@ class StockService extends BaseService
|
||||||
}
|
}
|
||||||
|
|
||||||
$productDetails = (object)$this->GetProductDetails($productId);
|
$productDetails = (object)$this->GetProductDetails($productId);
|
||||||
$potentialStockEntries = $this->GetProductStockEntries($productId, $locationId, true, $allowSubproductSubstitution);
|
$productStockAmountUnopened = $productDetails->stock_amount_aggregated - $productDetails->stock_amount_opened_aggregated;
|
||||||
|
$potentialStockEntries = $this->GetProductStockEntries($productId, true, $allowSubproductSubstitution);
|
||||||
|
|
||||||
if ($product->enable_tare_weight_handling == 1)
|
if ($product->enable_tare_weight_handling == 1)
|
||||||
{
|
{
|
||||||
throw new \Exception('Opening tare weight handling enabled products is not supported');
|
throw new \Exception('Opening tare weight handling enabled products is not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($locationId === null)
|
|
||||||
{
|
|
||||||
$productStockAmountUnopened = $this->DB->stock()->where('product_id = :1 AND open = 0', $productId)->sum('amount');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$productStockAmountUnopened = $this->DB->stock()->where('product_id = :1 AND open = 0 AND location_id = :2', $productId, $locationId)->sum('amount');
|
|
||||||
}
|
|
||||||
if ($amount > $productStockAmountUnopened)
|
if ($amount > $productStockAmountUnopened)
|
||||||
{
|
{
|
||||||
throw new \Exception('Amount to be opened cannot be > current unopened stock amount (if supplied, at the desired location)');
|
throw new \Exception('Amount to be opened cannot be > current unopened stock amount');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($specificStockEntryId !== 'default')
|
if ($specificStockEntryId !== 'default')
|
||||||
|
|
@ -1295,10 +1290,16 @@ class StockService extends BaseService
|
||||||
{
|
{
|
||||||
// Hard fail for now, as we not yet support transferring tare weight enabled products
|
// Hard fail for now, as we not yet support transferring tare weight enabled products
|
||||||
throw new \Exception('Transferring tare weight enabled products is not yet possible');
|
throw new \Exception('Transferring tare weight enabled products is not yet possible');
|
||||||
|
if ($amount < $productDetails->product->tare_weight)
|
||||||
|
{
|
||||||
|
throw new \Exception('The amount cannot be lower than the defined tare weight');
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = abs($amount - $productDetails->stock_amount - $productDetails->product->tare_weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
$productStockAmountAtFromLocation = $this->DB->stock()->where('product_id = :1 AND location_id = :2', $productId, $locationIdFrom)->sum('amount');
|
$productStockAmountAtFromLocation = $this->DB->stock()->where('product_id = :1 AND location_id = :2', $productId, $locationIdFrom)->sum('amount');
|
||||||
$potentialStockEntriesAtFromLocation = $this->GetProductStockEntries($productId, $locationIdFrom);
|
$potentialStockEntriesAtFromLocation = $this->GetProductStockEntriesForLocation($productId, $locationIdFrom);
|
||||||
|
|
||||||
if ($amount > $productStockAmountAtFromLocation)
|
if ($amount > $productStockAmountAtFromLocation)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user