diff --git a/composer.lock b/composer.lock index 3b03a332..5c48ff41 100644 --- a/composer.lock +++ b/composer.lock @@ -775,26 +775,29 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9" + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9", - "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" + }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12", - "phpstan/phpstan": "1.4.10 || 2.0.3", + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", "psr/log": "^1 || ^2 || ^3" }, "suggest": { @@ -814,9 +817,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.4" + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" }, - "time": "2024-12-07T21:18:45+00:00" + "time": "2025-04-07T20:06:18+00:00" }, { "name": "doctrine/doctrine-bundle", @@ -2269,16 +2272,16 @@ }, { "name": "jms/serializer", - "version": "3.32.3", + "version": "3.32.4", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "033c9beab9eb708509a3d400e9f0ffeb2d440e71" + "reference": "f5c6227b2664d1e75fda65f1e6c5686a0c034b31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/033c9beab9eb708509a3d400e9f0ffeb2d440e71", - "reference": "033c9beab9eb708509a3d400e9f0ffeb2d440e71", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/f5c6227b2664d1e75fda65f1e6c5686a0c034b31", + "reference": "f5c6227b2664d1e75fda65f1e6c5686a0c034b31", "shasum": "" }, "require": { @@ -2355,15 +2358,19 @@ ], "support": { "issues": "https://github.com/schmittjoh/serializer/issues", - "source": "https://github.com/schmittjoh/serializer/tree/3.32.3" + "source": "https://github.com/schmittjoh/serializer/tree/3.32.4" }, "funding": [ { "url": "https://github.com/goetas", "type": "github" + }, + { + "url": "https://github.com/scyzoryck", + "type": "github" } ], - "time": "2025-02-11T23:16:25+00:00" + "time": "2025-04-06T18:42:47+00:00" }, { "name": "jms/serializer-bundle", @@ -2456,16 +2463,16 @@ }, { "name": "kevinpapst/tabler-bundle", - "version": "1.7.0", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/kevinpapst/TablerBundle.git", - "reference": "39b5e2946c0d4fea5ad05be9b1cdad686d7035b3" + "reference": "7cf2672d7181041efe0ccb9b1186bc0d87816735" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kevinpapst/TablerBundle/zipball/39b5e2946c0d4fea5ad05be9b1cdad686d7035b3", - "reference": "39b5e2946c0d4fea5ad05be9b1cdad686d7035b3", + "url": "https://api.github.com/repos/kevinpapst/TablerBundle/zipball/7cf2672d7181041efe0ccb9b1186bc0d87816735", + "reference": "7cf2672d7181041efe0ccb9b1186bc0d87816735", "shasum": "" }, "require": { @@ -2515,7 +2522,7 @@ "description": "Admin/Backend theme bundle for Symfony based on Tabler.io", "support": { "issues": "https://github.com/kevinpapst/TablerBundle/issues", - "source": "https://github.com/kevinpapst/TablerBundle/tree/1.7.0" + "source": "https://github.com/kevinpapst/TablerBundle/tree/1.8.0" }, "funding": [ { @@ -2527,7 +2534,7 @@ "type": "github" } ], - "time": "2025-02-13T08:14:16+00:00" + "time": "2025-04-20T12:41:26+00:00" }, { "name": "league/csv", @@ -3867,16 +3874,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.6.1", + "version": "5.6.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8" + "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", - "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62", + "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62", "shasum": "" }, "require": { @@ -3925,9 +3932,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.1" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2" }, - "time": "2024-12-07T09:39:29+00:00" + "time": "2025-04-13T19:20:35+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -10350,16 +10357,16 @@ }, { "name": "zircote/swagger-php", - "version": "5.0.7", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "18457fa71f753cfd4a2b21916baf329864fdfaa6" + "reference": "a9b953c25f5bd11ea0542636936de04504496bd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/18457fa71f753cfd4a2b21916baf329864fdfaa6", - "reference": "18457fa71f753cfd4a2b21916baf329864fdfaa6", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/a9b953c25f5bd11ea0542636936de04504496bd9", + "reference": "a9b953c25f5bd11ea0542636936de04504496bd9", "shasum": "" }, "require": { @@ -10420,8 +10427,8 @@ "homepage": "https://radebatz.net" } ], - "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations", - "homepage": "https://github.com/zircote/swagger-php/", + "description": "Generate interactive documentation for your RESTful API using PHP attributes (preferred) or PHPDoc annotations", + "homepage": "https://github.com/zircote/swagger-php", "keywords": [ "api", "json", @@ -10430,9 +10437,9 @@ ], "support": { "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/5.0.7" + "source": "https://github.com/zircote/swagger-php/tree/5.1.0" }, - "time": "2025-03-19T03:31:11+00:00" + "time": "2025-04-18T00:35:12+00:00" } ], "packages-dev": [ @@ -11267,16 +11274,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.11", + "version": "2.1.12", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30" + "reference": "96dde49e967c0c22812bcfa7bda4ff82c09f3b0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8ca5f79a8f63c49b2359065832a654e1ec70ac30", - "reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/96dde49e967c0c22812bcfa7bda4ff82c09f3b0c", + "reference": "96dde49e967c0c22812bcfa7bda4ff82c09f3b0c", "shasum": "" }, "require": { @@ -11321,7 +11328,7 @@ "type": "github" } ], - "time": "2025-03-24T13:45:00+00:00" + "time": "2025-04-16T13:19:18+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", diff --git a/config/locales.php b/config/locales.php index af28db59..6122d9a3 100644 --- a/config/locales.php +++ b/config/locales.php @@ -1868,6 +1868,13 @@ 'rtl' => false, 'translation' => false, ], + 'ta' => + [ + 'date' => 'd/M/yy', + 'time' => 'h:mm a', + 'rtl' => false, + 'translation' => true, + ], 'tr' => [ 'date' => 'd.MM.y', diff --git a/config/services.yaml b/config/services.yaml index e985506b..441b232c 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -1,7 +1,7 @@ parameters: locale: en # can be regenerated with: bin/console kimai:reset:locales - kimai_locales: ['ar', 'ca', 'cs', 'da', 'de', 'de_CH', 'el', 'en', 'eo', 'es', 'eu', 'fa', 'fi', 'fo', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'nb_NO', 'nl', 'pa', 'pl', 'pt', 'pt_BR', 'ro', 'ru', 'sk', 'sl', 'sv', 'tr', 'uk', 'vi', 'zh_CN', 'zh_Hant', 'zh_Hant_TW', 'ca_AD', 'ca_ES', 'ca_FR', 'ca_IT', 'cs_CZ', 'da_DK', 'da_GL', 'de_AT', 'de_BE', 'de_CH', 'de_DE', 'de_IT', 'de_LI', 'de_LU', 'el_CY', 'el_GR', 'en_AE', 'en_AG', 'en_AI', 'en_AS', 'en_AT', 'en_AU', 'en_BB', 'en_BE', 'en_BI', 'en_BM', 'en_BS', 'en_BW', 'en_BZ', 'en_CA', 'en_CC', 'en_CH', 'en_CK', 'en_CM', 'en_CX', 'en_CY', 'en_DE', 'en_DG', 'en_DK', 'en_DM', 'en_ER', 'en_FI', 'en_FJ', 'en_FK', 'en_FM', 'en_GB', 'en_GD', 'en_GG', 'en_GH', 'en_GI', 'en_GM', 'en_GU', 'en_GY', 'en_HK', 'en_ID', 'en_IE', 'en_IL', 'en_IM', 'en_IN', 'en_IO', 'en_JE', 'en_JM', 'en_KE', 'en_KI', 'en_KN', 'en_KY', 'en_LC', 'en_LR', 'en_LS', 'en_MG', 'en_MH', 'en_MO', 'en_MP', 'en_MS', 'en_MT', 'en_MU', 'en_MV', 'en_MW', 'en_MY', 'en_NA', 'en_NF', 'en_NG', 'en_NH', 'en_NL', 'en_NR', 'en_NU', 'en_NZ', 'en_PG', 'en_PH', 'en_PK', 'en_PN', 'en_PR', 'en_PW', 'en_RH', 'en_RW', 'en_SB', 'en_SC', 'en_SD', 'en_SE', 'en_SG', 'en_SH', 'en_SI', 'en_SL', 'en_SS', 'en_SX', 'en_SZ', 'en_TC', 'en_TK', 'en_TO', 'en_TT', 'en_TV', 'en_TZ', 'en_UG', 'en_UM', 'en_US', 'en_VC', 'en_VG', 'en_VI', 'en_VU', 'en_WS', 'en_ZA', 'en_ZM', 'en_ZW', 'es_AR', 'es_BO', 'es_BR', 'es_BZ', 'es_CL', 'es_CO', 'es_CR', 'es_CU', 'es_DO', 'es_EA', 'es_EC', 'es_ES', 'es_GQ', 'es_GT', 'es_HN', 'es_IC', 'es_MX', 'es_NI', 'es_PA', 'es_PE', 'es_PH', 'es_PR', 'es_PY', 'es_SV', 'es_US', 'es_UY', 'es_VE', 'eu_ES', 'fa_AF', 'fa_IR', 'fi_FI', 'fo_DK', 'fo_FO', 'fr_BE', 'fr_BF', 'fr_BI', 'fr_BJ', 'fr_BL', 'fr_CA', 'fr_CD', 'fr_CF', 'fr_CG', 'fr_CH', 'fr_CI', 'fr_CM', 'fr_DJ', 'fr_DZ', 'fr_FR', 'fr_GA', 'fr_GF', 'fr_GN', 'fr_GP', 'fr_GQ', 'fr_HT', 'fr_KM', 'fr_LU', 'fr_MA', 'fr_MC', 'fr_MF', 'fr_MG', 'fr_ML', 'fr_MQ', 'fr_MR', 'fr_MU', 'fr_NC', 'fr_NE', 'fr_PF', 'fr_PM', 'fr_RE', 'fr_RW', 'fr_SC', 'fr_SN', 'fr_SY', 'fr_TD', 'fr_TG', 'fr_TN', 'fr_VU', 'fr_WF', 'fr_YT', 'he_IL', 'hr_BA', 'hr_HR', 'hu_HU', 'it_CH', 'it_IT', 'it_SM', 'it_VA', 'ja_JP', 'ko_CN', 'ko_KP', 'ko_KR', 'nl_AW', 'nl_BE', 'nl_BQ', 'nl_CW', 'nl_NL', 'nl_SR', 'nl_SX', 'pl_PL', 'pt_AO', 'pt_BR', 'pt_CH', 'pt_CV', 'pt_GQ', 'pt_GW', 'pt_LU', 'pt_MO', 'pt_MZ', 'pt_PT', 'pt_ST', 'pt_TL', 'ro_MD', 'ro_RO', 'ru_BY', 'ru_KG', 'ru_KZ', 'ru_MD', 'ru_RU', 'ru_UA', 'sk_SK', 'sv_AX', 'sv_FI', 'sv_SE', 'tr_CY', 'tr_TR', 'uk_UA', 'vi_VN'] + kimai_locales: ['ar', 'cs', 'da', 'de', 'de_CH', 'el', 'en', 'eo', 'es', 'eu', 'fa', 'fi', 'fo', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'nb_NO', 'nl', 'pa', 'pl', 'pt', 'pt_BR', 'ro', 'ru', 'sk', 'sl', 'sv', 'ta', 'tr', 'uk', 'vi', 'zh_CN', 'zh_Hant', 'zh_Hant_TW', 'cs_CZ', 'da_DK', 'da_GL', 'de_AT', 'de_BE', 'de_CH', 'de_DE', 'de_IT', 'de_LI', 'de_LU', 'el_CY', 'el_GR', 'en_AE', 'en_AG', 'en_AI', 'en_AS', 'en_AT', 'en_AU', 'en_BB', 'en_BE', 'en_BI', 'en_BM', 'en_BS', 'en_BW', 'en_BZ', 'en_CA', 'en_CC', 'en_CH', 'en_CK', 'en_CM', 'en_CX', 'en_CY', 'en_DE', 'en_DG', 'en_DK', 'en_DM', 'en_ER', 'en_FI', 'en_FJ', 'en_FK', 'en_FM', 'en_GB', 'en_GD', 'en_GG', 'en_GH', 'en_GI', 'en_GM', 'en_GU', 'en_GY', 'en_HK', 'en_ID', 'en_IE', 'en_IL', 'en_IM', 'en_IN', 'en_IO', 'en_JE', 'en_JM', 'en_KE', 'en_KI', 'en_KN', 'en_KY', 'en_LC', 'en_LR', 'en_LS', 'en_MG', 'en_MH', 'en_MO', 'en_MP', 'en_MS', 'en_MT', 'en_MU', 'en_MV', 'en_MW', 'en_MY', 'en_NA', 'en_NF', 'en_NG', 'en_NH', 'en_NL', 'en_NR', 'en_NU', 'en_NZ', 'en_PG', 'en_PH', 'en_PK', 'en_PN', 'en_PR', 'en_PW', 'en_RH', 'en_RW', 'en_SB', 'en_SC', 'en_SD', 'en_SE', 'en_SG', 'en_SH', 'en_SI', 'en_SL', 'en_SS', 'en_SX', 'en_SZ', 'en_TC', 'en_TK', 'en_TO', 'en_TT', 'en_TV', 'en_TZ', 'en_UG', 'en_UM', 'en_US', 'en_VC', 'en_VG', 'en_VI', 'en_VU', 'en_WS', 'en_ZA', 'en_ZM', 'en_ZW', 'es_AR', 'es_BO', 'es_BR', 'es_BZ', 'es_CL', 'es_CO', 'es_CR', 'es_CU', 'es_DO', 'es_EA', 'es_EC', 'es_ES', 'es_GQ', 'es_GT', 'es_HN', 'es_IC', 'es_MX', 'es_NI', 'es_PA', 'es_PE', 'es_PH', 'es_PR', 'es_PY', 'es_SV', 'es_US', 'es_UY', 'es_VE', 'eu_ES', 'fa_AF', 'fa_IR', 'fi_FI', 'fo_DK', 'fo_FO', 'fr_BE', 'fr_BF', 'fr_BI', 'fr_BJ', 'fr_BL', 'fr_CA', 'fr_CD', 'fr_CF', 'fr_CG', 'fr_CH', 'fr_CI', 'fr_CM', 'fr_DJ', 'fr_DZ', 'fr_FR', 'fr_GA', 'fr_GF', 'fr_GN', 'fr_GP', 'fr_GQ', 'fr_HT', 'fr_KM', 'fr_LU', 'fr_MA', 'fr_MC', 'fr_MF', 'fr_MG', 'fr_ML', 'fr_MQ', 'fr_MR', 'fr_MU', 'fr_NC', 'fr_NE', 'fr_PF', 'fr_PM', 'fr_RE', 'fr_RW', 'fr_SC', 'fr_SN', 'fr_SY', 'fr_TD', 'fr_TG', 'fr_TN', 'fr_VU', 'fr_WF', 'fr_YT', 'he_IL', 'hr_BA', 'hr_HR', 'hu_HU', 'it_CH', 'it_IT', 'it_SM', 'it_VA', 'ja_JP', 'ko_CN', 'ko_KP', 'ko_KR', 'nl_AW', 'nl_BE', 'nl_BQ', 'nl_CW', 'nl_NL', 'nl_SR', 'nl_SX', 'pl_PL', 'pt_AO', 'pt_BR', 'pt_CH', 'pt_CV', 'pt_GQ', 'pt_GW', 'pt_LU', 'pt_MO', 'pt_MZ', 'pt_PT', 'pt_ST', 'pt_TL', 'ro_MD', 'ro_RO', 'ru_BY', 'ru_KG', 'ru_KZ', 'ru_MD', 'ru_RU', 'ru_UA', 'sk_SK', 'sv_AX', 'sv_FI', 'sv_SE', 'tr_CY', 'tr_TR', 'uk_UA', 'vi_VN'] services: # default configuration for services in *this* file diff --git a/phpstan.neon b/phpstan.neon index 76a3f5ac..8b2ba46c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2097,11 +2097,6 @@ parameters: count: 1 path: src/Form/TimesheetAdminEditForm.php - - - message: "#^Cannot call method format\\(\\) on mixed\\.$#" - count: 4 - path: src/Form/TimesheetEditForm.php - - message: "#^Cannot call method getEnd\\(\\) on App\\\\Entity\\\\Timesheet\\|null\\.$#" count: 2 @@ -2122,11 +2117,6 @@ parameters: count: 1 path: src/Form/TimesheetEditForm.php - - - message: "#^Cannot clone non\\-object variable \\$end of type mixed\\.$#" - count: 1 - path: src/Form/TimesheetEditForm.php - - message: "#^Method App\\\\Form\\\\TimesheetEditForm\\:\\:addActivity\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" count: 1 @@ -3027,46 +3017,6 @@ parameters: count: 1 path: src/Invoice/Hydrator/InvoiceModelCustomerHydrator.php - - - message: "#^Cannot call method getAddress\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - - - message: "#^Cannot call method getCompany\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - - - message: "#^Cannot call method getContact\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - - - message: "#^Cannot call method getDueDays\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - - - message: "#^Cannot call method getLanguage\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - - - message: "#^Cannot call method getName\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - - - message: "#^Cannot call method getPaymentDetails\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - - - message: "#^Cannot call method getPaymentTerms\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - message: "#^Cannot call method getSubtotal\\(\\) on App\\\\Invoice\\\\CalculatorInterface\\|null\\.$#" count: 1 @@ -3082,11 +3032,6 @@ parameters: count: 2 path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - - message: "#^Cannot call method getTitle\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - message: "#^Cannot call method getTotal\\(\\) on App\\\\Invoice\\\\CalculatorInterface\\|null\\.$#" count: 1 @@ -3097,11 +3042,6 @@ parameters: count: 1 path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - - message: "#^Cannot call method getVatId\\(\\) on App\\\\Entity\\\\InvoiceTemplate\\|null\\.$#" - count: 1 - path: src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php - - message: "#^Method App\\\\Invoice\\\\Hydrator\\\\InvoiceModelDefaultHydrator\\:\\:hydrate\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 diff --git a/src/Activity/ActivityService.php b/src/Activity/ActivityService.php index 8daf7e94..6539cad2 100644 --- a/src/Activity/ActivityService.php +++ b/src/Activity/ActivityService.php @@ -120,12 +120,23 @@ class ActivityService // we cannot use max(number) because a varchar column returns unexpected results $start = $this->repository->countActivity(); $i = 0; + $createDate = new \DateTimeImmutable(); do { $start++; - $numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start): string|int { + $numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start, $createDate): string|int { return match ($format) { + 'Y' => $createDate->format('Y'), + 'y' => $createDate->format('y'), + 'M' => $createDate->format('m'), + 'm' => $createDate->format('n'), + 'D' => $createDate->format('d'), + 'd' => $createDate->format('j'), + 'YY' => (int) $createDate->format('Y') + $increaseBy, + 'yy' => (int) $createDate->format('y') + $increaseBy, + 'MM' => (int) $createDate->format('m') + $increaseBy, + 'DD' => (int) $createDate->format('d') + $increaseBy, 'ac' => $start + $increaseBy, default => $originalFormat, }; diff --git a/src/Command/RegenerateLocalesCommand.php b/src/Command/RegenerateLocalesCommand.php index aca0ad1d..d0eb290d 100644 --- a/src/Command/RegenerateLocalesCommand.php +++ b/src/Command/RegenerateLocalesCommand.php @@ -39,7 +39,7 @@ final class RegenerateLocalesCommand extends Command * * @var string[] */ - private array $noRegionCode = ['ar', 'id', 'pa', 'sl', 'ca']; + private array $noRegionCode = ['ar', 'id', 'pa', 'sl', 'ca', 'ta']; /** * A list of locales that will be activated, no matter if translation files exist for them. * @@ -47,11 +47,11 @@ final class RegenerateLocalesCommand extends Command */ private array $addLocaleToList = ['zh_Hant_TW']; /** - * A list of locales that will NOT be activated, as no translations exist by now. + * A list of locales that will NOT be activated, as not enough translations exist by now. * * @var string[] */ - private array $skipLocale = ['ca']; + private array $skipLocale = ['ca', 'et']; public function __construct( private readonly string $projectDirectory, @@ -86,6 +86,7 @@ final class RegenerateLocalesCommand extends Command $firstLevelLocales[] = $l; } $firstLevelLocales = array_unique(array_merge($firstLevelLocales, $this->addLocaleToList)); + $io->title('First level locales found'); $io->writeln(implode('|', $firstLevelLocales)); @@ -198,8 +199,23 @@ final class RegenerateLocalesCommand extends Command // in the future this list should be reduced to the list of available translations, but for a long time users // could choose from the entire list of all locales, so we likely have to keep that forever ... - $io->title('List of "kimai_locales" for services.yaml'); - $io->writeln("['" . implode("', '", $locales) . "']"); + $listOfLocales = array_map(fn ($locale) => "'$locale'", $locales); + $filename = 'config/services.yaml'; + $targetFile = $this->projectDirectory . DIRECTORY_SEPARATOR . $filename; + $content = file_get_contents($targetFile); + if ($content === false) { + $io->error('Failed reading configuration file at ' . $filename); + } else { + $content = preg_replace( + '/^(\s*kimai_locales:\s*\[).*?(\])$/m', + '${1}' . implode(', ', $listOfLocales) . '${2}', + $content + ); + + file_put_contents($targetFile, $content); + + $io->success('Replaced locale definitions in: ' . $filename); + } ksort($appLocales); diff --git a/src/Constants.php b/src/Constants.php index b95f953e..862094f2 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -17,11 +17,11 @@ final class Constants /** * The current release version */ - public const VERSION = '2.32.0'; + public const VERSION = '2.33.0'; /** * The current release: major * 10000 + minor * 100 + patch */ - public const VERSION_ID = 23200; + public const VERSION_ID = 23300; /** * The software name */ diff --git a/src/Controller/ContractController.php b/src/Controller/ContractController.php index 80bd3493..6b3c821a 100644 --- a/src/Controller/ContractController.php +++ b/src/Controller/ContractController.php @@ -63,6 +63,8 @@ final class ContractController extends AbstractController /** @var \DateTime $yearDate */ $yearDate = $values->getDate(); + // make sure we use the correct datetime for the selected user + $yearDate = $this->getDateTimeFactory($profile)->createStartOfYear($yearDate); $year = $workingTimeService->getYear($profile, $yearDate, $now); $page = new PageSetup('work_times'); diff --git a/src/Customer/CustomerService.php b/src/Customer/CustomerService.php index f3521201..8ea2ee4b 100644 --- a/src/Customer/CustomerService.php +++ b/src/Customer/CustomerService.php @@ -137,12 +137,23 @@ final class CustomerService // we cannot use max(number) because a varchar column returns unexpected results $start = $this->repository->countCustomer(); $i = 0; + $createDate = new \DateTimeImmutable(); do { $start++; - $numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start): string|int { + $numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start, $createDate): string|int { return match ($format) { + 'Y' => $createDate->format('Y'), + 'y' => $createDate->format('y'), + 'M' => $createDate->format('m'), + 'm' => $createDate->format('n'), + 'D' => $createDate->format('d'), + 'd' => $createDate->format('j'), + 'YY' => (int) $createDate->format('Y') + $increaseBy, + 'yy' => (int) $createDate->format('y') + $increaseBy, + 'MM' => (int) $createDate->format('m') + $increaseBy, + 'DD' => (int) $createDate->format('d') + $increaseBy, 'cc' => $start + $increaseBy, default => $originalFormat, }; diff --git a/src/Export/Base/CsvRenderer.php b/src/Export/Base/CsvRenderer.php index 8a05a6eb..bc8fe6b9 100644 --- a/src/Export/Base/CsvRenderer.php +++ b/src/Export/Base/CsvRenderer.php @@ -12,6 +12,7 @@ namespace App\Export\Base; use App\Entity\ExportableItem; use App\Export\ExportFilename; use App\Export\Package\CellFormatter\DateStringFormatter; +use App\Export\Package\CellFormatter\DurationPlainFormatter; use App\Export\Package\SpoutSpreadsheet; use App\Export\RendererInterface; use App\Export\TimesheetExportInterface; @@ -71,6 +72,7 @@ final class CsvRenderer implements RendererInterface, TimesheetExportInterface $spreadsheet->open($filename); $this->spreadsheetRenderer->registerFormatter('date', new DateStringFormatter()); + $this->spreadsheetRenderer->registerFormatter('duration', new DurationPlainFormatter()); $this->spreadsheetRenderer->writeSpreadsheet($spreadsheet, $exportItems, $query); return new \SplFileInfo($filename); diff --git a/src/Export/Base/SpreadsheetRenderer.php b/src/Export/Base/SpreadsheetRenderer.php index 27143ed3..4cd6d61c 100644 --- a/src/Export/Base/SpreadsheetRenderer.php +++ b/src/Export/Base/SpreadsheetRenderer.php @@ -105,7 +105,7 @@ final class SpreadsheetRenderer $formula = null; if (\in_array($column->getName(), $totalColumns)) { $columnName = $columnNames[$totalColumn - 1]; - $formula = \sprintf('=SUM(%s2:%s%s)', $columnName, $columnName, $currentRow); + $formula = \sprintf('=SUBTOTAL(9,%s2:%s%s)', $columnName, $columnName, $currentRow); } $totalRow[] = $formula; $totalColumn++; diff --git a/src/Export/Package/CellFormatter/CellWithFormatInterface.php b/src/Export/Package/CellFormatter/CellWithFormatInterface.php new file mode 100644 index 00000000..02241d3f --- /dev/null +++ b/src/Export/Package/CellFormatter/CellWithFormatInterface.php @@ -0,0 +1,15 @@ +duration = new Duration(); - } - public function formatValue(mixed $value): mixed { - if (is_numeric($value)) { - return $this->duration->format((int) $value); + if (!is_numeric($value) || (int) $value === 0) { + return new \DateInterval('PT0S'); } - return $this->duration->format(0); + $value = (int) $value; + + $seconds = abs($value); + $hours = intdiv($seconds, 3600); + $seconds %= 3600; + $minutes = intdiv($seconds, 60); + $seconds %= 60; + + $intervalSpec = \sprintf('PT%dH%dM%dS', $hours, $minutes, $seconds); + $interval = new \DateInterval($intervalSpec); + + if ($value < 0) { + $interval->invert = 1; + } + + return $interval; + } + + public function getFormat(): string + { + return '[hh]:mm:ss'; } } diff --git a/src/Export/Package/CellFormatter/DurationPlainFormatter.php b/src/Export/Package/CellFormatter/DurationPlainFormatter.php new file mode 100644 index 00000000..ca304b85 --- /dev/null +++ b/src/Export/Package/CellFormatter/DurationPlainFormatter.php @@ -0,0 +1,37 @@ +invert = 1; + } + + return $interval->format('%r%h:%I:%S'); + } +} diff --git a/src/Export/Package/Column.php b/src/Export/Package/Column.php index e6949e63..96b0c18b 100644 --- a/src/Export/Package/Column.php +++ b/src/Export/Package/Column.php @@ -11,6 +11,7 @@ namespace App\Export\Package; use App\Entity\ExportableItem; use App\Export\Package\CellFormatter\CellFormatterInterface; +use App\Export\Package\CellFormatter\CellWithFormatInterface; class Column { @@ -71,4 +72,13 @@ class Column { return $this->header ?? $this->name; } + + public function getFormat(): ?string + { + if ($this->formatter instanceof CellWithFormatInterface) { + return $this->formatter->getFormat(); + } + + return null; + } } diff --git a/src/Export/Package/SpoutSpreadsheet.php b/src/Export/Package/SpoutSpreadsheet.php index 089c7826..7d5115dd 100644 --- a/src/Export/Package/SpoutSpreadsheet.php +++ b/src/Export/Package/SpoutSpreadsheet.php @@ -26,7 +26,8 @@ use Symfony\Contracts\Translation\TranslatorInterface; class SpoutSpreadsheet implements SpreadsheetPackage { - private Style $dateStyle; + /** @var array */ + private array $styles = []; public function __construct( private readonly WriterInterface $writer, @@ -34,7 +35,6 @@ class SpoutSpreadsheet implements SpreadsheetPackage ) { $this->writer->setCreator(Constants::SOFTWARE); - $this->dateStyle = (new Style())->setFormat('yyyy-mm-dd'); } /** @@ -48,9 +48,15 @@ class SpoutSpreadsheet implements SpreadsheetPackage } $tmp = []; + $i = 0; foreach ($columns as $column) { $title = $this->translator->trans($column->getHeader()); $tmp[] = Cell::fromValue($title); + $style = null; + if ($column->getFormat() !== null) { + $style = (new Style())->setFormat($column->getFormat()); + } + $this->styles[$i++] = $style; } $style = new Style(); @@ -100,12 +106,9 @@ class SpoutSpreadsheet implements SpreadsheetPackage } $tmp = []; + $i = 0; foreach ($columns as $column) { - if ($column instanceof \DateTimeInterface) { - $tmp[] = Cell::fromValue($column, $this->dateStyle); - } else { - $tmp[] = Cell::fromValue($column); // @phpstan-ignore argument.type - } + $tmp[] = Cell::fromValue($column, $this->styles[$i++]); // @phpstan-ignore argument.type } $this->writer->addRow(new Row($tmp, $style)); diff --git a/src/Form/TimesheetEditForm.php b/src/Form/TimesheetEditForm.php index 901d9007..5d3b4681 100644 --- a/src/Form/TimesheetEditForm.php +++ b/src/Form/TimesheetEditForm.php @@ -207,15 +207,22 @@ class TimesheetEditForm extends AbstractType /** @var \DateTime|null $date */ $date = $event->getForm()->get('begin_date')->getData(); + /** @var \DateTime|null $time */ $time = $event->getForm()->get('begin_time')->getData(); if ($date === null || $time === null) { return; } + // if the user did not change the time, make sure to keep the seconds + $seconds = 0; + if ($data->getBegin()?->format('H:i') === $time->format('H:i')) { + $seconds = $data->getBegin()->format('s') ?? 0; + } + // mutable datetime are a problem for doctrine $newDate = clone $date; - $newDate->setTime($time->format('H'), $time->format('i')); + $newDate->setTime((int) $time->format('H'), (int) $time->format('i'), (int) $seconds); if ($data->getBegin() === null || $data->getBegin()->getTimestamp() !== $newDate->getTimestamp()) { $data->setBegin($newDate); @@ -251,6 +258,7 @@ class TimesheetEditForm extends AbstractType $timesheet = $event->getData(); $oldEnd = $timesheet->getEnd(); + /** @var \DateTime|null $end */ $end = $event->getForm()->get('end_time')->getData(); if ($end === null || $end === false) { $timesheet->setEnd(null); @@ -267,8 +275,15 @@ class TimesheetEditForm extends AbstractType if ($time === null) { throw new \Exception('Cannot work with timesheets without start time'); } + + // if the user did not change the time, make sure to keep the seconds + $seconds = 0; + if ($oldEnd !== null && $oldEnd->format('H:i') === $end->format('H:i')) { + $seconds = $oldEnd->format('s') ?? 0; + } + $newEnd = clone $time; - $newEnd->setTime($end->format('H'), $end->format('i')); + $newEnd->setTime((int) $end->format('H'), (int) $end->format('i'), (int) $seconds); if ($newEnd < $time) { $newEnd->modify('+ 1 day'); diff --git a/src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php b/src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php index a4111006..cb9ba75f 100644 --- a/src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php +++ b/src/Invoice/Hydrator/InvoiceModelDefaultHydrator.php @@ -18,11 +18,17 @@ final class InvoiceModelDefaultHydrator implements InvoiceModelHydrator public function hydrate(InvoiceModel $model): array { + $template = $model->getTemplate(); + if ($template === null) { + throw new \InvalidArgumentException('InvoiceModel needs a template'); + } + $currency = $model->getCurrency(); $tax = $model->getCalculator()->getTax(); $total = $model->getCalculator()->getTotal(); $subtotal = $model->getCalculator()->getSubtotal(); $formatter = $model->getFormatter(); + $language = $template->getLanguage(); $values = [ 'invoice.due_date' => $formatter->getFormattedDateTime($model->getDueDate()), @@ -31,7 +37,7 @@ final class InvoiceModelDefaultHydrator implements InvoiceModelHydrator 'invoice.date_process' => $model->getInvoiceDate()->format(self::DATE_PROCESS_FORMAT), // since 2.14 'invoice.number' => $model->getInvoiceNumber(), 'invoice.currency' => $currency, - 'invoice.language' => $model->getTemplate()->getLanguage(), // since 1.9 + 'invoice.language' => $language, // since 1.9 'invoice.currency_symbol' => $formatter->getCurrencySymbol($currency), 'invoice.vat' => $model->getCalculator()->getVat(), 'invoice.tax_hide' => $model->isHideZeroTax() && $tax === 0.00, @@ -47,15 +53,17 @@ final class InvoiceModelDefaultHydrator implements InvoiceModelHydrator 'invoice.subtotal_nc' => $formatter->getFormattedMoney($subtotal, $currency, false), 'invoice.subtotal_plain' => $subtotal, - 'template.name' => $model->getTemplate()->getName() ?? '', - 'template.company' => $model->getTemplate()->getCompany() ?? '', - 'template.address' => $model->getTemplate()->getAddress() ?? '', - 'template.title' => $model->getTemplate()->getTitle() ?? '', - 'template.payment_terms' => $model->getTemplate()->getPaymentTerms() ?? '', - 'template.due_days' => $model->getTemplate()->getDueDays(), - 'template.vat_id' => $model->getTemplate()->getVatId() ?? '', - 'template.contact' => $model->getTemplate()->getContact() ?? '', - 'template.payment_details' => $model->getTemplate()->getPaymentDetails() ?? '', + 'template.name' => $template->getName() ?? '', + 'template.company' => $template->getCompany() ?? '', + 'template.address' => $template->getAddress() ?? '', + 'template.title' => $template->getTitle() ?? '', + 'template.payment_terms' => $template->getPaymentTerms() ?? '', + 'template.due_days' => $template->getDueDays(), + 'template.vat_id' => $template->getVatId() ?? '', + 'template.contact' => $template->getContact() ?? '', + 'template.country' => null, + 'template.country_name' => null, + 'template.payment_details' => $template->getPaymentDetails() ?? '', 'query.begin' => '', 'query.begin_day' => '', diff --git a/src/Project/ProjectService.php b/src/Project/ProjectService.php index e8eb500e..fa7c328d 100644 --- a/src/Project/ProjectService.php +++ b/src/Project/ProjectService.php @@ -128,12 +128,23 @@ final class ProjectService // we cannot use max(number) because a varchar column returns unexpected results $start = $this->repository->countProject(); $i = 0; + $createDate = new \DateTimeImmutable(); do { $start++; - $numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start): string|int { + $numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start, $createDate): string|int { return match ($format) { + 'Y' => $createDate->format('Y'), + 'y' => $createDate->format('y'), + 'M' => $createDate->format('m'), + 'm' => $createDate->format('n'), + 'D' => $createDate->format('d'), + 'd' => $createDate->format('j'), + 'YY' => (int) $createDate->format('Y') + $increaseBy, + 'yy' => (int) $createDate->format('y') + $increaseBy, + 'MM' => (int) $createDate->format('m') + $increaseBy, + 'DD' => (int) $createDate->format('d') + $increaseBy, 'pc' => $start + $increaseBy, default => $originalFormat, }; diff --git a/src/Timesheet/DateTimeFactory.php b/src/Timesheet/DateTimeFactory.php index c1178458..fe69e6fa 100644 --- a/src/Timesheet/DateTimeFactory.php +++ b/src/Timesheet/DateTimeFactory.php @@ -48,8 +48,14 @@ final class DateTimeFactory return $date; } + /** + * @deprecated + * @codeCoverageIgnore + */ public function getStartOfLastMonth(): DateTimeInterface { + @trigger_error('The method "DateTimeFactory::getStartOfLastMonth()" will be removed soon', E_USER_DEPRECATED); + $date = $this->createDateTime('first day of -1 month'); $date = $date->setTime(0, 0, 0); @@ -66,9 +72,13 @@ final class DateTimeFactory return $this->createDateTime($date); } - return DateTime::createFromInterface($date); + return $this->createDateTime($date->format('Y-m-d H:i:s')); } + /** + * @deprecated + * @codeCoverageIgnore + */ private function createDate(DateTimeInterface|string|null $date = null): \DateTimeImmutable { if ($date === null) { @@ -79,7 +89,7 @@ final class DateTimeFactory return $this->create($date); } - return \DateTimeImmutable::createFromInterface($date); + return $this->create($date->format('Y-m-d H:i:s')); } public function getStartOfWeek(DateTimeInterface|string|null $date = null): DateTime @@ -125,8 +135,14 @@ final class DateTimeFactory return $date; } + /** + * @deprecated + * @codeCoverageIgnore + */ public function getEndOfLastMonth(): DateTimeInterface { + @trigger_error('The method "DateTimeFactory::getEndOfLastMonth()" will be removed soon', E_USER_DEPRECATED); + $date = $this->createDateTime('last day of -1 month'); $date = $date->setTime(23, 59, 59); @@ -152,15 +168,27 @@ final class DateTimeFactory return new \DateTimeImmutable($datetime, $this->getTimezone()); } + /** + * @deprecated + * @codeCoverageIgnore + */ public function createStartOfDay(DateTimeInterface|string|null $date = null): \DateTimeImmutable { + @trigger_error('The method "DateTimeFactory::createStartOfDay()" will be removed soon', E_USER_DEPRECATED); + $date = $this->createDate($date); return $date->modify('00:00:00'); } + /** + * @deprecated + * @codeCoverageIgnore + */ public function createEndOfDay(DateTimeInterface|string|null $date = null): \DateTimeImmutable { + @trigger_error('The method "DateTimeFactory::createEndOfDay()" will be removed soon', E_USER_DEPRECATED); + $date = $this->createDate($date); return $date->modify('23:59:59'); diff --git a/src/Twig/Runtime/ThemeExtension.php b/src/Twig/Runtime/ThemeExtension.php index a8331565..10dcbb55 100644 --- a/src/Twig/Runtime/ThemeExtension.php +++ b/src/Twig/Runtime/ThemeExtension.php @@ -97,9 +97,9 @@ final class ThemeExtension implements RuntimeExtensionInterface return $class; } - public function generateTitle(?string $prefix = null, string $delimiter = ' – '): string + public function generateTitle(): string { - return ($prefix ?? '') . Constants::SOFTWARE; + return Constants::SOFTWARE; } public function colorize(?string $color, ?string $identifier = null): string diff --git a/tests/Activity/ActivityServiceTest.php b/tests/Activity/ActivityServiceTest.php index 35b93b78..8374a531 100644 --- a/tests/Activity/ActivityServiceTest.php +++ b/tests/Activity/ActivityServiceTest.php @@ -35,7 +35,8 @@ class ActivityServiceTest extends TestCase private function getSut( ?EventDispatcherInterface $dispatcher = null, ?ValidatorInterface $validator = null, - ?ActivityRepository $repository = null + ?ActivityRepository $repository = null, + array $configuration = [] ): ActivityService { if ($repository === null) { $repository = $this->createMock(ActivityRepository::class); @@ -50,7 +51,7 @@ class ActivityServiceTest extends TestCase $validator->method('validate')->willReturn(new ConstraintViolationList()); } - $configuration = SystemConfigurationFactory::createStub(['activity' => []]); + $configuration = SystemConfigurationFactory::createStub(['activity' => $configuration]); $service = new ActivityService($repository, $configuration, $dispatcher, $validator); @@ -155,4 +156,71 @@ class ActivityServiceTest extends TestCase $project = $sut->createNewActivity(); self::assertNull($project->getProject()); } + + /** + * @dataProvider getTestData + */ + public function testActivityNumber(string $format, int|string $expected): void + { + $sut = $this->getSut(null, null, null, ['number_format' => $format]); + $activity = $sut->createNewActivity(); + + self::assertEquals((string) $expected, $activity->getNumber()); + } + + /** + * @return array> + */ + public static function getTestData(): array + { + $dateTime = new \DateTime(); + + $yearLong = (int) $dateTime->format('Y'); + $yearShort = (int) $dateTime->format('y'); + $monthLong = $dateTime->format('m'); + $monthShort = (int) $dateTime->format('n'); + $dayLong = $dateTime->format('d'); + $dayShort = (int) $dateTime->format('j'); + + return [ + // simple tests for single calls + ['{ac,1}', '2'], + ['{ac,2}', '02'], + ['{ac,3}', '002'], + ['{ac,4}', '0002'], + ['{Y}', $yearLong], + ['{y}', $yearShort], + ['{M}', $monthLong], + ['{m}', $monthShort], + ['{D}', $dayLong], + ['{d}', $dayShort], + // number formatting (not testing the lower case versions, as the tests might break depending on the date) + ['{Y,6}', '00' . $yearLong], + ['{M,3}', '0' . $monthLong], + ['{D,3}', '0' . $dayLong], + // increment dates + ['{YY}', $yearLong + 1], + ['{YY+1}', $yearLong + 1], + ['{YY+2}', $yearLong + 2], + ['{YY+3}', $yearLong + 3], + ['{YY-1}', $yearLong - 1], + ['{YY-2}', $yearLong - 2], + ['{YY-3}', $yearLong - 3], + ['{yy}', $yearShort + 1], + ['{yy+1}', $yearShort + 1], + ['{yy+2}', $yearShort + 2], + ['{yy+3}', $yearShort + 3], + ['{yy-1}', $yearShort - 1], + ['{yy-2}', $yearShort - 2], + ['{yy-3}', $yearShort - 3], + ['{MM}', $monthShort + 1], // cast to int removes leading zero + ['{MM+1}', $monthShort + 1], // cast to int removes leading zero + ['{MM+2}', $monthShort + 2], // cast to int removes leading zero + ['{MM+3}', $monthShort + 3], // cast to int removes leading zero + ['{DD}', $dayShort + 1], // cast to int removes leading zero + ['{DD+1}', $dayShort + 1], // cast to int removes leading zero + ['{DD+2}', $dayShort + 2], // cast to int removes leading zero + ['{DD+3}', $dayShort + 3], // cast to int removes leading zero + ]; + } } diff --git a/tests/Customer/CustomerServiceTest.php b/tests/Customer/CustomerServiceTest.php index 8f411bdf..6d91ccdf 100644 --- a/tests/Customer/CustomerServiceTest.php +++ b/tests/Customer/CustomerServiceTest.php @@ -157,4 +157,84 @@ class CustomerServiceTest extends TestCase $Customer = new Customer('foo'); $sut->saveNewCustomer($Customer); } + + /** + * @dataProvider getTestData + */ + public function testCustomerNumber(string $format, int|string $expected): void + { + $configuration = SystemConfigurationFactory::createStub([ + 'defaults' => [ + 'customer' => [ + 'timezone' => 'Europe/Vienna', + 'country' => 'IN', + 'currency' => 'RUB', + ] + ], + 'customer' => [ + 'number_format' => $format + ] + ]); + + $sut = $this->getSut(null, null, null, $configuration); + $customer = $sut->createNewCustomer('Test'); + + self::assertEquals((string) $expected, $customer->getNumber()); + } + + /** + * @return array> + */ + public static function getTestData(): array + { + $dateTime = new \DateTime(); + + $yearLong = (int) $dateTime->format('Y'); + $yearShort = (int) $dateTime->format('y'); + $monthLong = $dateTime->format('m'); + $monthShort = (int) $dateTime->format('n'); + $dayLong = $dateTime->format('d'); + $dayShort = (int) $dateTime->format('j'); + + return [ + // simple tests for single calls + ['{cc,1}', '2'], + ['{cc,2}', '02'], + ['{cc,3}', '002'], + ['{cc,4}', '0002'], + ['{Y}', $yearLong], + ['{y}', $yearShort], + ['{M}', $monthLong], + ['{m}', $monthShort], + ['{D}', $dayLong], + ['{d}', $dayShort], + // number formatting (not testing the lower case versions, as the tests might break depending on the date) + ['{Y,6}', '00' . $yearLong], + ['{M,3}', '0' . $monthLong], + ['{D,3}', '0' . $dayLong], + // increment dates + ['{YY}', $yearLong + 1], + ['{YY+1}', $yearLong + 1], + ['{YY+2}', $yearLong + 2], + ['{YY+3}', $yearLong + 3], + ['{YY-1}', $yearLong - 1], + ['{YY-2}', $yearLong - 2], + ['{YY-3}', $yearLong - 3], + ['{yy}', $yearShort + 1], + ['{yy+1}', $yearShort + 1], + ['{yy+2}', $yearShort + 2], + ['{yy+3}', $yearShort + 3], + ['{yy-1}', $yearShort - 1], + ['{yy-2}', $yearShort - 2], + ['{yy-3}', $yearShort - 3], + ['{MM}', $monthShort + 1], // cast to int removes leading zero + ['{MM+1}', $monthShort + 1], // cast to int removes leading zero + ['{MM+2}', $monthShort + 2], // cast to int removes leading zero + ['{MM+3}', $monthShort + 3], // cast to int removes leading zero + ['{DD}', $dayShort + 1], // cast to int removes leading zero + ['{DD+1}', $dayShort + 1], // cast to int removes leading zero + ['{DD+2}', $dayShort + 2], // cast to int removes leading zero + ['{DD+3}', $dayShort + 3], // cast to int removes leading zero + ]; + } } diff --git a/tests/Entity/InvoiceTest.php b/tests/Entity/InvoiceTest.php index a78040d8..6fbaf692 100644 --- a/tests/Entity/InvoiceTest.php +++ b/tests/Entity/InvoiceTest.php @@ -173,15 +173,13 @@ class InvoiceTest extends TestCase $user1->method('getUsername')->willReturn('foo-bar'); $timesheet = new Timesheet(); - $timesheet - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user1) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user1); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setBegin(new \DateTime()); + $timesheet->setEnd(new \DateTime()); $entries = [$timesheet]; diff --git a/tests/Export/Base/CsvRendererTest.php b/tests/Export/Base/CsvRendererTest.php index 58dbdadc..6459d2a8 100644 --- a/tests/Export/Base/CsvRendererTest.php +++ b/tests/Export/Base/CsvRendererTest.php @@ -28,10 +28,13 @@ use Symfony\Contracts\Translation\TranslatorInterface; */ class CsvRendererTest extends AbstractRendererTestCase { - protected function getAbstractRenderer(): CsvRenderer + protected function getAbstractRenderer(bool $exportDecimal = false): CsvRenderer { + $user = $this->createMock(User::class); + $user->expects($this->any())->method('isExportDecimal')->willReturn($exportDecimal); + $security = $this->createMock(Security::class); - $security->expects($this->any())->method('getUser')->willReturn(new User()); + $security->expects($this->any())->method('getUser')->willReturn($user); $security->expects($this->any())->method('isGranted')->willReturn(true); $translator = $this->createMock(TranslatorInterface::class); @@ -53,16 +56,17 @@ class CsvRendererTest extends AbstractRendererTestCase public static function getTestModel(): array { return [ - ['400', '2437.12', '1947.99', 7, 6, 1, 2, 2] + ['400', '2437.12', '1947.99', 7, 6, 1, 2, 2, false], + ['400', '2437.12', '1947.99', 7, 6, 1, 2, 2, true] ]; } /** * @dataProvider getTestModel */ - public function testRender(string $totalDuration, string $totalRate, string $expectedRate, int $expectedRows, int $expectedDescriptions, int $expectedUser1, int $expectedUser2, int $expectedUser3): void + public function testRender(string $totalDuration, string $totalRate, string $expectedRate, int $expectedRows, int $expectedDescriptions, int $expectedUser1, int $expectedUser2, int $expectedUser3, bool $exportDecimal): void { - $sut = $this->getAbstractRenderer(); + $sut = $this->getAbstractRenderer($exportDecimal); /** @var BinaryFileResponse $response */ $response = $this->render($sut); @@ -102,7 +106,7 @@ class CsvRendererTest extends AbstractRendererTestCase '2019-06-16', '12:00', '12:06', - '0:06', + ($exportDecimal ? '0.11' : '0:06:40'), //'0.11', 'EUR', '0', @@ -136,7 +140,7 @@ class CsvRendererTest extends AbstractRendererTestCase '2019-06-16', '12:00', '12:06', - '0:06', + ($exportDecimal ? '0.11' : '0:06:40'), //'0.11', 'EUR', '0', diff --git a/tests/Export/Package/CellFormatter/DateFormatterTest.php b/tests/Export/Package/CellFormatter/DateFormatterTest.php index 1882c176..32d1f02e 100644 --- a/tests/Export/Package/CellFormatter/DateFormatterTest.php +++ b/tests/Export/Package/CellFormatter/DateFormatterTest.php @@ -17,6 +17,12 @@ use PHPUnit\Framework\TestCase; */ class DateFormatterTest extends TestCase { + public function testGetFormat(): void + { + $formatter = new DateFormatter(); + self::assertEquals('yyyy-mm-dd', $formatter->getFormat()); + } + public function testFormatValueReturnsFormattedDateForDateTime(): void { $formatter = new DateFormatter(); diff --git a/tests/Export/Package/CellFormatter/DurationFormatterTest.php b/tests/Export/Package/CellFormatter/DurationFormatterTest.php index 1013d74a..3d5395f2 100644 --- a/tests/Export/Package/CellFormatter/DurationFormatterTest.php +++ b/tests/Export/Package/CellFormatter/DurationFormatterTest.php @@ -17,38 +17,57 @@ use PHPUnit\Framework\TestCase; */ class DurationFormatterTest extends TestCase { + public function testGetFormat(): void + { + $formatter = new DurationFormatter(); + self::assertEquals('[hh]:mm:ss', $formatter->getFormat()); + } + + public function testFormatValueReturnsFormattedDurationQuiteLong(): void + { + $formatter = new DurationFormatter(); + $result = $formatter->formatValue(701213); + self::assertInstanceOf(\DateInterval::class, $result); + self::assertEquals('194:46:53', $result->format('%r%H:%I:%S')); + } + public function testFormatValueReturnsFormattedDurationForNumericValue(): void { $formatter = new DurationFormatter(); - $result = $formatter->formatValue(7200); - self::assertEquals('2:00', $result); + $result = $formatter->formatValue(7213); + self::assertInstanceOf(\DateInterval::class, $result); + self::assertEquals('02:00:13', $result->format('%r%H:%I:%S')); } public function testFormatValueReturnsZeroForNonNumericValue(): void { $formatter = new DurationFormatter(); $result = $formatter->formatValue('not a number'); - self::assertEquals('0:00', $result); + self::assertInstanceOf(\DateInterval::class, $result); + self::assertEquals('00:00:00', $result->format('%r%H:%I:%S')); } public function testFormatValueReturnsFormattedDurationForFloatValue(): void { $formatter = new DurationFormatter(); - $result = $formatter->formatValue(4500.5); - self::assertEquals('1:15', $result); + $result = $formatter->formatValue(4521.5); + self::assertInstanceOf(\DateInterval::class, $result); + self::assertEquals('01:15:21', $result->format('%r%H:%I:%S')); } public function testFormatValueReturnsZeroForNullValue(): void { $formatter = new DurationFormatter(); $result = $formatter->formatValue(null); - self::assertEquals('0:00', $result); + self::assertInstanceOf(\DateInterval::class, $result); + self::assertEquals('00:00:00', $result->format('%r%H:%I:%S')); } public function testFormatValueReturnsFormattedDurationForNegativeValue(): void { $formatter = new DurationFormatter(); $result = $formatter->formatValue(-3600); - self::assertEquals('-1:00', $result); + self::assertInstanceOf(\DateInterval::class, $result); + self::assertEquals('-01:00:00', $result->format('%r%H:%I:%S')); } } diff --git a/tests/Export/Package/CellFormatter/DurationPlainFormatterTest.php b/tests/Export/Package/CellFormatter/DurationPlainFormatterTest.php new file mode 100644 index 00000000..45189b0e --- /dev/null +++ b/tests/Export/Package/CellFormatter/DurationPlainFormatterTest.php @@ -0,0 +1,61 @@ +formatValue(701213); + self::assertEquals('194:46:53', $result); + } + + public function testFormatValueReturnsFormattedDurationForNumericValue(): void + { + $formatter = new DurationPlainFormatter(); + $result = $formatter->formatValue(8246); + self::assertEquals('2:17:26', $result); + } + + public function testFormatValueReturnsZeroForNonNumericValue(): void + { + $formatter = new DurationPlainFormatter(); + $result = $formatter->formatValue('not a number'); + self::assertEquals('0:00:00', $result); + } + + public function testFormatValueReturnsFormattedDurationForFloatValue(): void + { + $formatter = new DurationPlainFormatter(); + $result = $formatter->formatValue(44513.5); + self::assertEquals('12:21:53', $result); + } + + public function testFormatValueReturnsZeroForNullValue(): void + { + $formatter = new DurationPlainFormatter(); + $result = $formatter->formatValue(null); + self::assertEquals('0:00:00', $result); + } + + public function testFormatValueReturnsFormattedDurationForNegativeValue(): void + { + $formatter = new DurationPlainFormatter(); + $result = $formatter->formatValue(-3600); + self::assertEquals('-1:00:00', $result); + } +} diff --git a/tests/Export/Package/ColumnTest.php b/tests/Export/Package/ColumnTest.php index 5f0aae0b..fb6de7cc 100644 --- a/tests/Export/Package/ColumnTest.php +++ b/tests/Export/Package/ColumnTest.php @@ -11,6 +11,7 @@ namespace App\Tests\Export\Package; use App\Entity\ExportableItem; use App\Export\Package\CellFormatter\CellFormatterInterface; +use App\Export\Package\CellFormatter\DateFormatter; use App\Export\Package\Column; use PHPUnit\Framework\TestCase; @@ -85,4 +86,17 @@ class ColumnTest extends TestCase $column = new Column('testName', $formatter); self::assertEquals('testName', $column->getHeader()); } + + public function testWithFormatReturnsNull(): void + { + $formatter = $this->createMock(CellFormatterInterface::class); + $column = new Column('testName', $formatter); + self::assertNull($column->getFormat()); + } + + public function testWithFormatReturnsValueFromFormatter(): void + { + $column = new Column('testName', new DateFormatter()); + self::assertEquals('yyyy-mm-dd', $column->getFormat()); + } } diff --git a/tests/Export/Renderer/AbstractRendererTestCase.php b/tests/Export/Renderer/AbstractRendererTestCase.php index cd7fe920..cc310e8d 100644 --- a/tests/Export/Renderer/AbstractRendererTestCase.php +++ b/tests/Export/Renderer/AbstractRendererTestCase.php @@ -67,84 +67,72 @@ abstract class AbstractRendererTestCase extends KernelTestCase $user2->method('getUsername')->willReturn('hello-world'); $timesheet = new Timesheet(); - $timesheet - ->setDuration(3600) // 60 minutes - ->setRate(293.27) - ->setUser($user1) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user1); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setBegin(new \DateTime()); + $timesheet->setEnd(new \DateTime()); $timesheet2 = new Timesheet(); - $timesheet2 - ->setDuration(400) - ->setRate(84.75) - ->setUser($user2) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user2); + $timesheet2->setActivity($activity); + $timesheet2->setProject($project); + $timesheet2->setBegin(new \DateTime()); + $timesheet2->setEnd(new \DateTime()); $timesheet3 = new Timesheet(); - $timesheet3 - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user1) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user1); + $timesheet3->setActivity($activity); + $timesheet3->setProject($project); + $timesheet3->setBegin(new \DateTime()); + $timesheet3->setEnd(new \DateTime()); $timesheet4 = new Timesheet(); - $timesheet4 - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user2) - ->setDescription('== jhg ljhg ') // make sure that spreadsheets don't render it as formula - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ->addTag((new Tag())->setName('foo')) - ; + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user2); + $timesheet4->setDescription('== jhg ljhg '); // make sure that spreadsheets don't render it as formula + $timesheet4->setActivity($activity); + $timesheet4->setProject($project); + $timesheet4->setBegin(new \DateTime()); + $timesheet4->setEnd(new \DateTime()); + $timesheet4->addTag((new Tag())->setName('foo')); $userKevin = new User(); $userKevin->setAlias('Kevin'); $userKevin->setUserIdentifier('kevin'); $timesheet5 = new Timesheet(); - $timesheet5 - ->setDuration(400) - ->setFixedRate(84) - ->setUser($userKevin) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2019-06-16 12:00:00')) - ->setEnd(new \DateTime('2019-06-16 12:06:40')) - ->addTag((new Tag())->setName('foo')) - ->addTag((new Tag())->setName('bar')) - ->setMetaField((new TimesheetMeta())->setName('foo')->setValue('meta-bar')->setIsVisible(true)) - ->setMetaField((new TimesheetMeta())->setName('foo2')->setValue('meta-bar2')->setIsVisible(true)) - ; + $timesheet5->setDuration(400); + $timesheet5->setFixedRate(84); + $timesheet5->setUser($userKevin); + $timesheet5->setActivity($activity); + $timesheet5->setProject($project); + $timesheet5->setBegin(new \DateTime('2019-06-16 12:00:00')); + $timesheet5->setEnd(new \DateTime('2019-06-16 12:06:40')); + $timesheet5->addTag((new Tag())->setName('foo')); + $timesheet5->addTag((new Tag())->setName('bar')); + $timesheet5->setMetaField((new TimesheetMeta())->setName('foo')->setValue('meta-bar')->setIsVisible(true)); + $timesheet5->setMetaField((new TimesheetMeta())->setName('foo2')->setValue('meta-bar2')->setIsVisible(true)); $userNivek = new User(); $userNivek->setAlias('niveK'); $userNivek->setUserIdentifier('nivek'); $timesheet6 = new Timesheet(); - $timesheet6 - ->setDuration(400) - ->setFixedRate(-100.92) - ->setUser($userNivek) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2019-06-16 12:00:00')) - ->setEnd(new \DateTime('2019-06-16 12:06:40')) - ; + $timesheet6->setDuration(400); + $timesheet6->setFixedRate(-100.92); + $timesheet6->setUser($userNivek); + $timesheet6->setActivity($activity); + $timesheet6->setProject($project); + $timesheet6->setBegin(new \DateTime('2019-06-16 12:00:00')); + $timesheet6->setEnd(new \DateTime('2019-06-16 12:06:40')); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5, $timesheet6]; diff --git a/tests/Export/Timesheet/AbstractRendererTestCase.php b/tests/Export/Timesheet/AbstractRendererTestCase.php index c0a79b13..2bd44db1 100644 --- a/tests/Export/Timesheet/AbstractRendererTestCase.php +++ b/tests/Export/Timesheet/AbstractRendererTestCase.php @@ -65,67 +65,57 @@ abstract class AbstractRendererTestCase extends KernelTestCase $user2->method('getUserIdentifier')->willReturn('hello-world'); $timesheet = new Timesheet(); - $timesheet - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user1) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user1); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setBegin(new \DateTime()); + $timesheet->setEnd(new \DateTime()); $timesheet2 = new Timesheet(); - $timesheet2 - ->setDuration(400) - ->setRate(84.75) - ->setUser($user2) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user2); + $timesheet2->setActivity($activity); + $timesheet2->setProject($project); + $timesheet2->setBegin(new \DateTime()); + $timesheet2->setEnd(new \DateTime()); $timesheet3 = new Timesheet(); - $timesheet3 - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user1) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user1); + $timesheet3->setActivity($activity); + $timesheet3->setProject($project); + $timesheet3->setBegin(new \DateTime()); + $timesheet3->setEnd(new \DateTime()); $timesheet4 = new Timesheet(); - $timesheet4 - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user2) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ->addTag((new Tag())->setName('foo')) - ; + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user2); + $timesheet4->setActivity($activity); + $timesheet4->setProject($project); + $timesheet4->setBegin(new \DateTime()); + $timesheet4->setEnd(new \DateTime()); + $timesheet4->addTag((new Tag())->setName('foo')); $user = new User(); $user->setUserIdentifier('kevin'); $timesheet5 = new Timesheet(); - $timesheet5 - ->setDuration(400) - ->setFixedRate(84) - ->setUser($user) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2019-06-16 12:00:00')) - ->setEnd(new \DateTime('2019-06-16 12:06:40')) - ->addTag((new Tag())->setName('foo')) - ->addTag((new Tag())->setName('bar')) - ->setMetaField((new TimesheetMeta())->setName('foo')->setValue('meta-bar')->setIsVisible(true)) - ->setMetaField((new TimesheetMeta())->setName('foo2')->setValue('meta-bar2')->setIsVisible(true)) - ; + $timesheet5->setDuration(400); + $timesheet5->setFixedRate(84); + $timesheet5->setUser($user); + $timesheet5->setActivity($activity); + $timesheet5->setProject($project); + $timesheet5->setBegin(new \DateTime('2019-06-16 12:00:00')); + $timesheet5->setEnd(new \DateTime('2019-06-16 12:06:40')); + $timesheet5->addTag((new Tag())->setName('foo')); + $timesheet5->addTag((new Tag())->setName('bar')); + $timesheet5->setMetaField((new TimesheetMeta())->setName('foo')->setValue('meta-bar')->setIsVisible(true)); + $timesheet5->setMetaField((new TimesheetMeta())->setName('foo2')->setValue('meta-bar2')->setIsVisible(true)); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; diff --git a/tests/Invoice/Calculator/AbstractCalculatorTestCase.php b/tests/Invoice/Calculator/AbstractCalculatorTestCase.php index 0a5e9056..e17bf503 100644 --- a/tests/Invoice/Calculator/AbstractCalculatorTestCase.php +++ b/tests/Invoice/Calculator/AbstractCalculatorTestCase.php @@ -86,14 +86,13 @@ abstract class AbstractCalculatorTestCase extends TestCase } $timesheet = new Timesheet(); - $timesheet - ->setDescription('timesheet description') - ->setBegin(new \DateTime()) - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user) - ->setActivity($activity) - ->setProject($project); + $timesheet->setDescription('timesheet description'); + $timesheet->setBegin(new \DateTime()); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user); + $timesheet->setActivity($activity); + $timesheet->setProject($project); $model = (new InvoiceModelFactoryFactory($this))->create()->createModel(new DebugFormatter(), $customer, $template, $query); $model->addEntries([$timesheet]); diff --git a/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php index a2bf53b8..f92facdd 100644 --- a/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php @@ -54,82 +54,74 @@ class ActivityInvoiceCalculatorTest extends AbstractCalculatorTestCase $activity3->method('getId')->willReturn(3); $timesheet = new Timesheet(); - $timesheet - ->setBegin(new \DateTime('2018-11-29')) - ->setEnd(new \DateTime()) - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user) - ->setActivity($activity1) - ->setProject((new Project())->setName('bar')); + $timesheet->setBegin(new \DateTime('2018-11-29')); + $timesheet->setEnd(new \DateTime()); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user); + $timesheet->setActivity($activity1); + $timesheet->setProject((new Project())->setName('bar')); $timesheet2 = new Timesheet(); - $timesheet2 - ->setBegin(clone $date) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(84.75) - ->setUser($user) - ->setActivity($activity2) - ->setProject((new Project())->setName('bar')); + $timesheet2->setBegin(clone $date); + $timesheet2->setEnd(new \DateTime()); + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user); + $timesheet2->setActivity($activity2); + $timesheet2->setProject((new Project())->setName('bar')); $timesheet3 = new Timesheet(); - $timesheet3 - ->setBegin(new \DateTime('2018-11-28')) - ->setEnd(new \DateTime()) - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user) - ->setActivity($activity1) - ->setProject((new Project())->setName('bar')); + $timesheet3->setBegin(new \DateTime('2018-11-28')); + $timesheet3->setEnd(new \DateTime()); + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user); + $timesheet3->setActivity($activity1); + $timesheet3->setProject((new Project())->setName('bar')); $timesheet4 = new Timesheet(); - $timesheet4 - ->setBegin(new \DateTime('2018-11-28')) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user) - ->setActivity($activity2) - ->setProject((new Project())->setName('bar')); + $timesheet4->setBegin(new \DateTime('2018-11-28')); + $timesheet4->setEnd(new \DateTime()); + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user); + $timesheet4->setActivity($activity2); + $timesheet4->setProject((new Project())->setName('bar')); $timesheet5 = new Timesheet(); - $timesheet5 - ->setBegin(new \DateTime('2018-11-29')) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(84) - ->setUser(new User()) - ->setActivity($activity3) - ->setProject((new Project())->setName('bar')); + $timesheet5->setBegin(new \DateTime('2018-11-29')); + $timesheet5->setEnd(new \DateTime()); + $timesheet5->setDuration(400); + $timesheet5->setRate(84); + $timesheet5->setUser(new User()); + $timesheet5->setActivity($activity3); + $timesheet5->setProject((new Project())->setName('bar')); $timesheet6 = new Timesheet(); - $timesheet6 - ->setBegin(clone $date) - ->setEnd(new \DateTime()) - ->setDuration(0) - ->setRate(0) - ->setUser(new User()) - ->setProject((new Project())->setName('bar')); + $timesheet6->setBegin(clone $date); + $timesheet6->setEnd(new \DateTime()); + $timesheet6->setDuration(0); + $timesheet6->setRate(0); + $timesheet6->setUser(new User()); + $timesheet6->setProject((new Project())->setName('bar')); $timesheet7 = new Timesheet(); - $timesheet7 - ->setBegin(clone $date) - ->setEnd(new \DateTime('2018-11-18')) - ->setDuration(0) - ->setRate(0) - ->setUser(new User()) - ->setActivity(new Activity()) - ->setProject((new Project())->setName('bar')); + $timesheet7->setBegin(clone $date); + $timesheet7->setEnd(new \DateTime('2018-11-18')); + $timesheet7->setDuration(0); + $timesheet7->setRate(0); + $timesheet7->setUser(new User()); + $timesheet7->setActivity(new Activity()); + $timesheet7->setProject((new Project())->setName('bar')); $timesheet8 = new Timesheet(); - $timesheet8 - ->setBegin(clone $date) - ->setEnd(new \DateTime()) - ->setDuration(0) - ->setRate(0) - ->setUser(new User()) - ->setProject((new Project())->setName('bar')); + $timesheet8->setBegin(clone $date); + $timesheet8->setEnd(new \DateTime()); + $timesheet8->setDuration(0); + $timesheet8->setRate(0); + $timesheet8->setUser(new User()); + $timesheet8->setProject((new Project())->setName('bar')); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5, $timesheet6, $timesheet7, $timesheet8]; diff --git a/tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php index 0973fcf4..9befb933 100644 --- a/tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php @@ -57,92 +57,83 @@ class ActivityUserInvoiceCalculatorTest extends AbstractCalculatorTestCase $activity3->method('getId')->willReturn(3); $timesheet = new Timesheet(); - $timesheet - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user1) - ->setActivity($activity1) - ->setProject((new Project())->setName('bar')); + $timesheet->setBegin(new \DateTime()); + $timesheet->setEnd(new \DateTime()); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user1); + $timesheet->setActivity($activity1); + $timesheet->setProject((new Project())->setName('bar')); $timesheet2 = new Timesheet(); - $timesheet2 - ->setBegin(new \DateTime('2018-11-18')) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(84.75) - ->setUser($user1) - ->setActivity($activity2) - ->setProject((new Project())->setName('bar')); + $timesheet2->setBegin(new \DateTime('2018-11-18')); + $timesheet2->setEnd(new \DateTime()); + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user1); + $timesheet2->setActivity($activity2); + $timesheet2->setProject((new Project())->setName('bar')); $timesheet3 = new Timesheet(); - $timesheet3 - ->setBegin(clone $date) - ->setEnd(new \DateTime()) - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user1) - ->setActivity($activity1) - ->setProject((new Project())->setName('bar')); + $timesheet3->setBegin(clone $date); + $timesheet3->setEnd(new \DateTime()); + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user1); + $timesheet3->setActivity($activity1); + $timesheet3->setProject((new Project())->setName('bar')); $timesheet4 = new Timesheet(); - $timesheet4 - ->setBegin(new \DateTime('2018-11-29')) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user1) - ->setActivity($activity2) - ->setProject((new Project())->setName('bar')); + $timesheet4->setBegin(new \DateTime('2018-11-29')); + $timesheet4->setEnd(new \DateTime()); + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user1); + $timesheet4->setActivity($activity2); + $timesheet4->setProject((new Project())->setName('bar')); $timesheet5 = new Timesheet(); - $timesheet5 - ->setBegin(new \DateTime('2018-11-18')) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(84) - ->setUser($user2) - ->setActivity($activity3) - ->setProject((new Project())->setName('bar')); + $timesheet5->setBegin(new \DateTime('2018-11-18')); + $timesheet5->setEnd(new \DateTime()); + $timesheet5->setDuration(400); + $timesheet5->setRate(84); + $timesheet5->setUser($user2); + $timesheet5->setActivity($activity3); + $timesheet5->setProject((new Project())->setName('bar')); $timesheet5a = new Timesheet(); - $timesheet5a - ->setBegin(new \DateTime('2018-11-08')) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(84) - ->setUser($user1) - ->setActivity($activity3) - ->setProject((new Project())->setName('bar')); + $timesheet5a->setBegin(new \DateTime('2018-11-08')); + $timesheet5a->setEnd(new \DateTime()); + $timesheet5a->setDuration(400); + $timesheet5a->setRate(84); + $timesheet5a->setUser($user1); + $timesheet5a->setActivity($activity3); + $timesheet5a->setProject((new Project())->setName('bar')); $timesheet6 = new Timesheet(); - $timesheet6 - ->setBegin(clone $date) - ->setEnd(new \DateTime()) - ->setDuration(0) - ->setRate(0) - ->setUser($user1) - ->setProject((new Project())->setName('bar')); + $timesheet6->setBegin(clone $date); + $timesheet6->setEnd(new \DateTime()); + $timesheet6->setDuration(0); + $timesheet6->setRate(0); + $timesheet6->setUser($user1); + $timesheet6->setProject((new Project())->setName('bar')); $timesheet7 = new Timesheet(); - $timesheet7 - ->setBegin(clone $date) - ->setEnd(new \DateTime()) - ->setDuration(0) - ->setRate(0) - ->setUser($user2) - ->setActivity(new Activity()) - ->setProject((new Project())->setName('bar')); + $timesheet7->setBegin(clone $date); + $timesheet7->setEnd(new \DateTime()); + $timesheet7->setDuration(0); + $timesheet7->setRate(0); + $timesheet7->setUser($user2); + $timesheet7->setActivity(new Activity()); + $timesheet7->setProject((new Project())->setName('bar')); $timesheet8 = new Timesheet(); - $timesheet8 - ->setBegin(clone $date) - ->setEnd(new \DateTime()) - ->setDuration(0) - ->setRate(0) - ->setUser($user2) - ->setProject((new Project())->setName('bar')); + $timesheet8->setBegin(clone $date); + $timesheet8->setEnd(new \DateTime()); + $timesheet8->setDuration(0); + $timesheet8->setRate(0); + $timesheet8->setUser($user2); + $timesheet8->setProject((new Project())->setName('bar')); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5, $timesheet5a, $timesheet6, $timesheet7, $timesheet8]; diff --git a/tests/Invoice/Calculator/DateInvoiceCalculatorTest.php b/tests/Invoice/Calculator/DateInvoiceCalculatorTest.php index 578c8f39..8e64bff1 100644 --- a/tests/Invoice/Calculator/DateInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/DateInvoiceCalculatorTest.php @@ -55,54 +55,49 @@ class DateInvoiceCalculatorTest extends AbstractCalculatorTestCase $project3->method('getId')->willReturn(3); $timesheet = new Timesheet(); - $timesheet - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user) - ->setActivity((new Activity())->setName('sdsd')) - ->setProject($project1); + $timesheet->setBegin(new DateTime('2018-11-29')); + $timesheet->setEnd(new DateTime()); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user); + $timesheet->setActivity((new Activity())->setName('sdsd')); + $timesheet->setProject($project1); $timesheet2 = new Timesheet(); - $timesheet2 - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(84.75) - ->setUser($user) - ->setActivity((new Activity())->setName('bar')) - ->setProject($project2); + $timesheet2->setBegin(new DateTime('2018-11-29')); + $timesheet2->setEnd(new DateTime()); + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user); + $timesheet2->setActivity((new Activity())->setName('bar')); + $timesheet2->setProject($project2); $timesheet3 = new Timesheet(); - $timesheet3 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user) - ->setActivity((new Activity())->setName('foo')) - ->setProject($project1); + $timesheet3->setBegin(new DateTime('2018-11-28')); + $timesheet3->setEnd(new DateTime()); + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user); + $timesheet3->setActivity((new Activity())->setName('foo')); + $timesheet3->setProject($project1); $timesheet4 = new Timesheet(); - $timesheet4 - ->setBegin($date) - ->setEnd(new DateTime('2018-11-28')) - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user) - ->setActivity((new Activity())->setName('blub')) - ->setProject($project2); + $timesheet4->setBegin($date); + $timesheet4->setEnd(new DateTime('2018-11-28')); + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user); + $timesheet4->setActivity((new Activity())->setName('blub')); + $timesheet4->setProject($project2); $timesheet5 = new Timesheet(); - $timesheet5 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(84) - ->setUser(new User()) - ->setActivity(new Activity()) - ->setProject($project3); + $timesheet5->setBegin(new DateTime('2018-11-28')); + $timesheet5->setEnd(new DateTime()); + $timesheet5->setDuration(400); + $timesheet5->setRate(84); + $timesheet5->setUser(new User()); + $timesheet5->setActivity(new Activity()); + $timesheet5->setProject($project3); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; diff --git a/tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php b/tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php index 9a18b409..82e466a3 100644 --- a/tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php @@ -57,54 +57,49 @@ class DateUserInvoiceCalculatorTest extends AbstractCalculatorTestCase $project3->method('getId')->willReturn(3); $timesheet = new Timesheet(); - $timesheet - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user1) - ->setActivity((new Activity())->setName('sdsd')) - ->setProject($project1); + $timesheet->setBegin(new DateTime('2018-11-29')); + $timesheet->setEnd(new DateTime()); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user1); + $timesheet->setActivity((new Activity())->setName('sdsd')); + $timesheet->setProject($project1); $timesheet2 = new Timesheet(); - $timesheet2 - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(84.75) - ->setUser($user1) - ->setActivity((new Activity())->setName('bar')) - ->setProject($project2); + $timesheet2->setBegin(new DateTime('2018-11-29')); + $timesheet2->setEnd(new DateTime()); + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user1); + $timesheet2->setActivity((new Activity())->setName('bar')); + $timesheet2->setProject($project2); $timesheet3 = new Timesheet(); - $timesheet3 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user1) - ->setActivity((new Activity())->setName('foo')) - ->setProject($project1); + $timesheet3->setBegin(new DateTime('2018-11-28')); + $timesheet3->setEnd(new DateTime()); + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user1); + $timesheet3->setActivity((new Activity())->setName('foo')); + $timesheet3->setProject($project1); $timesheet4 = new Timesheet(); - $timesheet4 - ->setBegin(new DateTime()) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user1) - ->setActivity((new Activity())->setName('blub')) - ->setProject($project2); + $timesheet4->setBegin(new DateTime()); + $timesheet4->setEnd(new DateTime()); + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user1); + $timesheet4->setActivity((new Activity())->setName('blub')); + $timesheet4->setProject($project2); $timesheet5 = new Timesheet(); - $timesheet5 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(84) - ->setUser($user2) - ->setActivity(new Activity()) - ->setProject($project3); + $timesheet5->setBegin(new DateTime('2018-11-28')); + $timesheet5->setEnd(new DateTime()); + $timesheet5->setDuration(400); + $timesheet5->setRate(84); + $timesheet5->setUser($user2); + $timesheet5->setActivity(new Activity()); + $timesheet5->setProject($project3); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; diff --git a/tests/Invoice/Calculator/PriceInvoiceCalculatorTest.php b/tests/Invoice/Calculator/PriceInvoiceCalculatorTest.php index bee33894..d4f7208c 100644 --- a/tests/Invoice/Calculator/PriceInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/PriceInvoiceCalculatorTest.php @@ -54,58 +54,53 @@ class PriceInvoiceCalculatorTest extends AbstractCalculatorTestCase $project3->method('getId')->willReturn(3); $timesheet = new Timesheet(); - $timesheet - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(3600) - ->setHourlyRate(293.27) - ->setRate(293.27) - ->setUser($user) - ->setActivity((new Activity())->setName('sdsd')) - ->setProject($project1); + $timesheet->setBegin(new DateTime('2018-11-29')); + $timesheet->setEnd(new DateTime()); + $timesheet->setDuration(3600); + $timesheet->setHourlyRate(293.27); + $timesheet->setRate(293.27); + $timesheet->setUser($user); + $timesheet->setActivity((new Activity())->setName('sdsd')); + $timesheet->setProject($project1); $timesheet2 = new Timesheet(); - $timesheet2 - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setHourlyRate(293.27) - ->setRate(84.75) - ->setUser($user) - ->setActivity((new Activity())->setName('bar')) - ->setProject($project2); + $timesheet2->setBegin(new DateTime('2018-11-29')); + $timesheet2->setEnd(new DateTime()); + $timesheet2->setDuration(400); + $timesheet2->setHourlyRate(293.27); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user); + $timesheet2->setActivity((new Activity())->setName('bar')); + $timesheet2->setProject($project2); $timesheet3 = new Timesheet(); - $timesheet3 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(1800) - ->setFixedRate(111.11) - ->setRate(111.11) - ->setUser($user) - ->setActivity((new Activity())->setName('foo')) - ->setProject($project1); + $timesheet3->setBegin(new DateTime('2018-11-28')); + $timesheet3->setEnd(new DateTime()); + $timesheet3->setDuration(1800); + $timesheet3->setFixedRate(111.11); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user); + $timesheet3->setActivity((new Activity())->setName('foo')); + $timesheet3->setProject($project1); $timesheet4 = new Timesheet(); - $timesheet4 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setHourlyRate(0) - ->setRate(1947.99) - ->setUser($user) - ->setActivity((new Activity())->setName('blub')) - ->setProject($project2); + $timesheet4->setBegin(new DateTime('2018-11-28')); + $timesheet4->setEnd(new DateTime()); + $timesheet4->setDuration(400); + $timesheet4->setHourlyRate(0); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user); + $timesheet4->setActivity((new Activity())->setName('blub')); + $timesheet4->setProject($project2); $timesheet5 = new Timesheet(); - $timesheet5 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(84) - ->setUser(new User()) - ->setActivity(new Activity()) - ->setProject($project3); + $timesheet5->setBegin(new DateTime('2018-11-28')); + $timesheet5->setEnd(new DateTime()); + $timesheet5->setDuration(400); + $timesheet5->setRate(84); + $timesheet5->setUser(new User()); + $timesheet5->setActivity(new Activity()); + $timesheet5->setProject($project3); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; diff --git a/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php index 6a39eecd..28c54ef1 100644 --- a/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php @@ -54,54 +54,49 @@ class ProjectInvoiceCalculatorTest extends AbstractCalculatorTestCase $project3->method('getId')->willReturn(3); $timesheet = new Timesheet(); - $timesheet - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user) - ->setActivity((new Activity())->setName('sdsd')) - ->setProject($project1); + $timesheet->setBegin(new DateTime('2018-11-29')); + $timesheet->setEnd(new DateTime()); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user); + $timesheet->setActivity((new Activity())->setName('sdsd')); + $timesheet->setProject($project1); $timesheet2 = new Timesheet(); - $timesheet2 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(84.75) - ->setUser($user) - ->setActivity((new Activity())->setName('bar')) - ->setProject($project2); + $timesheet2->setBegin(new DateTime('2018-11-28')); + $timesheet2->setEnd(new DateTime()); + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user); + $timesheet2->setActivity((new Activity())->setName('bar')); + $timesheet2->setProject($project2); $timesheet3 = new Timesheet(); - $timesheet3 - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user) - ->setActivity((new Activity())->setName('foo')) - ->setProject($project1); + $timesheet3->setBegin(new DateTime('2018-11-29')); + $timesheet3->setEnd(new DateTime()); + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user); + $timesheet3->setActivity((new Activity())->setName('foo')); + $timesheet3->setProject($project1); $timesheet4 = new Timesheet(); - $timesheet4 - ->setBegin(new DateTime('2018-11-08')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user) - ->setActivity((new Activity())->setName('blub')) - ->setProject($project2); + $timesheet4->setBegin(new DateTime('2018-11-08')); + $timesheet4->setEnd(new DateTime()); + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user); + $timesheet4->setActivity((new Activity())->setName('blub')); + $timesheet4->setProject($project2); $timesheet5 = new Timesheet(); - $timesheet5 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(84) - ->setUser(new User()) - ->setActivity(new Activity()) - ->setProject($project3); + $timesheet5->setBegin(new DateTime('2018-11-28')); + $timesheet5->setEnd(new DateTime()); + $timesheet5->setDuration(400); + $timesheet5->setRate(84); + $timesheet5->setUser(new User()); + $timesheet5->setActivity(new Activity()); + $timesheet5->setProject($project3); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; diff --git a/tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php index 5db59e39..cea0a2a0 100644 --- a/tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php @@ -57,54 +57,49 @@ class ProjectUserInvoiceCalculatorTest extends AbstractCalculatorTestCase $project3->method('getId')->willReturn(3); $timesheet = new Timesheet(); - $timesheet - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user1) - ->setActivity((new Activity())->setName('sdsd')) - ->setProject($project1); + $timesheet->setBegin(new DateTime('2018-11-29')); + $timesheet->setEnd(new DateTime()); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user1); + $timesheet->setActivity((new Activity())->setName('sdsd')); + $timesheet->setProject($project1); $timesheet2 = new Timesheet(); - $timesheet2 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(84.75) - ->setUser($user1) - ->setActivity((new Activity())->setName('bar')) - ->setProject($project2); + $timesheet2->setBegin(new DateTime('2018-11-28')); + $timesheet2->setEnd(new DateTime()); + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user1); + $timesheet2->setActivity((new Activity())->setName('bar')); + $timesheet2->setProject($project2); $timesheet3 = new Timesheet(); - $timesheet3 - ->setBegin(new DateTime('2018-11-29')) - ->setEnd(new DateTime()) - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user1) - ->setActivity((new Activity())->setName('foo')) - ->setProject($project1); + $timesheet3->setBegin(new DateTime('2018-11-29')); + $timesheet3->setEnd(new DateTime()); + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user1); + $timesheet3->setActivity((new Activity())->setName('foo')); + $timesheet3->setProject($project1); $timesheet4 = new Timesheet(); - $timesheet4 - ->setBegin(new DateTime('2018-11-08')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user1) - ->setActivity((new Activity())->setName('blub')) - ->setProject($project2); + $timesheet4->setBegin(new DateTime('2018-11-08')); + $timesheet4->setEnd(new DateTime()); + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user1); + $timesheet4->setActivity((new Activity())->setName('blub')); + $timesheet4->setProject($project2); $timesheet5 = new Timesheet(); - $timesheet5 - ->setBegin(new DateTime('2018-11-28')) - ->setEnd(new DateTime()) - ->setDuration(400) - ->setRate(84) - ->setUser($user2) - ->setActivity(new Activity()) - ->setProject($project3); + $timesheet5->setBegin(new DateTime('2018-11-28')); + $timesheet5->setEnd(new DateTime()); + $timesheet5->setDuration(400); + $timesheet5->setRate(84); + $timesheet5->setUser($user2); + $timesheet5->setActivity(new Activity()); + $timesheet5->setProject($project3); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; diff --git a/tests/Invoice/Calculator/ShortInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ShortInvoiceCalculatorTest.php index 1be5437e..d7f0e24d 100644 --- a/tests/Invoice/Calculator/ShortInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ShortInvoiceCalculatorTest.php @@ -49,43 +49,37 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTestCase $activity->setProject($project); $timesheet = new Timesheet(); - $timesheet - ->setDuration(3600) - ->setRate(293.27) - ->setHourlyRate(293.27) - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2018-11-29')) - ->setEnd(new \DateTime()) - ->addTag((new Tag())->setName('foo')) - ->addTag((new Tag())->setName('bar')) - ; + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setHourlyRate(293.27); + $timesheet->setUser(new User()); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setBegin(new \DateTime('2018-11-29')); + $timesheet->setEnd(new \DateTime()); + $timesheet->addTag((new Tag())->setName('foo')); + $timesheet->addTag((new Tag())->setName('bar')); $timesheet2 = new Timesheet(); - $timesheet2 - ->setDuration(400) - ->setRate(32.59) - ->setHourlyRate(293.27) - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2018-11-28')) - ->setEnd(new \DateTime()) - ->addTag((new Tag())->setName('bar1')) - ; + $timesheet2->setDuration(400); + $timesheet2->setRate(32.59); + $timesheet2->setHourlyRate(293.27); + $timesheet2->setUser(new User()); + $timesheet2->setActivity($activity); + $timesheet2->setProject($project); + $timesheet2->setBegin(new \DateTime('2018-11-28')); + $timesheet2->setEnd(new \DateTime()); + $timesheet2->addTag((new Tag())->setName('bar1')); $timesheet3 = new Timesheet(); - $timesheet3 - ->setDuration(1800) - ->setRate(146.64) - ->setHourlyRate(293.27) - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2018-11-29')) - ->setEnd(new \DateTime()) - ; + $timesheet3->setDuration(1800); + $timesheet3->setRate(146.64); + $timesheet3->setHourlyRate(293.27); + $timesheet3->setUser(new User()); + $timesheet3->setActivity($activity); + $timesheet3->setProject($project); + $timesheet3->setBegin(new \DateTime('2018-11-29')); + $timesheet3->setEnd(new \DateTime()); $entries = [$timesheet, $timesheet2, $timesheet3]; @@ -134,40 +128,34 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTestCase $activity->setProject($project); $timesheet = new Timesheet(); - $timesheet - ->setDuration(3600) - ->setRate(293.27) - ->setHourlyRate(293.27) - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setHourlyRate(293.27); + $timesheet->setUser(new User()); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setBegin(new \DateTime()); + $timesheet->setEnd(new \DateTime()); $timesheet2 = new Timesheet(); - $timesheet2 - ->setDuration(400) - ->setRate(84) - ->setHourlyRate(756.00) - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet2->setDuration(400); + $timesheet2->setRate(84); + $timesheet2->setHourlyRate(756.00); + $timesheet2->setUser(new User()); + $timesheet2->setActivity($activity); + $timesheet2->setProject($project); + $timesheet2->setBegin(new \DateTime()); + $timesheet2->setEnd(new \DateTime()); $timesheet3 = new Timesheet(); - $timesheet3 - ->setDuration(1800) - ->setRate(111.11) - ->setHourlyRate(222.22) - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setHourlyRate(222.22); + $timesheet3->setUser(new User()); + $timesheet3->setActivity($activity); + $timesheet3->setProject($project); + $timesheet3->setBegin(new \DateTime()); + $timesheet3->setEnd(new \DateTime()); $entries = [$timesheet, $timesheet2, $timesheet3]; @@ -212,38 +200,32 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTestCase $activity->setProject($project); $timesheet = new Timesheet(); - $timesheet - ->setDuration(3600) - ->setRate(293.27) - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser(new User()); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setBegin(new \DateTime()); + $timesheet->setEnd(new \DateTime()); $timesheet2 = new Timesheet(); - $timesheet2 - ->setDuration(400) - ->setFixedRate(84) - ->setRate(84) - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet2->setDuration(400); + $timesheet2->setFixedRate(84); + $timesheet2->setRate(84); + $timesheet2->setUser(new User()); + $timesheet2->setActivity($activity); + $timesheet2->setProject($project); + $timesheet2->setBegin(new \DateTime()); + $timesheet2->setEnd(new \DateTime()); $timesheet3 = new Timesheet(); - $timesheet3 - ->setDuration(1800) - ->setRate(111.11) - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser(new User()); + $timesheet3->setActivity($activity); + $timesheet3->setProject($project); + $timesheet3->setBegin(new \DateTime()); + $timesheet3->setEnd(new \DateTime()); $entries = [$timesheet, $timesheet2, $timesheet3]; diff --git a/tests/Invoice/Calculator/UserInvoiceCalculatorTest.php b/tests/Invoice/Calculator/UserInvoiceCalculatorTest.php index ae6e44a5..31dd10ea 100644 --- a/tests/Invoice/Calculator/UserInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/UserInvoiceCalculatorTest.php @@ -52,54 +52,49 @@ class UserInvoiceCalculatorTest extends AbstractCalculatorTestCase $user3->method('getId')->willReturn(3); $timesheet = new Timesheet(); - $timesheet - ->setBegin(new \DateTime('2018-11-29')) - ->setEnd(new \DateTime()) - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user1) - ->setActivity($activity) - ->setProject((new Project())->setName('bar')); + $timesheet->setBegin(new \DateTime('2018-11-29')); + $timesheet->setEnd(new \DateTime()); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user1); + $timesheet->setActivity($activity); + $timesheet->setProject((new Project())->setName('bar')); $timesheet2 = new Timesheet(); - $timesheet2 - ->setBegin(new \DateTime('2018-11-28')) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(84.75) - ->setUser($user2) - ->setActivity($activity) - ->setProject((new Project())->setName('bar')); + $timesheet2->setBegin(new \DateTime('2018-11-28')); + $timesheet2->setEnd(new \DateTime()); + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user2); + $timesheet2->setActivity($activity); + $timesheet2->setProject((new Project())->setName('bar')); $timesheet3 = new Timesheet(); - $timesheet3 - ->setBegin(new \DateTime('2018-11-08')) - ->setEnd(new \DateTime()) - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user1) - ->setActivity($activity) - ->setProject((new Project())->setName('bar')); + $timesheet3->setBegin(new \DateTime('2018-11-08')); + $timesheet3->setEnd(new \DateTime()); + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user1); + $timesheet3->setActivity($activity); + $timesheet3->setProject((new Project())->setName('bar')); $timesheet4 = new Timesheet(); - $timesheet4 - ->setBegin(new \DateTime('2018-11-28')) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user2) - ->setActivity($activity) - ->setProject((new Project())->setName('bar')); + $timesheet4->setBegin(new \DateTime('2018-11-28')); + $timesheet4->setEnd(new \DateTime()); + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user2); + $timesheet4->setActivity($activity); + $timesheet4->setProject((new Project())->setName('bar')); $timesheet5 = new Timesheet(); - $timesheet5 - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ->setDuration(400) - ->setRate(84) - ->setUser($user3) - ->setActivity($activity) - ->setProject((new Project())->setName('bar')); + $timesheet5->setBegin(new \DateTime()); + $timesheet5->setEnd(new \DateTime()); + $timesheet5->setDuration(400); + $timesheet5->setRate(84); + $timesheet5->setUser($user3); + $timesheet5->setActivity($activity); + $timesheet5->setProject((new Project())->setName('bar')); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; diff --git a/tests/Invoice/Calculator/WeeklyInvoiceCalculatorTest.php b/tests/Invoice/Calculator/WeeklyInvoiceCalculatorTest.php index d2fc1e3a..e3d81791 100644 --- a/tests/Invoice/Calculator/WeeklyInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/WeeklyInvoiceCalculatorTest.php @@ -57,54 +57,49 @@ class WeeklyInvoiceCalculatorTest extends AbstractCalculatorTestCase $end = new \DateTime('now', $timezone); $timesheet = new Timesheet(); - $timesheet - ->setBegin(new DateTime('2018-11-26 12:00:00', $timezone)) - ->setEnd(clone $end) - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user) - ->setActivity((new Activity())->setName('sdsd')) - ->setProject($project1); + $timesheet->setBegin(new DateTime('2018-11-26 12:00:00', $timezone)); + $timesheet->setEnd(clone $end); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user); + $timesheet->setActivity((new Activity())->setName('sdsd')); + $timesheet->setProject($project1); $timesheet2 = new Timesheet(); - $timesheet2 - ->setBegin(new DateTime('2018-11-26 12:00:00', $timezone)) - ->setEnd(clone $end) - ->setDuration(400) - ->setRate(84.75) - ->setUser($user) - ->setActivity((new Activity())->setName('bar')) - ->setProject($project2); + $timesheet2->setBegin(new DateTime('2018-11-26 12:00:00', $timezone)); + $timesheet2->setEnd(clone $end); + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user); + $timesheet2->setActivity((new Activity())->setName('bar')); + $timesheet2->setProject($project2); $timesheet3 = new Timesheet(); - $timesheet3 - ->setBegin(new DateTime('2018-11-25 12:00:00', $timezone)) - ->setEnd(clone $end) - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user) - ->setActivity((new Activity())->setName('foo')) - ->setProject($project1); + $timesheet3->setBegin(new DateTime('2018-11-25 12:00:00', $timezone)); + $timesheet3->setEnd(clone $end); + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user); + $timesheet3->setActivity((new Activity())->setName('foo')); + $timesheet3->setProject($project1); $timesheet4 = new Timesheet(); - $timesheet4 - ->setBegin(new DateTime('2018-11-25 12:00:00', $timezone)) - ->setEnd(clone $end) - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user) - ->setActivity((new Activity())->setName('blub')) - ->setProject($project2); + $timesheet4->setBegin(new DateTime('2018-11-25 12:00:00', $timezone)); + $timesheet4->setEnd(clone $end); + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user); + $timesheet4->setActivity((new Activity())->setName('blub')); + $timesheet4->setProject($project2); $timesheet5 = new Timesheet(); - $timesheet5 - ->setBegin(new DateTime('2018-11-25 12:00:00', $timezone)) - ->setEnd(clone $end) - ->setDuration(400) - ->setRate(84) - ->setUser(new User()) - ->setActivity(new Activity()) - ->setProject($project3); + $timesheet5->setBegin(new DateTime('2018-11-25 12:00:00', $timezone)); + $timesheet5->setEnd(clone $end); + $timesheet5->setDuration(400); + $timesheet5->setRate(84); + $timesheet5->setUser(new User()); + $timesheet5->setActivity(new Activity()); + $timesheet5->setProject($project3); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; diff --git a/tests/Invoice/Hydrator/InvoiceModelCustomerHydratorTest.php b/tests/Invoice/Hydrator/InvoiceModelCustomerHydratorTest.php index bf25a205..325850d8 100644 --- a/tests/Invoice/Hydrator/InvoiceModelCustomerHydratorTest.php +++ b/tests/Invoice/Hydrator/InvoiceModelCustomerHydratorTest.php @@ -43,7 +43,7 @@ class InvoiceModelCustomerHydratorTest extends TestCase 'customer.vat' => '', 'customer.vat_id' => '', 'customer.number' => '', - 'customer.country' => null, + 'customer.country' => 'AT', 'customer.homepage' => '', 'customer.comment' => '', 'customer.email' => '', diff --git a/tests/Invoice/Hydrator/InvoiceModelDefaultHydratorTest.php b/tests/Invoice/Hydrator/InvoiceModelDefaultHydratorTest.php index 7c91fa1b..03825c45 100644 --- a/tests/Invoice/Hydrator/InvoiceModelDefaultHydratorTest.php +++ b/tests/Invoice/Hydrator/InvoiceModelDefaultHydratorTest.php @@ -12,6 +12,7 @@ namespace App\Tests\Invoice\Hydrator; use App\Invoice\Hydrator\InvoiceModelDefaultHydrator; use App\Tests\Invoice\Renderer\RendererTestTrait; use PHPUnit\Framework\TestCase; +use ReflectionObject; /** * @covers \App\Invoice\Hydrator\InvoiceModelDefaultHydrator @@ -30,6 +31,23 @@ class InvoiceModelDefaultHydratorTest extends TestCase $this->assertModelStructure($result); } + public function testHydrateThrowsOnMissing(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('InvoiceModel needs a template'); + + $model = $this->getInvoiceModel(); + + $obj = new ReflectionObject($model); + $prop = $obj->getProperty('template'); + $prop->setAccessible(true); + $prop->setValue($model, null); + + $sut = new InvoiceModelDefaultHydrator(); + + $sut->hydrate($model); + } + protected function assertModelStructure(array $model, bool $hasProject = true): void { $keys = [ @@ -60,6 +78,8 @@ class InvoiceModelDefaultHydratorTest extends TestCase 'invoice.subtotal_plain', 'template.name', 'template.company', + 'template.country', + 'template.country_name', 'template.address', 'template.title', 'template.payment_terms', diff --git a/tests/Invoice/Renderer/DebugRendererTest.php b/tests/Invoice/Renderer/DebugRendererTest.php index 1821e780..15f0f29c 100644 --- a/tests/Invoice/Renderer/DebugRendererTest.php +++ b/tests/Invoice/Renderer/DebugRendererTest.php @@ -111,6 +111,7 @@ class DebugRendererTest extends TestCase 'invoice.subtotal_plain', 'template.name', 'template.company', + 'template.country', 'template.address', 'template.title', 'template.payment_terms', @@ -118,6 +119,7 @@ class DebugRendererTest extends TestCase 'template.vat_id', 'template.contact', 'template.payment_details', + 'template.country_name', 'query.day', 'query.month', 'query.month_number', diff --git a/tests/Invoice/Renderer/RendererTestTrait.php b/tests/Invoice/Renderer/RendererTestTrait.php index f2c26513..ddc4d766 100644 --- a/tests/Invoice/Renderer/RendererTestTrait.php +++ b/tests/Invoice/Renderer/RendererTestTrait.php @@ -88,6 +88,7 @@ trait RendererTestTrait $customer = new Customer('customer,with/special#name'); $customer->setAddress('Foo' . PHP_EOL . 'Street' . PHP_EOL . '1111 City'); $customer->setCurrency('EUR'); + $customer->setCountry('AT'); $customer->setMetaField((new CustomerMeta())->setName('foo-customer')->setValue('bar-customer')->setIsVisible(true)); $template = new InvoiceTemplate(); @@ -152,61 +153,54 @@ trait RendererTestTrait $user2->method('getVisiblePreferences')->willReturn([$pref1, $pref2]); $timesheet = new Timesheet(); - $timesheet - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user1) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2020-12-13 14:00:00')) - ->setEnd(new \DateTime('2020-12-13 15:00:00')) - ->setMetaField((new TimesheetMeta())->setName('foo-timesheet')->setValue('bar-timesheet')->setIsVisible(true)); + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user1); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setBegin(new \DateTime('2020-12-13 14:00:00')); + $timesheet->setEnd(new \DateTime('2020-12-13 15:00:00')); + $timesheet->setMetaField((new TimesheetMeta())->setName('foo-timesheet')->setValue('bar-timesheet')->setIsVisible(true)); $timesheet2 = new Timesheet(); - $timesheet2 - ->setDuration(400) - ->setRate(84.75) - ->setUser($user2) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2020-08-13 14:00:00')) - ->setEnd(new \DateTime('2020-08-13 14:06:40')) - ->setMetaField((new TimesheetMeta())->setName('foo-timesheet')->setValue('bar-timesheet')) - ->setMetaField((new TimesheetMeta())->setName('foo-timesheet2')->setValue('bar-timesheet2')->setIsVisible(true)) - ; + $timesheet2->setDuration(400); + $timesheet2->setRate(84.75); + $timesheet2->setUser($user2); + $timesheet2->setActivity($activity); + $timesheet2->setProject($project); + $timesheet2->setBegin(new \DateTime('2020-08-13 14:00:00')); + $timesheet2->setEnd(new \DateTime('2020-08-13 14:06:40')); + $timesheet2->setMetaField((new TimesheetMeta())->setName('foo-timesheet')->setValue('bar-timesheet')); + $timesheet2->setMetaField((new TimesheetMeta())->setName('foo-timesheet2')->setValue('bar-timesheet2')->setIsVisible(true)); $timesheet3 = new Timesheet(); - $timesheet3 - ->setDuration(1800) - ->setRate(111.11) - ->setUser($user1) - ->setActivity($activity2) - ->setDescription('== jhg ljhg ') // make sure that spreadsheets don't render it as formula - ->setProject($project2) - ->setBegin(new \DateTime('2020-08-12 18:00:00')) - ->setEnd(new \DateTime('2020-08-12 18:30:00')) - ->setMetaField((new TimesheetMeta())->setName('foo-timesheet')->setValue('bar-timesheet1')->setIsVisible(true)) - ; + $timesheet3->setDuration(1800); + $timesheet3->setRate(111.11); + $timesheet3->setUser($user1); + $timesheet3->setActivity($activity2); + $timesheet3->setDescription('== jhg ljhg '); // make sure that spreadsheets don't render it as formula + $timesheet3->setProject($project2); + $timesheet3->setBegin(new \DateTime('2020-08-12 18:00:00')); + $timesheet3->setEnd(new \DateTime('2020-08-12 18:30:00')); + $timesheet3->setMetaField((new TimesheetMeta())->setName('foo-timesheet')->setValue('bar-timesheet1')->setIsVisible(true)); $timesheet4 = new Timesheet(); - $timesheet4 - ->setDuration(400) - ->setRate(1947.99) - ->setUser($user2) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2020-12-13 14:00:00')) - ->setEnd(new \DateTime('2020-12-13 14:06:40')) - ->setDescription( - "foo\n" . - "foo\r\n" . - 'foo' . PHP_EOL . - "bar\n" . - "bar\r\n" . - 'Hello' - ) - ->setMetaField((new TimesheetMeta())->setName('foo-timesheet3')->setValue('bluuuub')->setIsVisible(true)) - ; + $timesheet4->setDuration(400); + $timesheet4->setRate(1947.99); + $timesheet4->setUser($user2); + $timesheet4->setActivity($activity); + $timesheet4->setProject($project); + $timesheet4->setBegin(new \DateTime('2020-12-13 14:00:00')); + $timesheet4->setEnd(new \DateTime('2020-12-13 14:06:40')); + $timesheet4->setDescription( + "foo\n" . + "foo\r\n" . + 'foo' . PHP_EOL . + "bar\n" . + "bar\r\n" . + 'Hello' + ); + $timesheet4->setMetaField((new TimesheetMeta())->setName('foo-timesheet3')->setValue('bluuuub')->setIsVisible(true)); $userKevin = new User(); $userKevin->setUserIdentifier('kevin'); @@ -214,23 +208,21 @@ trait RendererTestTrait $userKevin->addPreference($pref2); $timesheet5 = new Timesheet(); - $timesheet5 - ->setDuration(400) - ->setFixedRate(84) - ->setUser($userKevin) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2021-03-12 12:13:00')) - ->setEnd(new \DateTime('2021-03-12 12:17:40')) - ->setDescription( - "foo\n" . - "foo\r\n" . - 'foo' . PHP_EOL . - "bar\n" . - "bar\r\n" . - 'Hello' - ) - ; + $timesheet5->setDuration(400); + $timesheet5->setFixedRate(84); + $timesheet5->setUser($userKevin); + $timesheet5->setActivity($activity); + $timesheet5->setProject($project); + $timesheet5->setBegin(new \DateTime('2021-03-12 12:13:00')); + $timesheet5->setEnd(new \DateTime('2021-03-12 12:17:40')); + $timesheet5->setDescription( + "foo\n" . + "foo\r\n" . + 'foo' . PHP_EOL . + "bar\n" . + "bar\r\n" . + 'Hello' + ); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; @@ -279,6 +271,7 @@ trait RendererTestTrait $user->addPreference(new UserPreference('hello', 'world')); $customer = new Customer('customer,with/special#name'); + $customer->setCountry('DE'); $customer->setCurrency('USD'); $customer->setMetaField((new CustomerMeta())->setName('foo-customer')->setValue('bar-customer')->setIsVisible(true)); @@ -307,15 +300,13 @@ trait RendererTestTrait $user1->method('getVisiblePreferences')->willReturn([$pref1, $pref2]); $timesheet = new Timesheet(); - $timesheet - ->setDuration(3600) - ->setRate(293.27) - ->setUser($user1) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime('2020-08-12 18:00:00')) - ->setEnd(new \DateTime('2021-03-12 18:30:00')) - ; + $timesheet->setDuration(3600); + $timesheet->setRate(293.27); + $timesheet->setUser($user1); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setBegin(new \DateTime('2020-08-12 18:00:00')); + $timesheet->setEnd(new \DateTime('2021-03-12 18:30:00')); $entries = [$timesheet]; diff --git a/tests/Project/ProjectServiceTest.php b/tests/Project/ProjectServiceTest.php index 3e7f6b96..4a52b2c0 100644 --- a/tests/Project/ProjectServiceTest.php +++ b/tests/Project/ProjectServiceTest.php @@ -9,6 +9,7 @@ namespace App\Tests\Project; +use App\Configuration\SystemConfiguration; use App\Entity\Customer; use App\Entity\Project; use App\Entity\Team; @@ -38,7 +39,7 @@ class ProjectServiceTest extends TestCase private function getSut( ?EventDispatcherInterface $dispatcher = null, ?ValidatorInterface $validator = null, - bool $copyTeamsOnCreate = false + ?SystemConfiguration $configuration = null ): ProjectService { $repository = $this->createMock(ProjectRepository::class); @@ -54,7 +55,11 @@ class ProjectServiceTest extends TestCase $validator->method('validate')->willReturn(new ConstraintViolationList()); } - $configuration = SystemConfigurationFactory::createStub(['project' => ['copy_teams_on_create' => $copyTeamsOnCreate]]); + if ($configuration === null) { + $configuration = SystemConfigurationFactory::createStub( + ['project' => ['copy_teams_on_create' => false]] + ); + } return new ProjectService($repository, $configuration, $dispatcher, $validator); } @@ -151,8 +156,11 @@ class ProjectServiceTest extends TestCase public function testCreateNewProjectCopiesTeam(): void { $dispatcher = $this->createMock(EventDispatcherInterface::class); + $configuration = SystemConfigurationFactory::createStub( + ['project' => ['copy_teams_on_create' => true]] + ); - $sut = $this->getSut($dispatcher, null, true); + $sut = $this->getSut($dispatcher, null, $configuration); $team1 = new Team('foo'); $team2 = new Team('bar'); @@ -176,4 +184,78 @@ class ProjectServiceTest extends TestCase $project = $sut->createNewProject(); self::assertNull($project->getCustomer()); } + + /** + * @dataProvider getTestData + */ + public function testProjectNumber(string $format, int|string $expected): void + { + $configuration = SystemConfigurationFactory::createStub([ + 'project' => [ + 'copy_teams_on_create' => true, + 'number_format' => $format, + ] + ]); + + $sut = $this->getSut(null, null, $configuration); + $project = $sut->createNewProject(); + + self::assertEquals((string) $expected, $project->getNumber()); + } + + /** + * @return array> + */ + public static function getTestData(): array + { + $dateTime = new \DateTime(); + + $yearLong = (int) $dateTime->format('Y'); + $yearShort = (int) $dateTime->format('y'); + $monthLong = $dateTime->format('m'); + $monthShort = (int) $dateTime->format('n'); + $dayLong = $dateTime->format('d'); + $dayShort = (int) $dateTime->format('j'); + + return [ + // simple tests for single calls + ['{pc,1}', '2'], + ['{pc,2}', '02'], + ['{pc,3}', '002'], + ['{pc,4}', '0002'], + ['{Y}', $yearLong], + ['{y}', $yearShort], + ['{M}', $monthLong], + ['{m}', $monthShort], + ['{D}', $dayLong], + ['{d}', $dayShort], + // number formatting (not testing the lower case versions, as the tests might break depending on the date) + ['{Y,6}', '00' . $yearLong], + ['{M,3}', '0' . $monthLong], + ['{D,3}', '0' . $dayLong], + // increment dates + ['{YY}', $yearLong + 1], + ['{YY+1}', $yearLong + 1], + ['{YY+2}', $yearLong + 2], + ['{YY+3}', $yearLong + 3], + ['{YY-1}', $yearLong - 1], + ['{YY-2}', $yearLong - 2], + ['{YY-3}', $yearLong - 3], + ['{yy}', $yearShort + 1], + ['{yy+1}', $yearShort + 1], + ['{yy+2}', $yearShort + 2], + ['{yy+3}', $yearShort + 3], + ['{yy-1}', $yearShort - 1], + ['{yy-2}', $yearShort - 2], + ['{yy-3}', $yearShort - 3], + ['{MM}', $monthShort + 1], // cast to int removes leading zero + ['{MM+1}', $monthShort + 1], // cast to int removes leading zero + ['{MM+2}', $monthShort + 2], // cast to int removes leading zero + ['{MM+3}', $monthShort + 3], // cast to int removes leading zero + ['{DD}', $dayShort + 1], // cast to int removes leading zero + ['{DD+1}', $dayShort + 1], // cast to int removes leading zero + ['{DD+2}', $dayShort + 2], // cast to int removes leading zero + ['{DD+3}', $dayShort + 3], // cast to int removes leading zero + ]; + } } diff --git a/tests/Timesheet/Calculator/RateCalculatorTest.php b/tests/Timesheet/Calculator/RateCalculatorTest.php index c5a91f58..44d97fd8 100644 --- a/tests/Timesheet/Calculator/RateCalculatorTest.php +++ b/tests/Timesheet/Calculator/RateCalculatorTest.php @@ -132,15 +132,13 @@ class RateCalculatorTest extends TestCase $activity->setProject($project); $timesheet = new Timesheet(); - $timesheet - ->setEnd(new \DateTime()) - ->setHourlyRate($timesheetHourly) - ->setFixedRate($timesheetFixed) - ->setActivity($activity) - ->setProject($project) - ->setDuration($duration) - ->setUser($this->getTestUser($userRate, $userInternalRate)) - ; + $timesheet->setEnd(new \DateTime()); + $timesheet->setHourlyRate($timesheetHourly); + $timesheet->setFixedRate($timesheetFixed); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setDuration($duration); + $timesheet->setUser($this->getTestUser($userRate, $userInternalRate)); $rates = []; diff --git a/tests/Timesheet/DateTimeFactoryTest.php b/tests/Timesheet/DateTimeFactoryTest.php index 36f00fa6..b9ef25c2 100644 --- a/tests/Timesheet/DateTimeFactoryTest.php +++ b/tests/Timesheet/DateTimeFactoryTest.php @@ -45,7 +45,6 @@ class DateTimeFactoryTest extends TestCase public function testGetStartOfMonth(): void { $expected = new DateTime('now', new DateTimeZone(self::TEST_TIMEZONE)); - $sut = $this->createDateTimeFactory(self::TEST_TIMEZONE); $dateTime = $sut->getStartOfMonth(); self::assertEquals(0, $dateTime->format('H')); @@ -55,12 +54,30 @@ class DateTimeFactoryTest extends TestCase self::assertEquals($expected->format('m'), $dateTime->format('m')); self::assertEquals($expected->format('Y'), $dateTime->format('Y')); self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); + + $dateTime = $sut->getStartOfMonth('now'); + self::assertEquals(0, $dateTime->format('H')); + self::assertEquals(0, $dateTime->format('i')); + self::assertEquals(0, $dateTime->format('s')); + self::assertEquals(1, $dateTime->format('d')); + self::assertEquals($expected->format('m'), $dateTime->format('m')); + self::assertEquals($expected->format('Y'), $dateTime->format('Y')); + self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); + + $expected = new DateTime('now', new DateTimeZone('Atlantic/Canary')); + $dateTime = $sut->getStartOfMonth($expected); + self::assertEquals(0, $dateTime->format('H')); + self::assertEquals(0, $dateTime->format('i')); + self::assertEquals(0, $dateTime->format('s')); + self::assertEquals(1, $dateTime->format('d')); + self::assertEquals($expected->format('m'), $dateTime->format('m')); + self::assertEquals($expected->format('Y'), $dateTime->format('Y')); + self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); } public function testGetEndOfMonth(): void { $expected = new DateTime('last day of this month', new DateTimeZone(self::TEST_TIMEZONE)); - $sut = $this->createDateTimeFactory(self::TEST_TIMEZONE); $dateTime = $sut->getEndOfMonth(); self::assertEquals(23, $dateTime->format('H')); @@ -70,6 +87,26 @@ class DateTimeFactoryTest extends TestCase self::assertEquals($expected->format('m'), $dateTime->format('m')); self::assertEquals($expected->format('Y'), $dateTime->format('Y')); self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); + + $sut = $this->createDateTimeFactory(self::TEST_TIMEZONE); + $dateTime = $sut->getEndOfMonth('last day of this month'); + self::assertEquals(23, $dateTime->format('H')); + self::assertEquals(59, $dateTime->format('i')); + self::assertEquals(59, $dateTime->format('s')); + self::assertEquals($expected->format('d'), $dateTime->format('d')); + self::assertEquals($expected->format('m'), $dateTime->format('m')); + self::assertEquals($expected->format('Y'), $dateTime->format('Y')); + self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); + + $expected = new DateTime('last day of this month', new DateTimeZone('Atlantic/Canary')); + $dateTime = $sut->getEndOfMonth($expected); + self::assertEquals(23, $dateTime->format('H')); + self::assertEquals(59, $dateTime->format('i')); + self::assertEquals(59, $dateTime->format('s')); + self::assertEquals($expected->format('d'), $dateTime->format('d')); + self::assertEquals($expected->format('m'), $dateTime->format('m')); + self::assertEquals($expected->format('Y'), $dateTime->format('Y')); + self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); } public static function getStartOfWeekData() @@ -175,6 +212,8 @@ class DateTimeFactoryTest extends TestCase $sut = $this->createDateTimeFactory(self::TEST_TIMEZONE); $dateTime = $sut->createStartOfFinancialYear(); $expected = $sut->createDateTime('01 january this year 00:00:00'); + + self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); self::assertInstanceOf(DateTime::class, $dateTime); self::assertEquals($expected, $dateTime); } @@ -224,6 +263,7 @@ class DateTimeFactoryTest extends TestCase $now = $sut->createDateTime(); $year = $sut->createStartOfYear(); + self::assertEquals(self::TEST_TIMEZONE, $year->getTimezone()->getName()); self::assertEquals($now->format('Y'), $year->format('Y')); self::assertEquals('01', $year->format('m')); self::assertEquals('01', $year->format('d')); @@ -233,6 +273,15 @@ class DateTimeFactoryTest extends TestCase $begin = $sut->createDateTime('2017-12-31 23:59:59'); $year = $sut->createStartOfYear($begin); + self::assertEquals(self::TEST_TIMEZONE, $year->getTimezone()->getName()); + self::assertEquals('2017', $year->format('Y')); + self::assertEquals('01', $year->format('m')); + self::assertEquals('01', $year->format('d')); + self::assertEquals('00:00:00', $year->format('H:i:s')); + + $begin = new \DateTime('2017-12-01 23:59:59', new DateTimeZone('Atlantic/Canary')); + $year = $sut->createStartOfYear($begin); + self::assertEquals(self::TEST_TIMEZONE, $year->getTimezone()->getName()); self::assertEquals('2017', $year->format('Y')); self::assertEquals('01', $year->format('m')); self::assertEquals('01', $year->format('d')); @@ -245,6 +294,7 @@ class DateTimeFactoryTest extends TestCase $now = $sut->createDateTime(); $year = $sut->createEndOfYear(); + self::assertEquals(self::TEST_TIMEZONE, $year->getTimezone()->getName()); self::assertEquals($now->format('Y'), $year->format('Y')); self::assertEquals('12', $year->format('m')); self::assertEquals('31', $year->format('d')); @@ -254,9 +304,45 @@ class DateTimeFactoryTest extends TestCase $begin = $sut->createDateTime('2017-12-31 23:59:59'); $year = $sut->createEndOfYear($begin); + self::assertEquals(self::TEST_TIMEZONE, $year->getTimezone()->getName()); + self::assertEquals('2017', $year->format('Y')); + self::assertEquals('12', $year->format('m')); + self::assertEquals('31', $year->format('d')); + self::assertEquals('23:59:59', $year->format('H:i:s')); + + $begin = new \DateTime('2017-12-01 23:59:59', new DateTimeZone('Atlantic/Canary')); + $year = $sut->createEndOfYear($begin); + self::assertEquals(self::TEST_TIMEZONE, $year->getTimezone()->getName()); self::assertEquals('2017', $year->format('Y')); self::assertEquals('12', $year->format('m')); self::assertEquals('31', $year->format('d')); self::assertEquals('23:59:59', $year->format('H:i:s')); } + + public function testCreate(): void + { + $sut = $this->createDateTimeFactory(self::TEST_TIMEZONE); + $dateTime = $sut->create('2025-04-22 17:29:30'); + self::assertEquals(17, $dateTime->format('H')); + self::assertEquals(29, $dateTime->format('i')); + self::assertEquals(30, $dateTime->format('s')); + self::assertEquals('22', $dateTime->format('d')); + self::assertEquals('04', $dateTime->format('m')); + self::assertEquals('2025', $dateTime->format('Y')); + self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); + } + + public function testCreateFromFormat(): void + { + $sut = $this->createDateTimeFactory(self::TEST_TIMEZONE); + $dateTime = $sut->createDateTimeFromFormat('H:i:s m.d-Y', '17:29:30 04.22-2025'); + self::assertInstanceOf(DateTime::class, $dateTime); + self::assertEquals(17, $dateTime->format('H')); + self::assertEquals(29, $dateTime->format('i')); + self::assertEquals(30, $dateTime->format('s')); + self::assertEquals('22', $dateTime->format('d')); + self::assertEquals('04', $dateTime->format('m')); + self::assertEquals('2025', $dateTime->format('Y')); + self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); + } } diff --git a/tests/Timesheet/RateServiceTest.php b/tests/Timesheet/RateServiceTest.php index 039b7e6a..1c20e647 100644 --- a/tests/Timesheet/RateServiceTest.php +++ b/tests/Timesheet/RateServiceTest.php @@ -136,15 +136,13 @@ class RateServiceTest extends TestCase $activity->setProject($project); $timesheet = new Timesheet(); - $timesheet - ->setEnd(self::createDateTime()) - ->setHourlyRate($timesheetHourly) - ->setFixedRate($timesheetFixed) - ->setActivity($activity) - ->setProject($project) - ->setDuration($duration) - ->setUser($this->getTestUser($userRate, $userInternalRate)) - ; + $timesheet->setEnd(self::createDateTime()); + $timesheet->setHourlyRate($timesheetHourly); + $timesheet->setFixedRate($timesheetFixed); + $timesheet->setActivity($activity); + $timesheet->setProject($project); + $timesheet->setDuration($duration); + $timesheet->setUser($this->getTestUser($userRate, $userInternalRate)); $rates = []; diff --git a/translations/kiosk.de-CH.xlf b/translations/kiosk.de_CH.xlf similarity index 100% rename from translations/kiosk.de-CH.xlf rename to translations/kiosk.de_CH.xlf diff --git a/translations/kiosk.nb-NO.xlf b/translations/kiosk.nb_NO.xlf similarity index 100% rename from translations/kiosk.nb-NO.xlf rename to translations/kiosk.nb_NO.xlf diff --git a/translations/kiosk.pt-BR.xlf b/translations/kiosk.pt_BR.xlf similarity index 100% rename from translations/kiosk.pt-BR.xlf rename to translations/kiosk.pt_BR.xlf diff --git a/translations/kiosk.zh-Hans.xlf b/translations/kiosk.zh_CN.xlf similarity index 59% rename from translations/kiosk.zh-Hans.xlf rename to translations/kiosk.zh_CN.xlf index eee9117a..134db42f 100644 --- a/translations/kiosk.zh-Hans.xlf +++ b/translations/kiosk.zh_CN.xlf @@ -1,6 +1,6 @@ - + diff --git a/translations/kiosk.zh-Hant.xlf b/translations/kiosk.zh_Hant.xlf similarity index 100% rename from translations/kiosk.zh-Hant.xlf rename to translations/kiosk.zh_Hant.xlf diff --git a/translations/messages.de.xlf b/translations/messages.de.xlf index c5b17ade..5a6b1668 100644 --- a/translations/messages.de.xlf +++ b/translations/messages.de.xlf @@ -1938,6 +1938,22 @@ training Fortbildung + + Postcode + Postleitzahl + + + City + Stadt + + + address_deprecated + Dieses Feld wird in Kürze entfernt. Bitte übertragen Sie die Adresse, um weiterhin gültige Rechnungen zu erzeugen (z.B. für E-Rechnungen). + + + sending_company + Rechnungsabsender + diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index db86ccda..6c7dd666 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -1938,6 +1938,22 @@ training Training + + Postcode + ZIP / Postcode + + + City + City + + + address_deprecated + This field will be removed soon. Please transfer the address to continue generating valid invoices (e.g. for e-invoicing). + + + sending_company + Invoice Sender +