mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 09:39:57 +00:00
Allow optional partial units of products in stock (closes #123)
This commit is contained in:
parent
9e139e2b73
commit
dfc05e0bec
@ -981,7 +981,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"amount": {
|
||||
"type": "integer"
|
||||
"type": "double"
|
||||
},
|
||||
"best_before_date": {
|
||||
"type": "string",
|
||||
@ -1056,7 +1056,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"amount": {
|
||||
"type": "integer",
|
||||
"type": "double",
|
||||
"description": "The amount to remove"
|
||||
},
|
||||
"transaction_type": {
|
||||
@ -1191,7 +1191,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"amount": {
|
||||
"type": "integer",
|
||||
"type": "double",
|
||||
"description": "The amount to mark as opened"
|
||||
},
|
||||
"stock_entry_id": {
|
||||
@ -1870,6 +1870,9 @@
|
||||
"picture_file_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"allow_partial_units_in_stock": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"row_created_timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
@ -1925,7 +1928,7 @@
|
||||
"type": "integer"
|
||||
},
|
||||
"amount": {
|
||||
"type": "integer"
|
||||
"type": "double"
|
||||
},
|
||||
"best_before_date": {
|
||||
"type": "string",
|
||||
@ -2176,7 +2179,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"amount": {
|
||||
"type": "integer",
|
||||
"type": "double",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"description": "The manual entered amount"
|
||||
@ -2289,7 +2292,7 @@
|
||||
"type": "integer"
|
||||
},
|
||||
"amount": {
|
||||
"type": "integer"
|
||||
"type": "double"
|
||||
},
|
||||
"best_before_date": {
|
||||
"type": "string",
|
||||
@ -2345,7 +2348,7 @@
|
||||
"type": "integer"
|
||||
},
|
||||
"amount": {
|
||||
"type": "integer"
|
||||
"type": "double"
|
||||
},
|
||||
"best_before_date": {
|
||||
"type": "string",
|
||||
|
69
migrations/0049.sql
Normal file
69
migrations/0049.sql
Normal file
@ -0,0 +1,69 @@
|
||||
ALTER TABLE products
|
||||
ADD allow_partial_units_in_stock TINYINT NOT NULL DEFAULT 0;
|
||||
|
||||
PRAGMA legacy_alter_table = ON;
|
||||
|
||||
ALTER TABLE stock RENAME TO stock_old;
|
||||
|
||||
CREATE TABLE stock (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
product_id INTEGER NOT NULL,
|
||||
amount DECIMAL(15, 2) NOT NULL,
|
||||
best_before_date DATE,
|
||||
purchased_date DATE DEFAULT (datetime('now', 'localtime')),
|
||||
stock_id TEXT NOT NULL,
|
||||
price DECIMAL(15, 2),
|
||||
open TINYINT NOT NULL DEFAULT 0 CHECK(open IN (0, 1)),
|
||||
opened_date DATETIME,
|
||||
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||
);
|
||||
|
||||
INSERT INTO stock
|
||||
(product_id, amount, best_before_date, purchased_date, stock_id, price, open, opened_date, row_created_timestamp)
|
||||
SELECT product_id, amount, best_before_date, purchased_date, stock_id, price, open, opened_date, row_created_timestamp
|
||||
FROM stock_old;
|
||||
|
||||
DROP TABLE stock_old;
|
||||
|
||||
ALTER TABLE stock_log RENAME TO stock_log_old;
|
||||
|
||||
CREATE TABLE stock_log (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
product_id INTEGER NOT NULL,
|
||||
amount DECIMAL(15, 2) NOT NULL,
|
||||
best_before_date DATE,
|
||||
purchased_date DATE,
|
||||
used_date DATE,
|
||||
spoiled INTEGER NOT NULL DEFAULT 0,
|
||||
stock_id TEXT NOT NULL,
|
||||
transaction_type TEXT NOT NULL,
|
||||
price DECIMAL(15, 2),
|
||||
undone TINYINT NOT NULL DEFAULT 0 CHECK(undone IN (0, 1)),
|
||||
undone_timestamp DATETIME,
|
||||
opened_date DATETIME,
|
||||
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||
);
|
||||
|
||||
INSERT INTO stock_log
|
||||
(product_id, amount, best_before_date, purchased_date, used_date, spoiled, stock_id, transaction_type, price, undone, undone_timestamp, opened_date, row_created_timestamp)
|
||||
SELECT product_id, amount, best_before_date, purchased_date, used_date, spoiled, stock_id, transaction_type, price, undone, undone_timestamp, opened_date, row_created_timestamp
|
||||
FROM stock_log_old;
|
||||
|
||||
DROP TABLE stock_log_old;
|
||||
|
||||
ALTER TABLE shopping_list RENAME TO shopping_list_old;
|
||||
|
||||
CREATE TABLE shopping_list (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
product_id INTEGER,
|
||||
note TEXT,
|
||||
amount DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
||||
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||
);
|
||||
|
||||
INSERT INTO shopping_list
|
||||
(product_id, amount, note, row_created_timestamp)
|
||||
SELECT product_id, amount, note, row_created_timestamp
|
||||
FROM shopping_list_old;
|
||||
|
||||
DROP TABLE shopping_list_old;
|
@ -133,6 +133,19 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||
$('#amount').attr('max', productDetails.stock_amount);
|
||||
$('#amount_qu_unit').text(productDetails.quantity_unit_stock.name);
|
||||
|
||||
if (productDetails.product.allow_partial_units_in_stock == 1)
|
||||
{
|
||||
$("#amount").attr("min", "0.01");
|
||||
$("#amount").attr("step", "0.01");
|
||||
$("#amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', 0.01.toLocaleString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#amount").attr("min", "1");
|
||||
$("#amount").attr("step", "1");
|
||||
$("#amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', '1'));
|
||||
}
|
||||
|
||||
if ((productDetails.stock_amount || 0) === 0)
|
||||
{
|
||||
Grocy.Components.ProductPicker.SetValue('');
|
||||
|
@ -83,6 +83,19 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||
$('#new_amount').attr('not-equal', productDetails.stock_amount);
|
||||
$('#new_amount_qu_unit').text(productDetails.quantity_unit_stock.name);
|
||||
|
||||
if (productDetails.product.allow_partial_units_in_stock == 1)
|
||||
{
|
||||
$("#new_amount").attr("min", "0.01");
|
||||
$("#new_amount").attr("step", "0.01");
|
||||
$("#new_amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', 0.01.toLocaleString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#new_amount").attr("min", "1");
|
||||
$("#new_amount").attr("step", "1");
|
||||
$("#new_amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', '1'));
|
||||
}
|
||||
|
||||
$('#new_amount').focus();
|
||||
},
|
||||
function(xhr)
|
||||
|
@ -9,7 +9,7 @@
|
||||
redirectDestination = returnTo + '?createdproduct=' + encodeURIComponent($('#name').val());
|
||||
}
|
||||
|
||||
var jsonData = $('#product-form').serializeJSON();
|
||||
var jsonData = $('#product-form').serializeJSON({ checkboxUncheckedValue: "0" });
|
||||
Grocy.FrontendHelpers.BeginUiBusy("product-form");
|
||||
|
||||
if ($("#product-picture")[0].files.length > 0)
|
||||
|
@ -100,6 +100,19 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||
$('#amount_qu_unit').text(productDetails.quantity_unit_purchase.name);
|
||||
$('#price').val(productDetails.last_price);
|
||||
|
||||
if (productDetails.product.allow_partial_units_in_stock == 1)
|
||||
{
|
||||
$("#amount").attr("min", "0.01");
|
||||
$("#amount").attr("step", "0.01");
|
||||
$("#amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', 0.01.toLocaleString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#amount").attr("min", "1");
|
||||
$("#amount").attr("step", "1");
|
||||
$("#amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', '1'));
|
||||
}
|
||||
|
||||
if (productDetails.product.default_best_before_days.toString() !== '0')
|
||||
{
|
||||
if (productDetails.product.default_best_before_days == -1)
|
||||
|
@ -52,6 +52,20 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||
{
|
||||
$("#qu_id").val(productDetails.quantity_unit_stock.id);
|
||||
}
|
||||
|
||||
if (productDetails.product.allow_partial_units_in_stock == 1)
|
||||
{
|
||||
$("#amount").attr("min", "0.01");
|
||||
$("#amount").attr("step", "0.01");
|
||||
$("#amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', 0.01.toLocaleString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#amount").attr("min", "1");
|
||||
$("#amount").attr("step", "1");
|
||||
$("#amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', '1'));
|
||||
}
|
||||
|
||||
$('#amount').focus();
|
||||
Grocy.FrontendHelpers.ValidateForm('recipe-pos-form');
|
||||
},
|
||||
|
@ -47,6 +47,20 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||
function (productDetails)
|
||||
{
|
||||
$('#amount_qu_unit').text(productDetails.quantity_unit_purchase.name);
|
||||
|
||||
if (productDetails.product.allow_partial_units_in_stock == 1)
|
||||
{
|
||||
$("#amount").attr("min", "0.01");
|
||||
$("#amount").attr("step", "0.01");
|
||||
$("#amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', 0.01.toLocaleString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#amount").attr("min", "1");
|
||||
$("#amount").attr("step", "1");
|
||||
$("#amount").parent().find(".invalid-feedback").text(L('The amount cannot be lower than #1', '1'));
|
||||
}
|
||||
|
||||
$('#amount').focus();
|
||||
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
||||
},
|
||||
|
@ -109,7 +109,7 @@ class StockService extends BaseService
|
||||
}
|
||||
}
|
||||
|
||||
public function AddProduct(int $productId, int $amount, string $bestBeforeDate, $transactionType, $purchasedDate, $price)
|
||||
public function AddProduct(int $productId, float $amount, string $bestBeforeDate, $transactionType, $purchasedDate, $price)
|
||||
{
|
||||
if (!$this->ProductExists($productId))
|
||||
{
|
||||
@ -151,7 +151,7 @@ class StockService extends BaseService
|
||||
}
|
||||
}
|
||||
|
||||
public function ConsumeProduct(int $productId, int $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default')
|
||||
public function ConsumeProduct(int $productId, float $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default')
|
||||
{
|
||||
if (!$this->ProductExists($productId))
|
||||
{
|
||||
@ -258,7 +258,7 @@ class StockService extends BaseService
|
||||
return $this->Database->lastInsertId();
|
||||
}
|
||||
|
||||
public function OpenProduct(int $productId, int $amount, $specificStockEntryId = 'default')
|
||||
public function OpenProduct(int $productId, float $amount, $specificStockEntryId = 'default')
|
||||
{
|
||||
if (!$this->ProductExists($productId))
|
||||
{
|
||||
|
@ -126,6 +126,14 @@
|
||||
'additionalHtmlElements' => '<p id="qu-conversion-info" class="form-text text-muted small d-none"></p>'
|
||||
))
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input type="hidden" name="allow_partial_units_in_stock" value="0">
|
||||
<input @if($mode == 'edit' && $product->allow_partial_units_in_stock == 1) checked @endif class="form-check-input" type="checkbox" id="allow_partial_units_in_stock" name="allow_partial_units_in_stock" value="1">
|
||||
<label class="form-check-label" for="allow_partial_units_in_stock">{{ $L('Allow partial units in stock') }}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="product-picture">{{ $L('Product picture') }}</label>
|
||||
<div class="custom-file">
|
||||
|
Loading…
x
Reference in New Issue
Block a user