mirror of
https://github.com/grocy/grocy.git
synced 2025-10-19 19:36:35 +00:00
Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
dedbee3181 | ||
|
16f686deb8 | ||
|
973e4226b6 | ||
|
6e22d3b100 | ||
|
9b119da8e0 | ||
|
03f9ba45ea | ||
|
a965d01fb9 | ||
|
a123535b0a | ||
|
3a2929c016 | ||
|
106f25cc6b | ||
|
d6cc87ac86 | ||
|
a47bccab3f | ||
|
393a312186 | ||
|
7f21e2de34 | ||
|
82ac996b3a | ||
|
827134c972 | ||
|
787d5f11e0 | ||
|
2d2039f988 | ||
|
268f0d8a50 | ||
|
9dde46d419 | ||
|
162ba267a1 | ||
|
4691b45510 |
@@ -4,9 +4,11 @@
|
||||
|
||||
> _Recommendation: Benchmark tests showed that e.g. unit conversion handling is up to 5 times faster when using a more recent (3.39.4+) SQLite version._
|
||||
|
||||
### New feature: Quantity unit conversions with unlimited hierarchy
|
||||
### New feature: Indirect quantity unit conversions with unlimited levels
|
||||
|
||||
- Quantity unit conversions now support transitive conversions, means the QU hierarchy has now unlimited levels (thanks a lot @esclear)
|
||||
- Quantity unit conversions now support indirect conversions with unlimited levels (thanks a lot @esclear)
|
||||
- _Explained by a practical example: When a conversion between Teaspoons and Milliliters and another one between Milliliters and Liters exists (and so forth; unlimited levels), Grocy can now calculate Teaspoons to Liters (before a direct conversion definition between Teaspoons and Liters was required)_
|
||||
- **Heads up:** If you have such "each to each absolute conversion definitions" currently (for the example above the conversion between Teaspoons and Liters), you should clean them up, since they are no longer needed
|
||||
- The product option "Factor purchase to stock quantity unit" was removed
|
||||
- => Use normal product specific QU conversions instead, if needed
|
||||
- An existing "Factor purchase to stock quantity unit" was automatically migrated to a product specific QU conversion
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
### Shopping list
|
||||
|
||||
- Changed that prices on the shopping list (table columns "Last price (Unit)" and "Last price (Total)") are now related to the there selected quantity unit (instead of to the product's QU stock as before)
|
||||
- Changed that unit prices on the shopping list (table column "Last price (Unit)") are now related to the there selected quantity unit (instead of to the product's QU stock as before)
|
||||
|
||||
### Meal plan
|
||||
|
||||
|
13
changelog/72_4.0.2_2023-08-19.md
Normal file
13
changelog/72_4.0.2_2023-08-19.md
Normal file
@@ -0,0 +1,13 @@
|
||||
### Stock
|
||||
|
||||
- The stock report "Spendings" now also supports grouping by stores
|
||||
- Fixed that the upgrade failed when having (a lot of) redundant ("each to each") default quantity unit conversion definitions (thanks a lot @alkuzman and @esclear)
|
||||
- More on that by a practical example: When a conversion between Teaspoons and Milliliters and another one between Milliliters and Liters exists (and so forth; unlimited levels), Grocy can now (since v4.0.0) calculate the derived factor to convert Teaspoons to Liters on its own (before a direct conversion definition between Teaspoons and Liters was required)
|
||||
- So you might have a lot of such "each to each absolute conversion definitions" currently, when you were affected by failed upgrades (timeout problems due to that resolving indirect conversion factors took very long)
|
||||
- **Heads up:** This is now fixed, but you should clean up those redundant "each to each" definitions (in the example above the conversion between Teaspoons and Liters), since they are no longer needed
|
||||
- Fixed that the "Mark this stock entry as open"-button on the stock entries page opened always one unit instead of the whole stock entry
|
||||
- Fixed that edited stock entries were not considered in some cases (affecting the product's average price and the stock reports)
|
||||
|
||||
### Recipes
|
||||
|
||||
- Fixed that ingredient cost/energy values were wrong when unit conversions but _no_ product substitutions were involved
|
@@ -7,7 +7,7 @@
|
||||
"php-di/php-di": "^7.0.3",
|
||||
"berrnd/slim-blade-view": "^1.0.0",
|
||||
"morris/lessql": "dev-php82",
|
||||
"gettext/gettext": "dev-php81",
|
||||
"gettext/gettext": "^4.8.10",
|
||||
"eluceo/ical": "^2.2.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"gumlet/php-image-resize": "^2.0",
|
||||
@@ -20,10 +20,6 @@
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/berrnd/lessql"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/berrnd/Gettext"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
|
173
composer.lock
generated
173
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "ffa5545aaf16f26d4916e4c9f2eee408",
|
||||
"content-hash": "a350f5bd26aac82f0c126778cc8a1d29",
|
||||
"packages": [
|
||||
{
|
||||
"name": "berrnd/slim-blade-view",
|
||||
@@ -442,16 +442,16 @@
|
||||
},
|
||||
{
|
||||
"name": "gettext/gettext",
|
||||
"version": "dev-php81",
|
||||
"version": "v4.8.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/berrnd/Gettext.git",
|
||||
"reference": "505003f167881bd01b5991ee7762592b244e827e"
|
||||
"url": "https://github.com/php-gettext/Gettext.git",
|
||||
"reference": "b632aaf5e4579d0b2ae8bc61785e238bff4c5156"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/berrnd/Gettext/zipball/505003f167881bd01b5991ee7762592b244e827e",
|
||||
"reference": "505003f167881bd01b5991ee7762592b244e827e",
|
||||
"url": "https://api.github.com/repos/php-gettext/Gettext/zipball/b632aaf5e4579d0b2ae8bc61785e238bff4c5156",
|
||||
"reference": "b632aaf5e4579d0b2ae8bc61785e238bff4c5156",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -478,17 +478,7 @@
|
||||
"Gettext\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Gettext\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": [
|
||||
"phpunit",
|
||||
"phpcs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
@@ -503,9 +493,9 @@
|
||||
"description": "PHP gettext manager",
|
||||
"homepage": "https://github.com/oscarotero/Gettext",
|
||||
"keywords": [
|
||||
"JS",
|
||||
"gettext",
|
||||
"i18n",
|
||||
"js",
|
||||
"mo",
|
||||
"po",
|
||||
"translation"
|
||||
@@ -513,23 +503,23 @@
|
||||
"support": {
|
||||
"email": "oom@oscarotero.com",
|
||||
"issues": "https://github.com/oscarotero/Gettext/issues",
|
||||
"source": "https://github.com/berrnd/Gettext/tree/php81"
|
||||
"source": "https://github.com/php-gettext/Gettext/tree/v4.8.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/oscarotero"
|
||||
"url": "https://paypal.me/oscarotero",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/misteroom"
|
||||
"url": "https://github.com/oscarotero",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"url": "https://paypal.me/oscarotero"
|
||||
"url": "https://www.patreon.com/misteroom",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-10T14:11:03+00:00"
|
||||
"time": "2023-08-14T15:15:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gettext/languages",
|
||||
@@ -991,7 +981,7 @@
|
||||
},
|
||||
{
|
||||
"name": "illuminate/bus",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/bus.git",
|
||||
@@ -1044,16 +1034,16 @@
|
||||
},
|
||||
{
|
||||
"name": "illuminate/collections",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/collections.git",
|
||||
"reference": "66ff5aab0dd10659aff0efe3ff101819db192dfe"
|
||||
"reference": "f494398dbaaead9e5ff16a18002d11634e8358e6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/collections/zipball/66ff5aab0dd10659aff0efe3ff101819db192dfe",
|
||||
"reference": "66ff5aab0dd10659aff0efe3ff101819db192dfe",
|
||||
"url": "https://api.github.com/repos/illuminate/collections/zipball/f494398dbaaead9e5ff16a18002d11634e8358e6",
|
||||
"reference": "f494398dbaaead9e5ff16a18002d11634e8358e6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1095,11 +1085,11 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2023-08-02T14:57:32+00:00"
|
||||
"time": "2023-08-11T14:48:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/conditionable",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/conditionable.git",
|
||||
@@ -1145,7 +1135,7 @@
|
||||
},
|
||||
{
|
||||
"name": "illuminate/container",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/container.git",
|
||||
@@ -1196,7 +1186,7 @@
|
||||
},
|
||||
{
|
||||
"name": "illuminate/contracts",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/contracts.git",
|
||||
@@ -1244,16 +1234,16 @@
|
||||
},
|
||||
{
|
||||
"name": "illuminate/events",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/events.git",
|
||||
"reference": "84bafe2c432b22d21c3fb30be42fe2ae9b2f8fd8"
|
||||
"reference": "e8cbfa31e1ada8d178ffcd7a5e26e101ec280c59"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/events/zipball/84bafe2c432b22d21c3fb30be42fe2ae9b2f8fd8",
|
||||
"reference": "84bafe2c432b22d21c3fb30be42fe2ae9b2f8fd8",
|
||||
"url": "https://api.github.com/repos/illuminate/events/zipball/e8cbfa31e1ada8d178ffcd7a5e26e101ec280c59",
|
||||
"reference": "e8cbfa31e1ada8d178ffcd7a5e26e101ec280c59",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1295,11 +1285,11 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2023-06-27T14:35:49+00:00"
|
||||
"time": "2023-08-11T15:02:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/filesystem",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/filesystem.git",
|
||||
@@ -1363,7 +1353,7 @@
|
||||
},
|
||||
{
|
||||
"name": "illuminate/macroable",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/macroable.git",
|
||||
@@ -1409,7 +1399,7 @@
|
||||
},
|
||||
{
|
||||
"name": "illuminate/pipeline",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/pipeline.git",
|
||||
@@ -1457,16 +1447,16 @@
|
||||
},
|
||||
{
|
||||
"name": "illuminate/support",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/support.git",
|
||||
"reference": "7549dd081cc45c742b7d97064b64cf67fab4c7b6"
|
||||
"reference": "0a8526d55756955fcec6be7c2c6cd14d915c8c0f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/support/zipball/7549dd081cc45c742b7d97064b64cf67fab4c7b6",
|
||||
"reference": "7549dd081cc45c742b7d97064b64cf67fab4c7b6",
|
||||
"url": "https://api.github.com/repos/illuminate/support/zipball/0a8526d55756955fcec6be7c2c6cd14d915c8c0f",
|
||||
"reference": "0a8526d55756955fcec6be7c2c6cd14d915c8c0f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1524,20 +1514,20 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2023-07-31T15:02:41+00:00"
|
||||
"time": "2023-08-14T21:56:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/view",
|
||||
"version": "v10.17.1",
|
||||
"version": "v10.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/view.git",
|
||||
"reference": "dc8e10246d562aa371e2a3a793a1b23735ebf5e3"
|
||||
"reference": "e409930611f49a09b10ce78ed735ee1965bee25e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/view/zipball/dc8e10246d562aa371e2a3a793a1b23735ebf5e3",
|
||||
"reference": "dc8e10246d562aa371e2a3a793a1b23735ebf5e3",
|
||||
"url": "https://api.github.com/repos/illuminate/view/zipball/e409930611f49a09b10ce78ed735ee1965bee25e",
|
||||
"reference": "e409930611f49a09b10ce78ed735ee1965bee25e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1578,7 +1568,7 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2023-07-15T20:25:55+00:00"
|
||||
"time": "2023-08-14T14:52:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "interficieis/php-barcode",
|
||||
@@ -1857,25 +1847,29 @@
|
||||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
"version": "2.68.1",
|
||||
"version": "2.69.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/briannesbitt/Carbon.git",
|
||||
"reference": "4f991ed2a403c85efbc4f23eb4030063fdbe01da"
|
||||
"reference": "4308217830e4ca445583a37d1bf4aff4153fa81c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4f991ed2a403c85efbc4f23eb4030063fdbe01da",
|
||||
"reference": "4f991ed2a403c85efbc4f23eb4030063fdbe01da",
|
||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4308217830e4ca445583a37d1bf4aff4153fa81c",
|
||||
"reference": "4308217830e4ca445583a37d1bf4aff4153fa81c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": "^7.1.8 || ^8.0",
|
||||
"psr/clock": "^1.0",
|
||||
"symfony/polyfill-mbstring": "^1.0",
|
||||
"symfony/polyfill-php80": "^1.16",
|
||||
"symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/clock-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/dbal": "^2.0 || ^3.1.4",
|
||||
"doctrine/orm": "^2.7",
|
||||
@@ -1955,7 +1949,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-06-20T18:29:04+00:00"
|
||||
"time": "2023-08-03T09:00:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
@@ -2064,16 +2058,16 @@
|
||||
},
|
||||
{
|
||||
"name": "php-di/php-di",
|
||||
"version": "7.0.3",
|
||||
"version": "7.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-DI/PHP-DI.git",
|
||||
"reference": "d5dad2500f409d8b78371823c8b382fe9b5d0917"
|
||||
"reference": "9ea40a5a6970bf1ca5cbe148bc16cbad6ca3db6c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/d5dad2500f409d8b78371823c8b382fe9b5d0917",
|
||||
"reference": "d5dad2500f409d8b78371823c8b382fe9b5d0917",
|
||||
"url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/9ea40a5a6970bf1ca5cbe148bc16cbad6ca3db6c",
|
||||
"reference": "9ea40a5a6970bf1ca5cbe148bc16cbad6ca3db6c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2121,7 +2115,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-DI/PHP-DI/issues",
|
||||
"source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.3"
|
||||
"source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2133,7 +2127,55 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-06-17T10:21:14+00:00"
|
||||
"time": "2023-08-10T14:57:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/clock",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/clock.git",
|
||||
"reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
|
||||
"reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.0 || ^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Clock\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for reading the clock.",
|
||||
"homepage": "https://github.com/php-fig/clock",
|
||||
"keywords": [
|
||||
"clock",
|
||||
"now",
|
||||
"psr",
|
||||
"psr-20",
|
||||
"time"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-fig/clock/issues",
|
||||
"source": "https://github.com/php-fig/clock/tree/1.0.0"
|
||||
},
|
||||
"time": "2022-11-25T14:36:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
@@ -3671,8 +3713,7 @@
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"morris/lessql": 20,
|
||||
"gettext/gettext": 20
|
||||
"morris/lessql": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
|
@@ -21,29 +21,17 @@ class StockReportsController extends BaseController
|
||||
$where = "pph.purchased_date >= DATE(DATE('now', 'localtime'), 'start of month')";
|
||||
}
|
||||
|
||||
|
||||
if (isset($request->getQueryParams()['byGroup']))
|
||||
$groupBy = 'product';
|
||||
if (isset($request->getQueryParams()['group-by']) && in_array($request->getQueryParams()['group-by'], ['product', 'productgroup', 'store']))
|
||||
{
|
||||
$sql = "
|
||||
SELECT
|
||||
pg.id AS id,
|
||||
pg.name AS name,
|
||||
SUM(pph.amount * pph.price) AS total
|
||||
FROM products_price_history pph
|
||||
JOIN products p
|
||||
ON pph.product_id = p.id
|
||||
JOIN product_groups pg
|
||||
ON p.product_group_id = pg.id
|
||||
WHERE $where
|
||||
GROUP BY pg.id
|
||||
ORDER BY pg.NAME COLLATE NOCASE
|
||||
";
|
||||
$groupBy = $request->getQueryParams()['group-by'];
|
||||
}
|
||||
else
|
||||
|
||||
if ($groupBy == 'product')
|
||||
{
|
||||
if (isset($request->getQueryParams()['product_group']) and $request->getQueryParams()['product_group'] != 'all')
|
||||
if (isset($request->getQueryParams()['product-group']) and $request->getQueryParams()['product-group'] != 'all')
|
||||
{
|
||||
$where .= ' AND pg.id = ' . $request->getQueryParams()['product_group'];
|
||||
$where .= ' AND pg.id = ' . $request->getQueryParams()['product-group'];
|
||||
}
|
||||
|
||||
$sql = "
|
||||
@@ -59,16 +47,50 @@ class StockReportsController extends BaseController
|
||||
JOIN product_groups pg
|
||||
ON p.product_group_id = pg.id
|
||||
WHERE $where
|
||||
GROUP BY p.id
|
||||
ORDER BY p.NAME COLLATE NOCASE
|
||||
GROUP BY p.id, p.name, pg.id, pg.name
|
||||
ORDER BY p.name COLLATE NOCASE
|
||||
";
|
||||
}
|
||||
elseif ($groupBy == 'productgroup')
|
||||
{
|
||||
$sql = "
|
||||
SELECT
|
||||
pg.id AS id,
|
||||
pg.name AS name,
|
||||
SUM(pph.amount * pph.price) AS total
|
||||
FROM products_price_history pph
|
||||
JOIN products p
|
||||
ON pph.product_id = p.id
|
||||
JOIN product_groups pg
|
||||
ON p.product_group_id = pg.id
|
||||
WHERE $where
|
||||
GROUP BY pg.id, pg.name
|
||||
ORDER BY pg.name COLLATE NOCASE
|
||||
";
|
||||
}
|
||||
elseif ($groupBy == 'store')
|
||||
{
|
||||
$sql = "
|
||||
SELECT
|
||||
sl.id AS id,
|
||||
sl.name AS name,
|
||||
SUM(pph.amount * pph.price) AS total
|
||||
FROM products_price_history pph
|
||||
JOIN products p
|
||||
ON pph.product_id = p.id
|
||||
LEFT JOIN shopping_locations sl
|
||||
ON pph.shopping_location_id = sl.id
|
||||
WHERE $where
|
||||
GROUP BY sl.id, sl.name
|
||||
ORDER BY sl.NAME COLLATE NOCASE
|
||||
";
|
||||
}
|
||||
|
||||
return $this->renderPage($response, 'stockreportspendings', [
|
||||
'metrics' => $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ),
|
||||
'productGroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'selectedGroup' => isset($request->getQueryParams()['product_group']) ? $request->getQueryParams()['product_group'] : null,
|
||||
'byGroup' => isset($request->getQueryParams()['byGroup']) ? $request->getQueryParams()['byGroup'] : null
|
||||
'selectedGroup' => isset($request->getQueryParams()['product-group']) ? $request->getQueryParams()['product-group'] : null,
|
||||
'groupBy' => $groupBy
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -1204,11 +1204,6 @@ msgstr "Mai"
|
||||
msgid "Today"
|
||||
msgstr "Avui"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"No tots els ingredients de la recepta \"%s\" tenen existències, no s'ha "
|
||||
"eliminat res"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Desfer tasca"
|
||||
|
||||
|
@@ -277,9 +277,7 @@ msgid "Manage master data"
|
||||
msgstr "Spravovat základní data"
|
||||
|
||||
msgid "This will apply to added products"
|
||||
msgstr ""
|
||||
"Určuje, jak se změna množství balení produktu zapíše do Seznamu zásob a zda "
|
||||
"se k této změně vytisknou nálepky na produkt"
|
||||
msgstr "Tento údaj se zapíše jen pro přidané produkty do zásoby."
|
||||
|
||||
msgid "never"
|
||||
msgstr "nikdy"
|
||||
@@ -1236,10 +1234,6 @@ msgstr "Nikdy"
|
||||
msgid "Today"
|
||||
msgstr "Dnes"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"V zásobě nejsou všechny ingredience receptu „%s“ – nic nebude odebráno"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Vrátit úkol"
|
||||
|
||||
@@ -2728,7 +2722,7 @@ msgid "Decimal places allowed for prices (display)"
|
||||
msgstr "Počet desetinných míst pro zobrazení ceny"
|
||||
|
||||
msgid "Clear done items"
|
||||
msgstr "Smazat všechna zaškrtnutá"
|
||||
msgstr "Odstranit všechna vybraná"
|
||||
|
||||
msgid ""
|
||||
"This shows all to this product directly or indirectly related quantity units"
|
||||
@@ -2780,7 +2774,7 @@ msgid "Track chore execution now"
|
||||
msgstr "Splnění povinnosti s dnešním datem"
|
||||
|
||||
msgid "Total"
|
||||
msgstr "Součet"
|
||||
msgstr "Celkem"
|
||||
|
||||
msgid "Apply"
|
||||
msgstr "Provést"
|
||||
|
@@ -1209,10 +1209,6 @@ msgstr "Aldrig"
|
||||
msgid "Today"
|
||||
msgstr "Idag"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Ikke alle ingredienser til opskrift \"%s\" er i beholdningen, intet fjernet"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Fortryd opgave"
|
||||
|
||||
|
@@ -1222,11 +1222,6 @@ msgstr "Nie"
|
||||
msgid "Today"
|
||||
msgstr "Heute"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Nicht alle Zutaten, die vom Rezept \"%s\" benötigt werden, sind vorrätig, es"
|
||||
" wurde nichts aus dem Bestand entfernt"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Aufgabe rückgängig machen"
|
||||
|
||||
|
@@ -1218,9 +1218,6 @@ msgstr "Ποτέ"
|
||||
msgid "Today"
|
||||
msgstr "Σήμερα"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Δεν υπάρχουν όλα τα συστατικά της συνταγής \"%s\", τίποτα δεν αφαιρείται"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr ""
|
||||
|
||||
|
@@ -1198,9 +1198,6 @@ msgstr "Never"
|
||||
msgid "Today"
|
||||
msgstr "Today"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Undo task"
|
||||
|
||||
|
@@ -1247,11 +1247,6 @@ msgstr "Nunca"
|
||||
msgid "Today"
|
||||
msgstr "Hoy"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"No todos los ingredientes de la receta \"%s\" están en el inventario, nada "
|
||||
"fue eliminado"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Deshacer tarea"
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
# Translators:
|
||||
# Mario Loik <mariomobla@gmail.com>, 2020
|
||||
# Lauri Lepik, 2023
|
||||
# aylamz, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -9,7 +10,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Lauri Lepik, 2023\n"
|
||||
"Last-Translator: aylamz, 2023\n"
|
||||
"Language-Team: Estonian (Estonia) (https://app.transifex.com/grocy/teams/93189/et_EE/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -31,7 +32,7 @@ msgid "Candy cupboard"
|
||||
msgstr "Kommisahtel"
|
||||
|
||||
msgid "Tinned food cupboard"
|
||||
msgstr "Metallpurgitoidu sahtel"
|
||||
msgstr "Konservisahtel"
|
||||
|
||||
msgid "Fridge"
|
||||
msgstr "Külmkapp"
|
||||
@@ -106,16 +107,16 @@ msgid "Tomato"
|
||||
msgstr "Tomat"
|
||||
|
||||
msgid "Change towels in the bathroom"
|
||||
msgstr "Vaheta vannitoas rätikud"
|
||||
msgstr "Vaheta vetsu rätikud"
|
||||
|
||||
msgid "Mop the kitchen floor"
|
||||
msgstr "Pühi köögi põrand"
|
||||
|
||||
msgid "Warranty ends"
|
||||
msgstr "Garantii lõpeb"
|
||||
msgstr "Garantii lõppeb"
|
||||
|
||||
msgid "TV remote control"
|
||||
msgstr "TV pult"
|
||||
msgstr "Teleri pult"
|
||||
|
||||
msgid "Alarm clock"
|
||||
msgstr "Äratuskell"
|
||||
@@ -148,7 +149,7 @@ msgid "Pizza"
|
||||
msgstr "Pitsa"
|
||||
|
||||
msgid "Spaghetti bolognese"
|
||||
msgstr "Bolognese spagetid"
|
||||
msgstr "Pasta bolognese"
|
||||
|
||||
msgid "Sandwiches"
|
||||
msgstr "Võileivad"
|
||||
@@ -166,7 +167,7 @@ msgid "This is the note content of the recipe ingredient"
|
||||
msgstr "See on retsepti koostisosade sisu märge"
|
||||
|
||||
msgid "Demo User"
|
||||
msgstr "Demo Kasutaja"
|
||||
msgstr "Demo kasutaja"
|
||||
|
||||
msgid "Gram"
|
||||
msgid_plural "Grams"
|
||||
@@ -186,7 +187,7 @@ msgid "Sweets"
|
||||
msgstr "Maiustused"
|
||||
|
||||
msgid "Bakery products"
|
||||
msgstr "Ahjutooted"
|
||||
msgstr "Pagaritooted"
|
||||
|
||||
msgid "Tinned food"
|
||||
msgstr "Konserv"
|
||||
@@ -198,7 +199,7 @@ msgid "Vegetables/Fruits"
|
||||
msgstr "Köögiviljad/Puuviljad"
|
||||
|
||||
msgid "Refrigerated products"
|
||||
msgstr "Külmutatud Tooted"
|
||||
msgstr "Külmutatud tooted"
|
||||
|
||||
msgid "Coffee machine"
|
||||
msgstr "Kohvimasin"
|
||||
@@ -222,7 +223,7 @@ msgid "Milk"
|
||||
msgstr "Piim"
|
||||
|
||||
msgid "Chocolate sauce"
|
||||
msgstr "Šokolaadi kaste"
|
||||
msgstr "Šokolaadikaste"
|
||||
|
||||
msgid "Milliliters"
|
||||
msgstr "Millimeetrit"
|
||||
@@ -249,7 +250,7 @@ msgid "Russian"
|
||||
msgstr "Vene"
|
||||
|
||||
msgid "Vacuum the living room floor"
|
||||
msgstr "Korista tolmuimejaga elutuba"
|
||||
msgstr "Korista elutuba tolmuimejaga"
|
||||
|
||||
msgid "Clean the litter box"
|
||||
msgstr "Korista liivakast"
|
||||
@@ -267,7 +268,7 @@ msgid "Milk Chocolate"
|
||||
msgstr "Piimašokolaad"
|
||||
|
||||
msgid "Dark Chocolate"
|
||||
msgstr "Must Šokolaad"
|
||||
msgstr "Must šokolaad"
|
||||
|
||||
msgid "Slice"
|
||||
msgid_plural "Slices"
|
||||
@@ -275,16 +276,16 @@ msgstr[0] "Viil"
|
||||
msgstr[1] "Viilu"
|
||||
|
||||
msgid "Example userentity"
|
||||
msgstr "Näidis kasutajasisend"
|
||||
msgstr "Näidis kasutajaolem"
|
||||
|
||||
msgid "This is an example user entity..."
|
||||
msgstr "See on kasutaja sisendi näide..."
|
||||
msgstr "See on kasutajaolemi näide..."
|
||||
|
||||
msgid "Custom field"
|
||||
msgstr "Kohandatud väli"
|
||||
msgstr "Kohandatav väli"
|
||||
|
||||
msgid "Example field value..."
|
||||
msgstr "Näidisvälja väärtus..."
|
||||
msgstr "Välja näidisväärtus..."
|
||||
|
||||
msgid "Waffle rolls"
|
||||
msgstr "Vahvlirullid"
|
||||
@@ -320,7 +321,7 @@ msgid "This is a note"
|
||||
msgstr "See on märge"
|
||||
|
||||
msgid "Freezer"
|
||||
msgstr "Külmik"
|
||||
msgstr "Sügavkülmik"
|
||||
|
||||
msgid "Hungarian"
|
||||
msgstr "Ungari"
|
||||
@@ -411,4 +412,4 @@ msgid "Beer"
|
||||
msgstr "Õlu"
|
||||
|
||||
msgid "Estonian"
|
||||
msgstr ""
|
||||
msgstr "eesti"
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Lauri Lepik, 2023
|
||||
# aylamz, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +9,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2020-08-31 19:11+0000\n"
|
||||
"Last-Translator: Lauri Lepik, 2023\n"
|
||||
"Last-Translator: aylamz, 2023\n"
|
||||
"Language-Team: Estonian (Estonia) (https://app.transifex.com/grocy/teams/93189/et_EE/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -143,4 +144,4 @@ msgstr "Rumeenia keel"
|
||||
|
||||
# Estonian
|
||||
msgid "et_EE"
|
||||
msgstr ""
|
||||
msgstr "eesti keel"
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Lauri Lepik, 2023
|
||||
# aylamz, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +9,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Lauri Lepik, 2023\n"
|
||||
"Last-Translator: aylamz, 2023\n"
|
||||
"Language-Team: Estonian (Estonia) (https://app.transifex.com/grocy/teams/93189/et_EE/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -27,10 +28,10 @@ msgid "transfer_to"
|
||||
msgstr "kategooriasse üleviimine"
|
||||
|
||||
msgid "consume"
|
||||
msgstr "tarbimine"
|
||||
msgstr "tarbi"
|
||||
|
||||
msgid "inventory-correction"
|
||||
msgstr "invetuuri-parandus"
|
||||
msgstr "inventuuri-parandus"
|
||||
|
||||
msgid "product-opened"
|
||||
msgstr "toode-avatud"
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1204,9 +1204,6 @@ msgstr "Ei koskaan"
|
||||
msgid "Today"
|
||||
msgstr "Tänään"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Reseptin \"%s\" kaikkia ainesosia ei ole varastossa, ei poistettu mitään"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Kumoa tehtävä"
|
||||
|
||||
|
@@ -1265,11 +1265,6 @@ msgstr "Jamais"
|
||||
msgid "Today"
|
||||
msgstr "Aujourd'hui"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Des ingrédients de la recette \"%s\" sont manquants,\n"
|
||||
"rien n'est retiré"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Annuler"
|
||||
|
||||
|
@@ -1218,9 +1218,6 @@ msgstr "אף פעם"
|
||||
msgid "Today"
|
||||
msgstr "היום"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "לא כל הרכיבים של המתכון „%s” נמצאים במלאי, לא הוסר דבר"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "ביטול ביצוע משימה"
|
||||
|
||||
|
@@ -1216,11 +1216,6 @@ msgstr "Soha"
|
||||
msgid "Today"
|
||||
msgstr "Ma"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Nincs a \"%s\" recept összes hozzávalója készleten, így nem használtunk fel "
|
||||
"semmit se"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Feladat visszavonása"
|
||||
|
||||
|
@@ -11,6 +11,7 @@
|
||||
# Martino Falorni, 2023
|
||||
# Davide Casella, 2023
|
||||
# Saul il, 2023
|
||||
# Davide G., 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -18,7 +19,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Saul il, 2023\n"
|
||||
"Last-Translator: Davide G., 2023\n"
|
||||
"Language-Team: Italian (https://app.transifex.com/grocy/teams/93189/it/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -1244,11 +1245,6 @@ msgstr "Mai"
|
||||
msgid "Today"
|
||||
msgstr "Oggi"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Non tutti gli ingredienti della ricetta \"%s\" sono disponibili in dispensa,"
|
||||
" nulla è stato rimosso"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Annulla attività"
|
||||
|
||||
@@ -2763,7 +2759,7 @@ msgid "Product specifc QU conversions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Default quantity unit consume"
|
||||
msgstr ""
|
||||
msgstr "Quantità di unità di acquisto predefinita"
|
||||
|
||||
msgid "This is the default quantity unit used when consuming this product"
|
||||
msgstr ""
|
||||
|
@@ -1157,9 +1157,6 @@ msgstr "期限なし"
|
||||
msgid "Today"
|
||||
msgstr "今日"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr ""
|
||||
|
||||
|
@@ -1169,9 +1169,6 @@ msgstr "Never"
|
||||
msgid "Today"
|
||||
msgstr "오늘"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "작업 되돌리기"
|
||||
|
||||
|
@@ -1238,9 +1238,6 @@ msgstr "Niekada"
|
||||
msgid "Today"
|
||||
msgstr "Šiandien"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Ne visi recepto „%s“ ingredientai yra sandėlyje, nieko nėra pašalinta"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Anuliuoti užduotį"
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
# Daan Breur <daanbreur@gmail.com>, 2021
|
||||
# Luc Donderwinkel, 2022
|
||||
# 36d163aedfa797f6b2721cfc9bae9c42_308433e, 2023
|
||||
# Matthijs <matthijs@spamkip.com>, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -22,7 +23,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: 36d163aedfa797f6b2721cfc9bae9c42_308433e, 2023\n"
|
||||
"Last-Translator: Matthijs <matthijs@spamkip.com>, 2023\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/grocy/teams/93189/nl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -402,26 +403,26 @@ msgstr "Oekraïens"
|
||||
|
||||
msgid "Kilogram"
|
||||
msgid_plural "Kilograms"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "Kilogram"
|
||||
msgstr[1] "Kilogrammen"
|
||||
|
||||
msgid "Romanian"
|
||||
msgstr "Roemeense"
|
||||
|
||||
msgid "Pint"
|
||||
msgstr ""
|
||||
msgstr "Pint"
|
||||
|
||||
msgid "Beverages"
|
||||
msgstr ""
|
||||
msgstr "Dranken"
|
||||
|
||||
msgid "Ice Cream"
|
||||
msgstr ""
|
||||
msgstr "IJs"
|
||||
|
||||
msgid "Soda"
|
||||
msgstr ""
|
||||
msgstr "Frisdrank"
|
||||
|
||||
msgid "Beer"
|
||||
msgstr ""
|
||||
msgstr "Bier"
|
||||
|
||||
msgid "Estonian"
|
||||
msgstr ""
|
||||
msgstr "Estisch"
|
||||
|
@@ -2,7 +2,7 @@
|
||||
# Translators:
|
||||
# Stan Overgauw <stan.overgauw@gmail.com>, 2020
|
||||
# Luc Donderwinkel, 2022
|
||||
# 36d163aedfa797f6b2721cfc9bae9c42_308433e, 2023
|
||||
# Matthijs <transifex.com@brievenbus.6689.nl>, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2020-08-31 19:11+0000\n"
|
||||
"Last-Translator: 36d163aedfa797f6b2721cfc9bae9c42_308433e, 2023\n"
|
||||
"Last-Translator: Matthijs <transifex.com@brievenbus.6689.nl>, 2023\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/grocy/teams/93189/nl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -121,7 +121,7 @@ msgstr "Hebreeuws"
|
||||
|
||||
# Tamil
|
||||
msgid "ta"
|
||||
msgstr "Tamils"
|
||||
msgstr "Tamil"
|
||||
|
||||
# Finnish
|
||||
msgid "fi"
|
||||
@@ -141,8 +141,8 @@ msgstr "Oekraïens"
|
||||
|
||||
# Romanian
|
||||
msgid "ro_RO"
|
||||
msgstr "ro_RO"
|
||||
msgstr "Roemeens"
|
||||
|
||||
# Estonian
|
||||
msgid "et_EE"
|
||||
msgstr ""
|
||||
msgstr "Estisch"
|
||||
|
@@ -32,6 +32,7 @@
|
||||
# Pieter Vantorre, 2022
|
||||
# Luc Donderwinkel, 2022
|
||||
# vanhoof.tech, 2023
|
||||
# Matthijs <matthijs@spamkip.com>, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -39,7 +40,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: vanhoof.tech, 2023\n"
|
||||
"Last-Translator: Matthijs <matthijs@spamkip.com>, 2023\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/grocy/teams/93189/nl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -385,7 +386,7 @@ msgid "Removed %1$s of %2$s from stock"
|
||||
msgstr "%1$s %2$s verwijderd uit de voorraad"
|
||||
|
||||
msgid "About Grocy"
|
||||
msgstr ""
|
||||
msgstr "Over Grocy"
|
||||
|
||||
msgid "Close"
|
||||
msgstr "Sluit"
|
||||
@@ -1243,11 +1244,6 @@ msgstr "Nooit"
|
||||
msgid "Today"
|
||||
msgstr "Vandaag"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Niet alle ingrediënten van het recept \"%s\" zijn op voorraad, er is niets "
|
||||
"verwijderd"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Taak ongedaan maken"
|
||||
|
||||
@@ -1353,7 +1349,11 @@ msgid_plural ""
|
||||
"This means the next execution of this chore is scheduled at the same time "
|
||||
"(based on the start date) every %s days"
|
||||
msgstr[0] ""
|
||||
"Dit betekent dat de volgende uitvoering van dit klusje iedere dag op "
|
||||
"hetzelfde tijdstip (gebaseerd op de startdatum) gepland wordt"
|
||||
msgstr[1] ""
|
||||
"Dit betekent dat de volgende uitvoering van dit klusje iedere %s dagen op "
|
||||
"hetzelfde tijdstip (gebaseerd op de startdatum) gepland wordt"
|
||||
|
||||
msgid ""
|
||||
"This means the next execution of this chore is scheduled %s hour after the "
|
||||
@@ -1362,7 +1362,11 @@ msgid_plural ""
|
||||
"This means the next execution of this chore is scheduled %s hours after the "
|
||||
"last execution"
|
||||
msgstr[0] ""
|
||||
"Dit betekent dat de uitvoering van dit klusje %s uur na de laatste "
|
||||
"uitvoering gepland wordt"
|
||||
msgstr[1] ""
|
||||
"Dit betekent dat de uitvoering van dit klusje %s uur na de laatste "
|
||||
"uitvoering gepland wordt"
|
||||
|
||||
msgid ""
|
||||
"This means the next execution of this chore is scheduled every week on the "
|
||||
@@ -1371,7 +1375,11 @@ msgid_plural ""
|
||||
"This means the next execution of this chore is scheduled every %s weeks on "
|
||||
"the selected weekdays"
|
||||
msgstr[0] ""
|
||||
"Dit betekent dat de volgende uitvoering van dit klusje elke week gepland "
|
||||
"staat voor de geselecteerde weekdagen"
|
||||
msgstr[1] ""
|
||||
"Dit betekent dat de volgende uitvoering van dit klusje elke %s weken gepland"
|
||||
" staat voor de geselecteerde weekdagen"
|
||||
|
||||
msgid ""
|
||||
"This means the next execution of this chore is scheduled on the selected day"
|
||||
@@ -1380,7 +1388,11 @@ msgid_plural ""
|
||||
"This means the next execution of this chore is scheduled on the selected day"
|
||||
" every %s months"
|
||||
msgstr[0] ""
|
||||
"Dit betekent dat de volgende uitvoering van dit klusje iedere maand op de "
|
||||
"geselecteerde dag gepland staat"
|
||||
msgstr[1] ""
|
||||
"Dit betekent dat de volgende uitvoering van dit klusje iedere %s maanden op "
|
||||
"de geselecteerde dag gepland staat"
|
||||
|
||||
msgid "This means the next execution of this chore is not scheduled"
|
||||
msgstr ""
|
||||
@@ -1492,7 +1504,7 @@ msgid "Price factor"
|
||||
msgstr "Prijsfactor"
|
||||
|
||||
msgid "Do you find Grocy useful?"
|
||||
msgstr ""
|
||||
msgstr "Vind je Grocy nuttig?"
|
||||
|
||||
msgid "Say thanks"
|
||||
msgstr "Zeg bedankt"
|
||||
@@ -1510,7 +1522,7 @@ msgid "Output"
|
||||
msgstr "Uitvoer"
|
||||
|
||||
msgid "Energy"
|
||||
msgstr ""
|
||||
msgstr "Energie"
|
||||
|
||||
msgid "Per stock quantity unit"
|
||||
msgstr "Voorraadhoeveelheidseenheid"
|
||||
@@ -1578,7 +1590,11 @@ msgid_plural ""
|
||||
"This means the next execution of this chore is scheduled every %s years on "
|
||||
"the same day (based on the start date)"
|
||||
msgstr[0] ""
|
||||
"Dit betekent dat de volgende uitvoering van dit klusje ieder jaar op "
|
||||
"dezelfde dag (op basis van de startdatum) gepland staat"
|
||||
msgstr[1] ""
|
||||
"Dit betekent dat de volgende uitvoering van dit klusje iedere %s jaar op "
|
||||
"dezelfde dag (op basis van de startdatum) gepland staat"
|
||||
|
||||
msgid "Transfer"
|
||||
msgstr "Overdragen"
|
||||
@@ -1623,6 +1639,9 @@ msgid ""
|
||||
"Camera access is only possible when supported and allowed by your browser "
|
||||
"and when Grocy is served via a secure (https://) connection"
|
||||
msgstr ""
|
||||
"Camera-toegang is alleen mogelijk als dit ondersteund en toegestaan is door "
|
||||
"je browser, en als Grocy via een beveiligde (https://) verbinding wordt "
|
||||
"geopend"
|
||||
|
||||
msgid "Keep screen on"
|
||||
msgstr "Houd scherm aan"
|
||||
@@ -1944,7 +1963,7 @@ msgid "Chore journal"
|
||||
msgstr "Klusjesdagboek"
|
||||
|
||||
msgid "Track next chore schedule"
|
||||
msgstr ""
|
||||
msgstr "Voer volgend klusje uit"
|
||||
|
||||
msgid "Mark task as completed"
|
||||
msgstr "Markeer taak als gedaan"
|
||||
@@ -1971,6 +1990,8 @@ msgid ""
|
||||
"This is the default quantity unit used on purchase and when adding this "
|
||||
"product to the shopping list"
|
||||
msgstr ""
|
||||
"Dit is de standaardhoeveelheid die wordt gebruikt bij aankoop en bij het "
|
||||
"toevoegen van dit product aan de boodschappenlijst"
|
||||
|
||||
msgid ""
|
||||
"Show a warning when the due date of the purchased product is earlier than "
|
||||
@@ -1998,11 +2019,15 @@ msgid ""
|
||||
"This amount is used for the \"quick consume button\" on the stock overview "
|
||||
"page (related to quantity unit stock)"
|
||||
msgstr ""
|
||||
"Deze hoeveelheid wordt gebruikt voor de \"snel verbruiken knop\" op de "
|
||||
"voorraadoverzichtspagina (gerelateerd aan hoeveelheidsvoorraad)"
|
||||
|
||||
msgid ""
|
||||
"This amount is used for the \"quick open button\" on the stock overview page"
|
||||
" (related to quantity unit stock)"
|
||||
msgstr ""
|
||||
"Deze hoeveelheid wordt gebruikt voor de \"snel openen knop\" op de "
|
||||
"voorraadoverzichtspagina (gerelateerd aan hoeveelheidsvoorraad)"
|
||||
|
||||
msgid "Copy"
|
||||
msgstr "Kopieer"
|
||||
@@ -2293,19 +2318,21 @@ msgid "A product or a note is required"
|
||||
msgstr "Een product of notitie is nodig"
|
||||
|
||||
msgid "Grocycode"
|
||||
msgstr ""
|
||||
msgstr "Grocycode"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "Download"
|
||||
|
||||
# Example: Download *Product* Grocycode
|
||||
msgid "Download %s Grocycode"
|
||||
msgstr ""
|
||||
msgstr "%s Grocycode downloaden"
|
||||
|
||||
msgid ""
|
||||
"Grocycode is a unique referer to this %s in your Grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
"Grocycode is een unieke verwijzing naar dit %s in je Grocy omgeving - print "
|
||||
"het op een label en scan het net als iedere andere barcode"
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
@@ -2334,7 +2361,7 @@ msgstr "Fout tijdens het uitvoeren van WebHook"
|
||||
|
||||
# Example: Print *Product* Grocycode on label printer
|
||||
msgid "Print %s Grocycode on label printer"
|
||||
msgstr ""
|
||||
msgstr "Print %s Grocycode op labelprinter"
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr "Open voorraad invoer label in een nieuw venster"
|
||||
@@ -2559,6 +2586,8 @@ msgid ""
|
||||
"This means the next execution of this chore is scheduled dynamically based "
|
||||
"on the past average execution frequency"
|
||||
msgstr ""
|
||||
"Dit betekent dat de volgende uitvoering van dit klusje dynamisch wordt "
|
||||
"gepland op basis van de gemiddelde voorgaande uitvoeringen"
|
||||
|
||||
msgid "Average execution frequency"
|
||||
msgstr "Gemiddelde uitvoeringsfrequentie"
|
||||
@@ -2690,13 +2719,13 @@ msgstr ""
|
||||
"hoeveelheidseenheden en hun afgeleide conversiefactoren"
|
||||
|
||||
msgid "Show resolved conversions"
|
||||
msgstr ""
|
||||
msgstr "Toon opgeloste conversies"
|
||||
|
||||
msgid "QU conversions resolved"
|
||||
msgstr ""
|
||||
msgstr "Hoeveelheidseenheid conversies opgelost"
|
||||
|
||||
msgid "Product specifc QU conversions"
|
||||
msgstr ""
|
||||
msgstr "Product-specifieke hoeveelheidseenheid conversies"
|
||||
|
||||
msgid "Default quantity unit consume"
|
||||
msgstr "Standaard verbruikte hoeveelheidseenheid"
|
||||
@@ -2728,61 +2757,63 @@ msgstr ""
|
||||
"bijbehorende standaard vervaldagen) het label opnieuw afdrukken"
|
||||
|
||||
msgid "Quick open amount"
|
||||
msgstr ""
|
||||
msgstr "Snel deze hoeveelheid openen"
|
||||
|
||||
msgid "Track chore execution now"
|
||||
msgstr ""
|
||||
msgstr "Voer klusje nu uit"
|
||||
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
msgstr "Totaal"
|
||||
|
||||
msgid "Apply"
|
||||
msgstr ""
|
||||
msgstr "Toepassen"
|
||||
|
||||
msgid "Custom range"
|
||||
msgstr ""
|
||||
msgstr "Aangepast bereik"
|
||||
|
||||
msgid "Yesterday"
|
||||
msgstr ""
|
||||
msgstr "Gisteren"
|
||||
|
||||
msgid "Last %1$s day"
|
||||
msgid_plural "Last %1$s days"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "Laatste %1$s dag"
|
||||
msgstr[1] "Laatste %1$s dagen"
|
||||
|
||||
msgid "This month"
|
||||
msgstr ""
|
||||
msgstr "Deze maand"
|
||||
|
||||
msgid "Last month"
|
||||
msgstr ""
|
||||
msgstr "Vorige maand"
|
||||
|
||||
msgid "This year"
|
||||
msgstr ""
|
||||
msgstr "Dit jaar"
|
||||
|
||||
msgid "Last year"
|
||||
msgstr ""
|
||||
msgstr "Vorig jaar"
|
||||
|
||||
msgid "Reports"
|
||||
msgstr ""
|
||||
msgstr "Rapporten"
|
||||
|
||||
msgid "Spendings"
|
||||
msgstr ""
|
||||
msgstr "Uitgaven"
|
||||
|
||||
msgid "Stock report"
|
||||
msgstr ""
|
||||
msgstr "Voorraadrapport"
|
||||
|
||||
msgid "Out-of-stock products"
|
||||
msgstr ""
|
||||
msgstr "Producten niet op voorraad"
|
||||
|
||||
msgid "Quantity unit for prices"
|
||||
msgstr ""
|
||||
msgstr "Hoeveelheidseenheid voor prijzen"
|
||||
|
||||
msgid ""
|
||||
"When displaying prices for this product, they will be related to this "
|
||||
"quantity unit"
|
||||
msgstr ""
|
||||
"Bij het tonen van prijzen voor dit product, worden deze gerelateerd aan deze"
|
||||
" hoeveelheidseenheid"
|
||||
|
||||
msgid "This means 1 label will be printed"
|
||||
msgid_plural "This means %1$s labels will be printed"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "Dit betekend dat 1 label wordt geprint"
|
||||
msgstr[1] "Dit betekend dat %1$s labels worden geprint"
|
||||
|
@@ -1206,11 +1206,6 @@ msgstr "Aldri"
|
||||
msgid "Today"
|
||||
msgstr "I dag"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Ikke alle ingrediensene i oppskriften \"%s\" er på lager, så ingenting er "
|
||||
"fjernet!"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Angre oppgave"
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
# Kamila Frej, 2022
|
||||
# Michał G, 2022
|
||||
# Oskar Sawaryn, 2023
|
||||
# orl0pl, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -17,7 +18,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Oskar Sawaryn, 2023\n"
|
||||
"Last-Translator: orl0pl, 2023\n"
|
||||
"Language-Team: Polish (https://app.transifex.com/grocy/teams/93189/pl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -422,7 +423,7 @@ msgid "Romanian"
|
||||
msgstr "Rumuński"
|
||||
|
||||
msgid "Pint"
|
||||
msgstr ""
|
||||
msgstr "Pół kwarty"
|
||||
|
||||
msgid "Beverages"
|
||||
msgstr "Napoje"
|
||||
@@ -431,10 +432,10 @@ msgid "Ice Cream"
|
||||
msgstr "Lody"
|
||||
|
||||
msgid "Soda"
|
||||
msgstr ""
|
||||
msgstr "Soda"
|
||||
|
||||
msgid "Beer"
|
||||
msgstr "Piwo"
|
||||
|
||||
msgid "Estonian"
|
||||
msgstr ""
|
||||
msgstr "Estoński"
|
||||
|
@@ -19,6 +19,7 @@
|
||||
# Kamila Frej, 2022
|
||||
# Michał G, 2022
|
||||
# Oskar Sawaryn, 2023
|
||||
# orl0pl, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -26,7 +27,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Oskar Sawaryn, 2023\n"
|
||||
"Last-Translator: orl0pl, 2023\n"
|
||||
"Language-Team: Polish (https://app.transifex.com/grocy/teams/93189/pl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -384,7 +385,7 @@ msgid "Removed %1$s of %2$s from stock"
|
||||
msgstr "%2$s - %1$s - usunięto z zapasów"
|
||||
|
||||
msgid "About Grocy"
|
||||
msgstr ""
|
||||
msgstr "O Grocy"
|
||||
|
||||
msgid "Close"
|
||||
msgstr "Zamknij"
|
||||
@@ -895,6 +896,9 @@ msgid ""
|
||||
"The first item in this list would be picked by the default rule consume rule"
|
||||
" (Opened first, then first due first, then first in first out)"
|
||||
msgstr ""
|
||||
"Pierwszy element na tej liście zostanie wybrany domyślną regułą, którą jest "
|
||||
"\"Otwarte najpierw, następnie najszybciej przeterminowane, następnie "
|
||||
"pierwsze weszło-pierwsze wyszło\""
|
||||
|
||||
msgid "Mark %1$s of %2$s as open"
|
||||
msgstr "%2$s - %1$s - oznacz jako otwarte"
|
||||
@@ -1249,11 +1253,6 @@ msgstr "Nigdy"
|
||||
msgid "Today"
|
||||
msgstr "Dzisiaj"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Nie wszystkie składniki przepisu \"%s\" są dostępne, nic nie zostało "
|
||||
"usunięte"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Cofnij zadanie"
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
# Danilo Vieira <cebikyn@gmail.com>, 2019
|
||||
# Jefferson Brito Passos dos Santos <jeffersantoss@gmail.com>, 2019
|
||||
# Ryan Monteiro, 2022
|
||||
# Arthur Rodrigues <araruna@gmail.com>, 2022
|
||||
# Arthur Rodrigues <transifex@araruna.me>, 2022
|
||||
# Aurelio Barreto <aurelio@aureliobarreto.com>, 2023
|
||||
#
|
||||
msgid ""
|
||||
|
@@ -133,10 +133,10 @@ msgid "Battery"
|
||||
msgstr "Bateria"
|
||||
|
||||
msgid "Last charged"
|
||||
msgstr "Última Carga"
|
||||
msgstr "Último Carregamento"
|
||||
|
||||
msgid "Next planned charge cycle"
|
||||
msgstr "Próximo ciclo de carga prevista"
|
||||
msgstr "Próxima recarga"
|
||||
|
||||
msgid "Best before"
|
||||
msgstr "Melhor consumido antes de "
|
||||
@@ -572,7 +572,7 @@ msgstr "Diários"
|
||||
|
||||
msgid "0 means suggestions for the next charge cycle are disabled"
|
||||
msgstr ""
|
||||
"0 significa que as sugestões para o próximo ciclo de carga estão "
|
||||
"0 (zero) significa que as sugestões para o próximo ciclo de carga estão "
|
||||
"desabilitados"
|
||||
|
||||
msgid "Charge cycle interval (days)"
|
||||
@@ -913,7 +913,7 @@ msgid "Chore due"
|
||||
msgstr "Ativ."
|
||||
|
||||
msgid "Battery charge cycle due"
|
||||
msgstr "Vence carga"
|
||||
msgstr "Carregar"
|
||||
|
||||
msgid "Show clock in header"
|
||||
msgstr "Exibir relógio no cabeçalho"
|
||||
@@ -1240,11 +1240,6 @@ msgstr "Nunca"
|
||||
msgid "Today"
|
||||
msgstr "Hoje"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Nem todos os ingredientes da receita \"%s\" estão no estoque, nada foi "
|
||||
"removido"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Desfazer tarefa"
|
||||
|
||||
@@ -1976,7 +1971,7 @@ msgid "Mark task as completed"
|
||||
msgstr "Marcar a tarefa como concluída"
|
||||
|
||||
msgid "Track charge cycle"
|
||||
msgstr "Rastrear ciclo de recarga"
|
||||
msgstr "Atualizar ciclo de recarga"
|
||||
|
||||
msgid "Battery journal"
|
||||
msgstr "Diário"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2019
|
||||
# Arthur Rodrigues <araruna@gmail.com>, 2022
|
||||
# Arthur Rodrigues <transifex@araruna.me>, 2022
|
||||
# Fernando Luiz Bonifácio de Oliveira, 2022
|
||||
#
|
||||
msgid ""
|
||||
|
@@ -1226,11 +1226,6 @@ msgstr "Nunca"
|
||||
msgid "Today"
|
||||
msgstr "Hoje"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
"Nem todos os ingredientes da receita \"%s\" estão em stock, nada foi "
|
||||
"removido"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Desfazer tarefa"
|
||||
|
||||
|
@@ -1224,9 +1224,6 @@ msgstr "Niciodată"
|
||||
msgid "Today"
|
||||
msgstr "Astăzi"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Nu toate ingredientele rețetei \"%s\" sunt în stoc, nimic eliminat"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Anulați sarcina"
|
||||
|
||||
|
@@ -1253,9 +1253,6 @@ msgstr "Никогда"
|
||||
msgid "Today"
|
||||
msgstr "Сегодня"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Не все ингредиенты рецепта \"%s\" есть в запасе, ничего не изъято"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Отменить задание"
|
||||
|
||||
@@ -2741,10 +2738,10 @@ msgid "Track chore execution now"
|
||||
msgstr ""
|
||||
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
msgstr "Всего"
|
||||
|
||||
msgid "Apply"
|
||||
msgstr ""
|
||||
msgstr "Применить"
|
||||
|
||||
msgid "Custom range"
|
||||
msgstr ""
|
||||
@@ -2769,13 +2766,13 @@ msgid "This year"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last year"
|
||||
msgstr ""
|
||||
msgstr "Прошлый год"
|
||||
|
||||
msgid "Reports"
|
||||
msgstr ""
|
||||
msgstr "Отчеты"
|
||||
|
||||
msgid "Spendings"
|
||||
msgstr ""
|
||||
msgstr "Расходы"
|
||||
|
||||
msgid "Stock report"
|
||||
msgstr ""
|
||||
|
@@ -1228,9 +1228,6 @@ msgstr "Nikdy"
|
||||
msgid "Today"
|
||||
msgstr "Dnes"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Nie všetky suroviny v recepte \"%s\" sú v zásobe, nič nebude odstránené"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Zrušiť úlohu"
|
||||
|
||||
|
@@ -1218,9 +1218,6 @@ msgstr "Nikoli"
|
||||
msgid "Today"
|
||||
msgstr "Danes"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Nekatere sestavine recepta \"%s\" so na zalogi, ničesar ne bo odstranjeno"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Razveljavi opravilo"
|
||||
|
||||
|
@@ -1139,9 +1139,6 @@ msgstr ""
|
||||
msgid "Today"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr ""
|
||||
|
||||
|
@@ -1216,9 +1216,6 @@ msgstr "Aldrig"
|
||||
msgid "Today"
|
||||
msgstr "Idag"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Inte alla ingredienser i recept \"%s\" finns i lager, inget togs bort"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Ångra uppgift"
|
||||
|
||||
|
@@ -1175,9 +1175,6 @@ msgstr "ஒருபோதும் இல்லை"
|
||||
msgid "Today"
|
||||
msgstr "இன்று"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr ""
|
||||
|
||||
|
@@ -1192,9 +1192,6 @@ msgstr "Asla"
|
||||
msgid "Today"
|
||||
msgstr "Bugün"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Görevi geri al"
|
||||
|
||||
|
@@ -1236,9 +1236,6 @@ msgstr "Ніколи"
|
||||
msgid "Today"
|
||||
msgstr "Сьогодні"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "Не усі інгрідієнти рецепту \"%s\" є в наявності, нічого не видалено"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "Відмінити завдання"
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
# Weicheng Ao, 2022
|
||||
# 冠南 胡, 2023
|
||||
# foo bar, 2023
|
||||
# 石磊, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -15,7 +16,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: foo bar, 2023\n"
|
||||
"Last-Translator: 石磊, 2023\n"
|
||||
"Language-Team: Chinese (China) (https://app.transifex.com/grocy/teams/93189/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -45,17 +46,17 @@ msgstr[0] "%s件产品过期"
|
||||
|
||||
msgid "%s product is below defined min. stock amount"
|
||||
msgid_plural "%s products are below defined min. stock amount"
|
||||
msgstr[0] "%s产品低于定义的最小库存"
|
||||
msgstr[0] "%s件产品低于定义的最小库存"
|
||||
|
||||
msgid "Product"
|
||||
msgstr "产品"
|
||||
|
||||
msgid "%s Product"
|
||||
msgid_plural "%s Products"
|
||||
msgstr[0] "%s产品"
|
||||
msgstr[0] "%s件产品"
|
||||
|
||||
msgid "Amount"
|
||||
msgstr "总量"
|
||||
msgstr "数量"
|
||||
|
||||
msgid "Logout"
|
||||
msgstr "注销"
|
||||
@@ -67,7 +68,7 @@ msgid "Batteries overview"
|
||||
msgstr "电池总览"
|
||||
|
||||
msgid "Purchase"
|
||||
msgstr "购买"
|
||||
msgstr "采购"
|
||||
|
||||
msgid "Consume"
|
||||
msgstr "消耗"
|
||||
@@ -103,7 +104,7 @@ msgid "Chore"
|
||||
msgstr "家务"
|
||||
|
||||
msgid "Next estimated tracking"
|
||||
msgstr "接下来预测追踪"
|
||||
msgstr "预计下次跟踪时间"
|
||||
|
||||
msgid "Last tracked"
|
||||
msgstr "上次记录时间"
|
||||
@@ -130,7 +131,7 @@ msgid "Stock quantity unit"
|
||||
msgstr "库存数量单位"
|
||||
|
||||
msgid "Stock amount"
|
||||
msgstr "库存总量"
|
||||
msgstr "库存数量"
|
||||
|
||||
msgid "Last purchased"
|
||||
msgstr "上次购买时间"
|
||||
@@ -149,10 +150,10 @@ msgid ""
|
||||
msgstr "提交时加入所选商品的条形码清单"
|
||||
|
||||
msgid "New amount"
|
||||
msgstr "新增总量"
|
||||
msgstr "新增数量"
|
||||
|
||||
msgid "Note"
|
||||
msgstr "便签"
|
||||
msgstr "备注"
|
||||
|
||||
msgid "Tracked time"
|
||||
msgstr "记录时间"
|
||||
@@ -170,7 +171,7 @@ msgid "Charge cycles count"
|
||||
msgstr "充电周期次数"
|
||||
|
||||
msgid "Create shopping list item"
|
||||
msgstr "创建购物清单条目"
|
||||
msgstr "新建购物清单条目"
|
||||
|
||||
msgid "Edit shopping list item"
|
||||
msgstr "编辑购物清单条目"
|
||||
@@ -200,25 +201,25 @@ msgid "Barcode(s)"
|
||||
msgstr "条形码"
|
||||
|
||||
msgid "Minimum stock amount"
|
||||
msgstr "最小库存总量"
|
||||
msgstr "最小库存数量"
|
||||
|
||||
msgid "Default best before days"
|
||||
msgstr "默认最好早于"
|
||||
|
||||
msgid "Default quantity unit purchase"
|
||||
msgstr "默认购买数量单位"
|
||||
msgstr "默认采购数量单位"
|
||||
|
||||
msgid "Quantity unit stock"
|
||||
msgstr "库存数量单位"
|
||||
|
||||
msgid "Create location"
|
||||
msgstr "创建位置"
|
||||
msgstr "新建位置"
|
||||
|
||||
msgid "Create store"
|
||||
msgstr "创建商店"
|
||||
msgstr "新建商店"
|
||||
|
||||
msgid "Create quantity unit"
|
||||
msgstr "创建数量单位"
|
||||
msgstr "新建数量单位"
|
||||
|
||||
msgid "Period type"
|
||||
msgstr "周期类型"
|
||||
@@ -227,13 +228,13 @@ msgid "Period days"
|
||||
msgstr "周期天数"
|
||||
|
||||
msgid "Create chore"
|
||||
msgstr "创建家务"
|
||||
msgstr "新建家务"
|
||||
|
||||
msgid "Used in"
|
||||
msgstr "使用于"
|
||||
|
||||
msgid "Create battery"
|
||||
msgstr "创建电池"
|
||||
msgstr "新建电池"
|
||||
|
||||
msgid "Edit battery"
|
||||
msgstr "编辑电池"
|
||||
@@ -242,7 +243,7 @@ msgid "Edit chore"
|
||||
msgstr "编辑家务"
|
||||
|
||||
msgid "Edit quantity unit"
|
||||
msgstr "修改数量单位"
|
||||
msgstr "编辑数量单位"
|
||||
|
||||
msgid "Edit product"
|
||||
msgstr "编辑产品"
|
||||
@@ -251,7 +252,7 @@ msgid "Edit location"
|
||||
msgstr "编辑位置"
|
||||
|
||||
msgid "Edit store"
|
||||
msgstr "修改商店"
|
||||
msgstr "编辑商店"
|
||||
|
||||
msgid "Manage master data"
|
||||
msgstr "管理主数据"
|
||||
@@ -260,7 +261,7 @@ msgid "This will apply to added products"
|
||||
msgstr "这将应用于新增商品"
|
||||
|
||||
msgid "never"
|
||||
msgstr "从不"
|
||||
msgstr "永不"
|
||||
|
||||
msgid "Add products that are below defined min. stock amount"
|
||||
msgstr "添加低于最低库存数量的商品"
|
||||
@@ -281,7 +282,7 @@ msgid "Are you sure to delete battery \"%s\"?"
|
||||
msgstr "确定删除电池%s吗?"
|
||||
|
||||
msgid "Yes"
|
||||
msgstr "确定"
|
||||
msgstr "是"
|
||||
|
||||
msgid "No"
|
||||
msgstr "否"
|
||||
@@ -320,19 +321,19 @@ msgid "Are you sure to delete store \"%s\"?"
|
||||
msgstr "确定删除商店%s"
|
||||
|
||||
msgid "Manage API keys"
|
||||
msgstr "管理API 秘钥"
|
||||
msgstr "管理API 密钥"
|
||||
|
||||
msgid "REST API browser"
|
||||
msgstr "REST API 浏览器"
|
||||
msgstr "浏览REST API"
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "API 秘钥"
|
||||
msgstr "API 密钥"
|
||||
|
||||
msgid "Create new API key"
|
||||
msgstr "创建新API 秘钥"
|
||||
msgstr "新建API密钥"
|
||||
|
||||
msgid "API key"
|
||||
msgstr "API 秘钥"
|
||||
msgstr "API 密钥"
|
||||
|
||||
msgid "Expires"
|
||||
msgstr "过期"
|
||||
@@ -395,7 +396,7 @@ msgid "You have to select a battery"
|
||||
msgstr "请选择一个电池"
|
||||
|
||||
msgid "A name is required"
|
||||
msgstr "请填写名字"
|
||||
msgstr "请填写名称"
|
||||
|
||||
msgid "A location is required"
|
||||
msgstr "请填写位置"
|
||||
@@ -419,25 +420,25 @@ msgid "Calendar"
|
||||
msgstr "日历"
|
||||
|
||||
msgid "Recipes"
|
||||
msgstr "食谱"
|
||||
msgstr "菜谱"
|
||||
|
||||
msgid "Edit recipe"
|
||||
msgstr "编辑食谱"
|
||||
msgstr "编辑菜谱"
|
||||
|
||||
msgid "Ingredients list"
|
||||
msgstr "成分表"
|
||||
msgstr "配料表"
|
||||
|
||||
msgid "Add recipe ingredient"
|
||||
msgstr "添加食谱食材"
|
||||
msgstr "新增菜谱配料"
|
||||
|
||||
msgid "Edit recipe ingredient"
|
||||
msgstr "编辑食谱成分"
|
||||
msgstr "编辑菜谱配料"
|
||||
|
||||
msgid "Are you sure to delete recipe \"%s\"?"
|
||||
msgstr "确定删除食谱 %s"
|
||||
msgstr "您确定要删除菜谱“%s”吗?"
|
||||
|
||||
msgid "Are you sure to delete recipe ingredient \"%s\"?"
|
||||
msgstr "您确定要删除食谱成分\"%s\"吗?"
|
||||
msgstr "您确定要删除菜谱配料“%s”吗?"
|
||||
|
||||
msgid "Are you sure to empty shopping list \"%s\"?"
|
||||
msgstr "你确定要清空购物清单“%s”吗?"
|
||||
@@ -449,7 +450,7 @@ msgid "Requirements fulfilled"
|
||||
msgstr "满足要求"
|
||||
|
||||
msgid "Put missing products on shopping list"
|
||||
msgstr "将缺失的产品列在购物清单上"
|
||||
msgstr "将缺少的产品加入购物清单"
|
||||
|
||||
msgid "Enough in stock"
|
||||
msgstr "库存充足"
|
||||
@@ -470,7 +471,7 @@ msgid "Preparation"
|
||||
msgstr "预备"
|
||||
|
||||
msgid "Recipe"
|
||||
msgstr "食谱"
|
||||
msgstr "菜谱"
|
||||
|
||||
msgid "Not enough in stock, %1$s missing, %2$s already on shopping list"
|
||||
msgstr "库存不足,缺少 %1$s,%2$s 已经在购物清单中 "
|
||||
@@ -484,10 +485,10 @@ msgstr "将丢失的数量列在购物单上"
|
||||
msgid ""
|
||||
"Are you sure to put all missing ingredients for recipe \"%s\" on the "
|
||||
"shopping list?"
|
||||
msgstr "确定要将食谱“%s”中所缺少的食材都列在购物单上吗?"
|
||||
msgstr "您确定要将菜谱“%s”中缺少的全部配料加入采购清单吗?"
|
||||
|
||||
msgid "Added for recipe %s"
|
||||
msgstr "已添加到食谱%s"
|
||||
msgstr "已添加到菜谱%s"
|
||||
|
||||
msgid "Manage users"
|
||||
msgstr "管理用户"
|
||||
@@ -544,7 +545,7 @@ msgid "Charge cycle interval (days)"
|
||||
msgstr "充电周期间隔(天)"
|
||||
|
||||
msgid "Last price"
|
||||
msgstr "最后的价格"
|
||||
msgstr "最近价格"
|
||||
|
||||
msgid "Price history"
|
||||
msgstr "价格历史"
|
||||
@@ -590,13 +591,13 @@ msgstr "只检查是否有任何数量的库存"
|
||||
msgid ""
|
||||
"Are you sure to consume all ingredients needed by recipe \"%s\" (ingredients"
|
||||
" marked with \"only check if any amount is in stock\" will be ignored)?"
|
||||
msgstr "您确定要消耗食谱“%s”中所需的所有成分(标有“仅检查库存量”的成分将被忽略)吗?"
|
||||
msgstr "您确定要消耗菜谱“%s”中需要的全部配料吗(忽略被标记为“仅检查是否有库存”的配料)?"
|
||||
|
||||
msgid "Removed all ingredients of recipe \"%s\" from stock"
|
||||
msgstr "从库存中移除食谱“%s”中所有的食材"
|
||||
msgstr "已从库存中移除菜谱“%s”中的全部配料"
|
||||
|
||||
msgid "Consume all ingredients needed by this recipe"
|
||||
msgstr "消耗此食谱所需的所有成分 "
|
||||
msgstr "消耗此菜谱所需的所有配料"
|
||||
|
||||
msgid "Click to show technical details"
|
||||
msgstr "单击此处显示技术细节"
|
||||
@@ -763,16 +764,16 @@ msgid "Presets for new products"
|
||||
msgstr "新产品预设"
|
||||
|
||||
msgid "Included recipes"
|
||||
msgstr "随附的食谱"
|
||||
msgstr "关联菜谱"
|
||||
|
||||
msgid "A recipe is required"
|
||||
msgstr "请填写食谱"
|
||||
msgstr "请填写菜谱"
|
||||
|
||||
msgid "Add included recipe"
|
||||
msgstr "添加随附的食谱"
|
||||
msgstr "添加关联菜谱"
|
||||
|
||||
msgid "Edit included recipe"
|
||||
msgstr "编辑关联食谱"
|
||||
msgstr "编辑关联菜谱"
|
||||
|
||||
msgid "Group"
|
||||
msgstr "组"
|
||||
@@ -811,7 +812,7 @@ msgid "Charge cycle successfully undone"
|
||||
msgstr "充电周期取消成功"
|
||||
|
||||
msgid "Disable stock fulfillment checking for this ingredient"
|
||||
msgstr "禁用此成分的需求库存检查"
|
||||
msgstr "禁用此配料的库存需求检查"
|
||||
|
||||
msgid "Add all list items to stock"
|
||||
msgstr "将所有列表项添加到库存"
|
||||
@@ -879,7 +880,7 @@ msgid "Costs"
|
||||
msgstr "费用"
|
||||
|
||||
msgid "The ingredients listed here result in this amount of servings"
|
||||
msgstr "这里列出的成分导致份量如此"
|
||||
msgstr "配料可以制作的份数"
|
||||
|
||||
msgid "Do not check against the shopping list when adding missing items to it"
|
||||
msgstr "当把缺少的东西添加到购物清单时,不核对清单"
|
||||
@@ -903,7 +904,7 @@ msgid "This is for statistical purposes only"
|
||||
msgstr "仅作统计用途"
|
||||
|
||||
msgid "You have to select a recipe"
|
||||
msgstr "你必须选择一个食谱"
|
||||
msgstr "请选择一个菜谱"
|
||||
|
||||
msgid "Key type"
|
||||
msgstr "密钥类型"
|
||||
@@ -973,7 +974,7 @@ msgstr "键入新产品名称或条形码,然后按TAB或ENTER键启动工作
|
||||
msgid ""
|
||||
"This will be used as the default setting when adding this product as a "
|
||||
"recipe ingredient"
|
||||
msgstr "当添加此产品作为食谱成分时,这将用作默认设置"
|
||||
msgstr "当添加此产品作为菜谱配料时,这将作为默认设置"
|
||||
|
||||
msgid "Add item"
|
||||
msgstr "添加项目"
|
||||
@@ -997,7 +998,7 @@ msgid "Tasks settings"
|
||||
msgstr "任务设置"
|
||||
|
||||
msgid "Create shopping list"
|
||||
msgstr "创建购物清单"
|
||||
msgstr "新建购物清单"
|
||||
|
||||
msgid "Are you sure to delete shopping list \"%s\"?"
|
||||
msgstr "确认要删除购物清单 “%s” 吗?"
|
||||
@@ -1106,7 +1107,7 @@ msgid "Default location"
|
||||
msgstr "默认位置"
|
||||
|
||||
msgid "Default amount for purchase"
|
||||
msgstr "默认购买数量"
|
||||
msgstr "默认采购数量"
|
||||
|
||||
msgid "Default amount for consume"
|
||||
msgstr "默认消耗数量"
|
||||
@@ -1129,7 +1130,7 @@ msgid "Consume %1$s of %2$s"
|
||||
msgstr "消费%2$s中的%1$s"
|
||||
|
||||
msgid "Meal plan"
|
||||
msgstr "膳食计划"
|
||||
msgstr "饮食计划"
|
||||
|
||||
msgid "%s serving"
|
||||
msgid_plural "%s servings"
|
||||
@@ -1157,14 +1158,11 @@ msgid "per serving"
|
||||
msgstr "每餐份"
|
||||
|
||||
msgid "Never"
|
||||
msgstr "从不"
|
||||
msgstr "永不"
|
||||
|
||||
msgid "Today"
|
||||
msgstr "今天"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "并不是所有的食谱“%s”的成分在库存,没有删除"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "撤销任务"
|
||||
|
||||
@@ -1235,13 +1233,13 @@ msgid "This cannot be equal to %s"
|
||||
msgstr "这不能等于 %s"
|
||||
|
||||
msgid "This means 1 %1$s is the same as %2$s %3$s"
|
||||
msgstr "这意味着1%1$s等于%2$s%3$s"
|
||||
msgstr "1%1$s等同于%2$s%3$s"
|
||||
|
||||
msgid "QU conversions"
|
||||
msgstr "单位转换"
|
||||
|
||||
msgid "Override for product"
|
||||
msgstr "覆盖产品"
|
||||
msgstr "涵盖产品"
|
||||
|
||||
msgid "This equals %1$s %2$s"
|
||||
msgstr "这等于%1$s%2$s"
|
||||
@@ -1379,7 +1377,7 @@ msgstr "初始化条形码扫描库时出错"
|
||||
|
||||
msgid ""
|
||||
"The resulting price of this ingredient will be multiplied by this factor"
|
||||
msgstr "这种成分的最终价格将乘以这个系数"
|
||||
msgstr "此配料的的最终价格将乘以此系数"
|
||||
|
||||
msgid "Price factor"
|
||||
msgstr "价格系数"
|
||||
@@ -1391,7 +1389,7 @@ msgid "Say thanks"
|
||||
msgstr "表示感谢"
|
||||
|
||||
msgid "Search for recipes containing this product"
|
||||
msgstr "搜索含有此产品的食谱"
|
||||
msgstr "搜索含有此产品的菜谱"
|
||||
|
||||
msgid "Add to shopping list"
|
||||
msgstr "加入购物清单"
|
||||
@@ -1427,7 +1425,7 @@ msgid "Miss"
|
||||
msgstr "未命中"
|
||||
|
||||
msgid "Display recipe"
|
||||
msgstr "显示食谱"
|
||||
msgstr "显示菜谱"
|
||||
|
||||
msgid "Accumulate sub products min. stock amount"
|
||||
msgstr "累积子产品的最小库存数量"
|
||||
@@ -1456,7 +1454,7 @@ msgid "Clear"
|
||||
msgstr "清除"
|
||||
|
||||
msgid "Are you sure to remove the included recipe \"%s\"?"
|
||||
msgstr "您确定要删除随附的食谱“%s”吗?"
|
||||
msgstr "您确定要删除关联菜谱“%s”吗?"
|
||||
|
||||
msgid "Period interval"
|
||||
msgstr "时间间隔"
|
||||
@@ -1470,7 +1468,7 @@ msgid_plural ""
|
||||
msgstr[0] "这意味着该任务的下一次执行将安排在每%s年的同一天(基于开始日期) "
|
||||
|
||||
msgid "Transfer"
|
||||
msgstr "迁移"
|
||||
msgstr "转移"
|
||||
|
||||
msgid "From location"
|
||||
msgstr "起点位置"
|
||||
@@ -1482,7 +1480,7 @@ msgid "There are no units available at this location"
|
||||
msgstr "这个地方没有可用的单元"
|
||||
|
||||
msgid "Amount: %1$s; Due on %2$s; Bought on %3$s"
|
||||
msgstr "数额:%1$s;截止期:%2$s;购买日:%3$s"
|
||||
msgstr "数量:%1$s;截止日期:%2$s;采购日期:%3$s"
|
||||
|
||||
msgid "Transfered %1$s of %2$s from %3$s to %4$s"
|
||||
msgstr "将%2$s中的%1$s从%3$s转移到%4$s"
|
||||
@@ -1494,7 +1492,7 @@ msgid "Best before date"
|
||||
msgstr "保质期"
|
||||
|
||||
msgid "Purchased date"
|
||||
msgstr "购买日"
|
||||
msgstr "采购日期"
|
||||
|
||||
msgid "Consume all %s for this stock entry"
|
||||
msgstr "消耗这个库存条目的所有%s"
|
||||
@@ -1520,7 +1518,7 @@ msgid "Keep screen on while displaying a \"fullscreen-card\""
|
||||
msgstr "在显示“全屏幕卡”时保持屏幕打开"
|
||||
|
||||
msgid "A purchased date is required"
|
||||
msgstr "购买日期是必需的"
|
||||
msgstr "采购日期为必填项"
|
||||
|
||||
msgid ""
|
||||
"When a product is selected, one unit (per serving in stock quantity unit) "
|
||||
@@ -1552,16 +1550,16 @@ msgid "Add product"
|
||||
msgstr "添加产品"
|
||||
|
||||
msgid "Consume all ingredients needed by this weeks recipes or products"
|
||||
msgstr "消耗本星期食谱或产品所需的所有原料"
|
||||
msgstr "消耗本星期菜谱或产品中所需的全部配料"
|
||||
|
||||
msgid "Meal plan recipe"
|
||||
msgstr "膳食计划菜谱"
|
||||
msgstr "饮食计划菜谱"
|
||||
|
||||
msgid "Meal plan note"
|
||||
msgstr "膳食计划报告"
|
||||
msgstr "饮食计划备注"
|
||||
|
||||
msgid "Meal plan product"
|
||||
msgstr "膳食计划产品"
|
||||
msgstr "饮食计划产品"
|
||||
|
||||
msgid "Scan mode"
|
||||
msgstr "扫描模式"
|
||||
@@ -1604,13 +1602,13 @@ msgid "Base: %s"
|
||||
msgstr "基础:%s"
|
||||
|
||||
msgid "Recipes settings"
|
||||
msgstr "配方设置"
|
||||
msgstr "菜谱设置"
|
||||
|
||||
msgid "Recipe card"
|
||||
msgstr "食谱卡"
|
||||
msgstr "菜谱卡片"
|
||||
|
||||
msgid "Group ingredients by their product group"
|
||||
msgstr "按产品组对成分进行分组"
|
||||
msgstr "按产品组对配料进行分组"
|
||||
|
||||
msgid "Unknown store"
|
||||
msgstr "未知商店"
|
||||
@@ -1649,25 +1647,25 @@ msgid "means %1$s per %2$s"
|
||||
msgstr "每%2$s,%1$s财产"
|
||||
|
||||
msgid "Create recipe"
|
||||
msgstr "创建配方"
|
||||
msgstr "新建菜谱"
|
||||
|
||||
msgid "Save & continue to add ingredients and included recipes"
|
||||
msgstr "保存并继续添加配料和包括食谱"
|
||||
msgstr "保存并继续添加配料和关联菜谱"
|
||||
|
||||
msgid "Save & continue"
|
||||
msgstr "保存并继续"
|
||||
|
||||
msgid "Save & return to recipes"
|
||||
msgstr "保存并返回食谱"
|
||||
msgstr "保存并返回菜谱"
|
||||
|
||||
msgid "Stock value"
|
||||
msgstr "库存量"
|
||||
msgstr "库存金额"
|
||||
|
||||
msgid "Average price"
|
||||
msgstr "平均价格"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "有效的"
|
||||
msgstr "启用"
|
||||
|
||||
msgid "Barcodes"
|
||||
msgstr "条形码"
|
||||
@@ -1691,7 +1689,7 @@ msgid ""
|
||||
msgstr "根据库存原料的默认消费规则(先开、先到期、先进先出)的价格,缺货原料的最后价格 "
|
||||
|
||||
msgid "Clear filter"
|
||||
msgstr "清除过滤器"
|
||||
msgstr "清除筛选"
|
||||
|
||||
msgid "Permissions for user %s"
|
||||
msgstr "%s用户的权限"
|
||||
@@ -1757,15 +1755,15 @@ msgid "Consume exact amount"
|
||||
msgstr "消费确切数额"
|
||||
|
||||
msgid "Value"
|
||||
msgstr "值"
|
||||
msgstr "价值"
|
||||
|
||||
msgid "%s total value"
|
||||
msgstr "%s总值"
|
||||
msgstr "总价值%s"
|
||||
|
||||
msgid ""
|
||||
"Show purchased date on purchase and inventory page (otherwise the purchased "
|
||||
"date defaults to today)"
|
||||
msgstr "在购买和库存页面显示购买日期(否则购买日期默认为今天)"
|
||||
msgstr "在采购页面和库存页面显示采购日期(否则采购日期默认为当天)"
|
||||
|
||||
msgid "Common"
|
||||
msgstr "通用"
|
||||
@@ -1842,7 +1840,7 @@ msgstr "显示此API密钥的QR码"
|
||||
msgid ""
|
||||
"This is the default quantity unit used on purchase and when adding this "
|
||||
"product to the shopping list"
|
||||
msgstr "这是购买此产品和将此产品加入购物清单时所使用的默认数量单位"
|
||||
msgstr "这是采购此产品和将此产品加入购物清单时所使用的默认数量单位"
|
||||
|
||||
msgid ""
|
||||
"Show a warning when the due date of the purchased product is earlier than "
|
||||
@@ -1901,45 +1899,45 @@ msgstr "指产品过期后食用不安全"
|
||||
msgid ""
|
||||
"For purchases this amount of days will be added to today for the due date "
|
||||
"suggestion"
|
||||
msgstr "对于购买,这个天数将增加到今天的到期日建议"
|
||||
msgstr "建议截止日期,是从采购之日起加上此天数。"
|
||||
|
||||
msgid "-1 means that this product will be never overdue"
|
||||
msgstr "-1表示该产品永远不会过期"
|
||||
|
||||
msgid "Default due days"
|
||||
msgstr "默认到期日"
|
||||
msgstr "默认过期天数"
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr "当该产品被标记为打开时,到期日将被替换为今天+此天数,但只有当结果日期不在原始到期日之后(值为0时禁用此功能) "
|
||||
msgstr "本产品开封后,截止日期替换为开封日期加上此天数,但前提是新生成的日期不在原截止日期之后(值0将禁用此功能)"
|
||||
|
||||
msgid "Default due days after opened"
|
||||
msgstr "开封后默认到期日"
|
||||
msgstr "开封后默认过期天数"
|
||||
|
||||
msgid ""
|
||||
"On moving this product to a freezer location (so when freezing it), the due "
|
||||
"date will be replaced by today + this amount of days"
|
||||
msgstr "将本产品移至冷藏室时(因此将其冷冻时),到期日将替换为今天+该天数"
|
||||
msgstr "本产品放入冰箱时(即冷冻时),截止日期替换为冷冻日期加上此天数"
|
||||
|
||||
msgid "Default due days after freezing"
|
||||
msgstr "冻结后默认到期日"
|
||||
msgstr "冷藏后默认过期天数"
|
||||
|
||||
msgid ""
|
||||
"On moving this product from a freezer location (so when thawing it), the due"
|
||||
" date will be replaced by today + this amount of days"
|
||||
msgstr "当将产品从冷冻室移出时(解冻时),到期日将改为今天+这个天数"
|
||||
msgstr "本产品从冰箱取出时(即解冻时),截止日期替换为解冻日期加上此天数"
|
||||
|
||||
msgid "Default due days after thawing"
|
||||
msgstr "解冻后默认到期日"
|
||||
msgstr "解冻后默认过期天数"
|
||||
|
||||
msgid "Next due date"
|
||||
msgstr "下一个到期日"
|
||||
|
||||
msgid "%s product is due"
|
||||
msgid_plural "%s products are due"
|
||||
msgstr[0] "%s产品到期"
|
||||
msgstr[0] "%s件产品到期"
|
||||
|
||||
msgid "Due date"
|
||||
msgstr "截止日期"
|
||||
@@ -1949,7 +1947,7 @@ msgstr "永不逾期"
|
||||
|
||||
msgid "%s product is expired"
|
||||
msgid_plural "%s products are expired"
|
||||
msgstr[0] "%s产品已过期"
|
||||
msgstr[0] "%s件产品已过期"
|
||||
|
||||
msgid "Expired"
|
||||
msgstr "已过期"
|
||||
@@ -1977,12 +1975,12 @@ msgstr "该值必须在%1$s和%2$s之间,不能等于%3$s,并且必须是有
|
||||
msgid ""
|
||||
"This cannot be lower than %1$s and needs to be a valid number with max. %2$s"
|
||||
" decimal places"
|
||||
msgstr "此数字不能小于%1$s,并且必须是一个有效数字,最大值%2$s为小数位"
|
||||
msgstr "此数字不能小于%1$s,并且最多%2$s位小数位"
|
||||
|
||||
msgid ""
|
||||
"This must between %1$s and %2$s and needs to be a valid number with max. "
|
||||
"%3$s decimal places"
|
||||
msgstr "此数字必须在%1$s和%2$s之间,并且必须是一个有效数字,最大值%3$s为小数位"
|
||||
msgstr "此数字必须在%1$s和%2$s之间,并且最多%3$s位小数位"
|
||||
|
||||
msgid ""
|
||||
"Automatically do the booking using the last price and the amount of the "
|
||||
@@ -2010,7 +2008,7 @@ msgid "Download file"
|
||||
msgstr "下载文件"
|
||||
|
||||
msgid "Use the products \"Quick consume amount\""
|
||||
msgstr "使用产品“快速消费量”"
|
||||
msgstr "使用产品的“快速消耗数量”"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "禁用"
|
||||
@@ -2028,13 +2026,13 @@ msgid "Never show on stock overview"
|
||||
msgstr "不在库存总览显示"
|
||||
|
||||
msgid "None"
|
||||
msgstr "没有"
|
||||
msgstr "无"
|
||||
|
||||
msgid "Group by"
|
||||
msgstr "分组依据"
|
||||
|
||||
msgid "Ingredient group"
|
||||
msgstr "成分组"
|
||||
msgstr "配料分组"
|
||||
|
||||
msgid "Reset"
|
||||
msgstr "重置"
|
||||
@@ -2104,7 +2102,7 @@ msgid ""
|
||||
"The stock overview page lists all products which are currently in-stock or "
|
||||
"below their min. stock amount - enable this to hide this product there "
|
||||
"always"
|
||||
msgstr "库存总览页面列出了当前有库存或低于其最低库存的所有产品。库存量-启用此功能可将其始终隐藏在此处"
|
||||
msgstr "库存总览页面列出了当前在库或低于最小库存量的所有产品。启用此功能始终隐藏此产品"
|
||||
|
||||
msgid "Print options"
|
||||
msgstr "打印选项"
|
||||
@@ -2113,19 +2111,19 @@ msgid "A product or a note is required"
|
||||
msgstr "需要一件产品或一张便条"
|
||||
|
||||
msgid "Grocycode"
|
||||
msgstr ""
|
||||
msgstr "Grocycode"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "下载"
|
||||
|
||||
# Example: Download *Product* Grocycode
|
||||
msgid "Download %s Grocycode"
|
||||
msgstr ""
|
||||
msgstr "下载%sGrocycode"
|
||||
|
||||
msgid ""
|
||||
"Grocycode is a unique referer to this %s in your Grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
msgstr "Grocycode是Grocy实例中此%s的唯一引用,可以像其他条形码一样打印和扫描。"
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
@@ -2154,7 +2152,7 @@ msgstr "执行WebHook时出错"
|
||||
|
||||
# Example: Print *Product* Grocycode on label printer
|
||||
msgid "Print %s Grocycode on label printer"
|
||||
msgstr ""
|
||||
msgstr "打印%sGrocycode"
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr "在新窗口中打开股票库存输入标签"
|
||||
@@ -2214,16 +2212,16 @@ msgid "This product shouldn't be frozen"
|
||||
msgstr "本产品不应冷冻"
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr "复制所有%s的膳食计划"
|
||||
msgstr "复制全部%s的饮食计划条目"
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr "需要一个日期"
|
||||
msgstr "请填写日期"
|
||||
|
||||
msgid "Day"
|
||||
msgstr "日"
|
||||
msgstr "日期"
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr "添加食谱"
|
||||
msgstr "添加菜谱"
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr "复制这一天"
|
||||
@@ -2243,7 +2241,7 @@ msgid "Display product"
|
||||
msgstr "显示产品"
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr "复制食谱"
|
||||
msgstr "复制菜谱"
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr "复制%s"
|
||||
@@ -2264,19 +2262,19 @@ msgid "Configure sections"
|
||||
msgstr "配置部件"
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr "膳食计划部件"
|
||||
msgstr "饮食计划条目"
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr "创建膳食计划部件"
|
||||
msgstr "新增饮食计划条目"
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr "各部件将按膳食计划中的该数字订购"
|
||||
msgstr "在饮食计划表单上,各条目按照该编号进行排序"
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr "编辑膳食计划部分"
|
||||
msgstr "编辑饮食计划条目"
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr "你确定要删除膳食计划\"%s\"吗?"
|
||||
msgstr "您确定要删除饮食计划\"%s\"吗?"
|
||||
|
||||
msgid "Section"
|
||||
msgstr "部件"
|
||||
@@ -2329,7 +2327,7 @@ msgid "Save & add another task"
|
||||
msgstr "保存并添加另一个任务"
|
||||
|
||||
msgid "Treat opened as out of stock"
|
||||
msgstr "一开封即扣除库存"
|
||||
msgstr "开封后核减库存"
|
||||
|
||||
msgid ""
|
||||
"When enabled, opened items will be counted as missing for calculating if "
|
||||
@@ -2355,7 +2353,7 @@ msgid "The start date cannot be changed when the chore was once tracked"
|
||||
msgstr "一旦跟踪了家务,就不能更改开始日期 "
|
||||
|
||||
msgid "Show the recipe list and the recipe side by side"
|
||||
msgstr "并排显示食谱列表和食谱 "
|
||||
msgstr "并排显示菜谱和菜谱清单"
|
||||
|
||||
msgid ""
|
||||
"This means the next execution of this chore is scheduled dynamically based "
|
||||
@@ -2380,16 +2378,16 @@ msgstr "到期分数"
|
||||
msgid ""
|
||||
"The higher this number is, the more ingredients currently in stock are due "
|
||||
"soon, overdue or already expired"
|
||||
msgstr "这个数字越高,说明库存中即将到期、过期或已经过期的成分越多 "
|
||||
msgstr "此数值越高,当前库存中即将过期或已经过期的配料越多"
|
||||
|
||||
msgid "Disable own stock"
|
||||
msgstr "禁用的库存"
|
||||
msgstr "禁用自有库存"
|
||||
|
||||
msgid ""
|
||||
"When enabled, this product can't have own stock, means it will not be "
|
||||
"selectable on purchase (useful for parent products which are just used as a "
|
||||
"summary/total view of the child products)"
|
||||
msgstr "当启用时,该产品不能有自己的库存,意味着在购买时它将不可选(适用于父产品,仅用作子产品的汇总/总体视图) "
|
||||
msgstr "当启用后,此产品不需要库存管理,在采购时不可选(适用于仅用作子产品的汇总/摘要视图的父产品)"
|
||||
|
||||
msgid "Out of stock items will be shown at the products default location"
|
||||
msgstr "无库存项目将显示在产品默认位置 "
|
||||
@@ -2435,24 +2433,24 @@ msgid "Now / today"
|
||||
msgstr "现在/今天"
|
||||
|
||||
msgid "Add meal plan entry"
|
||||
msgstr "添加膳食计划条目"
|
||||
msgstr "添加饮食计划条目"
|
||||
|
||||
msgid "Edit meal plan entry"
|
||||
msgstr "编辑膳食计划条目"
|
||||
msgstr "编辑饮食计划条目"
|
||||
|
||||
msgid "Default consume location"
|
||||
msgstr "默认消耗/食用位置"
|
||||
|
||||
msgid "Stock entries at this location will be consumed first"
|
||||
msgstr "这个位置的库存条目将首先被消费 "
|
||||
msgstr "优先消耗此位置的库存 "
|
||||
|
||||
msgid "Move on open"
|
||||
msgstr "开封时移动到默认使用位置"
|
||||
msgstr "开封后转移"
|
||||
|
||||
msgid ""
|
||||
"When enabled, on marking this product as opened, the corresponding amount "
|
||||
"will be moved to the default consume location"
|
||||
msgstr "勾选后,在将此产品标记为已开封时,相应数量的产品将移动到默认使用位置"
|
||||
msgstr "若启用,当此产品被标记为开封时,相应数量的产品将转移到默认消耗位置"
|
||||
|
||||
msgid "Moved to %1$s"
|
||||
msgstr "移动到%1$s"
|
||||
@@ -2487,10 +2485,10 @@ msgid "This is the default quantity unit used when consuming this product"
|
||||
msgstr "这是消耗此产品时使用的默认数量单位"
|
||||
|
||||
msgid "Add to meal plan"
|
||||
msgstr "添加到膳食计划"
|
||||
msgstr "添加到饮食计划"
|
||||
|
||||
msgid "Successfully added the recipe to the meal plan"
|
||||
msgstr "已将食谱添加到膳食计划"
|
||||
msgstr "已将菜谱添加到饮食计划"
|
||||
|
||||
msgid "Reprint stock entry label"
|
||||
msgstr "重新打印库存输入标签"
|
||||
@@ -2556,7 +2554,7 @@ msgstr ""
|
||||
msgid ""
|
||||
"When displaying prices for this product, they will be related to this "
|
||||
"quantity unit"
|
||||
msgstr ""
|
||||
msgstr "当展示产品价格时,将此数量单位做为产品价格的计算单位"
|
||||
|
||||
msgid "This means 1 label will be printed"
|
||||
msgid_plural "This means %1$s labels will be printed"
|
||||
|
@@ -1158,9 +1158,6 @@ msgstr "從未"
|
||||
msgid "Today"
|
||||
msgstr "今天"
|
||||
|
||||
msgid "Not all ingredients of recipe \"%s\" are in stock, nothing removed"
|
||||
msgstr "食譜「%s」並非所有食材都有庫存,未處理。"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr "取消任務"
|
||||
|
||||
|
@@ -2,10 +2,64 @@ DROP VIEW quantity_unit_conversions_resolved;
|
||||
CREATE VIEW quantity_unit_conversions_resolved
|
||||
AS
|
||||
|
||||
-- First, determine conversions that are a single step.
|
||||
WITH RECURSIVE conversion_factors(product_id, from_qu_id, to_qu_id, factor)
|
||||
WITH RECURSIVE
|
||||
|
||||
-- Default QU conversions are handled in a later CTE, as we can't determine yet, for which products they are applicable.
|
||||
default_conversions(from_qu_id, to_qu_id, factor)
|
||||
AS (
|
||||
-- Priority 1: Product specific QU overrides
|
||||
SELECT
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor
|
||||
FROM quantity_unit_conversions
|
||||
WHERE product_id IS NULL
|
||||
),
|
||||
|
||||
-- First find the closure for all default conversions. This will allow for further pruning when looking for product closure.
|
||||
default_closure(depth, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
-- As a base case, select all available default conversions
|
||||
SELECT
|
||||
1 as depth,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor,
|
||||
'/' || from_qu_id || '/' || to_qu_id || '/' -- We need to keep track of the conversion path in order to prevent cycles
|
||||
FROM default_conversions
|
||||
|
||||
UNION
|
||||
|
||||
-- Recursive case: Find all paths
|
||||
SELECT
|
||||
c.depth + 1,
|
||||
c.from_qu_id,
|
||||
s.to_qu_id,
|
||||
c.factor * s.factor,
|
||||
c.path || s.to_qu_id || '/'
|
||||
FROM default_closure c
|
||||
JOIN default_conversions s
|
||||
ON c.to_qu_id = s.from_qu_id
|
||||
WHERE c.path NOT LIKE ('%/' || s.to_qu_id || '/%') -- Prevent cycles
|
||||
AND NOT EXISTS(SELECT 1 FROM default_conversions ci WHERE ci.from_qu_id = c.from_qu_id AND ci.to_qu_id = s.to_qu_id) -- Prune if one of the existing conversions repeats (saves a lot of processing time)
|
||||
|
||||
),
|
||||
|
||||
default_closure_distinct(from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
SELECT DISTINCT
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
FIRST_VALUE(factor) OVER win AS factor,
|
||||
FIRST_VALUE(path) OVER win AS path
|
||||
FROM default_closure
|
||||
GROUP BY from_qu_id, to_qu_id
|
||||
WINDOW win AS (PARTITION BY from_qu_id, to_qu_id ORDER BY depth)
|
||||
ORDER BY from_qu_id, to_qu_id
|
||||
),
|
||||
|
||||
product_conversions(product_id, from_qu_id, to_qu_id, factor)
|
||||
AS (
|
||||
-- Priority 1: Product-specific QU overrides
|
||||
-- Note that the quantity_unit_conversions table already contains both conversion directions for every conversion.
|
||||
SELECT
|
||||
product_id,
|
||||
@@ -26,21 +80,9 @@ AS (
|
||||
FROM products
|
||||
),
|
||||
|
||||
default_conversions(from_qu_id, to_qu_id, factor)
|
||||
product_closure(depth, product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
-- Default QU conversions are handled in a later CTE, as we can't determine yet, for which products they are applicable.
|
||||
SELECT
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor
|
||||
FROM quantity_unit_conversions
|
||||
WHERE product_id IS NULL
|
||||
),
|
||||
|
||||
-- Now build the closure of posisble conversions using a recursive CTE
|
||||
closure(depth, product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
-- As a base case, select the conversions that refer to a concrete product
|
||||
-- As a base case, select all available product-specific conversions
|
||||
SELECT
|
||||
1 as depth,
|
||||
product_id,
|
||||
@@ -48,11 +90,11 @@ AS (
|
||||
to_qu_id,
|
||||
factor,
|
||||
'/' || from_qu_id || '/' || to_qu_id || '/' -- We need to keep track of the conversion path in order to prevent cycles
|
||||
FROM conversion_factors
|
||||
FROM product_conversions
|
||||
|
||||
UNION
|
||||
|
||||
-- First recursive case: Add a product-associated conversion to the chain
|
||||
-- Recursive case: Find all paths
|
||||
SELECT
|
||||
c.depth + 1,
|
||||
c.product_id,
|
||||
@@ -60,31 +102,84 @@ AS (
|
||||
s.to_qu_id,
|
||||
c.factor * s.factor,
|
||||
c.path || s.to_qu_id || '/'
|
||||
FROM closure c
|
||||
JOIN conversion_factors s
|
||||
FROM product_closure c
|
||||
JOIN product_conversions s
|
||||
ON c.product_id = s.product_id
|
||||
AND c.to_qu_id = s.from_qu_id
|
||||
WHERE c.path NOT LIKE ('%/' || s.to_qu_id || '/%') -- Prevent cycles
|
||||
AND NOT EXISTS(SELECT 1 FROM product_conversions ci WHERE ci.product_id = c.product_id AND ci.from_qu_id = c.from_qu_id AND ci.to_qu_id = s.to_qu_id) -- Prune if one of the existing conversions repeats (saves a lot of processing time)
|
||||
),
|
||||
|
||||
UNION
|
||||
product_closure_distinct(product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
SELECT DISTINCT
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
FIRST_VALUE(factor) OVER win AS factor,
|
||||
FIRST_VALUE(path) OVER win AS path
|
||||
FROM product_closure
|
||||
GROUP BY product_id, from_qu_id, to_qu_id
|
||||
WINDOW win AS (PARTITION BY product_id, from_qu_id, to_qu_id ORDER BY depth)
|
||||
ORDER BY product_id, from_qu_id, to_qu_id
|
||||
),
|
||||
|
||||
-- Second recursive case: Add a default unit conversion to the *start* of the conversion chain
|
||||
-- Now we connect the two closures by adding the reachable conversions from product specific conversions to default conversions
|
||||
product_reachable(product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
SELECT
|
||||
c.depth + 1,
|
||||
c.product_id,
|
||||
s.from_qu_id,
|
||||
c.to_qu_id,
|
||||
s.factor * c.factor,
|
||||
'/' || s.from_qu_id || c.path
|
||||
FROM closure c
|
||||
JOIN default_conversions s
|
||||
ON s.to_qu_id = c.from_qu_id
|
||||
WHERE NOT EXISTS(SELECT 1 FROM conversion_factors ci WHERE ci.product_id = c.product_id AND ci.from_qu_id = s.from_qu_id AND ci.to_qu_id = s.to_qu_id) -- Do this only, if there is no product_specific conversion between the units in s
|
||||
AND c.path NOT LIKE ('%/' || s.from_qu_id || '/%') -- Prevent cycles
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor,
|
||||
path
|
||||
FROM product_closure_distinct
|
||||
|
||||
UNION
|
||||
|
||||
-- Third recursive case: Add a default unit conversion to the *end* of the conversion chain
|
||||
SELECT
|
||||
cd.product_id,
|
||||
dcd.from_qu_id,
|
||||
dcd.to_qu_id,
|
||||
dcd.factor,
|
||||
'/' || dcd.from_qu_id || '/' || dcd.to_qu_id || '/'
|
||||
FROM product_closure_distinct cd
|
||||
JOIN default_closure_distinct dcd
|
||||
ON cd.to_qu_id = dcd.from_qu_id
|
||||
OR cd.to_qu_id = dcd.to_qu_id
|
||||
WHERE NOT EXISTS(SELECT 1 FROM product_closure_distinct ci WHERE ci.product_id = cd.product_id AND ci.from_qu_id = dcd.from_qu_id AND ci.to_qu_id = dcd.to_qu_id)
|
||||
),
|
||||
|
||||
product_reachable_distinct(product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
SELECT DISTINCT
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
FIRST_VALUE(factor) OVER win AS factor,
|
||||
FIRST_VALUE(path) OVER win AS path
|
||||
FROM product_reachable
|
||||
GROUP BY product_id, from_qu_id, to_qu_id
|
||||
WINDOW win AS (PARTITION BY product_id, from_qu_id, to_qu_id)
|
||||
ORDER BY product_id, from_qu_id, to_qu_id
|
||||
),
|
||||
|
||||
-- Finally we build the combined closure
|
||||
closure_final(depth, product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
-- As a base case, select the product closure
|
||||
SELECT
|
||||
1,
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor,
|
||||
path -- We need to keep track of the conversion path in order to prevent cycles
|
||||
FROM product_reachable_distinct
|
||||
|
||||
UNION
|
||||
|
||||
-- Add a default unit conversion to the *end* of the conversion chain
|
||||
SELECT
|
||||
c.depth + 1,
|
||||
c.product_id,
|
||||
@@ -92,29 +187,12 @@ AS (
|
||||
s.to_qu_id,
|
||||
c.factor * s.factor,
|
||||
c.path || s.to_qu_id || '/'
|
||||
FROM closure c
|
||||
JOIN default_conversions s
|
||||
ON c.to_qu_id = s.from_qu_id
|
||||
WHERE NOT EXISTS(SELECT 1 FROM conversion_factors ci WHERE ci.product_id = c.product_id AND ci.from_qu_id = s.from_qu_id AND ci.to_qu_id = s.to_qu_id) -- Do this only, if there is no product_specific conversion between the units in s
|
||||
AND c.path NOT LIKE ('%/' || s.to_qu_id || '/%') -- Prevent cycles
|
||||
|
||||
UNION
|
||||
|
||||
-- Fourth case: Add the default unit conversions that are reachable by a given product.
|
||||
-- We cannot start with them directly, as we only want to add default conversions,
|
||||
-- where at least one of the units is 'reachable' from the product's stock quantity unit
|
||||
-- (and thus the conversion is sensible). Thus we add these cases here.
|
||||
SELECT
|
||||
1,
|
||||
c.product_id,
|
||||
s.from_qu_id,
|
||||
s.to_qu_id,
|
||||
s.factor,
|
||||
'/' || s.from_qu_id || '/' || s.to_qu_id || '/'
|
||||
FROM closure c
|
||||
JOIN default_conversions s
|
||||
ON c.path LIKE ('%/' || s.from_qu_id || '/' || s.to_qu_id || '/%') -- the conversion has been used as part of another path ...
|
||||
WHERE NOT EXISTS(SELECT 1 FROM conversion_factors ci WHERE ci.product_id = c.product_id AND ci.from_qu_id = s.from_qu_id AND ci.to_qu_id = s.to_qu_id) -- ... and is itself new
|
||||
FROM closure_final c
|
||||
JOIN product_reachable_distinct s
|
||||
ON c.product_id = s.product_id
|
||||
AND c.to_qu_id = s.from_qu_id
|
||||
WHERE c.path NOT LIKE ('%/' || s.to_qu_id || '/%') -- Prevent cycles
|
||||
AND NOT EXISTS(SELECT 1 FROM product_reachable_distinct ci WHERE ci.product_id = c.product_id AND ci.from_qu_id = c.from_qu_id AND ci.to_qu_id = s.to_qu_id) -- Prune (if already exists)
|
||||
)
|
||||
|
||||
SELECT DISTINCT
|
||||
@@ -126,13 +204,13 @@ SELECT DISTINCT
|
||||
c.to_qu_id,
|
||||
qu_to.name AS to_qu_name,
|
||||
qu_to.name_plural AS to_qu_name_plural,
|
||||
FIRST_VALUE(factor) OVER win AS factor,
|
||||
FIRST_VALUE(c.factor) OVER win AS factor,
|
||||
FIRST_VALUE(c.path) OVER win AS path
|
||||
FROM closure c
|
||||
FROM closure_final c
|
||||
JOIN quantity_units qu_from
|
||||
ON c.from_qu_id = qu_from.id
|
||||
JOIN quantity_units qu_to
|
||||
ON c.to_qu_id = qu_to.id
|
||||
GROUP BY product_id, from_qu_id, to_qu_id
|
||||
WINDOW win AS (PARTITION BY product_id, from_qu_id, to_qu_id ORDER BY depth ASC)
|
||||
ORDER BY product_id, from_qu_id, to_qu_id;
|
||||
GROUP BY c.product_id, c.from_qu_id, c.to_qu_id
|
||||
WINDOW win AS (PARTITION BY c.product_id, c.from_qu_id, c.to_qu_id ORDER BY c.depth)
|
||||
ORDER BY c.product_id, c.from_qu_id, c.to_qu_id;
|
||||
|
31
migrations/0228.sql
Normal file
31
migrations/0228.sql
Normal file
@@ -0,0 +1,31 @@
|
||||
DROP VIEW uihelper_shopping_list;
|
||||
CREATE VIEW uihelper_shopping_list
|
||||
AS
|
||||
SELECT
|
||||
sl.*,
|
||||
p.name AS product_name,
|
||||
plp.price * IFNULL(quc.factor, 1.0) AS last_price_unit,
|
||||
plp.price * sl.amount AS last_price_total,
|
||||
st.name AS default_shopping_location_name,
|
||||
qu.name AS qu_name,
|
||||
qu.name_plural AS qu_name_plural,
|
||||
pg.id AS product_group_id,
|
||||
pg.name AS product_group_name,
|
||||
pbcs.barcodes AS product_barcodes
|
||||
FROM shopping_list sl
|
||||
LEFT JOIN products p
|
||||
ON sl.product_id = p.id
|
||||
LEFT JOIN cache__products_last_purchased plp
|
||||
ON sl.product_id = plp.product_id
|
||||
LEFT JOIN shopping_locations st
|
||||
ON p.shopping_location_id = st.id
|
||||
LEFT JOIN quantity_units qu
|
||||
ON sl.qu_id = qu.id
|
||||
LEFT JOIN product_groups pg
|
||||
ON p.product_group_id = pg.id
|
||||
LEFT JOIN cache__quantity_unit_conversions_resolved quc
|
||||
ON p.id = quc.product_id
|
||||
AND p.qu_id_stock = quc.to_qu_id
|
||||
AND sl.qu_id = quc.from_qu_id
|
||||
LEFT JOIN product_barcodes_comma_separated pbcs
|
||||
ON sl.product_id = pbcs.product_id;
|
135
migrations/0229.sql
Normal file
135
migrations/0229.sql
Normal file
@@ -0,0 +1,135 @@
|
||||
DROP VIEW recipes_pos_resolved;
|
||||
CREATE VIEW recipes_pos_resolved
|
||||
AS
|
||||
|
||||
-- Multiplication by 1.0 to force conversion to float (REAL)
|
||||
|
||||
SELECT
|
||||
r.id AS recipe_id,
|
||||
rp.id AS recipe_pos_id,
|
||||
rp.product_id AS product_id,
|
||||
CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) ELSE rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) * ((rnr.includes_servings*1.0) / (rnrr.base_servings*1.0)) END AS recipe_amount,
|
||||
IFNULL(sc.amount_aggregated, 0) AS stock_amount,
|
||||
CASE WHEN IFNULL(sc.amount_aggregated, 0) >= CASE WHEN rp.only_check_single_unit_in_stock = 1 THEN 0.00000001 ELSE CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) ELSE rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) * ((rnr.includes_servings*1.0) / (rnrr.base_servings*1.0)) END END THEN 1 ELSE 0 END AS need_fulfilled,
|
||||
CASE WHEN IFNULL(sc.amount_aggregated, 0) - CASE WHEN rp.only_check_single_unit_in_stock = 1 THEN 0.00000001 ELSE CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) ELSE rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) * ((rnr.includes_servings*1.0) / (rnrr.base_servings*1.0)) END END < 0 THEN ABS(IFNULL(sc.amount_aggregated, 0) - (CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) ELSE rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) * ((rnr.includes_servings*1.0) / (rnrr.base_servings*1.0)) END)) ELSE 0 END AS missing_amount,
|
||||
IFNULL(sl.amount, 0) AS amount_on_shopping_list,
|
||||
CASE WHEN ROUND(IFNULL(sc.amount_aggregated, 0) + CASE WHEN r.not_check_shoppinglist = 1 THEN 0 ELSE IFNULL(sl.amount, 0) END, 2) >= ROUND(CASE WHEN rp.only_check_single_unit_in_stock = 1 THEN 0.00000001 ELSE CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) ELSE rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) * ((rnr.includes_servings*1.0) / (rnrr.base_servings*1.0)) END END, 2) THEN 1 ELSE 0 END AS need_fulfilled_with_shopping_list,
|
||||
rp.qu_id,
|
||||
(r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * rp.amount * IFNULL(pcp.price, 0) * rp.price_factor * CASE WHEN rp.product_id != p_effective.id THEN IFNULL(qucr.factor, 1.0) ELSE 1.0 END AS costs,
|
||||
CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN 0 ELSE 1 END AS is_nested_recipe_pos,
|
||||
rp.ingredient_group,
|
||||
pg.name as product_group,
|
||||
rp.id, -- Just a dummy id column
|
||||
r.type as recipe_type,
|
||||
rnr.includes_recipe_id as child_recipe_id,
|
||||
rp.note,
|
||||
rp.variable_amount AS recipe_variable_amount,
|
||||
rp.only_check_single_unit_in_stock,
|
||||
rp.amount / r.base_servings*1.0 * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * IFNULL(p_effective.calories, 0) * CASE WHEN rp.product_id != p_effective.id THEN IFNULL(qucr.factor, 1.0) ELSE 1.0 END AS calories,
|
||||
p.active AS product_active,
|
||||
CASE pvs.current_due_status
|
||||
WHEN 'ok' THEN 0
|
||||
WHEN 'due_soon' THEN 1
|
||||
WHEN 'overdue' THEN 10
|
||||
WHEN 'expired' THEN 20
|
||||
END AS due_score,
|
||||
IFNULL(pcs.product_id_effective, rp.product_id) AS product_id_effective,
|
||||
p.name AS product_name
|
||||
FROM recipes r
|
||||
JOIN recipes_nestings_resolved rnr
|
||||
ON r.id = rnr.recipe_id
|
||||
JOIN recipes rnrr
|
||||
ON rnr.includes_recipe_id = rnrr.id
|
||||
JOIN recipes_pos rp
|
||||
ON rnr.includes_recipe_id = rp.recipe_id
|
||||
JOIN products p
|
||||
ON rp.product_id = p.id
|
||||
JOIN products_volatile_status pvs
|
||||
ON rp.product_id = pvs.product_id
|
||||
LEFT JOIN product_groups pg
|
||||
ON p.product_group_id = pg.id
|
||||
LEFT JOIN (
|
||||
SELECT product_id, SUM(amount) AS amount
|
||||
FROM shopping_list
|
||||
GROUP BY product_id) sl
|
||||
ON rp.product_id = sl.product_id
|
||||
LEFT JOIN stock_current sc
|
||||
ON rp.product_id = sc.product_id
|
||||
LEFT JOIN products_current_substitutions pcs
|
||||
ON rp.product_id = pcs.parent_product_id
|
||||
LEFT JOIN products_current_price pcp
|
||||
ON IFNULL(pcs.product_id_effective, rp.product_id) = pcp.product_id
|
||||
LEFT JOIN products p_effective
|
||||
ON IFNULL(pcs.product_id_effective, rp.product_id) = p_effective.id
|
||||
LEFT JOIN cache__quantity_unit_conversions_resolved qucr
|
||||
ON IFNULL(pcs.product_id_effective, rp.product_id) = qucr.product_id
|
||||
AND CASE WHEN rp.product_id != p_effective.id THEN p.qu_id_stock ELSE rp.qu_id END = qucr.from_qu_id
|
||||
AND IFNULL(p_effective.qu_id_stock, p.qu_id_stock) = qucr.to_qu_id
|
||||
WHERE rp.not_check_stock_fulfillment = 0
|
||||
|
||||
UNION
|
||||
|
||||
-- Just add all recipe positions which should not be checked against stock with fulfilled need
|
||||
|
||||
SELECT
|
||||
r.id AS recipe_id,
|
||||
rp.id AS recipe_pos_id,
|
||||
rp.product_id AS product_id,
|
||||
CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) ELSE rp.amount * ((r.desired_servings*1.0) / (r.base_servings*1.0)) * ((rnr.includes_servings*1.0) / (rnrr.base_servings*1.0)) END AS recipe_amount,
|
||||
IFNULL(sc.amount_aggregated, 0) AS stock_amount,
|
||||
1 AS need_fulfilled,
|
||||
0 AS missing_amount,
|
||||
IFNULL(sl.amount, 0) AS amount_on_shopping_list,
|
||||
1 AS need_fulfilled_with_shopping_list,
|
||||
rp.qu_id,
|
||||
(r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * rp.amount * IFNULL(pcp.price, 0) * rp.price_factor * CASE WHEN rp.product_id != p_effective.id THEN IFNULL(qucr.factor, 1.0) ELSE 1.0 END AS costs,
|
||||
CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN 0 ELSE 1 END AS is_nested_recipe_pos,
|
||||
rp.ingredient_group,
|
||||
pg.name as product_group,
|
||||
rp.id, -- Just a dummy id column
|
||||
r.type as recipe_type,
|
||||
rnr.includes_recipe_id as child_recipe_id,
|
||||
rp.note,
|
||||
rp.variable_amount AS recipe_variable_amount,
|
||||
rp.only_check_single_unit_in_stock,
|
||||
rp.amount / r.base_servings*1.0 * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * IFNULL(p_effective.calories, 0) * CASE WHEN rp.product_id != p_effective.id THEN IFNULL(qucr.factor, 1.0) ELSE 1.0 END AS calories,
|
||||
p.active AS product_active,
|
||||
CASE pvs.current_due_status
|
||||
WHEN 'ok' THEN 0
|
||||
WHEN 'due_soon' THEN 1
|
||||
WHEN 'overdue' THEN 10
|
||||
WHEN 'expired' THEN 20
|
||||
END AS due_score,
|
||||
IFNULL(pcs.product_id_effective, rp.product_id) AS product_id_effective,
|
||||
p.name AS product_name
|
||||
FROM recipes r
|
||||
JOIN recipes_nestings_resolved rnr
|
||||
ON r.id = rnr.recipe_id
|
||||
JOIN recipes rnrr
|
||||
ON rnr.includes_recipe_id = rnrr.id
|
||||
JOIN recipes_pos rp
|
||||
ON rnr.includes_recipe_id = rp.recipe_id
|
||||
JOIN products p
|
||||
ON rp.product_id = p.id
|
||||
JOIN products_volatile_status pvs
|
||||
ON rp.product_id = pvs.product_id
|
||||
LEFT JOIN product_groups pg
|
||||
ON p.product_group_id = pg.id
|
||||
LEFT JOIN (
|
||||
SELECT product_id, SUM(amount) AS amount
|
||||
FROM shopping_list
|
||||
GROUP BY product_id) sl
|
||||
ON rp.product_id = sl.product_id
|
||||
LEFT JOIN stock_current sc
|
||||
ON rp.product_id = sc.product_id
|
||||
LEFT JOIN products_current_substitutions pcs
|
||||
ON rp.product_id = pcs.parent_product_id
|
||||
LEFT JOIN products_current_price pcp
|
||||
ON IFNULL(pcs.product_id_effective, rp.product_id) = pcp.product_id
|
||||
LEFT JOIN products p_effective
|
||||
ON IFNULL(pcs.product_id_effective, rp.product_id) = p_effective.id
|
||||
LEFT JOIN cache__quantity_unit_conversions_resolved qucr
|
||||
ON IFNULL(pcs.product_id_effective, rp.product_id) = qucr.product_id
|
||||
AND CASE WHEN rp.product_id != p_effective.id THEN p.qu_id_stock ELSE rp.qu_id END = qucr.from_qu_id
|
||||
AND IFNULL(p_effective.qu_id_stock, p.qu_id_stock) = qucr.to_qu_id
|
||||
WHERE rp.not_check_stock_fulfillment = 1;
|
92
migrations/0230.sql
Normal file
92
migrations/0230.sql
Normal file
@@ -0,0 +1,92 @@
|
||||
DROP VIEW stock_edited_entries;
|
||||
CREATE VIEW stock_edited_entries
|
||||
AS
|
||||
/*
|
||||
Returns stock_id's which have been edited manually
|
||||
*/
|
||||
SELECT
|
||||
x.stock_id,
|
||||
x.stock_log_id_of_newest_edited_entry,
|
||||
|
||||
-- When an origin entry was edited, the new origin amount is the one of the newest "stock-edit-new" + all
|
||||
-- previous consume transactions (mind that consume transaction amounts are negative, hence here - instead of +)
|
||||
(
|
||||
SELECT amount
|
||||
FROM stock_log sli
|
||||
WHERE sli.id = x.stock_log_id_of_newest_edited_entry
|
||||
)
|
||||
-
|
||||
IFNULL((
|
||||
SELECT SUM(amount)
|
||||
FROM stock_log sli_consumed
|
||||
WHERE sli_consumed.stock_id = x.stock_id
|
||||
AND sli_consumed.transaction_type IN ('consume', 'inventory-correction')
|
||||
AND sli_consumed.id < x.stock_log_id_of_newest_edited_entry
|
||||
AND sli_consumed.amount < 0
|
||||
AND sli_consumed.undone = 0), 0) AS edited_origin_amount
|
||||
FROM (
|
||||
SELECT
|
||||
sl_add.stock_id,
|
||||
MAX(sl_edit.id) AS stock_log_id_of_newest_edited_entry
|
||||
FROM stock_log sl_add
|
||||
JOIN stock_log sl_edit
|
||||
ON sl_add.stock_id = sl_edit.stock_id
|
||||
AND sl_edit.transaction_type = 'stock-edit-new'
|
||||
WHERE sl_add.transaction_type IN ('purchase', 'inventory-correction', 'self-production')
|
||||
AND sl_add.amount > 0
|
||||
GROUP BY sl_add.stock_id
|
||||
) x
|
||||
JOIN stock_log sl_edit
|
||||
ON x.stock_log_id_of_newest_edited_entry = sl_edit.id;
|
||||
|
||||
DROP VIEW products_average_price;
|
||||
CREATE VIEW products_average_price
|
||||
AS
|
||||
SELECT
|
||||
1 AS id, -- Dummy, LessQL needs an id column
|
||||
sl.product_id,
|
||||
SUM(IFNULL(sl.edited_origin_amount, sl.amount) * sl.price) / SUM(IFNULL(sl.edited_origin_amount, sl.amount)) as price
|
||||
FROM (
|
||||
SELECT sl.*, CASE WHEN sl.transaction_type = 'stock-edit-new' THEN see.edited_origin_amount END AS edited_origin_amount
|
||||
FROM stock_log sl
|
||||
LEFT JOIN stock_edited_entries see
|
||||
ON sl.stock_id = see.stock_id
|
||||
) sl
|
||||
WHERE sl.undone = 0
|
||||
AND (
|
||||
(sl.transaction_type IN ('purchase', 'inventory-correction', 'self-production') AND sl.stock_id NOT IN (SELECT stock_id FROM stock_edited_entries)) -- Unedited origin entries
|
||||
OR (sl.transaction_type = 'stock-edit-new' AND sl.id IN (SELECT stock_log_id_of_newest_edited_entry FROM stock_edited_entries)) -- Edited origin entries => take the newest "stock-edit-new" one
|
||||
)
|
||||
AND IFNULL(sl.price, 0) > 0
|
||||
AND IFNULL(sl.amount, 0) > 0
|
||||
GROUP BY sl.product_id;
|
||||
|
||||
-- Update products_average_price cache
|
||||
INSERT OR REPLACE INTO cache__products_average_price
|
||||
(product_id, price)
|
||||
SELECT product_id, price
|
||||
FROM products_average_price;
|
||||
|
||||
DROP VIEW products_price_history;
|
||||
CREATE VIEW products_price_history
|
||||
AS
|
||||
SELECT
|
||||
sl.product_id AS id, -- Dummy, LessQL needs an id column
|
||||
sl.product_id,
|
||||
sl.price,
|
||||
IFNULL(sl.edited_origin_amount, sl.amount) AS amount,
|
||||
sl.purchased_date,
|
||||
sl.shopping_location_id
|
||||
FROM (
|
||||
SELECT sl.*, CASE WHEN sl.transaction_type = 'stock-edit-new' THEN see.edited_origin_amount END AS edited_origin_amount
|
||||
FROM stock_log sl
|
||||
LEFT JOIN stock_edited_entries see
|
||||
ON sl.stock_id = see.stock_id
|
||||
) sl
|
||||
WHERE sl.undone = 0
|
||||
AND (
|
||||
(sl.transaction_type IN ('purchase', 'inventory-correction', 'self-production') AND sl.stock_id NOT IN (SELECT stock_id FROM stock_edited_entries)) -- Unedited origin entries
|
||||
OR (sl.transaction_type = 'stock-edit-new' AND sl.id IN (SELECT stock_log_id_of_newest_edited_entry FROM stock_edited_entries)) -- Edited origin entries => take the newest "stock-edit-new" one
|
||||
)
|
||||
AND IFNULL(sl.price, 0) > 0
|
||||
AND IFNULL(sl.amount, 0) > 0;
|
33
migrations/0231.sql
Normal file
33
migrations/0231.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
DROP TRIGGER default_qu_conversions;
|
||||
CREATE TRIGGER products_default_qu_conversions 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;
|
216
migrations/0232.sql
Normal file
216
migrations/0232.sql
Normal file
@@ -0,0 +1,216 @@
|
||||
DROP VIEW quantity_unit_conversions_resolved;
|
||||
CREATE VIEW quantity_unit_conversions_resolved
|
||||
AS
|
||||
|
||||
WITH RECURSIVE
|
||||
|
||||
-- Default QU conversions are handled in a later CTE, as we can't determine yet, for which products they are applicable.
|
||||
default_conversions(from_qu_id, to_qu_id, factor)
|
||||
AS (
|
||||
SELECT
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor
|
||||
FROM quantity_unit_conversions
|
||||
WHERE product_id IS NULL
|
||||
),
|
||||
|
||||
-- First find the closure for all default conversions. This will allow for further pruning when looking for product closure.
|
||||
default_closure(depth, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
-- As a base case, select all available default conversions
|
||||
SELECT
|
||||
1 as depth,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor,
|
||||
'/' || from_qu_id || '/' || to_qu_id || '/' -- We need to keep track of the conversion path in order to prevent cycles
|
||||
FROM default_conversions
|
||||
|
||||
UNION
|
||||
|
||||
-- Recursive case: Find all paths
|
||||
SELECT
|
||||
c.depth + 1,
|
||||
c.from_qu_id,
|
||||
s.to_qu_id,
|
||||
c.factor * s.factor,
|
||||
c.path || s.to_qu_id || '/'
|
||||
FROM default_closure c
|
||||
JOIN default_conversions s
|
||||
ON c.to_qu_id = s.from_qu_id
|
||||
WHERE c.path NOT LIKE ('%/' || s.to_qu_id || '/%') -- Prevent cycles
|
||||
AND NOT EXISTS(SELECT 1 FROM default_conversions ci WHERE ci.from_qu_id = c.from_qu_id AND ci.to_qu_id = s.to_qu_id) -- Prune if one of the existing conversions repeats (saves a lot of processing time)
|
||||
|
||||
),
|
||||
|
||||
default_closure_distinct(from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
SELECT DISTINCT
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
FIRST_VALUE(factor) OVER win AS factor,
|
||||
FIRST_VALUE(path) OVER win AS path
|
||||
FROM default_closure
|
||||
GROUP BY from_qu_id, to_qu_id
|
||||
WINDOW win AS (PARTITION BY from_qu_id, to_qu_id ORDER BY depth)
|
||||
ORDER BY from_qu_id, to_qu_id
|
||||
),
|
||||
|
||||
product_conversions(product_id, from_qu_id, to_qu_id, factor)
|
||||
AS (
|
||||
-- Priority 1: Product-specific QU overrides
|
||||
-- Note that the quantity_unit_conversions table already contains both conversion directions for every conversion.
|
||||
SELECT
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor
|
||||
FROM quantity_unit_conversions
|
||||
WHERE product_id IS NOT NULL
|
||||
|
||||
UNION
|
||||
|
||||
-- Priority 2: QU conversions with a factor of 1.0 from the stock unit to the stock unit
|
||||
SELECT
|
||||
id,
|
||||
qu_id_stock,
|
||||
qu_id_stock,
|
||||
1.0
|
||||
FROM products
|
||||
),
|
||||
|
||||
product_closure(depth, product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
-- As a base case, select all available product-specific conversions
|
||||
SELECT
|
||||
1 as depth,
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor,
|
||||
'/' || from_qu_id || '/' || to_qu_id || '/' -- We need to keep track of the conversion path in order to prevent cycles
|
||||
FROM product_conversions
|
||||
|
||||
UNION
|
||||
|
||||
-- Recursive case: Find all paths
|
||||
SELECT
|
||||
c.depth + 1,
|
||||
c.product_id,
|
||||
c.from_qu_id,
|
||||
s.to_qu_id,
|
||||
c.factor * s.factor,
|
||||
c.path || s.to_qu_id || '/'
|
||||
FROM product_closure c
|
||||
JOIN product_conversions s
|
||||
ON c.product_id = s.product_id
|
||||
AND c.to_qu_id = s.from_qu_id
|
||||
WHERE c.path NOT LIKE ('%/' || s.to_qu_id || '/%') -- Prevent cycles
|
||||
AND NOT EXISTS(SELECT 1 FROM product_conversions ci WHERE ci.product_id = c.product_id AND ci.from_qu_id = c.from_qu_id AND ci.to_qu_id = s.to_qu_id) -- Prune if one of the existing conversions repeats (saves a lot of processing time)
|
||||
),
|
||||
|
||||
product_closure_distinct(product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
SELECT DISTINCT
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
FIRST_VALUE(factor) OVER win AS factor,
|
||||
FIRST_VALUE(path) OVER win AS path
|
||||
FROM product_closure
|
||||
GROUP BY product_id, from_qu_id, to_qu_id
|
||||
WINDOW win AS (PARTITION BY product_id, from_qu_id, to_qu_id ORDER BY depth)
|
||||
ORDER BY product_id, from_qu_id, to_qu_id
|
||||
),
|
||||
|
||||
-- Now we connect the two closures by adding the reachable conversions from product specific conversions to default conversions
|
||||
product_reachable(product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
SELECT
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor,
|
||||
path
|
||||
FROM product_closure_distinct
|
||||
|
||||
UNION
|
||||
|
||||
SELECT
|
||||
cd.product_id,
|
||||
dcd.from_qu_id,
|
||||
dcd.to_qu_id,
|
||||
dcd.factor,
|
||||
'/' || dcd.from_qu_id || '/' || dcd.to_qu_id || '/'
|
||||
FROM product_closure_distinct cd
|
||||
JOIN default_closure_distinct dcd
|
||||
ON cd.to_qu_id = dcd.from_qu_id
|
||||
OR cd.to_qu_id = dcd.to_qu_id
|
||||
WHERE NOT EXISTS(SELECT 1 FROM product_closure_distinct ci WHERE ci.product_id = cd.product_id AND ci.from_qu_id = dcd.from_qu_id AND ci.to_qu_id = dcd.to_qu_id)
|
||||
),
|
||||
|
||||
product_reachable_distinct(product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
SELECT DISTINCT
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
FIRST_VALUE(factor) OVER win AS factor,
|
||||
FIRST_VALUE(path) OVER win AS path
|
||||
FROM product_reachable
|
||||
GROUP BY product_id, from_qu_id, to_qu_id
|
||||
WINDOW win AS (PARTITION BY product_id, from_qu_id, to_qu_id)
|
||||
ORDER BY product_id, from_qu_id, to_qu_id
|
||||
),
|
||||
|
||||
-- Finally we build the combined closure
|
||||
closure_final(depth, product_id, from_qu_id, to_qu_id, factor, path)
|
||||
AS (
|
||||
-- As a base case, select the product closure
|
||||
SELECT
|
||||
1,
|
||||
product_id,
|
||||
from_qu_id,
|
||||
to_qu_id,
|
||||
factor,
|
||||
path -- We need to keep track of the conversion path in order to prevent cycles
|
||||
FROM product_reachable_distinct
|
||||
|
||||
UNION
|
||||
|
||||
-- Add a default unit conversion to the *end* of the conversion chain
|
||||
SELECT
|
||||
c.depth + 1,
|
||||
c.product_id,
|
||||
c.from_qu_id,
|
||||
s.to_qu_id,
|
||||
c.factor * s.factor,
|
||||
c.path || s.to_qu_id || '/'
|
||||
FROM closure_final c
|
||||
JOIN product_reachable_distinct s
|
||||
ON c.product_id = s.product_id
|
||||
AND c.to_qu_id = s.from_qu_id
|
||||
WHERE c.path NOT LIKE ('%/' || s.to_qu_id || '/%') -- Prevent cycles
|
||||
AND NOT EXISTS(SELECT 1 FROM product_reachable_distinct ci WHERE ci.product_id = c.product_id AND ci.from_qu_id = c.from_qu_id AND ci.to_qu_id = s.to_qu_id) -- Prune (if already exists)
|
||||
)
|
||||
|
||||
SELECT DISTINCT
|
||||
-1 AS id, -- Dummy, LessQL needs an id column
|
||||
c.product_id,
|
||||
c.from_qu_id,
|
||||
qu_from.name AS from_qu_name,
|
||||
qu_from.name_plural AS from_qu_name_plural,
|
||||
c.to_qu_id,
|
||||
qu_to.name AS to_qu_name,
|
||||
qu_to.name_plural AS to_qu_name_plural,
|
||||
FIRST_VALUE(c.factor) OVER win AS factor,
|
||||
FIRST_VALUE(c.path) OVER win AS path
|
||||
FROM closure_final c
|
||||
JOIN quantity_units qu_from
|
||||
ON c.from_qu_id = qu_from.id
|
||||
JOIN quantity_units qu_to
|
||||
ON c.to_qu_id = qu_to.id
|
||||
GROUP BY c.product_id, c.from_qu_id, c.to_qu_id
|
||||
WINDOW win AS (PARTITION BY c.product_id, c.from_qu_id, c.to_qu_id ORDER BY c.depth)
|
||||
ORDER BY c.product_id, c.from_qu_id, c.to_qu_id;
|
@@ -585,77 +585,90 @@ if (window.location.hash)
|
||||
|
||||
function RefreshLocaleNumberDisplay(rootSelector = "#page-content")
|
||||
{
|
||||
$(rootSelector + " .locale-number.locale-number-currency").each(function()
|
||||
$(rootSelector + " .locale-number.locale-number-currency:not('.number-parsing-done')").each(function()
|
||||
{
|
||||
var text = $(this).text();
|
||||
var element = $(this);
|
||||
var text = element.text();
|
||||
if (!text || Number.isNaN(text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var value = Number.parseFloat(text);
|
||||
$(this).text(value.toLocaleString(undefined, { style: "currency", currency: Grocy.Currency, minimumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices_display, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices_display }));
|
||||
element.text(value.toLocaleString(undefined, { style: "currency", currency: Grocy.Currency, minimumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices_display, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices_display }));
|
||||
element.addClass("number-parsing-done");
|
||||
});
|
||||
|
||||
$(rootSelector + " .locale-number.locale-number-quantity-amount").each(function()
|
||||
$(rootSelector + " .locale-number.locale-number-quantity-amount:not('.number-parsing-done')").each(function()
|
||||
{
|
||||
var text = $(this).text();
|
||||
var element = $(this);
|
||||
var text = element.text();
|
||||
if (!text || Number.isNaN(text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var value = Number.parseFloat(text);
|
||||
$(this).text(value.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }));
|
||||
element.text(value.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }));
|
||||
element.addClass("number-parsing-done");
|
||||
});
|
||||
|
||||
$(rootSelector + " .locale-number.locale-number-generic").each(function()
|
||||
$(rootSelector + " .locale-number.locale-number-generic:not('.number-parsing-done')").each(function()
|
||||
{
|
||||
var text = $(this).text();
|
||||
var element = $(this);
|
||||
var text = element.text();
|
||||
if (!text || Number.isNaN(text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var value = Number.parseFloat(text);
|
||||
$(this).text(value.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 0 }));
|
||||
element.text(value.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 0 }));
|
||||
element.addClass("number-parsing-done");
|
||||
});
|
||||
}
|
||||
RefreshLocaleNumberDisplay();
|
||||
$(document).on("DOMSubtreeModified", ".locale-number", function()
|
||||
{
|
||||
$(this).removeClass("number-parsing-done");
|
||||
});
|
||||
|
||||
function RefreshLocaleNumberInput(rootSelector = "#page-content")
|
||||
{
|
||||
$(rootSelector + " .locale-number-input.locale-number-currency").each(function()
|
||||
{
|
||||
var value = $(this).val();
|
||||
var element = $(this);
|
||||
var value = element.val();
|
||||
if (!value || Number.isNaN(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$(this).val(Number.parseFloat(value).toLocaleString("en", { minimumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices_input, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices_input, useGrouping: false }));
|
||||
element.val(Number.parseFloat(value).toLocaleString("en", { minimumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices_input, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices_input, useGrouping: false }));
|
||||
});
|
||||
|
||||
$(rootSelector + " .locale-number-input.locale-number-quantity-amount").each(function()
|
||||
{
|
||||
var value = $(this).val();
|
||||
var element = $(this);
|
||||
var value = element.val();
|
||||
if (!value || Number.isNaN(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$(this).val(Number.parseFloat(value).toLocaleString("en", { minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts, useGrouping: false }));
|
||||
element.val(Number.parseFloat(value).toLocaleString("en", { minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts, useGrouping: false }));
|
||||
});
|
||||
|
||||
$(rootSelector + " .locale-number-input.locale-number-generic").each(function()
|
||||
{
|
||||
var value = $(this).val();
|
||||
var element = $(this);
|
||||
var value = element.val();
|
||||
if (!value || Number.isNaN(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$(this).val(value.toLocaleString("en", { minimumFractionDigits: 0, maximumFractionDigits: 2, useGrouping: false }));
|
||||
element.val(value.toLocaleString("en", { minimumFractionDigits: 0, maximumFractionDigits: 2, useGrouping: false }));
|
||||
});
|
||||
}
|
||||
RefreshLocaleNumberInput();
|
||||
|
@@ -906,9 +906,8 @@ $(document).on('click', '.recipe-consume-button', function(e)
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
toastr.warning(__t('Not all ingredients of recipe "%s" are in stock, nothing removed', objectName));
|
||||
Grocy.FrontendHelpers.EndUiBusy();
|
||||
console.error(xhr);
|
||||
Grocy.FrontendHelpers.ShowGenericError("A server error occured while processing your request", xhr.response);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@@ -265,8 +265,7 @@ $(".recipe-consume").on('click', function(e)
|
||||
function(xhr)
|
||||
{
|
||||
Grocy.FrontendHelpers.EndUiBusy();
|
||||
toastr.warning(__t('Not all ingredients of recipe "%s" are in stock, nothing removed', objectName));
|
||||
console.error(xhr);
|
||||
Grocy.FrontendHelpers.ShowGenericError("A server error occured while processing your request", xhr.response);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@@ -117,9 +117,10 @@ $(document).on('click', '.product-open-button', function(e)
|
||||
var productQuName = $(e.currentTarget).attr('data-product-qu-name');
|
||||
var specificStockEntryId = $(e.currentTarget).attr('data-stock-id');
|
||||
var stockRowId = $(e.currentTarget).attr('data-stockrow-id');
|
||||
var openAmount = Number.parseFloat($(e.currentTarget).attr('data-open-amount'));
|
||||
var button = $(e.currentTarget);
|
||||
|
||||
Grocy.Api.Post('stock/products/' + productId + '/open', { 'amount': 1, 'stock_entry_id': specificStockEntryId },
|
||||
Grocy.Api.Post('stock/products/' + productId + '/open', { 'amount': openAmount, 'stock_entry_id': specificStockEntryId },
|
||||
function(bookingResponse)
|
||||
{
|
||||
Grocy.Api.Get('stock/products/' + productId,
|
||||
|
@@ -134,12 +134,12 @@ $("#clear-filter-button").on("click", function()
|
||||
{
|
||||
RemoveUriParam("start_date");
|
||||
RemoveUriParam("end_date");
|
||||
RemoveUriParam("product_group");
|
||||
RemoveUriParam("product-group");
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$("#product-group-filter").on("change", function()
|
||||
{
|
||||
UpdateUriParam("product_group", $(this).val());
|
||||
UpdateUriParam("product-group", $(this).val());
|
||||
window.location.reload();
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"Version": "4.0.1",
|
||||
"ReleaseDate": "2023-08-06"
|
||||
"Version": "4.0.2",
|
||||
"ReleaseDate": "2023-08-19"
|
||||
}
|
||||
|
@@ -15,8 +15,12 @@
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="{{ $U('/img/icon-32.png?v=', true) }}{{ $version }}">
|
||||
|
||||
@if (GROCY_AUTHENTICATED)
|
||||
<link rel="manifest"
|
||||
crossorigin="use-credentials"
|
||||
href="{{ $U('/manifest') . '?data=' . base64_encode($__env->yieldContent('title') . '#' . $U($_SERVER['REQUEST_URI'])) }}">
|
||||
@endif
|
||||
|
||||
<title>@yield('title') | Grocy</title>
|
||||
|
||||
@@ -652,10 +656,8 @@
|
||||
class="dropdown-item discrete-link link-return">
|
||||
<i class="fa-solid fa-user-cog"></i> {{ $__t('User settings') }}
|
||||
</a>
|
||||
@if(!GROCY_IS_EMBEDDED_INSTALL && !GROCY_DISABLE_AUTH)
|
||||
<a class="dropdown-item discrete-link permission-USERS_READ"
|
||||
href="{{ $U('/users') }}"><i class="fa-solid fa-users"></i> {{ $__t('Manage users') }}</a>
|
||||
@endif
|
||||
<div class="dropdown-divider"></div>
|
||||
@if(!GROCY_DISABLE_AUTH)
|
||||
<a class="dropdown-item discrete-link"
|
||||
|
@@ -130,7 +130,8 @@
|
||||
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
||||
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
||||
data-stock-id="{{ $stockEntry->stock_id }}"
|
||||
data-stockrow-id="{{ $stockEntry->id }}">
|
||||
data-stockrow-id="{{ $stockEntry->id }}"
|
||||
data-open-amount="{{ $stockEntry->amount }}">
|
||||
<i class="fa-solid fa-box-open"></i>
|
||||
</a>
|
||||
@endif
|
||||
|
@@ -27,18 +27,22 @@
|
||||
</div>
|
||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
||||
id="related-links">
|
||||
<a class="btn btn-link responsive-button m-1 mt-md-0 mb-md-0 @if(!$byGroup) active @endif discrete-link disabled"
|
||||
<a class="btn btn-link responsive-button m-1 mt-md-0 mb-md-0 discrete-link disabled"
|
||||
href="#">
|
||||
{{ $__t('Group by') }}:
|
||||
</a>
|
||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right @if(!$byGroup) active @endif"
|
||||
href="{{ $U('/stockreports/spendings') }}">
|
||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right @if($groupBy == 'product') active @endif"
|
||||
href="{{ $U('/stockreports/spendings?group-by=product') }}">
|
||||
{{ $__t('Product') }}
|
||||
</a>
|
||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right @if($byGroup) active @endif"
|
||||
href="{{ $U('/stockreports/spendings?byGroup=true') }}">
|
||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right @if($groupBy == 'productgroup') active @endif"
|
||||
href="{{ $U('/stockreports/spendings?group-by=productgroup') }}">
|
||||
{{ $__t('Product group') }}
|
||||
</a>
|
||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right @if($groupBy == 'store') active @endif"
|
||||
href="{{ $U('/stockreports/spendings?group-by=store') }}">
|
||||
{{ $__t('Store') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,7 +64,7 @@
|
||||
value="" />
|
||||
</div>
|
||||
</div>
|
||||
@if(!$byGroup)
|
||||
@if($groupBy == 'product')
|
||||
<div class="col-sm-12 col-md-6 col-xl-4">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
@@ -100,7 +104,7 @@
|
||||
<tr>
|
||||
<th>{{ $__t('Name') }}</th>
|
||||
<th>{{ $__t('Total') }}</th>
|
||||
@if(!$byGroup)
|
||||
@if($groupBy == 'product')
|
||||
<th>{{ $__t('Product group') }}</th>
|
||||
@endif
|
||||
</tr>
|
||||
@@ -115,7 +119,7 @@
|
||||
data-order="{{ $metric->total }}">
|
||||
<span class="locale-number locale-number-currency">{{ $metric->total }}</span>
|
||||
</td>
|
||||
@if(!$byGroup)
|
||||
@if($groupBy == 'product')
|
||||
<td>
|
||||
{{ $metric->group_name }}
|
||||
</td>
|
||||
|
@@ -63,6 +63,7 @@
|
||||
value="@if($mode == 'edit'){{ $user->last_name }}@endif">
|
||||
</div>
|
||||
|
||||
@if(!GROCY_IS_EMBEDDED_INSTALL && !GROCY_DISABLE_AUTH)
|
||||
@if(!defined('GROCY_EXTERNALLY_MANAGED_AUTHENTICATION'))
|
||||
@if($mode == 'edit')
|
||||
<div class="form-group mb-1">
|
||||
@@ -115,6 +116,7 @@
|
||||
id="password_confirm"
|
||||
value="x">
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@include('components.userfieldsform', array(
|
||||
'userfields' => $userfields,
|
||||
|
@@ -97,12 +97,14 @@
|
||||
title="{{ $__t('Edit this item') }}">
|
||||
<i class="fa-solid fa-edit"></i>
|
||||
</a>
|
||||
@if(!GROCY_IS_EMBEDDED_INSTALL && !GROCY_DISABLE_AUTH)
|
||||
<a class="btn btn-info btn-sm"
|
||||
href="{{ $U('/user/' . $user->id . '/permissions') }}"
|
||||
data-toggle="tooltip"
|
||||
title="{{ $__t('Configure user permissions') }}">
|
||||
<i class="fa-solid fa-lock"></i>
|
||||
</a>
|
||||
@endif
|
||||
<a class="btn btn-danger btn-sm user-delete-button @if($user->id == GROCY_USER_ID) disabled @endif"
|
||||
href="#"
|
||||
data-user-id="{{ $user->id }}"
|
||||
|
12
yarn.lock
12
yarn.lock
@@ -29,9 +29,9 @@
|
||||
fsevents "2.3.2"
|
||||
|
||||
"@fontsource/open-sans@^5.0.0":
|
||||
version "5.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/open-sans/-/open-sans-5.0.8.tgz#d2a38bec673e1c5f8115fa8066aa93117d12225d"
|
||||
integrity sha512-d3Shc6QHoZMzZIL6m4M/geyK0EXHqLvUm9fmlkr1L/AEWgIasoLEBMKEdMczV2e66SHYAYKagIsBwfWnVhmPGQ==
|
||||
version "5.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/open-sans/-/open-sans-5.0.9.tgz#e5d6216cd32f3489940f5348945b11c65191d5a6"
|
||||
integrity sha512-u3P37qsYLuYTkQjevTInS8cwvhZznS08jauNkbzzyFBLSLogEdHqLmP/PyE8Bnrff+hVguA5WwtWThiy1m4Eaw==
|
||||
|
||||
"@fortawesome/fontawesome-free@^6.1.1":
|
||||
version "6.4.2"
|
||||
@@ -654,9 +654,9 @@ summernote@^0.8.18:
|
||||
integrity sha512-W9RhjQjsn+b1s9xiJQgJbCiYGJaDAc9CdEqXo+D13WuStG8lCdtKaO5AiNiSSMJsQJN2EfGSwbBQt+SFE2B8Kw==
|
||||
|
||||
swagger-ui-dist@^5.2.0:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.3.1.tgz#ae76a74136152d790b06a8b71ca389cac35ab78f"
|
||||
integrity sha512-El78OvXp9zMasfPrshtkW1CRx8AugAKoZuGGOTW+8llJzOV1RtDJYqQRz/6+2OakjeWWnZuRlN2Qj1Y0ilux3w==
|
||||
version "5.4.2"
|
||||
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.4.2.tgz#ff7b936bdfc84673a1823a0f05f3a933ba7ccd4c"
|
||||
integrity sha512-vT5QxP/NOr9m4gLZl+SpavWI3M9Fdh30+Sdw9rEtZbkqNmNNEPhjXas2xTD9rsJYYdLzAiMfwXvtooWH3xbLJA==
|
||||
|
||||
tempusdominus-bootstrap-4@^5.39.2:
|
||||
version "5.39.2"
|
||||
|
Reference in New Issue
Block a user