diff --git a/changelog/55_UNRELEASED_2019-xx-xx.md b/changelog/55_UNRELEASED_2019-xx-xx.md index 527b8b33..c9d83bf0 100644 --- a/changelog/55_UNRELEASED_2019-xx-xx.md +++ b/changelog/55_UNRELEASED_2019-xx-xx.md @@ -20,6 +20,12 @@ - On using "Consume all ingredients needed by this recipe" and when it has a product attached, one unit of that product (per serving in purchase quantity unit) will be added to stock (with the proper price based on the recipe ingredients) - (Thanks @kriddles for the intial work on this) +### New feature: Freeze/Thaw products +- New product options "Default best before days after freezing/thawing" to set how the best before date should be changed on freezing/thawing +- New location option "Is freezer" to indicate if the location is a freezer +- => When moving a product from/to a freezer location, the best before date is changed accordingly +- There is also a new sub feature flag `FEATURE_FLAG_STOCK_PRODUCT_FREEZING` to disable this if you don't need it (defaults to `true`) + ### Stock improvements/fixes - The productcard gets now also refreshed after a transaction was posted (purchase/consume/etc.) (thanks @kriddles) - The product field calories (kcal) now also allows decimal numbers diff --git a/config-dist.php b/config-dist.php index 35f6d83f..208bb59a 100644 --- a/config-dist.php +++ b/config-dist.php @@ -136,6 +136,7 @@ Setting('FEATURE_FLAG_STOCK_PRICE_TRACKING', true); Setting('FEATURE_FLAG_STOCK_LOCATION_TRACKING', true); Setting('FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING', true); Setting('FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING', true); +Setting('FEATURE_FLAG_STOCK_PRODUCT_FREEZING', true); Setting('FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS', true); Setting('FEATURE_FLAG_CHORES_ASSIGNMENTS', true); diff --git a/grocy.openapi.json b/grocy.openapi.json index c49ce067..cdf729de 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -3467,8 +3467,11 @@ "location_id": { "type": "integer" }, - "name": { + "location_name": { "type": "string" + }, + "location_is_freezer": { + "type": "integer" } }, "example": { diff --git a/localization/demo_data.pot b/localization/demo_data.pot index 51cc69a5..13858364 100644 --- a/localization/demo_data.pot +++ b/localization/demo_data.pot @@ -330,3 +330,6 @@ msgstr "" msgid "This is a note" msgstr "" + +msgid "Freezer" +msgstr "" diff --git a/localization/strings.pot b/localization/strings.pot index 96ed6add..b16d4a5c 100644 --- a/localization/strings.pot +++ b/localization/strings.pot @@ -1681,3 +1681,30 @@ msgstr "" msgid "Scan mode is on but not all required fields could be populated automatically" msgstr "" + +msgid "Is freezer" +msgstr "" + +msgid "When moving products from/to a freezer location, the products best before date is automatically adjusted according to the product settings" +msgstr "" + +msgid "On moving this product to a freezer location, the best before date will be replaced by today + this amount of days" +msgstr "" + +msgid "Default best before days after freezing" +msgstr "" + +msgid "On moving this product from a freezer location, the best before date will be replaced by today + this amount of days" +msgstr "" + +msgid "Default best before days after thawing" +msgstr "" + +msgid "This cannot be the same as the \"From\" location" +msgstr "" + +msgid "Thawed" +msgstr "" + +msgid "Frozen" +msgstr "" diff --git a/migrations/0097.sql b/migrations/0097.sql new file mode 100644 index 00000000..269911ef --- /dev/null +++ b/migrations/0097.sql @@ -0,0 +1,31 @@ +ALTER TABLE products +ADD default_best_before_days_after_freezing INTEGER NOT NULL DEFAULT 0; + +UPDATE products +SET default_best_before_days_after_freezing = 0; + +ALTER TABLE products +ADD default_best_before_days_after_thawing INTEGER NOT NULL DEFAULT 0; + +UPDATE products +SET default_best_before_days_after_thawing = 0; + +ALTER TABLE locations +ADD is_freezer TINYINT NOT NULL DEFAULT 0; + +UPDATE locations +SET is_freezer = 0; + +DROP VIEW stock_current_locations; +CREATE VIEW stock_current_locations +AS +SELECT + 1 AS id, -- Dummy, LessQL needs an id column + s.product_id, + s.location_id AS location_id, + l.name AS location_name, + l.is_freezer AS location_is_freezer +FROM stock s +JOIN locations l + ON s.location_id = l.id +GROUP BY s.product_id, s.location_id, l.name; diff --git a/public/viewjs/transfer.js b/public/viewjs/transfer.js index 83540394..0824f9f3 100644 --- a/public/viewjs/transfer.js +++ b/public/viewjs/transfer.js @@ -1,4 +1,4 @@ -$('#save-transfer-button').on('click', function(e) +$('#save-transfer-button').on('click', function (e) { e.preventDefault(); @@ -71,10 +71,18 @@ } else { - Grocy.FrontendHelpers.EndUiBusy("transfer-form"); toastr.success(successMessage); + if (parseInt($("#location_id_from option:selected").attr("data-is-freezer")) === 0 && parseInt($("#location_id_to option:selected").attr("data-is-freezer")) === 1) // Frozen + { + toastr.info('' + __t("Frozen") + " "); + } + if (parseInt($("#location_id_from option:selected").attr("data-is-freezer")) === 1 && parseInt($("#location_id_to option:selected").attr("data-is-freezer")) === 0) // Thawed + { + toastr.info('' + __t("Thawed") + " "); + } + $("#specific_stock_entry").find("option").remove().end().append(""); $("#specific_stock_entry").attr("disabled", ""); $("#specific_stock_entry").removeAttr("required"); @@ -151,7 +159,8 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e) { $("#location_id_from").append($("