mirror of
https://github.com/grocy/grocy.git
synced 2026-03-27 23:29:25 +01:00
Optimized product definition quantity unit handling
This commit is contained in:
parent
cf7df4bdf8
commit
487631397c
|
|
@ -10,6 +10,11 @@
|
|||
|
||||
### Stock
|
||||
|
||||
- Optimized product definition quantity unit handling:
|
||||
- As long as a product was not once in stock, the product options "Default quantity unit purchase", "Default quantity unit consume" and "Quantity unit for prices" can now be changed to any other unit
|
||||
- When necessary (means when no default quantity unit conversions apply), "1:1" product specific quantity unit conversion between the product's QU stock and the corresponding other unit will now be created automatically after editing a product (like already done when initially creating a product with different unit definitions)
|
||||
- For convenience, when changing a product's QU stock and when all other unit properties ("Default quantity unit purchase" etc.) are the same, they will now be changed in tandem (like already done when creating a new product and initially setting the product's QU stock)
|
||||
- (This should drastically improve the workflow of completing a product setup looked up via an external barcode lookup plugin)
|
||||
- Optimized the line plot markers color of the price history chart (product card) (thanks @DeepCoreSystem)
|
||||
- External barcode lookup plugin optimizations:
|
||||
- When an image URL without a file extension is returned, the file extension is now determined by the Content-Type header (if any) (thanks @jordy-u for the idea)
|
||||
|
|
|
|||
|
|
@ -195,12 +195,13 @@ class StockController extends BaseController
|
|||
{
|
||||
if ($args['productId'] == 'new')
|
||||
{
|
||||
$quantityunits = $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE');
|
||||
|
||||
return $this->renderPage($response, 'productform', [
|
||||
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name'),
|
||||
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
||||
'quantityunits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityunitsStock' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||
'referencedQuantityunits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityunitsAll' => $quantityunits,
|
||||
'quantityunitsReferenced' => $quantityunits,
|
||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'productgroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||
|
|
@ -217,9 +218,8 @@ class StockController extends BaseController
|
|||
'product' => $product,
|
||||
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
||||
'quantityunits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityunitsStock' => $this->getDatabase()->quantity_units()->where('id IN (SELECT to_qu_id FROM cache__quantity_unit_conversions_resolved WHERE product_id = :1) OR NOT EXISTS(SELECT 1 FROM stock_log WHERE product_id = :1)', $product->id)->orderBy('name', 'COLLATE NOCASE'),
|
||||
'referencedQuantityunits' => $this->getDatabase()->quantity_units()->where('active = 1')->where('id IN (SELECT to_qu_id FROM cache__quantity_unit_conversions_resolved WHERE product_id = :1)', $product->id)->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityunitsAll' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityunitsReferenced' => $this->getDatabase()->quantity_units()->where('id IN (SELECT to_qu_id FROM cache__quantity_unit_conversions_resolved WHERE product_id = :1) OR NOT EXISTS(SELECT 1 FROM stock_log WHERE product_id = :1)', $product->id)->orderBy('name', 'COLLATE NOCASE'),
|
||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'productgroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||
|
|
|
|||
|
|
@ -2470,3 +2470,6 @@ msgstr ""
|
|||
|
||||
msgid "List actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "After this product was once in stock and when the desired quantity unit cannot be selected here, first create a corresponding unit conversion"
|
||||
msgstr ""
|
||||
|
|
|
|||
66
migrations/0255.sql
Normal file
66
migrations/0255.sql
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
DROP TRIGGER products_default_qu_conversions;
|
||||
CREATE TRIGGER products_default_qu_conversions_INS AFTER INSERT ON products
|
||||
BEGIN
|
||||
-- Create product specific 1:1 conversions when QU stock != QU purchase/consume/price
|
||||
-- and when no default QU conversion apply
|
||||
|
||||
-- with qu_id_stock != qu_id_purchase
|
||||
INSERT INTO quantity_unit_conversions
|
||||
(from_qu_id, to_qu_id, factor, product_id)
|
||||
SELECT p.qu_id_purchase, p.qu_id_stock, 1, p.id
|
||||
FROM products p
|
||||
WHERE p.id = NEW.id
|
||||
AND p.qu_id_stock != qu_id_purchase
|
||||
AND NOT EXISTS(SELECT 1 FROM quantity_unit_conversions_resolved WHERE product_id = p.id AND from_qu_id = p.qu_id_stock AND to_qu_id = p.qu_id_purchase);
|
||||
|
||||
-- with qu_id_stock != qu_id_consume
|
||||
INSERT INTO quantity_unit_conversions
|
||||
(from_qu_id, to_qu_id, factor, product_id)
|
||||
SELECT p.qu_id_consume, p.qu_id_stock, 1, p.id
|
||||
FROM products p
|
||||
WHERE p.id = NEW.id
|
||||
AND p.qu_id_stock != qu_id_consume
|
||||
AND NOT EXISTS(SELECT 1 FROM quantity_unit_conversions_resolved WHERE product_id = p.id AND from_qu_id = p.qu_id_stock AND to_qu_id = p.qu_id_consume);
|
||||
|
||||
-- with qu_id_stock != qu_id_price
|
||||
INSERT INTO quantity_unit_conversions
|
||||
(from_qu_id, to_qu_id, factor, product_id)
|
||||
SELECT p.qu_id_price, p.qu_id_stock, 1, p.id
|
||||
FROM products p
|
||||
WHERE p.id = NEW.id
|
||||
AND p.qu_id_stock != qu_id_price
|
||||
AND NOT EXISTS(SELECT 1 FROM quantity_unit_conversions_resolved WHERE product_id = p.id AND from_qu_id = p.qu_id_stock AND to_qu_id = p.qu_id_price);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER products_default_qu_conversions_UPD AFTER UPDATE ON products
|
||||
BEGIN
|
||||
-- Create product specific 1:1 conversions when QU stock != QU purchase/consume/price
|
||||
-- and when no default QU conversion apply
|
||||
|
||||
-- with qu_id_stock != qu_id_purchase
|
||||
INSERT INTO quantity_unit_conversions
|
||||
(from_qu_id, to_qu_id, factor, product_id)
|
||||
SELECT p.qu_id_purchase, p.qu_id_stock, 1, p.id
|
||||
FROM products p
|
||||
WHERE p.id = NEW.id
|
||||
AND p.qu_id_stock != qu_id_purchase
|
||||
AND NOT EXISTS(SELECT 1 FROM quantity_unit_conversions_resolved WHERE product_id = p.id AND from_qu_id = p.qu_id_stock AND to_qu_id = p.qu_id_purchase);
|
||||
|
||||
-- with qu_id_stock != qu_id_consume
|
||||
INSERT INTO quantity_unit_conversions
|
||||
(from_qu_id, to_qu_id, factor, product_id)
|
||||
SELECT p.qu_id_consume, p.qu_id_stock, 1, p.id
|
||||
FROM products p
|
||||
WHERE p.id = NEW.id
|
||||
AND p.qu_id_stock != qu_id_consume
|
||||
AND NOT EXISTS(SELECT 1 FROM quantity_unit_conversions_resolved WHERE product_id = p.id AND from_qu_id = p.qu_id_stock AND to_qu_id = p.qu_id_consume);
|
||||
|
||||
-- with qu_id_stock != qu_id_price
|
||||
INSERT INTO quantity_unit_conversions
|
||||
(from_qu_id, to_qu_id, factor, product_id)
|
||||
SELECT p.qu_id_price, p.qu_id_stock, 1, p.id
|
||||
FROM products p
|
||||
WHERE p.id = NEW.id
|
||||
AND p.qu_id_stock != qu_id_price
|
||||
AND NOT EXISTS(SELECT 1 FROM quantity_unit_conversions_resolved WHERE product_id = p.id AND from_qu_id = p.qu_id_stock AND to_qu_id = p.qu_id_price);
|
||||
END;
|
||||
|
|
@ -352,29 +352,33 @@ $(document).on('click', '.barcode-delete-button', function(e)
|
|||
});
|
||||
});
|
||||
|
||||
var quIdStockBefore = $("#qu_id_stock").val();
|
||||
$('#qu_id_stock').change(function(e)
|
||||
{
|
||||
// Preset qu_id_purchase/qu_id_consume/qu_id_price by qu_id_stock if unset
|
||||
// Preset qu_id_purchase / qu_id_consume / qu_id_price by qu_id_stock if unset or identical
|
||||
|
||||
var quIdStock = $('#qu_id_stock');
|
||||
var quIdPurchase = $('#qu_id_purchase');
|
||||
var quIdConsume = $('#qu_id_consume');
|
||||
var quIdPrice = $('#qu_id_price');
|
||||
|
||||
if (quIdPurchase[0].selectedIndex === 0 && quIdStock[0].selectedIndex !== 0)
|
||||
if (quIdPurchase[0].selectedIndex === 0 && quIdStock[0].selectedIndex !== 0 || quIdStockBefore == quIdPurchase.val())
|
||||
{
|
||||
quIdPurchase[0].selectedIndex = quIdStock[0].selectedIndex;
|
||||
}
|
||||
|
||||
if (quIdConsume[0].selectedIndex === 0 && quIdStock[0].selectedIndex !== 0)
|
||||
if (quIdConsume[0].selectedIndex === 0 && quIdStock[0].selectedIndex !== 0 || quIdStockBefore == quIdConsume.val())
|
||||
{
|
||||
quIdConsume[0].selectedIndex = quIdStock[0].selectedIndex;
|
||||
}
|
||||
|
||||
if (quIdPrice[0].selectedIndex === 0 && quIdStock[0].selectedIndex !== 0)
|
||||
if (quIdPrice[0].selectedIndex === 0 && quIdStock[0].selectedIndex !== 0 || quIdStockBefore == quIdPrice.val())
|
||||
{
|
||||
quIdPrice[0].selectedIndex = quIdStock[0].selectedIndex;
|
||||
}
|
||||
|
||||
quIdStockBefore = quIdStock.val();
|
||||
|
||||
Grocy.FrontendHelpers.ValidateForm('product-form');
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -371,15 +371,19 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="qu_id_stock">{{ $__t('Quantity unit stock') }}</label>
|
||||
<i class="fa-solid fa-question-circle text-muted"
|
||||
data-toggle="tooltip"
|
||||
data-trigger="hover click"
|
||||
title="{{ $__t('After this product was once in stock and when the desired quantity unit cannot be selected here, first create a corresponding unit conversion') }}"></i>
|
||||
<select required
|
||||
class="custom-control custom-select input-group-qu"
|
||||
id="qu_id_stock"
|
||||
name="qu_id_stock">
|
||||
<option></option>
|
||||
@foreach($quantityunitsStock as $quantityunit)
|
||||
@foreach($quantityunitsReferenced as $qu)
|
||||
<option @if($mode=='edit'
|
||||
&&
|
||||
$quantityunit->id == $product->qu_id_stock) selected="selected" @endif value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">{{ $quantityunit->name }}</option>
|
||||
$qu->id == $product->qu_id_stock) selected="selected" @endif value="{{ $qu->id }}" data-plural-form="{{ $qu->name_plural }}">{{ $qu->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
||||
|
|
@ -396,10 +400,10 @@
|
|||
id="qu_id_purchase"
|
||||
name="qu_id_purchase">
|
||||
<option></option>
|
||||
@foreach($referencedQuantityunits as $quantityunit)
|
||||
@foreach($quantityunitsReferenced as $qu)
|
||||
<option @if($mode=='edit'
|
||||
&&
|
||||
$quantityunit->id == $product->qu_id_purchase) selected="selected" @endif value="{{ $quantityunit->id }}">{{ $quantityunit->name }}</option>
|
||||
$qu->id == $product->qu_id_purchase) selected="selected" @endif value="{{ $qu->id }}">{{ $qu->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
||||
|
|
@ -416,10 +420,10 @@
|
|||
id="qu_id_consume"
|
||||
name="qu_id_consume">
|
||||
<option></option>
|
||||
@foreach($referencedQuantityunits as $quantityunit)
|
||||
@foreach($quantityunitsReferenced as $qu)
|
||||
<option @if($mode=='edit'
|
||||
&&
|
||||
$quantityunit->id == $product->qu_id_consume) selected="selected" @endif value="{{ $quantityunit->id }}">{{ $quantityunit->name }}</option>
|
||||
$qu->id == $product->qu_id_consume) selected="selected" @endif value="{{ $qu->id }}">{{ $qu->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
||||
|
|
@ -436,10 +440,10 @@
|
|||
id="qu_id_price"
|
||||
name="qu_id_price">
|
||||
<option></option>
|
||||
@foreach($referencedQuantityunits as $quantityunit)
|
||||
@foreach($quantityunitsReferenced as $qu)
|
||||
<option @if($mode=='edit'
|
||||
&&
|
||||
$quantityunit->id == $product->qu_id_price) selected="selected" @endif value="{{ $quantityunit->id }}">{{ $quantityunit->name }}</option>
|
||||
$qu->id == $product->qu_id_price) selected="selected" @endif value="{{ $qu->id }}">{{ $qu->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
||||
|
|
@ -762,7 +766,7 @@
|
|||
</td>
|
||||
<td>
|
||||
@if(!empty($barcode->qu_id))
|
||||
{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $barcode->qu_id)->name }}
|
||||
{{ FindObjectInArrayByPropertyValue($quantityunitsAll, 'id', $barcode->qu_id)->name }}
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
|
|
@ -886,16 +890,16 @@
|
|||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->from_qu_id)->name }}
|
||||
{{ FindObjectInArrayByPropertyValue($quantityunitsAll, 'id', $quConversion->from_qu_id)->name }}
|
||||
</td>
|
||||
<td>
|
||||
{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name }}
|
||||
{{ FindObjectInArrayByPropertyValue($quantityunitsAll, 'id', $quConversion->to_qu_id)->name }}
|
||||
</td>
|
||||
<td>
|
||||
<span class="locale-number locale-number-quantity-amount">{{ $quConversion->factor }}</span>
|
||||
</td>
|
||||
<td class="font-italic">
|
||||
{!! $__t('This means 1 %1$s is the same as %2$s %3$s', FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->from_qu_id)->name, '<span class="locale-number locale-number-quantity-amount">' . $quConversion->factor . '</span>', $__n($quConversion->factor, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name_plural, true)) !!}
|
||||
{!! $__t('This means 1 %1$s is the same as %2$s %3$s', FindObjectInArrayByPropertyValue($quantityunitsAll, 'id', $quConversion->from_qu_id)->name, '<span class="locale-number locale-number-quantity-amount">' . $quConversion->factor . '</span>', $__n($quConversion->factor, FindObjectInArrayByPropertyValue($quantityunitsAll, 'id', $quConversion->to_qu_id)->name, FindObjectInArrayByPropertyValue($quantityunitsAll, 'id', $quConversion->to_qu_id)->name_plural, true)) !!}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user