From 74f94707699ae101082e14043861d3e59940359b Mon Sep 17 00:00:00 2001 From: Bernd Bestel Date: Tue, 17 Sep 2019 13:13:26 +0200 Subject: [PATCH] Implemented that chores can be assigned to users (closes #253) --- .tx/config | 12 +- changelog/52_UNRELEASED_2019-xx-xx.md | 3 + controllers/ChoresApiController.php | 33 +++++ controllers/ChoresController.php | 18 ++- grocy.openapi.json | 71 ++++++++++- helpers/extensions.php | 14 ++- localization/chore_assignment_types.pot | 25 ++++ ...chore_types.pot => chore_period_types.pot} | 0 localization/component_translations.pot | 3 + localization/da/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 14 +-- localization/da/component_translations.po | 19 ++- localization/de/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/de/component_translations.po | 3 + localization/en/chore_assignment_types.po | 25 ++++ .../{chore_types.po => chore_period_types.po} | 5 +- localization/en/component_translations.po | 3 + localization/en_GB/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/en_GB/component_translations.po | 17 ++- localization/es/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/es/component_translations.po | 3 + localization/fr/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/fr/component_translations.po | 3 + localization/it/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/it/component_translations.po | 25 ++-- localization/nl/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/nl/component_translations.po | 3 + localization/no/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 5 +- localization/no/component_translations.po | 3 + localization/pl/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/pl/component_translations.po | 3 + localization/ru/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/ru/component_translations.po | 3 + localization/strings.pot | 46 ++++++- localization/sv_SE/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/sv_SE/component_translations.po | 3 + localization/ta/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/ta/component_translations.po | 3 + localization/tr/chore_assignment_types.po | 26 ++++ .../{chore_types.po => chore_period_types.po} | 0 localization/tr/component_translations.po | 3 + migrations/0082.sql | 4 +- migrations/0083.sql | 74 +++++++++++ package.json | 3 +- public/viewjs/choreform.js | 70 ++++++++++- public/viewjs/choresoverview.js | 18 ++- routes.php | 1 + services/ChoresService.php | 117 ++++++++++++++++-- services/DemoDataGeneratorService.php | 4 +- services/LocalizationService.php | 6 +- views/choreform.blade.php | 32 ++++- views/choresoverview.blade.php | 21 +++- views/layout/default.blade.php | 1 + yarn.lock | 5 + 65 files changed, 987 insertions(+), 75 deletions(-) create mode 100644 localization/chore_assignment_types.pot rename localization/{chore_types.pot => chore_period_types.pot} (100%) create mode 100644 localization/da/chore_assignment_types.po rename localization/da/{chore_types.po => chore_period_types.po} (72%) create mode 100644 localization/de/chore_assignment_types.po rename localization/de/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/en/chore_assignment_types.po rename localization/en/{chore_types.po => chore_period_types.po} (99%) create mode 100644 localization/en_GB/chore_assignment_types.po rename localization/en_GB/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/es/chore_assignment_types.po rename localization/es/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/fr/chore_assignment_types.po rename localization/fr/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/it/chore_assignment_types.po rename localization/it/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/nl/chore_assignment_types.po rename localization/nl/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/no/chore_assignment_types.po rename localization/no/{chore_types.po => chore_period_types.po} (83%) create mode 100644 localization/pl/chore_assignment_types.po rename localization/pl/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/ru/chore_assignment_types.po rename localization/ru/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/sv_SE/chore_assignment_types.po rename localization/sv_SE/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/ta/chore_assignment_types.po rename localization/ta/{chore_types.po => chore_period_types.po} (100%) create mode 100644 localization/tr/chore_assignment_types.po rename localization/tr/{chore_types.po => chore_period_types.po} (100%) create mode 100644 migrations/0083.sql diff --git a/.tx/config b/.tx/config index 8a923e1a..4f86a1be 100644 --- a/.tx/config +++ b/.tx/config @@ -1,9 +1,15 @@ [main] host = https://www.transifex.com -[grocy.chore_types] -file_filter = localization//chore_types.po -source_file = localization/chore_types.pot +[grocy.chore_period_types] +file_filter = localization//chore_period_types.po +source_file = localization/chore_period_types.pot +source_lang = en +type = PO + +[grocy.chore_assignment_types] +file_filter = localization//chore_assignment_types.po +source_file = localization/chore_assignment_types.pot source_lang = en type = PO diff --git a/changelog/52_UNRELEASED_2019-xx-xx.md b/changelog/52_UNRELEASED_2019-xx-xx.md index 1b74ca60..972d7be7 100644 --- a/changelog/52_UNRELEASED_2019-xx-xx.md +++ b/changelog/52_UNRELEASED_2019-xx-xx.md @@ -12,6 +12,9 @@ - Recipe improvements - Based on the new linked quantity units, recipe ingredients can now use any product related unit, the amount is calculated according to the cnoversion factor of the unit relation - Chores improvements + - Chores can now be assigned to users + - Option per chore, different "assignment types" like "Random", "Who least did first", etc. + - On the chores overview page the list can be filterd to only show chores assigned to the currently logged in user - New option "Due date rollover" per chore which means the chore can never be overdue, the due date will shift forward each day when due - Equipment improvements/fixes - Fixed that the delete button not always deleted the currently selected equipment item diff --git a/controllers/ChoresApiController.php b/controllers/ChoresApiController.php index 7b4c28bc..4fb6b336 100644 --- a/controllers/ChoresApiController.php +++ b/controllers/ChoresApiController.php @@ -70,4 +70,37 @@ class ChoresApiController extends BaseApiController return $this->GenericErrorResponse($response, $ex->getMessage()); } } + + public function CalculateNextExecutionAssignments(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) + { + try + { + $requestBody = $request->getParsedBody(); + + $choreId = null; + if (array_key_exists('chore_id', $requestBody) && !empty($requestBody['chore_id']) && is_numeric($requestBody['chore_id'])) + { + $choreId = intval($requestBody['chore_id']); + } + + if ($choreId === null) + { + $chores = $this->Database->chores(); + foreach ($chores as $chore) + { + $this->ChoresService->CalculateNextExecutionAssignment($chore->id); + } + } + else + { + $this->ChoresService->CalculateNextExecutionAssignment($choreId); + } + + return $this->EmptyApiResponse($response); + } + catch (\Exception $ex) + { + return $this->GenericErrorResponse($response, $ex->getMessage()); + } + } } diff --git a/controllers/ChoresController.php b/controllers/ChoresController.php index e483441b..2c224e7d 100644 --- a/controllers/ChoresController.php +++ b/controllers/ChoresController.php @@ -28,7 +28,8 @@ class ChoresController extends BaseController 'currentChores' => $this->ChoresService->GetCurrent(), 'nextXDays' => $nextXDays, 'userfields' => $this->UserfieldsService->GetFields('chores'), - 'userfieldValues' => $this->UserfieldsService->GetAllValues('chores') + 'userfieldValues' => $this->UserfieldsService->GetAllValues('chores'), + 'users' => $usersService->GetUsersAsDto() ]); } @@ -60,21 +61,28 @@ class ChoresController extends BaseController public function ChoreEditForm(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) { + $usersService = new UsersService(); + $users = $usersService->GetUsersAsDto(); + if ($args['choreId'] == 'new') { return $this->AppContainer->view->render($response, 'choreform', [ - 'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService'), + 'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_PERIOD_TYPE_'), 'mode' => 'create', - 'userfields' => $this->UserfieldsService->GetFields('chores') + 'userfields' => $this->UserfieldsService->GetFields('chores'), + 'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'), + 'users' => $users ]); } else { return $this->AppContainer->view->render($response, 'choreform', [ 'chore' => $this->Database->chores($args['choreId']), - 'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService'), + 'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_PERIOD_TYPE_'), 'mode' => 'edit', - 'userfields' => $this->UserfieldsService->GetFields('chores') + 'userfields' => $this->UserfieldsService->GetFields('chores'), + 'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'), + 'users' => $users ]); } } diff --git a/grocy.openapi.json b/grocy.openapi.json index f4d08d7d..f41d6432 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -2100,6 +2100,48 @@ } } }, + "/chores/executions/calculate-next-assignments": { + "post": { + "summary": "(Re)calculates all next user assignments of all chores", + "tags": [ + "Chores" + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "chore_id": { + "type": "integer", + "description": "The chore id of the chore which next user assignment should be (re)calculated, when omitted, the next user assignments of all chores will (re)caluclated" + } + }, + "example": { + "chore_id": 1 + } + } + } + } + }, + "responses": { + "204": { + "description": "The operation was successful" + }, + "400": { + "description": "The operation was not successful", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenericErrorResponse" + } + } + } + } + } + } + }, "/batteries": { "get": { "summary": "Returns all batteries incl. the next estimated charge time per battery", @@ -2853,6 +2895,9 @@ "next_estimated_execution_time": { "type": "string", "format": "date-time" + }, + "next_execution_assigned_user": { + "$ref": "#/components/schemas/UserDto" } }, "example": { @@ -3091,15 +3136,39 @@ "type": "string", "enum": [ "manually", - "dynamic-regular" + "dynamic-regular", + "daily", + "weekly", + "monthly" ] }, + "period_config": { + "type": "string" + }, "period_days": { "type": "integer" }, "track_date_only": { "type": "boolean" }, + "rollover": { + "type": "boolean" + }, + "assignment_type": { + "type": "string", + "enum": [ + "no-assignment", + "who-least-did-first", + "random", + "in-alphabetical-order" + ] + }, + "assignment_config": { + "type": "string" + }, + "next_execution_assigned_to_user_id": { + "type": "integer" + }, "row_created_timestamp": { "type": "string", "format": "date-time" diff --git a/helpers/extensions.php b/helpers/extensions.php index 8bf97e23..e92b85a4 100644 --- a/helpers/extensions.php +++ b/helpers/extensions.php @@ -88,10 +88,20 @@ function SumArrayValue($array, $propertyName) return $sum; } -function GetClassConstants($className) +function GetClassConstants($className, $prefix = null) { $r = new ReflectionClass($className); - return $r->getConstants(); + $constants = $r->getConstants(); + + if ($prefix === null) + { + return $constants; + } + else + { + $matchingKeys = preg_grep('!^' . $prefix . '!', array_keys($constants)); + return array_intersect_key($constants, array_flip($matchingKeys)); + } } function RandomString($length, $allowedChars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') diff --git a/localization/chore_assignment_types.pot b/localization/chore_assignment_types.pot new file mode 100644 index 00000000..90d5e087 --- /dev/null +++ b/localization/chore_assignment_types.pot @@ -0,0 +1,25 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Translation migration from old PHP array files\n" +"Language-Team: http://www.transifex.com/grocy/grocy/language/en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n" +"PO-Revision-Date: 2019-05-01T17:59:17+00:00\n" +"Language: en\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 "" diff --git a/localization/chore_types.pot b/localization/chore_period_types.pot similarity index 100% rename from localization/chore_types.pot rename to localization/chore_period_types.pot diff --git a/localization/component_translations.pot b/localization/component_translations.pot index a513bd0d..f65749a6 100644 --- a/localization/component_translations.pot +++ b/localization/component_translations.pot @@ -29,3 +29,6 @@ msgstr "" msgid "fullcalendar_locale" msgstr "" + +msgid "bootstrap-select_locale" +msgstr "" diff --git a/localization/da/chore_assignment_types.po b/localization/da/chore_assignment_types.po new file mode 100644 index 00000000..ac5e6068 --- /dev/null +++ b/localization/da/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Danish (https://www.transifex.com/grocy/teams/93189/da/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: da\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 "" diff --git a/localization/da/chore_types.po b/localization/da/chore_period_types.po similarity index 72% rename from localization/da/chore_types.po rename to localization/da/chore_period_types.po index c47253ad..e521501c 100644 --- a/localization/da/chore_types.po +++ b/localization/da/chore_period_types.po @@ -1,5 +1,5 @@ # Translators: -# Bernd Bestel , 2019 +# Troels Siggaard , 2019 # msgid "" msgstr "" @@ -7,7 +7,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-05-01T17:59:17+00:00\n" "PO-Revision-Date: 2019-05-01 17:42+0000\n" -"Last-Translator: Bernd Bestel , 2019\n" +"Last-Translator: Troels Siggaard , 2019\n" "Language-Team: Danish (https://www.transifex.com/grocy/teams/93189/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -17,16 +17,16 @@ msgstr "" "X-Domain: grocy/chore_types\n" msgid "manually" -msgstr "Manuelt" +msgstr "manuelt" msgid "dynamic-regular" -msgstr "" +msgstr "gentagende-dynamisk" msgid "daily" -msgstr "" +msgstr "daglig" msgid "weekly" -msgstr "" +msgstr "ugentlig" msgid "monthly" -msgstr "" +msgstr "månedlig" diff --git a/localization/da/component_translations.po b/localization/da/component_translations.po index 1de9e2c5..a4dc0810 100644 --- a/localization/da/component_translations.po +++ b/localization/da/component_translations.po @@ -1,3 +1,6 @@ +# Translators: +# Troels Siggaard , 2019 +# Bernd Bestel , 2019 # msgid "" msgstr "" @@ -5,6 +8,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-05-01T17:59:17+00:00\n" "PO-Revision-Date: 2019-05-01 17:42+0000\n" +"Last-Translator: Bernd Bestel , 2019\n" "Language-Team: Danish (https://www.transifex.com/grocy/teams/93189/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -14,19 +18,22 @@ msgstr "" "X-Domain: grocy/component_translations\n" msgid "timeago_locale" -msgstr "" +msgstr "timdsiden_lokal" msgid "timeago_nan" -msgstr "" +msgstr "tidsiden_ien" msgid "moment_locale" -msgstr "" +msgstr "tidspunkt_lokal" msgid "datatables_localization" -msgstr "" +msgstr "datatabeller_lokalisering" msgid "summernote_locale" -msgstr "" +msgstr "summernote_lokal" msgid "fullcalendar_locale" -msgstr "" +msgstr "fuldkalender_lokal" + +msgid "bootstrap-select_locale" +msgstr "da_DK" diff --git a/localization/de/chore_assignment_types.po b/localization/de/chore_assignment_types.po new file mode 100644 index 00000000..3fe6f071 --- /dev/null +++ b/localization/de/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: German (https://www.transifex.com/grocy/teams/93189/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: de\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 "" diff --git a/localization/de/chore_types.po b/localization/de/chore_period_types.po similarity index 100% rename from localization/de/chore_types.po rename to localization/de/chore_period_types.po diff --git a/localization/de/component_translations.po b/localization/de/component_translations.po index 6066893b..2f6d6dc7 100644 --- a/localization/de/component_translations.po +++ b/localization/de/component_translations.po @@ -52,3 +52,6 @@ msgstr "de-DE" msgid "fullcalendar_locale" msgstr "de" + +msgid "bootstrap-select_locale" +msgstr "de_DE" diff --git a/localization/en/chore_assignment_types.po b/localization/en/chore_assignment_types.po new file mode 100644 index 00000000..306c74df --- /dev/null +++ b/localization/en/chore_assignment_types.po @@ -0,0 +1,25 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Translation migration from old PHP array files\n" +"Language-Team: http://www.transifex.com/grocy/grocy/language/en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n" +"PO-Revision-Date: 2019-05-01T17:59:17+00:00\n" +"Language: en\n" +"X-Domain: grocy/chore_assignment_types\n" + +msgid "no-assignment" +msgstr "No assignment" + +msgid "who-least-did-first" +msgstr "Who least did first" + +msgid "random" +msgstr "Random" + +msgid "in-alphabetical-order" +msgstr "In alphabetical order" diff --git a/localization/en/chore_types.po b/localization/en/chore_period_types.po similarity index 99% rename from localization/en/chore_types.po rename to localization/en/chore_period_types.po index 9ba782f7..dc6c4a78 100644 --- a/localization/en/chore_types.po +++ b/localization/en/chore_period_types.po @@ -1,14 +1,15 @@ +# 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-01T17:59:17+00:00\n" "Last-Translator: Translation migration from old PHP array files\n" "Language-Team: http://www.transifex.com/grocy/grocy/language/en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n" -"PO-Revision-Date: 2019-05-01T17:59:17+00:00\n" "Language: en\n" "X-Domain: grocy/chore_types\n" diff --git a/localization/en/component_translations.po b/localization/en/component_translations.po index e0937cfc..12759406 100644 --- a/localization/en/component_translations.po +++ b/localization/en/component_translations.po @@ -29,3 +29,6 @@ msgstr "x" msgid "fullcalendar_locale" msgstr "x" + +msgid "bootstrap-select_locale" +msgstr "x" diff --git a/localization/en_GB/chore_assignment_types.po b/localization/en_GB/chore_assignment_types.po new file mode 100644 index 00000000..cacd1f2f --- /dev/null +++ b/localization/en_GB/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: English (United Kingdom) (https://www.transifex.com/grocy/teams/93189/en_GB/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en_GB\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 "" diff --git a/localization/en_GB/chore_types.po b/localization/en_GB/chore_period_types.po similarity index 100% rename from localization/en_GB/chore_types.po rename to localization/en_GB/chore_period_types.po diff --git a/localization/en_GB/component_translations.po b/localization/en_GB/component_translations.po index 5f32a302..78a9c2d0 100644 --- a/localization/en_GB/component_translations.po +++ b/localization/en_GB/component_translations.po @@ -17,19 +17,32 @@ msgstr "" "X-Domain: grocy/component_translations\n" msgid "timeago_locale" -msgstr "" +msgstr "en" msgid "timeago_nan" -msgstr "" +msgstr "NaN years ago" msgid "moment_locale" msgstr "en-gb" msgid "datatables_localization" msgstr "" +"{\"sEmptyTable\":\"No data available in table\",\"sInfo\":\"Showing _START_ " +"to _END_ of _TOTAL_ entries\",\"sInfoEmpty\":\"Showing 0 to 0 of 0 " +"entries\",\"sInfoFiltered\":\"(filtered from _MAX_ total " +"entries)\",\"sInfoPostFix\":\"\",\"sInfoThousands\":\",\",\"sLengthMenu\":\"Show" +" _MENU_ " +"entries\",\"sLoadingRecords\":\"Loading...\",\"sProcessing\":\"Processing...\",\"sSearch\":\"Search:\",\"sZeroRecords\":\"No" +" matching records " +"found\",\"oPaginate\":{\"sFirst\":\"First\",\"sLast\":\"Last\",\"sNext\":\"Next\",\"sPrevious\":\"Previous\"},\"oAria\":{\"sSortAscending\":\":" +" activate to sort column ascending\",\"sSortDescending\":\": activate to " +"sort column descending\"}}" msgid "summernote_locale" msgstr "en-gb" msgid "fullcalendar_locale" msgstr "en-gb" + +msgid "bootstrap-select_locale" +msgstr "x" diff --git a/localization/es/chore_assignment_types.po b/localization/es/chore_assignment_types.po new file mode 100644 index 00000000..a8886bc6 --- /dev/null +++ b/localization/es/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Spanish (https://www.transifex.com/grocy/teams/93189/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\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 "" diff --git a/localization/es/chore_types.po b/localization/es/chore_period_types.po similarity index 100% rename from localization/es/chore_types.po rename to localization/es/chore_period_types.po diff --git a/localization/es/component_translations.po b/localization/es/component_translations.po index b186639d..1bbfcd88 100644 --- a/localization/es/component_translations.po +++ b/localization/es/component_translations.po @@ -43,3 +43,6 @@ msgstr "es-ES" msgid "fullcalendar_locale" msgstr "es" + +msgid "bootstrap-select_locale" +msgstr "es_ES" diff --git a/localization/fr/chore_assignment_types.po b/localization/fr/chore_assignment_types.po new file mode 100644 index 00000000..bbc92d12 --- /dev/null +++ b/localization/fr/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: French (https://www.transifex.com/grocy/teams/93189/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fr\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 "" diff --git a/localization/fr/chore_types.po b/localization/fr/chore_period_types.po similarity index 100% rename from localization/fr/chore_types.po rename to localization/fr/chore_period_types.po diff --git a/localization/fr/component_translations.po b/localization/fr/component_translations.po index c823b363..d70b80f4 100644 --- a/localization/fr/component_translations.po +++ b/localization/fr/component_translations.po @@ -47,3 +47,6 @@ msgstr "fr-FR" msgid "fullcalendar_locale" msgstr "fr" + +msgid "bootstrap-select_locale" +msgstr "fr_FR" diff --git a/localization/it/chore_assignment_types.po b/localization/it/chore_assignment_types.po new file mode 100644 index 00000000..cf28407d --- /dev/null +++ b/localization/it/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Italian (https://www.transifex.com/grocy/teams/93189/it/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: it\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 "" diff --git a/localization/it/chore_types.po b/localization/it/chore_period_types.po similarity index 100% rename from localization/it/chore_types.po rename to localization/it/chore_period_types.po diff --git a/localization/it/component_translations.po b/localization/it/component_translations.po index f8514a6f..c87ccfa6 100644 --- a/localization/it/component_translations.po +++ b/localization/it/component_translations.po @@ -1,4 +1,5 @@ # Translators: +# Antonino Ursino , 2019 # Bernd Bestel , 2019 # msgid "" @@ -17,28 +18,22 @@ msgstr "" "X-Domain: grocy/component_translations\n" msgid "timeago_locale" -msgstr "it" +msgstr "tempofa_locale" msgid "timeago_nan" -msgstr "NaN anni fa" +msgstr "tempofa_nan" msgid "moment_locale" -msgstr "it" +msgstr "istante_locale" msgid "datatables_localization" -msgstr "" -"{\"sEmptyTable\":\"Nessun dato disponibile\",\"sInfo\":\"Mostrando da " -"_START_ a _END_ di _TOTAL_ voci\",\"sInfoEmpty\":\"Mostrando da 0 a 0 di 0 " -"voci\",\"sInfoFiltered\":\"(Filtrato da _MAX_ voci " -"totali)\",\"sInfoPostFix\":\"\",\"sInfoThousands\":\",\",\"sLengthMenu\":\"Mostra" -" _MENU_ " -"voci\",\"sLoadingRecords\":\"Caricando...\",\"sProcessing\":\"Calcolando...\",\"sSearch\":\"Cerca:\",\"sZeroRecords\":\"Nessun" -" risultato " -"trovato\",\"oPaginate\":{\"sFirst\":\"Prima\",\"sLast\":\"Ultima\",\"sNext\":\"Prossima\",\"sPrevious\":\"Precedente\"},\"oAria\":{\"sSortAscending\":\":" -" ordine crescente\",\"sSortDescending\":\": ordine decrescente\"}}" +msgstr "datitabelle_localizzazione" msgid "summernote_locale" -msgstr "it-IT" +msgstr "summernote_locale" msgid "fullcalendar_locale" -msgstr "fr" +msgstr "calendariocompleto_locale" + +msgid "bootstrap-select_locale" +msgstr "it_IT" diff --git a/localization/nl/chore_assignment_types.po b/localization/nl/chore_assignment_types.po new file mode 100644 index 00000000..ef2ad59d --- /dev/null +++ b/localization/nl/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Dutch (https://www.transifex.com/grocy/teams/93189/nl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: nl\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 "" diff --git a/localization/nl/chore_types.po b/localization/nl/chore_period_types.po similarity index 100% rename from localization/nl/chore_types.po rename to localization/nl/chore_period_types.po diff --git a/localization/nl/component_translations.po b/localization/nl/component_translations.po index 3a82e60c..d860ce99 100644 --- a/localization/nl/component_translations.po +++ b/localization/nl/component_translations.po @@ -45,3 +45,6 @@ msgstr "nl-NL" msgid "fullcalendar_locale" msgstr "nl" + +msgid "bootstrap-select_locale" +msgstr "nl_NL" diff --git a/localization/no/chore_assignment_types.po b/localization/no/chore_assignment_types.po new file mode 100644 index 00000000..ca98a8df --- /dev/null +++ b/localization/no/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: no\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 "" diff --git a/localization/no/chore_types.po b/localization/no/chore_period_types.po similarity index 83% rename from localization/no/chore_types.po rename to localization/no/chore_period_types.po index e408b30e..ffe8051c 100644 --- a/localization/no/chore_types.po +++ b/localization/no/chore_period_types.po @@ -1,5 +1,6 @@ # Translators: # Bernd Bestel , 2019 +# Andreas Henden , 2019 # msgid "" msgstr "" @@ -7,7 +8,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-05-01T17:59:17+00:00\n" "PO-Revision-Date: 2019-05-01 17:42+0000\n" -"Last-Translator: Bernd Bestel , 2019\n" +"Last-Translator: Andreas Henden , 2019\n" "Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -17,7 +18,7 @@ msgstr "" "X-Domain: grocy/chore_types\n" msgid "manually" -msgstr "Manuel" +msgstr "manuelt" msgid "dynamic-regular" msgstr "Automatisk" diff --git a/localization/no/component_translations.po b/localization/no/component_translations.po index 0094213b..764095e0 100644 --- a/localization/no/component_translations.po +++ b/localization/no/component_translations.po @@ -48,3 +48,6 @@ msgstr "nb-NO" msgid "fullcalendar_locale" msgstr "nb" + +msgid "bootstrap-select_locale" +msgstr "nb_NO" diff --git a/localization/pl/chore_assignment_types.po b/localization/pl/chore_assignment_types.po new file mode 100644 index 00000000..66363a9a --- /dev/null +++ b/localization/pl/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Polish (https://www.transifex.com/grocy/teams/93189/pl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pl\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\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 "" diff --git a/localization/pl/chore_types.po b/localization/pl/chore_period_types.po similarity index 100% rename from localization/pl/chore_types.po rename to localization/pl/chore_period_types.po diff --git a/localization/pl/component_translations.po b/localization/pl/component_translations.po index 56fd2295..a7d39191 100644 --- a/localization/pl/component_translations.po +++ b/localization/pl/component_translations.po @@ -43,3 +43,6 @@ msgstr "pl-PL" msgid "fullcalendar_locale" msgstr "pl" + +msgid "bootstrap-select_locale" +msgstr "pl_PL" diff --git a/localization/ru/chore_assignment_types.po b/localization/ru/chore_assignment_types.po new file mode 100644 index 00000000..a0bbc97f --- /dev/null +++ b/localization/ru/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Russian (https://www.transifex.com/grocy/teams/93189/ru/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ru\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\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 "" diff --git a/localization/ru/chore_types.po b/localization/ru/chore_period_types.po similarity index 100% rename from localization/ru/chore_types.po rename to localization/ru/chore_period_types.po diff --git a/localization/ru/component_translations.po b/localization/ru/component_translations.po index d25210d2..54761505 100644 --- a/localization/ru/component_translations.po +++ b/localization/ru/component_translations.po @@ -33,3 +33,6 @@ msgstr "ru-RU" msgid "fullcalendar_locale" msgstr "ru" + +msgid "bootstrap-select_locale" +msgstr "ru_RU" diff --git a/localization/strings.pot b/localization/strings.pot index 0f7990e2..421945ba 100644 --- a/localization/strings.pot +++ b/localization/strings.pot @@ -349,7 +349,7 @@ msgstr "" msgid "This means %s will be removed from stock" msgstr "" -msgid "This means it is estimated that a new execution of this chore is tracked %s days after the last was tracked" +msgid "This means the next execution of this chore is scheduled %s days after the last execution" msgstr "" msgid "Removed %1$s of %2$s from stock" @@ -1367,3 +1367,47 @@ msgstr "" msgid "Edit QU conversion" msgstr "" + +msgid "An assignment type is required" +msgstr "" + +msgid "Assignment type" +msgstr "" + +msgid "This means the next execution of this chore is scheduled 1 day after the last execution" +msgstr "" + +msgid "This means the next execution of this chore is scheduled 1 day after the last execution, but only for the weekdays selected below" +msgstr "" + +msgid "This means the next execution of this chore is not scheduled" +msgstr "" + +msgid "This means the next execution of this chore is scheduled on the below selected day of each month" +msgstr "" + +msgid "This means the next execution of this chore will not be assigned to anyone" +msgstr "" + +msgid "This means the next execution of this chore will be assigned to the one who executed it least" +msgstr "" + +msgid "This means the next execution of this chore will be assigned randomly" +msgstr "" + +msgid "This means the next execution of this chore will be assigned to the next one in alphabetical order" +msgstr "" + +msgid "Assign to" +msgstr "" + +msgid "This assignment type requires that at least one is assigned" +msgstr "" + +msgid "%s chore is assigned to me" +msgid_plural "%s chores are assigned to me" +msgstr[0] "" +msgstr[1] "" + +msgid "Assigned to me" +msgstr "" diff --git a/localization/sv_SE/chore_assignment_types.po b/localization/sv_SE/chore_assignment_types.po new file mode 100644 index 00000000..0751501a --- /dev/null +++ b/localization/sv_SE/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Swedish (Sweden) (https://www.transifex.com/grocy/teams/93189/sv_SE/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sv_SE\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 "" diff --git a/localization/sv_SE/chore_types.po b/localization/sv_SE/chore_period_types.po similarity index 100% rename from localization/sv_SE/chore_types.po rename to localization/sv_SE/chore_period_types.po diff --git a/localization/sv_SE/component_translations.po b/localization/sv_SE/component_translations.po index 7cb1a9be..40b39585 100644 --- a/localization/sv_SE/component_translations.po +++ b/localization/sv_SE/component_translations.po @@ -43,3 +43,6 @@ msgstr "sv-SE" msgid "fullcalendar_locale" msgstr "sv" + +msgid "bootstrap-select_locale" +msgstr "sv_SE" diff --git a/localization/ta/chore_assignment_types.po b/localization/ta/chore_assignment_types.po new file mode 100644 index 00000000..1fe9fe75 --- /dev/null +++ b/localization/ta/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Tamil (https://www.transifex.com/grocy/teams/93189/ta/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ta\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 "" diff --git a/localization/ta/chore_types.po b/localization/ta/chore_period_types.po similarity index 100% rename from localization/ta/chore_types.po rename to localization/ta/chore_period_types.po diff --git a/localization/ta/component_translations.po b/localization/ta/component_translations.po index 3838faa2..ee5a2957 100644 --- a/localization/ta/component_translations.po +++ b/localization/ta/component_translations.po @@ -30,3 +30,6 @@ msgstr "" msgid "fullcalendar_locale" msgstr "" + +msgid "bootstrap-select_locale" +msgstr "" diff --git a/localization/tr/chore_assignment_types.po b/localization/tr/chore_assignment_types.po new file mode 100644 index 00000000..4ca8561b --- /dev/null +++ b/localization/tr/chore_assignment_types.po @@ -0,0 +1,26 @@ +# +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" +"Language-Team: Turkish (https://www.transifex.com/grocy/teams/93189/tr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: tr\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 "" diff --git a/localization/tr/chore_types.po b/localization/tr/chore_period_types.po similarity index 100% rename from localization/tr/chore_types.po rename to localization/tr/chore_period_types.po diff --git a/localization/tr/component_translations.po b/localization/tr/component_translations.po index e958877a..37cb4dc7 100644 --- a/localization/tr/component_translations.po +++ b/localization/tr/component_translations.po @@ -44,3 +44,6 @@ msgstr "tr-TR" msgid "fullcalendar_locale" msgstr "tr" + +msgid "bootstrap-select_locale" +msgstr "tr_TR" diff --git a/migrations/0082.sql b/migrations/0082.sql index 23e56cee..ed81cd4b 100644 --- a/migrations/0082.sql +++ b/migrations/0082.sql @@ -67,7 +67,7 @@ UNION -- Second: Product specific overrides SELECT -p.id AS id, -- Dummy, LessQL needs an id column + p.id AS id, -- Dummy, LessQL needs an id column p.id AS product_id, quc.from_qu_id AS from_qu_id, qu_from.name AS from_qu_name, @@ -87,7 +87,7 @@ UNION -- Third: Default quantity unit conversion factors SELECT -p.id AS id, -- Dummy, LessQL needs an id column + p.id AS id, -- Dummy, LessQL needs an id column p.id AS product_id, p.qu_id_stock AS from_qu_id, qu_from.name AS from_qu_name, diff --git a/migrations/0083.sql b/migrations/0083.sql new file mode 100644 index 00000000..861bc242 --- /dev/null +++ b/migrations/0083.sql @@ -0,0 +1,74 @@ +ALTER TABLE chores +ADD assignment_type TEXT; + +ALTER TABLE chores +ADD assignment_config TEXT; + +ALTER TABLE chores +ADD next_execution_assigned_to_user_id INT; + +DROP VIEW chores_current; +CREATE VIEW chores_current +AS +SELECT + x.chore_id, + x.last_tracked_time, + CASE WHEN x.rollover = 1 AND DATETIME('now', 'localtime') > x.next_estimated_execution_time THEN + DATETIME(STRFTIME('%Y-%m-%d', DATETIME('now', 'localtime')) || ' ' || STRFTIME('%H:%M:%S', x.next_estimated_execution_time)) + ELSE + x.next_estimated_execution_time + END AS next_estimated_execution_time, + x.track_date_only, + x.next_execution_assigned_to_user_id +FROM ( + +SELECT + h.id AS chore_id, + MAX(l.tracked_time) AS last_tracked_time, + CASE h.period_type + WHEN 'manually' THEN '2999-12-31 23:59:59' + WHEN 'dynamic-regular' THEN DATETIME(MAX(l.tracked_time), '+' || CAST(h.period_days AS TEXT) || ' day') + WHEN 'daily' THEN DATETIME(IFNULL(MAX(l.tracked_time), DATETIME('now', 'localtime')), '+1 day') + WHEN 'weekly' THEN + CASE + WHEN period_config LIKE '%sunday%' THEN DATETIME(IFNULL(MAX(l.tracked_time), DATETIME('now', 'localtime')), '1 days', 'weekday 0') + WHEN period_config LIKE '%monday%' THEN DATETIME(IFNULL(MAX(l.tracked_time), DATETIME('now', 'localtime')), '1 days', 'weekday 1') + WHEN period_config LIKE '%tuesday%' THEN DATETIME(IFNULL(MAX(l.tracked_time), DATETIME('now', 'localtime')), '1 days', 'weekday 2') + WHEN period_config LIKE '%wednesday%' THEN DATETIME(IFNULL(MAX(l.tracked_time), DATETIME('now', 'localtime')), '1 days', 'weekday 3') + WHEN period_config LIKE '%thursday%' THEN DATETIME(IFNULL(MAX(l.tracked_time), DATETIME('now', 'localtime')), '1 days', 'weekday 4') + WHEN period_config LIKE '%friday%' THEN DATETIME(IFNULL(MAX(l.tracked_time), DATETIME('now', 'localtime')), '1 days', 'weekday 5') + WHEN period_config LIKE '%saturday%' THEN DATETIME(IFNULL(MAX(l.tracked_time), DATETIME('now', 'localtime')), '1 days', 'weekday 6') + END + WHEN 'monthly' THEN DATETIME(IFNULL(MAX(l.tracked_time), DATETIME('now', 'localtime')), '+1 month', 'start of month', '+' || CAST(h.period_days - 1 AS TEXT) || ' day') + END AS next_estimated_execution_time, + h.track_date_only, + h.rollover, + h.next_execution_assigned_to_user_id +FROM chores h +LEFT JOIN chores_log l + ON h.id = l.chore_id + AND l.undone = 0 +GROUP BY h.id, h.period_days + +) x; + +CREATE VIEW chores_assigned_users_resolved +AS +SELECT + c.id AS chore_id, + u.id AS user_id +FROM chores c +JOIN users u + ON ',' || c.assignment_config || ',' LIKE '%,' || CAST(u.id AS TEXT) || ',%'; + +CREATE VIEW chores_execution_users_statistics +AS +SELECT + c.id AS id, -- Dummy, LessQL needs an id column + c.id AS chore_id, + caur.user_id AS user_id, + (SELECT COUNT(1) FROM chores_log WHERE chore_id = c.id AND done_by_user_id = caur.user_id AND undone = 0) AS execution_count +FROM chores c +JOIN chores_assigned_users_resolved caur + ON c.id = caur.chore_id +GROUP BY c.id, caur.user_id; diff --git a/package.json b/package.json index a5bed61f..27cf9823 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "swagger-ui-dist": "^3.22.1", "tempusdominus-bootstrap-4": "https://github.com/berrnd/tempusdominus-bootstrap-4.git#master", "timeago": "^1.6.7", - "toastr": "^2.1.4" + "toastr": "^2.1.4", + "bootstrap-select": "^1.13.10" } } diff --git a/public/viewjs/choreform.js b/public/viewjs/choreform.js index ebe74574..cde3e161 100644 --- a/public/viewjs/choreform.js +++ b/public/viewjs/choreform.js @@ -3,6 +3,7 @@ e.preventDefault(); var jsonData = $('#chore-form').serializeJSON({ checkboxUncheckedValue: "0" }); + jsonData.assignment_config = $("#assignment_config").val().join(","); Grocy.FrontendHelpers.BeginUiBusy("chore-form"); if (Grocy.EditMode === 'create') @@ -13,7 +14,17 @@ Grocy.EditObjectId = result.created_object_id; Grocy.Components.UserfieldsForm.Save(function() { - window.location.href = U('/chores'); + Grocy.Api.Post('chores/executions/calculate-next-assignments', { "chore_id": Grocy.EditObjectId }, + function (result) + { + window.location.href = U('/chores'); + }, + function (xhr) + { + Grocy.FrontendHelpers.EndUiBusy(); + console.error(xhr); + } + ); }); }, function(xhr) @@ -30,7 +41,17 @@ { Grocy.Components.UserfieldsForm.Save(function() { - window.location.href = U('/chores'); + Grocy.Api.Post('chores/executions/calculate-next-assignments', { "chore_id": Grocy.EditObjectId }, + function (result) + { + window.location.href = U('/chores'); + }, + function (xhr) + { + Grocy.FrontendHelpers.EndUiBusy(); + console.error(xhr); + } + ); }); }, function(xhr) @@ -80,6 +101,7 @@ Grocy.FrontendHelpers.ValidateForm('chore-form'); setTimeout(function() { $(".input-group-chore-period-type").trigger("change"); + $(".input-group-chore-assignment-type").trigger("change"); }, 100); $('.input-group-chore-period-type').on('change', function(e) @@ -94,7 +116,7 @@ $('.input-group-chore-period-type').on('change', function(e) if (periodType === 'manually') { - // + $('#chore-period-type-info').text(__t('This means the next execution of this chore is not scheduled')); } else if (periodType === 'dynamic-regular') { @@ -102,21 +124,59 @@ $('.input-group-chore-period-type').on('change', function(e) $("#period_days").attr("min", "0"); $("#period_days").attr("max", "9999"); $("#period_days").parent().find(".invalid-feedback").text(__t('This cannot be negative')); - $('#chore-period-type-info').text(__t('This means it is estimated that a new execution of this chore is tracked %s days after the last was tracked', periodDays.toString())); + $('#chore-period-type-info').text(__t('This means the next execution of this chore is scheduled %s days after the last execution', periodDays.toString())); } else if (periodType === 'daily') { - // + $('#chore-period-type-info').text(__t('This means the next execution of this chore is scheduled 1 day after the last execution')); } else if (periodType === 'weekly') { + $('#chore-period-type-info').text(__t('This means the next execution of this chore is scheduled 1 day after the last execution, but only for the weekdays selected below')); $("#period_config").val($(".period-type-weekly input:checkbox:checked").map(function () { return this.value; }).get().join(",")); } else if (periodType === 'monthly') { + $('#chore-period-type-info').text(__t('This means the next execution of this chore is scheduled on the below selected day of each month')); $("label[for='period_days']").text(__t("Day of month")); $("#period_days").attr("min", "1"); $("#period_days").attr("max", "31"); $("#period_days").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', "1", "31")); } + + Grocy.FrontendHelpers.ValidateForm('chore-form'); +}); + +$('.input-group-chore-assignment-type').on('change', function(e) +{ + var assignmentType = $('#assignment_type').val(); + + $('#chore-period-assignment-info').text(""); + $("#assignment_config").removeAttr("required"); + $("#assignment_config").attr("disabled", ""); + + if (assignmentType === 'no-assignment') + { + $('#chore-assignment-type-info').text(__t('This means the next execution of this chore will not be assigned to anyone')); + } + else if (assignmentType === 'who-least-did-first') + { + $('#chore-assignment-type-info').text(__t('This means the next execution of this chore will be assigned to the one who executed it least')); + $("#assignment_config").attr("required", ""); + $("#assignment_config").removeAttr("disabled"); + } + else if (assignmentType === 'random') + { + $('#chore-assignment-type-info').text(__t('This means the next execution of this chore will be assigned randomly')); + $("#assignment_config").attr("required", ""); + $("#assignment_config").removeAttr("disabled"); + } + else if (assignmentType === 'in-alphabetical-order') + { + $('#chore-assignment-type-info').text(__t('This means the next execution of this chore will be assigned to the next one in alphabetical order')); + $("#assignment_config").attr("required", ""); + $("#assignment_config").removeAttr("disabled"); + } + + Grocy.FrontendHelpers.ValidateForm('chore-form'); }); diff --git a/public/viewjs/choresoverview.js b/public/viewjs/choresoverview.js index e86fe10f..fc93ce6e 100644 --- a/public/viewjs/choresoverview.js +++ b/public/viewjs/choresoverview.js @@ -43,7 +43,7 @@ $("#status-filter").on("change", function() // Transfer CSS classes of selected element to dropdown element (for background) $(this).attr("class", $("#" + $(this).attr("id") + " option[value='" + value + "']").attr("class") + " form-control"); - choresOverviewTable.column(4).search(value).draw(); + choresOverviewTable.column(5).search(value).draw(); }); $(".status-filter-button").on("click", function() @@ -114,6 +114,15 @@ $(document).on('click', '.track-chore-button', function(e) $('#chore-' + choreId + '-next-execution-time-timeago').attr('datetime', result.next_estimated_execution_time); } + if (result.chore.next_execution_assigned_to_user_id != null) + { + $('#chore-' + choreId + '-next-execution-assigned-user').parent().effect('highlight', {}, 500); + $('#chore-' + choreId + '-next-execution-assigned-user').fadeOut(500, function () + { + $(this).text(result.next_execution_assigned_user.display_name).fadeIn(500); + }); + } + Grocy.FrontendHelpers.EndUiBusy(); toastr.success(__t('Tracked execution of chore %1$s on %2$s', choreName, trackedTime)); RefreshStatistics(); @@ -160,6 +169,7 @@ function RefreshStatistics() { var dueCount = 0; var overdueCount = 0; + var assignedToMeCount = 0; var now = moment(); var nextXDaysThreshold = moment().add(nextXDays, "days"); result.forEach(element => { @@ -172,10 +182,16 @@ function RefreshStatistics() { dueCount++; } + + if (parseInt(element.next_execution_assigned_to_user_id) == Grocy.UserId) + { + assignedToMeCount++; + } }); $("#info-due-chores").text(__n(dueCount, '%s chore is due to be done', '%s chores are due to be done') + ' ' + __n(nextXDays, 'within the next day', 'within the next %s days')); $("#info-overdue-chores").text(__n(overdueCount, '%s chore is overdue to be done', '%s chores are overdue to be done')); + $("#info-assigned-to-me-chores").text(__n(assignedToMeCount, '%s chore is assigned to me', '%s chores are assigned to me')); }, function(xhr) { diff --git a/routes.php b/routes.php index 42d7b80a..fb62cd9c 100644 --- a/routes.php +++ b/routes.php @@ -190,6 +190,7 @@ $app->group('/api', function() $this->get('/chores/{choreId}', '\Grocy\Controllers\ChoresApiController:ChoreDetails'); $this->post('/chores/{choreId}/execute', '\Grocy\Controllers\ChoresApiController:TrackChoreExecution'); $this->post('/chores/executions/{executionId}/undo', '\Grocy\Controllers\ChoresApiController:UndoChoreExecution'); + $this->post('/chores/executions/calculate-next-assignments', '\Grocy\Controllers\ChoresApiController:CalculateNextExecutionAssignments'); } // Batteries diff --git a/services/ChoresService.php b/services/ChoresService.php index 1599e35e..e9ab72ab 100644 --- a/services/ChoresService.php +++ b/services/ChoresService.php @@ -4,11 +4,16 @@ namespace Grocy\Services; class ChoresService extends BaseService { - const CHORE_TYPE_MANUALLY = 'manually'; - const CHORE_TYPE_DYNAMIC_REGULAR = 'dynamic-regular'; - const CHORE_TYPE_DAILY = 'daily'; - const CHORE_TYPE_weekly = 'weekly'; - const CHORE_TYPE_monthly = 'monthly'; + const CHORE_PERIOD_TYPE_MANUALLY = 'manually'; + const CHORE_PERIOD_TYPE_DYNAMIC_REGULAR = 'dynamic-regular'; + const CHORE_PERIOD_TYPE_DAILY = 'daily'; + const CHORE_PERIOD_TYPE_WEEKLY = 'weekly'; + const CHORE_PERIOD_TYPE_MONTHLY = 'monthly'; + + const CHORE_ASSIGNMENT_TYPE_NO_ASSIGNMENT = 'no-assignment'; + const CHORE_ASSIGNMENT_TYPE_WHO_LEAST_DID_FIRST = 'who-least-did-first'; + const CHORE_ASSIGNMENT_TYPE_RANDOM = 'random'; + const CHORE_ASSIGNMENT_TYPE_IN_ALPHABETICAL_ORDER = 'in-alphabetical-order'; public function GetCurrent() { @@ -23,26 +28,34 @@ class ChoresService extends BaseService throw new \Exception('Chore does not exist'); } + $usersService = new UsersService(); + $users = $usersService->GetUsersAsDto(); + $chore = $this->Database->chores($choreId); $choreTrackedCount = $this->Database->chores_log()->where('chore_id = :1 AND undone = 0', $choreId)->count(); $choreLastTrackedTime = $this->Database->chores_log()->where('chore_id = :1 AND undone = 0', $choreId)->max('tracked_time'); - $nextExeuctionTime = $this->Database->chores_current()->where('chore_id', $choreId)->min('next_estimated_execution_time'); + $nextExecutionTime = $this->Database->chores_current()->where('chore_id', $choreId)->min('next_estimated_execution_time'); $lastChoreLogRow = $this->Database->chores_log()->where('chore_id = :1 AND tracked_time = :2 AND undone = 0', $choreId, $choreLastTrackedTime)->fetch(); $lastDoneByUser = null; if ($lastChoreLogRow !== null && !empty($lastChoreLogRow)) { - $usersService = new UsersService(); - $users = $usersService->GetUsersAsDto(); $lastDoneByUser = FindObjectInArrayByPropertyValue($users, 'id', $lastChoreLogRow->done_by_user_id); } + $nextExecutionAssignedUser = null; + if (!empty($chore->next_execution_assigned_to_user_id)) + { + $nextExecutionAssignedUser = FindObjectInArrayByPropertyValue($users, 'id', $chore->next_execution_assigned_to_user_id); + } + return array( 'chore' => $chore, 'last_tracked' => $choreLastTrackedTime, 'tracked_count' => $choreTrackedCount, 'last_done_by' => $lastDoneByUser, - 'next_estimated_execution_time' => $nextExeuctionTime + 'next_estimated_execution_time' => $nextExecutionTime, + 'next_execution_assigned_user' => $nextExecutionAssignedUser ); } @@ -72,7 +85,9 @@ class ChoresService extends BaseService )); $logRow->save(); - return $this->Database->lastInsertId(); + $lastInsertId = $this->Database->lastInsertId(); + $this->CalculateNextExecutionAssignment($choreId); + return $lastInsertId; } private function ChoreExists($choreId) @@ -95,4 +110,86 @@ class ChoresService extends BaseService 'undone_timestamp' => date('Y-m-d H:i:s') )); } + + public function CalculateNextExecutionAssignment($choreId) + { + if (!$this->ChoreExists($choreId)) + { + throw new \Exception('Chore does not exist'); + } + + $chore = $this->Database->chores($choreId); + $choreLastTrackedTime = $this->Database->chores_log()->where('chore_id = :1 AND undone = 0', $choreId)->max('tracked_time'); + $lastChoreLogRow = $this->Database->chores_log()->where('chore_id = :1 AND tracked_time = :2 AND undone = 0', $choreId, $choreLastTrackedTime)->fetch(); + $lastDoneByUserId = $lastChoreLogRow->done_by_user_id; + + $usersService = new UsersService(); + $users = $usersService->GetUsersAsDto(); + $assignedUsers = array(); + foreach ($users as $user) + { + if (in_array($user->id, explode(',', $chore->assignment_config))) + { + $assignedUsers[] = $user; + } + } + + $nextExecutionUserId = null; + if ($chore->assignment_type == self::CHORE_ASSIGNMENT_TYPE_RANDOM) + { + // Random assignment and only 1 user in the group? Well, ok - will be hard to guess the next one... + if (count($assignedUsers) == 1) + { + $nextExecutionUserId = array_shift($assignedUsers)->id; + } + else + { + // Randomness in small groups will likely often result in the same user, so try it as long as this is the case + while ($nextExecutionUserId == null || $nextExecutionUserId == $lastDoneByUserId) + { + $nextExecutionUserId = $assignedUsers[array_rand($assignedUsers)]->id; + } + } + } + else if ($chore->assignment_type == self::CHORE_ASSIGNMENT_TYPE_IN_ALPHABETICAL_ORDER) + { + usort($assignedUsers, function($a, $b) + { + return strcmp($a->display_name, $b->display_name); + }); + + $nextRoundMatches = false; + foreach ($assignedUsers as $user) + { + if ($nextRoundMatches) + { + $nextExecutionUserId = $user->id; + break; + } + + if ($user->id == $lastDoneByUserId) + { + $nextRoundMatches = true; + } + } + + // If nothing has matched, probably it was the last user in the sorted list -> the first one is the next one + if ($nextExecutionUserId == null) + { + $nextExecutionUserId = array_shift($assignedUsers)->id; + } + } + else if ($chore->assignment_type == self::CHORE_ASSIGNMENT_TYPE_WHO_LEAST_DID_FIRST) + { + $row = $this->Database->chores_execution_users_statistics()->where('chore_id = :1', $choreId)->orderBy('execution_count')->limit(1)->fetch(); + if ($row != null) + { + $nextExecutionUserId = $row->user_id; + } + } + + $chore->update(array( + 'next_execution_assigned_to_user_id' => $nextExecutionUserId + )); + } } diff --git a/services/DemoDataGeneratorService.php b/services/DemoDataGeneratorService.php index 5074f76a..770c96ab 100644 --- a/services/DemoDataGeneratorService.php +++ b/services/DemoDataGeneratorService.php @@ -125,8 +125,8 @@ class DemoDataGeneratorService extends BaseService INSERt INTO meal_plan(day, recipe_id) VALUES ('{$sundayThisWeek}', 4); INSERT INTO chores (name, period_type, period_days) VALUES ('{$this->__t_sql('Changed towels in the bathroom')}', 'manually', 5); --1 - INSERT INTO chores (name, period_type, period_days) VALUES ('{$this->__t_sql('Cleaned the kitchen floor')}', 'dynamic-regular', 7); --2 - INSERT INTO chores (name, period_type, period_days) VALUES ('{$this->__t_sql('Lawn mowed in the garden')}', 'dynamic-regular', 21); --3 + INSERT INTO chores (name, period_type, period_days, assignment_type, assignment_config, next_execution_assigned_to_user_id) VALUES ('{$this->__t_sql('Cleaned the kitchen floor')}', 'dynamic-regular', 7, 'random', '1,2,3,4', 1); --2 + INSERT INTO chores (name, period_type, period_days, assignment_type, assignment_config, next_execution_assigned_to_user_id) VALUES ('{$this->__t_sql('Lawn mowed in the garden')}', 'dynamic-regular', 21, 'random', '1,2,3,4', 1); --3 INSERT INTO chores (name, period_type, period_days) VALUES ('{$this->__t_sql('The thing which happens on the 5th of every month')}', 'monthly', 5); --4 INSERT INTO chores (name, period_type) VALUES ('{$this->__t_sql('The thing which happens daily')}', 'daily'); --5 INSERT INTO chores (name, period_type, period_config) VALUES ('{$this->__t_sql('The thing which happens on Mondays and Wednesdays')}', 'weekly', 'monday,wednesday'); --6 diff --git a/services/LocalizationService.php b/services/LocalizationService.php index c47301b5..8478510c 100644 --- a/services/LocalizationService.php +++ b/services/LocalizationService.php @@ -34,7 +34,8 @@ class LocalizationService { $this->PotMain = Translations::fromPoFile(__DIR__ . '/../localization/strings.pot'); - $this->Pot = Translations::fromPoFile(__DIR__ . '/../localization/chore_types.pot'); + $this->Pot = Translations::fromPoFile(__DIR__ . '/../localization/chore_period_types.pot'); + $this->Pot = $this->Pot->mergeWith(Translations::fromPoFile(__DIR__ . '/../localization/chore_assignment_types.pot')); $this->Pot = $this->Pot->mergeWith(Translations::fromPoFile(__DIR__ . '/../localization/component_translations.pot')); $this->Pot = $this->Pot->mergeWith(Translations::fromPoFile(__DIR__ . '/../localization/demo_data.pot')); $this->Pot = $this->Pot->mergeWith(Translations::fromPoFile(__DIR__ . '/../localization/stock_transaction_types.pot')); @@ -45,7 +46,8 @@ class LocalizationService $this->PoUserStrings = new Translations(); $this->PoUserStrings->setDomain('grocy/userstrings'); - $this->Po = Translations::fromPoFile(__DIR__ . "/../localization/$culture/chore_types.po"); + $this->Po = Translations::fromPoFile(__DIR__ . "/../localization/$culture/chore_period_types.po"); + $this->Po = $this->Po->mergeWith(Translations::fromPoFile(__DIR__ . "/../localization/$culture/chore_assignment_types.po")); $this->Po = $this->Po->mergeWith(Translations::fromPoFile(__DIR__ . "/../localization/$culture/component_translations.po")); $this->Po = $this->Po->mergeWith(Translations::fromPoFile(__DIR__ . "/../localization/$culture/demo_data.po")); $this->Po = $this->Po->mergeWith(Translations::fromPoFile(__DIR__ . "/../localization/$culture/stock_transaction_types.po")); diff --git a/views/choreform.blade.php b/views/choreform.blade.php index 5fd8c49a..17a3eaaf 100644 --- a/views/choreform.blade.php +++ b/views/choreform.blade.php @@ -8,6 +8,15 @@ @section('viewJsName', 'choreform') +@push('pageScripts') + + @if(!empty($__t('bootstrap-select_locale') && $__t('bootstrap-select_locale') != 'x'))@endif +@endpush + +@push('pageStyles') + +@endpush + @section('content')
@@ -33,7 +42,7 @@
- + +
+ + +
{{ $__t('An assignment type is required') }}
+
+ +
+ + +
{{ $__t('This assignment type requires that at least one is assigned') }}
+
+
diff --git a/views/choresoverview.blade.php b/views/choresoverview.blade.php index 59a67a20..33febe05 100644 --- a/views/choresoverview.blade.php +++ b/views/choresoverview.blade.php @@ -17,7 +17,8 @@

-

+

+

@@ -32,6 +33,7 @@ +
@@ -45,6 +47,7 @@ {{ $__t('Chore') }} {{ $__t('Next estimated tracking') }} {{ $__t('Last tracked') }} + {{ $__t('Assigned to') }} Hidden status @include('components.userfields_thead', array( @@ -55,7 +58,7 @@ @foreach($currentChores as $curentChoreEntry) - + chore_id)->name }} - @if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_TYPE_MANUALLY) + @if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY) {{ $curentChoreEntry->next_estimated_execution_time }} @else @@ -94,8 +97,18 @@ {{ $curentChoreEntry->last_tracked_time }} + + + @if(!empty($curentChoreEntry->next_execution_assigned_to_user_id)) + {{ FindObjectInArrayByPropertyValue($users, 'id', $curentChoreEntry->next_execution_assigned_to_user_id)->display_name }} + @else + ... + @endif + + - @if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_TYPE_MANUALLY && $curentChoreEntry->next_estimated_execution_time < date('Y-m-d H:i:s')) overdue @elseif(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_TYPE_MANUALLY && $curentChoreEntry->next_estimated_execution_time < date('Y-m-d H:i:s', strtotime("+$nextXDays days"))) duesoon @endif + @if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY && $curentChoreEntry->next_estimated_execution_time < date('Y-m-d H:i:s')) overdue @elseif(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY && $curentChoreEntry->next_estimated_execution_time < date('Y-m-d H:i:s', strtotime("+$nextXDays days"))) duesoon @endif + @if($curentChoreEntry->next_execution_assigned_to_user_id == GROCY_USER_ID) assigned-to-me @endif @include('components.userfields_tbody', array( diff --git a/views/layout/default.blade.php b/views/layout/default.blade.php index 6eb4e86e..2fb655c8 100644 --- a/views/layout/default.blade.php +++ b/views/layout/default.blade.php @@ -57,6 +57,7 @@ Grocy.GettextPo = {!! $GettextPo !!}; Grocy.UserSettings = {!! json_encode($userSettings) !!}; Grocy.FeatureFlags = {!! json_encode($featureFlags) !!}; + Grocy.UserId = {{ GROCY_USER_ID }}; diff --git a/yarn.lock b/yarn.lock index 58e144b5..6ce0dfaf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,6 +25,11 @@ bootbox@^5.1.3: bootstrap ">=3.0.0" jquery ">=1.9.1" +bootstrap-select@^1.13.10: + version "1.13.10" + resolved "https://registry.yarnpkg.com/bootstrap-select/-/bootstrap-select-1.13.10.tgz#b0cf57f8d448bc0488faba04ecaa2f4c5216e144" + integrity sha512-mwfyd+VWHY8wDN4je4Y8PPEaOAzDPUz95z5F5zxzlIqebqxtbrujclFWLrhkVOyETpsgZCL1rsfyEnHpAugtGg== + bootstrap@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.0.0.tgz#ceb03842c145fcc1b9b4e15da2a05656ba68469a"