Fixed shopping list QU handling (fixes #1385, fixes #1384)

This commit is contained in:
Bernd Bestel 2021-07-02 17:37:06 +02:00
parent 187d48f93d
commit cae924eb81
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
6 changed files with 128 additions and 9 deletions

View File

@ -39,6 +39,7 @@
- The amount now defaults to `1` for adding items quicker
- Fixed that shopping list prints had a grey background (thanks @Forceu)
- Fixed the form validation on the shopping list item page (thanks @Forceu)
- Fixed that when adding products to the shopping list from the stock overview page, the used quantity unit was always the products default purchase QU (and not the selected one)
### Recipe improvements/fixes
- Recipe printing improvements (thanks @Ape)

View File

@ -180,6 +180,7 @@ class StockApiController extends BaseApiController
$listId = 1;
$amount = 1;
$quId = -1;
$productId = null;
$note = null;
@ -203,12 +204,17 @@ class StockApiController extends BaseApiController
$note = $requestBody['note'];
}
if (array_key_exists('qu_id', $requestBody) && !empty($requestBody['qu_id']))
{
$quId = $requestBody['qu_id'];
}
if ($productId == null)
{
throw new \Exception('No product id was supplied');
}
$this->getStockService()->AddProductToShoppingList($productId, $amount, $note, $listId);
$this->getStockService()->AddProductToShoppingList($productId, $amount, $quId, $note, $listId);
return $this->EmptyApiResponse($response);
}
catch (\Exception $ex)

103
migrations/0133.sql Normal file
View File

@ -0,0 +1,103 @@
DROP VIEW quantity_unit_conversions_resolved;
CREATE VIEW quantity_unit_conversions_resolved
AS
-- 1. Product "purchase to stock" conversion factor
SELECT
-1 AS id, -- Dummy, LessQL needs an id column
p.id AS product_id,
p.qu_id_purchase AS from_qu_id,
qu_from.name AS from_qu_name,
qu_from.name_plural AS from_qu_name_plural,
p.qu_id_stock AS to_qu_id,
qu_to.name AS to_qu_name,
qu_to.name_plural AS to_qu_name_plural,
p.qu_factor_purchase_to_stock AS factor
FROM products p
JOIN quantity_units qu_from
ON p.qu_id_purchase = qu_from.id
JOIN quantity_units qu_to
ON p.qu_id_stock = qu_to.id
UNION -- Inversed
SELECT
-1 AS id, -- Dummy, LessQL needs an id column
p.id AS product_id,
p.qu_id_stock AS from_qu_id,
qu_to.name AS from_qu_name,
qu_to.name_plural AS from_qu_name_plural,
p.qu_id_purchase AS to_qu_id,
qu_from.name AS to_qu_name,
qu_from.name_plural AS to_qu_name_plural,
1 / p.qu_factor_purchase_to_stock AS factor
FROM products p
JOIN quantity_units qu_from
ON p.qu_id_purchase = qu_from.id
JOIN quantity_units qu_to
ON p.qu_id_stock = qu_to.id
UNION
-- 2. Product specific QU overrides
SELECT
-1 AS id, -- Dummy, LessQL needs an id column
p.id AS product_id,
quc.from_qu_id AS from_qu_id,
qu_from.name AS from_qu_name,
qu_from.name_plural AS from_qu_name_plural,
quc.to_qu_id AS to_qu_id,
qu_to.name AS to_qu_name,
qu_to.name_plural AS to_qu_name_plural,
quc.factor AS factor
FROM products p
JOIN quantity_unit_conversions quc
ON p.id = quc.product_id
JOIN quantity_units qu_from
ON quc.from_qu_id = qu_from.id
JOIN quantity_units qu_to
ON quc.to_qu_id = qu_to.id
UNION
-- 3. Default (direct) QU conversion factors
SELECT
-1 AS id, -- Dummy, LessQL needs an id column
p.id AS product_id,
p.qu_id_stock AS from_qu_id,
qu_from.name AS from_qu_name,
qu_from.name_plural AS from_qu_name_plural,
quc.to_qu_id AS to_qu_id,
qu_to.name AS to_qu_name,
qu_to.name_plural AS to_qu_name_plural,
quc.factor AS factor
FROM products p
JOIN quantity_unit_conversions quc
ON p.qu_id_stock = quc.from_qu_id
AND quc.product_id IS NULL
JOIN quantity_units qu_from
ON quc.from_qu_id = qu_from.id
JOIN quantity_units qu_to
ON quc.to_qu_id = qu_to.id
UNION
-- 4. Default (indirect) QU conversion factors
SELECT
-1 AS id, -- Dummy, LessQL needs an id column
p.id AS product_id,
(SELECT from_qu_id FROM quantity_unit_conversions WHERE to_qu_id = quc.to_qu_id AND product_id = p.id) AS from_qu_id,
qu_from.name AS from_qu_name,
qu_from.name_plural AS from_qu_name_plural,
quc.from_qu_id AS to_qu_id,
qu_to.name AS to_qu_name,
qu_to.name_plural AS to_qu_name_plural,
quc.factor * (SELECT factor FROM quantity_unit_conversions WHERE to_qu_id = quc.to_qu_id AND product_id = p.id) AS factor
FROM products p
JOIN product_qu_relations pqr
ON p.id = pqr.product_id
JOIN quantity_unit_conversions quc
ON pqr.qu_id = quc.from_qu_id
AND quc.product_id IS NULL
JOIN quantity_units qu_from
ON (SELECT from_qu_id FROM quantity_unit_conversions WHERE to_qu_id = quc.to_qu_id AND product_id = p.id) = qu_from.id
JOIN quantity_units qu_to
ON quc.from_qu_id = qu_to.id;

View File

@ -21,7 +21,7 @@ Grocy.Components.ProductAmountPicker.Reload = function(productId, destinationQuI
if (!$('#qu_id option[value="' + conversion.to_qu_id + '"]').length) // Don't add the destination QU multiple times
{
$("#qu_id").append('<option value="' + conversion.to_qu_id + '" data-qu-factor="' + factor + '">' + conversion.to_qu_name + '</option>');
$("#qu_id").append('<option value="' + conversion.to_qu_id + '" data-qu-factor="' + factor + '" data-qu-name-plural="' + conversion.to_qu_name_plural + '">' + conversion.to_qu_name + '</option>');
}
});
}
@ -68,7 +68,7 @@ Grocy.Components.ProductAmountPicker.AllowAnyQu = function(keepInitialQu = false
$("#qu_id").find("option").remove().end();
Grocy.QuantityUnits.forEach(qu =>
{
$("#qu_id").append('<option value="' + qu.id + '" data-qu-factor="1">' + qu.name + '</option>');
$("#qu_id").append('<option value="' + qu.id + '" data-qu-factor="1" data-qu-name-plural="' + qu.name_plural + '>' + qu.name + '</option>');
});
if (keepInitialQu)

View File

@ -10,6 +10,7 @@ $('#save-shoppinglist-button').on('click', function(e)
}
var jsonData = $('#shoppinglist-form').serializeJSON();
var displayAmount = parseFloat(jsonData.display_amount);
if (!jsonData.product_id)
{
jsonData.amount = jsonData.display_amount;
@ -37,7 +38,7 @@ $('#save-shoppinglist-button').on('click', function(e)
Grocy.Api.Get('stock/products/' + jsonData.product_id,
function(productDetails)
{
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", parseFloat(jsonData.product_amount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(jsonData.product_amount, productDetails.default_quantity_unit_purchase.name, productDetails.default_quantity_unit_purchase.name_plural), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural")), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
},
@ -74,7 +75,7 @@ $('#save-shoppinglist-button').on('click', function(e)
Grocy.Api.Get('stock/products/' + jsonData.product_id,
function(productDetails)
{
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", parseFloat(jsonData.amount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(jsonData.amount, productDetails.default_quantity_unit_purchase.name, productDetails.default_quantity_unit_purchase.name_plural), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural")), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
},
@ -116,7 +117,7 @@ $('#save-shoppinglist-button').on('click', function(e)
Grocy.Api.Get('stock/products/' + jsonData.product_id,
function(productDetails)
{
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", parseFloat(jsonData.amount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(jsonData.amount, productDetails.default_quantity_unit_purchase.name, productDetails.default_quantity_unit_purchase.name_plural), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural")), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
},

View File

@ -214,7 +214,7 @@ class StockService extends BaseService
}
}
public function AddProductToShoppingList($productId, $amount = 1, $note = null, $listId = 1)
public function AddProductToShoppingList($productId, $amount = 1, $quId = -1, $note = null, $listId = 1)
{
if (!$this->ShoppingListExists($listId))
{
@ -226,9 +226,15 @@ class StockService extends BaseService
throw new \Exception('Product does not exist or is inactive');
}
if ($quId == -1)
{
$quId = $this->getDatabase()->products($productId)->qu_id_purchase;
}
$alreadyExistingEntry = $this->getDatabase()->shopping_list()->where('product_id = :1 AND shopping_list_id = :2', $productId, $listId)->fetch();
if ($alreadyExistingEntry)
{ // Update
{
// Update
$alreadyExistingEntry->update([
'amount' => ($alreadyExistingEntry->amount + $amount),
'shopping_list_id' => $listId,
@ -236,10 +242,12 @@ class StockService extends BaseService
]);
}
else
{ // Insert
{
// Insert
$shoppinglistRow = $this->getDatabase()->shopping_list()->createRow([
'product_id' => $productId,
'amount' => $amount,
'qu_id' => $quId,
'shopping_list_id' => $listId,
'note' => $note
]);