Make the quick consume buttons on the stock overview page configurable per product (closes #613)

This commit is contained in:
Bernd Bestel 2020-11-15 09:57:45 +01:00
parent 17ae7e3d0c
commit 1d1642b464
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
9 changed files with 54 additions and 14 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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 ""

View File

@ -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

View File

@ -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

View File

@ -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');
});

View File

@ -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) + '<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>');
toastr.success(__t('Marked %1$s of %2$s as opened', amount.toString() + " " + productQuName, productName) + '<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>');
RefreshStatistics();
RefreshProductRow(productId);
},

View File

@ -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'

View File

@ -174,16 +174,16 @@
<tr id="product-{{ $currentStockEntry->product_id }}-row"
class="@if(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $currentStockEntry->amount > 0) table-danger @elseif(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('+' . $nextXDays . ' days')) && $currentStockEntry->amount > 0) table-warning @elseif ($currentStockEntry->product_missing) table-info @endif">
<td class="fit-content border-right">
<a class="permission-STOCK_CONSUME btn btn-success btn-sm product-consume-button @if($currentStockEntry->amount < 1 || $currentStockEntry->enable_tare_weight_handling == 1) disabled @endif"
<a class="permission-STOCK_CONSUME btn btn-success btn-sm product-consume-button @if($currentStockEntry->amount < $currentStockEntry->quick_consume_amount || $currentStockEntry->enable_tare_weight_handling == 1) disabled @endif"
href="#"
data-toggle="tooltip"
data-placement="left"
title="{{ $__t('Consume %1$s of %2$s', '1 ' . $currentStockEntry->qu_unit_name, $currentStockEntry->product_name) }}"
title="{{ $__t('Consume %1$s of %2$s', $currentStockEntry->quick_consume_amount . ' ' . $currentStockEntry->qu_unit_name, $currentStockEntry->product_name) }}"
data-product-id="{{ $currentStockEntry->product_id }}"
data-product-name="{{ $currentStockEntry->product_name }}"
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
data-consume-amount="1">
<i class="fas fa-utensils"></i> 1
data-consume-amount="{{ $currentStockEntry->quick_consume_amount }}">
<i class="fas fa-utensils"></i> <span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</span>
</a>
<a id="product-{{ $currentStockEntry->product_id }}-consume-all-button"
class="permission-STOCK_CONSUME d-none d-sm-inline-block btn btn-danger btn-sm product-consume-button @if($currentStockEntry->amount == 0) disabled @endif"
@ -199,15 +199,16 @@
<i class="fas fa-utensils"></i> {{ $__t('All') }}
</a>
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
<a class="btn btn-success btn-sm product-open-button @if($currentStockEntry->amount < 1 || $currentStockEntry->amount == $currentStockEntry->amount_opened || $currentStockEntry->enable_tare_weight_handling == 1) disabled @endif"
<a class="btn btn-success btn-sm product-open-button @if($currentStockEntry->amount < $currentStockEntry->quick_consume_amount || $currentStockEntry->amount == $currentStockEntry->amount_opened || $currentStockEntry->enable_tare_weight_handling == 1) disabled @endif"
href="#"
data-toggle="tooltip"
data-placement="left"
title="{{ $__t('Mark %1$s of %2$s as open', '1 ' . $currentStockEntry->qu_unit_name, $currentStockEntry->product_name) }}"
title="{{ $__t('Mark %1$s of %2$s as open', $currentStockEntry->quick_consume_amount . ' ' . $currentStockEntry->qu_unit_name, $currentStockEntry->product_name) }}"
data-product-id="{{ $currentStockEntry->product_id }}"
data-product-name="{{ $currentStockEntry->product_name }}"
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}">
<i class="fas fa-box-open"></i> 1
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
data-open-amount="{{ $currentStockEntry->quick_consume_amount }}">
<i class="fas fa-box-open"></i> <span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</span>
</a>
@endif
<div class="dropdown d-inline-block">