Compare commits
327 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f32d0bb28d | ||
|
|
23af6adcee | ||
|
|
7581ad8d1b | ||
|
|
a324d430e0 | ||
|
|
68bd83e104 | ||
|
|
95d490d6ff | ||
|
|
634bae4930 | ||
|
|
b5284a80c9 | ||
|
|
eb5332f0da | ||
|
|
a5ea20afc6 | ||
|
|
c70a7efd15 | ||
|
|
1463a8d21b | ||
|
|
9fe398c4bf | ||
|
|
541cf6599f | ||
|
|
29033a28a9 | ||
|
|
487631397c | ||
|
|
cf7df4bdf8 | ||
|
|
471f21e992 | ||
|
|
2a124a3d47 | ||
|
|
bf96ff5b92 | ||
|
|
b1e3ef7881 | ||
|
|
68b4abfac4 | ||
|
|
1934256f29 | ||
|
|
8129b6b60b | ||
|
|
5bb016dfa5 | ||
|
|
23ccd05719 | ||
|
|
4c5fbffd25 | ||
|
|
8509645985 | ||
|
|
7de98db143 | ||
|
|
31185beac5 | ||
|
|
c8ee47f935 | ||
|
|
4148f8e88e | ||
|
|
ba2cb6ce08 | ||
|
|
6b18b0a7be | ||
|
|
ad0447497c | ||
|
|
3e4f200475 | ||
|
|
8560becb83 | ||
|
|
d6f3595684 | ||
|
|
8de5700310 | ||
|
|
21aa5eab21 | ||
|
|
b5c9cbccf5 | ||
|
|
de7ad6b115 | ||
|
|
a3f66b664b | ||
|
|
4364f07899 | ||
|
|
d26f24a28b | ||
|
|
e786433273 | ||
|
|
03ab765ccd | ||
|
|
b2ba1de9e3 | ||
|
|
89b8a9c1a9 | ||
|
|
541318e964 | ||
|
|
d1a8900f98 | ||
|
|
6ca87a9a49 | ||
|
|
2a3e23ded4 | ||
|
|
46253c455f | ||
|
|
63dcfcde47 | ||
|
|
54cd5a004d | ||
|
|
c11bbba214 | ||
|
|
fdddc9295d | ||
|
|
1d6e545710 | ||
|
|
57438409c4 | ||
|
|
72453eac0a | ||
|
|
27b79841fc | ||
|
|
2b994fd2ee | ||
|
|
ce5be6645e | ||
|
|
b7c4011e80 | ||
|
|
ebcc9a422e | ||
|
|
6a7436dbf0 | ||
|
|
bf353d9622 | ||
|
|
2690e535e3 | ||
|
|
98769aea11 | ||
|
|
9c60fdec5a | ||
|
|
d37c98e5f0 | ||
|
|
a1dea994c9 | ||
|
|
11fdf5929a | ||
|
|
56d8c2f13a | ||
|
|
aa88046ca4 | ||
|
|
a35db9f1d3 | ||
|
|
c8ac094bf4 | ||
|
|
a177e2a185 | ||
|
|
1f5263ef22 | ||
|
|
d747a6c86a | ||
|
|
e3d0ddbce6 | ||
|
|
ab09ce219c | ||
|
|
646263ab2a | ||
|
|
cccf1d430f | ||
|
|
aad589eaca | ||
|
|
f4226876c9 | ||
|
|
12a318c6f2 | ||
|
|
844d6279ae | ||
|
|
de881eb78e | ||
|
|
0d1a8bdfb6 | ||
|
|
bbd5f5e7ae | ||
|
|
262f3df3ab | ||
|
|
f8e2e4ced7 | ||
|
|
c24679b799 | ||
|
|
33ec1626e8 | ||
|
|
4468a6ac98 | ||
|
|
4f964cb386 | ||
|
|
9d92020a07 | ||
|
|
3abf4865bc | ||
|
|
69e21fd483 | ||
|
|
0bbc06a70c | ||
|
|
8e1d9a4871 | ||
|
|
d76d5d2537 | ||
|
|
38882c5ec6 | ||
|
|
4f9e39edd7 | ||
|
|
9c0e0c5870 | ||
|
|
a4b3a5592e | ||
|
|
ef9413c5c1 | ||
|
|
0ff5aee6f6 | ||
|
|
61b6afa364 | ||
|
|
1946ff870e | ||
|
|
e3965ed82c | ||
|
|
f3effc5a60 | ||
|
|
bc78359dba | ||
|
|
72e1a9aee7 | ||
|
|
83b8b95b73 | ||
|
|
23d7b6ad3c | ||
|
|
f9c7c67dc7 | ||
|
|
c05181aa53 | ||
|
|
1daa15a303 | ||
|
|
4300da8f64 | ||
|
|
abf109885a | ||
|
|
f142798a81 | ||
|
|
fe2a628f35 | ||
|
|
6605eeafd0 | ||
|
|
ded742a7c1 | ||
|
|
b0dded1346 | ||
|
|
113a9ecf39 | ||
|
|
9e5ce48091 | ||
|
|
dc05753a0f | ||
|
|
49839d933b | ||
|
|
97dbd7bf08 | ||
|
|
9cac3b2311 | ||
|
|
11d28622e8 | ||
|
|
c99dd46007 | ||
|
|
645f9e2599 | ||
|
|
caa28af0d2 | ||
|
|
cc40344845 | ||
|
|
c8ccc0b529 | ||
|
|
a734d1c3ae | ||
|
|
f4d5f21832 | ||
|
|
e7cea3d949 | ||
|
|
96059a1b32 | ||
|
|
a06991f81b | ||
|
|
245bdbe6e8 | ||
|
|
4a674e3bfa | ||
|
|
632162c1be | ||
|
|
7d6b76effb | ||
|
|
b706f0c65a | ||
|
|
b6ce9eec30 | ||
|
|
c73be7d18e | ||
|
|
c9ffe4885d | ||
|
|
a2c2049037 | ||
|
|
2c0b1a7be0 | ||
|
|
5721c4bd62 | ||
|
|
a373f8ae4b | ||
|
|
201bda93a2 | ||
|
|
1900a5b8a2 | ||
|
|
98fad559d4 | ||
|
|
bed18b1981 | ||
|
|
0270f6aa08 | ||
|
|
5f26e914a2 | ||
|
|
b2aa882abb | ||
|
|
e273158796 | ||
|
|
a1008eac30 | ||
|
|
d7b5b8958a | ||
|
|
04c5928612 | ||
|
|
9a319a6ee0 | ||
|
|
cd25284d35 | ||
|
|
58eda2f152 | ||
|
|
ceb6774260 | ||
|
|
7b7293e108 | ||
|
|
11ea8f3716 | ||
|
|
1b8f4e6a4f | ||
|
|
3321deec70 | ||
|
|
5b48004449 | ||
|
|
9e1020b7f8 | ||
|
|
185e6b20ad | ||
|
|
2bc58e083d | ||
|
|
1323fff3e2 | ||
|
|
d186e26898 | ||
|
|
4f6075d8c5 | ||
|
|
d5dacb1053 | ||
|
|
1246f402e5 | ||
|
|
7080ec9a8f | ||
|
|
df28026a80 | ||
|
|
434525826e | ||
|
|
c21090f522 | ||
|
|
5a2600209f | ||
|
|
8ac8000f30 | ||
|
|
8821280642 | ||
|
|
2047d38c6e | ||
|
|
a68c1087dd | ||
|
|
2f7478bddb | ||
|
|
af1f2aef96 | ||
|
|
6602c76005 | ||
|
|
8f9b295e68 | ||
|
|
5167ba1154 | ||
|
|
b26dfe3fb0 | ||
|
|
402d98757e | ||
|
|
a7fc87c9bc | ||
|
|
5c1814989a | ||
|
|
e005c51b1a | ||
|
|
f14110aa1e | ||
|
|
affa7c41a1 | ||
|
|
9c123bd92a | ||
|
|
7f1dfd0496 | ||
|
|
49ff780e3f | ||
|
|
477f333466 | ||
|
|
e01e0f3abe | ||
|
|
8ba3305a21 | ||
|
|
24cac247f5 | ||
|
|
6a68e410e4 | ||
|
|
88d0d32ea0 | ||
|
|
11ac985e57 | ||
|
|
ac26c5510b | ||
|
|
85bff136de | ||
|
|
d2a878e98e | ||
|
|
4d8f08eddd | ||
|
|
edf973df00 | ||
|
|
8497f37b24 | ||
|
|
40d1a9c3d0 | ||
|
|
c7abed0d68 | ||
|
|
bf05434a5c | ||
|
|
18125d8989 | ||
|
|
75f0af2bd3 | ||
|
|
7b1a864486 | ||
|
|
f2f9a16e59 | ||
|
|
9f94ba55a4 | ||
|
|
15ab198af0 | ||
|
|
4659f51551 | ||
|
|
33d5ec44d2 | ||
|
|
fc072b13f2 | ||
|
|
efae5fea5b | ||
|
|
3aeecfa24d | ||
|
|
bae83535dd | ||
|
|
fb407a7fa7 | ||
|
|
151bd7f025 | ||
|
|
99f448dd64 | ||
|
|
7f7f1e8dce | ||
|
|
6b69487bc5 | ||
|
|
ee01f41979 | ||
|
|
97ecbd25b6 | ||
|
|
9458eb8b90 | ||
|
|
3c35a69c32 | ||
|
|
c9bc10820d | ||
|
|
8f52aaeadc | ||
|
|
dc05476d09 | ||
|
|
80d7284d72 | ||
|
|
b3a5128dbd | ||
|
|
7969145bbf | ||
|
|
f01ca33c33 | ||
|
|
fdf5559c25 | ||
|
|
27f9d70b56 | ||
|
|
c9215a9a4e | ||
|
|
69db4b558b | ||
|
|
35a4b75432 | ||
|
|
f36ad805b3 | ||
|
|
35766bf5b3 | ||
|
|
3308e79027 | ||
|
|
1e60f940e4 | ||
|
|
c8891236e6 | ||
|
|
b0d6e24bd4 | ||
|
|
b2295ce6d2 | ||
|
|
32ce04a1b7 | ||
|
|
dfa3262426 | ||
|
|
1f7580af3f | ||
|
|
60adda2b42 | ||
|
|
387a5f7dd3 | ||
|
|
f6bdb6e836 | ||
|
|
82d899d609 | ||
|
|
fdbb8a045a | ||
|
|
07db1f35bc | ||
|
|
dde577b98b | ||
|
|
5080d776a7 | ||
|
|
8c21969b84 | ||
|
|
13e99d3f07 | ||
|
|
dedbee3181 | ||
|
|
16f686deb8 | ||
|
|
973e4226b6 | ||
|
|
6e22d3b100 | ||
|
|
9b119da8e0 | ||
|
|
03f9ba45ea | ||
|
|
a965d01fb9 | ||
|
|
a123535b0a | ||
|
|
3a2929c016 | ||
|
|
106f25cc6b | ||
|
|
d6cc87ac86 | ||
|
|
a47bccab3f | ||
|
|
393a312186 | ||
|
|
7f21e2de34 | ||
|
|
82ac996b3a | ||
|
|
827134c972 | ||
|
|
787d5f11e0 | ||
|
|
2d2039f988 | ||
|
|
268f0d8a50 | ||
|
|
9dde46d419 | ||
|
|
162ba267a1 | ||
|
|
4691b45510 | ||
|
|
e2ebc037f2 | ||
|
|
550aa5565b | ||
|
|
c105ebc979 | ||
|
|
7ef744a995 | ||
|
|
ee4a082c74 | ||
|
|
1d7f7b2992 | ||
|
|
7689356a57 | ||
|
|
1401ed5c00 | ||
|
|
bae4a7f04c | ||
|
|
a44d746176 | ||
|
|
3afb9643c4 | ||
|
|
61a3a4329b | ||
|
|
491ad8c791 | ||
|
|
339a1ebffc | ||
|
|
1c35fecc85 | ||
|
|
d006436d49 | ||
|
|
6c4cc00fd5 | ||
|
|
847337443d | ||
|
|
b74fbddd94 | ||
|
|
8b444a03e5 | ||
|
|
e946ec79d5 | ||
|
|
ca740e8cee | ||
|
|
5d48b02b37 | ||
|
|
73ad9d39ab | ||
|
|
fd7e24b7d1 | ||
|
|
57ccb8645e | ||
|
|
e8d6d455f4 |
|
|
@ -10,7 +10,7 @@ for /f "tokens=*" %%a in ('jq .Version versiontemp.json --raw-output') do set ve
|
||||||
del versiontemp.json
|
del versiontemp.json
|
||||||
|
|
||||||
del "%releasePath%\grocy_%version%.zip"
|
del "%releasePath%\grocy_%version%.zip"
|
||||||
7za a -r "%releasePath%\grocy_%version%.zip" "%projectPath%\*" -xr!.* -xr!build.bat -xr!composer.json -xr!composer.lock -xr!package.json -xr!yarn.lock -xr!docs
|
7za a -r "%releasePath%\grocy_%version%.zip" "%projectPath%\*" -xr!.* -xr!build.bat -xr!composer.json -xr!composer.lock -xr!package.json -xr!yarn.lock -xr!docs -xr!test -x!public\packages\@fortawesome\fontawesome-free\js -x!public\packages\@fortawesome\fontawesome-free\less -x!public\packages\@fortawesome\fontawesome-free\metadata -x!public\packages\@fortawesome\fontawesome-free\scss -x!public\packages\@fortawesome\fontawesome-free\sprites -x!public\packages\@fortawesome\fontawesome-free\svgs
|
||||||
7za a "%releasePath%\grocy_%version%.zip" "%projectPath%\public\.htaccess"
|
7za a "%releasePath%\grocy_%version%.zip" "%projectPath%\public\.htaccess"
|
||||||
7za rn "%releasePath%\grocy_%version%.zip" .htaccess public\.htaccess
|
7za rn "%releasePath%\grocy_%version%.zip" .htaccess public\.htaccess
|
||||||
7za d "%releasePath%\grocy_%version%.zip" data\*.* data\storage data\viewcache\* changelog\__TEMPLATE.md
|
7za d "%releasePath%\grocy_%version%.zip" data\*.* data\storage data\viewcache\* changelog\__TEMPLATE.md
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,5 @@ if ($adminUserRow == null)
|
||||||
}
|
}
|
||||||
|
|
||||||
$adminUserRow->update([
|
$adminUserRow->update([
|
||||||
'password' => password_hash('admin', PASSWORD_DEFAULT)
|
'password' => password_hash('admin', PASSWORD_ARGON2ID)
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
pushd ..
|
pushd ..
|
||||||
|
set COMPOSER_FUND=0
|
||||||
call composer install
|
call composer install
|
||||||
call yarn install
|
call yarn install
|
||||||
popd
|
popd
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
pushd ..
|
pushd ..
|
||||||
|
|
||||||
for /d %%d in (localization\*) do (
|
for /d %%d in (localization\*) do (
|
||||||
if %%~nxd neq en (
|
if %%~nxd neq en (
|
||||||
tx pull --languages %%~nxd --force
|
tx pull --languages %%~nxd --force
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
copy /Y localization\en\userfield_types.po localization\en_GB\userfield_types.po
|
copy /Y localization\en\userfield_types.po localization\en_GB\userfield_types.po
|
||||||
copy /Y localization\en\stock_transaction_types.po localization\en_GB\stock_transaction_types.po
|
copy /Y localization\en\stock_transaction_types.po localization\en_GB\stock_transaction_types.po
|
||||||
copy /Y localization\en\component_translations.po localization\en_GB\component_translations.po
|
copy /Y localization\en\component_translations.po localization\en_GB\component_translations.po
|
||||||
|
|
@ -11,4 +13,5 @@ copy /Y localization\en\chore_period_types.po localization\en_GB\chore_period_ty
|
||||||
copy /Y localization\en\chore_assignment_types.po localization\en_GB\chore_assignment_types.po
|
copy /Y localization\en\chore_assignment_types.po localization\en_GB\chore_assignment_types.po
|
||||||
copy /Y localization\en\permissions.po localization\en_GB\permissions.po
|
copy /Y localization\en\permissions.po localization\en_GB\permissions.po
|
||||||
copy /Y localization\en\locales.po localization\en_GB\locales.po
|
copy /Y localization\en\locales.po localization\en_GB\locales.po
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
pushd ..
|
pushd ..
|
||||||
|
set COMPOSER_FUND=0
|
||||||
call composer update
|
call composer update
|
||||||
call yarn upgrade
|
call yarn upgrade
|
||||||
popd
|
popd
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_style = tab
|
|
||||||
indent_size = 4
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
14
.github/CONTRIBUTING.md
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
## Help & Usage Questions
|
||||||
|
→ [r/grocy on Reddit](https://www.reddit.com/r/grocy)
|
||||||
|
|
||||||
|
## Bug Reports & Feature Requests
|
||||||
|
→ [Issue Tracker](https://github.com/grocy/grocy/issues/new/choose)
|
||||||
|
|
||||||
|
## Say thanks
|
||||||
|
→ <https://grocy.info/#say-thanks>
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
→ [Transifex](https://explore.transifex.com/grocy/grocy/)
|
||||||
|
|
||||||
|
## Pull Requests
|
||||||
|
This project does not accept code contributions.
|
||||||
9
.github/ISSUE_TEMPLATE/bug-report.md
vendored
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: If you've found something that does not work, please report it to help improve
|
about: If you've found something that does not work, please report it to help improve Grocy
|
||||||
Grocy
|
|
||||||
title: 'Bug: '
|
title: 'Bug: '
|
||||||
labels: bug
|
labels: bug
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
@ -13,10 +12,10 @@ Please make sure to:
|
||||||
|
|
||||||
- Describe the bug as detailed as possible by providing the exact steps how to reproduce it
|
- Describe the bug as detailed as possible by providing the exact steps how to reproduce it
|
||||||
- Attach screenshots where useful
|
- Attach screenshots where useful
|
||||||
- Check if the problem was maybe already reported or fixed by searching open and closed issues here
|
- Check if the problem was maybe already reported or fixed by searching open and also already closed requests here
|
||||||
- Keep it to one topic per issue
|
- Keep it to one topic per request
|
||||||
|
|
||||||
Please also try to reproduce the problem on the pre-release demo: => https://demo-prerelease.grocy.info
|
Please also try to reproduce the problem on the pre-release demo: => https://demo-prerelease.grocy.info
|
||||||
- Use a private demo instance to make your example persistent
|
- Use a private demo instance to make your example persistent
|
||||||
- If the problem is not reproducible there, it's most likely not a bug - please use the r/grocy subreddit for general questions / help: => https://www.reddit.com/r/grocy
|
- If the problem is not reproducible there, it's most likely not a bug - please use the r/grocy subreddit for general help and usage questions: => https://www.reddit.com/r/grocy
|
||||||
-->
|
-->
|
||||||
|
|
|
||||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Questions / Help
|
- name: Help & Usage Questions
|
||||||
url: https://www.reddit.com/r/grocy
|
url: https://www.reddit.com/r/grocy
|
||||||
about: Please use the r/grocy subreddit for general questions / help
|
about: Please use the r/grocy subreddit for general help and usage questions
|
||||||
|
|
|
||||||
7
.github/ISSUE_TEMPLATE/feature-request.md
vendored
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
name: Feature Request
|
name: Feature Request
|
||||||
about: Ideas for improvements or new things which you would find useful are always
|
about: Ideas for improvements or new things which you would find useful are always welcome
|
||||||
welcome
|
|
||||||
title: 'Feature Request: '
|
title: 'Feature Request: '
|
||||||
labels: enhancement
|
labels: enhancement
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
@ -11,7 +10,7 @@ assignees: ''
|
||||||
<!--
|
<!--
|
||||||
Please make sure to:
|
Please make sure to:
|
||||||
|
|
||||||
- Describe what you would find useful
|
- Describe what you would find useful as detailed as possible
|
||||||
- Check if your idea was maybe already requested by searching open requests here
|
- Check if your idea was maybe already requested by searching open and also already closed requests here
|
||||||
- Keep it to one topic per request
|
- Keep it to one topic per request
|
||||||
-->
|
-->
|
||||||
|
|
|
||||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
This project does not accept code contributions.
|
||||||
4
.github/SECURITY.md
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
Grocy is not an enterprise application and neither one you (should) host publicly (means without authentication) on the internet.
|
Grocy is not an enterprise application and neither one you (should) host publicly (means without authentication) on the internet.
|
||||||
|
|
||||||
So unless something really bad can be abused _unauthenticated_, please just open a regular issue on the [Issue Tracker](https://github.com/grocy/grocy/issues/new/choose).
|
So unless something really bad can be abused _unauthenticated_, it's considered practically irrelevant for the target use case of Grocy and therefore not even worth reporting that.
|
||||||
|
|
||||||
You can also contact me directly, please see [berrnd.de](https://berrnd.de) for any contact information.
|
If you really think you've found something critical and valid for the target use case of Grocy and you feel the need to contact me privately on that, please see [berrnd.de](https://berrnd.de) for any contact information.
|
||||||
|
|
|
||||||
BIN
.github/publication_assets/chores.png
vendored
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 131 KiB |
BIN
.github/publication_assets/mealplan.png
vendored
|
Before Width: | Height: | Size: 499 KiB After Width: | Height: | Size: 540 KiB |
BIN
.github/publication_assets/shoppinglist.png
vendored
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 53 KiB |
BIN
.github/publication_assets/stock.png
vendored
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 212 KiB |
1
.gitignore
vendored
|
|
@ -1,5 +1,4 @@
|
||||||
embedded.txt
|
embedded.txt
|
||||||
.DS_Store
|
|
||||||
/.release
|
/.release
|
||||||
/packages
|
/packages
|
||||||
/public/packages
|
/public/packages
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@ $finder = PhpCsFixer\Finder::create()
|
||||||
->exclude(['packages'])
|
->exclude(['packages'])
|
||||||
->ignoreVCSIgnored(true)
|
->ignoreVCSIgnored(true)
|
||||||
->files()->name('*.php')
|
->files()->name('*.php')
|
||||||
->in(__DIR__)
|
->in(__DIR__);
|
||||||
;
|
|
||||||
|
|
||||||
$cfg = new PhpCsFixer\Config();
|
$cfg = new PhpCsFixer\Config();
|
||||||
return $cfg
|
return $cfg
|
||||||
|
|
@ -15,81 +14,41 @@ return $cfg
|
||||||
'array_syntax' => ['syntax' => 'short'],
|
'array_syntax' => ['syntax' => 'short'],
|
||||||
'combine_consecutive_unsets' => true,
|
'combine_consecutive_unsets' => true,
|
||||||
'class_attributes_separation' => true,
|
'class_attributes_separation' => true,
|
||||||
|
'class_attributes_separation' => ['elements' => ['const' => 'none', 'property' => 'none']],
|
||||||
'multiline_whitespace_before_semicolons' => false,
|
'multiline_whitespace_before_semicolons' => false,
|
||||||
'single_quote' => true,
|
'single_quote' => true,
|
||||||
// 'blank_line_after_opening_tag' => true,
|
'blank_line_after_opening_tag' => true,
|
||||||
// 'blank_line_before_return' => true,
|
'curly_braces_position' => [
|
||||||
'braces' => [
|
'control_structures_opening_brace' => 'next_line_unless_newline_at_signature_end',
|
||||||
'allow_single_line_closure' => true,
|
'anonymous_functions_opening_brace' => 'next_line_unless_newline_at_signature_end'
|
||||||
'position_after_anonymous_constructs' => 'same',
|
],
|
||||||
'position_after_control_structures' => 'next',
|
'control_structure_continuation_position' => [
|
||||||
'position_after_functions_and_oop_constructs' => 'next',
|
'position' => 'next_line'
|
||||||
|
],
|
||||||
|
'cast_spaces' => [
|
||||||
|
'space' => 'none'
|
||||||
],
|
],
|
||||||
// 'cast_spaces' => true,
|
|
||||||
// 'class_definition' => array('singleLine' => true),
|
|
||||||
'concat_space' => ['spacing' => 'one'],
|
'concat_space' => ['spacing' => 'one'],
|
||||||
'declare_equal_normalize' => true,
|
'declare_equal_normalize' => true,
|
||||||
'function_typehint_space' => true,
|
'type_declaration_spaces' => true,
|
||||||
'single_line_comment_style' => ['comment_types' => ['hash']],
|
'single_line_comment_style' => ['comment_types' => ['hash']],
|
||||||
'include' => true,
|
'include' => true,
|
||||||
'lowercase_cast' => true,
|
'lowercase_cast' => true,
|
||||||
// 'native_function_casing' => true,
|
|
||||||
// 'new_with_braces' => true,
|
|
||||||
// 'no_blank_lines_after_class_opening' => true,
|
|
||||||
// 'no_blank_lines_after_phpdoc' => true,
|
|
||||||
// 'no_empty_comment' => true,
|
|
||||||
// 'no_empty_phpdoc' => true,
|
|
||||||
// 'no_empty_statement' => true,
|
|
||||||
'no_leading_import_slash' => true,
|
'no_leading_import_slash' => true,
|
||||||
'no_leading_namespace_whitespace' => true,
|
'no_leading_namespace_whitespace' => true,
|
||||||
// 'no_mixed_echo_print' => array('use' => 'echo'),
|
|
||||||
'no_multiline_whitespace_around_double_arrow' => true,
|
'no_multiline_whitespace_around_double_arrow' => true,
|
||||||
// 'no_short_bool_cast' => true,
|
|
||||||
// 'no_singleline_whitespace_before_semicolons' => true,
|
|
||||||
'no_spaces_around_offset' => true,
|
'no_spaces_around_offset' => true,
|
||||||
// 'no_trailing_comma_in_list_call' => true,
|
|
||||||
// 'no_trailing_comma_in_singleline_array' => true,
|
|
||||||
// 'no_unneeded_control_parentheses' => true,
|
|
||||||
// 'no_unused_imports' => true,
|
|
||||||
'no_whitespace_before_comma_in_array' => true,
|
'no_whitespace_before_comma_in_array' => true,
|
||||||
'no_whitespace_in_blank_line' => true,
|
'no_whitespace_in_blank_line' => true,
|
||||||
// 'normalize_index_brace' => true,
|
|
||||||
'object_operator_without_whitespace' => true,
|
'object_operator_without_whitespace' => true,
|
||||||
// 'php_unit_fqcn_annotation' => true,
|
'blank_lines_before_namespace' => true,
|
||||||
// 'phpdoc_align' => true,
|
|
||||||
// 'phpdoc_annotation_without_dot' => true,
|
|
||||||
// 'phpdoc_indent' => true,
|
|
||||||
// 'phpdoc_inline_tag' => true,
|
|
||||||
// 'phpdoc_no_access' => true,
|
|
||||||
// 'phpdoc_no_alias_tag' => true,
|
|
||||||
// 'phpdoc_no_empty_return' => true,
|
|
||||||
// 'phpdoc_no_package' => true,
|
|
||||||
// 'phpdoc_no_useless_inheritdoc' => true,
|
|
||||||
// 'phpdoc_return_self_reference' => true,
|
|
||||||
// 'phpdoc_scalar' => true,
|
|
||||||
// 'phpdoc_separation' => true,
|
|
||||||
// 'phpdoc_single_line_var_spacing' => true,
|
|
||||||
// 'phpdoc_summary' => true,
|
|
||||||
// 'phpdoc_to_comment' => true,
|
|
||||||
// 'phpdoc_trim' => true,
|
|
||||||
// 'phpdoc_types' => true,
|
|
||||||
// 'phpdoc_var_without_name' => true,
|
|
||||||
// 'pre_increment' => true,
|
|
||||||
// 'return_type_declaration' => true,
|
|
||||||
// 'self_accessor' => true,
|
|
||||||
// 'short_scalar_cast' => true,
|
|
||||||
'single_blank_line_before_namespace' => true,
|
|
||||||
// 'single_class_element_per_statement' => true,
|
|
||||||
// 'space_after_semicolon' => true,
|
|
||||||
// 'standardize_not_equals' => true,
|
|
||||||
'ternary_operator_spaces' => true,
|
'ternary_operator_spaces' => true,
|
||||||
// 'trailing_comma_in_multiline_array' => true,
|
|
||||||
'trim_array_spaces' => true,
|
'trim_array_spaces' => true,
|
||||||
'unary_operator_spaces' => true,
|
'unary_operator_spaces' => true,
|
||||||
'whitespace_after_comma_in_array' => true,
|
'whitespace_after_comma_in_array' => true,
|
||||||
|
'no_trailing_comma_in_singleline' => true
|
||||||
])
|
])
|
||||||
->setIndent("\t")
|
->setIndent("\t")
|
||||||
->setLineEnding("\n")
|
->setLineEnding("\n")
|
||||||
->setUsingCache(false)
|
->setUsingCache(false)
|
||||||
->setFinder($finder)
|
->setFinder($finder);
|
||||||
;
|
|
||||||
|
|
|
||||||
15
.vscode/settings.json
vendored
|
|
@ -1,16 +1,3 @@
|
||||||
{
|
{
|
||||||
"phpserver.relativePath": "public",
|
"phpserver.relativePath": "public"
|
||||||
"editor.formatOnType": true,
|
|
||||||
"editor.formatOnPaste": true,
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"editor.insertSpaces": false,
|
|
||||||
"javascript.format.placeOpenBraceOnNewLineForControlBlocks": true,
|
|
||||||
"javascript.format.placeOpenBraceOnNewLineForFunctions": true,
|
|
||||||
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
|
|
||||||
"javascript.preferences.quoteStyle": "double",
|
|
||||||
"blade.format.enable": true,
|
|
||||||
"html.format.wrapAttributes": "force",
|
|
||||||
"html.format.wrapLineLength": 0,
|
|
||||||
"php-cs-fixer.formatHtml": true,
|
|
||||||
"php-cs-fixer.autoFixBySemicolon": true
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 Bernd Bestel
|
Copyright (c) 2017-2026 Bernd Bestel (<https://berrnd.de>)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
92
README.md
|
|
@ -1,7 +1,10 @@
|
||||||
|
-----
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img alt="Logo" height="60" src="https://raw.githubusercontent.com/grocy/grocy/master/public/img/logo.svg?sanitize=true" />
|
<img alt="Logo" height="50" src="https://raw.githubusercontent.com/grocy/grocy/master/public/img/logo.svg?sanitize=true" />
|
||||||
<h3>ERP beyond your fridge</h3>
|
<h2>ERP beyond your fridge</h2>
|
||||||
<h4>Grocy is a web-based self-hosted groceries & household management solution for your home<br>Created by <a href="https://github.com/berrnd">@berrnd</a></h4>
|
<h3>Grocy is a web-based self-hosted groceries & household management solution for your home</h3>
|
||||||
|
<em><h4>This is a hobby project by <a href="https://berrnd.de">Bernd Bestel</a></h4></em>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
@ -13,14 +16,14 @@
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
See the website → <https://grocy.info>
|
See the website. → <https://grocy.info>
|
||||||
|
|
||||||
## Questions / Help / Bug Reports / Feature Requests
|
## Questions / Help / Bug Reports / Feature Requests
|
||||||
|
|
||||||
- General help and usage questions → [r/grocy subreddit](https://www.reddit.com/r/grocy)
|
- General help and usage questions → [r/grocy on Reddit](https://www.reddit.com/r/grocy)
|
||||||
- Bug Reports and Feature Requests → [Issue Tracker](https://github.com/grocy/grocy/issues/new/choose)
|
- Bug Reports and Feature Requests → [Issue Tracker](https://github.com/grocy/grocy/issues/new/choose)
|
||||||
|
|
||||||
_Please don't send me private messages or call me regarding Grocy help. I check the issue tracker and the subreddit pretty much daily, but don't provide any support beyond that._
|
_Please don't send me private messages or call me regarding anything Grocy. I check the issue tracker and the subreddit pretty much daily, but don't provide any support beyond that._
|
||||||
|
|
||||||
## Community contributions
|
## Community contributions
|
||||||
|
|
||||||
|
|
@ -28,11 +31,9 @@ See the website for a list of community contributed Add-ons / Tools. → [htt
|
||||||
|
|
||||||
## How to install
|
## How to install
|
||||||
|
|
||||||
> Checkout [grocy-desktop](https://github.com/grocy/grocy-desktop), if you want to run Grocy without having to manage a webserver just like a normal (Windows) desktop application.
|
> Checkout [Grocy Desktop](https://github.com/grocy/grocy-desktop), if you want to run Grocy without having to manage a webserver just like a normal (Windows) desktop application.
|
||||||
>
|
>
|
||||||
> Directly download the [latest release](https://releases.grocy.info/latest-desktop) - the installation is nothing more than just clicking 2 times "next".
|
> Directly download the [latest release](https://releases.grocy.info/latest-desktop) (also [available via the Microsoft Store](https://apps.microsoft.com/detail/9NWB1TRNNKSF)) - the installation is nothing more than just clicking 2 times "next".
|
||||||
|
|
||||||
See the website for some installation guides and troubleshooting help. → [https://grocy.info/links](https://grocy.info/links)
|
|
||||||
|
|
||||||
Grocy is technically a pretty simple PHP application, so the basic notes to get it running are:
|
Grocy is technically a pretty simple PHP application, so the basic notes to get it running are:
|
||||||
- Unpack the [latest release](https://releases.grocy.info/latest)
|
- Unpack the [latest release](https://releases.grocy.info/latest)
|
||||||
|
|
@ -45,42 +46,42 @@ Grocy is technically a pretty simple PHP application, so the basic notes to get
|
||||||
|
|
||||||
Alternatively clone this repository (the `release` branch always references the latest released version) and install Composer and Yarn dependencies manually.
|
Alternatively clone this repository (the `release` branch always references the latest released version) and install Composer and Yarn dependencies manually.
|
||||||
|
|
||||||
|
See the website for more installation guides and troubleshooting help. → [https://grocy.info/links](https://grocy.info/links)
|
||||||
|
|
||||||
### Platform support
|
### Platform support
|
||||||
|
|
||||||
- PHP 8.1 (with SQLite 3.34.0+)
|
- PHP 8.5 (with SQLite 3.40+)
|
||||||
- Required PHP extensions: `fileinfo`, `pdo_sqlite`, `gd`, `ctype`, `json`, `intl`, `zlib`, `mbstring`
|
- Required PHP extensions: `fileinfo`, `pdo_sqlite`, `gd`, `ctype`, `intl`, `zlib`, `mbstring`
|
||||||
- _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._
|
- Recent Firefox, Chrome or Edge
|
||||||
|
|
||||||
## How to run using Docker
|
## How to run using Docker
|
||||||
|
|
||||||
See [grocy/grocy-docker](https://github.com/grocy/grocy-docker) or [linuxserver/docker-grocy](https://github.com/linuxserver/docker-grocy) for instructions.
|
→ https://hub.docker.com/r/linuxserver/grocy
|
||||||
|
|
||||||
## How to update
|
## How to update
|
||||||
|
|
||||||
- Overwrite everything with the [latest release](https://releases.grocy.info/latest) while keeping the `data` directory
|
- Overwrite everything with the [latest release](https://releases.grocy.info/latest) while keeping the `data` directory
|
||||||
- Check `config-dist.php` for new configuration options and add them to your `data/config.php` where appropriate (the default values from `config-dist.php` will be used for not in `data/config.php` defined settings)
|
- Check `config-dist.php` for new configuration options and add them to your `data/config.php` where appropriate (the default values from `config-dist.php` will be used for not in `data/config.php` defined settings)
|
||||||
- Empty the `data/viewcache` directory
|
|
||||||
- Visit the main route once to apply database migrations ([see below](https://github.com/grocy/grocy#database-migrations))
|
|
||||||
|
|
||||||
If you run Grocy on Linux, there is also `update.sh` (remember to make the script executable (`chmod +x update.sh`) and ensure that you have `unzip` installed) which does exactly this and additionally creates a backup (`.tgz` archive) of the current installation in `data/backups` (backups older than 60 days will be deleted during the update).
|
If you run Grocy on Linux, there is also `update.sh` (remember to make the script executable via `chmod +x update.sh` and ensure that you have `unzip` installed) which does exactly this and additionally creates a backup (`.tgz` archive) of the current installation in `data/backups` (backups older than 60 days will be deleted during the update).
|
||||||
|
|
||||||
## Localization
|
## Localization
|
||||||
|
|
||||||
Grocy is fully localizable - the default language is English (integrated into code), a German localization is always maintained by me.
|
Grocy is fully localizable - the default language is English (integrated into code), a German localization is always maintained by me.
|
||||||
|
|
||||||
You can easily help translating Grocy on [Transifex](https://www.transifex.com/grocy/grocy/dashboard/) if your language is incomplete or not available yet.
|
You can easily help translating Grocy on [Transifex](https://explore.transifex.com/grocy/grocy/) if your language is incomplete or not available yet.
|
||||||
|
|
||||||
The default language can be set in `data/config.php`, e. g. `Setting('DEFAULT_LOCALE', 'it');` and there is also a user setting (see the user settings page) to set a different language per user.
|
The default language can be set in `data/config.php`, e. g. `Setting('DEFAULT_LOCALE', 'de');` and there is also a user setting (see the user settings page) to set a different language per user.
|
||||||
|
|
||||||
The [pre-release demo](https://demo-prerelease.grocy.info) is available for any translation which is at least 70 % complete and will pull the translations from Transifex 10 minutes past every hour, so you can have a kind of instant preview of your contributed translations. Thank you!
|
The [pre-release demo](https://demo-prerelease.grocy.info) is available for any translation which is at least 70 % complete and will pull the translations from Transifex 10 minutes past every hour, so you can have a kind of instant preview of your contributed translations. Thank you!
|
||||||
|
|
||||||
Also any translation which once reached a completion level of 70 % ([`strings` resource](https://www.transifex.com/grocy/grocy/strings/)) will be included in releases.
|
Also any translation which once reached a completion level of 70 % ([`strings` resource](https://app.transifex.com/grocy/grocy/strings/)) will be included in releases.
|
||||||
|
|
||||||
_RTL languages are unfortunately not yet supported._
|
_RTL languages are not yet supported._
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
A household needs to be managed. I did this so far (almost 10 years) with my first self written software (a C# Windows forms application) and with a bunch of Excel sheets. The software was a pain to use at the end and Excel is Excel. So I searched for and tried different things for a (very) long time, nothing 100 % fitted, so this is my aim for a "complete household management"-thing. ERP your fridge!
|
A household needs to be managed. Before Grocy I did this (for almost 10 years) using my first self written software (a C# Windows forms application) and with a bunch of Excel sheets. The software was a pain to use at the end and Excel is Excel. So I searched for and tried different things for a (very) long time, nothing 100 % fitted, so this is my aim for a "complete household management"-thing. ERP your fridge!
|
||||||
|
|
||||||
## Things worth to know
|
## Things worth to know
|
||||||
|
|
||||||
|
|
@ -88,25 +89,37 @@ A household needs to be managed. I did this so far (almost 10 years) with my fir
|
||||||
|
|
||||||
See the integrated Swagger UI instance on [/api](https://demo.grocy.info/api).
|
See the integrated Swagger UI instance on [/api](https://demo.grocy.info/api).
|
||||||
|
|
||||||
|
The web frontend uses exactly this API for pretty much everything. So everything you can do there is also possible via the API.
|
||||||
|
|
||||||
### Barcode readers & camera scanning
|
### Barcode readers & camera scanning
|
||||||
|
|
||||||
Some fields (with a barcode icon above) also allow to select a value by scanning a barcode. It works best when your barcode reader prefixes every barcode with a letter which is normally not part of a item name (I use a `$`) and sends a `TAB` after a scan.
|
Some fields (with a barcode icon) also allow to select a value by scanning a barcode. It works best when your barcode reader prefixes every barcode with a letter which is normally not part of a item name (I use a `$`) and sends a `TAB` after a scan.
|
||||||
|
|
||||||
Additionally it's also possible to use your device camera to scan a barcode by using the camera button on the right side of the corresponding field (powered by [Quagga2](https://github.com/ericblade/quagga2), totally offline / client-side camera stream processing, please note due to browser security restrictions, this only works when serving Grocy via a secure connection (`https://`)). Quick video demo: <https://www.youtube.com/watch?v=Y5YH6IJFnfc>
|
Additionally it's also possible to use your device camera to scan a barcode by using the camera button on the right side of the corresponding input field (powered by [ZXing](https://github.com/zxing-js/library), totally offline / client-side camera stream processing. Please note due to browser security restrictions, this only works when serving Grocy via a secure connection (`https://`)). [Here](https://www.youtube.com/watch?v=veezFX4X1JU) and [there](https://www.youtube.com/watch?v=Y5YH6IJFnfc) are quick video demos of that.
|
||||||
|
|
||||||
_My personal recommendation: Use a USB barcode laser scanner. They are cheap and work 1000 % better, faster, under any lighting condition and from any angle._
|
_My personal recommendation: Use a USB barcode laser scanner. They are cheap and work 1000% better, faster, under any lighting condition and from any angle._
|
||||||
|
|
||||||
|
### Barcode lookup via external services
|
||||||
|
|
||||||
|
Products can be directly added to the database via looking them up against external services by a barcode.
|
||||||
|
|
||||||
|
This can be done in-place using the product picker workflow "External barcode lookup" (the workflow dialog is displayed when entering something unknown in any product input field) Quick video demo: <https://www.youtube.com/watch?v=-moXPA-VvGc>
|
||||||
|
|
||||||
|
A plugin for [Open Food Facts](https://world.openfoodfacts.org/) is included and used by default (see the `data/config.php` option `STOCK_BARCODE_LOOKUP_PLUGIN`).
|
||||||
|
|
||||||
|
See that plugin or `plugins/DemoBarcodeLookupPlugin.php` for a commented example implementation if you want to build a plugin.
|
||||||
|
|
||||||
### Input shorthands for date fields
|
### Input shorthands for date fields
|
||||||
|
|
||||||
For (productivity) reasons all date (and time) input (and display) fields use the ISO-8601 format regardless of localization.
|
For (productivity) reasons all date (and time) input (and display) fields use the ISO-8601 format regardless of localization.
|
||||||
The following shorthands are available:
|
The following shorthands are available:
|
||||||
- `MMDD` gets expanded to the given day on the current year, if > today, or to the given day next year, if < today, in proper notation
|
- `MMDD` gets expanded to the given day on the current year, if > today, or to the given day next year, if < today, in proper notation
|
||||||
- Example: `0517` will be converted to `2021-05-17`
|
- Example: `0517` will be converted to `2026-05-17`
|
||||||
- `YYYYMMDD` gets expanded to the proper ISO-8601 notation
|
- `YYYYMMDD` gets expanded to the proper ISO-8601 notation
|
||||||
- Example: `20210417` will be converted to `2021-04-17`
|
- Example: `20260417` will be converted to `2026-04-17`
|
||||||
- `YYYYMMe` or `YYYYMM+` gets expanded to the end of the given month in the given year in proper notation
|
- `YYYYMMe` or `YYYYMM+` gets expanded to the end of the given month in the given year in proper notation
|
||||||
- Example: `202107e` will be converted to `2021-07-31`
|
- Example: `202607e` will be converted to `2026-07-31`
|
||||||
- `[+/-]n[d/m/y]` gets expanded to a date relative to today, while adding (**+**) or subtracting (**-**) the **n**umber of**d**ays/**m**onths/**y**ears, in proper notation
|
- `[+/-]n[d/m/y]` gets expanded to a date relative to today, while adding (**+**) or subtracting (**-**) the **n**umber of **d**ays/**m**onths/**y**ears, in proper notation
|
||||||
- Example: `+1m` will be converted to the same day next month
|
- Example: `+1m` will be converted to the same day next month
|
||||||
- `x` gets expanded to `2999-12-31` (which is an alias for "never overdue")
|
- `x` gets expanded to `2999-12-31` (which is an alias for "never overdue")
|
||||||
- Down/up arrow keys will increase/decrease the date by 1 day
|
- Down/up arrow keys will increase/decrease the date by 1 day
|
||||||
|
|
@ -119,17 +132,18 @@ The following shorthands are available:
|
||||||
Wherever a button contains a bold highlighted letter, this is a shortcut key.
|
Wherever a button contains a bold highlighted letter, this is a shortcut key.
|
||||||
Example: Button "**P** Add as new product" can be "pressed" by using the `P` key on your keyboard.
|
Example: Button "**P** Add as new product" can be "pressed" by using the `P` key on your keyboard.
|
||||||
|
|
||||||
### Barcode lookup via external services
|
### Installable web app (PWA)
|
||||||
|
|
||||||
Products can be directly added to the database via looking them up against external services by a barcode.
|
Grocy's web frontend is responsive and an "installable web app" ([PWA](https://en.wikipedia.org/wiki/Progressive_web_app), without providing any offline usage capabilities), that provides a pretty native mobile app-like experience without the need for additional tools.
|
||||||
This is currently only possible through the REST API.
|
|
||||||
There is no plugin included for any service, see the reference implementation in `data/plugins/DemoBarcodeLookupPlugin.php`.
|
- Quick video demo on Android/Firefox: <https://www.youtube.com/watch?v=L38drVZfwHs>
|
||||||
|
- Quick video demo on Android/Chrome: <https://www.youtube.com/watch?v=rjLdXUFDNuk>
|
||||||
|
|
||||||
### Database migrations
|
### Database migrations
|
||||||
|
|
||||||
Database schema migration is automatically done when visiting the root (`/`) route (click on the logo in the left upper edge).
|
Database schema migration is done when visiting the root (`/`) route (click on the logo in the left upper edge) as needed and is also triggered automatically if the version has changed (so when an update has been made).
|
||||||
|
|
||||||
_Please note: Database migrations are supposed to work between releases, not between every commit. If you want to run the current `master` branch (which is the development version), you need to handle that (and maybe more) yourself._
|
_Please note: Database migrations are supposed to work between releases, not between every commit. If you want to run the current `master` branch (which is the development version), you need to handle that (and more) yourself._
|
||||||
|
|
||||||
### Disable certain features
|
### Disable certain features
|
||||||
|
|
||||||
|
|
@ -142,21 +156,21 @@ If you don't use certain feature sets of Grocy (for example if you don't need "C
|
||||||
|
|
||||||
### Demo mode
|
### Demo mode
|
||||||
|
|
||||||
When the `MODE` setting is set to `dev`, `demo` or `prerelease`, the application will work in a demo mode which means authentication is disabled and some demo data will be generated during the database schema migration.
|
When the `MODE` setting is set to `dev`, `demo` or `prerelease`, the application will work in a demo mode which means authentication is disabled and some demo data will be generated during the database schema migration (pass the query parameter `nodemodata`, e.g. `https://grocy.example.com/?nodemodata` to skip that).
|
||||||
|
|
||||||
### Embedded mode
|
### Embedded mode
|
||||||
|
|
||||||
When the file `embedded.txt` exists, it must contain a valid and writable path which will be used as the data directory instead of `data` and authentication will be disabled (used in [grocy-desktop](https://github.com/grocy/grocy-desktop)).
|
When the file `embedded.txt` exists, it must contain a valid and writable path which will be used as the data directory instead of `data` and authentication will be disabled (used in [Grocy Desktop](https://github.com/grocy/grocy-desktop)).
|
||||||
|
|
||||||
In embedded mode, settings can be overridden by text files in `data/settingoverrides`, the file name must be `<SettingName>.txt` (e. g. `BASE_URL.txt`) and the content must be the setting value (normally one single line).
|
In embedded mode, settings can be overridden by text files in `data/settingoverrides`, the file name must be `<SettingName>.txt` (e. g. `BASE_URL.txt`) and the content must be the setting value (normally one single line).
|
||||||
|
|
||||||
## Contributing / Say Thanks
|
## Contributing / Say Thanks
|
||||||
|
|
||||||
Any help is welcome, feel free to contribute anything which comes to your mind or see <https://grocy.info/#say-thanks> if you just want to say thanks.
|
See <https://grocy.info/#say-thanks> if you just want to say thanks or [Contributing](https://github.com/grocy/grocy?tab=contributing-ov-file#contributing-ov-file) for anything else.
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
There is none. The progress of a specific bug/enhancement is always tracked in the corresponding issue, at least by commit comment references.
|
There is none. The progress of a specific bug/enhancement is always tracked in the corresponding request, at least by commit comment references.
|
||||||
|
|
||||||
[Milestones](https://github.com/grocy/grocy/milestones) are used to indicate in which version the corresponding request was done (`vNEXT` means it's currently planned to do that for the next release).
|
[Milestones](https://github.com/grocy/grocy/milestones) are used to indicate in which version the corresponding request was done (`vNEXT` means it's currently planned to do that for the next release).
|
||||||
|
|
||||||
|
|
|
||||||
43
app.php
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
use Grocy\Controllers\ExceptionController;
|
use Grocy\Controllers\ExceptionController;
|
||||||
use Grocy\Helpers\UrlManager;
|
use Grocy\Helpers\UrlManager;
|
||||||
|
use Grocy\Helpers\SlimBladeView;
|
||||||
use Grocy\Middleware\LocaleMiddleware;
|
use Grocy\Middleware\LocaleMiddleware;
|
||||||
use Grocy\Middleware\CorsMiddleware;
|
use Grocy\Middleware\CorsMiddleware;
|
||||||
use Psr\Container\ContainerInterface as Container;
|
use Psr\Container\ContainerInterface as Container;
|
||||||
use Slim\Factory\AppFactory;
|
use Slim\Factory\AppFactory;
|
||||||
use Slim\Views\Blade;
|
|
||||||
|
|
||||||
// Load composer dependencies
|
// Load composer dependencies
|
||||||
require_once __DIR__ . '/packages/autoload.php';
|
require_once __DIR__ . '/packages/autoload.php';
|
||||||
|
|
@ -14,7 +14,6 @@ require_once __DIR__ . '/packages/autoload.php';
|
||||||
// Load config files
|
// Load config files
|
||||||
require_once GROCY_DATAPATH . '/config.php';
|
require_once GROCY_DATAPATH . '/config.php';
|
||||||
require_once __DIR__ . '/config-dist.php'; // For not in own config defined values we use the default ones
|
require_once __DIR__ . '/config-dist.php'; // For not in own config defined values we use the default ones
|
||||||
require_once __DIR__ . '/helpers/ConfigurationValidator.php';
|
|
||||||
|
|
||||||
// Error reporting definitions
|
// Error reporting definitions
|
||||||
if (GROCY_MODE === 'dev')
|
if (GROCY_MODE === 'dev')
|
||||||
|
|
@ -44,17 +43,38 @@ if (GROCY_DISABLE_AUTH === true)
|
||||||
// Check if any invalid entries in config.php have been made
|
// Check if any invalid entries in config.php have been made
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
(new ConfigurationValidator())->validateConfig();
|
(new Grocy\Helpers\ConfigurationValidator())->validateConfig();
|
||||||
}
|
}
|
||||||
catch (EInvalidConfig $ex)
|
catch (\Grocy\Helpers\EInvalidConfig $ex)
|
||||||
{
|
{
|
||||||
exit('Invalid setting in config.php: ' . $ex->getMessage());
|
exit('Invalid setting in config.php: ' . $ex->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create data/viewcache folder if it doesn't exist
|
// Create data/viewcache folder if it doesn't exist
|
||||||
if (!file_exists(GROCY_DATAPATH . '/viewcache'))
|
$viewcachePath = GROCY_DATAPATH . '/viewcache';
|
||||||
|
if (!file_exists($viewcachePath))
|
||||||
{
|
{
|
||||||
mkdir(GROCY_DATAPATH . '/viewcache');
|
mkdir($viewcachePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty data/viewcache when and trigger database migrations when:
|
||||||
|
// The version changed (so when an update was done)
|
||||||
|
// GROCY_BASE_URL OR GROCY_BASE_PATH changed
|
||||||
|
$hash = hash('sha256', file_get_contents(__DIR__ . '/version.json') . GROCY_BASE_URL . GROCY_BASE_PATH);
|
||||||
|
$hashCacheFile = $viewcachePath . "/$hash.txt";
|
||||||
|
if (!file_exists($hashCacheFile))
|
||||||
|
{
|
||||||
|
EmptyFolder($viewcachePath);
|
||||||
|
touch($hashCacheFile);
|
||||||
|
|
||||||
|
if (function_exists('opcache_reset'))
|
||||||
|
{
|
||||||
|
opcache_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schema migration happens on the root route, so redirect to there
|
||||||
|
header('Location: ' . (new UrlManager(GROCY_BASE_URL))->ConstructUrl('/'));
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup base application
|
// Setup base application
|
||||||
|
|
@ -62,15 +82,18 @@ AppFactory::setContainer(new DI\Container());
|
||||||
$app = AppFactory::create();
|
$app = AppFactory::create();
|
||||||
|
|
||||||
$container = $app->getContainer();
|
$container = $app->getContainer();
|
||||||
$container->set('view', function (Container $container) {
|
$container->set('view', function (Container $container)
|
||||||
return new Blade(__DIR__ . '/views', GROCY_DATAPATH . '/viewcache');
|
{
|
||||||
|
return new SlimBladeView(__DIR__ . '/views', GROCY_DATAPATH . '/viewcache');
|
||||||
});
|
});
|
||||||
|
|
||||||
$container->set('UrlManager', function (Container $container) {
|
$container->set('UrlManager', function (Container $container)
|
||||||
|
{
|
||||||
return new UrlManager(GROCY_BASE_URL);
|
return new UrlManager(GROCY_BASE_URL);
|
||||||
});
|
});
|
||||||
|
|
||||||
$container->set('ApiKeyHeaderName', function (Container $container) {
|
$container->set('ApiKeyHeaderName', function (Container $container)
|
||||||
|
{
|
||||||
return 'GROCY-API-KEY';
|
return 'GROCY-API-KEY';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
- New related project: **grocy-desktop**
|
- New related project: **Grocy Desktop**
|
||||||
- => https://github.com/grocy/grocy-desktop
|
- => https://github.com/grocy/grocy-desktop
|
||||||
- Run Grocy without a webserver just like a normal (Windows) desktop application
|
- Run Grocy without a webserver just like a normal (Windows) desktop application
|
||||||
- New "embedded mode" for Grocy to help running in "desktop application mode" [see README](https://github.com/grocy/grocy#embedded-mode)
|
- New "embedded mode" for Grocy to help running in "desktop application mode" [see README](https://github.com/grocy/grocy#embedded-mode)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,5 @@
|
||||||
- Some other small CSS fixes (context menus were not fully displayed when the parent container was to small, improved padding for text inputs)
|
- Some other small CSS fixes (context menus were not fully displayed when the parent container was to small, improved padding for text inputs)
|
||||||
- As always: Updated translations (thanks all the translators)
|
- As always: Updated translations (thanks all the translators)
|
||||||
|
|
||||||
### Self promotion
|
### Other
|
||||||
[grocy-desktop](https://github.com/grocy/grocy-desktop) is now also available through the Microsoft Store
|
- [Grocy Desktop](https://github.com/grocy/grocy-desktop) is now also available through the Microsoft Store: https://apps.microsoft.com/detail/9NWB1TRNNKSF
|
||||||
|
|
||||||
<a href="//www.microsoft.com/store/apps/9nwb1trnnksf?cid=storebadge&ocid=badge"><img src="https://assets.windowsphone.com/85864462-9c82-451e-9355-a3d5f874397a/English_get-it-from-MS_InvariantCulture_Default.png" alt="Get it from Microsoft" width="150px" /></a>
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,6 @@
|
||||||
- Also applies to quantity units, n-plural forms can be entered on the quantity unit edit page
|
- Also applies to quantity units, n-plural forms can be entered on the quantity unit edit page
|
||||||
- It's not required to install the PHP gettext extension, on both, server and client, managed implementations of gettext are used ([oscarotero/Gettext](https://github.com/oscarotero/Gettext) & [oscarotero/gettext-translator](https://github.com/oscarotero/gettext-translator))
|
- It's not required to install the PHP gettext extension, on both, server and client, managed implementations of gettext are used ([oscarotero/Gettext](https://github.com/oscarotero/Gettext) & [oscarotero/gettext-translator](https://github.com/oscarotero/gettext-translator))
|
||||||
- Some other small fixes and improvements
|
- Some other small fixes and improvements
|
||||||
- The "Add as barcode to existing product" productpicker workflow failed to add the barcode to the given product
|
- The "Add as barcode to existing product" product picker workflow failed to add the barcode to the given product
|
||||||
- Recipes can now be filter by stock availability
|
- Recipes can now be filter by stock availability
|
||||||
- Added a feature flag (`config.php` setting) to also be able to hide all stock related UI elements and routes
|
- Added a feature flag (`config.php` setting) to also be able to hide all stock related UI elements and routes
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
### New feature: Custom entities / objects / lists
|
### New Feature: Custom entities / objects / lists
|
||||||
|
|
||||||
- Custom entities are based on Userfields and can be used to add any custom lists you want to have in Grocy
|
- Custom entities are based on Userfields and can be used to add any custom lists you want to have in Grocy
|
||||||
- They can have an own menu entry in the sidebar
|
- They can have an own menu entry in the sidebar
|
||||||
- => See "Manage master data" -> "Userentities" or try it on the demo: https://demo.grocy.info/userobjects/exampleuserentity
|
- => See "Manage master data" -> "Userentities" or try it on the demo: https://demo.grocy.info/userobjects/exampleuserentity
|
||||||
|
|
||||||
### New feature: Use the device camera for barcode scanning
|
### New Feature: Use the device camera for barcode scanning
|
||||||
- Available on any barcode-enabled field (so currently only for picking products) - a new camera button at the right of side the text field
|
- Available on any barcode-enabled field (so currently only for picking products) - a new camera button at the right of side the text field
|
||||||
- Implemented using [QuaggaJS](https://github.com/serratus/quaggaJS) - camera stream processing happens totally offline / client-side
|
- Implemented using [QuaggaJS](https://github.com/serratus/quaggaJS) - camera stream processing happens totally offline / client-side
|
||||||
- Please note due to browser security restrictions, this only works when serving Grocy via a secure connection (`https://`)
|
- Please note due to browser security restrictions, this only works when serving Grocy via a secure connection (`https://`)
|
||||||
- There is also a `config.php` setting `DISABLE_BROWSER_BARCODE_CAMERA_SCANNING` to disable this, if you don't need it at all (defaults to `false`)
|
- There is also a `config.php` setting `DISABLE_BROWSER_BARCODE_CAMERA_SCANNING` to disable this, if you don't need it at all (defaults to `false`)
|
||||||
- I you have problems that barcodes are not recognized properly, there is a little "barcode scanner testing page" at [/barcodescannertesting](https://demo.grocy.info/barcodescannertesting)
|
- If you have problems that barcodes are not recognized properly, there is a little "barcode scanner testing page" at [/barcodescannertesting](https://demo.grocy.info/barcodescannertesting)
|
||||||
- => Quick video demo: https://www.youtube.com/watch?v=Y5YH6IJFnfc
|
- => Quick video demo: https://www.youtube.com/watch?v=Y5YH6IJFnfc
|
||||||
|
|
||||||
### Stock improvements/fixes
|
### Stock improvements/fixes
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
### Userfield improvements/fixes
|
### Userfield improvements/fixes
|
||||||
- New Userfield type "Select list" for a list of predefined values where a single or also multiple values can then be selected on the entity object
|
- New Userfield type "Select list" for a list of predefined values where a single or also multiple values can then be selected on the entity object
|
||||||
- New Userfield type "Link" - a single-line-textbox where the content will be rendered as a clickable link
|
- New Userfield type "Link" - a single-line-textbox where the content will be rendered as a clickable link
|
||||||
- Userfields of type "checkbox" are rendered as a checkmark in tables when checked (instead of "1" as till now)
|
- Userfields of type "Checkbox" are rendered as a checkmark in tables when checked (instead of "1" as till now)
|
||||||
- Product Userfields are now also rendered on the shopping list (for items which have a product referenced)
|
- Product Userfields are now also rendered on the shopping list (for items which have a product referenced)
|
||||||
- Fixed that the Userfield type "Preset list" had always the caption "Product group" instead of the configured one (thanks @oncleben31)
|
- Fixed that the Userfield type "Preset list" had always the caption "Product group" instead of the configured one (thanks @oncleben31)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
### New feature: Transfer products between locations and edit stock entries
|
### New Feature: Transfer products between locations and edit stock entries
|
||||||
- New menu entry in the sidebar to transfer products (or as a shortcut in the more/context menu per line on the stock overview page)
|
- New menu entry in the sidebar to transfer products (or as a shortcut in the more/context menu per line on the stock overview page)
|
||||||
- New button "Stock entries" in the header of the stock overview page (or as a shortcut in the more/context menu per line) to show the detail stock entries behind each product
|
- New button "Stock entries" in the header of the stock overview page (or as a shortcut in the more/context menu per line) to show the detail stock entries behind each product
|
||||||
- From there you can also edit the stock entries
|
- From there you can also edit the stock entries
|
||||||
- (A huge THANK YOU goes to @kriddles for the work on this feature)
|
- (A huge THANK YOU goes to @kriddles for the work on this feature)
|
||||||
|
|
||||||
### New feature: Scan mode
|
### New Feature: Scan mode
|
||||||
- Just scan one product after another, no manual input required and audio feedback is provided
|
- Just scan one product after another, no manual input required and audio feedback is provided
|
||||||
- New switch-button on the purchase and consume page
|
- New switch-button on the purchase and consume page
|
||||||
- When enabled
|
- When enabled
|
||||||
|
|
@ -14,13 +14,13 @@
|
||||||
- Audio feedback is provided after scanning and on success/error of the transaction
|
- Audio feedback is provided after scanning and on success/error of the transaction
|
||||||
- => Quick video demo: https://www.youtube.com/watch?v=83dm9iD718k
|
- => Quick video demo: https://www.youtube.com/watch?v=83dm9iD718k
|
||||||
|
|
||||||
### New feature: Self produced products
|
### New Feature: Self produced products
|
||||||
- To a recipe a product can be attached
|
- To a recipe a product can be attached
|
||||||
- This products needs a "Default best before date"
|
- This products needs a "Default best before date"
|
||||||
- On using "Consume all ingredients needed by this recipe" and when it has a product attached, one unit of that product (per serving in purchase quantity unit) will be added to stock (with the proper price based on the recipe ingredients)
|
- On using "Consume all ingredients needed by this recipe" and when it has a product attached, one unit of that product (per serving in purchase quantity unit) will be added to stock (with the proper price based on the recipe ingredients)
|
||||||
- (Thanks @kriddles for the initial work on this)
|
- (Thanks @kriddles for the initial work on this)
|
||||||
|
|
||||||
### New feature: Freeze/Thaw products
|
### New Feature: Freeze/Thaw products
|
||||||
- New product options "Default best before days after freezing/thawing" to set how the best before date should be changed on freezing/thawing
|
- New product options "Default best before days after freezing/thawing" to set how the best before date should be changed on freezing/thawing
|
||||||
- New location option "Is freezer" to indicate if the location is a freezer
|
- New location option "Is freezer" to indicate if the location is a freezer
|
||||||
- => When moving a product from/to a freezer location, the best before date is changed accordingly
|
- => When moving a product from/to a freezer location, the best before date is changed accordingly
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
### New feature: Price history per store
|
### New Feature: Price history per store
|
||||||
- Define stores under master data
|
- Define stores under master data
|
||||||
- New product option to set the default store
|
- New product option to set the default store
|
||||||
- Track on purchase/inventory in which store you bought the product (gets prefilled by the last store you purchased the product, or the default store of the product if you never bought it)
|
- Track on purchase/inventory in which store you bought the product (gets prefilled by the last store you purchased the product, or the default store of the product if you never bought it)
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,18 @@
|
||||||
|
|
||||||
> ❗ If some pages/tables doesn't load at all, please check that your `/data/config.php` setting `CURRENCY` is a valid ISO 4217 currency code - that's most probably the issue then.
|
> ❗ If some pages/tables doesn't load at all, please check that your `/data/config.php` setting `CURRENCY` is a valid ISO 4217 currency code - that's most probably the issue then.
|
||||||
|
|
||||||
### New feature: Use any product related quantity unit anywhere
|
### New Feature: Use any product related quantity unit anywhere
|
||||||
- Finally it's possible to use any product related quantity unit on any page
|
- Finally it's possible to use any product related quantity unit on any page
|
||||||
- Products still have one quantity unit stock and one (default) quantity unit purchase, but any QU, which has a direct or indirect conversion for that product, can be used to pick an amount
|
- Products still have one quantity unit stock and one (default) quantity unit purchase, but any QU, which has a direct or indirect conversion for that product, can be used to pick an amount
|
||||||
- Because the stock quantity unit is now the base for everything, it cannot be changed after the product was once added to stock (for now, maybe there will be a possibilty to change it in a future release)
|
- Because the stock quantity unit is now the base for everything, it cannot be changed after the product was once added to stock (for now, maybe there will be a possibilty to change it in a future release)
|
||||||
|
|
||||||
### New feature: Prefill purchase data by barcodes
|
### New Feature: Prefill purchase data by barcodes
|
||||||
- Imagine you buy for example eggs in different pack sizes and they have different barcodes
|
- Imagine you buy for example eggs in different pack sizes and they have different barcodes
|
||||||
- Each product barcode can be assigned an amount, quantity unit and store (on the product edit page), which is then automatically prefilled on the purchase page
|
- Each product barcode can be assigned an amount, quantity unit and store (on the product edit page), which is then automatically prefilled on the purchase page
|
||||||
- Additionally, the last price per barcode will be tracked and prefilled as a "Total price" on purchase
|
- Additionally, the last price per barcode will be tracked and prefilled as a "Total price" on purchase
|
||||||
- (Thanks @kriddles for the initial work on this)
|
- (Thanks @kriddles for the initial work on this)
|
||||||
|
|
||||||
### New feature: User permissions
|
### New Feature: User permissions
|
||||||
- Users can now have permissions, can be configured per user on the "Manage users" page (lock icon)
|
- Users can now have permissions, can be configured per user on the "Manage users" page (lock icon)
|
||||||
- Default permissions for new users can be set via a new `config.php` setting `DEFAULT_PERMISSIONS` (defaults to `ADMIN`, so no changed behavior when not configured)
|
- Default permissions for new users can be set via a new `config.php` setting `DEFAULT_PERMISSIONS` (defaults to `ADMIN`, so no changed behavior when not configured)
|
||||||
- All currently existing users will get all permissions (`ADMIN`) during the update/migration
|
- All currently existing users will get all permissions (`ADMIN`) during the update/migration
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
- Other users only see their API keys on that page
|
- Other users only see their API keys on that page
|
||||||
- (Thanks @fipwmaqzufheoxq92ebc for the initial work on this)
|
- (Thanks @fipwmaqzufheoxq92ebc for the initial work on this)
|
||||||
|
|
||||||
### New feature: External authentication support
|
### New Feature: External authentication support
|
||||||
- New `config.php` setting `AUTH_CLASS` to change the used authentication provider
|
- New `config.php` setting `AUTH_CLASS` to change the used authentication provider
|
||||||
- Via LDAP
|
- Via LDAP
|
||||||
- New `config.php` settings `LDAP_DOMAIN`, `LDAP_ADDRESS` and `LDAP_BASE_DN`
|
- New `config.php` settings `LDAP_DOMAIN`, `LDAP_ADDRESS` and `LDAP_BASE_DN`
|
||||||
|
|
@ -56,14 +56,14 @@
|
||||||
- Products can now be duplicated (new dropdown menu item on the products list page, all fields will be preset from the copied product, except the name)
|
- Products can now be duplicated (new dropdown menu item on the products list page, all fields will be preset from the copied product, except the name)
|
||||||
- Products can now be merged (new dropdown menu item on the products list page)
|
- Products can now be merged (new dropdown menu item on the products list page)
|
||||||
- Useful if you have two products which are basically the same and want to replace all occurrences of one with the other one
|
- Useful if you have two products which are basically the same and want to replace all occurrences of one with the other one
|
||||||
- When consuming or opening a parent product, which is currently not in stock, any in-stock sub product will now be consumed/opened (like already automatically done when consuming recipes)
|
- When consuming or opening a parent product, which is currently not in stock, any in stock sub product will now be consumed/opened (like already automatically done when consuming recipes)
|
||||||
- Opened stock entries get now consumed first by default when no specific stock entry is used/selected
|
- Opened stock entries get now consumed first by default when no specific stock entry is used/selected
|
||||||
- So the default consume rule is now "Opened first, then first due first, then first in first out"
|
- So the default consume rule is now "Opened first, then first due first, then first in first out"
|
||||||
- Optimized/clarified what the total/unit price on the purchase page is (thanks @kriddles)
|
- Optimized/clarified what the total/unit price on the purchase page is (thanks @kriddles)
|
||||||
- On the purchase page the amount field is now displayed above/before the due date for better `TAB` handling (thanks @kriddles)
|
- On the purchase page the amount field is now displayed above/before the due date for better `TAB` handling (thanks @kriddles)
|
||||||
- Changed that when `FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING` is disabled, products now get internally a due date of "never overdue" (aka `2999-12-31`) instead of today (thanks @kriddles)
|
- Changed that when `FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING` is disabled, products now get internally a due date of "never overdue" (aka `2999-12-31`) instead of today (thanks @kriddles)
|
||||||
- Products can now be disabled to keep the history/journal, but hide it everywhere, without deleting it (new product option "Active", deleting a product now explicitly also deletes its journal and all other references) (thanks @kriddles for the initial work on this)
|
- Products can now be disabled to keep the history/journal, but hide it everywhere, without deleting it (new product option "Active", deleting a product now explicitly also deletes its journal and all other references) (thanks @kriddles for the initial work on this)
|
||||||
- Products can now be hidden from the stock overview page, even if they are in-stock (new product option "Never show on stock overview", disabled by default, so no changed behavior when not configured)
|
- Products can now be hidden from the stock overview page, even if they are in stock (new product option "Never show on stock overview", disabled by default, so no changed behavior when not configured)
|
||||||
- That's maybe useful for parent products you only use as a kind of "container"
|
- That's maybe useful for parent products you only use as a kind of "container"
|
||||||
- The due date is now also prefilled on the inventory page based on the products "Default due days" (was only done on the purchase page before)
|
- The due date is now also prefilled on the inventory page based on the products "Default due days" (was only done on the purchase page before)
|
||||||
- On the stock journal page, it's now visible if a consume-booking was spoiled
|
- On the stock journal page, it's now visible if a consume-booking was spoiled
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
- Fixed that a "Total price" on purchase was not handled correctly for tare weight handling enabled products (the total price was wrongly related to the amount including the tare weight)
|
- Fixed that a "Total price" on purchase was not handled correctly for tare weight handling enabled products (the total price was wrongly related to the amount including the tare weight)
|
||||||
|
|
||||||
### Shopping list improvements
|
### Shopping list improvements
|
||||||
- Added a button to add all currently in-stock but overdue and expired products to the shopping list (thanks @m-byte)
|
- Added a button to add all currently in stock but overdue and expired products to the shopping list (thanks @m-byte)
|
||||||
- Improved that when `FEATURE_FLAG_STOCK` is disabled, all product/stock related inputs and buttons are now hidden on the shopping list page (thanks @fipwmaqzufheoxq92ebc)
|
- Improved that when `FEATURE_FLAG_STOCK` is disabled, all product/stock related inputs and buttons are now hidden on the shopping list page (thanks @fipwmaqzufheoxq92ebc)
|
||||||
- Shopping list items can now have their own Userfields (entity `shopping_list`), on the shopping list table those fields are rendered additionally to the product Userfields
|
- Shopping list items can now have their own Userfields (entity `shopping_list`), on the shopping list table those fields are rendered additionally to the product Userfields
|
||||||
- The print view is now configurable (new dialog before printing - option to hide header, group products by their product group, alternative list layout)
|
- The print view is now configurable (new dialog before printing - option to hide header, group products by their product group, alternative list layout)
|
||||||
|
|
@ -253,8 +253,8 @@
|
||||||
- `>=` greater or equal
|
- `>=` greater or equal
|
||||||
- `§` regular expression
|
- `§` regular expression
|
||||||
- `<value>` is the value to search for
|
- `<value>` is the value to search for
|
||||||
- New endpoint `/stock/shoppinglist/add-overdue-products` to add all currently in-stock but overdue products to a shopping list (thanks @m-byte)
|
- New endpoint `/stock/shoppinglist/add-overdue-products` to add all currently in stock but overdue products to a shopping list (thanks @m-byte)
|
||||||
- New endpoint `/stock/shoppinglist/add-expired-products` to add all currently in-stock but expired products to a shopping list
|
- New endpoint `/stock/shoppinglist/add-expired-products` to add all currently in stock but expired products to a shopping list
|
||||||
- New endpoints GET/POST/PUT `/users/{userId}/permissions` for the new user permissions feature mentioned above
|
- New endpoints GET/POST/PUT `/users/{userId}/permissions` for the new user permissions feature mentioned above
|
||||||
- New endpoint `/user` to get the currently authenticated user
|
- New endpoint `/user` to get the currently authenticated user
|
||||||
- New endpoint DELETE `/user/settings/{settingKey}` to delete a user setting
|
- New endpoint DELETE `/user/settings/{settingKey}` to delete a user setting
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
> ⚠️ PHP 8.0 (with SQLite 3.27.2+) is from now on the only supported runtime version.
|
> ⚠️ PHP 8.0 (with SQLite 3.27.2+) is from now on the only supported runtime version.
|
||||||
|
|
||||||
### New feature: Grocycode / label printer support
|
### New Feature: Grocycode / label printer support
|
||||||
|
|
||||||
#### (Own) Product/stock entry/chores/batteries labels/barcodes
|
#### (Own) Product/stock entry/chores/batteries labels/barcodes
|
||||||
- Print own labels/barcodes for products/stock entries/chores/batteries and then scan that code on every place a product/stock entry/chore/battery can be selected
|
- Print own labels/barcodes for products/stock entries/chores/batteries and then scan that code on every place a product/stock entry/chore/battery can be selected
|
||||||
|
|
@ -21,12 +21,12 @@
|
||||||
- https://github.com/grocy/grocy/tree/v3.1.0/docs/label-printing.md
|
- https://github.com/grocy/grocy/tree/v3.1.0/docs/label-printing.md
|
||||||
- (Thanks a lot @mistressofjellyfish for the initial work on this)
|
- (Thanks a lot @mistressofjellyfish for the initial work on this)
|
||||||
|
|
||||||
### New feature: Meal plan sections
|
### New Feature: Meal plan sections
|
||||||
- Split the meal plan into sections like Breakfast/Lunch/Dinner
|
- Split the meal plan into sections like Breakfast/Lunch/Dinner
|
||||||
- => New button "Configure sections" on the meal plan page to configure the sections (top right corner)
|
- => New button "Configure sections" on the meal plan page to configure the sections (top right corner)
|
||||||
- => Each meal plan entry can be assigned to a section
|
- => Each meal plan entry can be assigned to a section
|
||||||
|
|
||||||
### New feature: Shopping list thermal printer support
|
### New Feature: Shopping list thermal printer support
|
||||||
- The shopping list can now be printed on a thermal printer
|
- The shopping list can now be printed on a thermal printer
|
||||||
- The printer must be compatible to the `ESC/POS` protocol and needs to be locally attached or network reachable to/by the machine hosting Grocy (so the server)
|
- The printer must be compatible to the `ESC/POS` protocol and needs to be locally attached or network reachable to/by the machine hosting Grocy (so the server)
|
||||||
- See the new `TPRINTER*` `config.php` options to configure the printer connection and other options
|
- See the new `TPRINTER*` `config.php` options to configure the printer connection and other options
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
- Product barcodes are now enforced to be unique across products
|
- Product barcodes are now enforced to be unique across products
|
||||||
- On the stock overview page it's now also possible to search/filter by product barcodes (via the general search field)
|
- On the stock overview page it's now also possible to search/filter by product barcodes (via the general search field)
|
||||||
- The product picker on the consume and transfer page now only shows products which are currently in stock
|
- The product picker on the consume and transfer page now only shows products which are currently in stock
|
||||||
- Added a filter option to only show currently in-stock products on the stock overview and products list (master data) page
|
- Added a filter option to only show currently in stock products on the stock overview and products list (master data) page
|
||||||
- Added new columns on the stock overview page (hidden by default): Product description, product default location, parent product, product picture
|
- Added new columns on the stock overview page (hidden by default): Product description, product default location, parent product, product picture
|
||||||
- Added a new product option "Should not be frozen" (defaults to disabled and only visible when `FEATURE_FLAG_STOCK_PRODUCT_FREEZING` is enabled)
|
- Added a new product option "Should not be frozen" (defaults to disabled and only visible when `FEATURE_FLAG_STOCK_PRODUCT_FREEZING` is enabled)
|
||||||
- When enabled, on moving the product to a freezer location (so when freezing it), a corresponding warning will be shown
|
- When enabled, on moving the product to a freezer location (so when freezing it), a corresponding warning will be shown
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
- Fixed the form validation on the shopping list item page (thanks @Forceu)
|
- Fixed the form validation on the shopping list item page (thanks @Forceu)
|
||||||
- Fixed that when adding products to the shopping list from the stock overview page, the used quantity unit was always the products default purchase QU (and not the selected one)
|
- Fixed that when adding products to the shopping list from the stock overview page, the used quantity unit was always the products default purchase QU (and not the selected one)
|
||||||
- Fixed that the displayed last unit/total price was wrong when the used quantity unit was not the products stock QU
|
- Fixed that the displayed last unit/total price was wrong when the used quantity unit was not the products stock QU
|
||||||
- Fixed that the "Add as barcode to existing product" productpicker workflow did not work
|
- Fixed that the "Add as barcode to existing product" product picker workflow did not work
|
||||||
|
|
||||||
### Recipe improvements/fixes
|
### Recipe improvements/fixes
|
||||||
- Recipe printing improvements (thanks @Ape)
|
- Recipe printing improvements (thanks @Ape)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
- When adding (purchase) a product with "Default due days after freezing" set directly to a freezer location, the due date is now prefilled by that (instead of the normal "Default due days") (thanks @grahamc for the initial work on this)
|
- When adding (purchase) a product with "Default due days after freezing" set directly to a freezer location, the due date is now prefilled by that (instead of the normal "Default due days") (thanks @grahamc for the initial work on this)
|
||||||
- Chores can now be merged (new item in the context-/more-menu on the chores list page)
|
- Chores can now be merged (new item in the context-/more-menu on the chores list page)
|
||||||
- Fixed that "Label per unit" stock entry labels (on purchase) weren't unique per unit
|
- Fixed that "Label per unit" stock entry labels (on purchase) weren't unique per unit
|
||||||
- Fixed that the "Add as new product" productpicker workflow, started from the shopping list item form, always selected the default shopping list after finishing the flow
|
- Fixed that the "Add as new product" product picker workflow, started from the shopping list item form, always selected the default shopping list after finishing the flow
|
||||||
- Fixed that when undoing a product opened transaction and when the product has "Default due days after opened" set, the original due date wasn't restored
|
- Fixed that when undoing a product opened transaction and when the product has "Default due days after opened" set, the original due date wasn't restored
|
||||||
- Fixed that "Track date only"-chores were shown as overdue on the due day on the chores overview page
|
- Fixed that "Track date only"-chores were shown as overdue on the due day on the chores overview page
|
||||||
- Fixed that dropdown filters for tables maybe did not work after reordering columns
|
- Fixed that dropdown filters for tables maybe did not work after reordering columns
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
### New feature: Notes and Userfields for stock entries
|
### New Feature: Notes and Userfields for stock entries
|
||||||
|
|
||||||
- Stock entries can now have notes
|
- Stock entries can now have notes
|
||||||
- For example to distinguish between same, yet different products (e.g. having only a generic product "Chocolate" and note in that field what special one it is exactly this time - as an alternative to have sub products)
|
- For example to distinguish between same, yet different products (e.g. having only a generic product "Chocolate" and note in that field what special one it is exactly this time - as an alternative to have sub products)
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
- => Configure the desired Userfields for the entity `stock`
|
- => Configure the desired Userfields for the entity `stock`
|
||||||
- => Those Userfields are then visible on the same places as mentioned above for the built-in "Note" field
|
- => Those Userfields are then visible on the same places as mentioned above for the built-in "Note" field
|
||||||
|
|
||||||
### New feature: Recipes "Due score"
|
### New Feature: Recipes "Due score"
|
||||||
|
|
||||||
- A number (new column on the recipes page) which represents a score which is higher the more ingredients, of the corresponding recipe, currently in stock are due soon, overdue or already expired
|
- A number (new column on the recipes page) which represents a score which is higher the more ingredients, of the corresponding recipe, currently in stock are due soon, overdue or already expired
|
||||||
- Or in other words: A score to see which recipes to cook to not waste already overdue/expired or due soon products
|
- Or in other words: A score to see which recipes to cook to not waste already overdue/expired or due soon products
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
- => Instead the corresponding inverse conversion is now always created/updated/deleted automatically
|
- => Instead the corresponding inverse conversion is now always created/updated/deleted automatically
|
||||||
- New product option "Disable own stock" (defaults to disabled)
|
- New product option "Disable own stock" (defaults to disabled)
|
||||||
- When enabled, the corresponding 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 sub products)
|
- When enabled, the corresponding 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 sub products)
|
||||||
- The location content sheet can now optionally list also out of stock products (at the products default location, new checkbox "Show only in-stock products" at the top of the page, defaults to enabled)
|
- The location content sheet can now optionally list also out of stock products (at the products default location, new checkbox "Show only in stock products" at the top of the page, defaults to enabled)
|
||||||
- Added a location filter to the stock entries page
|
- Added a location filter to the stock entries page
|
||||||
- Added the product Grocycode as a (hidden by default) column to the products list (master data)
|
- Added the product Grocycode as a (hidden by default) column to the products list (master data)
|
||||||
- The price entered on the inventory page is now related to the selected quantity unit (like on the purchase page, was always related to the products stock QU before)
|
- The price entered on the inventory page is now related to the selected quantity unit (like on the purchase page, was always related to the products stock QU before)
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,16 @@
|
||||||
|
|
||||||
> _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._
|
> _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
|
- The product option "Factor purchase to stock quantity unit" was removed
|
||||||
- => Use normal product specific QU conversions instead, if needed
|
- => 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
|
- An existing "Factor purchase to stock quantity unit" was automatically migrated to a product specific QU conversion
|
||||||
|
|
||||||
### New feature: Stock reports
|
### New Feature: Stock reports
|
||||||
|
|
||||||
- New button "Reports" on the stock overview page
|
- New button "Reports" on the stock overview page
|
||||||
- The first report (more to come) "Spendings" makes it possible to explore (pie chart and table data) the total value spend by product or product group in any time range
|
- The first report (more to come) "Spendings" makes it possible to explore (pie chart and table data) the total value spend by product or product group in any time range
|
||||||
|
|
@ -31,11 +33,11 @@
|
||||||
- New product option "Auto reprint stock entry label"
|
- New product option "Auto reprint stock entry label"
|
||||||
- When enabled, auto-changing the due date of a stock entry (by opening/freezing/thawing and having corresponding default due days set) will reprint its label (only server side label printer WebHooks are supported)
|
- When enabled, auto-changing the due date of a stock entry (by opening/freezing/thawing and having corresponding default due days set) will reprint its label (only server side label printer WebHooks are supported)
|
||||||
- Defaults to disabled, so no changed behavior when not configured
|
- Defaults to disabled, so no changed behavior when not configured
|
||||||
- Added a new option "Reprint stock entry label" on the stock entry edit page (will print the correspondind stock entry label on save)
|
- Added a new option "Reprint stock entry label" on the stock entry edit page (will print the corresponding stock entry label on save)
|
||||||
- This option will be automatically set on changing the entry's due date
|
- This option will be automatically set on changing the entry's due date
|
||||||
- The product option "Quick consume amount" (the amount used for the "quick consume/open buttons" on the stock overview page) has been split into another option "Quick open amount", to be able to set different amounts for consume and open (defaults to the "Quick consume amount" per product, so no changed behavior when not configured)
|
- The product option "Quick consume amount" (the amount used for the "quick consume/open buttons" on the stock overview page) has been split into another option "Quick open amount", to be able to set different amounts for consume and open (defaults to the "Quick consume amount" per product, so no changed behavior when not configured)
|
||||||
- Changed that for the product's average and last price (and for the price history chart) stock transactions with an empty or `0` price are ignored
|
- Changed that for the product's average and last price (and for the price history chart) stock transactions with an empty or `0` price are ignored
|
||||||
- Added a filter option to only show currently out-of-stock products on the products list (master data) page
|
- Added a filter option to only show currently out of stock products on the products list (master data) page
|
||||||
- When clicking a product name on the products list (master data) or on the stock journal page, the product card will now be displayed (like on the stock overview page)
|
- When clicking a product name on the products list (master data) or on the stock journal page, the product card will now be displayed (like on the stock overview page)
|
||||||
- When using/scanning a product barcode and the purchase or inventory page, the barcode's note will now also be prefilled (if any)
|
- When using/scanning a product barcode and the purchase or inventory page, the barcode's note will now also be prefilled (if any)
|
||||||
- Each row on the stock journal now also has a context-/more menu for quick access to product related actions (the same as on the stock overview page)
|
- Each row on the stock journal now also has a context-/more menu for quick access to product related actions (the same as on the stock overview page)
|
||||||
|
|
@ -43,7 +45,7 @@
|
||||||
- Fixed that hiding the "Purchased date" column (table options) on the stock entries page didn't work
|
- Fixed that hiding the "Purchased date" column (table options) on the stock entries page didn't work
|
||||||
- Fixed that sorting by the "Value" and "Min. stock amount" columns on the stock overview page didn't work
|
- Fixed that sorting by the "Value" and "Min. stock amount" columns on the stock overview page didn't work
|
||||||
- Fixed that the consumed amount was wrong, when consuming multiple substituted subproducts at once and when multiple/different conversion factors were involved
|
- Fixed that the consumed amount was wrong, when consuming multiple substituted subproducts at once and when multiple/different conversion factors were involved
|
||||||
- Fixed that for a product's average price, only currently in-stock items were considered, not already consumed ones
|
- Fixed that for a product's average price, only currently in stock items were considered, not already consumed ones
|
||||||
- Fixed that when copying a product, some fields (like "Default consume location" or "Disable own stock) weren't copied along
|
- Fixed that when copying a product, some fields (like "Default consume location" or "Disable own stock) weren't copied along
|
||||||
- Fixed that the total product count on the stock overview page also included products with "Never show on stock overview" enabled
|
- Fixed that the total product count on the stock overview page also included products with "Never show on stock overview" enabled
|
||||||
|
|
||||||
|
|
|
||||||
19
changelog/71_4.0.1_2023-08-06.md
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
> 💡 PHP 8.2 is from now on (additionally to PHP 8.1) supported.
|
||||||
|
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- Fixed performance issues affecting all places where quantity unit conversions / prices are involved
|
||||||
|
- Fixed that the upgrade failed when having improperly defined product specific quantity unit conversions
|
||||||
|
- Fixed that edited stock entries were not considered in some cases (affecting the product's last price, average price, the price history and the stock reports)
|
||||||
|
|
||||||
|
### Shopping list
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
- Fixed that the meal plan did initially not display the current week when the settings `MEAL_PLAN_FIRST_DAY_OF_WEEK` and `CALENDAR_FIRST_DAY_OF_WEEK` were set to different values
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
- Fixed performance issues on the endpoint `/stock/products/{productId}`
|
||||||
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
|
||||||
12
changelog/73_4.0.3_2023-09-02.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- Performance improvements related to the stock overview page / displaying a product card
|
||||||
|
- Performance improvements related to consuming products (thanks @alkuzman)
|
||||||
|
|
||||||
|
### Userfields
|
||||||
|
|
||||||
|
- New Userfield type "Number (currency)", just like the type "Number (decimal)", but it will render the value according to / with the configured currency
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Performance improvements related to table (layout) loading handling
|
||||||
43
changelog/74_4.1.0_2024-02-09.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
> 💡 PHP 8.3 is from now on (additionally to PHP 8.2) supported.
|
||||||
|
>
|
||||||
|
> ⚠️ PHP 8.1 is no longer supported.
|
||||||
|
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- Fixed that the location dropdown on the consume page contained the same location multiple times if there are currently stock entries at multiple locations of the corresponding product
|
||||||
|
- Fixed that the status filter "_n_ products are overdue" on the stock overview page also counted/included stock entries due today or tomorrow
|
||||||
|
- Fixed that the stock report "Spendings" did not take products without an assigned product group into account (thanks @Torqu3Wr3nch for the initial work on this)
|
||||||
|
- Fixed that the success message after opening a stock entry on the stock entries page displayed always an amount of `1` instead of the actual amount opened
|
||||||
|
- Fixed that the "Consume this stock entry as spoiled" context menu action on the stock entries page consumed always an amount of `1` instead of the whole stock entry
|
||||||
|
|
||||||
|
### Recipes
|
||||||
|
|
||||||
|
- Fixed that copying recipes with special characters in the name was not possible
|
||||||
|
|
||||||
|
### Meal plan
|
||||||
|
|
||||||
|
- Fixed that the meal plan page was broken after deleting all meal plan items of a week
|
||||||
|
|
||||||
|
### Calendar
|
||||||
|
|
||||||
|
- The different event types (due products, chores, tasks and so on) can now have different colors
|
||||||
|
- => New button "Configure colors" on the calendar page to configure these colors (top right corner)
|
||||||
|
|
||||||
|
### Tasks
|
||||||
|
|
||||||
|
- Added a new table filter for categories (thanks @geoffwright240 for the initial work on this)
|
||||||
|
|
||||||
|
### Userfields
|
||||||
|
|
||||||
|
- Fixed that when having a userfield of type "Select list (multiple items can be selected)" and selecting no item, editing of the corresponding form was broken
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Night mode is now also used on the login page if that's the system preferred color scheme (generally if night mode is on or not is based on user settings and before logging in no user context is available)
|
||||||
|
- Optimized sidebar icon spacing (thanks @chris-thorn)
|
||||||
|
- Fixed that file uploads (product pictures and so on) didn't work for files where the file name contains multiple spaces
|
||||||
|
- Fixed that some dialogs were not properly (too small) displayed (mostly affecting Firefox >= 121)
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
- Optimized that the endpoints `GET /objects/{entity}` and `GET /objects/{entity}/{objectId}` now also return Userfields for the entity `stock`
|
||||||
26
changelog/75_4.2.0_2024-03-15.md
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- When using/scanning a stock entry Grocycode on the transfer page, the "Use specific stock item" dropdown (and "From location") is now also prefilled accordingly
|
||||||
|
- Fixed that for the product's last price stock transactions with an empty or `0` price weren't ignored
|
||||||
|
- Fixed that when copying a product, the field "Move on open" wasn't copied along
|
||||||
|
|
||||||
|
### Shopping list
|
||||||
|
|
||||||
|
- The shopping lists dropdown on the shopping list page now also shows the number of items on the corresponding shopping list
|
||||||
|
|
||||||
|
### Recipes
|
||||||
|
|
||||||
|
- Optimized that when creating a recipe, the desired serving amount is now initially prefilled by the recipe's base serving amount
|
||||||
|
|
||||||
|
### Batteries
|
||||||
|
|
||||||
|
- It's now possible to track any addtional info on a battery charge cycle by using Userfields (thanks @TheDodger)
|
||||||
|
- => Configure the desired Userfields for the entity `battery_charge_cycles`
|
||||||
|
- => The on a battery charge cycle tracking entered information is then visible on the corresponding battery charge cycle journal entry
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Optimized that file uploads are no longer completely buffered in memory before writing them to disk (thanks @bbx0)
|
||||||
|
- Optimized top right corner menus icon spacing (thanks @TheDodger for the initial work on this)
|
||||||
|
- Fixed again that some dialogs were not properly (too small) displayed (this time mostly affecting Chrome/Edge)
|
||||||
|
- Fixed that table states (visible columns, sorting, column order and so on) could be reset to default after not accessing/using the corresponding page for a certain amount of time
|
||||||
28
changelog/76_4.3.0_2024-12-23.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- Optimized form validation (max amount checks) related to unit conversion with a lot of decimal places on the consume and transfer page
|
||||||
|
- Optimized that the stock report "Spendings" now excludes self produced products (thanks @danielr18 for the initial work on this)
|
||||||
|
- Fixed that when copying a product, the field "Treat opened as out of stock" wasn't copied along (thanks @TheDodger)
|
||||||
|
- Fixed that the product groups filter on the master data products page used a contains search instead of an exact search
|
||||||
|
- Fixed that Scan Mode on the purchase and consume page didn't work (not all fields were properly populated) when using/scanning a product Grocycode
|
||||||
|
|
||||||
|
### Shopping list
|
||||||
|
|
||||||
|
- Fixed that when printing a shoppping list, the table/list wasn't sorted (will now be sorted alphabetically by the product name of the corresponding list item)
|
||||||
|
- Fixed that when deleting a shopping list item and marking another one as done while not reloading the page in-between, the deleted item reappeared (was only a visual problem, there was no problem on deleting the item on the backend / in the database)
|
||||||
|
|
||||||
|
### Recipes
|
||||||
|
|
||||||
|
- When self producing a product ("Produces product" recipe option) the name of the recipe is now added to the note field of the created stock entry
|
||||||
|
- Fixed that when `FEATURE_FLAG_STOCK_STOCK` was set to `false`, the "Put missing products on shopping list"-button was not visible
|
||||||
|
- Fixed that scanning a product barcode on the recipe ingredient edit page didn't work
|
||||||
|
- Fixed that the recipe edit button on the recipes page gallery view didn't work
|
||||||
|
|
||||||
|
### Userfields
|
||||||
|
|
||||||
|
- Userentity tables (custom objects / lists) now also have the table options icon (top left corner eye icon, to e.g. add a grouping condition)
|
||||||
|
- Userfield names can now also contain underscores
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
- Optimized that uploading files where the file name contains non-ASCII characters is now also possible
|
||||||
86
changelog/77_4.4.0_2025-01-24.md
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
### New Feature: External Barcode Lookups as a product picker workflow + a built-in Plugin for Open Food Facts
|
||||||
|
|
||||||
|
- Added a new product picker workflow "External barcode lookup"
|
||||||
|
- This executes the configured barcode lookup plugin with the given barcode
|
||||||
|
- If the lookup was successful, the product edit page of the created product is displayed where the product setup can be completed (if required)
|
||||||
|
- After that, the transaction is continued with that product as usual
|
||||||
|
- A plugin for [Open Food Facts](https://world.openfoodfacts.org/) is now included and used by default (see the `config.php` option `STOCK_BARCODE_LOOKUP_PLUGIN` and maybe change it as needed)
|
||||||
|
- The product name and image (and of course the barcode itself) are taken over from Open Food Facts to the product being looked up
|
||||||
|
- => Quick video demo (using a Barcode Laser Scanner): https://www.youtube.com/watch?v=-moXPA-VvGc
|
||||||
|
- => Quick video demo (using Browser Camera Barcode Scanning): https://www.youtube.com/watch?v=veezFX4X1JU
|
||||||
|
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- Added a new stock setting (top right corner settings menu) "Show all out of stock products" to optionally also show all out of stock products on the stock overview page (defaults to disabled, so no changed behavior when not configured)
|
||||||
|
- By default the stock overview page lists all products which are currently in stock or below their min. stock amount
|
||||||
|
- When this new setting is enabled, all (active) products are always shown
|
||||||
|
- Added a new product option "Can't be opened"
|
||||||
|
- When enabled the product open functionality for that product is disabled
|
||||||
|
- Defaults to disabled, so no changed behavior when not configured
|
||||||
|
- Added a new product option "Default purchase price type"
|
||||||
|
- Can be used to set the default price type (Unit price / Total price) on the purchase page per product
|
||||||
|
- Previously "Unit price" was the default on purchase and the selection was not saved and not reset when selecting another product, means the price type selection was retained when doing multiple purchase transactions in one go
|
||||||
|
- The default for the new product option is "Unspecified" which keeps the previous behavior
|
||||||
|
- When products are automatically added to the shopping list (e.g. by the "below defined min. stock amount"-functionality or when adding missing recipe ingredients) the product's "Default quantity unit purchase" is now used (instead of the product's "Quantity unit stock")
|
||||||
|
- Product barcode matching is now case-insensitive
|
||||||
|
- Added a new column "Product picture" on the products list (master data) page (hidden by default)
|
||||||
|
- Optimized that when navigation between the different "Group by"-variants on the stock report "Spendings", the selected date range now remains persistent
|
||||||
|
- Added a new "Presets for new products" stock setting for the "Default stock entry label" option of new products
|
||||||
|
- Added a trendline to the price history chart (product card)
|
||||||
|
- Added a "Add to shopping list"-button on the product card
|
||||||
|
- Optimized that when moving a product to a freezer location (so when freezing it) the due date will no longer be replaced when the product option "Default due days after freezing" is set to `0`
|
||||||
|
- The "Decimal places allowed" stock settings now have an upper limit of 10 (since such a high number makes not so much sense in reality and causes form validation problems)
|
||||||
|
- Fixed that a once set quantity unit on a product barcode could not be removed on edit
|
||||||
|
- Fixed that when consuming a specific stock entry which is opened, and which originated from a before partly opened stock entry, the unopened one was wrongly consumed instead
|
||||||
|
|
||||||
|
### Shopping list
|
||||||
|
|
||||||
|
- Added a new shopping list setting (top right corner settings menu) "Round up quantity amounts to the nearest whole number"
|
||||||
|
- When enabled, all quantity amounts on the shopping list are always displayed rounded up to the nearest whole number
|
||||||
|
- Defaults to disabled, so no changed behavior when not configured
|
||||||
|
|
||||||
|
### Recipes
|
||||||
|
|
||||||
|
- Consuming a recipe is now also possible when not all needed ingredients are currently in stock (the in stock amount, if any, of the corresponding ingredient will be consumed in that case)
|
||||||
|
- For in stock ingredients, the amount actually in stock is now displayed next to the hint "Enough in stock"
|
||||||
|
- Added a new recipe ingredient option "Round up quantity amounts to the nearest whole number"
|
||||||
|
- When enabled, resulting quantity amounts (after scaling according the desired serving amount) are always rounded up to the nearest whole number
|
||||||
|
- Defaults to disabled, so no changed behavior when not configured
|
||||||
|
- Optimizations/changes when adding missing recipe ingredients to the shopping list:
|
||||||
|
- When the ingredient option "Only check if any amount is in stock" is enabled and when no corresponding unit conversion exists, the amount/unit is now taken "as is" (as defined in the recipe ingredient) into the created shopping list item
|
||||||
|
- The shopping list item no longer gets a note "Added for recipe" set and the ingredient note is no longer appended
|
||||||
|
- When the corresponding product is already on the shopping list, the amount of the existing item is incremented instead of creating a new shopping list item
|
||||||
|
- When a new shopping list item is created, the product's "Default quantity unit purchase" is now used (instead of the product's "Quantity unit stock")
|
||||||
|
- When no price information is available for at least one ingredient, a red exclamation mark is now displayed next to the recipe total cost information
|
||||||
|
- When clicking a recipe ingredient / product name, the product card will now be opened like on many other places throughout Grocy
|
||||||
|
- Fixed that calories/costs of recipe ingredients were wrong when the ingredient option "Only check if any amount is in stock" was set and the on the ingredient used quantity unit was different from the product's QU stock
|
||||||
|
- Fixed that multi-nested recipes (at least 3 levels of "included recipes") resulted in wrong amounts/costs/calories calculated for the ingredients originating in those nested recipes (also affected the meal plan)
|
||||||
|
|
||||||
|
### Meal plan
|
||||||
|
|
||||||
|
- Fixed that amounts/costs/calories were wrong for recipes which had at least 2 levels of "included recipes"
|
||||||
|
|
||||||
|
### Chores
|
||||||
|
|
||||||
|
- Added a possibility to see if a scheduled chore was tracked/done on time or not:
|
||||||
|
- When tracking chores, the "Next estimated tracking date" (so the current scheduled time) is now also stored in the corresponding chore journal entry and displayed in a new column "Scheduled tracking time" on the chores journal page
|
||||||
|
- When the "Tracked time" is later than the "Scheduled tracking time", the corresponding chore journal entry is now highlighted in red on the chores journal page
|
||||||
|
- Added a new column "Time of tracking" on the chores journal page (displays the time when the tracking actually happened, hidden by default)
|
||||||
|
- Added a new option "Swap track next schedule / track now buttons" (chores settings / top right corner settings menu) to swap the "Track next chore schedule" / "Track chore execution now" buttons/menu items on the chores overview page (defaults to disabled, so no changed behavior when not configured)
|
||||||
|
|
||||||
|
### Userfields
|
||||||
|
|
||||||
|
- Optimized Userfields of type "Checkbox"
|
||||||
|
- When it's a mandatory Userfield, the initial state of the corresponding checkbox is now indeterminate, means it's now also possible to actively not check it (previously mandatory meant the checkbox has to be set)
|
||||||
|
- Fixed that Userfield default values were not initialized for the `stock` entity (so affecting the purchase and inventory page)
|
||||||
|
- Fixed that uploading bigger or multiple files (so when the upload usually takes a little longer) didn't work (Userfield type "File")
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Optimized nested modal dialogs:
|
||||||
|
- Nested dialogs are now no longer displayed "in each other" and instead "on top of each other"
|
||||||
|
- Dialogs can now be closed with the `ESC` key on the keyboard
|
||||||
|
- There is no longer a close button at the bottom (outside of the displayed `iframe`) and instead one at the top right corner of the dialog
|
||||||
|
- Wide dialogs (e.g. all showing a table, like showing stock entries of a product from the stock overview more/context menu per line) now use the full screen width
|
||||||
|
- Improved the handling of the initial field focus on form pages
|
||||||
|
- The previously manually necessary update steps (e.g. emptying the `data/viewcache` directory) are now fully automated, so no need to do this manually after this and future updates
|
||||||
21
changelog/78_4.4.1_2025-01-31.md
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- Fixed that the built-in Open Food Facts external barcode lookup plugin used the staging environment of the Open Food Facts API instead of the production one
|
||||||
|
- Fixed that the product group filter on the products page (master data) didn't work when the selected product group contained special characters
|
||||||
|
- Fixed that the product filter on the stock journal summary page didn't work when the selected product contained special characters
|
||||||
|
|
||||||
|
### Shopping list
|
||||||
|
|
||||||
|
- Optimized that non-number amounts are now prevented on database level (was infamously a problem when using specific community contributed alternative clients)
|
||||||
|
|
||||||
|
### Tasks
|
||||||
|
|
||||||
|
- Fixed that set table filters were not applied after editing or adding a task
|
||||||
|
|
||||||
|
### Userfields
|
||||||
|
|
||||||
|
- Fixed that saving Userfields of type "Select list (multiple items can be selected)" did not work
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Optimized that when navigating between form input fields via the keyboard (`TAB`) there was an unwanted delay at some places
|
||||||
28
changelog/79_4.4.2_2025-02-28.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- Optimized that the built-in Open Food Facts external barcode lookup plugin now uses the localized product name (if provided by the Open Food Facts API, based on the set Grocy language of the current user)
|
||||||
|
- Fixed that the product filter on the stock entires page didn't work when the product column was reordered / not the second one
|
||||||
|
|
||||||
|
### Shopping list
|
||||||
|
|
||||||
|
- When the shopping list setting (top right corner settings menu) "Round up quantity amounts to the nearest whole number" is enabled, the "Last price (Total)" of each shopping list item and the total value of the shopping list are now also scaled up accordingly
|
||||||
|
- The print options (show header, layout type etc.) are now saved (as user settings, so global defaults can also defined in `config.php` as usual)
|
||||||
|
|
||||||
|
### Userfields
|
||||||
|
|
||||||
|
- Fixed that saving Userfields of type "Link (with title)" did not work
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Fixed that most dialogs didn't work when hosting Grocy "embedded" in an `iframe` (affecting e.g. the [Home Assistant Add-on](https://github.com/hassio-addons/addon-grocy))
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
- Exposed the `permission_hierarchy` entity (read only, => `GET /objects/permission_hierarchy`) to provide a permission name / id mapping
|
||||||
|
|
||||||
|
### Other
|
||||||
|
- A quick reminder about official native Grocy app experiences:
|
||||||
|
- Grocy's web frontend is responsive and an "installable web app" ([PWA](https://en.wikipedia.org/wiki/Progressive_web_app), without providing any offline usage capabilities), that provides a pretty native mobile app-like experience without the need for additional tools
|
||||||
|
- => Quick video demo on Android/Firefox: https://www.youtube.com/watch?v=L38drVZfwHs
|
||||||
|
- => Quick video demo on Android/Chrome: https://www.youtube.com/watch?v=rjLdXUFDNuk
|
||||||
|
- [Grocy Desktop](https://github.com/grocy/grocy-desktop) is a way to run Grocy without having to manage a webserver, just like a normal (Windows) desktop application - available as a [classic `.msi` installation package](https://releases.grocy.info/latest-desktop) or as a [Microsoft Store App](https://apps.microsoft.com/detail/9NWB1TRNNKSF)
|
||||||
16
changelog/80_4.5.0_2025-03-28.md
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- Optimizations in the built-in Open Food Facts external barcode lookup plugin:
|
||||||
|
- A provided but empty localized product name is now ignored
|
||||||
|
- Non-ASCII characters in product names are now ignored (e.g. line breaks caused problems)
|
||||||
|
- Optimized that when an external barcode lookup plugin returned an image URL with query parameters, an invalid picture (file name) was added to the created product
|
||||||
|
- Added a new column "Default store" on the stock overview page (hidden by default)
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Optimized that the default font of the web frontend is now also used for non-latin characters
|
||||||
|
- Label printer WebHooks now include a new property/field `details` (that's the full product/chore/battery/etc. object)
|
||||||
|
- And also `stock_entry` (containing the full stock entry object) when printing a stock entry label
|
||||||
|
- The component used (so far [Quagga2](https://github.com/ericblade/quagga2)) that powers the camera barcode scanner was replaced by [ZXing](https://github.com/zxing-js/library) which should perform overall better and it also supports 2D barcodes (QRCode/DataMatrix) (thanks @gergof)
|
||||||
|
- New translations: (thanks all the translators)
|
||||||
|
- Bulgarian (demo available at <https://bg.demo.grocy.info>)
|
||||||
36
changelog/81_4.6.0_2026-03-06.md
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
> ⚠️ PHP 8.5 (with SQLite 3.40+) is from now on the only supported runtime version.
|
||||||
|
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- Optimized product definition quantity unit handling:
|
||||||
|
- As long as a product was not once in stock, the product options "Default quantity unit purchase", "Default quantity unit consume" and "Quantity unit for prices" can now be changed to any other unit
|
||||||
|
- When necessary (means when no default quantity unit conversions apply), "1:1" product specific quantity unit conversion between the product's QU stock and the corresponding other unit will now be created automatically after editing a product (like already done when initially creating a product with different unit definitions)
|
||||||
|
- For convenience, when changing a product's QU stock and when all other unit properties ("Default quantity unit purchase" etc.) are the same, they will now be changed in tandem (like already done when creating a new product and initially setting the product's QU stock)
|
||||||
|
- (This should drastically improve the workflow of completing a product setup looked up via an external barcode lookup plugin)
|
||||||
|
- Optimized the line plot markers color of the price history chart (product card) (thanks @DeepCoreSystem)
|
||||||
|
- External barcode lookup plugin optimizations:
|
||||||
|
- When an image URL without a file extension is returned, the file extension is now determined by the Content-Type header (if any) (thanks @jordy-u for the idea)
|
||||||
|
- Data URLs for images are now supported (`data:image/png;base64,xxxx`) (thanks @GammaC0de)
|
||||||
|
- Fixed that German Umlauts and other special characters were removed from product names when looking up a barcode via the built-in Open Food Facts external barcode lookup plugin
|
||||||
|
- Fixed that when using/scanning a barcode on the purchase page with a note attached (which prefills the note field) and when manually selecting another product afterwards, the note of the previously used barcode was incorrectly prefilled again
|
||||||
|
- Fixed that the "next input focus handling" (jumping to the next input after entering a value) didn't work at some places (e.g. after entering a purchased date on the purchase page)
|
||||||
|
- Fixed that changing the stock setting "Due soon days" wasn't saved/applied
|
||||||
|
- Fixed that "Reprint stock entry label" on the stock entry edit page didn't actually print the corresponding label
|
||||||
|
|
||||||
|
### Shopping list
|
||||||
|
|
||||||
|
- An amount of `0` is now allowed for shopping list items (just a convenience optimization, it was already possible to leave the amount field empty which implicitly resulted in an amount of `0`)
|
||||||
|
- Fixed that the "Add all list items to stock" workflow closed the dialog after every item instead only after the last one was added
|
||||||
|
|
||||||
|
### Chores
|
||||||
|
|
||||||
|
- Fixed that changing the chore setting "Due soon days" wasn't saved/applied
|
||||||
|
|
||||||
|
### Userfields
|
||||||
|
|
||||||
|
- Fixed that the corresponding form was broken when using a `%` in an Userfield caption (only affected numeric and date-time Userfields)
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Added a workaround for different SQL errors when running Grocy on FreeBSD and SQLite 3.41+
|
||||||
|
- Fixed that the date input shorthand `[+/-]n[d/m/y]` didn't work when the value length was >= 4 (e.g. `+10d`)
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
> ❗ xxxImportant upgrade informationXXX
|
> ❗ xxxImportant upgrade informationXXX
|
||||||
|
|
||||||
### New feature: xxxx
|
> 💡 xxxMinor upgrade informationXXX
|
||||||
|
|
||||||
|
### New Feature: xxxx
|
||||||
|
|
||||||
- xxx
|
- xxx
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
{
|
{
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.1",
|
"php": "8.5.*",
|
||||||
"slim/slim": "^4.0",
|
|
||||||
"slim/psr7": "^1.0",
|
|
||||||
"slim/http": "^1.0",
|
|
||||||
"php-di/php-di": "^7.0.3",
|
|
||||||
"berrnd/slim-blade-view": "^1.0.0",
|
|
||||||
"morris/lessql": "dev-php81",
|
|
||||||
"gettext/gettext": "dev-php81",
|
|
||||||
"eluceo/ical": "^2.2.0",
|
"eluceo/ical": "^2.2.0",
|
||||||
"erusev/parsedown": "^1.7",
|
"erusev/parsedown": "^1.7",
|
||||||
"gumlet/php-image-resize": "^2.0",
|
|
||||||
"ezyang/htmlpurifier": "^4.13",
|
"ezyang/htmlpurifier": "^4.13",
|
||||||
"interficieis/php-barcode": "^2.0.2",
|
"gettext/gettext": "dev-4.x-fork",
|
||||||
|
"gumlet/php-image-resize": "^2.0",
|
||||||
"guzzlehttp/guzzle": "^7.0",
|
"guzzlehttp/guzzle": "^7.0",
|
||||||
"mike42/escpos-php": "^3.0"
|
"interficieis/php-barcode": "^2.0.2",
|
||||||
|
"mike42/escpos-php": "^4.0",
|
||||||
|
"morris/lessql": "dev-master-fork",
|
||||||
|
"php-di/php-di": "^7.0.3",
|
||||||
|
"slim/http": "^1.0",
|
||||||
|
"slim/psr7": "^1.0",
|
||||||
|
"slim/slim": "^4.0",
|
||||||
|
"webman/blade": "^1.5",
|
||||||
|
"ramsey/uuid": "^4.9"
|
||||||
},
|
},
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
|
|
@ -23,7 +24,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "vcs",
|
"type": "vcs",
|
||||||
"url": "https://github.com/berrnd/Gettext"
|
"url": "https://github.com/berrnd/php-gettext"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
|
@ -39,6 +40,7 @@
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"vendor-dir": "packages",
|
"vendor-dir": "packages",
|
||||||
"platform-check": false
|
"platform-check": false,
|
||||||
|
"optimize-autoloader": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1861
composer.lock
generated
|
|
@ -14,8 +14,9 @@
|
||||||
// The settings defined here below
|
// The settings defined here below
|
||||||
|
|
||||||
// Either "production", "dev", "demo" or "prerelease"
|
// Either "production", "dev", "demo" or "prerelease"
|
||||||
// When not "production", authentication will be disabled and
|
// When not "production", the application will work in a demo mode which means
|
||||||
// demo data will be populated during database migrations
|
// authentication is disabled and some demo data will be generated during the database schema migration
|
||||||
|
// (pass the query parameter "nodemodata", e.g. https://grocy.example.com/?nodemodata to skip that)
|
||||||
Setting('MODE', 'production');
|
Setting('MODE', 'production');
|
||||||
|
|
||||||
// The directory name of one of the available localization folders
|
// The directory name of one of the available localization folders
|
||||||
|
|
@ -63,9 +64,10 @@ Setting('BASE_PATH', '');
|
||||||
Setting('BASE_URL', '/');
|
Setting('BASE_URL', '/');
|
||||||
|
|
||||||
// The plugin to use for external barcode lookups,
|
// The plugin to use for external barcode lookups,
|
||||||
// must be the filename (folder /data/plugins) without the .php extension,
|
// must be the filename (folder "/plugins" for built-in plugins or "/data/plugins" for user plugins) without the .php extension,
|
||||||
// see /data/plugins/DemoBarcodeLookupPlugin.php for an example implementation
|
// see /plugins/DemoBarcodeLookupPlugin.php for a commented example implementation
|
||||||
Setting('STOCK_BARCODE_LOOKUP_PLUGIN', 'DemoBarcodeLookupPlugin');
|
// Leave empty to disable external barcode lookups
|
||||||
|
Setting('STOCK_BARCODE_LOOKUP_PLUGIN', 'OpenFoodFactsBarcodeLookupPlugin');
|
||||||
|
|
||||||
// If, however, your webserver does not support URL rewriting, set this to true
|
// If, however, your webserver does not support URL rewriting, set this to true
|
||||||
Setting('DISABLE_URL_REWRITING', false);
|
Setting('DISABLE_URL_REWRITING', false);
|
||||||
|
|
@ -101,14 +103,14 @@ Setting('LDAP_UID_ATTR', ''); // Windows AD: "sAMAccountName", OpenLDAP: "uid",
|
||||||
Setting('DEFAULT_PERMISSIONS', ['ADMIN']);
|
Setting('DEFAULT_PERMISSIONS', ['ADMIN']);
|
||||||
|
|
||||||
// "1D" (=> Code128) or "2D" (=> DataMatrix)
|
// "1D" (=> Code128) or "2D" (=> DataMatrix)
|
||||||
Setting('GROCYCODE_TYPE', '1D');
|
Setting('GROCYCODE_TYPE', '2D');
|
||||||
|
|
||||||
|
|
||||||
// Label printer settings
|
// Label printer settings
|
||||||
Setting('LABEL_PRINTER_WEBHOOK', ''); // The URI that Grocy will POST to when asked to print a label
|
Setting('LABEL_PRINTER_WEBHOOK', ''); // The URI that Grocy will POST to when asked to print a label
|
||||||
Setting('LABEL_PRINTER_RUN_SERVER', true); // Whether the webhook will be called server- or client-side
|
Setting('LABEL_PRINTER_RUN_SERVER', true); // Whether the webhook will be called server- or client-side
|
||||||
Setting('LABEL_PRINTER_PARAMS', ['font_family' => 'Source Sans Pro (Regular)']); // Additional parameters supplied to the webhook
|
Setting('LABEL_PRINTER_PARAMS', ['font_family' => 'Source Sans Pro (Regular)']); // Additional parameters supplied to the webhook
|
||||||
Setting('LABEL_PRINTER_HOOK_JSON', false); // TRUE to use JSON or FALSE to use normal POST request variables
|
Setting('LABEL_PRINTER_HOOK_JSON', true); // TRUE to use JSON or FALSE to use normal POST request variables
|
||||||
|
|
||||||
|
|
||||||
// Thermal printer options
|
// Thermal printer options
|
||||||
|
|
@ -178,6 +180,7 @@ DefaultUserSetting('product_presets_product_group_id', -1); // Default product g
|
||||||
DefaultUserSetting('product_presets_qu_id', -1); // Default quantity unit id for new products (-1 means no quantity unit is preset)
|
DefaultUserSetting('product_presets_qu_id', -1); // Default quantity unit id for new products (-1 means no quantity unit is preset)
|
||||||
DefaultUserSetting('product_presets_default_due_days', 0); // Default due days for new products (-1 means that the product will be never overdue)
|
DefaultUserSetting('product_presets_default_due_days', 0); // Default due days for new products (-1 means that the product will be never overdue)
|
||||||
DefaultUserSetting('product_presets_treat_opened_as_out_of_stock', true); // Default "Treat opened as out of stock" option for new products
|
DefaultUserSetting('product_presets_treat_opened_as_out_of_stock', true); // Default "Treat opened as out of stock" option for new products
|
||||||
|
DefaultUserSetting('product_presets_default_stock_label_type', 0); // "Default stock entry label" option for new products (0 = No label, 1 = Single Label, 2 = Label per unit)
|
||||||
DefaultUserSetting('stock_decimal_places_amounts', 4); // Default decimal places allowed for amounts
|
DefaultUserSetting('stock_decimal_places_amounts', 4); // Default decimal places allowed for amounts
|
||||||
DefaultUserSetting('stock_decimal_places_prices_input', 2); // Default decimal places allowed for prices (input)
|
DefaultUserSetting('stock_decimal_places_prices_input', 2); // Default decimal places allowed for prices (input)
|
||||||
DefaultUserSetting('stock_decimal_places_prices_display', 2); // Default decimal places allowed for prices (display)
|
DefaultUserSetting('stock_decimal_places_prices_display', 2); // Default decimal places allowed for prices (display)
|
||||||
|
|
@ -189,14 +192,19 @@ DefaultUserSetting('stock_default_consume_amount_use_quick_consume_amount', fals
|
||||||
DefaultUserSetting('scan_mode_consume_enabled', false); // If scan mode on the consume page is enabled
|
DefaultUserSetting('scan_mode_consume_enabled', false); // If scan mode on the consume page is enabled
|
||||||
DefaultUserSetting('scan_mode_purchase_enabled', false); // If scan mode on the purchase page is enabled
|
DefaultUserSetting('scan_mode_purchase_enabled', false); // If scan mode on the purchase page is enabled
|
||||||
DefaultUserSetting('show_icon_on_stock_overview_page_when_product_is_on_shopping_list', true); // When enabled, an icon is shown on the stock overview page (next to the product name) when the prodcut is currently on a shopping list
|
DefaultUserSetting('show_icon_on_stock_overview_page_when_product_is_on_shopping_list', true); // When enabled, an icon is shown on the stock overview page (next to the product name) when the prodcut is currently on a shopping list
|
||||||
|
DefaultUserSetting('stock_overview_show_all_out_of_stock_products', false); // By default the stock overview page lists all products which are currently in stock or below their min. stock amount - when this is enabled, all (active) products are always shown
|
||||||
DefaultUserSetting('show_purchased_date_on_purchase', false); // Whether the purchased date should be editable on purchase (defaults to today otherwise)
|
DefaultUserSetting('show_purchased_date_on_purchase', false); // Whether the purchased date should be editable on purchase (defaults to today otherwise)
|
||||||
DefaultUserSetting('show_warning_on_purchase_when_due_date_is_earlier_than_next', true); // Show a warning on purchase when the due date of the purchased product is earlier than the next due date in stock
|
DefaultUserSetting('show_warning_on_purchase_when_due_date_is_earlier_than_next', true); // Show a warning on purchase when the due date of the purchased product is earlier than the next due date in stock
|
||||||
|
|
||||||
// Shopping list settings
|
// Shopping list settings
|
||||||
DefaultUserSetting('shopping_list_to_stock_workflow_auto_submit_when_prefilled', false); // Automatically do the booking using the last price and the amount of the shopping list item, if the product has "Default due days" set
|
DefaultUserSetting('shopping_list_to_stock_workflow_auto_submit_when_prefilled', false); // Automatically do the booking using the last price and the amount of the shopping list item, if the product has "Default due days" set
|
||||||
DefaultUserSetting('shopping_list_show_calendar', false); // When enabled, a small (month view) calendar will be shown on the shopping list page
|
DefaultUserSetting('shopping_list_show_calendar', false); // When enabled, a small (month view) calendar will be shown on the shopping list page
|
||||||
|
DefaultUserSetting('shopping_list_round_up', false); // When enabled, all quantity amounts on the shopping list are always displayed rounded up to the nearest whole number
|
||||||
DefaultUserSetting('shopping_list_auto_add_below_min_stock_amount', false); // If products should be automatically added to the shopping list when they are below their min. stock amount
|
DefaultUserSetting('shopping_list_auto_add_below_min_stock_amount', false); // If products should be automatically added to the shopping list when they are below their min. stock amount
|
||||||
DefaultUserSetting('shopping_list_auto_add_below_min_stock_amount_list_id', 1); // When the above setting is enabled, the id of the shopping list to which the products will be added
|
DefaultUserSetting('shopping_list_auto_add_below_min_stock_amount_list_id', 1); // When the above setting is enabled, the id of the shopping list to which the products will be added
|
||||||
|
DefaultUserSetting('shopping_list_print_show_header', true); // Default for the shopping list print option "Show header"
|
||||||
|
DefaultUserSetting('shopping_list_print_group_by_product_group', true); // Default for the shopping list print option "Group by product group"
|
||||||
|
DefaultUserSetting('shopping_list_print_layout_type', 'table'); // Default for the shopping list print option "Layout type" (table or list)
|
||||||
|
|
||||||
// Recipe settings
|
// Recipe settings
|
||||||
DefaultUserSetting('recipe_ingredients_group_by_product_group', false); // Group recipe ingredients by their product group
|
DefaultUserSetting('recipe_ingredients_group_by_product_group', false); // Group recipe ingredients by their product group
|
||||||
|
|
@ -205,6 +213,7 @@ DefaultUserSetting('recipes_show_ingredient_checkbox', false); // When enabled,
|
||||||
|
|
||||||
// Chores settings
|
// Chores settings
|
||||||
DefaultUserSetting('chores_due_soon_days', 5); // The "due soon" days
|
DefaultUserSetting('chores_due_soon_days', 5); // The "due soon" days
|
||||||
|
DefaultUserSetting('chores_overview_swap_tracking_buttons', false); // When enabled, the "Track next chore schedule" and "Track chore execution now" buttons/menu items are swapped
|
||||||
|
|
||||||
// Batteries settings
|
// Batteries settings
|
||||||
DefaultUserSetting('batteries_due_soon_days', 5); // The "due soon" days
|
DefaultUserSetting('batteries_due_soon_days', 5); // The "due soon" days
|
||||||
|
|
@ -212,11 +221,9 @@ DefaultUserSetting('batteries_due_soon_days', 5); // The "due soon" days
|
||||||
// Tasks settings
|
// Tasks settings
|
||||||
DefaultUserSetting('tasks_due_soon_days', 5); // The "due soon" days
|
DefaultUserSetting('tasks_due_soon_days', 5); // The "due soon" days
|
||||||
|
|
||||||
// Component configuration for Quagga2 - read https://github.com/ericblade/quagga2#configobject for details
|
// Calendar settings
|
||||||
// Below is a generic good configuration,
|
DefaultUserSetting('calendar_color_products', '#007bff'); // The event color (hex code) for due products
|
||||||
// for an iPhone 7 Plus, halfsample = true, patchsize = small, frequency = 5 yields very good results
|
DefaultUserSetting('calendar_color_tasks', '#28a745'); // The event color (hex code) for due tasks
|
||||||
DefaultUserSetting('quagga2_numofworkers', 4);
|
DefaultUserSetting('calendar_color_chores', '#ffc107'); // The event color (hex code) for due chores
|
||||||
DefaultUserSetting('quagga2_halfsample', false);
|
DefaultUserSetting('calendar_color_batteries', '#17a2b8'); // The event color (hex code) for due battery charge cycles
|
||||||
DefaultUserSetting('quagga2_patchsize', 'medium');
|
DefaultUserSetting('calendar_color_meal_plan', '#6c757d'); // The event color (hex code) for meal plan items
|
||||||
DefaultUserSetting('quagga2_frequency', 10);
|
|
||||||
DefaultUserSetting('quagga2_debug', true);
|
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,12 @@ namespace Grocy\Controllers;
|
||||||
|
|
||||||
use LessQL\Result;
|
use LessQL\Result;
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
|
use Slim\Exception\HttpException;
|
||||||
|
|
||||||
class BaseApiController extends BaseController
|
class BaseApiController extends BaseController
|
||||||
{
|
{
|
||||||
const PATTERN_FIELD = '[A-Za-z_][A-Za-z0-9_]+';
|
const PATTERN_FIELD = '[A-Za-z_][A-Za-z0-9_]+';
|
||||||
|
|
||||||
const PATTERN_OPERATOR = '!?((>=)|(<=)|=|~|<|>|(§))';
|
const PATTERN_OPERATOR = '!?((>=)|(<=)|=|~|<|>|(§))';
|
||||||
|
|
||||||
const PATTERN_VALUE = '[A-Za-z\p{L}\p{M}0-9*_.$#^| -\\\]+';
|
const PATTERN_VALUE = '[A-Za-z\p{L}\p{M}0-9*_.$#^| -\\\]+';
|
||||||
|
|
||||||
protected $OpenApiSpec = null;
|
protected $OpenApiSpec = null;
|
||||||
|
|
@ -151,4 +150,47 @@ class BaseApiController extends BaseController
|
||||||
|
|
||||||
return $this->OpenApiSpec;
|
return $this->OpenApiSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static $htmlPurifierInstance = null;
|
||||||
|
protected function GetParsedAndFilteredRequestBody($request)
|
||||||
|
{
|
||||||
|
if ($request->getHeaderLine('Content-Type') != 'application/json')
|
||||||
|
{
|
||||||
|
throw new HttpException($request, 'Bad Content-Type', 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::$htmlPurifierInstance == null)
|
||||||
|
{
|
||||||
|
$htmlPurifierConfig = \HTMLPurifier_Config::createDefault();
|
||||||
|
$htmlPurifierConfig->set('Cache.SerializerPath', GROCY_DATAPATH . '/viewcache');
|
||||||
|
$htmlPurifierConfig->set('HTML.Allowed', 'div,b,strong,i,em,u,a[href|title|target],iframe[src|width|height|frameborder],ul,ol,li,p[style],br,span[style],img[style|width|height|alt|src],table[border|width|style],tbody,tr,td,th,blockquote,*[style|class|id],h1,h2,h3,h4,h5,h6');
|
||||||
|
$htmlPurifierConfig->set('Attr.EnableID', true);
|
||||||
|
$htmlPurifierConfig->set('HTML.SafeIframe', true);
|
||||||
|
$htmlPurifierConfig->set('CSS.AllowedProperties', 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align,width,height');
|
||||||
|
$htmlPurifierConfig->set('URI.AllowedSchemes', ['data' => true, 'http' => true, 'https' => true]);
|
||||||
|
$htmlPurifierConfig->set('URI.SafeIframeRegexp', '%^.*%'); // Allow any iframe source
|
||||||
|
$htmlPurifierConfig->set('CSS.MaxImgLength', null);
|
||||||
|
|
||||||
|
self::$htmlPurifierInstance = new \HTMLPurifier($htmlPurifierConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestBody = $request->getParsedBody();
|
||||||
|
foreach ($requestBody as $key => &$value)
|
||||||
|
{
|
||||||
|
// HTMLPurifier removes boolean values (true/false) and arrays, so explicitly keep them
|
||||||
|
// Maybe also possible through HTMLPurifier config (http://htmlpurifier.org/live/configdoc/plain.html)
|
||||||
|
if (!is_bool($value) && !is_array($value))
|
||||||
|
{
|
||||||
|
$value = self::$htmlPurifierInstance->purify($value);
|
||||||
|
|
||||||
|
// Allow some special chars
|
||||||
|
// Maybe also possible through HTMLPurifier config (http://htmlpurifier.org/live/configdoc/plain.html)
|
||||||
|
$value = str_replace('&', '&', $value);
|
||||||
|
$value = str_replace('>', '>', $value);
|
||||||
|
$value = str_replace('<', '<', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $requestBody;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ class BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $AppContainer;
|
protected $AppContainer;
|
||||||
|
protected $View;
|
||||||
|
|
||||||
protected function getApiKeyService()
|
protected function getApiKeyService()
|
||||||
{
|
{
|
||||||
|
|
@ -123,10 +124,12 @@ class BaseController
|
||||||
$this->View->set('version', $versionInfo->Version);
|
$this->View->set('version', $versionInfo->Version);
|
||||||
|
|
||||||
$localizationService = $this->getLocalizationService();
|
$localizationService = $this->getLocalizationService();
|
||||||
$this->View->set('__t', function (string $text, ...$placeholderValues) use ($localizationService) {
|
$this->View->set('__t', function (string $text, ...$placeholderValues) use ($localizationService)
|
||||||
|
{
|
||||||
return $localizationService->__t($text, $placeholderValues);
|
return $localizationService->__t($text, $placeholderValues);
|
||||||
});
|
});
|
||||||
$this->View->set('__n', function ($number, $singularForm, $pluralForm, $isQu = false) use ($localizationService) {
|
$this->View->set('__n', function ($number, $singularForm, $pluralForm, $isQu = false) use ($localizationService)
|
||||||
|
{
|
||||||
return $localizationService->__n($number, $singularForm, $pluralForm, $isQu);
|
return $localizationService->__n($number, $singularForm, $pluralForm, $isQu);
|
||||||
});
|
});
|
||||||
$this->View->set('LocalizationStrings', $localizationService->GetPoAsJsonString());
|
$this->View->set('LocalizationStrings', $localizationService->GetPoAsJsonString());
|
||||||
|
|
@ -140,7 +143,8 @@ class BaseController
|
||||||
}
|
}
|
||||||
$this->View->set('dir', $dir);
|
$this->View->set('dir', $dir);
|
||||||
|
|
||||||
$this->View->set('U', function ($relativePath, $isResource = false) use ($container) {
|
$this->View->set('U', function ($relativePath, $isResource = false) use ($container)
|
||||||
|
{
|
||||||
return $container->get('UrlManager')->ConstructUrl($relativePath, $isResource);
|
return $container->get('UrlManager')->ConstructUrl($relativePath, $isResource);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -204,43 +208,4 @@ class BaseController
|
||||||
|
|
||||||
return $this->render($response, $viewName, $data);
|
return $this->render($response, $viewName, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static $htmlPurifierInstance = null;
|
|
||||||
|
|
||||||
protected function GetParsedAndFilteredRequestBody($request)
|
|
||||||
{
|
|
||||||
if (self::$htmlPurifierInstance == null)
|
|
||||||
{
|
|
||||||
$htmlPurifierConfig = \HTMLPurifier_Config::createDefault();
|
|
||||||
$htmlPurifierConfig->set('Cache.SerializerPath', GROCY_DATAPATH . '/viewcache');
|
|
||||||
$htmlPurifierConfig->set('HTML.Allowed', 'div,b,strong,i,em,u,a[href|title|target],iframe[src|width|height|frameborder],ul,ol,li,p[style],br,span[style],img[style|width|height|alt|src],table[border|width|style],tbody,tr,td,th,blockquote,*[style|class|id],h1,h2,h3,h4,h5,h6');
|
|
||||||
$htmlPurifierConfig->set('Attr.EnableID', true);
|
|
||||||
$htmlPurifierConfig->set('HTML.SafeIframe', true);
|
|
||||||
$htmlPurifierConfig->set('CSS.AllowedProperties', 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align,width,height');
|
|
||||||
$htmlPurifierConfig->set('URI.AllowedSchemes', ['data' => true, 'http' => true, 'https' => true]);
|
|
||||||
$htmlPurifierConfig->set('URI.SafeIframeRegexp', '%^.*%'); // Allow any iframe source
|
|
||||||
$htmlPurifierConfig->set('CSS.MaxImgLength', null);
|
|
||||||
|
|
||||||
self::$htmlPurifierInstance = new \HTMLPurifier($htmlPurifierConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
$requestBody = $request->getParsedBody();
|
|
||||||
foreach ($requestBody as $key => &$value)
|
|
||||||
{
|
|
||||||
// HTMLPurifier removes boolean values (true/false) and arrays, so explicitly keep them
|
|
||||||
// Maybe also possible through HTMLPurifier config (http://htmlpurifier.org/live/configdoc/plain.html)
|
|
||||||
if (!is_bool($value) && !is_array($value))
|
|
||||||
{
|
|
||||||
$value = self::$htmlPurifierInstance->purify($value);
|
|
||||||
|
|
||||||
// Allow some special chars
|
|
||||||
// Maybe also possible through HTMLPurifier config (http://htmlpurifier.org/live/configdoc/plain.html)
|
|
||||||
$value = str_replace('&', '&', $value);
|
|
||||||
$value = str_replace('>', '>', $value);
|
|
||||||
$value = str_replace('<', '<', $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $requestBody;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,11 +69,12 @@ class BatteriesApiController extends BaseApiController
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$battery = $this->getDatabase()->batteries()->where('id', $args['batteryId'])->fetch();
|
$batteryDetails = (object)$this->getBatteriesService()->GetBatteryDetails($args['batteryId']);
|
||||||
|
|
||||||
$webhookData = array_merge([
|
$webhookData = array_merge([
|
||||||
'battery' => $battery->name,
|
'battery' => $batteryDetails->battery->name,
|
||||||
'grocycode' => (string)(new Grocycode(Grocycode::BATTERY, $args['batteryId'])),
|
'grocycode' => (string)(new Grocycode(Grocycode::BATTERY, $args['batteryId'])),
|
||||||
|
'details' => $batteryDetails,
|
||||||
], GROCY_LABEL_PRINTER_PARAMS);
|
], GROCY_LABEL_PRINTER_PARAMS);
|
||||||
|
|
||||||
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,9 @@ class BatteriesController extends BaseController
|
||||||
|
|
||||||
return $this->renderPage($response, 'batteriesjournal', [
|
return $this->renderPage($response, 'batteriesjournal', [
|
||||||
'chargeCycles' => $this->getDatabase()->battery_charge_cycles()->where($where)->orderBy('tracked_time', 'DESC'),
|
'chargeCycles' => $this->getDatabase()->battery_charge_cycles()->where($where)->orderBy('tracked_time', 'DESC'),
|
||||||
'batteries' => $this->getDatabase()->batteries()->where('active = 1')->orderBy('name', 'COLLATE NOCASE')
|
'batteries' => $this->getDatabase()->batteries()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
|
'userfields' => $this->getUserfieldsService()->GetFields('battery_charge_cycles'),
|
||||||
|
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('battery_charge_cycles')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,7 +117,8 @@ class BatteriesController extends BaseController
|
||||||
public function TrackChargeCycle(Request $request, Response $response, array $args)
|
public function TrackChargeCycle(Request $request, Response $response, array $args)
|
||||||
{
|
{
|
||||||
return $this->renderPage($response, 'batterytracking', [
|
return $this->renderPage($response, 'batterytracking', [
|
||||||
'batteries' => $this->getDatabase()->batteries()->where('active = 1')->orderBy('name', 'COLLATE NOCASE')
|
'batteries' => $this->getDatabase()->batteries()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
|
'userfields' => $this->getUserfieldsService()->GetFields('battery_charge_cycles')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,11 +120,12 @@ class ChoresApiController extends BaseApiController
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$chore = $this->getDatabase()->chores()->where('id', $args['choreId'])->fetch();
|
$choreDetails = (object)$this->getChoresService()->GetChoreDetails($args['choreId']);
|
||||||
|
|
||||||
$webhookData = array_merge([
|
$webhookData = array_merge([
|
||||||
'chore' => $chore->name,
|
'chore' => $choreDetails->chore->name,
|
||||||
'grocycode' => (string)(new Grocycode(Grocycode::CHORE, $args['choreId'])),
|
'grocycode' => (string)(new Grocycode(Grocycode::CHORE, $args['choreId'])),
|
||||||
|
'details' => $choreDetails,
|
||||||
], GROCY_LABEL_PRINTER_PARAMS);
|
], GROCY_LABEL_PRINTER_PARAMS);
|
||||||
|
|
||||||
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
||||||
|
|
|
||||||
|
|
@ -109,9 +109,27 @@ class FilesApiController extends BaseApiController
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileName = $this->checkFileName($args['fileName']);
|
$fileName = $this->checkFileName($args['fileName']);
|
||||||
$data = $request->getBody()->getContents();
|
|
||||||
|
|
||||||
file_put_contents($this->getFilesService()->GetFilePath($args['group'], $fileName), $data);
|
$fileHandle = fopen($this->getFilesService()->GetFilePath($args['group'], $fileName), 'xb');
|
||||||
|
if($fileHandle === false)
|
||||||
|
{
|
||||||
|
throw new \Exception("Error while creating file $fileName");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the file to disk in chunks of 1 MB
|
||||||
|
$requestBody = $request->getBody();
|
||||||
|
while ($data = $requestBody->read(1048576))
|
||||||
|
{
|
||||||
|
if (fwrite($fileHandle, $data) === false)
|
||||||
|
{
|
||||||
|
throw new \Exception("Error while writing file $fileName");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fclose($fileHandle) === false)
|
||||||
|
{
|
||||||
|
throw new \Exception("Error while closing file $fileName");
|
||||||
|
}
|
||||||
|
|
||||||
return $this->EmptyApiResponse($response);
|
return $this->EmptyApiResponse($response);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,28 +190,31 @@ class GenericEntityApiController extends BaseApiController
|
||||||
|
|
||||||
public function GetObject(Request $request, Response $response, array $args)
|
public function GetObject(Request $request, Response $response, array $args)
|
||||||
{
|
{
|
||||||
if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoListing($args['entity']))
|
if (!$this->IsValidExposedEntity($args['entity']) || $this->IsEntityWithNoListing($args['entity']))
|
||||||
{
|
|
||||||
$userfields = $this->getUserfieldsService()->GetValues($args['entity'], $args['objectId']);
|
|
||||||
if (count($userfields) === 0)
|
|
||||||
{
|
|
||||||
$userfields = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$object = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
|
||||||
if ($object == null)
|
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, 'Object not found', 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$object['userfields'] = $userfields;
|
|
||||||
|
|
||||||
return $this->ApiResponse($response, $object);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed');
|
return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$object = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
||||||
|
if ($object == null)
|
||||||
|
{
|
||||||
|
return $this->GenericErrorResponse($response, 'Object not found', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle this somehow more generically
|
||||||
|
$referencingId = $args['objectId'];
|
||||||
|
if ($args['entity'] == 'stock')
|
||||||
|
{
|
||||||
|
$referencingId = $object->stock_id;
|
||||||
|
}
|
||||||
|
$userfields = $this->getUserfieldsService()->GetValues($args['entity'], $referencingId);
|
||||||
|
if (count($userfields) === 0)
|
||||||
|
{
|
||||||
|
$userfields = null;
|
||||||
|
}
|
||||||
|
$object['userfields'] = $userfields;
|
||||||
|
|
||||||
|
return $this->ApiResponse($response, $object);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetObjects(Request $request, Response $response, array $args)
|
public function GetObjects(Request $request, Response $response, array $args)
|
||||||
|
|
@ -222,8 +225,8 @@ class GenericEntityApiController extends BaseApiController
|
||||||
}
|
}
|
||||||
|
|
||||||
$objects = $this->queryData($this->getDatabase()->{$args['entity']}(), $request->getQueryParams());
|
$objects = $this->queryData($this->getDatabase()->{$args['entity']}(), $request->getQueryParams());
|
||||||
$userfields = $this->getUserfieldsService()->GetFields($args['entity']);
|
|
||||||
|
|
||||||
|
$userfields = $this->getUserfieldsService()->GetFields($args['entity']);
|
||||||
if (count($userfields) > 0)
|
if (count($userfields) > 0)
|
||||||
{
|
{
|
||||||
$allUserfieldValues = $this->getUserfieldsService()->GetAllValues($args['entity']);
|
$allUserfieldValues = $this->getUserfieldsService()->GetAllValues($args['entity']);
|
||||||
|
|
@ -233,7 +236,14 @@ class GenericEntityApiController extends BaseApiController
|
||||||
$userfieldKeyValuePairs = null;
|
$userfieldKeyValuePairs = null;
|
||||||
foreach ($userfields as $userfield)
|
foreach ($userfields as $userfield)
|
||||||
{
|
{
|
||||||
$value = FindObjectInArrayByPropertyValue(FindAllObjectsInArrayByPropertyValue($allUserfieldValues, 'object_id', $object->id), 'name', $userfield->name);
|
// TODO: Handle this somehow more generically
|
||||||
|
$userfieldReference = 'id';
|
||||||
|
if ($args['entity'] == 'stock')
|
||||||
|
{
|
||||||
|
$userfieldReference = 'stock_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = FindObjectInArrayByPropertyValue(FindAllObjectsInArrayByPropertyValue($allUserfieldValues, 'object_id', $object->{$userfieldReference}), 'name', $userfield->name);
|
||||||
if ($value)
|
if ($value)
|
||||||
{
|
{
|
||||||
$userfieldKeyValuePairs[$userfield->name] = $value->value;
|
$userfieldKeyValuePairs[$userfield->name] = $value->value;
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,11 @@ trait GrocycodeTrait
|
||||||
|
|
||||||
if (GROCY_GROCYCODE_TYPE == '2D')
|
if (GROCY_GROCYCODE_TYPE == '2D')
|
||||||
{
|
{
|
||||||
$png = (new DatamatrixFactory())->setCode((string) $grocycode)->setSize($size)->getDatamatrixPngData();
|
$png = (new DatamatrixFactory())->setCode((string)$grocycode)->setSize($size)->getDatamatrixPngData();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$png = (new BarcodeFactory())->setType('C128')->setCode((string) $grocycode)->setHeight($size)->getBarcodePngData();
|
$png = (new BarcodeFactory())->setType('C128')->setCode((string)$grocycode)->setHeight($size)->getBarcodePngData();
|
||||||
}
|
}
|
||||||
|
|
||||||
$isDownload = $request->getQueryParam('download', false);
|
$isDownload = $request->getQueryParam('download', false);
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ class LoginController extends BaseController
|
||||||
public function ProcessLogin(Request $request, Response $response, array $args)
|
public function ProcessLogin(Request $request, Response $response, array $args)
|
||||||
{
|
{
|
||||||
$authMiddlewareClass = GROCY_AUTH_CLASS;
|
$authMiddlewareClass = GROCY_AUTH_CLASS;
|
||||||
if ($authMiddlewareClass::ProcessLogin($this->GetParsedAndFilteredRequestBody($request)))
|
if ($authMiddlewareClass::ProcessLogin($request->getParsedBody()))
|
||||||
{
|
{
|
||||||
return $response->withRedirect($this->AppContainer->get('UrlManager')->ConstructUrl('/'));
|
return $response->withRedirect($this->AppContainer->get('UrlManager')->ConstructUrl('/'));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ class RecipesApiController extends BaseApiController
|
||||||
$webhookData = array_merge([
|
$webhookData = array_merge([
|
||||||
'recipe' => $recipe->name,
|
'recipe' => $recipe->name,
|
||||||
'grocycode' => (string)(new Grocycode(Grocycode::RECIPE, $args['recipeId'])),
|
'grocycode' => (string)(new Grocycode(Grocycode::RECIPE, $args['recipeId'])),
|
||||||
|
'details' => $recipe
|
||||||
], GROCY_LABEL_PRINTER_PARAMS);
|
], GROCY_LABEL_PRINTER_PARAMS);
|
||||||
|
|
||||||
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
||||||
|
|
|
||||||
|
|
@ -57,17 +57,24 @@ class RecipesController extends BaseController
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$weekRecipe = $this->getDatabase()->recipes()->where("type = 'mealplan-week' AND name = LTRIM(STRFTIME('%Y-%W', DATE('$start')), '0')")->fetch();
|
||||||
|
$weekRecipeId = 0;
|
||||||
|
if ($weekRecipe != null)
|
||||||
|
{
|
||||||
|
$weekRecipeId = $weekRecipe->id;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->renderPage($response, 'mealplan', [
|
return $this->renderPage($response, 'mealplan', [
|
||||||
'fullcalendarEventSources' => $events,
|
'fullcalendarEventSources' => $events,
|
||||||
'recipes' => $recipes,
|
'recipes' => $recipes,
|
||||||
'internalRecipes' => $this->getDatabase()->recipes()->where("id IN (SELECT recipe_id FROM meal_plan_internal_recipe_relation WHERE $mealPlanWhereTimespan)")->fetchAll(),
|
'internalRecipes' => $this->getDatabase()->recipes()->where("id IN (SELECT recipe_id FROM meal_plan_internal_recipe_relation WHERE $mealPlanWhereTimespan) OR id = $weekRecipeId")->fetchAll(),
|
||||||
'recipesResolved' => $this->getRecipesService()->GetRecipesResolved("recipe_id IN (SELECT recipe_id FROM meal_plan_internal_recipe_relation WHERE $mealPlanWhereTimespan)"),
|
'recipesResolved' => $this->getRecipesService()->GetRecipesResolved("recipe_id IN (SELECT recipe_id FROM meal_plan_internal_recipe_relation WHERE $mealPlanWhereTimespan) OR recipe_id = $weekRecipeId"),
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'),
|
'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved(),
|
||||||
'mealplanSections' => $this->getDatabase()->meal_plan_sections()->orderBy('sort_number'),
|
'mealplanSections' => $this->getDatabase()->meal_plan_sections()->orderBy('sort_number'),
|
||||||
'usedMealplanSections' => $this->getDatabase()->meal_plan_sections()->where("id IN (SELECT section_id FROM meal_plan WHERE $mealPlanWhereTimespan)")->orderBy('sort_number'),
|
'usedMealplanSections' => $this->getDatabase()->meal_plan_sections()->where("id IN (SELECT section_id FROM meal_plan WHERE $mealPlanWhereTimespan)")->orderBy('sort_number'),
|
||||||
'weekRecipe' => $this->getDatabase()->recipes()->where("type = 'mealplan-week' AND name = LTRIM(STRFTIME('%Y-%W', DATE('$start')), '0')")->fetch()
|
'weekRecipe' => $weekRecipe
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,7 +114,7 @@ class RecipesController extends BaseController
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units(),
|
'quantityUnits' => $this->getDatabase()->quantity_units(),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('recipes'),
|
'userfields' => $this->getUserfieldsService()->GetFields('recipes'),
|
||||||
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('recipes'),
|
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('recipes'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved(),
|
||||||
'selectedRecipeTotalCosts' => $totalCosts,
|
'selectedRecipeTotalCosts' => $totalCosts,
|
||||||
'selectedRecipeTotalCalories' => $totalCalories,
|
'selectedRecipeTotalCalories' => $totalCalories,
|
||||||
'mealplanSections' => $this->getDatabase()->meal_plan_sections()->orderBy('sort_number')
|
'mealplanSections' => $this->getDatabase()->meal_plan_sections()->orderBy('sort_number')
|
||||||
|
|
@ -162,7 +169,7 @@ class RecipesController extends BaseController
|
||||||
'recipes' => $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE'),
|
'recipes' => $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'recipeNestings' => $this->getDatabase()->recipes_nestings()->where('recipe_id', $recipeId),
|
'recipeNestings' => $this->getDatabase()->recipes_nestings()->where('recipe_id', $recipeId),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('recipes'),
|
'userfields' => $this->getUserfieldsService()->GetFields('recipes'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,8 +182,9 @@ class RecipesController extends BaseController
|
||||||
'recipe' => $this->getDatabase()->recipes($args['recipeId']),
|
'recipe' => $this->getDatabase()->recipes($args['recipeId']),
|
||||||
'recipePos' => new \stdClass(),
|
'recipePos' => new \stdClass(),
|
||||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
|
'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -186,8 +194,9 @@ class RecipesController extends BaseController
|
||||||
'recipe' => $this->getDatabase()->recipes($args['recipeId']),
|
'recipe' => $this->getDatabase()->recipes($args['recipeId']),
|
||||||
'recipePos' => $this->getDatabase()->recipes_pos($args['recipePosId']),
|
'recipePos' => $this->getDatabase()->recipes_pos($args['recipePosId']),
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'),
|
'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
|
'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -442,7 +442,6 @@ class StockApiController extends BaseApiController
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$addFoundProduct = false;
|
$addFoundProduct = false;
|
||||||
|
|
||||||
if (isset($request->getQueryParams()['add']) && ($request->getQueryParams()['add'] === 'true' || $request->getQueryParams()['add'] === 1))
|
if (isset($request->getQueryParams()['add']) && ($request->getQueryParams()['add'] === 'true' || $request->getQueryParams()['add'] === 1))
|
||||||
{
|
{
|
||||||
$addFoundProduct = true;
|
$addFoundProduct = true;
|
||||||
|
|
@ -673,11 +672,12 @@ class StockApiController extends BaseApiController
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$product = $this->getDatabase()->products()->where('id', $args['productId'])->fetch();
|
$productDetails = (object)$this->getStockService()->GetProductDetails($args['productId']);
|
||||||
|
|
||||||
$webhookData = array_merge([
|
$webhookData = array_merge([
|
||||||
'product' => $product->name,
|
'product' => $productDetails->product->name,
|
||||||
'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $product->id)),
|
'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $productDetails->product->id)),
|
||||||
|
'details' => $productDetails,
|
||||||
], GROCY_LABEL_PRINTER_PARAMS);
|
], GROCY_LABEL_PRINTER_PARAMS);
|
||||||
|
|
||||||
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
||||||
|
|
@ -698,11 +698,13 @@ class StockApiController extends BaseApiController
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$stockEntry = $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch();
|
$stockEntry = $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch();
|
||||||
$product = $this->getDatabase()->products()->where('id', $stockEntry->product_id)->fetch();
|
$productDetails = (object)$this->getStockService()->GetProductDetails($stockEntry->product_id);
|
||||||
|
|
||||||
$webhookData = array_merge([
|
$webhookData = array_merge([
|
||||||
'product' => $product->name,
|
'product' => $productDetails->product->name,
|
||||||
'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $stockEntry->product_id, [$stockEntry->stock_id])),
|
'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $stockEntry->product_id, [$stockEntry->stock_id])),
|
||||||
|
'details' => $productDetails,
|
||||||
|
'stock_entry' => $stockEntry,
|
||||||
], GROCY_LABEL_PRINTER_PARAMS);
|
], GROCY_LABEL_PRINTER_PARAMS);
|
||||||
|
|
||||||
if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace Grocy\Controllers;
|
||||||
|
|
||||||
use Grocy\Helpers\Grocycode;
|
use Grocy\Helpers\Grocycode;
|
||||||
use Grocy\Services\RecipesService;
|
use Grocy\Services\RecipesService;
|
||||||
|
use DI\Container;
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
|
|
||||||
|
|
@ -11,6 +12,24 @@ class StockController extends BaseController
|
||||||
{
|
{
|
||||||
use GrocycodeTrait;
|
use GrocycodeTrait;
|
||||||
|
|
||||||
|
public function __construct(Container $container)
|
||||||
|
{
|
||||||
|
parent::__construct($container);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$externalBarcodeLookupPluginName = $this->getStockService()->GetExternalBarcodeLookupPluginName();
|
||||||
|
}
|
||||||
|
catch (\Exception)
|
||||||
|
{
|
||||||
|
$externalBarcodeLookupPluginName = '';
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
$this->View->set('ExternalBarcodeLookupPluginName', $externalBarcodeLookupPluginName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function Consume(Request $request, Response $response, array $args)
|
public function Consume(Request $request, Response $response, array $args)
|
||||||
{
|
{
|
||||||
return $this->renderPage($response, 'consume', [
|
return $this->renderPage($response, 'consume', [
|
||||||
|
|
@ -19,7 +38,7 @@ class StockController extends BaseController
|
||||||
'recipes' => $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE'),
|
'recipes' => $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,7 +50,7 @@ class StockController extends BaseController
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved(),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('stock')
|
'userfields' => $this->getUserfieldsService()->GetFields('stock')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -118,10 +137,17 @@ class StockController extends BaseController
|
||||||
public function Overview(Request $request, Response $response, array $args)
|
public function Overview(Request $request, Response $response, array $args)
|
||||||
{
|
{
|
||||||
$usersService = $this->getUsersService();
|
$usersService = $this->getUsersService();
|
||||||
$nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_due_soon_days'];
|
$userSettings = $usersService->GetUserSettings(GROCY_USER_ID);
|
||||||
|
$nextXDays = $userSettings['stock_due_soon_days'];
|
||||||
|
|
||||||
|
$where = 'is_in_stock_or_below_min_stock = 1';
|
||||||
|
if (boolval($userSettings['stock_overview_show_all_out_of_stock_products']))
|
||||||
|
{
|
||||||
|
$where = '1=1';
|
||||||
|
}
|
||||||
|
|
||||||
return $this->renderPage($response, 'stockoverview', [
|
return $this->renderPage($response, 'stockoverview', [
|
||||||
'currentStock' => $this->getStockService()->GetCurrentStockOverview(),
|
'currentStock' => $this->getDatabase()->uihelper_stock_current_overview()->where($where),
|
||||||
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'currentStockLocations' => $this->getStockService()->GetCurrentStockLocations(),
|
'currentStockLocations' => $this->getStockService()->GetCurrentStockLocations(),
|
||||||
'nextXDays' => $nextXDays,
|
'nextXDays' => $nextXDays,
|
||||||
|
|
@ -147,7 +173,7 @@ class StockController extends BaseController
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved(),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('product_barcodes')
|
'userfields' => $this->getUserfieldsService()->GetFields('product_barcodes')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -159,7 +185,7 @@ class StockController extends BaseController
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved(),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('product_barcodes')
|
'userfields' => $this->getUserfieldsService()->GetFields('product_barcodes')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -169,12 +195,13 @@ class StockController extends BaseController
|
||||||
{
|
{
|
||||||
if ($args['productId'] == 'new')
|
if ($args['productId'] == 'new')
|
||||||
{
|
{
|
||||||
|
$quantityunits = $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE');
|
||||||
|
|
||||||
return $this->renderPage($response, 'productform', [
|
return $this->renderPage($response, 'productform', [
|
||||||
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name'),
|
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name'),
|
||||||
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'quantityunitsAll' => $quantityunits,
|
||||||
'quantityunitsStock' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityunitsReferenced' => $quantityunits,
|
||||||
'referencedQuantityunits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'productgroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'productgroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||||
|
|
@ -191,9 +218,8 @@ class StockController extends BaseController
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'quantityunitsAll' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityunitsStock' => $this->getDatabase()->quantity_units()->where('id IN (SELECT to_qu_id FROM quantity_unit_conversions_resolved WHERE product_id = :1) OR NOT EXISTS(SELECT 1 FROM stock_log WHERE product_id = :1)', $product->id)->orderBy('name', 'COLLATE NOCASE'),
|
'quantityunitsReferenced' => $this->getDatabase()->quantity_units()->where('id IN (SELECT to_qu_id FROM cache__quantity_unit_conversions_resolved WHERE product_id = :1) OR NOT EXISTS(SELECT 1 FROM stock_log WHERE product_id = :1)', $product->id)->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'referencedQuantityunits' => $this->getDatabase()->quantity_units()->where('active = 1')->where('id IN (SELECT to_qu_id FROM quantity_unit_conversions_resolved WHERE product_id = :1)', $product->id)->orderBy('name', 'COLLATE NOCASE'),
|
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'productgroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'productgroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||||
|
|
@ -289,7 +315,7 @@ class StockController extends BaseController
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved(),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('stock')
|
'userfields' => $this->getUserfieldsService()->GetFields('stock')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -393,13 +419,13 @@ class StockController extends BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->renderPage($response, 'shoppinglist', [
|
return $this->renderPage($response, 'shoppinglist', [
|
||||||
'listItems' => $this->getDatabase()->uihelper_shopping_list()->where('shopping_list_id = :1', $listId),
|
'listItems' => $this->getDatabase()->uihelper_shopping_list()->where('shopping_list_id = :1', $listId)->orderBy('product_name', 'COLLATE NOCASE'),
|
||||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'missingProducts' => $this->getStockService()->GetMissingProducts(),
|
'missingProducts' => $this->getStockService()->GetMissingProducts(),
|
||||||
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name', 'COLLATE NOCASE'),
|
'shoppingLists' => $this->getDatabase()->shopping_lists_view()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'selectedShoppingListId' => $listId,
|
'selectedShoppingListId' => $listId,
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved(),
|
||||||
'productUserfields' => $this->getUserfieldsService()->GetFields('products'),
|
'productUserfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||||
'productUserfieldValues' => $this->getUserfieldsService()->GetAllValues('products'),
|
'productUserfieldValues' => $this->getUserfieldsService()->GetAllValues('products'),
|
||||||
'productGroupUserfields' => $this->getUserfieldsService()->GetFields('product_groups'),
|
'productGroupUserfields' => $this->getUserfieldsService()->GetFields('product_groups'),
|
||||||
|
|
@ -438,7 +464,7 @@ class StockController extends BaseController
|
||||||
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name', 'COLLATE NOCASE'),
|
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved(),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('shopping_list')
|
'userfields' => $this->getUserfieldsService()->GetFields('shopping_list')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -451,7 +477,7 @@ class StockController extends BaseController
|
||||||
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name', 'COLLATE NOCASE'),
|
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'mode' => 'edit',
|
'mode' => 'edit',
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved(),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('shopping_list')
|
'userfields' => $this->getUserfieldsService()->GetFields('shopping_list')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -564,7 +590,7 @@ class StockController extends BaseController
|
||||||
'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(),
|
'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(),
|
||||||
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'quantityUnitConversionsResolved' => $this->getDatabase()->cache__quantity_unit_conversions_resolved()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -599,11 +625,11 @@ class StockController extends BaseController
|
||||||
if (isset($request->getQueryParams()['product']))
|
if (isset($request->getQueryParams()['product']))
|
||||||
{
|
{
|
||||||
$product = $this->getDatabase()->products($request->getQueryParams()['product']);
|
$product = $this->getDatabase()->products($request->getQueryParams()['product']);
|
||||||
$quantityUnitConversionsResolved = $this->getDatabase()->quantity_unit_conversions_resolved()->where('product_id', $product->id);
|
$quantityUnitConversionsResolved = $this->getDatabase()->cache__quantity_unit_conversions_resolved()->where('product_id', $product->id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$quantityUnitConversionsResolved = $this->getDatabase()->quantity_unit_conversions_resolved()->where('product_id IS NULL');
|
$quantityUnitConversionsResolved = $this->getDatabase()->cache__quantity_unit_conversions_resolved()->where('product_id IS NULL');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->renderPage($response, 'quantityunitconversionsresolved', [
|
return $this->renderPage($response, 'quantityunitconversionsresolved', [
|
||||||
|
|
|
||||||
|
|
@ -9,41 +9,38 @@ class StockReportsController extends BaseController
|
||||||
{
|
{
|
||||||
public function Spendings(Request $request, Response $response, array $args)
|
public function Spendings(Request $request, Response $response, array $args)
|
||||||
{
|
{
|
||||||
|
$where = "pph.transaction_type != 'self-production'";
|
||||||
|
|
||||||
if (isset($request->getQueryParams()['start_date']) && isset($request->getQueryParams()['end_date']) && IsIsoDate($request->getQueryParams()['start_date']) && IsIsoDate($request->getQueryParams()['end_date']))
|
if (isset($request->getQueryParams()['start_date']) && isset($request->getQueryParams()['end_date']) && IsIsoDate($request->getQueryParams()['start_date']) && IsIsoDate($request->getQueryParams()['end_date']))
|
||||||
{
|
{
|
||||||
$startDate = $request->getQueryParams()['start_date'];
|
$startDate = $request->getQueryParams()['start_date'];
|
||||||
$endDate = $request->getQueryParams()['end_date'];
|
$endDate = $request->getQueryParams()['end_date'];
|
||||||
$where = "pph.purchased_date BETWEEN '$startDate' AND '$endDate'";
|
$where .= " AND pph.purchased_date BETWEEN '$startDate' AND '$endDate'";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Default to this month
|
// Default to this month
|
||||||
$where = "pph.purchased_date >= DATE(DATE('now', 'localtime'), 'start of month')";
|
$where .= " AND pph.purchased_date >= DATE(DATE('now', 'localtime'), 'start of month')";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$groupBy = 'product';
|
||||||
if (isset($request->getQueryParams()['byGroup']))
|
if (isset($request->getQueryParams()['group-by']) && in_array($request->getQueryParams()['group-by'], ['product', 'productgroup', 'store']))
|
||||||
{
|
{
|
||||||
$sql = "
|
$groupBy = $request->getQueryParams()['group-by'];
|
||||||
SELECT
|
|
||||||
pg.id AS id,
|
|
||||||
pg.name AS name,
|
|
||||||
SUM(pph.amount * pph.price) AS total
|
|
||||||
FROM product_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
|
|
||||||
";
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if ($groupBy == 'product')
|
||||||
{
|
{
|
||||||
if (isset($request->getQueryParams()['product_group']) and $request->getQueryParams()['product_group'] != 'all')
|
if (isset($request->getQueryParams()['product-group']))
|
||||||
{
|
{
|
||||||
$where .= ' AND pg.id = ' . $request->getQueryParams()['product_group'];
|
if ($request->getQueryParams()['product-group'] == 'ungrouped')
|
||||||
|
{
|
||||||
|
$where .= ' AND pg.id IS NULL';
|
||||||
|
}
|
||||||
|
elseif ($request->getQueryParams()['product-group'] != 'all')
|
||||||
|
{
|
||||||
|
$where .= ' AND pg.id = ' . $request->getQueryParams()['product-group'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
|
|
@ -53,22 +50,56 @@ class StockReportsController extends BaseController
|
||||||
pg.id AS group_id,
|
pg.id AS group_id,
|
||||||
pg.name AS group_name,
|
pg.name AS group_name,
|
||||||
SUM(pph.amount * pph.price) AS total
|
SUM(pph.amount * pph.price) AS total
|
||||||
FROM product_price_history pph
|
FROM products_price_history pph
|
||||||
JOIN products p
|
JOIN products p
|
||||||
ON pph.product_id = p.id
|
ON pph.product_id = p.id
|
||||||
JOIN product_groups pg
|
LEFT JOIN product_groups pg
|
||||||
ON p.product_group_id = pg.id
|
ON p.product_group_id = pg.id
|
||||||
WHERE $where
|
WHERE $where
|
||||||
GROUP BY p.id
|
GROUP BY p.id, p.name, pg.id, pg.name
|
||||||
ORDER BY p.NAME COLLATE NOCASE
|
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
|
||||||
|
LEFT 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', [
|
return $this->renderPage($response, 'stockreportspendings', [
|
||||||
'metrics' => $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ),
|
'metrics' => $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ),
|
||||||
'productGroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'productGroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'selectedGroup' => isset($request->getQueryParams()['product_group']) ? $request->getQueryParams()['product_group'] : null,
|
'selectedGroup' => isset($request->getQueryParams()['product-group']) ? $request->getQueryParams()['product-group'] : null,
|
||||||
'byGroup' => isset($request->getQueryParams()['byGroup']) ? $request->getQueryParams()['byGroup'] : null
|
'groupBy' => $groupBy
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,34 @@ class SystemController extends BaseController
|
||||||
if (GROCY_MODE === 'dev' || GROCY_MODE === 'demo' || GROCY_MODE === 'prerelease')
|
if (GROCY_MODE === 'dev' || GROCY_MODE === 'demo' || GROCY_MODE === 'prerelease')
|
||||||
{
|
{
|
||||||
$demoDataGeneratorService = DemoDataGeneratorService::getInstance();
|
$demoDataGeneratorService = DemoDataGeneratorService::getInstance();
|
||||||
$demoDataGeneratorService->PopulateDemoData();
|
$demoDataGeneratorService->PopulateDemoData(isset($request->getQueryParams()['nodemodata']));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response->withRedirect($this->AppContainer->get('UrlManager')->ConstructUrl($this->GetEntryPageRelative()));
|
return $response->withRedirect($this->AppContainer->get('UrlManager')->ConstructUrl($this->GetEntryPageRelative()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function Manifest(Request $request, Response $response, array $args)
|
||||||
|
{
|
||||||
|
$data = explode('#', base64_decode($request->getQueryParams()['data']));
|
||||||
|
|
||||||
|
$manifest = [
|
||||||
|
'name' => 'Grocy ' . $data[0],
|
||||||
|
'short_name' => 'Grocy ' . $data[0],
|
||||||
|
'icons' => [[
|
||||||
|
'src' => './img/icon-1024.png',
|
||||||
|
'sizes'=> '1024x1024',
|
||||||
|
'type' => 'image/png'
|
||||||
|
]],
|
||||||
|
'start_url' => $data[1],
|
||||||
|
'background_color' => '#333131',
|
||||||
|
'theme_color' => '#333131',
|
||||||
|
'display' => 'standalone'
|
||||||
|
];
|
||||||
|
|
||||||
|
$response->getBody()->write(json_encode($manifest));
|
||||||
|
return $response->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
private function GetEntryPageRelative()
|
private function GetEntryPageRelative()
|
||||||
{
|
{
|
||||||
if (defined('GROCY_ENTRY_PAGE'))
|
if (defined('GROCY_ENTRY_PAGE'))
|
||||||
|
|
|
||||||
|
|
@ -8,63 +8,34 @@ use LessQL\Result;
|
||||||
class User
|
class User
|
||||||
{
|
{
|
||||||
const PERMISSION_ADMIN = 'ADMIN';
|
const PERMISSION_ADMIN = 'ADMIN';
|
||||||
|
|
||||||
const PERMISSION_BATTERIES = 'BATTERIES';
|
const PERMISSION_BATTERIES = 'BATTERIES';
|
||||||
|
|
||||||
const PERMISSION_BATTERIES_TRACK_CHARGE_CYCLE = 'BATTERIES_TRACK_CHARGE_CYCLE';
|
const PERMISSION_BATTERIES_TRACK_CHARGE_CYCLE = 'BATTERIES_TRACK_CHARGE_CYCLE';
|
||||||
|
|
||||||
const PERMISSION_BATTERIES_UNDO_CHARGE_CYCLE = 'BATTERIES_UNDO_CHARGE_CYCLE';
|
const PERMISSION_BATTERIES_UNDO_CHARGE_CYCLE = 'BATTERIES_UNDO_CHARGE_CYCLE';
|
||||||
|
|
||||||
const PERMISSION_CALENDAR = 'CALENDAR';
|
const PERMISSION_CALENDAR = 'CALENDAR';
|
||||||
|
|
||||||
const PERMISSION_CHORES = 'CHORES';
|
const PERMISSION_CHORES = 'CHORES';
|
||||||
|
|
||||||
const PERMISSION_CHORE_TRACK_EXECUTION = 'CHORE_TRACK_EXECUTION';
|
const PERMISSION_CHORE_TRACK_EXECUTION = 'CHORE_TRACK_EXECUTION';
|
||||||
|
|
||||||
const PERMISSION_CHORE_UNDO_EXECUTION = 'CHORE_UNDO_EXECUTION';
|
const PERMISSION_CHORE_UNDO_EXECUTION = 'CHORE_UNDO_EXECUTION';
|
||||||
|
|
||||||
const PERMISSION_EQUIPMENT = 'EQUIPMENT';
|
const PERMISSION_EQUIPMENT = 'EQUIPMENT';
|
||||||
|
|
||||||
const PERMISSION_MASTER_DATA_EDIT = 'MASTER_DATA_EDIT';
|
const PERMISSION_MASTER_DATA_EDIT = 'MASTER_DATA_EDIT';
|
||||||
|
|
||||||
const PERMISSION_RECIPES = 'RECIPES';
|
const PERMISSION_RECIPES = 'RECIPES';
|
||||||
|
|
||||||
const PERMISSION_RECIPES_MEALPLAN = 'RECIPES_MEALPLAN';
|
const PERMISSION_RECIPES_MEALPLAN = 'RECIPES_MEALPLAN';
|
||||||
|
|
||||||
const PERMISSION_SHOPPINGLIST = 'SHOPPINGLIST';
|
const PERMISSION_SHOPPINGLIST = 'SHOPPINGLIST';
|
||||||
|
|
||||||
const PERMISSION_SHOPPINGLIST_ITEMS_ADD = 'SHOPPINGLIST_ITEMS_ADD';
|
const PERMISSION_SHOPPINGLIST_ITEMS_ADD = 'SHOPPINGLIST_ITEMS_ADD';
|
||||||
|
|
||||||
const PERMISSION_SHOPPINGLIST_ITEMS_DELETE = 'SHOPPINGLIST_ITEMS_DELETE';
|
const PERMISSION_SHOPPINGLIST_ITEMS_DELETE = 'SHOPPINGLIST_ITEMS_DELETE';
|
||||||
|
|
||||||
const PERMISSION_STOCK = 'STOCK';
|
const PERMISSION_STOCK = 'STOCK';
|
||||||
|
|
||||||
const PERMISSION_STOCK_CONSUME = 'STOCK_CONSUME';
|
const PERMISSION_STOCK_CONSUME = 'STOCK_CONSUME';
|
||||||
|
|
||||||
const PERMISSION_STOCK_EDIT = 'STOCK_EDIT';
|
const PERMISSION_STOCK_EDIT = 'STOCK_EDIT';
|
||||||
|
|
||||||
const PERMISSION_STOCK_INVENTORY = 'STOCK_INVENTORY';
|
const PERMISSION_STOCK_INVENTORY = 'STOCK_INVENTORY';
|
||||||
|
|
||||||
const PERMISSION_STOCK_OPEN = 'STOCK_OPEN';
|
const PERMISSION_STOCK_OPEN = 'STOCK_OPEN';
|
||||||
|
|
||||||
const PERMISSION_STOCK_PURCHASE = 'STOCK_PURCHASE';
|
const PERMISSION_STOCK_PURCHASE = 'STOCK_PURCHASE';
|
||||||
|
|
||||||
const PERMISSION_STOCK_TRANSFER = 'STOCK_TRANSFER';
|
const PERMISSION_STOCK_TRANSFER = 'STOCK_TRANSFER';
|
||||||
|
|
||||||
const PERMISSION_TASKS = 'TASKS';
|
const PERMISSION_TASKS = 'TASKS';
|
||||||
|
|
||||||
const PERMISSION_TASKS_MARK_COMPLETED = 'TASKS_MARK_COMPLETED';
|
const PERMISSION_TASKS_MARK_COMPLETED = 'TASKS_MARK_COMPLETED';
|
||||||
|
|
||||||
const PERMISSION_TASKS_UNDO_EXECUTION = 'TASKS_UNDO_EXECUTION';
|
const PERMISSION_TASKS_UNDO_EXECUTION = 'TASKS_UNDO_EXECUTION';
|
||||||
|
|
||||||
const PERMISSION_USERS = 'USERS';
|
const PERMISSION_USERS = 'USERS';
|
||||||
|
|
||||||
const PERMISSION_USERS_CREATE = 'USERS_CREATE';
|
const PERMISSION_USERS_CREATE = 'USERS_CREATE';
|
||||||
|
|
||||||
const PERMISSION_USERS_EDIT = 'USERS_EDIT';
|
const PERMISSION_USERS_EDIT = 'USERS_EDIT';
|
||||||
|
|
||||||
const PERMISSION_USERS_EDIT_SELF = 'USERS_EDIT_SELF';
|
const PERMISSION_USERS_EDIT_SELF = 'USERS_EDIT_SELF';
|
||||||
|
|
||||||
const PERMISSION_USERS_READ = 'USERS_READ';
|
const PERMISSION_USERS_READ = 'USERS_READ';
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@ class UsersController extends BaseController
|
||||||
public function UserSettings(Request $request, Response $response, array $args)
|
public function UserSettings(Request $request, Response $response, array $args)
|
||||||
{
|
{
|
||||||
return $this->renderPage($response, 'usersettings', [
|
return $this->renderPage($response, 'usersettings', [
|
||||||
'languages' => array_filter(scandir(__DIR__ . '/../localization'), function ($item) {
|
'languages' => array_filter(scandir(__DIR__ . '/../localization'), function ($item)
|
||||||
|
{
|
||||||
if ($item == '.' || $item == '..')
|
if ($item == '.' || $item == '..')
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
1
data/plugins/.gitignore
vendored
|
|
@ -1,3 +1,2 @@
|
||||||
*
|
*
|
||||||
!.gitignore
|
!.gitignore
|
||||||
!DemoBarcodeLookupPlugin.php
|
|
||||||
|
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Grocy\Helpers\BaseBarcodeLookupPlugin;
|
|
||||||
|
|
||||||
/*
|
|
||||||
This class must extend BaseBarcodeLookupPlugin (in namespace \Grocy\Helpers)
|
|
||||||
*/
|
|
||||||
class DemoBarcodeLookupPlugin extends BaseBarcodeLookupPlugin
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
To use this plugin, configure it in data/config.php like this:
|
|
||||||
Setting('STOCK_BARCODE_LOOKUP_PLUGIN', 'DemoBarcodeLookupPlugin');
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
To try it:
|
|
||||||
Call the API function at /api/stock/barcodes/external-lookup/{barcode}
|
|
||||||
|
|
||||||
When you also add ?add=true as a query parameter to the API call,
|
|
||||||
on a successful lookup the product is added to the database and in the output
|
|
||||||
the new product id is included (automatically, nothing to do here in the plugin)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Provided references:
|
|
||||||
|
|
||||||
$this->Locations contains all locations
|
|
||||||
$this->QuantityUnits contains all quantity units
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Useful hints:
|
|
||||||
|
|
||||||
Get a quantity unit by name:
|
|
||||||
$quantityUnit = FindObjectInArrayByPropertyValue($this->QuantityUnits, 'name', 'Piece');
|
|
||||||
|
|
||||||
Get a location by name:
|
|
||||||
$location = FindObjectInArrayByPropertyValue($this->Locations, 'name', 'Fridge');
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
This class must implement the protected abstract function ExecuteLookup($barcode),
|
|
||||||
which is called with the barcode that needs to be looked up and must return an
|
|
||||||
associative array of the product model or null, when nothing was found for the barcode.
|
|
||||||
|
|
||||||
The returned array must contain at least these properties:
|
|
||||||
array(
|
|
||||||
'name' => '',
|
|
||||||
'location_id' => 1, // A valid id of a location object, check against $this->Locations
|
|
||||||
'qu_id_purchase' => 1, // A valid id of quantity unit object, check against $this->QuantityUnits
|
|
||||||
'qu_id_stock' => 1, // A valid id of quantity unit object, check against $this->QuantityUnits
|
|
||||||
'qu_factor_purchase_to_stock' => 1, // Normally 1 when quantity unit stock and purchase is the same
|
|
||||||
'barcode' => $barcode // The barcode of the product, maybe just pass through $barcode or manipulate it if necessary
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
protected function ExecuteLookup($barcode)
|
|
||||||
{
|
|
||||||
if ($barcode === 'x')
|
|
||||||
{ // Demonstration when nothing is found
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
elseif ($barcode === 'e')
|
|
||||||
{ // Demonstration when an error occurred
|
|
||||||
throw new \Exception('This is the error message from the plugin...');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'LookedUpProduct_' . RandomString(5),
|
|
||||||
'location_id' => $this->Locations[0]->id,
|
|
||||||
'qu_id_purchase' => $this->QuantityUnits[0]->id,
|
|
||||||
'qu_id_stock' => $this->QuantityUnits[0]->id,
|
|
||||||
'qu_factor_purchase_to_stock' => 1,
|
|
||||||
'barcode' => $barcode
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1063,6 +1063,7 @@
|
||||||
"/users/{userId}/permissions": {
|
"/users/{userId}/permissions": {
|
||||||
"get": {
|
"get": {
|
||||||
"summary": "Returns the assigned permissions of the given user",
|
"summary": "Returns the assigned permissions of the given user",
|
||||||
|
"description": "See \"GET /objects/permission_hierarchy\" for a permission name / id mapping",
|
||||||
"tags": [
|
"tags": [
|
||||||
"User management"
|
"User management"
|
||||||
],
|
],
|
||||||
|
|
@ -1113,6 +1114,7 @@
|
||||||
},
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"summary": "Adds a permission to the given user",
|
"summary": "Adds a permission to the given user",
|
||||||
|
"description": "See \"GET /objects/permission_hierarchy\" for a permission name / id mapping",
|
||||||
"tags": [
|
"tags": [
|
||||||
"User management"
|
"User management"
|
||||||
],
|
],
|
||||||
|
|
@ -1161,6 +1163,7 @@
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"summary": "Replaces the assigned permissions of the given user",
|
"summary": "Replaces the assigned permissions of the given user",
|
||||||
|
"description": "See \"GET /objects/permission_hierarchy\" for a permission name / id mapping",
|
||||||
"tags": [
|
"tags": [
|
||||||
"User management"
|
"User management"
|
||||||
],
|
],
|
||||||
|
|
@ -1614,10 +1617,7 @@
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
"$ref": "#/components/schemas/CurrentVolatilStockResponse"
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/CurrentVolatilStockResponse"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2007,7 +2007,7 @@
|
||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`true` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
"description": "`true` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
|
|
@ -2242,7 +2242,7 @@
|
||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`true` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
"description": "`true` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
|
|
@ -2540,7 +2540,7 @@
|
||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`rue` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
"description": "`rue` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
|
|
@ -2763,7 +2763,7 @@
|
||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`rue` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
"description": "`rue` when any in stock sub product should be used when the given product is a parent product and currently not in stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
|
|
@ -3444,7 +3444,7 @@
|
||||||
},
|
},
|
||||||
"/recipes/{recipeId}/consume": {
|
"/recipes/{recipeId}/consume": {
|
||||||
"post": {
|
"post": {
|
||||||
"summary": "Consumes all products of the given recipe",
|
"summary": "Consumes all in stock ingredients of the given recipe (for ingredients that are only partially in stock, the in stock amount will be consumed)",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Recipes"
|
"Recipes"
|
||||||
],
|
],
|
||||||
|
|
@ -4511,6 +4511,106 @@
|
||||||
"move_on_open": "1"
|
"move_on_open": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ProductWithoutUserfields": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"location_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"qu_id_purchase": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"qu_id_stock": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"enable_tare_weight_handling": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"not_check_stock_fulfillment_for_recipes": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"product_group_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"tare_weight": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"min_stock_amount": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"default_best_before_days": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"default_best_before_days_after_open": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"picture_file_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"row_created_timestamp": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"shopping_location_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"treat_opened_as_out_of_stock": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"auto_reprint_stock_label": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"no_own_stock": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"should_not_be_frozen": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"default_consume_location_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"move_on_open": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"id": "1",
|
||||||
|
"name": "Cookies",
|
||||||
|
"description": null,
|
||||||
|
"location_id": "4",
|
||||||
|
"qu_id_purchase": "3",
|
||||||
|
"qu_id_stock": "3",
|
||||||
|
"min_stock_amount": "8",
|
||||||
|
"default_best_before_days": "0",
|
||||||
|
"row_created_timestamp": "2019-05-02 20:12:26",
|
||||||
|
"product_group_id": "1",
|
||||||
|
"picture_file_name": "cookies.jpg",
|
||||||
|
"default_best_before_days_after_open": "0",
|
||||||
|
"enable_tare_weight_handling": "0",
|
||||||
|
"tare_weight": "0.0",
|
||||||
|
"not_check_stock_fulfillment_for_recipes": "0",
|
||||||
|
"shopping_location_id": null,
|
||||||
|
"userfields": null,
|
||||||
|
"should_not_be_frozen": "1",
|
||||||
|
"default_consume_location_id": "5",
|
||||||
|
"move_on_open": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"QuantityUnit": {
|
"QuantityUnit": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -4733,7 +4833,10 @@
|
||||||
"$ref": "#/components/schemas/Product"
|
"$ref": "#/components/schemas/Product"
|
||||||
},
|
},
|
||||||
"product_barcodes": {
|
"product_barcodes": {
|
||||||
"$ref": "#/components/schemas/ProductBarcode"
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/ProductBarcode"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"quantity_unit_stock": {
|
"quantity_unit_stock": {
|
||||||
"$ref": "#/components/schemas/QuantityUnit"
|
"$ref": "#/components/schemas/QuantityUnit"
|
||||||
|
|
@ -4753,7 +4856,7 @@
|
||||||
},
|
},
|
||||||
"last_used": {
|
"last_used": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date"
|
||||||
},
|
},
|
||||||
"stock_amount": {
|
"stock_amount": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
|
|
@ -4763,7 +4866,7 @@
|
||||||
},
|
},
|
||||||
"next_due_date": {
|
"next_due_date": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date"
|
||||||
},
|
},
|
||||||
"last_price": {
|
"last_price": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
|
@ -5326,7 +5429,7 @@
|
||||||
},
|
},
|
||||||
"purchased_date": {
|
"purchased_date": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date"
|
||||||
},
|
},
|
||||||
"used_date": {
|
"used_date": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
@ -5521,7 +5624,7 @@
|
||||||
"description": "Indicates wheter this product has sub-products or not / if the fields `amount_aggregated` and `amount_opened_aggregated` are filled"
|
"description": "Indicates wheter this product has sub-products or not / if the fields `amount_aggregated` and `amount_opened_aggregated` are filled"
|
||||||
},
|
},
|
||||||
"product": {
|
"product": {
|
||||||
"$ref": "#/components/schemas/Product"
|
"$ref": "#/components/schemas/ProductWithoutUserfields"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -5801,7 +5904,10 @@
|
||||||
"products_last_purchased",
|
"products_last_purchased",
|
||||||
"products_average_price",
|
"products_average_price",
|
||||||
"quantity_unit_conversions_resolved",
|
"quantity_unit_conversions_resolved",
|
||||||
"recipes_pos_resolved"
|
"recipes_pos_resolved",
|
||||||
|
"battery_charge_cycles",
|
||||||
|
"product_barcodes_view",
|
||||||
|
"permission_hierarchy"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"ExposedEntityNoListing": {
|
"ExposedEntityNoListing": {
|
||||||
|
|
@ -5821,7 +5927,10 @@
|
||||||
"products_last_purchased",
|
"products_last_purchased",
|
||||||
"products_average_price",
|
"products_average_price",
|
||||||
"quantity_unit_conversions_resolved",
|
"quantity_unit_conversions_resolved",
|
||||||
"recipes_pos_resolved"
|
"recipes_pos_resolved",
|
||||||
|
"battery_charge_cycles",
|
||||||
|
"product_barcodes_view",
|
||||||
|
"permission_hierarchy"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"ExposedEntityNoDelete": {
|
"ExposedEntityNoDelete": {
|
||||||
|
|
@ -5834,7 +5943,10 @@
|
||||||
"products_last_purchased",
|
"products_last_purchased",
|
||||||
"products_average_price",
|
"products_average_price",
|
||||||
"quantity_unit_conversions_resolved",
|
"quantity_unit_conversions_resolved",
|
||||||
"recipes_pos_resolved"
|
"recipes_pos_resolved",
|
||||||
|
"battery_charge_cycles",
|
||||||
|
"product_barcodes_view",
|
||||||
|
"permission_hierarchy"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"ExposedEntityEditRequiresAdmin": {
|
"ExposedEntityEditRequiresAdmin": {
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,19 @@ namespace Grocy\Helpers;
|
||||||
|
|
||||||
abstract class BaseBarcodeLookupPlugin
|
abstract class BaseBarcodeLookupPlugin
|
||||||
{
|
{
|
||||||
final public function __construct($locations, $quantityUnits)
|
// That's a "self-referencing constant" and forces the child class to define it
|
||||||
|
public const PLUGIN_NAME = self::PLUGIN_NAME;
|
||||||
|
|
||||||
|
final public function __construct($locations, $quantityUnits, $userSettings)
|
||||||
{
|
{
|
||||||
$this->Locations = $locations;
|
$this->Locations = $locations;
|
||||||
$this->QuantityUnits = $quantityUnits;
|
$this->QuantityUnits = $quantityUnits;
|
||||||
|
$this->UserSettings = $userSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $Locations;
|
protected $Locations;
|
||||||
|
|
||||||
protected $QuantityUnits;
|
protected $QuantityUnits;
|
||||||
|
protected $UserSettings;
|
||||||
|
|
||||||
final public function Lookup($barcode)
|
final public function Lookup($barcode)
|
||||||
{
|
{
|
||||||
|
|
@ -30,7 +34,8 @@ abstract class BaseBarcodeLookupPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsAssociativeArray($pluginOutput))
|
if (!IsAssociativeArray($pluginOutput))
|
||||||
{ // $pluginOutput is at least an indexed array here
|
{
|
||||||
|
// $pluginOutput is at least an indexed array here
|
||||||
throw new \Exception('Plugin output must be an associative array');
|
throw new \Exception('Plugin output must be an associative array');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,8 +45,8 @@ abstract class BaseBarcodeLookupPlugin
|
||||||
'location_id',
|
'location_id',
|
||||||
'qu_id_purchase',
|
'qu_id_purchase',
|
||||||
'qu_id_stock',
|
'qu_id_stock',
|
||||||
'qu_factor_purchase_to_stock',
|
'__qu_factor_purchase_to_stock',
|
||||||
'barcode'
|
'__barcode'
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($minimunNeededProperties as $prop)
|
foreach ($minimunNeededProperties as $prop)
|
||||||
|
|
@ -54,29 +59,29 @@ abstract class BaseBarcodeLookupPlugin
|
||||||
|
|
||||||
// $pluginOutput contains all needed properties here
|
// $pluginOutput contains all needed properties here
|
||||||
|
|
||||||
// Check referenced entity ids are valid
|
// Check if referenced entity ids are valid
|
||||||
$locationId = $pluginOutput['location_id'];
|
$locationId = $pluginOutput['location_id'];
|
||||||
if (FindObjectInArrayByPropertyValue($this->Locations, 'id', $locationId) === null)
|
if (FindObjectInArrayByPropertyValue($this->Locations, 'id', $locationId) === null)
|
||||||
{
|
{
|
||||||
throw new \Exception("Location $locationId is not a valid location id");
|
throw new \Exception("Provided location_id ($locationId) is not a valid location id");
|
||||||
}
|
}
|
||||||
|
|
||||||
$quIdPurchase = $pluginOutput['qu_id_purchase'];
|
$quIdPurchase = $pluginOutput['qu_id_purchase'];
|
||||||
if (FindObjectInArrayByPropertyValue($this->QuantityUnits, 'id', $quIdPurchase) === null)
|
if (FindObjectInArrayByPropertyValue($this->QuantityUnits, 'id', $quIdPurchase) === null)
|
||||||
{
|
{
|
||||||
throw new \Exception("Location $quIdPurchase is not a valid quantity unit id");
|
throw new \Exception("Provided qu_id_purchase ($quIdPurchase) is not a valid quantity unit id");
|
||||||
}
|
}
|
||||||
|
|
||||||
$quIdStock = $pluginOutput['qu_id_stock'];
|
$quIdStock = $pluginOutput['qu_id_stock'];
|
||||||
if (FindObjectInArrayByPropertyValue($this->QuantityUnits, 'id', $quIdStock) === null)
|
if (FindObjectInArrayByPropertyValue($this->QuantityUnits, 'id', $quIdStock) === null)
|
||||||
{
|
{
|
||||||
throw new \Exception("Location $quIdStock is not a valid quantity unit id");
|
throw new \Exception("Provided qu_id_stock ($quIdStock) is not a valid quantity unit id");
|
||||||
}
|
}
|
||||||
|
|
||||||
$quFactor = $pluginOutput['qu_factor_purchase_to_stock'];
|
$quFactor = $pluginOutput['__qu_factor_purchase_to_stock'];
|
||||||
if (empty($quFactor) || !is_numeric($quFactor))
|
if (empty($quFactor) || !is_numeric($quFactor))
|
||||||
{
|
{
|
||||||
throw new \Exception('Quantity unit factor is empty or not a number');
|
throw new \Exception('Provided __qu_factor_purchase_to_stock is empty or not a number');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $pluginOutput;
|
return $pluginOutput;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class EInvalidConfig extends Exception
|
namespace Grocy\Helpers;
|
||||||
|
|
||||||
|
class EInvalidConfig extends \Exception
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,9 @@ namespace Grocy\Helpers;
|
||||||
class Grocycode
|
class Grocycode
|
||||||
{
|
{
|
||||||
public const PRODUCT = 'p';
|
public const PRODUCT = 'p';
|
||||||
|
|
||||||
public const BATTERY = 'b';
|
public const BATTERY = 'b';
|
||||||
|
|
||||||
public const CHORE = 'c';
|
public const CHORE = 'c';
|
||||||
|
|
||||||
public const RECIPE = 'r';
|
public const RECIPE = 'r';
|
||||||
|
|
||||||
public const MAGIC = 'grcy';
|
public const MAGIC = 'grcy';
|
||||||
|
|
||||||
public function __construct(...$args)
|
public function __construct(...$args)
|
||||||
|
|
@ -49,11 +45,8 @@ class Grocycode
|
||||||
}
|
}
|
||||||
|
|
||||||
public static $Items = [self::PRODUCT, self::BATTERY, self::CHORE, self::RECIPE];
|
public static $Items = [self::PRODUCT, self::BATTERY, self::CHORE, self::RECIPE];
|
||||||
|
|
||||||
private $type;
|
private $type;
|
||||||
|
|
||||||
private $id;
|
private $id;
|
||||||
|
|
||||||
private $extra_data = [];
|
private $extra_data = [];
|
||||||
|
|
||||||
public static function Validate(string $code)
|
public static function Validate(string $code)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class ERequirementNotMet extends Exception
|
namespace Grocy\Helpers;
|
||||||
|
|
||||||
|
class ERequirementNotMet extends \Exception
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const REQUIRED_PHP_EXTENSIONS = ['fileinfo', 'pdo_sqlite', 'gd', 'ctype', 'json', 'intl', 'zlib', 'mbstring',
|
const REQUIRED_PHP_EXTENSIONS = ['fileinfo', 'pdo_sqlite', 'gd', 'ctype', 'intl', 'zlib', 'mbstring',
|
||||||
|
|
||||||
// These are core extensions, so normally can't be missing, but seems to be the case, however, on FreeBSD
|
// These are core extensions, so normally can't be missing, but seems to be the case, however, on FreeBSD
|
||||||
'filter', 'iconv', 'tokenizer'
|
'filter', 'iconv', 'tokenizer', 'json'
|
||||||
];
|
];
|
||||||
|
|
||||||
const REQUIRED_PHP_VERSION = '8.1.0';
|
const REQUIRED_PHP_VERSION = '8.5.0';
|
||||||
const REQUIRED_SQLITE_VERSION = '3.34.0';
|
const REQUIRED_SQLITE_VERSION = '3.40.0';
|
||||||
|
|
||||||
class PrerequisiteChecker
|
class PrerequisiteChecker
|
||||||
{
|
{
|
||||||
|
|
@ -80,7 +83,7 @@ class PrerequisiteChecker
|
||||||
|
|
||||||
private function getSqlVersionAsString()
|
private function getSqlVersionAsString()
|
||||||
{
|
{
|
||||||
$dbh = new PDO('sqlite::memory:');
|
$dbh = new \PDO('sqlite::memory:');
|
||||||
return $dbh->query('select sqlite_version()')->fetch()[0];
|
return $dbh->query('select sqlite_version()')->fetch()[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
helpers/SlimBladeView.php
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Grocy\Helpers;
|
||||||
|
|
||||||
|
use Jenssegers\Blade\Blade;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
class SlimBladeView
|
||||||
|
{
|
||||||
|
public function __construct(string $viewPaths, string $cachePath)
|
||||||
|
{
|
||||||
|
$this->ViewPaths = $viewPaths;
|
||||||
|
$this->CachePath = $cachePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $ViewPaths;
|
||||||
|
protected $CachePath;
|
||||||
|
protected $ViewData = [];
|
||||||
|
|
||||||
|
public function render(ResponseInterface $response, string $template, array $data = [])
|
||||||
|
{
|
||||||
|
$data = array_merge($this->ViewData, $data);
|
||||||
|
$renderer = new Blade($this->ViewPaths, $this->CachePath, null);
|
||||||
|
$output = $renderer->make($template, $data)->render();
|
||||||
|
|
||||||
|
$response->getBody()->write($output);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value)
|
||||||
|
{
|
||||||
|
$this->ViewData[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -262,3 +262,19 @@ function require_frontend_packages(array $packages)
|
||||||
|
|
||||||
$GROCY_REQUIRED_FRONTEND_PACKAGES = array_unique(array_merge($GROCY_REQUIRED_FRONTEND_PACKAGES, $packages));
|
$GROCY_REQUIRED_FRONTEND_PACKAGES = array_unique(array_merge($GROCY_REQUIRED_FRONTEND_PACKAGES, $packages));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function EmptyFolder($folderPath)
|
||||||
|
{
|
||||||
|
foreach (glob("{$folderPath}/*") as $item)
|
||||||
|
{
|
||||||
|
if (is_dir($item))
|
||||||
|
{
|
||||||
|
EmptyFolder($item);
|
||||||
|
rmdir($item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unlink($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
31
localization/bg_BG/chore_assignment_types.po
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Translators:
|
||||||
|
# Plamen Stoyanov <fireto@gmail.com>, 2020
|
||||||
|
# Dwight Schrute <rvelitchkov@gmail.com>, 2020
|
||||||
|
# Mihail Andreev, 2020
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
|
"PO-Revision-Date: 2019-09-17 10:45+0000\n"
|
||||||
|
"Last-Translator: Mihail Andreev, 2020\n"
|
||||||
|
"Language-Team: Bulgarian (Bulgaria) (https://app.transifex.com/grocy/teams/93189/bg_BG/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: bg_BG\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Domain: grocy/chore_assignment_types\n"
|
||||||
|
|
||||||
|
msgid "no-assignment"
|
||||||
|
msgstr "не-разпределен"
|
||||||
|
|
||||||
|
msgid "who-least-did-first"
|
||||||
|
msgstr "пръв-последния-направил"
|
||||||
|
|
||||||
|
msgid "random"
|
||||||
|
msgstr "случаен"
|
||||||
|
|
||||||
|
msgid "in-alphabetical-order"
|
||||||
|
msgstr "по-азбучен-ред"
|
||||||
39
localization/bg_BG/chore_period_types.po
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Translators:
|
||||||
|
# Plamen Stoyanov <fireto@gmail.com>, 2020
|
||||||
|
# Svetoslav Slavkov <contact@sslavkov.eu>, 2023
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"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: Svetoslav Slavkov <contact@sslavkov.eu>, 2023\n"
|
||||||
|
"Language-Team: Bulgarian (Bulgaria) (https://app.transifex.com/grocy/teams/93189/bg_BG/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: bg_BG\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Domain: grocy/chore_types\n"
|
||||||
|
|
||||||
|
msgid "manually"
|
||||||
|
msgstr "Ръчно"
|
||||||
|
|
||||||
|
msgid "daily"
|
||||||
|
msgstr "Ежедневно"
|
||||||
|
|
||||||
|
msgid "weekly"
|
||||||
|
msgstr "Ежеседмично"
|
||||||
|
|
||||||
|
msgid "monthly"
|
||||||
|
msgstr "Ежемесечно"
|
||||||
|
|
||||||
|
msgid "yearly"
|
||||||
|
msgstr "Ежегодно"
|
||||||
|
|
||||||
|
msgid "hourly"
|
||||||
|
msgstr "почасово"
|
||||||
|
|
||||||
|
msgid "adaptive"
|
||||||
|
msgstr "адаптивен"
|
||||||
84
localization/bg_BG/component_translations.po
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
# Translators:
|
||||||
|
# Bernd Bestel <bernd@berrnd.de>, 2025
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"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: Bernd Bestel <bernd@berrnd.de>, 2025\n"
|
||||||
|
"Language-Team: Bulgarian (Bulgaria) (https://app.transifex.com/grocy/teams/93189/bg_BG/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: bg_BG\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Domain: grocy/component_translations\n"
|
||||||
|
|
||||||
|
msgid "moment_locale"
|
||||||
|
msgstr "bg"
|
||||||
|
|
||||||
|
msgid "datatables_localization"
|
||||||
|
msgstr ""
|
||||||
|
"{\"processing\":\"Обработка на резултатите...\",\"lengthMenu\":\"Показване "
|
||||||
|
"на _MENU_ резултата\",\"zeroRecords\":\"Няма намерени "
|
||||||
|
"резултати\",\"info\":\"Показване на резултати от _START_ до _END_ от общо "
|
||||||
|
"_TOTAL_\",\"infoEmpty\":\"Показване на резултати от 0 до 0 от общо "
|
||||||
|
"0\",\"infoFiltered\":\"(филтрирани от общо _MAX_ "
|
||||||
|
"резултата)\",\"search\":\"Търсене:\",\"paginate\":{\"first\":\"Първа\",\"previous\":\"Предишна\",\"next\":\"Следваща\",\"last\":\"Последна\"},\"aria\":{\"sortAscending\":\"сортирай"
|
||||||
|
" възходящо\",\"sortDescending\":\"сортирай "
|
||||||
|
"низходящо\"},\"autoFill\":{\"cancel\":\"Oткажи\",\"fill\":\"Попълни всички "
|
||||||
|
"клетки с <i>%d<i></i></i>\",\"fillHorizontal\":\"Попълни хоризонтални "
|
||||||
|
"клетки\",\"fillVertical\":\"Попълни вертикални "
|
||||||
|
"клетки\"},\"searchBuilder\":{\"add\":\"Добави\",\"deleteTitle\":\"Изтрий "
|
||||||
|
"критериите за търсене\",\"clearAll\":\"Изчисти "
|
||||||
|
"всичко\",\"condition\":\"Правило\",\"conditions\":{\"array\":{\"contains\":\"Съдържа\",\"empty\":\"Празно\",\"equals\":\"Еднакво"
|
||||||
|
" с\",\"not\":\"Различно от\",\"notEmpty\":\"Не е "
|
||||||
|
"празно\",\"without\":\"Без\"},\"date\":{\"after\":\"След\",\"before\":\"Преди\",\"between\":\"Между\",\"empty\":\"Празно\",\"equals\":\"Равна"
|
||||||
|
" на\",\"not\":\"Различна от\",\"notBetween\":\"Не е "
|
||||||
|
"между\",\"notEmpty\":\"Не е "
|
||||||
|
"празно\"},\"number\":{\"between\":\"Между\",\"empty\":\"Празно\",\"equals\":\"Равно\",\"gt\":\"Над\",\"gte\":\"Над"
|
||||||
|
" или равно\",\"lt\":\"Под\",\"lte\":\"Под или равно\",\"not\":\"Различно "
|
||||||
|
"от\",\"notBetween\":\"Не е между\",\"notEmpty\":\"Не е "
|
||||||
|
"празно\"},\"string\":{\"contains\":\"Съдържа\",\"empty\":\"Празно\",\"endsWith\":\"Завършва"
|
||||||
|
" с\",\"equals\":\"Еднакво с\",\"not\":\"Различно от\",\"notEmpty\":\"Не е "
|
||||||
|
"празно\",\"startsWith\":\"Започва "
|
||||||
|
"с\"}},\"data\":\"Поле\",\"logicAnd\":\"И\",\"logicOr\":\"Или\",\"value\":\"Стойност\"},\"searchPanes\":{\"clearMessage\":\"Изтрий"
|
||||||
|
" всички\",\"emptyPanes\":\"Няма "
|
||||||
|
"SearchPanes\",\"loadMessage\":\"Зареждане...\",\"title\":\"Активни филтри - "
|
||||||
|
"%d\"},\"buttons\":{\"collection\":\"Колекция\",\"colvis\":\"Показване/Скриване"
|
||||||
|
" на колони\",\"colvisRestore\":\"Показване на всички "
|
||||||
|
"колони\",\"copy\":\"Копиране\",\"copyKeys\":\"Натисни <i>ctrl или u2318 + C "
|
||||||
|
"за да копираш данните от таблицата.<br /> За да отмените, щракнете върху "
|
||||||
|
"това съобщение или натиснете "
|
||||||
|
"<i>escape</i>.</i>\",\"copySuccess\":{\"1\":\"Копиран един "
|
||||||
|
"ред\",\"_\":\"Копирани %ds реда\"},\"copyTitle\":\"Копиране в "
|
||||||
|
"буфера\",\"pageLength\":{\"_\":\"Покажи %d реда\",\"-1\":\"Покажи всички "
|
||||||
|
"редове\"},\"print\":\"Принтиране\"},\"datetime\":{\"hours\":\"Часове\",\"minutes\":\"Минути\",\"months\":{\"0\":\"Януари\",\"1\":\"Февруари\",\"2\":\"Март\",\"3\":\"Април\",\"4\":\"Май\",\"5\":\"Юни\",\"6\":\"Юли\",\"7\":\"Август\",\"8\":\"Септември\",\"9\":\"Октомври\",\"10\":\"Ноември\",\"11\":\"Декември\"},\"next\":\"Напред\",\"previous\":\"Назад\",\"seconds\":\"Секунди\",\"weekdays\":[\"Нед\",\"Пон\",\"Вт\",\"Ср\",\"Четв\",\"Пет\",\"Съб\"]},\"editor\":{\"close\":\"Затвори\",\"create\":{\"button\":\"Нов"
|
||||||
|
" запис\",\"submit\":\"Създай\",\"title\":\"Създай нов "
|
||||||
|
"запис\"},\"edit\":{\"button\":\"Промени\",\"submit\":\"Промени\",\"title\":\"Промени"
|
||||||
|
" запис\"},\"error\":{\"system\":\"Грешка в "
|
||||||
|
"системата!\"},\"multi\":{\"info\":\"Избраните елементи съдържат различни "
|
||||||
|
"стойности за това поле. За да редактирате и зададете всички елементи за това"
|
||||||
|
" поле на една и съща стойност, щракнете или докоснете тук, в противен случай"
|
||||||
|
" те ще запазят своите индивидуални стойности.\",\"noMulti\":\"Това полеможе "
|
||||||
|
"да се редактира индивидуално, но не е част от група.\",\"restore\":\"Отмяна "
|
||||||
|
"на промените\",\"title\":\"Множество "
|
||||||
|
"стойности\"},\"remove\":{\"button\":\"Изтрий\",\"confirm\":{\"1\":\"Сигурни "
|
||||||
|
"ли сте, че искате да изтриете 1 ред?\",\"_\":\"Сигурни ли сте, че искате да "
|
||||||
|
"изтриете %d реда?\"},\"submit\":\"Изтрий\",\"title\":\"Изтрий "
|
||||||
|
"запис\"}},\"emptyTable\":\"Няма налични данни в "
|
||||||
|
"таблицата\",\"loadingRecords\":\"Зареждане...\",\"select\":{\"cells\":{\"1\":\"%d"
|
||||||
|
" избрана клетка\",\"_\":\"%d избрани клетки\"},\"columns\":{\"1\":\"%d "
|
||||||
|
"избрана колона\",\"_\":\"%d избрани колони\"},\"rows\":{\"1\":\"%d избран "
|
||||||
|
"ред\",\"_\":\"%d избрани реда\"}}}"
|
||||||
|
|
||||||
|
msgid "summernote_locale"
|
||||||
|
msgstr "bg-BG"
|
||||||
|
|
||||||
|
msgid "fullcalendar_locale"
|
||||||
|
msgstr "bg"
|
||||||
|
|
||||||
|
msgid "bootstrap-select_locale"
|
||||||
|
msgstr "bg_BG"
|
||||||
417
localization/bg_BG/demo_data.po
Normal file
|
|
@ -0,0 +1,417 @@
|
||||||
|
# Translators:
|
||||||
|
# Plamen Stoyanov <fireto@gmail.com>, 2020
|
||||||
|
# Mihail Andreev, 2020
|
||||||
|
# Steliyan Stoyanov, 2025
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"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: Steliyan Stoyanov, 2025\n"
|
||||||
|
"Language-Team: Bulgarian (Bulgaria) (https://app.transifex.com/grocy/teams/93189/bg_BG/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: bg_BG\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Domain: grocy/demo_data\n"
|
||||||
|
|
||||||
|
msgid "Cookies"
|
||||||
|
msgstr "Бисквити"
|
||||||
|
|
||||||
|
msgid "Chocolate"
|
||||||
|
msgstr "Шоколад"
|
||||||
|
|
||||||
|
msgid "Pantry"
|
||||||
|
msgstr "Килер"
|
||||||
|
|
||||||
|
msgid "Candy cupboard"
|
||||||
|
msgstr "Шкаф за бонбони"
|
||||||
|
|
||||||
|
msgid "Tinned food cupboard"
|
||||||
|
msgstr "Шкаф за консерви"
|
||||||
|
|
||||||
|
msgid "Fridge"
|
||||||
|
msgstr "Хладилник"
|
||||||
|
|
||||||
|
msgid "Piece"
|
||||||
|
msgid_plural "Pieces"
|
||||||
|
msgstr[0] "Брой"
|
||||||
|
msgstr[1] "Броя"
|
||||||
|
|
||||||
|
msgid "Pack"
|
||||||
|
msgid_plural "Packs"
|
||||||
|
msgstr[0] "Опаковка"
|
||||||
|
msgstr[1] "Опаковки"
|
||||||
|
|
||||||
|
msgid "Glass"
|
||||||
|
msgid_plural "Glasses"
|
||||||
|
msgstr[0] "Чаша"
|
||||||
|
msgstr[1] "Чаши"
|
||||||
|
|
||||||
|
msgid "Tin"
|
||||||
|
msgid_plural "Tins"
|
||||||
|
msgstr[0] "Консерва"
|
||||||
|
msgstr[1] "Консерви"
|
||||||
|
|
||||||
|
msgid "Can"
|
||||||
|
msgid_plural "Cans"
|
||||||
|
msgstr[0] "Кен"
|
||||||
|
msgstr[1] "Кена"
|
||||||
|
|
||||||
|
msgid "Bunch"
|
||||||
|
msgid_plural "Bunches"
|
||||||
|
msgstr[0] "Куп"
|
||||||
|
msgstr[1] "Куп"
|
||||||
|
|
||||||
|
msgid "Gummy bears"
|
||||||
|
msgstr "Гумени мечета"
|
||||||
|
|
||||||
|
msgid "Crisps"
|
||||||
|
msgstr "Чипс"
|
||||||
|
|
||||||
|
msgid "Eggs"
|
||||||
|
msgstr "Яйца"
|
||||||
|
|
||||||
|
msgid "Noodles"
|
||||||
|
msgstr "Юфка"
|
||||||
|
|
||||||
|
msgid "Pickles"
|
||||||
|
msgstr "Туршия"
|
||||||
|
|
||||||
|
msgid "Gulash soup"
|
||||||
|
msgstr "Супа гулаш"
|
||||||
|
|
||||||
|
msgid "Yogurt"
|
||||||
|
msgstr "Кисело мляко"
|
||||||
|
|
||||||
|
msgid "Cheese"
|
||||||
|
msgstr "Сирене"
|
||||||
|
|
||||||
|
msgid "Cold cuts"
|
||||||
|
msgstr "Сухи мезета"
|
||||||
|
|
||||||
|
msgid "Paprika"
|
||||||
|
msgstr "Пипер"
|
||||||
|
|
||||||
|
msgid "Cucumber"
|
||||||
|
msgstr "Краставица"
|
||||||
|
|
||||||
|
msgid "Radish"
|
||||||
|
msgstr "Ряпа"
|
||||||
|
|
||||||
|
msgid "Tomato"
|
||||||
|
msgstr "Домати"
|
||||||
|
|
||||||
|
msgid "Change towels in the bathroom"
|
||||||
|
msgstr "Смени кърпите в банята"
|
||||||
|
|
||||||
|
msgid "Mop the kitchen floor"
|
||||||
|
msgstr "Избършете пода в кухнята"
|
||||||
|
|
||||||
|
msgid "Warranty ends"
|
||||||
|
msgstr "Край на гаранцията"
|
||||||
|
|
||||||
|
msgid "TV remote control"
|
||||||
|
msgstr "Дистанционно за телевизор"
|
||||||
|
|
||||||
|
msgid "Alarm clock"
|
||||||
|
msgstr "Будилник"
|
||||||
|
|
||||||
|
msgid "Heat remote control"
|
||||||
|
msgstr "Дистанционно за термостат"
|
||||||
|
|
||||||
|
msgid "Take out the trash"
|
||||||
|
msgstr "Изхвърлете боклука"
|
||||||
|
|
||||||
|
msgid "Some good snacks"
|
||||||
|
msgstr "Хубави закуски"
|
||||||
|
|
||||||
|
msgid "Pizza dough"
|
||||||
|
msgstr "Тесто за пица"
|
||||||
|
|
||||||
|
msgid "Sieved tomatoes"
|
||||||
|
msgstr "Пасирани домати"
|
||||||
|
|
||||||
|
msgid "Salami"
|
||||||
|
msgstr "Салам"
|
||||||
|
|
||||||
|
msgid "Toast"
|
||||||
|
msgstr "Хляб за тост"
|
||||||
|
|
||||||
|
msgid "Minced meat"
|
||||||
|
msgstr "Кайма"
|
||||||
|
|
||||||
|
msgid "Pizza"
|
||||||
|
msgstr "Пица"
|
||||||
|
|
||||||
|
msgid "Spaghetti bolognese"
|
||||||
|
msgstr "Спагети болонезе"
|
||||||
|
|
||||||
|
msgid "Sandwiches"
|
||||||
|
msgstr "Сандвичи"
|
||||||
|
|
||||||
|
msgid "English"
|
||||||
|
msgstr "Английски"
|
||||||
|
|
||||||
|
msgid "German"
|
||||||
|
msgstr "Немски"
|
||||||
|
|
||||||
|
msgid "Italian"
|
||||||
|
msgstr "Италиански"
|
||||||
|
|
||||||
|
msgid "This is the note content of the recipe ingredient"
|
||||||
|
msgstr "Това е съдържанието на бележката за съставката на рецептата"
|
||||||
|
|
||||||
|
msgid "Demo User"
|
||||||
|
msgstr "Демо потребител"
|
||||||
|
|
||||||
|
msgid "Gram"
|
||||||
|
msgid_plural "Grams"
|
||||||
|
msgstr[0] "Грам"
|
||||||
|
msgstr[1] "Грама"
|
||||||
|
|
||||||
|
msgid "Flour"
|
||||||
|
msgstr "Брашно"
|
||||||
|
|
||||||
|
msgid "Pancakes"
|
||||||
|
msgstr "Палачинки"
|
||||||
|
|
||||||
|
msgid "Sugar"
|
||||||
|
msgstr "Захар"
|
||||||
|
|
||||||
|
msgid "Sweets"
|
||||||
|
msgstr "Сладкиши"
|
||||||
|
|
||||||
|
msgid "Bakery products"
|
||||||
|
msgstr "Хлебни продукти"
|
||||||
|
|
||||||
|
msgid "Tinned food"
|
||||||
|
msgstr "Консерва"
|
||||||
|
|
||||||
|
msgid "Butchery products"
|
||||||
|
msgstr "Месни продукти"
|
||||||
|
|
||||||
|
msgid "Vegetables/Fruits"
|
||||||
|
msgstr "Зеленчуци/Плодове"
|
||||||
|
|
||||||
|
msgid "Refrigerated products"
|
||||||
|
msgstr "Охладени продукти"
|
||||||
|
|
||||||
|
msgid "Coffee machine"
|
||||||
|
msgstr "Кафе машина"
|
||||||
|
|
||||||
|
msgid "Dishwasher"
|
||||||
|
msgstr "Съдомиялна"
|
||||||
|
|
||||||
|
msgid "Liter"
|
||||||
|
msgstr "Литър"
|
||||||
|
|
||||||
|
msgid "Liters"
|
||||||
|
msgstr "Литри"
|
||||||
|
|
||||||
|
msgid "Bottle"
|
||||||
|
msgstr "Бутилка"
|
||||||
|
|
||||||
|
msgid "Bottles"
|
||||||
|
msgstr "Бутилки"
|
||||||
|
|
||||||
|
msgid "Milk"
|
||||||
|
msgstr "Мляко"
|
||||||
|
|
||||||
|
msgid "Chocolate sauce"
|
||||||
|
msgstr "Шоколадов сос"
|
||||||
|
|
||||||
|
msgid "Milliliters"
|
||||||
|
msgstr "Милилитри"
|
||||||
|
|
||||||
|
msgid "Milliliter"
|
||||||
|
msgstr "Милилитър"
|
||||||
|
|
||||||
|
msgid "Bottom"
|
||||||
|
msgstr "Дъно"
|
||||||
|
|
||||||
|
msgid "Topping"
|
||||||
|
msgstr "Топинг"
|
||||||
|
|
||||||
|
msgid "French"
|
||||||
|
msgstr "Френски"
|
||||||
|
|
||||||
|
msgid "Turkish"
|
||||||
|
msgstr "Турски"
|
||||||
|
|
||||||
|
msgid "Spanish"
|
||||||
|
msgstr "Испански"
|
||||||
|
|
||||||
|
msgid "Russian"
|
||||||
|
msgstr "Руски"
|
||||||
|
|
||||||
|
msgid "Vacuum the living room floor"
|
||||||
|
msgstr "Почистете пода с прахосмукачка в хола"
|
||||||
|
|
||||||
|
msgid "Clean the litter box"
|
||||||
|
msgstr "Почистете кутията за отпадъци"
|
||||||
|
|
||||||
|
msgid "Change the bed sheets"
|
||||||
|
msgstr "Смени чаршафите"
|
||||||
|
|
||||||
|
msgid "Swedish"
|
||||||
|
msgstr "Шведски"
|
||||||
|
|
||||||
|
msgid "Polish"
|
||||||
|
msgstr "Полски"
|
||||||
|
|
||||||
|
msgid "Milk Chocolate"
|
||||||
|
msgstr "Млечен шоколад"
|
||||||
|
|
||||||
|
msgid "Dark Chocolate"
|
||||||
|
msgstr "Тъмен шоколад"
|
||||||
|
|
||||||
|
msgid "Slice"
|
||||||
|
msgid_plural "Slices"
|
||||||
|
msgstr[0] "Резън"
|
||||||
|
msgstr[1] "Резъни"
|
||||||
|
|
||||||
|
msgid "Example userentity"
|
||||||
|
msgstr "Пример за ползване"
|
||||||
|
|
||||||
|
msgid "This is an example user entity..."
|
||||||
|
msgstr "Това е примерен потребителски запис..."
|
||||||
|
|
||||||
|
msgid "Custom field"
|
||||||
|
msgstr "Персонализирано поле"
|
||||||
|
|
||||||
|
msgid "Example field value..."
|
||||||
|
msgstr "Примерна стойност на полето..."
|
||||||
|
|
||||||
|
msgid "Waffle rolls"
|
||||||
|
msgstr "Вафлени рула"
|
||||||
|
|
||||||
|
msgid "Danish"
|
||||||
|
msgstr "Датски"
|
||||||
|
|
||||||
|
msgid "Dutch"
|
||||||
|
msgstr "Холандски"
|
||||||
|
|
||||||
|
msgid "Norwegian"
|
||||||
|
msgstr "Норвежки"
|
||||||
|
|
||||||
|
msgid "Demo"
|
||||||
|
msgstr "Демонстрация"
|
||||||
|
|
||||||
|
msgid "Stable version"
|
||||||
|
msgstr "Стабилна версия"
|
||||||
|
|
||||||
|
msgid "Preview version"
|
||||||
|
msgstr "Предварителна версия"
|
||||||
|
|
||||||
|
msgid "current release"
|
||||||
|
msgstr "текущо издание"
|
||||||
|
|
||||||
|
msgid "not yet released"
|
||||||
|
msgstr "още не издадено"
|
||||||
|
|
||||||
|
msgid "Portuguese (Brazil)"
|
||||||
|
msgstr "Португалски (Бразилия)"
|
||||||
|
|
||||||
|
msgid "This is a note"
|
||||||
|
msgstr "Това е бележка"
|
||||||
|
|
||||||
|
msgid "Freezer"
|
||||||
|
msgstr "Фризер"
|
||||||
|
|
||||||
|
msgid "Hungarian"
|
||||||
|
msgstr "Унгарски"
|
||||||
|
|
||||||
|
msgid "Slovak"
|
||||||
|
msgstr "Словашки"
|
||||||
|
|
||||||
|
msgid "Czech"
|
||||||
|
msgstr "Чехия"
|
||||||
|
|
||||||
|
msgid "Portuguese (Portugal)"
|
||||||
|
msgstr "Португалски (Португалия)"
|
||||||
|
|
||||||
|
# Use a in your country well known supermarket name
|
||||||
|
msgid "DemoSupermarket1"
|
||||||
|
msgstr "ДемоСупермаркет1"
|
||||||
|
|
||||||
|
# Use a in your country well known supermarket name
|
||||||
|
msgid "DemoSupermarket2"
|
||||||
|
msgstr "ТестовСупермаркет2"
|
||||||
|
|
||||||
|
msgid "Japanese"
|
||||||
|
msgstr "Японски"
|
||||||
|
|
||||||
|
msgid "Chinese (Taiwan)"
|
||||||
|
msgstr "Китайски (Тайван)"
|
||||||
|
|
||||||
|
msgid "Greek"
|
||||||
|
msgstr "гръцки"
|
||||||
|
|
||||||
|
msgid "Korean"
|
||||||
|
msgstr "корейски"
|
||||||
|
|
||||||
|
msgid "Chinese (China)"
|
||||||
|
msgstr "Китайски (China)"
|
||||||
|
|
||||||
|
msgid "Hebrew (Israel)"
|
||||||
|
msgstr "Иврит (Israel)"
|
||||||
|
|
||||||
|
msgid "Tamil"
|
||||||
|
msgstr "Тамилски"
|
||||||
|
|
||||||
|
msgid "Finnish"
|
||||||
|
msgstr "Финландски"
|
||||||
|
|
||||||
|
msgid "Breakfast"
|
||||||
|
msgstr "Закуска"
|
||||||
|
|
||||||
|
msgid "Lunch"
|
||||||
|
msgstr "Обяд"
|
||||||
|
|
||||||
|
msgid "Dinner"
|
||||||
|
msgstr "Вечеря"
|
||||||
|
|
||||||
|
msgid "Catalan"
|
||||||
|
msgstr "Каталонски"
|
||||||
|
|
||||||
|
msgid "Slovenian"
|
||||||
|
msgstr "Словенски"
|
||||||
|
|
||||||
|
msgid "Lithuanian"
|
||||||
|
msgstr "Литовски"
|
||||||
|
|
||||||
|
msgid "Ukrainian"
|
||||||
|
msgstr "Украински"
|
||||||
|
|
||||||
|
msgid "Kilogram"
|
||||||
|
msgid_plural "Kilograms"
|
||||||
|
msgstr[0] "килограм"
|
||||||
|
msgstr[1] "Килограми"
|
||||||
|
|
||||||
|
msgid "Romanian"
|
||||||
|
msgstr "Румънски"
|
||||||
|
|
||||||
|
msgid "Pint"
|
||||||
|
msgstr "Закачено"
|
||||||
|
|
||||||
|
msgid "Beverages"
|
||||||
|
msgstr "Напитки"
|
||||||
|
|
||||||
|
msgid "Ice Cream"
|
||||||
|
msgstr "Сладолед"
|
||||||
|
|
||||||
|
msgid "Soda"
|
||||||
|
msgstr "Газирана вода"
|
||||||
|
|
||||||
|
msgid "Beer"
|
||||||
|
msgstr "Бира"
|
||||||
|
|
||||||
|
msgid "Estonian"
|
||||||
|
msgstr "Естонски"
|
||||||
|
|
||||||
|
msgid "Bulgarian"
|
||||||
|
msgstr ""
|
||||||
150
localization/bg_BG/locales.po
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
# Translators:
|
||||||
|
# Mihail Andreev, 2020
|
||||||
|
# N T, 2025
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"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: N T, 2025\n"
|
||||||
|
"Language-Team: Bulgarian (Bulgaria) (https://app.transifex.com/grocy/teams/93189/bg_BG/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: bg_BG\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Domain: grocy/locales\n"
|
||||||
|
|
||||||
|
# Czech
|
||||||
|
msgid "cs"
|
||||||
|
msgstr "cs"
|
||||||
|
|
||||||
|
# Danish
|
||||||
|
msgid "da"
|
||||||
|
msgstr "da"
|
||||||
|
|
||||||
|
# German
|
||||||
|
msgid "de"
|
||||||
|
msgstr "de"
|
||||||
|
|
||||||
|
# Greek
|
||||||
|
msgid "el_GR"
|
||||||
|
msgstr "el_GR"
|
||||||
|
|
||||||
|
# English
|
||||||
|
msgid "en"
|
||||||
|
msgstr "en"
|
||||||
|
|
||||||
|
# English (Great Britain)
|
||||||
|
msgid "en_GB"
|
||||||
|
msgstr "en_GB"
|
||||||
|
|
||||||
|
# Spanish
|
||||||
|
msgid "es"
|
||||||
|
msgstr "es"
|
||||||
|
|
||||||
|
# French
|
||||||
|
msgid "fr"
|
||||||
|
msgstr "fr"
|
||||||
|
|
||||||
|
# Hungarian
|
||||||
|
msgid "hu"
|
||||||
|
msgstr "hu"
|
||||||
|
|
||||||
|
# Italian
|
||||||
|
msgid "it"
|
||||||
|
msgstr "it"
|
||||||
|
|
||||||
|
# Japanese
|
||||||
|
msgid "ja"
|
||||||
|
msgstr "ja"
|
||||||
|
|
||||||
|
# Korean
|
||||||
|
msgid "ko_KR"
|
||||||
|
msgstr "ko_KR"
|
||||||
|
|
||||||
|
# Dutch
|
||||||
|
msgid "nl"
|
||||||
|
msgstr "nl"
|
||||||
|
|
||||||
|
# Norwegian
|
||||||
|
msgid "no"
|
||||||
|
msgstr "no"
|
||||||
|
|
||||||
|
# Polish
|
||||||
|
msgid "pl"
|
||||||
|
msgstr "pl"
|
||||||
|
|
||||||
|
# Portuguese (Brazil)
|
||||||
|
msgid "pt_BR"
|
||||||
|
msgstr "pt_BR"
|
||||||
|
|
||||||
|
# Portuguese (Portugal)
|
||||||
|
msgid "pt_PT"
|
||||||
|
msgstr "pt_PT"
|
||||||
|
|
||||||
|
# Russian
|
||||||
|
msgid "ru"
|
||||||
|
msgstr "ru"
|
||||||
|
|
||||||
|
# Slovak
|
||||||
|
msgid "sk_SK"
|
||||||
|
msgstr "sk_SK"
|
||||||
|
|
||||||
|
# Slovenian
|
||||||
|
msgid "sl"
|
||||||
|
msgstr "sl"
|
||||||
|
|
||||||
|
# Swedish
|
||||||
|
msgid "sv_SE"
|
||||||
|
msgstr "sv_SE"
|
||||||
|
|
||||||
|
# Turkish
|
||||||
|
msgid "tr"
|
||||||
|
msgstr "tr"
|
||||||
|
|
||||||
|
# Chinese (Taiwan)
|
||||||
|
msgid "zh_TW"
|
||||||
|
msgstr "zh_TW"
|
||||||
|
|
||||||
|
# Chinese (China)
|
||||||
|
msgid "zh_CN"
|
||||||
|
msgstr "zh_CN"
|
||||||
|
|
||||||
|
# Hebrew (Israel)
|
||||||
|
msgid "he_IL"
|
||||||
|
msgstr "he_IL"
|
||||||
|
|
||||||
|
# Tamil
|
||||||
|
msgid "ta"
|
||||||
|
msgstr "ta"
|
||||||
|
|
||||||
|
# Finnish
|
||||||
|
msgid "fi"
|
||||||
|
msgstr "fi"
|
||||||
|
|
||||||
|
# Catalan
|
||||||
|
msgid "ca"
|
||||||
|
msgstr "ca"
|
||||||
|
|
||||||
|
# Lithuanian
|
||||||
|
msgid "lt"
|
||||||
|
msgstr "lt"
|
||||||
|
|
||||||
|
# Ukrainian
|
||||||
|
msgid "uk"
|
||||||
|
msgstr "uk"
|
||||||
|
|
||||||
|
# Romanian
|
||||||
|
msgid "ro_RO"
|
||||||
|
msgstr "ro_RO"
|
||||||
|
|
||||||
|
# Estonian
|
||||||
|
msgid "et_EE"
|
||||||
|
msgstr "et_EE"
|
||||||
|
|
||||||
|
# Bulgarian
|
||||||
|
msgid "bg_BG"
|
||||||
|
msgstr ""
|
||||||
137
localization/bg_BG/permissions.po
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
# Translators:
|
||||||
|
# Mihail Andreev, 2020
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
|
"PO-Revision-Date: 2020-08-29 16:33+0000\n"
|
||||||
|
"Last-Translator: Mihail Andreev, 2020\n"
|
||||||
|
"Language-Team: Bulgarian (Bulgaria) (https://app.transifex.com/grocy/teams/93189/bg_BG/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: bg_BG\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Domain: grocy/permissions\n"
|
||||||
|
|
||||||
|
# All permissions
|
||||||
|
msgid "ADMIN"
|
||||||
|
msgstr "ADMIN"
|
||||||
|
|
||||||
|
# Create users
|
||||||
|
msgid "USERS_CREATE"
|
||||||
|
msgstr "USERS_CREATE"
|
||||||
|
|
||||||
|
# Edit users (including passwords)
|
||||||
|
msgid "USERS_EDIT"
|
||||||
|
msgstr "USERS_EDIT"
|
||||||
|
|
||||||
|
# Show users
|
||||||
|
msgid "USERS_READ"
|
||||||
|
msgstr "USERS_READ"
|
||||||
|
|
||||||
|
# Edit own user data / change own password
|
||||||
|
msgid "USERS_EDIT_SELF"
|
||||||
|
msgstr "USERS_EDIT_SELF"
|
||||||
|
|
||||||
|
# Undo charge cycle
|
||||||
|
msgid "BATTERIES_UNDO_CHARGE_CYCLE"
|
||||||
|
msgstr "BATTERIES_UNDO_CHARGE_CYCLE"
|
||||||
|
|
||||||
|
# Track charge cycle
|
||||||
|
msgid "BATTERIES_TRACK_CHARGE_CYCLE"
|
||||||
|
msgstr "BATTERIES_TRACK_CHARGE_CYCLE"
|
||||||
|
|
||||||
|
# Track execution
|
||||||
|
msgid "CHORE_TRACK_EXECUTION"
|
||||||
|
msgstr "CHORE_TRACK_EXECUTION"
|
||||||
|
|
||||||
|
# Undo execution
|
||||||
|
msgid "CHORE_UNDO_EXECUTION"
|
||||||
|
msgstr "CHORE_UNDO_EXECUTION"
|
||||||
|
|
||||||
|
# Edit master data
|
||||||
|
msgid "MASTER_DATA_EDIT"
|
||||||
|
msgstr "MASTER_DATA_EDIT"
|
||||||
|
|
||||||
|
# Undo execution
|
||||||
|
msgid "TASKS_UNDO_EXECUTION"
|
||||||
|
msgstr "TASKS_UNDO_EXECUTION"
|
||||||
|
|
||||||
|
# Mark completed
|
||||||
|
msgid "TASKS_MARK_COMPLETED"
|
||||||
|
msgstr "TASKS_MARK_COMPLETED"
|
||||||
|
|
||||||
|
# Edit stock entries
|
||||||
|
msgid "STOCK_EDIT"
|
||||||
|
msgstr "STOCK_EDIT"
|
||||||
|
|
||||||
|
# Transfer
|
||||||
|
msgid "STOCK_TRANSFER"
|
||||||
|
msgstr "STOCK_TRANSFER"
|
||||||
|
|
||||||
|
# Inventory
|
||||||
|
msgid "STOCK_INVENTORY"
|
||||||
|
msgstr "STOCK_INVENTORY"
|
||||||
|
|
||||||
|
# Consume
|
||||||
|
msgid "STOCK_CONSUME"
|
||||||
|
msgstr "STOCK_CONSUME"
|
||||||
|
|
||||||
|
# Open products
|
||||||
|
msgid "STOCK_OPEN"
|
||||||
|
msgstr "STOCK_OPEN"
|
||||||
|
|
||||||
|
# Purchase
|
||||||
|
msgid "STOCK_PURCHASE"
|
||||||
|
msgstr "STOCK_PURCHASE"
|
||||||
|
|
||||||
|
# Add items
|
||||||
|
msgid "SHOPPINGLIST_ITEMS_ADD"
|
||||||
|
msgstr "SHOPPINGLIST_ITEMS_ADD"
|
||||||
|
|
||||||
|
# Remove items
|
||||||
|
msgid "SHOPPINGLIST_ITEMS_DELETE"
|
||||||
|
msgstr "SHOPPINGLIST_ITEMS_DELETE"
|
||||||
|
|
||||||
|
# User management
|
||||||
|
msgid "USERS"
|
||||||
|
msgstr "USERS"
|
||||||
|
|
||||||
|
# Stock
|
||||||
|
msgid "STOCK"
|
||||||
|
msgstr "STOCK"
|
||||||
|
|
||||||
|
# Shopping list
|
||||||
|
msgid "SHOPPINGLIST"
|
||||||
|
msgstr "SHOPPINGLIST"
|
||||||
|
|
||||||
|
# Chores
|
||||||
|
msgid "CHORES"
|
||||||
|
msgstr "CHORES"
|
||||||
|
|
||||||
|
# Batteries
|
||||||
|
msgid "BATTERIES"
|
||||||
|
msgstr "BATTERIES"
|
||||||
|
|
||||||
|
# Tasks
|
||||||
|
msgid "TASKS"
|
||||||
|
msgstr "TASKS"
|
||||||
|
|
||||||
|
# Recipes
|
||||||
|
msgid "RECIPES"
|
||||||
|
msgstr "RECIPES"
|
||||||
|
|
||||||
|
# Equipment
|
||||||
|
msgid "EQUIPMENT"
|
||||||
|
msgstr "EQUIPMENT"
|
||||||
|
|
||||||
|
# Calendar
|
||||||
|
msgid "CALENDAR"
|
||||||
|
msgstr "CALENDAR"
|
||||||
|
|
||||||
|
# Meal plan
|
||||||
|
msgid "RECIPES_MEALPLAN"
|
||||||
|
msgstr "RECIPES_MEALPLAN"
|
||||||
45
localization/bg_BG/stock_transaction_types.po
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Translators:
|
||||||
|
# Plamen Stoyanov <fireto@gmail.com>, 2020
|
||||||
|
# Mihail Andreev, 2020
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"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: Mihail Andreev, 2020\n"
|
||||||
|
"Language-Team: Bulgarian (Bulgaria) (https://app.transifex.com/grocy/teams/93189/bg_BG/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: bg_BG\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Domain: grocy/stock_transaction_types\n"
|
||||||
|
|
||||||
|
msgid "purchase"
|
||||||
|
msgstr "покупка"
|
||||||
|
|
||||||
|
msgid "transfer_from"
|
||||||
|
msgstr "прехвърли_от"
|
||||||
|
|
||||||
|
msgid "transfer_to"
|
||||||
|
msgstr "прехвъли_към"
|
||||||
|
|
||||||
|
msgid "consume"
|
||||||
|
msgstr "консумирай"
|
||||||
|
|
||||||
|
msgid "inventory-correction"
|
||||||
|
msgstr "корекция-инвентаризация"
|
||||||
|
|
||||||
|
msgid "product-opened"
|
||||||
|
msgstr "отворен-продукт"
|
||||||
|
|
||||||
|
msgid "stock-edit-old"
|
||||||
|
msgstr "наличност-промяна-стар"
|
||||||
|
|
||||||
|
msgid "stock-edit-new"
|
||||||
|
msgstr "наличност-промяна-нов"
|
||||||
|
|
||||||
|
msgid "self-production"
|
||||||
|
msgstr "домашна-продукция"
|
||||||
2839
localization/bg_BG/strings.po
Normal file
75
localization/bg_BG/userfield_types.po
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
# Translators:
|
||||||
|
# Plamen Stoyanov <fireto@gmail.com>, 2020
|
||||||
|
# Mihail Andreev, 2020
|
||||||
|
# Steliyan Stoyanov, 2025
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
|
"PO-Revision-Date: 2019-05-01 17:43+0000\n"
|
||||||
|
"Last-Translator: Steliyan Stoyanov, 2025\n"
|
||||||
|
"Language-Team: Bulgarian (Bulgaria) (https://app.transifex.com/grocy/teams/93189/bg_BG/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: bg_BG\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Domain: grocy/userfield_types\n"
|
||||||
|
|
||||||
|
# Text (single line)
|
||||||
|
msgid "text-single-line"
|
||||||
|
msgstr "текст-един-ред"
|
||||||
|
|
||||||
|
# Text (multi line)
|
||||||
|
msgid "text-multi-line"
|
||||||
|
msgstr "текст-няколко-реда"
|
||||||
|
|
||||||
|
# Number (integral)
|
||||||
|
msgid "number-integral"
|
||||||
|
msgstr "Число"
|
||||||
|
|
||||||
|
# Number (decimal)
|
||||||
|
msgid "number-decimal"
|
||||||
|
msgstr "число-цяло"
|
||||||
|
|
||||||
|
# Number (currency)
|
||||||
|
msgid "number-currency"
|
||||||
|
msgstr "Валута число"
|
||||||
|
|
||||||
|
# Date (without time)
|
||||||
|
msgid "date"
|
||||||
|
msgstr "дата"
|
||||||
|
|
||||||
|
# Date & time
|
||||||
|
msgid "datetime"
|
||||||
|
msgstr "момент"
|
||||||
|
|
||||||
|
# Checkbox
|
||||||
|
msgid "checkbox"
|
||||||
|
msgstr "чекбокс"
|
||||||
|
|
||||||
|
# Select list (a single item can be selected)
|
||||||
|
msgid "preset-list"
|
||||||
|
msgstr "предварително зададен списък"
|
||||||
|
|
||||||
|
# Select list (multiple items can be selected)
|
||||||
|
msgid "preset-checklist"
|
||||||
|
msgstr "предварително зададен избираем списък"
|
||||||
|
|
||||||
|
# Link
|
||||||
|
msgid "link"
|
||||||
|
msgstr "връзка"
|
||||||
|
|
||||||
|
# Link (with title)
|
||||||
|
msgid "link-with-title"
|
||||||
|
msgstr "Връзка със заглавие"
|
||||||
|
|
||||||
|
# File
|
||||||
|
msgid "file"
|
||||||
|
msgstr "файл"
|
||||||
|
|
||||||
|
# Image
|
||||||
|
msgid "image"
|
||||||
|
msgstr "изображение"
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# gimy16 <gimy16@hotmail.com>, 2021
|
# gimy16 <gimy16@hotmail.com>, 2021
|
||||||
# Carles Riera <blauigris@gmail.com>, 2022
|
# Carles Riera <blauigris@gmail.com>, 2022
|
||||||
|
# Auri, 2024
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -9,7 +9,7 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
"PO-Revision-Date: 2019-09-17 10:45+0000\n"
|
"PO-Revision-Date: 2019-09-17 10:45+0000\n"
|
||||||
"Last-Translator: Carles Riera <blauigris@gmail.com>, 2022\n"
|
"Last-Translator: Auri, 2024\n"
|
||||||
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|
@ -19,7 +19,7 @@ msgstr ""
|
||||||
"X-Domain: grocy/chore_assignment_types\n"
|
"X-Domain: grocy/chore_assignment_types\n"
|
||||||
|
|
||||||
msgid "no-assignment"
|
msgid "no-assignment"
|
||||||
msgstr "sense actius"
|
msgstr "no assignat"
|
||||||
|
|
||||||
msgid "who-least-did-first"
|
msgid "who-least-did-first"
|
||||||
msgstr "qui menys ha fet primer"
|
msgstr "qui menys ha fet primer"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Joan Rodas <joanrc93@gmail.com>, 2020
|
# Joan Rodas <joanrc93@gmail.com>, 2020
|
||||||
# gimy16 <gimy16@hotmail.com>, 2021
|
|
||||||
# Martí Gombau, 2023
|
# Martí Gombau, 2023
|
||||||
|
# Auri, 2024
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -10,7 +9,7 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||||
"Last-Translator: Martí Gombau, 2023\n"
|
"Last-Translator: Auri, 2024\n"
|
||||||
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|
@ -23,16 +22,16 @@ msgid "manually"
|
||||||
msgstr "manualment"
|
msgstr "manualment"
|
||||||
|
|
||||||
msgid "daily"
|
msgid "daily"
|
||||||
msgstr "diari"
|
msgstr "cada dia"
|
||||||
|
|
||||||
msgid "weekly"
|
msgid "weekly"
|
||||||
msgstr "setmanalment"
|
msgstr "cada setmana"
|
||||||
|
|
||||||
msgid "monthly"
|
msgid "monthly"
|
||||||
msgstr "mensual"
|
msgstr "cada mes"
|
||||||
|
|
||||||
msgid "yearly"
|
msgid "yearly"
|
||||||
msgstr "anual"
|
msgstr "cada any"
|
||||||
|
|
||||||
msgid "hourly"
|
msgid "hourly"
|
||||||
msgstr "cada hora"
|
msgstr "cada hora"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Bernd Bestel <bernd@berrnd.de>, 2022
|
# Bernd Bestel <bernd@berrnd.de>, 2022
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Joan Rodas <joanrc93@gmail.com>, 2020
|
# Joan Rodas <joanrc93@gmail.com>, 2020
|
||||||
# gimy16 <gimy16@hotmail.com>, 2021
|
# gimy16 <gimy16@hotmail.com>, 2021
|
||||||
# Martí Gombau, 2023
|
# Martí Gombau, 2023
|
||||||
|
# Auri, 2024
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -10,7 +10,7 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||||
"Last-Translator: Martí Gombau, 2023\n"
|
"Last-Translator: Auri, 2024\n"
|
||||||
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|
@ -397,19 +397,22 @@ msgid "Romanian"
|
||||||
msgstr "Romanès "
|
msgstr "Romanès "
|
||||||
|
|
||||||
msgid "Pint"
|
msgid "Pint"
|
||||||
msgstr ""
|
msgstr "Terrina/es"
|
||||||
|
|
||||||
msgid "Beverages"
|
msgid "Beverages"
|
||||||
msgstr ""
|
msgstr "Begudes"
|
||||||
|
|
||||||
msgid "Ice Cream"
|
msgid "Ice Cream"
|
||||||
msgstr ""
|
msgstr "Gelats"
|
||||||
|
|
||||||
msgid "Soda"
|
msgid "Soda"
|
||||||
msgstr ""
|
msgstr "Refresc"
|
||||||
|
|
||||||
msgid "Beer"
|
msgid "Beer"
|
||||||
msgstr ""
|
msgstr "Cervesa"
|
||||||
|
|
||||||
msgid "Estonian"
|
msgid "Estonian"
|
||||||
|
msgstr "Estonià"
|
||||||
|
|
||||||
|
msgid "Bulgarian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Martí Gombau, 2023
|
# Martí Gombau, 2023
|
||||||
|
# Auri, 2024
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -8,7 +8,7 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
"PO-Revision-Date: 2020-08-31 19:11+0000\n"
|
"PO-Revision-Date: 2020-08-31 19:11+0000\n"
|
||||||
"Last-Translator: Martí Gombau, 2023\n"
|
"Last-Translator: Auri, 2024\n"
|
||||||
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|
@ -143,4 +143,8 @@ msgstr "ro_RO"
|
||||||
|
|
||||||
# Estonian
|
# Estonian
|
||||||
msgid "et_EE"
|
msgid "et_EE"
|
||||||
|
msgstr "et_EE"
|
||||||
|
|
||||||
|
# Bulgarian
|
||||||
|
msgid "bg_BG"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# gimy16 <gimy16@hotmail.com>, 2021
|
# gimy16 <gimy16@hotmail.com>, 2021
|
||||||
# Martí Gombau, 2023
|
# Martí Gombau, 2023
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# gimy16 <gimy16@hotmail.com>, 2021
|
# gimy16 <gimy16@hotmail.com>, 2021
|
||||||
|
# Auri, 2024
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -8,7 +8,7 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||||
"Last-Translator: gimy16 <gimy16@hotmail.com>, 2021\n"
|
"Last-Translator: Auri, 2024\n"
|
||||||
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|
@ -36,10 +36,10 @@ msgid "product-opened"
|
||||||
msgstr "Producte_obert"
|
msgstr "Producte_obert"
|
||||||
|
|
||||||
msgid "stock-edit-old"
|
msgid "stock-edit-old"
|
||||||
msgstr "Edició_d'estoc_antic"
|
msgstr "edició-existència-antiga"
|
||||||
|
|
||||||
msgid "stock-edit-new"
|
msgid "stock-edit-new"
|
||||||
msgstr "Edició_d'estoc_nou"
|
msgstr "edició-existència-nova"
|
||||||
|
|
||||||
msgid "self-production"
|
msgid "self-production"
|
||||||
msgstr "Producció_pròpia"
|
msgstr "Producció_pròpia"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Joan Rodas <joanrc93@gmail.com>, 2020
|
# Joan Rodas <joanrc93@gmail.com>, 2020
|
||||||
# Carles Riera <blauigris@gmail.com>, 2021
|
# Carles Riera <blauigris@gmail.com>, 2021
|
||||||
# jorclaret, 2022
|
# jorclaret, 2022
|
||||||
# Martí Gombau, 2023
|
# Martí Gombau, 2023
|
||||||
|
# Auri, 2024
|
||||||
|
# Pau Nofuentes Sendra, 2024
|
||||||
|
# Roger Solé Vilajuliu, 2024
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -11,7 +13,7 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||||
"Last-Translator: Martí Gombau, 2023\n"
|
"Last-Translator: Roger Solé Vilajuliu, 2024\n"
|
||||||
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|
@ -129,7 +131,7 @@ msgid "Product overview"
|
||||||
msgstr "Resum de productes"
|
msgstr "Resum de productes"
|
||||||
|
|
||||||
msgid "Stock quantity unit"
|
msgid "Stock quantity unit"
|
||||||
msgstr "Unitat d'inventari"
|
msgstr "Unitat d'existències"
|
||||||
|
|
||||||
msgid "Stock amount"
|
msgid "Stock amount"
|
||||||
msgstr "Existències"
|
msgstr "Existències"
|
||||||
|
|
@ -213,7 +215,7 @@ msgid "Default quantity unit purchase"
|
||||||
msgstr "Unitat predeterminada"
|
msgstr "Unitat predeterminada"
|
||||||
|
|
||||||
msgid "Quantity unit stock"
|
msgid "Quantity unit stock"
|
||||||
msgstr "Unitat d'inventari"
|
msgstr "Unitat d'existències"
|
||||||
|
|
||||||
msgid "Create location"
|
msgid "Create location"
|
||||||
msgstr "Afegir ubicació"
|
msgstr "Afegir ubicació"
|
||||||
|
|
@ -281,8 +283,8 @@ msgstr "Clau d'accés"
|
||||||
msgid "Invalid credentials, please try again"
|
msgid "Invalid credentials, please try again"
|
||||||
msgstr "Credencials invàlides, sius-plau torna-ho a intentar"
|
msgstr "Credencials invàlides, sius-plau torna-ho a intentar"
|
||||||
|
|
||||||
msgid "Are you sure to delete battery \"%s\"?"
|
msgid "Are you sure you want to delete battery \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar la bateria \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Yes"
|
msgid "Yes"
|
||||||
msgstr "Sí"
|
msgstr "Sí"
|
||||||
|
|
@ -290,8 +292,8 @@ msgstr "Sí"
|
||||||
msgid "No"
|
msgid "No"
|
||||||
msgstr "No"
|
msgstr "No"
|
||||||
|
|
||||||
msgid "Are you sure to delete chore \"%s\"?"
|
msgid "Are you sure you want to delete chore \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar la feina de casa \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "\"%s\" could not be resolved to a product, how do you want to proceed?"
|
msgid "\"%s\" could not be resolved to a product, how do you want to proceed?"
|
||||||
msgstr "no s'ha pogut identificar com a producte, com vols procedir?"
|
msgstr "no s'ha pogut identificar com a producte, com vols procedir?"
|
||||||
|
|
@ -311,17 +313,17 @@ msgstr "Afegir com a codi de barres a un producte existent"
|
||||||
msgid "Add as new product and prefill barcode"
|
msgid "Add as new product and prefill barcode"
|
||||||
msgstr "Afegir com a nou producte amb el codi de barres"
|
msgstr "Afegir com a nou producte amb el codi de barres"
|
||||||
|
|
||||||
msgid "Are you sure to delete quantity unit \"%s\"?"
|
msgid "Are you sure you want to delete quantity unit \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar la unitat \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Are you sure to delete product \"%s\"?"
|
msgid "Are you sure you want to delete product \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar el producte \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Are you sure to delete location \"%s\"?"
|
msgid "Are you sure you want to delete location \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar la ubicació \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Are you sure to delete store \"%s\"?"
|
msgid "Are you sure you want to delete store \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar l'establiment \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Manage API keys"
|
msgid "Manage API keys"
|
||||||
msgstr "Gestiona les claus de l'API"
|
msgstr "Gestiona les claus de l'API"
|
||||||
|
|
@ -357,14 +359,11 @@ msgid "Removed %1$s of %2$s from stock"
|
||||||
msgstr "%1$s de %2$s eliminats de l'inventari"
|
msgstr "%1$s de %2$s eliminats de l'inventari"
|
||||||
|
|
||||||
msgid "About Grocy"
|
msgid "About Grocy"
|
||||||
msgstr ""
|
msgstr "Sobre Grocy"
|
||||||
|
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Tancar"
|
msgstr "Tancar"
|
||||||
|
|
||||||
msgid "Released on"
|
|
||||||
msgstr "Publicat el"
|
|
||||||
|
|
||||||
msgid "Added %1$s of %2$s to stock"
|
msgid "Added %1$s of %2$s to stock"
|
||||||
msgstr "%1$s de %2$s afegits a l'inventari"
|
msgstr "%1$s de %2$s afegits a l'inventari"
|
||||||
|
|
||||||
|
|
@ -437,14 +436,14 @@ msgstr "Afegir ingredient a la recepta"
|
||||||
msgid "Edit recipe ingredient"
|
msgid "Edit recipe ingredient"
|
||||||
msgstr "Editar ingredient de la recepta"
|
msgstr "Editar ingredient de la recepta"
|
||||||
|
|
||||||
msgid "Are you sure to delete recipe \"%s\"?"
|
msgid "Are you sure you want to delete recipe \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar la recepta \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Are you sure to delete recipe ingredient \"%s\"?"
|
msgid "Are you sure you want to delete recipe ingredient \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar l'ingredient \"%s\" de la recepta?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Are you sure to empty shopping list \"%s\"?"
|
msgid "Are you sure you want to empty shopping list \"%s\"?"
|
||||||
msgstr "Segur que vols buidar la llista de la compra \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Clear list"
|
msgid "Clear list"
|
||||||
msgstr "Buidar llista"
|
msgstr "Buidar llista"
|
||||||
|
|
@ -493,14 +492,9 @@ msgid "Put missing amount on shopping list"
|
||||||
msgstr "Afegeix els que falten a la llista de la compra"
|
msgstr "Afegeix els que falten a la llista de la compra"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure to put all missing ingredients for recipe \"%s\" on the "
|
"Are you sure you want to put all missing ingredients for recipe \"%s\" on "
|
||||||
"shopping list?"
|
"the shopping list?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Segur que vols afegir tots els ingredients que falten per a la recepta "
|
|
||||||
"\"%s\" a la llista de la compra?"
|
|
||||||
|
|
||||||
msgid "Added for recipe %s"
|
|
||||||
msgstr "Afegit per a la recepta %s"
|
|
||||||
|
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Gestiona els usuaris"
|
msgstr "Gestiona els usuaris"
|
||||||
|
|
@ -511,8 +505,8 @@ msgstr "Usuari"
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr "Usuaris"
|
msgstr "Usuaris"
|
||||||
|
|
||||||
msgid "Are you sure to delete user \"%s\"?"
|
msgid "Are you sure you want to delete user \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar l'usuari \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Create user"
|
msgid "Create user"
|
||||||
msgstr "Afegir usuari"
|
msgstr "Afegir usuari"
|
||||||
|
|
@ -608,15 +602,13 @@ msgid "Only check if any amount is in stock"
|
||||||
msgstr "Només comprovar si hi ha existències"
|
msgstr "Només comprovar si hi ha existències"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure to consume all ingredients needed by recipe \"%s\" (ingredients"
|
"Are you sure you want to consume all ingredients needed by recipe \"%s\" "
|
||||||
" marked with \"only check if any amount is in stock\" will be ignored)?"
|
"(ingredients marked with \"only check if any amount is in stock\" will be "
|
||||||
|
"ignored)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Segur que vols consumir tots els ingredients requerits per fer la recepta "
|
|
||||||
"\"%s\" (Els ingredients marcats amb \"només comprovar si hi ha "
|
|
||||||
"existències\") s'ignoraran?"
|
|
||||||
|
|
||||||
msgid "Removed all ingredients of recipe \"%s\" from stock"
|
msgid "Removed all in stock ingredients needed by recipe \"%s\" from stock"
|
||||||
msgstr " Tots els ingredients de la recepta \"%s\" s'han eliminat de l'inventari"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Consume all ingredients needed by this recipe"
|
msgid "Consume all ingredients needed by this recipe"
|
||||||
msgstr "Consumir tots els ingredients requerits per aquesta recepta"
|
msgstr "Consumir tots els ingredients requerits per aquesta recepta"
|
||||||
|
|
@ -666,8 +658,8 @@ msgstr "Categoria"
|
||||||
msgid "Edit task"
|
msgid "Edit task"
|
||||||
msgstr "Editar tasca"
|
msgstr "Editar tasca"
|
||||||
|
|
||||||
msgid "Are you sure to delete task \"%s\"?"
|
msgid "Are you sure you want to delete task \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar la tasca \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "%s task is due to be done"
|
msgid "%s task is due to be done"
|
||||||
msgid_plural "%s tasks are due to be done"
|
msgid_plural "%s tasks are due to be done"
|
||||||
|
|
@ -700,8 +692,8 @@ msgstr "Editar grup de productes"
|
||||||
msgid "Product group"
|
msgid "Product group"
|
||||||
msgstr "Grup de productes"
|
msgstr "Grup de productes"
|
||||||
|
|
||||||
msgid "Are you sure to delete product group \"%s\"?"
|
msgid "Are you sure you want to delete product group \"%s\"?"
|
||||||
msgstr "Estàs segur d'eliminar el grup de producte \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Stay logged in permanently"
|
msgid "Stay logged in permanently"
|
||||||
msgstr "Mantenir-se connectat permanentment"
|
msgstr "Mantenir-se connectat permanentment"
|
||||||
|
|
@ -855,6 +847,9 @@ msgid ""
|
||||||
"The first item in this list would be picked by the default rule consume rule"
|
"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)"
|
" (Opened first, then first due first, then first in first out)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"El primer element d'aquesta llista serà utilitzat per la regla de consum per"
|
||||||
|
" defecte (Primer l'obert, després el que caduca primer, després el primer "
|
||||||
|
"que entra el primer que surt)"
|
||||||
|
|
||||||
msgid "Mark %1$s of %2$s as open"
|
msgid "Mark %1$s of %2$s as open"
|
||||||
msgstr "Marcar %1$s de %2$s com a obert"
|
msgstr "Marcar %1$s de %2$s com a obert"
|
||||||
|
|
@ -869,7 +864,9 @@ msgid "Not opened"
|
||||||
msgstr "No obert"
|
msgstr "No obert"
|
||||||
|
|
||||||
msgid "Opened"
|
msgid "Opened"
|
||||||
msgstr "Obert"
|
msgid_plural "Opened"
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
msgid "%s opened"
|
msgid "%s opened"
|
||||||
msgstr "%s obert"
|
msgstr "%s obert"
|
||||||
|
|
@ -953,6 +950,10 @@ msgid ""
|
||||||
"always weigh the whole jar, the amount to be posted is then automatically "
|
"always weigh the whole jar, the amount to be posted is then automatically "
|
||||||
"calculated based on what is in stock and the tare weight defined below"
|
"calculated based on what is in stock and the tare weight defined below"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Això serà útil per exemple per a farina en pots - quan es "
|
||||||
|
"compra/consumeix/inventaria, sempre es pesa el pot sencer, la quantitat "
|
||||||
|
"final és calculada automàticament basat en la quantitat en existències i la "
|
||||||
|
"tara definida a continuació."
|
||||||
|
|
||||||
msgid "Tare weight"
|
msgid "Tare weight"
|
||||||
msgstr "Tara"
|
msgstr "Tara"
|
||||||
|
|
@ -1034,8 +1035,8 @@ msgstr "Configuració de tasques"
|
||||||
msgid "Create shopping list"
|
msgid "Create shopping list"
|
||||||
msgstr "Crear llista de la compra"
|
msgstr "Crear llista de la compra"
|
||||||
|
|
||||||
msgid "Are you sure to delete shopping list \"%s\"?"
|
msgid "Are you sure you want to delete shopping list \"%s\"?"
|
||||||
msgstr "Estàs segur d'eliminar la llista de la compra \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Average shelf life"
|
msgid "Average shelf life"
|
||||||
msgstr "Temps de vida mitjà de l'inventari"
|
msgstr "Temps de vida mitjà de l'inventari"
|
||||||
|
|
@ -1156,6 +1157,9 @@ msgid ""
|
||||||
"When this is not empty, it will be shown instead of the amount entered above"
|
"When this is not empty, it will be shown instead of the amount entered above"
|
||||||
" while the amount there will still be used for stock fulfillment checking"
|
" while the amount there will still be used for stock fulfillment checking"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Quan no estigui buit, es mostrarà enlloc de la quantitat introduïda a dalt. "
|
||||||
|
"La quantitat de dalt seguirà sent la utilitzada en les comprovacions "
|
||||||
|
"d'existències a l'inventari. "
|
||||||
|
|
||||||
msgid "Track date only"
|
msgid "Track date only"
|
||||||
msgstr "Només seguiment de data"
|
msgstr "Només seguiment de data"
|
||||||
|
|
@ -1169,7 +1173,7 @@ msgid "Consume %1$s of %2$s"
|
||||||
msgstr "Consumir %1$s de %2$s"
|
msgstr "Consumir %1$s de %2$s"
|
||||||
|
|
||||||
msgid "Meal plan"
|
msgid "Meal plan"
|
||||||
msgstr "Calendari de menús"
|
msgstr "Calendari d'àpats"
|
||||||
|
|
||||||
msgid "%s serving"
|
msgid "%s serving"
|
||||||
msgid_plural "%s servings"
|
msgid_plural "%s servings"
|
||||||
|
|
@ -1204,11 +1208,6 @@ msgstr "Mai"
|
||||||
msgid "Today"
|
msgid "Today"
|
||||||
msgstr "Avui"
|
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"
|
msgid "Undo task"
|
||||||
msgstr "Desfer tasca"
|
msgstr "Desfer tasca"
|
||||||
|
|
||||||
|
|
@ -1219,6 +1218,8 @@ msgid ""
|
||||||
"When enabled the chore can never be overdue, the due date will shift forward"
|
"When enabled the chore can never be overdue, the due date will shift forward"
|
||||||
" each day when due"
|
" each day when due"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Quan s'activa, la tasca no pot vèncer mai, la dada de venciment és moure un "
|
||||||
|
"dia endavant cada dia després del venciment."
|
||||||
|
|
||||||
msgid "Location Content Sheet"
|
msgid "Location Content Sheet"
|
||||||
msgstr "Full de continguts d'ubicació"
|
msgstr "Full de continguts d'ubicació"
|
||||||
|
|
@ -1245,8 +1246,8 @@ msgstr "Quantitat consumida"
|
||||||
msgid "Time of printing"
|
msgid "Time of printing"
|
||||||
msgstr "Hora d'impressi"
|
msgstr "Hora d'impressi"
|
||||||
|
|
||||||
msgid "Are you sure to delete equipment \"%s\"?"
|
msgid "Are you sure you want to delete equipment \"%s\"?"
|
||||||
msgstr "Estàs segur d'eliminar l'equipament \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Parent product"
|
msgid "Parent product"
|
||||||
msgstr "Producte pare"
|
msgstr "Producte pare"
|
||||||
|
|
@ -1310,7 +1311,11 @@ msgid_plural ""
|
||||||
"This means the next execution of this chore is scheduled at the same time "
|
"This means the next execution of this chore is scheduled at the same time "
|
||||||
"(based on the start date) every %s days"
|
"(based on the start date) every %s days"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada a la "
|
||||||
|
"mateixa hora (basat en la data d'inici) cada dia"
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada a la "
|
||||||
|
"mateixa hora (basat en la data d'inici) cada %s dies"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"This means the next execution of this chore is scheduled %s hour after the "
|
"This means the next execution of this chore is scheduled %s hour after the "
|
||||||
|
|
@ -1319,7 +1324,11 @@ msgid_plural ""
|
||||||
"This means the next execution of this chore is scheduled %s hours after the "
|
"This means the next execution of this chore is scheduled %s hours after the "
|
||||||
"last execution"
|
"last execution"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada 1 hora "
|
||||||
|
"després de l'última execució"
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada %s hores "
|
||||||
|
"després de l'última execució"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"This means the next execution of this chore is scheduled every week on the "
|
"This means the next execution of this chore is scheduled every week on the "
|
||||||
|
|
@ -1328,7 +1337,11 @@ msgid_plural ""
|
||||||
"This means the next execution of this chore is scheduled every %s weeks on "
|
"This means the next execution of this chore is scheduled every %s weeks on "
|
||||||
"the selected weekdays"
|
"the selected weekdays"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada cada "
|
||||||
|
"setmana als dies seleccionats"
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada cada %s "
|
||||||
|
"setmanes als dies seleccionats"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"This means the next execution of this chore is scheduled on the selected day"
|
"This means the next execution of this chore is scheduled on the selected day"
|
||||||
|
|
@ -1337,7 +1350,11 @@ msgid_plural ""
|
||||||
"This means the next execution of this chore is scheduled on the selected day"
|
"This means the next execution of this chore is scheduled on the selected day"
|
||||||
" every %s months"
|
" every %s months"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada al dia "
|
||||||
|
"seleccionat cada mes"
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada al dia "
|
||||||
|
"seleccionat cada %s mesos"
|
||||||
|
|
||||||
msgid "This means the next execution of this chore is not scheduled"
|
msgid "This means the next execution of this chore is not scheduled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -1346,30 +1363,37 @@ msgstr ""
|
||||||
msgid ""
|
msgid ""
|
||||||
"This means the next execution of this chore will not be assigned to anyone"
|
"This means the next execution of this chore will not be assigned to anyone"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca no serà assignada a ningú"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"This means the next execution of this chore will be assigned to the one who "
|
"This means the next execution of this chore will be assigned to the one who "
|
||||||
"executed it least"
|
"executed it least"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca serà assignada a qui l'hagi"
|
||||||
|
" executat l'última vegada"
|
||||||
|
|
||||||
msgid "This means the next execution of this chore will be assigned randomly"
|
msgid "This means the next execution of this chore will be assigned randomly"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca serà assignada "
|
||||||
|
"aleatòriament a algú"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"This means the next execution of this chore will be assigned to the next one"
|
"This means the next execution of this chore will be assigned to the next one"
|
||||||
" in alphabetical order"
|
" in alphabetical order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca serà assignada la següent "
|
||||||
|
"persona en ordre alfabètic"
|
||||||
|
|
||||||
msgid "Assign to"
|
msgid "Assign to"
|
||||||
msgstr ""
|
msgstr "Assigna a"
|
||||||
|
|
||||||
msgid "This assignment type requires that at least one is assigned"
|
msgid "This assignment type requires that at least one is assigned"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "%s chore is assigned to me"
|
msgid "%s chore is assigned to me"
|
||||||
msgid_plural "%s chores are assigned to me"
|
msgid_plural "%s chores are assigned to me"
|
||||||
msgstr[0] ""
|
msgstr[0] "Tens assignada %s feina"
|
||||||
msgstr[1] ""
|
msgstr[1] "Tens assignades %s feines"
|
||||||
|
|
||||||
msgid "Assigned to me"
|
msgid "Assigned to me"
|
||||||
msgstr "Assignat a mi"
|
msgstr "Assignat a mi"
|
||||||
|
|
@ -1383,8 +1407,8 @@ msgstr "Assignació"
|
||||||
msgid "Consume product on chore execution"
|
msgid "Consume product on chore execution"
|
||||||
msgstr "Consumir producte al executar la tasca"
|
msgstr "Consumir producte al executar la tasca"
|
||||||
|
|
||||||
msgid "Are you sure to delete user field \"%s\"?"
|
msgid "Are you sure you want to delete user field \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar el camp d'usuari \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Userentities"
|
msgid "Userentities"
|
||||||
msgstr "Entitat d'usuari"
|
msgstr "Entitat d'usuari"
|
||||||
|
|
@ -1404,8 +1428,8 @@ msgstr "Editar %s"
|
||||||
msgid "Create %s"
|
msgid "Create %s"
|
||||||
msgstr "Crear %s"
|
msgstr "Crear %s"
|
||||||
|
|
||||||
msgid "Are you sure to delete this userobject?"
|
msgid "Are you sure you want to delete this userobject?"
|
||||||
msgstr "Segur que vols eliminar aquest objecte d'usuari?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Icon CSS class"
|
msgid "Icon CSS class"
|
||||||
msgstr "Icona classe CSS"
|
msgstr "Icona classe CSS"
|
||||||
|
|
@ -1440,7 +1464,7 @@ msgid "Price factor"
|
||||||
msgstr "Factor de preu"
|
msgstr "Factor de preu"
|
||||||
|
|
||||||
msgid "Do you find Grocy useful?"
|
msgid "Do you find Grocy useful?"
|
||||||
msgstr ""
|
msgstr "Trobes que Grocy t'és d'utilitat?"
|
||||||
|
|
||||||
msgid "Say thanks"
|
msgid "Say thanks"
|
||||||
msgstr "Dir gràcies"
|
msgstr "Dir gràcies"
|
||||||
|
|
@ -1458,7 +1482,7 @@ msgid "Output"
|
||||||
msgstr "Resultat"
|
msgstr "Resultat"
|
||||||
|
|
||||||
msgid "Energy"
|
msgid "Energy"
|
||||||
msgstr ""
|
msgstr "Energia"
|
||||||
|
|
||||||
msgid "Per stock quantity unit"
|
msgid "Per stock quantity unit"
|
||||||
msgstr "Per unitat d'existències"
|
msgstr "Per unitat d'existències"
|
||||||
|
|
@ -1491,9 +1515,12 @@ msgid ""
|
||||||
"If enabled, the min. stock amount of sub products will be accumulated into "
|
"If enabled, the min. stock amount of sub products will be accumulated into "
|
||||||
"this product, means the sub product will never be missing, only this product"
|
"this product, means the sub product will never be missing, only this product"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Si s'activa, el mínim d'existències dels subproductes seran acumulats en "
|
||||||
|
"aquest producte, volent dir que el subproducte mai podrà faltar, només "
|
||||||
|
"aquest producte."
|
||||||
|
|
||||||
msgid "Are you sure to remove this conversion?"
|
msgid "Are you sure you want to remove this conversion?"
|
||||||
msgstr "Estas segur d'eliminar aquesta conversió?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Unit price"
|
msgid "Unit price"
|
||||||
msgstr "Preu unitari"
|
msgstr "Preu unitari"
|
||||||
|
|
@ -1510,8 +1537,8 @@ msgstr "Il·limitat"
|
||||||
msgid "Clear"
|
msgid "Clear"
|
||||||
msgstr "Neteja"
|
msgstr "Neteja"
|
||||||
|
|
||||||
msgid "Are you sure to remove the included recipe \"%s\"?"
|
msgid "Are you sure you want to remove the included recipe \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar la recepta inclosa \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Period interval"
|
msgid "Period interval"
|
||||||
msgstr "Interval"
|
msgstr "Interval"
|
||||||
|
|
@ -1523,10 +1550,14 @@ msgid_plural ""
|
||||||
"This means the next execution of this chore is scheduled every %s years on "
|
"This means the next execution of this chore is scheduled every %s years on "
|
||||||
"the same day (based on the start date)"
|
"the same day (based on the start date)"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada cada any al"
|
||||||
|
" mateix dia (basat en la data d'inici)"
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada cada %s "
|
||||||
|
"anys al mateix dia (basat en la data d'inici)"
|
||||||
|
|
||||||
msgid "Transfer"
|
msgid "Transfer"
|
||||||
msgstr ""
|
msgstr "Transfereix"
|
||||||
|
|
||||||
msgid "From location"
|
msgid "From location"
|
||||||
msgstr "D'ubicació"
|
msgstr "D'ubicació"
|
||||||
|
|
@ -1559,10 +1590,10 @@ msgid "The amount cannot be lower than %1$s"
|
||||||
msgstr "La quantitat no pot ser inferior a %1$s"
|
msgstr "La quantitat no pot ser inferior a %1$s"
|
||||||
|
|
||||||
msgid "Stock entry successfully updated"
|
msgid "Stock entry successfully updated"
|
||||||
msgstr ""
|
msgstr "Entrada d'existències actualitzada correctament"
|
||||||
|
|
||||||
msgid "Edit stock entry"
|
msgid "Edit stock entry"
|
||||||
msgstr ""
|
msgstr "Edita l'entrada d'inventari"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Camera access is only possible when supported and allowed by your browser "
|
"Camera access is only possible when supported and allowed by your browser "
|
||||||
|
|
@ -1594,8 +1625,8 @@ msgstr ""
|
||||||
msgid "Booking does not exist or was already undone"
|
msgid "Booking does not exist or was already undone"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Are you sure to delete API key \"%s\"?"
|
msgid "Are you sure you want to delete API key \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar la clau API \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Add note"
|
msgid "Add note"
|
||||||
msgstr "Afegir nota"
|
msgstr "Afegir nota"
|
||||||
|
|
@ -1648,8 +1679,8 @@ msgstr "Descongelat"
|
||||||
msgid "Frozen"
|
msgid "Frozen"
|
||||||
msgstr "Congelat"
|
msgstr "Congelat"
|
||||||
|
|
||||||
msgid "Are you sure to delete userentity \"%s\"?"
|
msgid "Are you sure you want to delete userentity \"%s\"?"
|
||||||
msgstr "Segur que vols eliminar l'entitat d'usuari \"%s\"?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Shopping list settings"
|
msgid "Shopping list settings"
|
||||||
msgstr "Configuració de la llista de la compra"
|
msgstr "Configuració de la llista de la compra"
|
||||||
|
|
@ -1660,9 +1691,6 @@ msgstr "Mostra la vista mensual de calendari"
|
||||||
msgid "Desired servings"
|
msgid "Desired servings"
|
||||||
msgstr "Racions desitjades"
|
msgstr "Racions desitjades"
|
||||||
|
|
||||||
msgid "Base: %s"
|
|
||||||
msgstr "Base: %s"
|
|
||||||
|
|
||||||
msgid "Recipes settings"
|
msgid "Recipes settings"
|
||||||
msgstr "Configuració de receptes"
|
msgstr "Configuració de receptes"
|
||||||
|
|
||||||
|
|
@ -1746,7 +1774,7 @@ msgstr "Editar codi de barres"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Based on the prices of the default consume rule (Opened first, then first "
|
"Based on the prices of the default consume rule (Opened first, then first "
|
||||||
"due first, then first in first out) for in-stock ingredients and on the last"
|
"due first, then first in first out) for in stock ingredients and on the last"
|
||||||
" price for missing ones"
|
" price for missing ones"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -1874,7 +1902,7 @@ msgid "Transaction time"
|
||||||
msgstr "Hora de la transacció"
|
msgstr "Hora de la transacció"
|
||||||
|
|
||||||
msgid "Chore journal"
|
msgid "Chore journal"
|
||||||
msgstr ""
|
msgstr "Resum de tasques"
|
||||||
|
|
||||||
msgid "Track next chore schedule"
|
msgid "Track next chore schedule"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -1904,6 +1932,8 @@ msgid ""
|
||||||
"This is the default quantity unit used on purchase and when adding this "
|
"This is the default quantity unit used on purchase and when adding this "
|
||||||
"product to the shopping list"
|
"product to the shopping list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Aquesta és la unitat per defecte que es farà servir en comprar i quan "
|
||||||
|
"s'afegeix el producte a la llista de la compra"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Show a warning when the due date of the purchased product is earlier than "
|
"Show a warning when the due date of the purchased product is earlier than "
|
||||||
|
|
@ -1912,9 +1942,8 @@ msgstr ""
|
||||||
"Mostra una advertència quan la data de caducitat del producte comprat és més"
|
"Mostra una advertència quan la data de caducitat del producte comprat és més"
|
||||||
" propera que la de les existències"
|
" propera que la de les existències"
|
||||||
|
|
||||||
msgid "This is due earlier than already in-stock items"
|
msgid "This is due earlier than already in stock items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Aquesta data de caducitat és més propera que la que ja tens en existències"
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"When enabled, after changing/scanning a product and if all fields could be "
|
"When enabled, after changing/scanning a product and if all fields could be "
|
||||||
|
|
@ -1929,17 +1958,21 @@ msgid ""
|
||||||
"This amount is used for the \"quick consume button\" on the stock overview "
|
"This amount is used for the \"quick consume button\" on the stock overview "
|
||||||
"page (related to quantity unit stock)"
|
"page (related to quantity unit stock)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Aquesta quantitat és utilitzada pel botó de \"consumir ràpidament\" en la "
|
||||||
|
"pàgina d'existències (en unitats d'existències)"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"This amount is used for the \"quick open button\" on the stock overview page"
|
"This amount is used for the \"quick open button\" on the stock overview page"
|
||||||
" (related to quantity unit stock)"
|
" (related to quantity unit stock)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Aquesta quantitat és utilitzada pel botó de \"obrir ràpidament\" en la "
|
||||||
|
"pàgina d'existències (en unitats d'existències)"
|
||||||
|
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "Copiar"
|
msgstr "Copiar"
|
||||||
|
|
||||||
msgid "Are you sure to remove this barcode?"
|
msgid "Are you sure you want to remove this barcode?"
|
||||||
msgstr "Segur que vols eliminar aquest codi de barres?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Due date type"
|
msgid "Due date type"
|
||||||
msgstr "Tipus de data de caducitat"
|
msgstr "Tipus de data de caducitat"
|
||||||
|
|
@ -2062,11 +2095,15 @@ msgid ""
|
||||||
"This cannot be lower than %1$s and needs to be a valid number with max. %2$s"
|
"This cannot be lower than %1$s and needs to be a valid number with max. %2$s"
|
||||||
" decimal places"
|
" decimal places"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Això no pot ser més baix que %1$s i ha de ser un nombre vàlid amb un màxim "
|
||||||
|
"de %2$s decimals"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"This must between %1$s and %2$s and needs to be a valid number with max. "
|
"This must between %1$s and %2$s and needs to be a valid number with max. "
|
||||||
"%3$s decimal places"
|
"%3$s decimal places"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Aquest ha de ser entre %1$s i %2$s i ha de ser un nombre vàlid amb un màxim "
|
||||||
|
"de %3$s decimals"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Automatically do the booking using the last price and the amount of the "
|
"Automatically do the booking using the last price and the amount of the "
|
||||||
|
|
@ -2123,13 +2160,13 @@ msgid "Ingredient group"
|
||||||
msgstr "Grup d'ingredients"
|
msgstr "Grup d'ingredients"
|
||||||
|
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "Reiniciar"
|
msgstr "Reinicia"
|
||||||
|
|
||||||
msgid "Are you sure to reset the table options?"
|
msgid "Are you sure you want to reset the table options?"
|
||||||
msgstr "Segur que vols reiniciar les opcions de la taula?"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Hide/view columns"
|
msgid "Hide/view columns"
|
||||||
msgstr "Ocultar/mostrar columnes"
|
msgstr "Oculta/mostra columnes"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"A different amount/unit can then be used below while for stock fulfillment "
|
"A different amount/unit can then be used below while for stock fulfillment "
|
||||||
|
|
@ -2140,7 +2177,7 @@ msgid "Last price (Unit)"
|
||||||
msgstr "Últim preu (unitat)"
|
msgstr "Últim preu (unitat)"
|
||||||
|
|
||||||
msgid "Last price (Total)"
|
msgid "Last price (Total)"
|
||||||
msgstr "Últim preu (Total)"
|
msgstr "Últim preu (total)"
|
||||||
|
|
||||||
msgid "Show header"
|
msgid "Show header"
|
||||||
msgstr "Mostrar capçalera"
|
msgstr "Mostrar capçalera"
|
||||||
|
|
@ -2187,7 +2224,7 @@ msgid "Link"
|
||||||
msgstr "Enllaç"
|
msgstr "Enllaç"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"The stock overview page lists all products which are currently in-stock or "
|
"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 "
|
"below their min. stock amount - enable this to hide this product there "
|
||||||
"always"
|
"always"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -2199,7 +2236,7 @@ msgid "A product or a note is required"
|
||||||
msgstr "Es requereix un producte o nota"
|
msgstr "Es requereix un producte o nota"
|
||||||
|
|
||||||
msgid "Grocycode"
|
msgid "Grocycode"
|
||||||
msgstr ""
|
msgstr "Grocycode"
|
||||||
|
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr "Descàrrega"
|
msgstr "Descàrrega"
|
||||||
|
|
@ -2215,7 +2252,7 @@ msgstr ""
|
||||||
|
|
||||||
# Abbreviation for "due date"
|
# Abbreviation for "due date"
|
||||||
msgid "DD"
|
msgid "DD"
|
||||||
msgstr ""
|
msgstr "DC"
|
||||||
|
|
||||||
msgid "Print on label printer"
|
msgid "Print on label printer"
|
||||||
msgstr "Imprimir en una impressora d'etiquetes"
|
msgstr "Imprimir en una impressora d'etiquetes"
|
||||||
|
|
@ -2260,8 +2297,8 @@ msgstr "No s'ha pogut imprimir"
|
||||||
msgid "Only done items"
|
msgid "Only done items"
|
||||||
msgstr "Només elements completats"
|
msgstr "Només elements completats"
|
||||||
|
|
||||||
msgid "Show only in-stock products"
|
msgid "Show only in stock products"
|
||||||
msgstr "Mostra només productes en existències"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Product description"
|
msgid "Product description"
|
||||||
msgstr "Descripció de producte"
|
msgstr "Descripció de producte"
|
||||||
|
|
@ -2282,8 +2319,8 @@ msgstr "Camp d'usuari obligatori"
|
||||||
msgid "When enabled, then this field must be filled on the destination form"
|
msgid "When enabled, then this field must be filled on the destination form"
|
||||||
msgstr "Quan activat, aquest camp s'ha d'omplir en el formulari de dest"
|
msgstr "Quan activat, aquest camp s'ha d'omplir en el formulari de dest"
|
||||||
|
|
||||||
msgid "In-stock products"
|
msgid "In stock products"
|
||||||
msgstr "Productes en existències"
|
msgstr ""
|
||||||
|
|
||||||
msgid "Timestamp"
|
msgid "Timestamp"
|
||||||
msgstr "Marca de temps"
|
msgstr "Marca de temps"
|
||||||
|
|
@ -2348,30 +2385,30 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Stock entry"
|
msgid "Stock entry"
|
||||||
msgstr ""
|
msgstr "Entrada d'existències"
|
||||||
|
|
||||||
msgid "Configure sections"
|
msgid "Configure sections"
|
||||||
msgstr "Configurar seccions"
|
msgstr "Configurar seccions"
|
||||||
|
|
||||||
msgid "Meal plan sections"
|
msgid "Meal plan sections"
|
||||||
msgstr ""
|
msgstr "Seccions de planificador d'àpats"
|
||||||
|
|
||||||
msgid "Create meal plan section"
|
msgid "Create meal plan section"
|
||||||
msgstr ""
|
msgstr "Crea una secció al planificador d'àpats"
|
||||||
|
|
||||||
msgid "Sections will be ordered by that number on the meal plan"
|
msgid "Sections will be ordered by that number on the meal plan"
|
||||||
msgstr ""
|
msgstr "Les seccions seran ordenades pel número en el planificador d'àpats."
|
||||||
|
|
||||||
msgid "Edit meal plan section"
|
msgid "Edit meal plan section"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
msgid "Are you sure you want to delete meal plan section \"%s\"?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Section"
|
msgid "Section"
|
||||||
msgstr "Secció"
|
msgstr "Secció"
|
||||||
|
|
||||||
msgid "Are you sure to empty the shopping list?"
|
msgid "Are you sure you want to empty the shopping list?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "This is the default which will be prefilled on purchase"
|
msgid "This is the default which will be prefilled on purchase"
|
||||||
|
|
@ -2404,8 +2441,8 @@ msgstr[1] ""
|
||||||
|
|
||||||
msgid "%s chore is due to be done today"
|
msgid "%s chore is due to be done today"
|
||||||
msgid_plural "%s chores are due to be done today"
|
msgid_plural "%s chores are due to be done today"
|
||||||
msgstr[0] ""
|
msgstr[0] "%s tasca s'ha d'acabar avui"
|
||||||
msgstr[1] ""
|
msgstr[1] "%s tasques s'han d'acabar avui"
|
||||||
|
|
||||||
msgid "%s battery is due to be charged today"
|
msgid "%s battery is due to be charged today"
|
||||||
msgid_plural "%s batteries are due to be charged today"
|
msgid_plural "%s batteries are due to be charged today"
|
||||||
|
|
@ -2416,18 +2453,20 @@ msgid "Set to 0 to hide due soon filters/highlighting"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Save & close"
|
msgid "Save & close"
|
||||||
msgstr ""
|
msgstr "Desa i tanca"
|
||||||
|
|
||||||
msgid "Save & add another task"
|
msgid "Save & add another task"
|
||||||
msgstr ""
|
msgstr "Desa i afegeix una altra tasca"
|
||||||
|
|
||||||
msgid "Treat opened as out of stock"
|
msgid "Treat opened as out of stock"
|
||||||
msgstr ""
|
msgstr "Tracta obert com a esgotat"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"When enabled, opened items will be counted as missing for calculating if "
|
"When enabled, opened items will be counted as missing for calculating if "
|
||||||
"this product is below its minimum stock amount"
|
"this product is below its minimum stock amount"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Quan s'activa, els elements oberts seran comptats com a absents per calcular"
|
||||||
|
" si aquest producte es troba per sota els mínims d'existències."
|
||||||
|
|
||||||
msgid "Skipped"
|
msgid "Skipped"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -2436,16 +2475,18 @@ msgid "Skip next chore schedule"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr ""
|
msgstr "Hora"
|
||||||
|
|
||||||
msgid "A start date is required"
|
msgid "A start date is required"
|
||||||
msgstr ""
|
msgstr "La data d'inici és necessària"
|
||||||
|
|
||||||
msgid "Start date"
|
msgid "Start date"
|
||||||
msgstr ""
|
msgstr "Data d'inici"
|
||||||
|
|
||||||
msgid "The start date cannot be changed when the chore was once tracked"
|
msgid "The start date cannot be changed when the chore was once tracked"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"La data d'inici no es pot canviar després de començar el seguiment de la "
|
||||||
|
"tasca"
|
||||||
|
|
||||||
msgid "Show the recipe list and the recipe side by side"
|
msgid "Show the recipe list and the recipe side by side"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -2454,18 +2495,20 @@ msgid ""
|
||||||
"This means the next execution of this chore is scheduled dynamically based "
|
"This means the next execution of this chore is scheduled dynamically based "
|
||||||
"on the past average execution frequency"
|
"on the past average execution frequency"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Això vol dir que la pròxima execució de la tasca està programada "
|
||||||
|
"dinàmicament basant-se en la freqüència mitjana d'execució "
|
||||||
|
|
||||||
msgid "Average execution frequency"
|
msgid "Average execution frequency"
|
||||||
msgstr ""
|
msgstr "Freqüència mitjana de realització"
|
||||||
|
|
||||||
msgid "Reschedule next execution"
|
msgid "Reschedule next execution"
|
||||||
msgstr ""
|
msgstr "Re-programa la següent realització"
|
||||||
|
|
||||||
msgid "This can only be in the future"
|
msgid "This can only be in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Rescheduled"
|
msgid "Rescheduled"
|
||||||
msgstr ""
|
msgstr "Re-programada"
|
||||||
|
|
||||||
msgid "Due score"
|
msgid "Due score"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -2476,13 +2519,16 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Disable own stock"
|
msgid "Disable own stock"
|
||||||
msgstr ""
|
msgstr "Deshabilitar inventari propi"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"When enabled, this product can't have own stock, means it will not be "
|
"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 "
|
"selectable on purchase (useful for parent products which are just used as a "
|
||||||
"summary/total view of the child products)"
|
"summary/total view of the child products)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Quan s'habilita, aquest producte no pot tenir quantitat d'existències "
|
||||||
|
"pròpies, això vol dir que no es podrà seleccionar per comprar (útil per "
|
||||||
|
"productes para que són una vista resum/total dels subproductes)"
|
||||||
|
|
||||||
msgid "Out of stock items will be shown at the products default location"
|
msgid "Out of stock items will be shown at the products default location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -2502,45 +2548,47 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Night mode"
|
msgid "Night mode"
|
||||||
msgstr ""
|
msgstr "Mode nocturn"
|
||||||
|
|
||||||
msgid "On"
|
msgid "On"
|
||||||
msgstr ""
|
msgstr "ON"
|
||||||
|
|
||||||
msgid "Use system setting"
|
msgid "Use system setting"
|
||||||
msgstr ""
|
msgstr "Utilitza la configuració del sistema"
|
||||||
|
|
||||||
msgid "Off"
|
msgid "Off"
|
||||||
msgstr ""
|
msgstr "OFF"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Automatically add products that are below their defined min. stock amount to"
|
"Automatically add products that are below their defined min. stock amount to"
|
||||||
" the shopping list"
|
" the shopping list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Afegeix automàticament els productes que estiguin per sota el seu valor "
|
||||||
|
"d'existències mínim definit a la llista de compra"
|
||||||
|
|
||||||
msgid "Reassigned"
|
msgid "Reassigned"
|
||||||
msgstr ""
|
msgstr "Re-assignada"
|
||||||
|
|
||||||
msgid "Default value"
|
msgid "Default value"
|
||||||
msgstr ""
|
msgstr "Valor predeterminat"
|
||||||
|
|
||||||
msgid "Now / today"
|
msgid "Now / today"
|
||||||
msgstr ""
|
msgstr "Ara / avui"
|
||||||
|
|
||||||
msgid "Add meal plan entry"
|
msgid "Add meal plan entry"
|
||||||
msgstr ""
|
msgstr "Afegeix entrada al menú"
|
||||||
|
|
||||||
msgid "Edit meal plan entry"
|
msgid "Edit meal plan entry"
|
||||||
msgstr ""
|
msgstr "Edita entrada del menú"
|
||||||
|
|
||||||
msgid "Default consume location"
|
msgid "Default consume location"
|
||||||
msgstr ""
|
msgstr "Ubicació de consum predeterminada"
|
||||||
|
|
||||||
msgid "Stock entries at this location will be consumed first"
|
msgid "Stock entries at this location will be consumed first"
|
||||||
msgstr ""
|
msgstr "Les existències en aquesta ubicació es consumiran primer"
|
||||||
|
|
||||||
msgid "Move on open"
|
msgid "Move on open"
|
||||||
msgstr ""
|
msgstr "Mou quan s'obri"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"When enabled, on marking this product as opened, the corresponding amount "
|
"When enabled, on marking this product as opened, the corresponding amount "
|
||||||
|
|
@ -2548,13 +2596,13 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Moved to %1$s"
|
msgid "Moved to %1$s"
|
||||||
msgstr ""
|
msgstr "S'ha mogut a %1$s"
|
||||||
|
|
||||||
msgid "Decimal places allowed for prices (input)"
|
msgid "Decimal places allowed for prices (input)"
|
||||||
msgstr ""
|
msgstr "Posicions decimals permeses pels preus (entrada)"
|
||||||
|
|
||||||
msgid "Decimal places allowed for prices (display)"
|
msgid "Decimal places allowed for prices (display)"
|
||||||
msgstr ""
|
msgstr "Posicions decimals permeses pels preus (visualització)"
|
||||||
|
|
||||||
msgid "Clear done items"
|
msgid "Clear done items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -2565,25 +2613,27 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Show resolved conversions"
|
msgid "Show resolved conversions"
|
||||||
msgstr ""
|
msgstr "Mostra les conversions resoltes"
|
||||||
|
|
||||||
msgid "QU conversions resolved"
|
msgid "QU conversions resolved"
|
||||||
msgstr ""
|
msgstr "Conversions QU resoltes"
|
||||||
|
|
||||||
msgid "Product specifc QU conversions"
|
msgid "Product specific QU conversions"
|
||||||
msgstr ""
|
msgstr "Conversions QU específiques de producte"
|
||||||
|
|
||||||
msgid "Default quantity unit consume"
|
msgid "Default quantity unit consume"
|
||||||
msgstr ""
|
msgstr "Unitat de consum predeterminada"
|
||||||
|
|
||||||
msgid "This is the default quantity unit used when consuming this product"
|
msgid "This is the default quantity unit used when consuming this product"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Aquesta és la unitat per defecte que es farà servir en consumir aquest "
|
||||||
|
"producte"
|
||||||
|
|
||||||
msgid "Add to meal plan"
|
msgid "Add to meal plan"
|
||||||
msgstr ""
|
msgstr "Afegeix al menú"
|
||||||
|
|
||||||
msgid "Successfully added the recipe to the meal plan"
|
msgid "Successfully added the recipe to the meal plan"
|
||||||
msgstr ""
|
msgstr "Recepta afegida al menú correctament"
|
||||||
|
|
||||||
msgid "Reprint stock entry label"
|
msgid "Reprint stock entry label"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -2604,44 +2654,44 @@ msgid "Track chore execution now"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr ""
|
msgstr "Total"
|
||||||
|
|
||||||
msgid "Apply"
|
msgid "Apply"
|
||||||
msgstr ""
|
msgstr "Aplica"
|
||||||
|
|
||||||
msgid "Custom range"
|
msgid "Custom range"
|
||||||
msgstr ""
|
msgstr "Interval personalitzat"
|
||||||
|
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr ""
|
msgstr "Ahir"
|
||||||
|
|
||||||
msgid "Last %1$s day"
|
msgid "Last %1$s day"
|
||||||
msgid_plural "Last %1$s days"
|
msgid_plural "Last %1$s days"
|
||||||
msgstr[0] ""
|
msgstr[0] "L'últim %1$s dia"
|
||||||
msgstr[1] ""
|
msgstr[1] "Els últims %1$s dies"
|
||||||
|
|
||||||
msgid "This month"
|
msgid "This month"
|
||||||
msgstr ""
|
msgstr "Aquest mes"
|
||||||
|
|
||||||
msgid "Last month"
|
msgid "Last month"
|
||||||
msgstr ""
|
msgstr "El mes passat"
|
||||||
|
|
||||||
msgid "This year"
|
msgid "This year"
|
||||||
msgstr ""
|
msgstr "Aquest any"
|
||||||
|
|
||||||
msgid "Last year"
|
msgid "Last year"
|
||||||
msgstr ""
|
msgstr "L'any passat"
|
||||||
|
|
||||||
msgid "Reports"
|
msgid "Reports"
|
||||||
msgstr ""
|
msgstr "Informes"
|
||||||
|
|
||||||
msgid "Spendings"
|
msgid "Spendings"
|
||||||
msgstr ""
|
msgstr "Despeses"
|
||||||
|
|
||||||
msgid "Stock report"
|
msgid "Stock report"
|
||||||
msgstr ""
|
msgstr "Informe d'existències"
|
||||||
|
|
||||||
msgid "Out-of-stock products"
|
msgid "Out of stock products"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Quantity unit for prices"
|
msgid "Quantity unit for prices"
|
||||||
|
|
@ -2651,8 +2701,74 @@ msgid ""
|
||||||
"When displaying prices for this product, they will be related to this "
|
"When displaying prices for this product, they will be related to this "
|
||||||
"quantity unit"
|
"quantity unit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Quan es mostrin els preus per aquest producte, seran referits a aquesta "
|
||||||
|
"unitat"
|
||||||
|
|
||||||
msgid "This means 1 label will be printed"
|
msgid "This means 1 label will be printed"
|
||||||
msgid_plural "This means %1$s labels will be printed"
|
msgid_plural "This means %1$s labels will be printed"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
|
msgid "External barcode lookup"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Error while executing the barcode lookup plugin"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Nothing was found for the given barcode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Configure colors"
|
||||||
|
msgstr "Configura els colors"
|
||||||
|
|
||||||
|
msgid "Swap track next schedule / track now buttons"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Scheduled tracking time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Time of tracking"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Show all out of stock products"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"By default the stock overview page lists all products which are currently in"
|
||||||
|
" stock or below their min. stock amount - when this is enabled, all (active)"
|
||||||
|
" products are always shown"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No price information is available for at least one ingredient"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For ingredients that are only partially in stock, the in stock amount will "
|
||||||
|
"be consumed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Can't be opened"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Default purchase price type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "This will be used as the default price type selection on purchase"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Unspecified"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Round up quantity amounts to the nearest whole number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Stock actions"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "List actions"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"After this product was once in stock and when the desired quantity unit "
|
||||||
|
"cannot be selected here, first create a corresponding unit conversion"
|
||||||
|
msgstr ""
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# gimy16 <gimy16@hotmail.com>, 2021
|
# gimy16 <gimy16@hotmail.com>, 2021
|
||||||
|
# Roger Solé Vilajuliu, 2024
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -8,7 +8,7 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
"PO-Revision-Date: 2019-05-01 17:43+0000\n"
|
"PO-Revision-Date: 2019-05-01 17:43+0000\n"
|
||||||
"Last-Translator: gimy16 <gimy16@hotmail.com>, 2021\n"
|
"Last-Translator: Roger Solé Vilajuliu, 2024\n"
|
||||||
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
"Language-Team: Catalan (https://app.transifex.com/grocy/teams/93189/ca/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|
@ -33,6 +33,10 @@ msgstr "nombre-integral"
|
||||||
msgid "number-decimal"
|
msgid "number-decimal"
|
||||||
msgstr "nombre-decimal"
|
msgstr "nombre-decimal"
|
||||||
|
|
||||||
|
# Number (currency)
|
||||||
|
msgid "number-currency"
|
||||||
|
msgstr "nombre-moneda"
|
||||||
|
|
||||||
# Date (without time)
|
# Date (without time)
|
||||||
msgid "date"
|
msgid "date"
|
||||||
msgstr "data"
|
msgstr "data"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Radim Kabeláč <radim.ekk@gmail.com>, 2020
|
# Radim Kabeláč <radim.ekk@gmail.com>, 2020
|
||||||
# Pavel Paseka, 2022
|
# Pavel Paseka, 2022
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Tomas Reznicek <tomas.reznicek@gmail.com>, 2019
|
# Tomas Reznicek <tomas.reznicek@gmail.com>, 2019
|
||||||
# Michal Petříček <michal@petricek.org>, 2019
|
# Michal Petříček <michal@petricek.org>, 2019
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Tomas Reznicek <tomas.reznicek@gmail.com>, 2019
|
# Tomas Reznicek <tomas.reznicek@gmail.com>, 2019
|
||||||
# Bernd Bestel <bernd@berrnd.de>, 2020
|
# Bernd Bestel <bernd@berrnd.de>, 2020
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Michal Petříček <michal@petricek.org>, 2019
|
# Michal Petříček <michal@petricek.org>, 2019
|
||||||
# Ondřej Suk <ondra.suk.55@gmail.com>, 2020
|
# Ondřej Suk <ondra.suk.55@gmail.com>, 2020
|
||||||
|
|
@ -432,3 +431,6 @@ msgstr "Pivo"
|
||||||
|
|
||||||
msgid "Estonian"
|
msgid "Estonian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bulgarian"
|
||||||
|
msgstr ""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Radim Kabeláč <radim.ekk@gmail.com>, 2020
|
# Radim Kabeláč <radim.ekk@gmail.com>, 2020
|
||||||
# Jarda Tesar <intossh@gmail.com>, 2021
|
# Jarda Tesar <intossh@gmail.com>, 2021
|
||||||
|
|
@ -146,3 +145,7 @@ msgstr "Rumunština"
|
||||||
# Estonian
|
# Estonian
|
||||||
msgid "et_EE"
|
msgid "et_EE"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
# Bulgarian
|
||||||
|
msgid "bg_BG"
|
||||||
|
msgstr ""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Pavel Paseka, 2022
|
# Pavel Paseka, 2022
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Pavel Paseka, 2022
|
# Pavel Paseka, 2022
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#
|
|
||||||
# Translators:
|
# Translators:
|
||||||
# Tomas Reznicek <tomas.reznicek@gmail.com>, 2019
|
# Tomas Reznicek <tomas.reznicek@gmail.com>, 2019
|
||||||
# Michal Petříček <michal@petricek.org>, 2019
|
# Michal Petříček <michal@petricek.org>, 2019
|
||||||
|
|
@ -8,7 +7,7 @@
|
||||||
# Radim Kabeláč <radim.ekk@gmail.com>, 2020
|
# Radim Kabeláč <radim.ekk@gmail.com>, 2020
|
||||||
# Jaroslav Lichtblau <l10n@lichtblau.cz>, 2020
|
# Jaroslav Lichtblau <l10n@lichtblau.cz>, 2020
|
||||||
# Jarda Tesar <intossh@gmail.com>, 2021
|
# Jarda Tesar <intossh@gmail.com>, 2021
|
||||||
# Pavel Paseka, 2023
|
# Pavel Paseka, 2026
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -16,7 +15,7 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||||
"Last-Translator: Pavel Paseka, 2023\n"
|
"Last-Translator: Pavel Paseka, 2026\n"
|
||||||
"Language-Team: Czech (https://app.transifex.com/grocy/teams/93189/cs/)\n"
|
"Language-Team: Czech (https://app.transifex.com/grocy/teams/93189/cs/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|
@ -277,9 +276,7 @@ msgid "Manage master data"
|
||||||
msgstr "Spravovat základní data"
|
msgstr "Spravovat základní data"
|
||||||
|
|
||||||
msgid "This will apply to added products"
|
msgid "This will apply to added products"
|
||||||
msgstr ""
|
msgstr "Tento údaj se zapíše jen pro přidané produkty do zásoby."
|
||||||
"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"
|
|
||||||
|
|
||||||
msgid "never"
|
msgid "never"
|
||||||
msgstr "nikdy"
|
msgstr "nikdy"
|
||||||
|
|
@ -299,8 +296,8 @@ msgstr "Heslo"
|
||||||
msgid "Invalid credentials, please try again"
|
msgid "Invalid credentials, please try again"
|
||||||
msgstr "Nesprávné jméno nebo heslo, zkuste to ještě jednou"
|
msgstr "Nesprávné jméno nebo heslo, zkuste to ještě jednou"
|
||||||
|
|
||||||
msgid "Are you sure to delete battery \"%s\"?"
|
msgid "Are you sure you want to delete battery \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat baterii „%s“"
|
msgstr "Odstranit baterii „%s“?"
|
||||||
|
|
||||||
msgid "Yes"
|
msgid "Yes"
|
||||||
msgstr "Ano"
|
msgstr "Ano"
|
||||||
|
|
@ -308,8 +305,8 @@ msgstr "Ano"
|
||||||
msgid "No"
|
msgid "No"
|
||||||
msgstr "Ne"
|
msgstr "Ne"
|
||||||
|
|
||||||
msgid "Are you sure to delete chore \"%s\"?"
|
msgid "Are you sure you want to delete chore \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat povinnost „%s“?"
|
msgstr "Odstranit povinnost „%s“?"
|
||||||
|
|
||||||
msgid "\"%s\" could not be resolved to a product, how do you want to proceed?"
|
msgid "\"%s\" could not be resolved to a product, how do you want to proceed?"
|
||||||
msgstr "Žádný uložený produkt se nejmenuje „%s“. Jak chcete pokračovat?"
|
msgstr "Žádný uložený produkt se nejmenuje „%s“. Jak chcete pokračovat?"
|
||||||
|
|
@ -329,17 +326,17 @@ msgstr "Přidat jako čárový kód k existujícímu produktu"
|
||||||
msgid "Add as new product and prefill barcode"
|
msgid "Add as new product and prefill barcode"
|
||||||
msgstr "Přidat jako nový produkt a předvyplnit čárový kód"
|
msgstr "Přidat jako nový produkt a předvyplnit čárový kód"
|
||||||
|
|
||||||
msgid "Are you sure to delete quantity unit \"%s\"?"
|
msgid "Are you sure you want to delete quantity unit \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat měrnou jednotku „%s“?"
|
msgstr "Odstranit jednotku množství „%s“?"
|
||||||
|
|
||||||
msgid "Are you sure to delete product \"%s\"?"
|
msgid "Are you sure you want to delete product \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat produkt „%s“?"
|
msgstr "Odstranit produkt „%s“?"
|
||||||
|
|
||||||
msgid "Are you sure to delete location \"%s\"?"
|
msgid "Are you sure you want to delete location \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat umístění „%s“?"
|
msgstr "Odstranit umístění „%s“?"
|
||||||
|
|
||||||
msgid "Are you sure to delete store \"%s\"?"
|
msgid "Are you sure you want to delete store \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat obchod „%s“?"
|
msgstr "Odstranit obchod „%s“?"
|
||||||
|
|
||||||
msgid "Manage API keys"
|
msgid "Manage API keys"
|
||||||
msgstr "Spravovat API klíče"
|
msgstr "Spravovat API klíče"
|
||||||
|
|
@ -380,9 +377,6 @@ msgstr "Co je Grocy"
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Zavřít"
|
msgstr "Zavřít"
|
||||||
|
|
||||||
msgid "Released on"
|
|
||||||
msgstr "Vydaná"
|
|
||||||
|
|
||||||
msgid "Added %1$s of %2$s to stock"
|
msgid "Added %1$s of %2$s to stock"
|
||||||
msgstr "Zásoba se zvýšila o %1$s produktu %2$s"
|
msgstr "Zásoba se zvýšila o %1$s produktu %2$s"
|
||||||
|
|
||||||
|
|
@ -455,14 +449,14 @@ msgstr "Přidat ingredienci"
|
||||||
msgid "Edit recipe ingredient"
|
msgid "Edit recipe ingredient"
|
||||||
msgstr "Upravit ingredienci"
|
msgstr "Upravit ingredienci"
|
||||||
|
|
||||||
msgid "Are you sure to delete recipe \"%s\"?"
|
msgid "Are you sure you want to delete recipe \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat recept „%s“?"
|
msgstr "Odstranit recept „%s“?"
|
||||||
|
|
||||||
msgid "Are you sure to delete recipe ingredient \"%s\"?"
|
msgid "Are you sure you want to delete recipe ingredient \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat ingredienci „%s“?"
|
msgstr "Odstranit ingredienci „%s“?"
|
||||||
|
|
||||||
msgid "Are you sure to empty shopping list \"%s\"?"
|
msgid "Are you sure you want to empty shopping list \"%s\"?"
|
||||||
msgstr "Opravdu chcete vyprázdnit nákupní seznam „%s“?"
|
msgstr "Vyprázdnit nákupní seznam „%s“?"
|
||||||
|
|
||||||
msgid "Clear list"
|
msgid "Clear list"
|
||||||
msgstr "Vyprázdnit seznam"
|
msgstr "Vyprázdnit seznam"
|
||||||
|
|
@ -507,15 +501,12 @@ msgid "Put missing amount on shopping list"
|
||||||
msgstr "Přidat chybějící množství do nákupního seznamu"
|
msgstr "Přidat chybějící množství do nákupního seznamu"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure to put all missing ingredients for recipe \"%s\" on the "
|
"Are you sure you want to put all missing ingredients for recipe \"%s\" on "
|
||||||
"shopping list?"
|
"the shopping list?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Chcete přidat všechny chybějící ingredience z receptu „%s“ do nákupního "
|
"Chcete přidat všechny chybějící ingredience z receptu „%s“ do nákupního "
|
||||||
"seznamu?"
|
"seznamu?"
|
||||||
|
|
||||||
msgid "Added for recipe %s"
|
|
||||||
msgstr "Ingredience pro recept „%s“"
|
|
||||||
|
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Spravovat uživatele"
|
msgstr "Spravovat uživatele"
|
||||||
|
|
||||||
|
|
@ -525,8 +516,8 @@ msgstr "Uživatel"
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr "Uživatelé"
|
msgstr "Uživatelé"
|
||||||
|
|
||||||
msgid "Are you sure to delete user \"%s\"?"
|
msgid "Are you sure you want to delete user \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat uživatele „%s“?"
|
msgstr "Odstranit uživatele „%s“?"
|
||||||
|
|
||||||
msgid "Create user"
|
msgid "Create user"
|
||||||
msgstr "Vytvořit uživatele"
|
msgstr "Vytvořit uživatele"
|
||||||
|
|
@ -630,14 +621,15 @@ msgid "Only check if any amount is in stock"
|
||||||
msgstr "Pouze zkontrolovat, zda je v zásobě jakékoliv množství"
|
msgstr "Pouze zkontrolovat, zda je v zásobě jakékoliv množství"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure to consume all ingredients needed by recipe \"%s\" (ingredients"
|
"Are you sure you want to consume all ingredients needed by recipe \"%s\" "
|
||||||
" marked with \"only check if any amount is in stock\" will be ignored)?"
|
"(ingredients marked with \"only check if any amount is in stock\" will be "
|
||||||
|
"ignored)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Opravdu si přejete spotřebovat všechny ingredience receptu „%s“? Ingredience"
|
"Přejete se spotřebovat všechny ingredience receptu „%s“? Ingredience "
|
||||||
" označené „Zkontrolovat pouze zda je v zásobě jakékoliv množství“ budou "
|
"označené „Zkontrolovat pouze zda je v zásobě jakékoliv množství“ budou "
|
||||||
"ignorovány."
|
"ignorovány."
|
||||||
|
|
||||||
msgid "Removed all ingredients of recipe \"%s\" from stock"
|
msgid "Removed all in stock ingredients needed by recipe \"%s\" from stock"
|
||||||
msgstr "Všechny ingredience z receptu „%s“ byly odebrány ze zásob"
|
msgstr "Všechny ingredience z receptu „%s“ byly odebrány ze zásob"
|
||||||
|
|
||||||
msgid "Consume all ingredients needed by this recipe"
|
msgid "Consume all ingredients needed by this recipe"
|
||||||
|
|
@ -688,8 +680,8 @@ msgstr "Kategorie"
|
||||||
msgid "Edit task"
|
msgid "Edit task"
|
||||||
msgstr "Upravit úkol"
|
msgstr "Upravit úkol"
|
||||||
|
|
||||||
msgid "Are you sure to delete task \"%s\"?"
|
msgid "Are you sure you want to delete task \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat úkol „%s?"
|
msgstr "Odstranit úkol „%s“?"
|
||||||
|
|
||||||
msgid "%s task is due to be done"
|
msgid "%s task is due to be done"
|
||||||
msgid_plural "%s tasks are due to be done"
|
msgid_plural "%s tasks are due to be done"
|
||||||
|
|
@ -726,8 +718,8 @@ msgstr "Upravit skupinu produktů"
|
||||||
msgid "Product group"
|
msgid "Product group"
|
||||||
msgstr "Skupina produktů"
|
msgstr "Skupina produktů"
|
||||||
|
|
||||||
msgid "Are you sure to delete product group \"%s\"?"
|
msgid "Are you sure you want to delete product group \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat skupinu produktů „%s“?"
|
msgstr "Odstranit skupinu produktů „%s“?"
|
||||||
|
|
||||||
msgid "Stay logged in permanently"
|
msgid "Stay logged in permanently"
|
||||||
msgstr "Zůstat přihlášen"
|
msgstr "Zůstat přihlášen"
|
||||||
|
|
@ -805,7 +797,7 @@ msgid "Create equipment"
|
||||||
msgstr "Vytvořit vybavení"
|
msgstr "Vytvořit vybavení"
|
||||||
|
|
||||||
msgid "The current file will be deleted on save"
|
msgid "The current file will be deleted on save"
|
||||||
msgstr "Aktuální soubor bude smazán při uložení této položky vybavení"
|
msgstr "Soubor se smaže až po kliknutí na tlačítku Uložit"
|
||||||
|
|
||||||
msgid "No picture available"
|
msgid "No picture available"
|
||||||
msgstr "Obrázek není k dispozici"
|
msgstr "Obrázek není k dispozici"
|
||||||
|
|
@ -898,7 +890,11 @@ msgid "Not opened"
|
||||||
msgstr "Neotevřené"
|
msgstr "Neotevřené"
|
||||||
|
|
||||||
msgid "Opened"
|
msgid "Opened"
|
||||||
msgstr "Otevřené"
|
msgid_plural "Opened"
|
||||||
|
msgstr[0] "Otevřeno"
|
||||||
|
msgstr[1] "Otevřené"
|
||||||
|
msgstr[2] "Otevřených"
|
||||||
|
msgstr[3] "Otevřených"
|
||||||
|
|
||||||
msgid "%s opened"
|
msgid "%s opened"
|
||||||
msgstr "%s otevřen"
|
msgstr "%s otevřen"
|
||||||
|
|
@ -1007,7 +1003,7 @@ msgid "Gallery"
|
||||||
msgstr "Galerie"
|
msgstr "Galerie"
|
||||||
|
|
||||||
msgid "The current picture will be deleted on save"
|
msgid "The current picture will be deleted on save"
|
||||||
msgstr "Aktuální obrázek bude smazán při uložení nového"
|
msgstr "Obrázek se smaže až po kliknutí na jedno z tlačítek Uložit"
|
||||||
|
|
||||||
msgid "Journal for this battery"
|
msgid "Journal for this battery"
|
||||||
msgstr "Deník k této baterii"
|
msgstr "Deník k této baterii"
|
||||||
|
|
@ -1064,8 +1060,8 @@ msgstr "Nastavení úkolů"
|
||||||
msgid "Create shopping list"
|
msgid "Create shopping list"
|
||||||
msgstr "Vytvořit nákupní seznam"
|
msgstr "Vytvořit nákupní seznam"
|
||||||
|
|
||||||
msgid "Are you sure to delete shopping list \"%s\"?"
|
msgid "Are you sure you want to delete shopping list \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat nákupní seznam „%s?"
|
msgstr "Smazat nákupní seznam „%s?"
|
||||||
|
|
||||||
msgid "Average shelf life"
|
msgid "Average shelf life"
|
||||||
msgstr "Průměrná doba uskladnění"
|
msgstr "Průměrná doba uskladnění"
|
||||||
|
|
@ -1107,10 +1103,10 @@ msgid "Sunday"
|
||||||
msgstr "Neděle"
|
msgstr "Neděle"
|
||||||
|
|
||||||
msgid "Configure userfields"
|
msgid "Configure userfields"
|
||||||
msgstr "Upravit uživatelská pole"
|
msgstr "Upravit sloupce tabulky"
|
||||||
|
|
||||||
msgid "Userfields"
|
msgid "Userfields"
|
||||||
msgstr "Uživatelská pole"
|
msgstr "Vlastní sloupce tabulky"
|
||||||
|
|
||||||
msgid "Entity"
|
msgid "Entity"
|
||||||
msgstr "Entita"
|
msgstr "Entita"
|
||||||
|
|
@ -1122,7 +1118,7 @@ msgid "Type"
|
||||||
msgstr "Typ"
|
msgstr "Typ"
|
||||||
|
|
||||||
msgid "Create userfield"
|
msgid "Create userfield"
|
||||||
msgstr "Vytvoř uživatelské pole"
|
msgstr "Vytvořit sloupec uživatelské tabulky"
|
||||||
|
|
||||||
msgid "A entity is required"
|
msgid "A entity is required"
|
||||||
msgstr "Proměnná je povinný údaj"
|
msgstr "Proměnná je povinný údaj"
|
||||||
|
|
@ -1137,10 +1133,10 @@ msgid "Show as column in tables"
|
||||||
msgstr "Zobrazit jako řádek v tabulkách"
|
msgstr "Zobrazit jako řádek v tabulkách"
|
||||||
|
|
||||||
msgid "This is required and can only contain letters and numbers"
|
msgid "This is required and can only contain letters and numbers"
|
||||||
msgstr "Toto je povinné pole a může obsahovat pouze písmena a číslice"
|
msgstr "Toto je povinný údaj a může obsahovat pouze písmena a číslice"
|
||||||
|
|
||||||
msgid "Edit userfield"
|
msgid "Edit userfield"
|
||||||
msgstr "Upravit uživatelská pole"
|
msgstr "Upravit sloupec uživatelské tabulky"
|
||||||
|
|
||||||
msgid "Plural forms"
|
msgid "Plural forms"
|
||||||
msgstr "Množné čislo"
|
msgstr "Množné čislo"
|
||||||
|
|
@ -1236,10 +1232,6 @@ msgstr "Nikdy"
|
||||||
msgid "Today"
|
msgid "Today"
|
||||||
msgstr "Dnes"
|
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"
|
msgid "Undo task"
|
||||||
msgstr "Vrátit úkol"
|
msgstr "Vrátit úkol"
|
||||||
|
|
||||||
|
|
@ -1278,8 +1270,8 @@ msgstr "Spotřebované množství"
|
||||||
msgid "Time of printing"
|
msgid "Time of printing"
|
||||||
msgstr "Čas tisku"
|
msgstr "Čas tisku"
|
||||||
|
|
||||||
msgid "Are you sure to delete equipment \"%s\"?"
|
msgid "Are you sure you want to delete equipment \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat vybavení „%s“?"
|
msgstr "Odstranit zařízení „%s“?"
|
||||||
|
|
||||||
msgid "Parent product"
|
msgid "Parent product"
|
||||||
msgstr "Nadřazený produkt"
|
msgstr "Nadřazený produkt"
|
||||||
|
|
@ -1458,8 +1450,8 @@ msgstr "Přiřazení"
|
||||||
msgid "Consume product on chore execution"
|
msgid "Consume product on chore execution"
|
||||||
msgstr "Spotřebovat produkt při splnění povinnosti"
|
msgstr "Spotřebovat produkt při splnění povinnosti"
|
||||||
|
|
||||||
msgid "Are you sure to delete user field \"%s\"?"
|
msgid "Are you sure you want to delete user field \"%s\"?"
|
||||||
msgstr "Opravdu si přejete smazat uživatelské pole „%s“?"
|
msgstr "Odstranit sloupec „%s“?"
|
||||||
|
|
||||||
msgid "Userentities"
|
msgid "Userentities"
|
||||||
msgstr "Uživatelské tabulky"
|
msgstr "Uživatelské tabulky"
|
||||||
|
|
@ -1479,8 +1471,8 @@ msgstr "Upravit %s"
|
||||||
msgid "Create %s"
|
msgid "Create %s"
|
||||||
msgstr "Vytvořit %s"
|
msgstr "Vytvořit %s"
|
||||||
|
|
||||||
msgid "Are you sure to delete this userobject?"
|
msgid "Are you sure you want to delete this userobject?"
|
||||||
msgstr "Opravdu si přejete smazat položku definovanou uživatelem?"
|
msgstr "Odstranit položku definovanou uživatelem?"
|
||||||
|
|
||||||
msgid "Icon CSS class"
|
msgid "Icon CSS class"
|
||||||
msgstr "CSS třída ikony"
|
msgstr "CSS třída ikony"
|
||||||
|
|
@ -1516,7 +1508,7 @@ msgid "Price factor"
|
||||||
msgstr "Násobek ceny ingredience"
|
msgstr "Násobek ceny ingredience"
|
||||||
|
|
||||||
msgid "Do you find Grocy useful?"
|
msgid "Do you find Grocy useful?"
|
||||||
msgstr "Je pro vás Grocy užitečný?"
|
msgstr "Je pro vás Grocy užitečné?"
|
||||||
|
|
||||||
msgid "Say thanks"
|
msgid "Say thanks"
|
||||||
msgstr "Poděkujte za aplikaci"
|
msgstr "Poděkujte za aplikaci"
|
||||||
|
|
@ -1546,7 +1538,7 @@ msgid "Expected barcode"
|
||||||
msgstr "Očekávaný čárový kód"
|
msgstr "Očekávaný čárový kód"
|
||||||
|
|
||||||
msgid "Scan field"
|
msgid "Scan field"
|
||||||
msgstr "Skenovací pole"
|
msgstr "Naskenováno"
|
||||||
|
|
||||||
msgid "Scanned barcodes"
|
msgid "Scanned barcodes"
|
||||||
msgstr "Naskenované čárové kódy"
|
msgstr "Naskenované čárové kódy"
|
||||||
|
|
@ -1571,8 +1563,8 @@ msgstr ""
|
||||||
"přičteno do tohoto produktu. To znamená že podřízené produkty nikdy nebudou "
|
"přičteno do tohoto produktu. To znamená že podřízené produkty nikdy nebudou "
|
||||||
"chybět, ale pouze tento produkt."
|
"chybět, ale pouze tento produkt."
|
||||||
|
|
||||||
msgid "Are you sure to remove this conversion?"
|
msgid "Are you sure you want to remove this conversion?"
|
||||||
msgstr "Opravdu chcete odstranit tento převod?"
|
msgstr "Odstranit tento převod?"
|
||||||
|
|
||||||
msgid "Unit price"
|
msgid "Unit price"
|
||||||
msgstr "Cena za jednotku"
|
msgstr "Cena za jednotku"
|
||||||
|
|
@ -1589,8 +1581,8 @@ msgstr "Neomezeně"
|
||||||
msgid "Clear"
|
msgid "Clear"
|
||||||
msgstr "Vymazat"
|
msgstr "Vymazat"
|
||||||
|
|
||||||
msgid "Are you sure to remove the included recipe \"%s\"?"
|
msgid "Are you sure you want to remove the included recipe \"%s\"?"
|
||||||
msgstr "Opravdu chcete odstranit dílčí recept „%s“?"
|
msgstr "Odstranit dílčí recept „%s“?"
|
||||||
|
|
||||||
msgid "Period interval"
|
msgid "Period interval"
|
||||||
msgstr "Interval opakování"
|
msgstr "Interval opakování"
|
||||||
|
|
@ -1686,8 +1678,8 @@ msgstr "Tato akce nemůže být vrácena zpět"
|
||||||
msgid "Booking does not exist or was already undone"
|
msgid "Booking does not exist or was already undone"
|
||||||
msgstr "Tato akce neexistuje nebo již byla vrácena zpět"
|
msgstr "Tato akce neexistuje nebo již byla vrácena zpět"
|
||||||
|
|
||||||
msgid "Are you sure to delete API key \"%s\"?"
|
msgid "Are you sure you want to delete API key \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat API klíč „%s“?"
|
msgstr "Odstranit API klíč „%s“?"
|
||||||
|
|
||||||
msgid "Add note"
|
msgid "Add note"
|
||||||
msgstr "Přidat poznámku"
|
msgstr "Přidat poznámku"
|
||||||
|
|
@ -1727,7 +1719,7 @@ msgstr "vypnut"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Scan mode is on but not all required fields could be populated automatically"
|
"Scan mode is on but not all required fields could be populated automatically"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Skenovací režim je zapnutý, ale ne všechna vyžadovaná pole mohou být "
|
"Skenovací režim je zapnutý, ale ne všechna vyžadovaná data mohou být "
|
||||||
"vyplněna automaticky"
|
"vyplněna automaticky"
|
||||||
|
|
||||||
msgid "Is freezer"
|
msgid "Is freezer"
|
||||||
|
|
@ -1742,8 +1734,8 @@ msgstr "Rozmraženo"
|
||||||
msgid "Frozen"
|
msgid "Frozen"
|
||||||
msgstr "Zmraženo"
|
msgstr "Zmraženo"
|
||||||
|
|
||||||
msgid "Are you sure to delete userentity \"%s\"?"
|
msgid "Are you sure you want to delete userentity \"%s\"?"
|
||||||
msgstr "Opravdu chcete smazat uživatelskou tabulku „%s“?"
|
msgstr "Odstranit uživatelský sloupec tabulky „%s“?"
|
||||||
|
|
||||||
msgid "Shopping list settings"
|
msgid "Shopping list settings"
|
||||||
msgstr "Nastavení nákupního seznamu"
|
msgstr "Nastavení nákupního seznamu"
|
||||||
|
|
@ -1754,9 +1746,6 @@ msgstr "Zobrazit měsíční kalendář"
|
||||||
msgid "Desired servings"
|
msgid "Desired servings"
|
||||||
msgstr "Počet porcí"
|
msgstr "Počet porcí"
|
||||||
|
|
||||||
msgid "Base: %s"
|
|
||||||
msgstr "Základ: %s"
|
|
||||||
|
|
||||||
msgid "Recipes settings"
|
msgid "Recipes settings"
|
||||||
msgstr "Nastavení receptu"
|
msgstr "Nastavení receptu"
|
||||||
|
|
||||||
|
|
@ -1840,13 +1829,13 @@ msgstr "Upravit čárový kód"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Based on the prices of the default consume rule (Opened first, then first "
|
"Based on the prices of the default consume rule (Opened first, then first "
|
||||||
"due first, then first in first out) for in-stock ingredients and on the last"
|
"due first, then first in first out) for in stock ingredients and on the last"
|
||||||
" price for missing ones"
|
" price for missing ones"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Základem ceny je cena produktu v zásobě podle výchozího pořadí spotřeby "
|
"Základem ceny je cena produktu v zásobě podle výchozího pořadí spotřeby "
|
||||||
"produktů. Tedy nejprve se spotřebují otevřené, pak ty s nejbližším datem "
|
"produktů. Tedy nejprve se spotřebují otevřené, pak ty s nejbližším datem "
|
||||||
"spotřeby a nakonec podle pravidla „dříve nakoupený, dříve spotřebovaný“. Pro"
|
"spotřeby a nakonec podle pravidla „dříve nakoupený – dříve spotřebovaný“. "
|
||||||
" chybějící produkty je použita cena z posledního nákupu."
|
"Pro chybějící produkty je použita cena z posledního nákupu."
|
||||||
|
|
||||||
msgid "Clear filter"
|
msgid "Clear filter"
|
||||||
msgstr "Smazat filtr"
|
msgstr "Smazat filtr"
|
||||||
|
|
@ -1880,8 +1869,8 @@ msgstr "Výpis běžících funkcí – stack trace"
|
||||||
|
|
||||||
msgid "Easy error info copy & paste (for reporting)"
|
msgid "Easy error info copy & paste (for reporting)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Budete-li psát vývojářům, pošlete jim celý tento text. Stačí do něj kliknout"
|
"Budete-li psát vývojářům, pošlete jim text níže. Stačí do něj kliknout a "
|
||||||
" a celý se vybere (pro Ctrl-C)."
|
"celý se vybere (pro Ctrl-C)."
|
||||||
|
|
||||||
msgid "This page does not exist"
|
msgid "This page does not exist"
|
||||||
msgstr "Tato stránka neexistuje"
|
msgstr "Tato stránka neexistuje"
|
||||||
|
|
@ -2016,7 +2005,7 @@ msgstr ""
|
||||||
"Upozorni, pokud je datum min. trvanlivosti (použitelnosti) nakoupeného "
|
"Upozorni, pokud je datum min. trvanlivosti (použitelnosti) nakoupeného "
|
||||||
"produktu dříve, než nejbližší datum spotřeby produktu v zásobě."
|
"produktu dříve, než nejbližší datum spotřeby produktu v zásobě."
|
||||||
|
|
||||||
msgid "This is due earlier than already in-stock items"
|
msgid "This is due earlier than already in stock items"
|
||||||
msgstr "Datum min. trvanlivosti je dříve, než u produktů v zásobě"
|
msgstr "Datum min. trvanlivosti je dříve, než u produktů v zásobě"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
|
|
@ -2047,8 +2036,8 @@ msgstr ""
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "Kopírovat"
|
msgstr "Kopírovat"
|
||||||
|
|
||||||
msgid "Are you sure to remove this barcode?"
|
msgid "Are you sure you want to remove this barcode?"
|
||||||
msgstr "Opravdu chcete smazat tento čárový kód?"
|
msgstr "Odstranit tento čárový kód?"
|
||||||
|
|
||||||
msgid "Due date type"
|
msgid "Due date type"
|
||||||
msgstr "Typ trvanlivosti produktu"
|
msgstr "Typ trvanlivosti produktu"
|
||||||
|
|
@ -2203,7 +2192,7 @@ msgstr "Takto se položka databáze zobrazuje ve webové stránce"
|
||||||
|
|
||||||
msgid "Multiple Userfields will be ordered by that number on the input form"
|
msgid "Multiple Userfields will be ordered by that number on the input form"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Řada uživatelských položek bude uspořádána podle tohoto čísla při jejich "
|
"Řada uživatelských sloupců bude uspořádána podle tohoto čísla při jejich "
|
||||||
"zadávání"
|
"zadávání"
|
||||||
|
|
||||||
msgid "Sort number"
|
msgid "Sort number"
|
||||||
|
|
@ -2245,8 +2234,8 @@ msgstr "Skupina ingrediencí"
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "Resetovat"
|
msgstr "Resetovat"
|
||||||
|
|
||||||
msgid "Are you sure to reset the table options?"
|
msgid "Are you sure you want to reset the table options?"
|
||||||
msgstr "Opravdu chcete uvést sloupce tabulky do výchozího stavu?"
|
msgstr "Uvést sloupce tabulky do výchozího stavu?"
|
||||||
|
|
||||||
msgid "Hide/view columns"
|
msgid "Hide/view columns"
|
||||||
msgstr "Zobrazit/skrýt sloupce"
|
msgstr "Zobrazit/skrýt sloupce"
|
||||||
|
|
@ -2312,7 +2301,7 @@ msgid "Link"
|
||||||
msgstr "Odkaz"
|
msgstr "Odkaz"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"The stock overview page lists all products which are currently in-stock or "
|
"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 "
|
"below their min. stock amount - enable this to hide this product there "
|
||||||
"always"
|
"always"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -2390,7 +2379,7 @@ msgstr "Nedaří se tisknout"
|
||||||
msgid "Only done items"
|
msgid "Only done items"
|
||||||
msgstr "vybrané produkty"
|
msgstr "vybrané produkty"
|
||||||
|
|
||||||
msgid "Show only in-stock products"
|
msgid "Show only in stock products"
|
||||||
msgstr "Zobrazit produkty se zásobou"
|
msgstr "Zobrazit produkty se zásobou"
|
||||||
|
|
||||||
msgid "Product description"
|
msgid "Product description"
|
||||||
|
|
@ -2407,12 +2396,12 @@ msgid "Mandatory"
|
||||||
msgstr "Povinné"
|
msgstr "Povinné"
|
||||||
|
|
||||||
msgid "Mandatory Userfield"
|
msgid "Mandatory Userfield"
|
||||||
msgstr "Povinné uživatelské pole"
|
msgstr "Povinný uživatelský údaj"
|
||||||
|
|
||||||
msgid "When enabled, then this field must be filled on the destination form"
|
msgid "When enabled, then this field must be filled on the destination form"
|
||||||
msgstr "Použijete-li tento údaj ve formuláři, bude povinný"
|
msgstr "Použijete-li tento údaj ve formuláři, bude povinný"
|
||||||
|
|
||||||
msgid "In-stock products"
|
msgid "In stock products"
|
||||||
msgstr "produkty se zásobou"
|
msgstr "produkty se zásobou"
|
||||||
|
|
||||||
msgid "Timestamp"
|
msgid "Timestamp"
|
||||||
|
|
@ -2503,14 +2492,14 @@ msgstr ""
|
||||||
msgid "Edit meal plan section"
|
msgid "Edit meal plan section"
|
||||||
msgstr "Upravit část dne v jídelníčku"
|
msgstr "Upravit část dne v jídelníčku"
|
||||||
|
|
||||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
msgid "Are you sure you want to delete meal plan section \"%s\"?"
|
||||||
msgstr "Chcete odstranit rozdělení dne s názvem: %s?"
|
msgstr "Odstranit rozdělení dne s názvem: %s?"
|
||||||
|
|
||||||
msgid "Section"
|
msgid "Section"
|
||||||
msgstr "Část dne v jídelníčku"
|
msgstr "Část dne v jídelníčku"
|
||||||
|
|
||||||
msgid "Are you sure to empty the shopping list?"
|
msgid "Are you sure you want to empty the shopping list?"
|
||||||
msgstr "Opravdu chcete smazat nákupní seznam?"
|
msgstr "Vyprázdnit nákupní seznam?"
|
||||||
|
|
||||||
msgid "This is the default which will be prefilled on purchase"
|
msgid "This is the default which will be prefilled on purchase"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -2728,7 +2717,7 @@ msgid "Decimal places allowed for prices (display)"
|
||||||
msgstr "Počet desetinných míst pro zobrazení ceny"
|
msgstr "Počet desetinných míst pro zobrazení ceny"
|
||||||
|
|
||||||
msgid "Clear done items"
|
msgid "Clear done items"
|
||||||
msgstr "Smazat všechna zaškrtnutá"
|
msgstr "Odstranit všechna vybraná"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"This shows all to this product directly or indirectly related quantity units"
|
"This shows all to this product directly or indirectly related quantity units"
|
||||||
|
|
@ -2743,7 +2732,7 @@ msgstr "Zobrazit všechny převody"
|
||||||
msgid "QU conversions resolved"
|
msgid "QU conversions resolved"
|
||||||
msgstr "Všechny převody měrných jednotek pro"
|
msgstr "Všechny převody měrných jednotek pro"
|
||||||
|
|
||||||
msgid "Product specifc QU conversions"
|
msgid "Product specific QU conversions"
|
||||||
msgstr "Převody měrných jednotek pro tento produkt"
|
msgstr "Převody měrných jednotek pro tento produkt"
|
||||||
|
|
||||||
msgid "Default quantity unit consume"
|
msgid "Default quantity unit consume"
|
||||||
|
|
@ -2780,7 +2769,7 @@ msgid "Track chore execution now"
|
||||||
msgstr "Splnění povinnosti s dnešním datem"
|
msgstr "Splnění povinnosti s dnešním datem"
|
||||||
|
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "Součet"
|
msgstr "Celkem"
|
||||||
|
|
||||||
msgid "Apply"
|
msgid "Apply"
|
||||||
msgstr "Provést"
|
msgstr "Provést"
|
||||||
|
|
@ -2819,16 +2808,16 @@ msgstr "Výdaje"
|
||||||
msgid "Stock report"
|
msgid "Stock report"
|
||||||
msgstr "Přehled zásob"
|
msgstr "Přehled zásob"
|
||||||
|
|
||||||
msgid "Out-of-stock products"
|
msgid "Out of stock products"
|
||||||
msgstr "Produkty bez zásoby"
|
msgstr "Produkty bez zásoby"
|
||||||
|
|
||||||
msgid "Quantity unit for prices"
|
msgid "Quantity unit for prices"
|
||||||
msgstr "Množstevní jednotka pro ceny"
|
msgstr "Měrná jednotka pro ceny"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"When displaying prices for this product, they will be related to this "
|
"When displaying prices for this product, they will be related to this "
|
||||||
"quantity unit"
|
"quantity unit"
|
||||||
msgstr "Zobrazované ceny produktu budou odpovídat této množstevní jednotce"
|
msgstr "Zobrazované ceny produktu budou odpovídat této měrné jednotce"
|
||||||
|
|
||||||
msgid "This means 1 label will be printed"
|
msgid "This means 1 label will be printed"
|
||||||
msgid_plural "This means %1$s labels will be printed"
|
msgid_plural "This means %1$s labels will be printed"
|
||||||
|
|
@ -2836,3 +2825,77 @@ msgstr[0] "Vytiskne se 1nálepka"
|
||||||
msgstr[1] "Vytisknou se %1$s nálepky"
|
msgstr[1] "Vytisknou se %1$s nálepky"
|
||||||
msgstr[2] "Vytiskne se %1$s nálepek"
|
msgstr[2] "Vytiskne se %1$s nálepek"
|
||||||
msgstr[3] "Vytiskne se %1$s nálepek"
|
msgstr[3] "Vytiskne se %1$s nálepek"
|
||||||
|
|
||||||
|
msgid "External barcode lookup"
|
||||||
|
msgstr "Čtení čárového kódu modulem aplikace"
|
||||||
|
|
||||||
|
msgid "Error while executing the barcode lookup plugin"
|
||||||
|
msgstr "Vyhodnocení doplňkovým modulem se nezdařilo"
|
||||||
|
|
||||||
|
msgid "Nothing was found for the given barcode"
|
||||||
|
msgstr "Pro tento čárový kód nebylo nic nalezeno"
|
||||||
|
|
||||||
|
msgid "Configure colors"
|
||||||
|
msgstr "Změnit barvy"
|
||||||
|
|
||||||
|
msgid "Swap track next schedule / track now buttons"
|
||||||
|
msgstr ""
|
||||||
|
"Změna funkce zeleného tlačítka: Zaznamenat splnění naplánované povinnosti "
|
||||||
|
"NEBO Zaznamenat splnění povinnosti právě teď."
|
||||||
|
|
||||||
|
msgid "Scheduled tracking time"
|
||||||
|
msgstr "Naplánované splnění povinnosti"
|
||||||
|
|
||||||
|
msgid "Time of tracking"
|
||||||
|
msgstr "Plnění povinností"
|
||||||
|
|
||||||
|
msgid "Show all out of stock products"
|
||||||
|
msgstr "Zobrazit produkty bez zásoby"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"By default the stock overview page lists all products which are currently in"
|
||||||
|
" stock or below their min. stock amount - when this is enabled, all (active)"
|
||||||
|
" products are always shown"
|
||||||
|
msgstr ""
|
||||||
|
"Stránka Přehledu zásob zobrazuje všechny produkty, které jsou v zásobě nebo "
|
||||||
|
"pod jejich minimálním stavem. Zaškrtnutím se zobrazí všechny (aktivní) "
|
||||||
|
"produkty."
|
||||||
|
|
||||||
|
msgid "No price information is available for at least one ingredient"
|
||||||
|
msgstr "U nejméně jedné ingredience chybí informace o ceně"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For ingredients that are only partially in stock, the in stock amount will "
|
||||||
|
"be consumed."
|
||||||
|
msgstr ""
|
||||||
|
"U ingrediencí, kde není v zásobě celé jejich množství se spotřebuje jejich "
|
||||||
|
"aktuální zásoba."
|
||||||
|
|
||||||
|
msgid "Can't be opened"
|
||||||
|
msgstr "Tento produkt nelze „otevřít“."
|
||||||
|
|
||||||
|
msgid "Default purchase price type"
|
||||||
|
msgstr "Výchozí druh ceny"
|
||||||
|
|
||||||
|
msgid "This will be used as the default price type selection on purchase"
|
||||||
|
msgstr "Toto bude použito jako výchozí druh ceny při nákupu"
|
||||||
|
|
||||||
|
msgid "Unspecified"
|
||||||
|
msgstr "Neurčené"
|
||||||
|
|
||||||
|
msgid "Round up quantity amounts to the nearest whole number"
|
||||||
|
msgstr "Zaokrouhlete množství na (nejbližší) celé číslo"
|
||||||
|
|
||||||
|
msgid "Stock actions"
|
||||||
|
msgstr "Operace se zásobami"
|
||||||
|
|
||||||
|
msgid "List actions"
|
||||||
|
msgstr "Operace se seznamem"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"After this product was once in stock and when the desired quantity unit "
|
||||||
|
"cannot be selected here, first create a corresponding unit conversion"
|
||||||
|
msgstr ""
|
||||||
|
"Pokud byl tento produkt alespoň jednou v zásobě a není na výběr jednotka "
|
||||||
|
"množství, kterou byste potřebovali, vytvořte si vhodnou konverzi stávající "
|
||||||
|
"množstevní jednotky."
|
||||||
|
|
|
||||||