diff --git a/changelog/60_UNRELEASED_2020-xx-xx.md b/changelog/60_UNRELEASED_2020-xx-xx.md
index 961a064d..ec7e28c5 100644
--- a/changelog/60_UNRELEASED_2020-xx-xx.md
+++ b/changelog/60_UNRELEASED_2020-xx-xx.md
@@ -31,6 +31,7 @@ _- (Because the stock quantity unit is now the base for everything, it cannot be
### Stock improvements/fixes
- When creating a quantity unit conversion it's now possible to automatically create the inverse conversion (thanks @kriddles)
- On purchase there is now a warning shown, when the best before date of the purchased product is earlier than the next best before date in stock (enabled by default, can be disabled by a new stock setting (top right corner settings menu))
+- The amount to be used for the "quick consume/open buttons" on the stock overview page can now be configured per product (new product option "Quick consume amount", defaults to 1)
- Optimized/clarified what the total/unit price is on the purchase page (thanks @kriddles)
- On the purchase page the amount field is now displayed above/before the best before date for better `TAB` handling (thanks @kriddles)
- Changed that when `FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING` is disabled, products now get internally a best before of "never expires" (aka `2999-12-31`) instead of today (thanks @kriddles)
diff --git a/controllers/StockController.php b/controllers/StockController.php
index 94ff438b..89ed2a76 100644
--- a/controllers/StockController.php
+++ b/controllers/StockController.php
@@ -142,7 +142,7 @@ class StockController extends BaseController
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
'userfields' => $this->getUserfieldsService()->GetFields('products'),
- 'products' => $this->getDatabase()->products()->where('IFNULL(parent_product_id, \'\') = \'\' and active = 1')->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('parent_product_id IS NULL and active = 1')->orderBy('name'),
'isSubProductOfOthers' => false,
'mode' => 'create'
]);
@@ -159,7 +159,7 @@ class StockController extends BaseController
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
'userfields' => $this->getUserfieldsService()->GetFields('products'),
- 'products' => $this->getDatabase()->products()->where('id != :1 AND IFNULL(parent_product_id, \'\') = \'\' and active = 1', $product->id)->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('id != :1 AND parent_product_id IS NULL and active = 1', $product->id)->orderBy('name'),
'isSubProductOfOthers' => $this->getDatabase()->products()->where('parent_product_id = :1', $product->id)->count() !== 0,
'mode' => 'edit',
'quConversions' => $this->getDatabase()->quantity_unit_conversions()
diff --git a/localization/strings.pot b/localization/strings.pot
index bd359d09..a52519ae 100644
--- a/localization/strings.pot
+++ b/localization/strings.pot
@@ -1933,3 +1933,9 @@ msgstr ""
msgid "When enabled, the amount will always be filled with 1 after changing/scanning a product and if all fields could be automatically populated (by product defaults), the transaction is automatically submitted"
msgstr ""
+
+msgid "Quick consume amount"
+msgstr ""
+
+msgid "This amount is used for the \"quick consume/open buttons\" on the stock overview page (related to quantity unit stock)"
+msgstr ""
diff --git a/migrations/0103.sql b/migrations/0103.sql
index a8078496..6dcd2ab9 100644
--- a/migrations/0103.sql
+++ b/migrations/0103.sql
@@ -68,6 +68,7 @@ CREATE TABLE products (
parent_product_id INT,
calories INTEGER,
cumulate_min_stock_amount_of_sub_products TINYINT DEFAULT 0,
+ quick_consume_amount REAL NOT NULL DEFAULT 1,
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
);
@@ -88,6 +89,22 @@ BEGIN
) NOTNULL) THEN RAISE(ABORT, "qu_id_stock cannot be changed when the product was once added to stock") END;
END;
+CREATE TRIGGER enforce_parent_product_id_null_when_empty_INS AFTER INSERT ON products
+BEGIN
+ UPDATE products
+ SET parent_product_id = NULL
+ WHERE id = NEW.id
+ AND IFNULL(parent_product_id, '') = '';
+END;
+
+CREATE TRIGGER enforce_parent_product_id_null_when_empty_UPD AFTER UPDATE ON products
+BEGIN
+ UPDATE products
+ SET parent_product_id = NULL
+ WHERE id = NEW.id
+ AND IFNULL(parent_product_id, '') = '';
+END;
+
DROP VIEW stock_current_location_content;
CREATE VIEW stock_current_location_content
AS
diff --git a/migrations/0105.sql b/migrations/0105.sql
index 803d7628..a67d670f 100644
--- a/migrations/0105.sql
+++ b/migrations/0105.sql
@@ -22,7 +22,8 @@ SELECT
sc.amount_aggregated,
p.calories AS product_calories,
sc.amount * p.calories AS calories,
- sc.amount_aggregated * p.calories AS calories_aggregated
+ sc.amount_aggregated * p.calories AS calories_aggregated,
+ p.quick_consume_amount
FROM (
SELECT *
FROM stock_current
@@ -59,7 +60,8 @@ SELECT
sc.amount_aggregated,
p.calories AS product_calories,
sc.amount * p.calories AS calories,
- sc.amount_aggregated * p.calories AS calories_aggregated
+ sc.amount_aggregated * p.calories AS calories_aggregated,
+ p.quick_consume_amount
FROM (
SELECT *
FROM stock_current
diff --git a/public/viewjs/productform.js b/public/viewjs/productform.js
index 8f86ab65..88e2de1a 100644
--- a/public/viewjs/productform.js
+++ b/public/viewjs/productform.js
@@ -185,6 +185,7 @@ $('.input-group-qu').on('change', function(e)
}
$("#tare_weight_qu_info").text($("#qu_id_stock option:selected").text());
+ $("#quick_consume_qu_info").text($("#qu_id_stock option:selected").text());
Grocy.FrontendHelpers.ValidateForm('product-form');
});
diff --git a/public/viewjs/stockoverview.js b/public/viewjs/stockoverview.js
index e53b8309..60af4527 100755
--- a/public/viewjs/stockoverview.js
+++ b/public/viewjs/stockoverview.js
@@ -162,9 +162,10 @@ $(document).on('click', '.product-open-button', function(e)
var productId = $(e.currentTarget).attr('data-product-id');
var productName = $(e.currentTarget).attr('data-product-name');
var productQuName = $(e.currentTarget).attr('data-product-qu-name');
+ var amount = $(e.currentTarget).attr('data-open-amount');
var button = $(e.currentTarget);
- Grocy.Api.Post('stock/products/' + productId + '/open', { 'amount': 1 },
+ Grocy.Api.Post('stock/products/' + productId + '/open', { 'amount': amount },
function(bookingResponse)
{
Grocy.Api.Get('stock/products/' + productId,
@@ -176,7 +177,7 @@ $(document).on('click', '.product-open-button', function(e)
}
Grocy.FrontendHelpers.EndUiBusy();
- toastr.success(__t('Marked %1$s of %2$s as opened', 1 + " " + productQuName, productName) + '
' + __t("Undo") + '');
+ toastr.success(__t('Marked %1$s of %2$s as opened', amount.toString() + " " + productQuName, productName) + '
' + __t("Undo") + '');
RefreshStatistics();
RefreshProductRow(productId);
},
diff --git a/views/productform.blade.php b/views/productform.blade.php
index dd70ed41..7392c508 100644
--- a/views/productform.blade.php
+++ b/views/productform.blade.php
@@ -351,6 +351,17 @@
value="0">
@endif
+ @php if($mode == 'edit') { $value = $product->quick_consume_amount; } else { $value = 1; } @endphp
+ @include('components.numberpicker', array(
+ 'id' => 'quick_consume_amount',
+ 'label' => 'Quick consume amount',
+ 'min' => '0.' . str_repeat('0', $userSettings['stock_decimal_places_amounts'] - 1) . '1',
+ 'value' => $value,
+ 'invalidFeedback' => $__t('The amount cannot be lower than %s', '0'),
+ 'hint' => $__t('This amount is used for the "quick consume/open buttons" on the stock overview page (related to quantity unit stock)'),
+ 'contextInfoId' => 'quick_consume_qu_info'
+ ))
+
@include('components.userfieldsform', array(
'userfields' => $userfields,
'entity' => 'products'
diff --git a/views/stockoverview.blade.php b/views/stockoverview.blade.php
index fb47bb37..8cd8f31d 100755
--- a/views/stockoverview.blade.php
+++ b/views/stockoverview.blade.php
@@ -174,16 +174,16 @@