mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 09:39:57 +00:00
Implemented notes and Userfields for stock entries (closes #443)
This commit is contained in:
parent
2983687f34
commit
d3a39270de
@ -2,6 +2,17 @@
|
|||||||
|
|
||||||
> ❗ xxxImportant upgrade informationXXX
|
> ❗ xxxImportant upgrade informationXXX
|
||||||
|
|
||||||
|
### New feature: Notes and Userfields for stock entries
|
||||||
|
|
||||||
|
- Stock entries can now have notes
|
||||||
|
- For example to distinguish between same, yet different products (e.g. having only a generic product "Chocolate" and note in that field what special one it is exactly this time)
|
||||||
|
- => New field on the purchase and inventory page
|
||||||
|
- => New column on the stock entries and stock journal page
|
||||||
|
- => Visible also in the "Use a specific stock item" dropdown on the consume and transfer page
|
||||||
|
- Additionally it's also possible to add arbitrary own fields by using Userfields
|
||||||
|
- => Configure the desired Userfields for the entity `stock`
|
||||||
|
- => Those Userfields are then visible on the same places as mentioned above for the built-in "Note" field
|
||||||
|
|
||||||
### New feature: Recipes "Due score"
|
### New feature: Recipes "Due score"
|
||||||
|
|
||||||
- A number (new column on the recipes page) which represents a score which is higher the more ingredients, of the corresponding recipe, currently in stock are due soon, overdue or already expired
|
- A number (new column on the recipes page) which represents a score which is higher the more ingredients, of the corresponding recipe, currently in stock are due soon, overdue or already expired
|
||||||
|
@ -100,42 +100,36 @@ class StockApiController extends BaseApiController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$bestBeforeDate = null;
|
$bestBeforeDate = null;
|
||||||
|
|
||||||
if (array_key_exists('best_before_date', $requestBody) && IsIsoDate($requestBody['best_before_date']))
|
if (array_key_exists('best_before_date', $requestBody) && IsIsoDate($requestBody['best_before_date']))
|
||||||
{
|
{
|
||||||
$bestBeforeDate = $requestBody['best_before_date'];
|
$bestBeforeDate = $requestBody['best_before_date'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$purchasedDate = date('Y-m-d');
|
$purchasedDate = date('Y-m-d');
|
||||||
|
|
||||||
if (array_key_exists('purchased_date', $requestBody) && IsIsoDate($requestBody['purchased_date']))
|
if (array_key_exists('purchased_date', $requestBody) && IsIsoDate($requestBody['purchased_date']))
|
||||||
{
|
{
|
||||||
$purchasedDate = $requestBody['purchased_date'];
|
$purchasedDate = $requestBody['purchased_date'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$price = null;
|
$price = null;
|
||||||
|
|
||||||
if (array_key_exists('price', $requestBody) && is_numeric($requestBody['price']))
|
if (array_key_exists('price', $requestBody) && is_numeric($requestBody['price']))
|
||||||
{
|
{
|
||||||
$price = $requestBody['price'];
|
$price = $requestBody['price'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$locationId = null;
|
$locationId = null;
|
||||||
|
|
||||||
if (array_key_exists('location_id', $requestBody) && is_numeric($requestBody['location_id']))
|
if (array_key_exists('location_id', $requestBody) && is_numeric($requestBody['location_id']))
|
||||||
{
|
{
|
||||||
$locationId = $requestBody['location_id'];
|
$locationId = $requestBody['location_id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$shoppingLocationId = null;
|
$shoppingLocationId = null;
|
||||||
|
|
||||||
if (array_key_exists('shopping_location_id', $requestBody) && is_numeric($requestBody['shopping_location_id']))
|
if (array_key_exists('shopping_location_id', $requestBody) && is_numeric($requestBody['shopping_location_id']))
|
||||||
{
|
{
|
||||||
$shoppingLocationId = $requestBody['shopping_location_id'];
|
$shoppingLocationId = $requestBody['shopping_location_id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
|
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
|
||||||
|
|
||||||
if (array_key_exists('transaction_type', $requestBody) && !empty($requestBody['transactiontype']))
|
if (array_key_exists('transaction_type', $requestBody) && !empty($requestBody['transactiontype']))
|
||||||
{
|
{
|
||||||
$transactionType = $requestBody['transactiontype'];
|
$transactionType = $requestBody['transactiontype'];
|
||||||
@ -147,7 +141,13 @@ class StockApiController extends BaseApiController
|
|||||||
$stockLabelType = intval($requestBody['stock_label_type']);
|
$stockLabelType = intval($requestBody['stock_label_type']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$transactionId = $this->getStockService()->AddProduct($args['productId'], $requestBody['amount'], $bestBeforeDate, $transactionType, $purchasedDate, $price, $locationId, $shoppingLocationId, $unusedTransactionId, $stockLabelType);
|
$note = null;
|
||||||
|
if (array_key_exists('note', $requestBody))
|
||||||
|
{
|
||||||
|
$note = $requestBody['note'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$transactionId = $this->getStockService()->AddProduct($args['productId'], $requestBody['amount'], $bestBeforeDate, $transactionType, $purchasedDate, $price, $locationId, $shoppingLocationId, $unusedTransactionId, $stockLabelType, false, $note);
|
||||||
|
|
||||||
$args['transactionId'] = $transactionId;
|
$args['transactionId'] = $transactionId;
|
||||||
return $this->StockTransactions($request, $response, $args);
|
return $this->StockTransactions($request, $response, $args);
|
||||||
@ -394,34 +394,36 @@ class StockApiController extends BaseApiController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$bestBeforeDate = null;
|
$bestBeforeDate = null;
|
||||||
|
|
||||||
if (array_key_exists('best_before_date', $requestBody) && IsIsoDate($requestBody['best_before_date']))
|
if (array_key_exists('best_before_date', $requestBody) && IsIsoDate($requestBody['best_before_date']))
|
||||||
{
|
{
|
||||||
$bestBeforeDate = $requestBody['best_before_date'];
|
$bestBeforeDate = $requestBody['best_before_date'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$price = null;
|
$price = null;
|
||||||
|
|
||||||
if (array_key_exists('price', $requestBody) && is_numeric($requestBody['price']))
|
if (array_key_exists('price', $requestBody) && is_numeric($requestBody['price']))
|
||||||
{
|
{
|
||||||
$price = $requestBody['price'];
|
$price = $requestBody['price'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$locationId = null;
|
$locationId = null;
|
||||||
|
|
||||||
if (array_key_exists('location_id', $requestBody) && is_numeric($requestBody['location_id']))
|
if (array_key_exists('location_id', $requestBody) && is_numeric($requestBody['location_id']))
|
||||||
{
|
{
|
||||||
$locationId = $requestBody['location_id'];
|
$locationId = $requestBody['location_id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$shoppingLocationId = null;
|
$shoppingLocationId = null;
|
||||||
|
|
||||||
if (array_key_exists('shopping_location_id', $requestBody) && is_numeric($requestBody['shopping_location_id']))
|
if (array_key_exists('shopping_location_id', $requestBody) && is_numeric($requestBody['shopping_location_id']))
|
||||||
{
|
{
|
||||||
$shoppingLocationId = $requestBody['shopping_location_id'];
|
$shoppingLocationId = $requestBody['shopping_location_id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$transactionId = $this->getStockService()->EditStockEntry($args['entryId'], $requestBody['amount'], $bestBeforeDate, $locationId, $shoppingLocationId, $price, $requestBody['open'], $requestBody['purchased_date']);
|
$note = null;
|
||||||
|
if (array_key_exists('note', $requestBody))
|
||||||
|
{
|
||||||
|
$note = $requestBody['note'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$transactionId = $this->getStockService()->EditStockEntry($args['entryId'], $requestBody['amount'], $bestBeforeDate, $locationId, $shoppingLocationId, $price, $requestBody['open'], $requestBody['purchased_date'], $note);
|
||||||
$args['transactionId'] = $transactionId;
|
$args['transactionId'] = $transactionId;
|
||||||
return $this->StockTransactions($request, $response, $args);
|
return $this->StockTransactions($request, $response, $args);
|
||||||
}
|
}
|
||||||
@ -506,7 +508,13 @@ class StockApiController extends BaseApiController
|
|||||||
$stockLabelType = intval($requestBody['stock_label_type']);
|
$stockLabelType = intval($requestBody['stock_label_type']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$transactionId = $this->getStockService()->InventoryProduct($args['productId'], $requestBody['new_amount'], $bestBeforeDate, $locationId, $price, $shoppingLocationId, $purchasedDate, $stockLabelType);
|
$note = null;
|
||||||
|
if (array_key_exists('note', $requestBody))
|
||||||
|
{
|
||||||
|
$note = $requestBody['note'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$transactionId = $this->getStockService()->InventoryProduct($args['productId'], $requestBody['new_amount'], $bestBeforeDate, $locationId, $price, $shoppingLocationId, $purchasedDate, $stockLabelType, $note);
|
||||||
$args['transactionId'] = $transactionId;
|
$args['transactionId'] = $transactionId;
|
||||||
return $this->StockTransactions($request, $response, $args);
|
return $this->StockTransactions($request, $response, $args);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,8 @@ class StockController extends BaseController
|
|||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
||||||
|
'userfields' => $this->getUserfieldsService()->GetFields('stock')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +60,9 @@ class StockController extends BaseController
|
|||||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'users' => $usersService->GetUsersAsDto(),
|
'users' => $usersService->GetUsersAsDto(),
|
||||||
'transactionTypes' => GetClassConstants('\Grocy\Services\StockService', 'TRANSACTION_TYPE_')
|
'transactionTypes' => GetClassConstants('\Grocy\Services\StockService', 'TRANSACTION_TYPE_'),
|
||||||
|
'userfieldsStock' => $this->getUserfieldsService()->GetFields('stock'),
|
||||||
|
'userfieldValuesStock' => $this->getUserfieldsService()->GetAllValues('stock')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +264,8 @@ class StockController extends BaseController
|
|||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
||||||
|
'userfields' => $this->getUserfieldsService()->GetFields('stock')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,8 +502,10 @@ class StockController extends BaseController
|
|||||||
'stockEntries' => $this->getDatabase()->stock()->orderBy('product_id'),
|
'stockEntries' => $this->getDatabase()->stock()->orderBy('product_id'),
|
||||||
'currentStockLocations' => $this->getStockService()->GetCurrentStockLocations(),
|
'currentStockLocations' => $this->getStockService()->GetCurrentStockLocations(),
|
||||||
'nextXDays' => $nextXDays,
|
'nextXDays' => $nextXDays,
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
'userfieldsProducts' => $this->getUserfieldsService()->GetFields('products'),
|
||||||
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('products')
|
'userfieldValuesProducts' => $this->getUserfieldsService()->GetAllValues('products'),
|
||||||
|
'userfieldsStock' => $this->getUserfieldsService()->GetFields('stock'),
|
||||||
|
'userfieldValuesStock' => $this->getUserfieldsService()->GetAllValues('stock')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1911,6 +1911,10 @@
|
|||||||
"stock_label_type": {
|
"stock_label_type": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "`1` = No label, `2` = Single label, `3` = Label per unit"
|
"description": "`1` = No label, `2` = Single label, `3` = Label per unit"
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "An optional note for the corresponding stock entry"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
@ -2167,6 +2171,10 @@
|
|||||||
"stock_label_type": {
|
"stock_label_type": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "`1` = No label, `2` = Single label, `3` = Label per unit (only applies to added products)"
|
"description": "`1` = No label, `2` = Single label, `3` = Label per unit (only applies to added products)"
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "An optional note for the corresponding stock entry (only applies to added products)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4659,6 +4667,9 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date"
|
"format": "date"
|
||||||
},
|
},
|
||||||
|
"note": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"row_created_timestamp": {
|
"row_created_timestamp": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
@ -5286,6 +5297,9 @@
|
|||||||
"transaction_type": {
|
"transaction_type": {
|
||||||
"$ref": "#/components/schemas/StockTransactionType"
|
"$ref": "#/components/schemas/StockTransactionType"
|
||||||
},
|
},
|
||||||
|
"note": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"row_created_timestamp": {
|
"row_created_timestamp": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
|
100
migrations/0178.sql
Normal file
100
migrations/0178.sql
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
ALTER TABLE stock
|
||||||
|
ADD note TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE stock_log
|
||||||
|
ADD note TEXT;
|
||||||
|
|
||||||
|
PRAGMA legacy_alter_table = ON;
|
||||||
|
|
||||||
|
ALTER TABLE userfield_values RENAME TO userfield_values_old;
|
||||||
|
|
||||||
|
CREATE TABLE userfield_values (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
field_id INTEGER NOT NULL,
|
||||||
|
object_id TEXT NOT NULL,
|
||||||
|
value TEXT NOT NULL,
|
||||||
|
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
|
||||||
|
|
||||||
|
UNIQUE(field_id, object_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO userfield_values
|
||||||
|
(id, field_id, object_id, value, row_created_timestamp)
|
||||||
|
SELECT id, field_id, object_id, value, row_created_timestamp
|
||||||
|
FROM userfield_values_old;
|
||||||
|
|
||||||
|
DROP TABLE userfield_values_old;
|
||||||
|
|
||||||
|
CREATE TRIGGER userfield_values_special_handling AFTER INSERT ON userfield_values
|
||||||
|
BEGIN
|
||||||
|
-- Entity stock:
|
||||||
|
-- object_id is the transaction_id on insert -> replace it by the corresponding stock_id
|
||||||
|
INSERT OR REPLACE INTO userfield_values
|
||||||
|
(field_id, object_id, value)
|
||||||
|
SELECT uv.field_id, sl.stock_id, uv.value
|
||||||
|
FROM userfield_values uv
|
||||||
|
JOIN stock_log sl
|
||||||
|
ON uv.object_id = sl.transaction_id
|
||||||
|
AND sl.transaction_type IN ('purchase', 'inventory-correction')
|
||||||
|
WHERE uv.field_id IN (SELECT id FROM userfields WHERE entity = 'stock')
|
||||||
|
AND uv.field_id = NEW.field_id
|
||||||
|
AND uv.object_id = NEW.object_id;
|
||||||
|
|
||||||
|
DELETE FROM userfield_values
|
||||||
|
WHERE field_id IN (SELECT id FROM userfields WHERE entity = 'stock')
|
||||||
|
AND field_id = NEW.field_id
|
||||||
|
AND object_id = NEW.object_id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
DROP VIEW stock_splits;
|
||||||
|
CREATE VIEW stock_splits
|
||||||
|
AS
|
||||||
|
|
||||||
|
/*
|
||||||
|
Helper view which shows splitted stock rows which could be compacted
|
||||||
|
(a stock_id starting with "x" indicates that this entry shouldn't be compacted)
|
||||||
|
*/
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
product_id,
|
||||||
|
SUM(amount) AS total_amount,
|
||||||
|
MIN(stock_id) AS stock_id_to_keep,
|
||||||
|
MAX(id) AS id_to_keep,
|
||||||
|
GROUP_CONCAT(id) AS id_group,
|
||||||
|
GROUP_CONCAT(stock_id) AS stock_id_group,
|
||||||
|
id -- Dummy
|
||||||
|
FROM stock
|
||||||
|
WHERE stock_id NOT LIKE 'x%'
|
||||||
|
GROUP BY product_id, best_before_date, purchased_date, price, open, opened_date, location_id, shopping_location_id, IFNULL(note, '')
|
||||||
|
HAVING COUNT(*) > 1;
|
||||||
|
|
||||||
|
DROP VIEW uihelper_stock_journal;
|
||||||
|
CREATE VIEW uihelper_stock_journal
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
sl.id,
|
||||||
|
sl.row_created_timestamp,
|
||||||
|
sl.correlation_id,
|
||||||
|
sl.undone,
|
||||||
|
sl.undone_timestamp,
|
||||||
|
sl.transaction_type,
|
||||||
|
sl.spoiled,
|
||||||
|
sl.amount,
|
||||||
|
sl.location_id,
|
||||||
|
l.name AS location_name,
|
||||||
|
p.name AS product_name,
|
||||||
|
qu.name AS qu_name,
|
||||||
|
qu.name_plural AS qu_name_plural,
|
||||||
|
u.display_name AS user_display_name,
|
||||||
|
p.id AS product_id,
|
||||||
|
sl.note,
|
||||||
|
sl.stock_id
|
||||||
|
FROM stock_log sl
|
||||||
|
LEFT JOIN users_dto u
|
||||||
|
ON sl.user_id = u.id
|
||||||
|
JOIN products p
|
||||||
|
ON sl.product_id = p.id
|
||||||
|
JOIN locations l
|
||||||
|
ON sl.location_id = l.id
|
||||||
|
JOIN quantity_units qu
|
||||||
|
ON p.qu_id_stock = qu.id;
|
@ -171,6 +171,80 @@ Grocy.Components.UserfieldsForm.Load = function()
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Grocy.Components.UserfieldsForm.Clear = function()
|
||||||
|
{
|
||||||
|
if (!$("#userfields-form").length)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.Api.Get('objects/userfields?query[]=entity=' + $("#userfields-form").data("entity"),
|
||||||
|
function(result)
|
||||||
|
{
|
||||||
|
$.each(result, function(key, userfield)
|
||||||
|
{
|
||||||
|
var input = $(".userfield-input[data-userfield-name='" + userfield.name + "']");
|
||||||
|
|
||||||
|
if (input.attr("type") == "checkbox")
|
||||||
|
{
|
||||||
|
input.prop("checked", false);
|
||||||
|
}
|
||||||
|
else if (input.hasAttr("multiple"))
|
||||||
|
{
|
||||||
|
input.val("");
|
||||||
|
$(".selectpicker").selectpicker("render");
|
||||||
|
}
|
||||||
|
else if (input.attr('type') == "file")
|
||||||
|
{
|
||||||
|
var formGroup = input.parent().parent().parent();
|
||||||
|
|
||||||
|
formGroup.find("label.custom-file-label").text("");
|
||||||
|
formGroup.find(".userfield-file-show").attr('href', U('/files/userfiles/' + value));
|
||||||
|
formGroup.find('.userfield-file-show').removeClass('d-none');
|
||||||
|
formGroup.find('img.userfield-current-file')
|
||||||
|
.attr('src', U('/files/userfiles/' + value + '?force_serve_as=picture&best_fit_width=250&best_fit_height=250'));
|
||||||
|
LoadImagesLazy();
|
||||||
|
|
||||||
|
formGroup.find('.userfield-file-delete').click(
|
||||||
|
function()
|
||||||
|
{
|
||||||
|
formGroup.find("label.custom-file-label").text(__t("No file selected"));
|
||||||
|
formGroup.find(".userfield-file-show").addClass('d-none');
|
||||||
|
input.attr('data-old-file', "");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
input.on("change", function(e)
|
||||||
|
{
|
||||||
|
formGroup.find(".userfield-file-show").addClass('d-none');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (input.attr("data-userfield-type") == "link")
|
||||||
|
{
|
||||||
|
var formRow = input.parent().parent();
|
||||||
|
formRow.find(".userfield-link-title").val(data.title);
|
||||||
|
formRow.find(".userfield-link-link").val(data.link);
|
||||||
|
|
||||||
|
input.val("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
input.val("");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("form").each(function()
|
||||||
|
{
|
||||||
|
Grocy.FrontendHelpers.ValidateForm(this.id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$(".userfield-link").keyup(function(e)
|
$(".userfield-link").keyup(function(e)
|
||||||
{
|
{
|
||||||
var formRow = $(this).parent().parent();
|
var formRow = $(this).parent().parent();
|
||||||
|
@ -286,10 +286,16 @@ function OnLocationChange(locationId, stockId)
|
|||||||
{
|
{
|
||||||
if ($("#specific_stock_entry option[value='" + stockEntry.stock_id + "']").length == 0)
|
if ($("#specific_stock_entry option[value='" + stockEntry.stock_id + "']").length == 0)
|
||||||
{
|
{
|
||||||
|
var noteTxt = "";
|
||||||
|
if (stockEntry.note != null && !stockEntry.note.isEmpty())
|
||||||
|
{
|
||||||
|
noteTxt = " " + stockEntry.note;
|
||||||
|
}
|
||||||
|
|
||||||
$("#specific_stock_entry").append($("<option>", {
|
$("#specific_stock_entry").append($("<option>", {
|
||||||
value: stockEntry.stock_id,
|
value: stockEntry.stock_id,
|
||||||
amount: stockEntry.amount,
|
amount: stockEntry.amount,
|
||||||
text: __t("Amount: %1$s; Due on %2$s; Bought on %3$s", stockEntry.amount, moment(stockEntry.best_before_date).format("YYYY-MM-DD"), moment(stockEntry.purchased_date).format("YYYY-MM-DD")) + "; " + openTxt
|
text: __t("Amount: %1$s; Due on %2$s; Bought on %3$s", stockEntry.amount, moment(stockEntry.best_before_date).format("YYYY-MM-DD"), moment(stockEntry.purchased_date).format("YYYY-MM-DD")) + "; " + openTxt + noteTxt
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
var jsonData = {};
|
var jsonData = {};
|
||||||
jsonData.new_amount = jsonForm.amount;
|
jsonData.new_amount = jsonForm.amount;
|
||||||
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
||||||
|
jsonData.note = jsonForm.note;
|
||||||
jsonData.stock_label_type = jsonForm.stock_label_type;
|
jsonData.stock_label_type = jsonForm.stock_label_type;
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
{
|
{
|
||||||
@ -116,6 +117,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Grocy.EditObjectId = result[0].transaction_id;
|
||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function(result)
|
function(result)
|
||||||
{
|
{
|
||||||
@ -123,39 +125,48 @@
|
|||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined)
|
||||||
{
|
{
|
||||||
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
Grocy.Components.UserfieldsForm.Save(function()
|
||||||
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
{
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
||||||
|
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
||||||
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
Grocy.Components.UserfieldsForm.Save(function()
|
||||||
toastr.success(successMessage);
|
|
||||||
Grocy.Components.ProductPicker.FinishFlow();
|
|
||||||
|
|
||||||
Grocy.Components.ProductAmountPicker.Reset();
|
|
||||||
$('#inventory-change-info').addClass('d-none');
|
|
||||||
$("#tare-weight-handling-info").addClass("d-none");
|
|
||||||
$("#display_amount").attr("min", "0");
|
|
||||||
$('#display_amount').val('');
|
|
||||||
$('#display_amount').removeAttr("data-not-equal");
|
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
|
||||||
$('#price').val('');
|
|
||||||
Grocy.Components.DateTimePicker.Clear();
|
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
|
||||||
{
|
{
|
||||||
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
||||||
}
|
toastr.success(successMessage);
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.FinishFlow();
|
||||||
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
Grocy.Components.ProductAmountPicker.Reset();
|
||||||
{
|
$('#inventory-change-info').addClass('d-none');
|
||||||
$("#stock_label_type").val(0);
|
$("#tare-weight-handling-info").addClass("d-none");
|
||||||
}
|
$("#display_amount").attr("min", "0");
|
||||||
|
$('#display_amount').val('');
|
||||||
|
$('#display_amount').removeAttr("data-not-equal");
|
||||||
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
|
$('#price').val('');
|
||||||
|
$('#note').val('');
|
||||||
|
Grocy.Components.DateTimePicker.Clear();
|
||||||
|
Grocy.Components.ProductPicker.SetValue('');
|
||||||
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
|
{
|
||||||
|
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
||||||
|
}
|
||||||
|
Grocy.Components.ProductPicker.GetInputElement().focus();
|
||||||
|
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
||||||
|
Grocy.Components.UserfieldsForm.Clear();
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
|
{
|
||||||
|
$("#stock_label_type").val(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr)
|
||||||
|
@ -28,6 +28,7 @@ $('#save-purchase-button').on('click', function(e)
|
|||||||
{
|
{
|
||||||
var jsonData = {};
|
var jsonData = {};
|
||||||
jsonData.amount = jsonForm.amount;
|
jsonData.amount = jsonForm.amount;
|
||||||
|
jsonData.note = jsonForm.note;
|
||||||
jsonData.stock_label_type = jsonForm.stock_label_type;
|
jsonData.stock_label_type = jsonForm.stock_label_type;
|
||||||
|
|
||||||
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
@ -165,61 +166,70 @@ $('#save-purchase-button').on('click', function(e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Grocy.EditObjectId = result[0].transaction_id;
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined)
|
||||||
{
|
{
|
||||||
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
Grocy.Components.UserfieldsForm.Save(function()
|
||||||
window.parent.postMessage(WindowMessageBag("AfterItemAdded", GetUriParam("listitemid")), Grocy.BaseUrl);
|
{
|
||||||
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("Ready"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("AfterItemAdded", GetUriParam("listitemid")), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
||||||
|
window.parent.postMessage(WindowMessageBag("Ready"), Grocy.BaseUrl);
|
||||||
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
Grocy.Components.UserfieldsForm.Save(function()
|
||||||
toastr.success(successMessage);
|
|
||||||
Grocy.Components.ProductPicker.FinishFlow();
|
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && BoolVal(Grocy.UserSettings.show_warning_on_purchase_when_due_date_is_earlier_than_next))
|
|
||||||
{
|
{
|
||||||
if (moment(jsonData.best_before_date).isBefore(CurrentProductDetails.next_due_date))
|
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
||||||
|
toastr.success(successMessage);
|
||||||
|
Grocy.Components.ProductPicker.FinishFlow();
|
||||||
|
|
||||||
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && BoolVal(Grocy.UserSettings.show_warning_on_purchase_when_due_date_is_earlier_than_next))
|
||||||
{
|
{
|
||||||
toastr.warning(__t("This is due earlier than already in-stock items"));
|
if (moment(jsonData.best_before_date).isBefore(CurrentProductDetails.next_due_date))
|
||||||
|
{
|
||||||
|
toastr.warning(__t("This is due earlier than already in-stock items"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Grocy.Components.ProductAmountPicker.Reset();
|
Grocy.Components.ProductAmountPicker.Reset();
|
||||||
$("#purchase-form").removeAttr("data-used-barcode");
|
$("#purchase-form").removeAttr("data-used-barcode");
|
||||||
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
||||||
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_purchase_amount));
|
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_purchase_amount));
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
$('#price').val('');
|
$('#price').val('');
|
||||||
$("#tare-weight-handling-info").addClass("d-none");
|
$("#tare-weight-handling-info").addClass("d-none");
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
{
|
{
|
||||||
Grocy.Components.LocationPicker.Clear();
|
Grocy.Components.LocationPicker.Clear();
|
||||||
}
|
}
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||||
{
|
{
|
||||||
Grocy.Components.DateTimePicker.Clear();
|
Grocy.Components.DateTimePicker.Clear();
|
||||||
}
|
}
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
Grocy.Components.ProductPicker.SetValue('');
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
{
|
{
|
||||||
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
||||||
}
|
}
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.GetInputElement().focus();
|
||||||
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
{
|
{
|
||||||
$("#stock_label_type").val(0);
|
$("#stock_label_type").val(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#price-hint').text("");
|
$('#price-hint').text("");
|
||||||
var priceTypeUnitPrice = $("#price-type-unit-price");
|
$('#note').val("");
|
||||||
var priceTypeUnitPriceLabel = $("[for=" + priceTypeUnitPrice.attr("id") + "]");
|
var priceTypeUnitPrice = $("#price-type-unit-price");
|
||||||
priceTypeUnitPriceLabel.text(__t("Unit price"));
|
var priceTypeUnitPriceLabel = $("[for=" + priceTypeUnitPrice.attr("id") + "]");
|
||||||
|
priceTypeUnitPriceLabel.text(__t("Unit price"));
|
||||||
|
Grocy.Components.UserfieldsForm.Clear();
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr)
|
||||||
|
@ -217,6 +217,7 @@ function RefreshStockEntryRow(stockRowId)
|
|||||||
);
|
);
|
||||||
|
|
||||||
$('#stock-' + stockRowId + '-price').text(result.price);
|
$('#stock-' + stockRowId + '-price').text(result.price);
|
||||||
|
$('#stock-' + stockRowId + '-note').text(result.note);
|
||||||
$('#stock-' + stockRowId + '-purchased-date').text(result.purchased_date);
|
$('#stock-' + stockRowId + '-purchased-date').text(result.purchased_date);
|
||||||
$('#stock-' + stockRowId + '-purchased-date-timeago').attr('datetime', result.purchased_date + ' 23:59:59');
|
$('#stock-' + stockRowId + '-purchased-date-timeago').attr('datetime', result.purchased_date + ' 23:59:59');
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
jsonData.amount = jsonForm.amount;
|
jsonData.amount = jsonForm.amount;
|
||||||
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
||||||
jsonData.purchased_date = Grocy.Components.DateTimePicker2.GetValue();
|
jsonData.purchased_date = Grocy.Components.DateTimePicker2.GetValue();
|
||||||
|
jsonData.note = jsonForm.note;
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
{
|
{
|
||||||
jsonData.shopping_location_id = Grocy.Components.ShoppingLocationPicker.GetValue();
|
jsonData.shopping_location_id = Grocy.Components.ShoppingLocationPicker.GetValue();
|
||||||
|
@ -315,10 +315,16 @@ $("#location_id_from").on('change', function(e)
|
|||||||
{
|
{
|
||||||
if ($("#specific_stock_entry option[value='" + stockEntry.stock_id + "']").length == 0)
|
if ($("#specific_stock_entry option[value='" + stockEntry.stock_id + "']").length == 0)
|
||||||
{
|
{
|
||||||
|
var noteTxt = "";
|
||||||
|
if (stockEntry.note != null && !stockEntry.note.isEmpty())
|
||||||
|
{
|
||||||
|
noteTxt = " " + stockEntry.note;
|
||||||
|
}
|
||||||
|
|
||||||
$("#specific_stock_entry").append($("<option>", {
|
$("#specific_stock_entry").append($("<option>", {
|
||||||
value: stockEntry.stock_id,
|
value: stockEntry.stock_id,
|
||||||
amount: stockEntry.amount,
|
amount: stockEntry.amount,
|
||||||
text: __t("Amount: %1$s; Due on %2$s; Bought on %3$s", stockEntry.amount, moment(stockEntry.best_before_date).format("YYYY-MM-DD"), moment(stockEntry.purchased_date).format("YYYY-MM-DD")) + "; " + openTxt
|
text: __t("Amount: %1$s; Due on %2$s; Bought on %3$s", stockEntry.amount, moment(stockEntry.best_before_date).format("YYYY-MM-DD"), moment(stockEntry.purchased_date).format("YYYY-MM-DD")) + "; " + openTxt + noteTxt
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ class StockService extends BaseService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function AddProduct(int $productId, float $amount, $bestBeforeDate, $transactionType, $purchasedDate, $price, $locationId = null, $shoppingLocationId = null, &$transactionId = null, $stockLabelType = 0, $addExactAmount = false)
|
public function AddProduct(int $productId, float $amount, $bestBeforeDate, $transactionType, $purchasedDate, $price, $locationId = null, $shoppingLocationId = null, &$transactionId = null, $stockLabelType = 0, $addExactAmount = false, $note = null)
|
||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
@ -203,7 +203,8 @@ class StockService extends BaseService
|
|||||||
'location_id' => $locationId,
|
'location_id' => $locationId,
|
||||||
'transaction_id' => $transactionId,
|
'transaction_id' => $transactionId,
|
||||||
'shopping_location_id' => $shoppingLocationId,
|
'shopping_location_id' => $shoppingLocationId,
|
||||||
'user_id' => GROCY_USER_ID
|
'user_id' => GROCY_USER_ID,
|
||||||
|
'note' => $note
|
||||||
]);
|
]);
|
||||||
$logRow->save();
|
$logRow->save();
|
||||||
|
|
||||||
@ -215,7 +216,8 @@ class StockService extends BaseService
|
|||||||
'stock_id' => $stockId,
|
'stock_id' => $stockId,
|
||||||
'price' => $price,
|
'price' => $price,
|
||||||
'location_id' => $locationId,
|
'location_id' => $locationId,
|
||||||
'shopping_location_id' => $shoppingLocationId
|
'shopping_location_id' => $shoppingLocationId,
|
||||||
|
'note' => $note
|
||||||
]);
|
]);
|
||||||
$stockRow->save();
|
$stockRow->save();
|
||||||
|
|
||||||
@ -252,7 +254,8 @@ class StockService extends BaseService
|
|||||||
'location_id' => $locationId,
|
'location_id' => $locationId,
|
||||||
'transaction_id' => $transactionId,
|
'transaction_id' => $transactionId,
|
||||||
'shopping_location_id' => $shoppingLocationId,
|
'shopping_location_id' => $shoppingLocationId,
|
||||||
'user_id' => GROCY_USER_ID
|
'user_id' => GROCY_USER_ID,
|
||||||
|
'note' => $note
|
||||||
]);
|
]);
|
||||||
$logRow->save();
|
$logRow->save();
|
||||||
|
|
||||||
@ -264,7 +267,8 @@ class StockService extends BaseService
|
|||||||
'stock_id' => $stockId,
|
'stock_id' => $stockId,
|
||||||
'price' => $price,
|
'price' => $price,
|
||||||
'location_id' => $locationId,
|
'location_id' => $locationId,
|
||||||
'shopping_location_id' => $shoppingLocationId
|
'shopping_location_id' => $shoppingLocationId,
|
||||||
|
'note' => $note
|
||||||
]);
|
]);
|
||||||
$stockRow->save();
|
$stockRow->save();
|
||||||
|
|
||||||
@ -451,7 +455,8 @@ class StockService extends BaseService
|
|||||||
'recipe_id' => $recipeId,
|
'recipe_id' => $recipeId,
|
||||||
'transaction_id' => $transactionId,
|
'transaction_id' => $transactionId,
|
||||||
'user_id' => GROCY_USER_ID,
|
'user_id' => GROCY_USER_ID,
|
||||||
'location_id' => $stockEntry->location_id
|
'location_id' => $stockEntry->location_id,
|
||||||
|
'note' => $stockEntry->note
|
||||||
]);
|
]);
|
||||||
$logRow->save();
|
$logRow->save();
|
||||||
|
|
||||||
@ -478,7 +483,8 @@ class StockService extends BaseService
|
|||||||
'recipe_id' => $recipeId,
|
'recipe_id' => $recipeId,
|
||||||
'transaction_id' => $transactionId,
|
'transaction_id' => $transactionId,
|
||||||
'user_id' => GROCY_USER_ID,
|
'user_id' => GROCY_USER_ID,
|
||||||
'location_id' => $stockEntry->location_id
|
'location_id' => $stockEntry->location_id,
|
||||||
|
'note' => $stockEntry->note
|
||||||
]);
|
]);
|
||||||
$logRow->save();
|
$logRow->save();
|
||||||
|
|
||||||
@ -500,7 +506,7 @@ class StockService extends BaseService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function EditStockEntry(int $stockRowId, float $amount, $bestBeforeDate, $locationId, $shoppingLocationId, $price, $open, $purchasedDate)
|
public function EditStockEntry(int $stockRowId, float $amount, $bestBeforeDate, $locationId, $shoppingLocationId, $price, $open, $purchasedDate, $note = null)
|
||||||
{
|
{
|
||||||
$stockRow = $this->getDatabase()->stock()->where('id = :1', $stockRowId)->fetch();
|
$stockRow = $this->getDatabase()->stock()->where('id = :1', $stockRowId)->fetch();
|
||||||
if ($stockRow === null)
|
if ($stockRow === null)
|
||||||
@ -524,7 +530,8 @@ class StockService extends BaseService
|
|||||||
'correlation_id' => $correlationId,
|
'correlation_id' => $correlationId,
|
||||||
'transaction_id' => $transactionId,
|
'transaction_id' => $transactionId,
|
||||||
'stock_row_id' => $stockRow->id,
|
'stock_row_id' => $stockRow->id,
|
||||||
'user_id' => GROCY_USER_ID
|
'user_id' => GROCY_USER_ID,
|
||||||
|
'note' => $stockRow->note
|
||||||
]);
|
]);
|
||||||
$logOldRowForStockUpdate->save();
|
$logOldRowForStockUpdate->save();
|
||||||
|
|
||||||
@ -546,7 +553,8 @@ class StockService extends BaseService
|
|||||||
'shopping_location_id' => $shoppingLocationId,
|
'shopping_location_id' => $shoppingLocationId,
|
||||||
'opened_date' => $openedDate,
|
'opened_date' => $openedDate,
|
||||||
'open' => BoolToInt($open),
|
'open' => BoolToInt($open),
|
||||||
'purchased_date' => $purchasedDate
|
'purchased_date' => $purchasedDate,
|
||||||
|
'note' => $note
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$logNewRowForStockUpdate = $this->getDatabase()->stock_log()->createRow([
|
$logNewRowForStockUpdate = $this->getDatabase()->stock_log()->createRow([
|
||||||
@ -563,7 +571,8 @@ class StockService extends BaseService
|
|||||||
'correlation_id' => $correlationId,
|
'correlation_id' => $correlationId,
|
||||||
'transaction_id' => $transactionId,
|
'transaction_id' => $transactionId,
|
||||||
'stock_row_id' => $stockRow->id,
|
'stock_row_id' => $stockRow->id,
|
||||||
'user_id' => GROCY_USER_ID
|
'user_id' => GROCY_USER_ID,
|
||||||
|
'note' => $stockRow->note
|
||||||
]);
|
]);
|
||||||
$logNewRowForStockUpdate->save();
|
$logNewRowForStockUpdate->save();
|
||||||
|
|
||||||
@ -852,7 +861,7 @@ class StockService extends BaseService
|
|||||||
return $this->getDatabase()->stock()->where('id', $entryId)->fetch();
|
return $this->getDatabase()->stock()->where('id', $entryId)->fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function InventoryProduct(int $productId, float $newAmount, $bestBeforeDate, $locationId = null, $price = null, $shoppingLocationId = null, $purchasedDate = null, $stockLabelType = 0)
|
public function InventoryProduct(int $productId, float $newAmount, $bestBeforeDate, $locationId = null, $price = null, $shoppingLocationId = null, $purchasedDate = null, $stockLabelType = 0, $note = null)
|
||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
@ -899,7 +908,7 @@ class StockService extends BaseService
|
|||||||
$bookingAmount = $newAmount;
|
$bookingAmount = $newAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->AddProduct($productId, $bookingAmount, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION, $purchasedDate, $price, $locationId, $shoppingLocationId, $unusedTransactionId, $stockLabelType);
|
return $this->AddProduct($productId, $bookingAmount, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION, $purchasedDate, $price, $locationId, $shoppingLocationId, $unusedTransactionId, $stockLabelType, false, $note);
|
||||||
}
|
}
|
||||||
elseif ($newAmount < $productDetails->stock_amount + $containerWeight)
|
elseif ($newAmount < $productDetails->stock_amount + $containerWeight)
|
||||||
{
|
{
|
||||||
@ -1629,6 +1638,7 @@ class StockService extends BaseService
|
|||||||
{
|
{
|
||||||
$this->getDatabaseService()->ExecuteDbStatement('UPDATE stock SET stock_id = \'' . $splittedStockEntry->stock_id_to_keep . '\' WHERE stock_id = \'' . $stockId . '\'');
|
$this->getDatabaseService()->ExecuteDbStatement('UPDATE stock SET stock_id = \'' . $splittedStockEntry->stock_id_to_keep . '\' WHERE stock_id = \'' . $stockId . '\'');
|
||||||
$this->getDatabaseService()->ExecuteDbStatement('UPDATE stock_log SET stock_id = \'' . $splittedStockEntry->stock_id_to_keep . '\' WHERE stock_id = \'' . $stockId . '\'');
|
$this->getDatabaseService()->ExecuteDbStatement('UPDATE stock_log SET stock_id = \'' . $splittedStockEntry->stock_id_to_keep . '\' WHERE stock_id = \'' . $stockId . '\'');
|
||||||
|
$this->getDatabaseService()->ExecuteDbStatement('UPDATE userfield_values SET object_id = \'' . $splittedStockEntry->stock_id_to_keep . '\' WHERE field_id IN (SELECT id FROM userfields WHERE entity = \'stock\') AND object_id = \'' . $stockId . '\'');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +132,27 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="note">
|
||||||
|
{{ $__t('Note') }}
|
||||||
|
<i class="fas fa-question-circle text-muted"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
data-trigger="hover click"
|
||||||
|
title="{{ $__t('This will apply to added products') }}"></i>
|
||||||
|
</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
id="note"
|
||||||
|
name="note">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include('components.userfieldsform', array(
|
||||||
|
'userfields' => $userfields,
|
||||||
|
'entity' => 'stock'
|
||||||
|
))
|
||||||
|
|
||||||
<button id="save-inventory-button"
|
<button id="save-inventory-button"
|
||||||
class="btn btn-success">{{ $__t('OK') }}</button>
|
class="btn btn-success">{{ $__t('OK') }}</button>
|
||||||
|
|
||||||
|
@ -162,6 +162,21 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="note">{{ $__t('Note') }}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
id="note"
|
||||||
|
name="note">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include('components.userfieldsform', array(
|
||||||
|
'userfields' => $userfields,
|
||||||
|
'entity' => 'stock'
|
||||||
|
))
|
||||||
|
|
||||||
<button id="save-purchase-button"
|
<button id="save-purchase-button"
|
||||||
class="btn btn-success d-block">{{ $__t('OK') }}</button>
|
class="btn btn-success d-block">{{ $__t('OK') }}</button>
|
||||||
|
|
||||||
|
@ -73,9 +73,14 @@
|
|||||||
data-shadow-rowgroup-column="9">{{ $__t('Purchased date') }}</th>
|
data-shadow-rowgroup-column="9">{{ $__t('Purchased date') }}</th>
|
||||||
<th class="d-none">Hidden purchased_date</th>
|
<th class="d-none">Hidden purchased_date</th>
|
||||||
<th>{{ $__t('Timestamp') }}</th>
|
<th>{{ $__t('Timestamp') }}</th>
|
||||||
|
<th>{{ $__t('Note') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', array(
|
||||||
'userfields' => $userfields
|
'userfields' => $userfieldsProducts
|
||||||
|
))
|
||||||
|
|
||||||
|
@include('components.userfields_thead', array(
|
||||||
|
'userfields' => $userfieldsStock
|
||||||
))
|
))
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -274,10 +279,18 @@
|
|||||||
<time class="timeago timeago-contextual"
|
<time class="timeago timeago-contextual"
|
||||||
datetime="{{ $stockEntry->row_created_timestamp }}"></time>
|
datetime="{{ $stockEntry->row_created_timestamp }}"></time>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<span id="stock-{{ $stockEntry->id }}-note">{{ $stockEntry->note }}</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', array(
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfieldsProducts,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $stockEntry->product_id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValuesProducts, 'object_id', $stockEntry->product_id)
|
||||||
|
))
|
||||||
|
|
||||||
|
@include('components.userfields_tbody', array(
|
||||||
|
'userfields' => $userfieldsStock,
|
||||||
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValuesStock, 'object_id', $stockEntry->stock_id)
|
||||||
))
|
))
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -129,6 +129,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="note">{{ $__t('Note') }}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
id="note"
|
||||||
|
name="note"
|
||||||
|
value="{{ $stockEntry->note }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button id="save-stockentry-button"
|
<button id="save-stockentry-button"
|
||||||
class="btn btn-success">{{ $__t('OK') }}</button>
|
class="btn btn-success">{{ $__t('OK') }}</button>
|
||||||
|
|
||||||
|
@ -147,6 +147,11 @@
|
|||||||
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}</th>
|
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
||||||
|
<th>{{ $__t('Note') }}</th>
|
||||||
|
|
||||||
|
@include('components.userfields_thead', array(
|
||||||
|
'userfields' => $userfieldsStock
|
||||||
|
))
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@ -193,6 +198,14 @@
|
|||||||
<td>
|
<td>
|
||||||
{{ $stockLogEntry->user_display_name }}
|
{{ $stockLogEntry->user_display_name }}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ $stockLogEntry->note }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
@include('components.userfields_tbody', array(
|
||||||
|
'userfields' => $userfieldsStock,
|
||||||
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValuesStock, 'object_id', $stockLogEntry->stock_id)
|
||||||
|
))
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user