mirror of
https://github.com/grocy/grocy.git
synced 2025-07-12 18:27:15 +00:00
Make the quick consume buttons on the stock overview page configurable per product (closes #613)
This commit is contained in:
parent
17ae7e3d0c
commit
1d1642b464
@ -31,6 +31,7 @@ _- (Because the stock quantity unit is now the base for everything, it cannot be
|
|||||||
### Stock improvements/fixes
|
### Stock improvements/fixes
|
||||||
- When creating a quantity unit conversion it's now possible to automatically create the inverse conversion (thanks @kriddles)
|
- 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))
|
- 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)
|
- 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)
|
- 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)
|
- 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)
|
||||||
|
@ -142,7 +142,7 @@ class StockController extends BaseController
|
|||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||||
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
'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,
|
'isSubProductOfOthers' => false,
|
||||||
'mode' => 'create'
|
'mode' => 'create'
|
||||||
]);
|
]);
|
||||||
@ -159,7 +159,7 @@ class StockController extends BaseController
|
|||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||||
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
'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,
|
'isSubProductOfOthers' => $this->getDatabase()->products()->where('parent_product_id = :1', $product->id)->count() !== 0,
|
||||||
'mode' => 'edit',
|
'mode' => 'edit',
|
||||||
'quConversions' => $this->getDatabase()->quantity_unit_conversions()
|
'quConversions' => $this->getDatabase()->quantity_unit_conversions()
|
||||||
|
@ -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"
|
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 ""
|
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 ""
|
||||||
|
@ -68,6 +68,7 @@ CREATE TABLE products (
|
|||||||
parent_product_id INT,
|
parent_product_id INT,
|
||||||
calories INTEGER,
|
calories INTEGER,
|
||||||
cumulate_min_stock_amount_of_sub_products TINYINT DEFAULT 0,
|
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'))
|
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;
|
) NOTNULL) THEN RAISE(ABORT, "qu_id_stock cannot be changed when the product was once added to stock") END;
|
||||||
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;
|
DROP VIEW stock_current_location_content;
|
||||||
CREATE VIEW stock_current_location_content
|
CREATE VIEW stock_current_location_content
|
||||||
AS
|
AS
|
||||||
|
@ -22,7 +22,8 @@ SELECT
|
|||||||
sc.amount_aggregated,
|
sc.amount_aggregated,
|
||||||
p.calories AS product_calories,
|
p.calories AS product_calories,
|
||||||
sc.amount * p.calories AS 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 (
|
FROM (
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM stock_current
|
FROM stock_current
|
||||||
@ -59,7 +60,8 @@ SELECT
|
|||||||
sc.amount_aggregated,
|
sc.amount_aggregated,
|
||||||
p.calories AS product_calories,
|
p.calories AS product_calories,
|
||||||
sc.amount * p.calories AS 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 (
|
FROM (
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM stock_current
|
FROM stock_current
|
||||||
|
@ -185,6 +185,7 @@ $('.input-group-qu').on('change', function(e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
$("#tare_weight_qu_info").text($("#qu_id_stock option:selected").text());
|
$("#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');
|
Grocy.FrontendHelpers.ValidateForm('product-form');
|
||||||
});
|
});
|
||||||
|
@ -162,9 +162,10 @@ $(document).on('click', '.product-open-button', function(e)
|
|||||||
var productId = $(e.currentTarget).attr('data-product-id');
|
var productId = $(e.currentTarget).attr('data-product-id');
|
||||||
var productName = $(e.currentTarget).attr('data-product-name');
|
var productName = $(e.currentTarget).attr('data-product-name');
|
||||||
var productQuName = $(e.currentTarget).attr('data-product-qu-name');
|
var productQuName = $(e.currentTarget).attr('data-product-qu-name');
|
||||||
|
var amount = $(e.currentTarget).attr('data-open-amount');
|
||||||
var button = $(e.currentTarget);
|
var button = $(e.currentTarget);
|
||||||
|
|
||||||
Grocy.Api.Post('stock/products/' + productId + '/open', { 'amount': 1 },
|
Grocy.Api.Post('stock/products/' + productId + '/open', { 'amount': amount },
|
||||||
function(bookingResponse)
|
function(bookingResponse)
|
||||||
{
|
{
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
@ -176,7 +177,7 @@ $(document).on('click', '.product-open-button', function(e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy();
|
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();
|
RefreshStatistics();
|
||||||
RefreshProductRow(productId);
|
RefreshProductRow(productId);
|
||||||
},
|
},
|
||||||
|
@ -351,6 +351,17 @@
|
|||||||
value="0">
|
value="0">
|
||||||
@endif
|
@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(
|
@include('components.userfieldsform', array(
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'entity' => 'products'
|
'entity' => 'products'
|
||||||
|
@ -174,16 +174,16 @@
|
|||||||
<tr id="product-{{ $currentStockEntry->product_id }}-row"
|
<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">
|
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">
|
<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="#"
|
href="#"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
data-placement="left"
|
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-id="{{ $currentStockEntry->product_id }}"
|
||||||
data-product-name="{{ $currentStockEntry->product_name }}"
|
data-product-name="{{ $currentStockEntry->product_name }}"
|
||||||
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
||||||
data-consume-amount="1">
|
data-consume-amount="{{ $currentStockEntry->quick_consume_amount }}">
|
||||||
<i class="fas fa-utensils"></i> 1
|
<i class="fas fa-utensils"></i> <span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a id="product-{{ $currentStockEntry->product_id }}-consume-all-button"
|
<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"
|
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') }}
|
<i class="fas fa-utensils"></i> {{ $__t('All') }}
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
@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="#"
|
href="#"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
data-placement="left"
|
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-id="{{ $currentStockEntry->product_id }}"
|
||||||
data-product-name="{{ $currentStockEntry->product_name }}"
|
data-product-name="{{ $currentStockEntry->product_name }}"
|
||||||
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}">
|
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
||||||
<i class="fas fa-box-open"></i> 1
|
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>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<div class="dropdown d-inline-block">
|
<div class="dropdown d-inline-block">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user