Release 2.0.11 (#3932)
- added "today" as selector in date-range dropdown - added feature to prevent auto-select of dropdowns with only one entry - added hint that no changes were detected in batch update - added negative invoice sums are possible (e.g. for credit notes) - fix project list is expanded after submission - fix invalid date parsing causes 500 - fix: prevent auto-select of activities in export and invoice form (in case only one global activity exists) - fix team assignments for customer and project were not saved (using API now) - fix form fieldset with legend styling (e.g. team project assignment) - fix required meta-field were forced to have a value in batch update - fix tomselect meta-field was not disabled in batch update - fix unset internal rate is shown as 0 - fix one minute rounding problem in duration-only mode with "now" being default time - fix column width and label for duration-only mode - tech debt: cleanup invoice template (remove invoice layout) - tech debt: reorder for simpler comparison with invoice form - possible BC for devs: remove unused methods from form trait - bump composer packages (includes new translations for auth screens)
This commit is contained in:
@@ -278,7 +278,7 @@ export default class KimaiFormSelect extends KimaiFormPlugin {
|
||||
const optionLength = allOptions.length;
|
||||
let selectOption = '';
|
||||
|
||||
if (optionLength === 1) {
|
||||
if (optionLength === 1 && node.dataset['autoselect'] === undefined) {
|
||||
selectOption = allOptions[0].value;
|
||||
} else if (optionLength === 2 && emptyOption !== null) {
|
||||
selectOption = allOptions[1].value;
|
||||
|
||||
@@ -4,3 +4,9 @@
|
||||
fieldset legend.col-form-label {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
/* See project assignment to teams */
|
||||
fieldset.form-fieldset legend {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"friendsofsymfony/rest-bundle": "^3.0",
|
||||
"gedmo/doctrine-extensions": "^3.6",
|
||||
"jms/serializer-bundle": "^5.0",
|
||||
"kevinpapst/tabler-bundle": "^0.12",
|
||||
"kevinpapst/tabler-bundle": "^0.13",
|
||||
"league/csv": "^9.4",
|
||||
"mpdf/mpdf": "^8.0",
|
||||
"nelmio/api-doc-bundle": "^4.0",
|
||||
|
||||
100
composer.lock
generated
100
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "56bca57f2bb60cae0ec13012925f7b89",
|
||||
"content-hash": "42733cc81b93bcae0a70454796d6c486",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@@ -2415,16 +2415,16 @@
|
||||
},
|
||||
{
|
||||
"name": "kevinpapst/tabler-bundle",
|
||||
"version": "0.12",
|
||||
"version": "0.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kevinpapst/TablerBundle.git",
|
||||
"reference": "b2643be7f670f07764bac35af498f09ee93258dd"
|
||||
"reference": "28287dc810186ef3188811af071cb67832e7c7f0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/kevinpapst/TablerBundle/zipball/b2643be7f670f07764bac35af498f09ee93258dd",
|
||||
"reference": "b2643be7f670f07764bac35af498f09ee93258dd",
|
||||
"url": "https://api.github.com/repos/kevinpapst/TablerBundle/zipball/28287dc810186ef3188811af071cb67832e7c7f0",
|
||||
"reference": "28287dc810186ef3188811af071cb67832e7c7f0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2473,7 +2473,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/0.12"
|
||||
"source": "https://github.com/kevinpapst/TablerBundle/tree/0.13"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2485,7 +2485,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-04T23:55:06+00:00"
|
||||
"time": "2023-03-21T09:35:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-escaper",
|
||||
@@ -2551,34 +2551,37 @@
|
||||
},
|
||||
{
|
||||
"name": "league/csv",
|
||||
"version": "9.8.0",
|
||||
"version": "9.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/csv.git",
|
||||
"reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47"
|
||||
"reference": "b4418ede47fbd88facc34e40a16c8ce9153b961b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/csv/zipball/9d2e0265c5d90f5dd601bc65ff717e05cec19b47",
|
||||
"reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47",
|
||||
"url": "https://api.github.com/repos/thephpleague/csv/zipball/b4418ede47fbd88facc34e40a16c8ce9153b961b",
|
||||
"reference": "b4418ede47fbd88facc34e40a16c8ce9153b961b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.4 || ^8.0"
|
||||
"php": "^8.1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"doctrine/collections": "^2.1.2",
|
||||
"ext-dom": "*",
|
||||
"friendsofphp/php-cs-fixer": "^v3.4.0",
|
||||
"phpstan/phpstan": "^1.3.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.1.0",
|
||||
"phpunit/phpunit": "^9.5.11"
|
||||
"ext-xdebug": "*",
|
||||
"friendsofphp/php-cs-fixer": "^v3.14.3",
|
||||
"phpbench/phpbench": "^1.2.8",
|
||||
"phpstan/phpstan": "^1.10.4",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.1.2",
|
||||
"phpstan/phpstan-phpunit": "^1.3.10",
|
||||
"phpstan/phpstan-strict-rules": "^1.5.0",
|
||||
"phpunit/phpunit": "^10.0.14"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes",
|
||||
"ext-dom": "Required to use the XMLConverter and the HTMLConverter classes",
|
||||
"ext-iconv": "Needed to ease transcoding CSV using iconv stream filters"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -2631,7 +2634,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-04T00:13:07+00:00"
|
||||
"time": "2023-03-11T15:57:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lorenzo/pinky",
|
||||
@@ -10312,16 +10315,16 @@
|
||||
},
|
||||
{
|
||||
"name": "zircote/swagger-php",
|
||||
"version": "4.7.3",
|
||||
"version": "4.7.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zircote/swagger-php.git",
|
||||
"reference": "0299edc47eb4813a2c598a0348eaf205704adc92"
|
||||
"reference": "4a1d1272c2dd3afd8d96e92f02dc3565d5cc3c18"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/0299edc47eb4813a2c598a0348eaf205704adc92",
|
||||
"reference": "0299edc47eb4813a2c598a0348eaf205704adc92",
|
||||
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/4a1d1272c2dd3afd8d96e92f02dc3565d5cc3c18",
|
||||
"reference": "4a1d1272c2dd3afd8d96e92f02dc3565d5cc3c18",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10384,9 +10387,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/zircote/swagger-php/issues",
|
||||
"source": "https://github.com/zircote/swagger-php/tree/4.7.3"
|
||||
"source": "https://github.com/zircote/swagger-php/tree/4.7.8"
|
||||
},
|
||||
"time": "2023-03-08T02:27:27+00:00"
|
||||
"time": "2023-03-19T21:25:02+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@@ -10829,16 +10832,16 @@
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.14.4",
|
||||
"version": "v3.15.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "1b3d9dba63d93b8a202c31e824748218781eae6b"
|
||||
"reference": "d48755372a113bddb99f749e34805d83f3acfe04"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/1b3d9dba63d93b8a202c31e824748218781eae6b",
|
||||
"reference": "1b3d9dba63d93b8a202c31e824748218781eae6b",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/d48755372a113bddb99f749e34805d83f3acfe04",
|
||||
"reference": "d48755372a113bddb99f749e34805d83f3acfe04",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10905,9 +10908,15 @@
|
||||
}
|
||||
],
|
||||
"description": "A tool to automatically fix PHP code style",
|
||||
"keywords": [
|
||||
"Static code analysis",
|
||||
"fixer",
|
||||
"standards",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.14.4"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.15.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -10915,7 +10924,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-09T21:49:13+00:00"
|
||||
"time": "2023-03-13T23:26:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
@@ -11155,16 +11164,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.5",
|
||||
"version": "1.10.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "1fb6f494d82455151ecf15c5c191923f5d84324e"
|
||||
"reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/1fb6f494d82455151ecf15c5c191923f5d84324e",
|
||||
"reference": "1fb6f494d82455151ecf15c5c191923f5d84324e",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/b10ceb526d9607903c5b2673f1fc8775dbe48975",
|
||||
"reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -11193,8 +11202,11 @@
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://phpstan.org/user-guide/getting-started",
|
||||
"forum": "https://github.com/phpstan/phpstan/discussions",
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.10.5"
|
||||
"security": "https://github.com/phpstan/phpstan/security/policy",
|
||||
"source": "https://github.com/phpstan/phpstan-src"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -11210,20 +11222,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-07T16:48:45+00:00"
|
||||
"time": "2023-03-16T15:24:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-doctrine",
|
||||
"version": "1.3.33",
|
||||
"version": "1.3.37",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-doctrine.git",
|
||||
"reference": "fcb67c2a747300ff8e6ae278191f6ff79fc90370"
|
||||
"reference": "62bd362b432fe29e175168689510ddd927b698f8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/fcb67c2a747300ff8e6ae278191f6ff79fc90370",
|
||||
"reference": "fcb67c2a747300ff8e6ae278191f6ff79fc90370",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/62bd362b432fe29e175168689510ddd927b698f8",
|
||||
"reference": "62bd362b432fe29e175168689510ddd927b698f8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -11278,9 +11290,9 @@
|
||||
"description": "Doctrine extensions for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-doctrine/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.33"
|
||||
"source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.37"
|
||||
},
|
||||
"time": "2023-02-21T08:52:52+00:00"
|
||||
"time": "2023-03-17T14:57:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
|
||||
457
phpstan.neon
457
phpstan.neon
@@ -1560,109 +1560,9 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controller/TagController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\TagController\\:\\:createAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TagController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\TagController\\:\\:editAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TagController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\TagController\\:\\:multiDelete\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TagController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$tags of method App\\\\Repository\\\\TagRepository\\:\\:multiDelete\\(\\) expects iterable\\<App\\\\Entity\\\\Tag\\>, iterable\\<object\\> given\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TagController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\TeamController\\:\\:duplicateTeam\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TeamController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\TeamController\\:\\:editAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TeamController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\TeamController\\:\\:editMemberAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TeamController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:addTag\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:getMetaField\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:getTags\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:removeTag\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:setActivity\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:setBillable\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:setExported\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:setFixedRate\\(\\)\\.$#"
|
||||
count: 3
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:setHourlyRate\\(\\)\\.$#"
|
||||
count: 3
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:setInternalRate\\(\\)\\.$#"
|
||||
count: 3
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:setMetaField\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:setProject\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method object\\:\\:setUser\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getEntities\\(\\) on mixed\\.$#"
|
||||
count: 3
|
||||
count: 2
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
@@ -1675,11 +1575,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\TimesheetAbstractController\\:\\:multiUpdate\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\TimesheetAbstractController\\:\\:prepareQuery\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
@@ -1690,16 +1585,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$timesheets of method App\\\\Timesheet\\\\TimesheetService\\:\\:updateMultipleTimesheets\\(\\) expects array, iterable\\<object\\> given\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\<object\\> given\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetAbstractController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$page of method App\\\\Controller\\\\TimesheetAbstractController\\:\\:getEditForm\\(\\) expects int, mixed given\\.$#"
|
||||
count: 1
|
||||
@@ -3620,11 +3505,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/TimesheetPreCreateForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/AbstractToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3635,11 +3515,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/AbstractToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/AbstractToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3665,26 +3540,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/AbstractToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/AbstractToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/AbstractToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/AbstractToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/AbstractToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3710,11 +3570,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/AbstractToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ActivityToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3725,11 +3580,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ActivityToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ActivityToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3755,26 +3605,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ActivityToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ActivityToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ActivityToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ActivityToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ActivityToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3800,11 +3635,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/ActivityToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\CustomerToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/CustomerToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\CustomerToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3815,11 +3645,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/CustomerToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\CustomerToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/CustomerToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\CustomerToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3845,26 +3670,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/CustomerToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\CustomerToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/CustomerToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\CustomerToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/CustomerToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\CustomerToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/CustomerToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\CustomerToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/CustomerToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\CustomerToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3890,11 +3700,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/CustomerToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ExportToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ExportToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3905,11 +3710,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ExportToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ExportToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3935,26 +3735,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ExportToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ExportToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ExportToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ExportToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ExportToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3980,11 +3765,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/ExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceArchiveForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceArchiveForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceArchiveForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -3995,11 +3775,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceArchiveForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceArchiveForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceArchiveForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceArchiveForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4025,26 +3800,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceArchiveForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceArchiveForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceArchiveForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceArchiveForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceArchiveForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceArchiveForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceArchiveForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceArchiveForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceArchiveForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceArchiveForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4070,11 +3830,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/InvoiceArchiveForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4085,11 +3840,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4115,26 +3865,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/InvoiceToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\InvoiceToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4160,11 +3895,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/InvoiceToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ProjectToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ProjectToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ProjectToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4175,11 +3905,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ProjectToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ProjectToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ProjectToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ProjectToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4205,26 +3930,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ProjectToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ProjectToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ProjectToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ProjectToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ProjectToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ProjectToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ProjectToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ProjectToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/ProjectToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\ProjectToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4250,11 +3960,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/ProjectToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TagToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TagToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TagToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4265,11 +3970,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TagToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TagToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TagToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TagToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4295,26 +3995,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TagToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TagToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TagToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TagToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TagToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TagToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TagToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TagToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TagToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TagToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4340,11 +4025,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/TagToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TeamToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TeamToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TeamToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4355,11 +4035,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TeamToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TeamToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TeamToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TeamToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4385,26 +4060,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TeamToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TeamToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TeamToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TeamToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TeamToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TeamToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TeamToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TeamToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TeamToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TeamToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4430,11 +4090,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/TeamToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetExportToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetExportToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4445,11 +4100,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetExportToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetExportToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4475,26 +4125,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetExportToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetExportToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetExportToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetExportToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetExportToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4520,11 +4155,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/TimesheetExportToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4535,11 +4165,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4565,26 +4190,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/TimesheetToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\TimesheetToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4610,11 +4220,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Form/Toolbar/TimesheetToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\UserToolbarForm\\:\\:addActivityChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/UserToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\UserToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4625,11 +4230,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/UserToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\UserToolbarForm\\:\\:addCustomerChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/UserToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\UserToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -4655,26 +4255,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Toolbar/UserToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\UserToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$allowEmpty with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/UserToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\UserToolbarForm\\:\\:addDateRangeChoice\\(\\) has parameter \\$required with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/UserToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\UserToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/UserToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\UserToolbarForm\\:\\:addProjectChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Toolbar/UserToolbarForm.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Toolbar\\\\UserToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -5320,11 +4905,6 @@ parameters:
|
||||
count: 6
|
||||
path: src/Invoice/ServiceInvoice.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getTotal\\(\\) on App\\\\Invoice\\\\CalculatorInterface\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Invoice/ServiceInvoice.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method hasInvoiceTemplate\\(\\) on App\\\\Entity\\\\Customer\\|null\\.$#"
|
||||
count: 1
|
||||
@@ -6950,26 +6530,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Timesheet/TrackingMode/AbstractTrackingMode.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getTimezone\\(\\) on DateTime\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Timesheet/TrackingMode/DurationFixedBeginMode.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method modify\\(\\) on DateTime\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Timesheet/TrackingMode/DurationFixedBeginMode.php
|
||||
|
||||
-
|
||||
message: "#^Cannot clone DateTime\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Timesheet/TrackingMode/DurationFixedBeginMode.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$begin of method App\\\\Entity\\\\Timesheet\\:\\:setBegin\\(\\) expects DateTime, DateTime\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Timesheet/TrackingMode/DurationFixedBeginMode.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Twig\\\\Configuration\\:\\:__call\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
@@ -7964,3 +7524,18 @@ parameters:
|
||||
message: "#^Property App\\\\Widget\\\\WidgetService\\:\\:\\$widgets type has no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Widget/WidgetService.php
|
||||
|
||||
-
|
||||
message: "#^Property App\\\\Form\\\\MultiUpdate\\\\MultiUpdateTableDTO\\:\\:\\$entities with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection does not specify its types\\: TKey, T$#"
|
||||
count: 1
|
||||
path: src/Form/MultiUpdate/MultiUpdateTableDTO.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\MultiUpdate\\\\MultiUpdateTableDTO\\:\\:getEntities\\(\\) return type with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection does not specify its types\\: TKey, T$#"
|
||||
count: 1
|
||||
path: src/Form/MultiUpdate/MultiUpdateTableDTO.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\MultiUpdate\\\\MultiUpdateTableDTO\\:\\:setEntities\\(\\) has parameter \\$entities with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection but does not specify its types\\: TKey, T$#"
|
||||
count: 1
|
||||
path: src/Form/MultiUpdate/MultiUpdateTableDTO.php
|
||||
|
||||
File diff suppressed because one or more lines are too long
2
public/build/app.4ca3f16e.js
Normal file
2
public/build/app.4ca3f16e.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3,10 +3,10 @@
|
||||
"app": {
|
||||
"js": [
|
||||
"/build/runtime.f0079159.js",
|
||||
"/build/app.454ad090.js"
|
||||
"/build/app.4ca3f16e.js"
|
||||
],
|
||||
"css": [
|
||||
"/build/app.c429ff5b.css"
|
||||
"/build/app.b10b16e5.css"
|
||||
]
|
||||
},
|
||||
"export-pdf": {
|
||||
@@ -63,8 +63,8 @@
|
||||
},
|
||||
"integrity": {
|
||||
"/build/runtime.f0079159.js": "sha384-H22sAW1aTvyIPqvHOvGXWSWTxf0y6mptp+MsVmyXCfjx/WJjBbhX9gbUZ+qIuihV",
|
||||
"/build/app.454ad090.js": "sha384-5EqTkHqGv38S0Z8pXK2h0tHtGoCxbBkAYeSg1S0pe5eTWItPP4fiIfgJkD6eVH9U",
|
||||
"/build/app.c429ff5b.css": "sha384-m7RJ9g2fW3tENrf+oi/FsH8wTu6fsjuhvpDztfqr+YjNN0AvCapER6yvmGkqwp+I",
|
||||
"/build/app.4ca3f16e.js": "sha384-4VmfUWQxO4OK+j7bPm7p+B8b/krMYs5T+JLrU6DPiTep/LNoMLq11DGP7QL0j7Pu",
|
||||
"/build/app.b10b16e5.css": "sha384-dwEgmHAQRm4PP7XTYkJfIoB+Iumd+0WuH5FyoC/+qC3WQ/e1gCTmlx9M2mIBxPuK",
|
||||
"/build/export-pdf.587575e7.js": "sha384-J50GStmmfVwUTN4dIRQ02eg9hyzGFPSzpTtpPody92j0V6zCqw+s5l8+ZhVTugeW",
|
||||
"/build/export-pdf.d8a6c23b.css": "sha384-ztepocHE4rnGE9eKZ4kL6jTKaePUyiwiB9TjJjstjpf/ckcKg1HedrEOOk/8ElJg",
|
||||
"/build/invoice.c8ae95ad.js": "sha384-2eVY7MBiMQxo1vhfizU+fYfEZbz9bYUdzqxnpTQhxpYiLaxeSV4WnaObq2G7/Pks",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"build/app.css": "/build/app.c429ff5b.css",
|
||||
"build/app.js": "/build/app.454ad090.js",
|
||||
"build/app.css": "/build/app.b10b16e5.css",
|
||||
"build/app.js": "/build/app.4ca3f16e.js",
|
||||
"build/export-pdf.css": "/build/export-pdf.d8a6c23b.css",
|
||||
"build/export-pdf.js": "/build/export-pdf.587575e7.js",
|
||||
"build/invoice.css": "/build/invoice.3c80ee80.css",
|
||||
|
||||
@@ -15,6 +15,9 @@ use App\Entity\Project;
|
||||
use App\Entity\Team;
|
||||
use App\Entity\User;
|
||||
use App\Form\API\TeamApiEditForm;
|
||||
use App\Repository\ActivityRepository;
|
||||
use App\Repository\CustomerRepository;
|
||||
use App\Repository\ProjectRepository;
|
||||
use App\Repository\TeamRepository;
|
||||
use FOS\RestBundle\Controller\Annotations as Rest;
|
||||
use FOS\RestBundle\View\View;
|
||||
@@ -230,15 +233,14 @@ final class TeamController extends BaseApiController
|
||||
#[Rest\Post(path: '/{id}/customers/{customerId}', name: 'post_team_customer', requirements: ['id' => '\d+', 'customerId' => '\d+'])]
|
||||
#[ApiSecurity(name: 'apiUser')]
|
||||
#[ApiSecurity(name: 'apiToken')]
|
||||
public function postCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer): Response
|
||||
public function postCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer, CustomerRepository $customerRepository): Response
|
||||
{
|
||||
if ($team->hasCustomer($customer)) {
|
||||
throw new BadRequestHttpException('Team has already access to customer');
|
||||
}
|
||||
|
||||
$team->addCustomer($customer);
|
||||
|
||||
$this->repository->saveTeam($team);
|
||||
$customerRepository->saveCustomer($customer);
|
||||
|
||||
$view = new View($team, Response::HTTP_OK);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
@@ -256,15 +258,14 @@ final class TeamController extends BaseApiController
|
||||
#[ApiSecurity(name: 'apiUser')]
|
||||
#[ApiSecurity(name: 'apiToken')]
|
||||
#[Rest\Delete(path: '/{id}/customers/{customerId}', name: 'delete_team_customer', requirements: ['id' => '\d+', 'customerId' => '\d+'])]
|
||||
public function deleteCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer): Response
|
||||
public function deleteCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer, CustomerRepository $customerRepository): Response
|
||||
{
|
||||
if (!$team->hasCustomer($customer)) {
|
||||
throw new BadRequestHttpException('Customer is not assigned to the team');
|
||||
}
|
||||
|
||||
$team->removeCustomer($customer);
|
||||
|
||||
$this->repository->saveTeam($team);
|
||||
$customerRepository->saveCustomer($customer);
|
||||
|
||||
$view = new View($team, Response::HTTP_OK);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
@@ -282,15 +283,14 @@ final class TeamController extends BaseApiController
|
||||
#[Rest\Post(path: '/{id}/projects/{projectId}', name: 'post_team_project', requirements: ['id' => '\d+', 'projectId' => '\d+'])]
|
||||
#[ApiSecurity(name: 'apiUser')]
|
||||
#[ApiSecurity(name: 'apiToken')]
|
||||
public function postProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project): Response
|
||||
public function postProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project, ProjectRepository $projectRepository): Response
|
||||
{
|
||||
if ($team->hasProject($project)) {
|
||||
throw new BadRequestHttpException('Team has already access to project');
|
||||
}
|
||||
|
||||
$team->addProject($project);
|
||||
|
||||
$this->repository->saveTeam($team);
|
||||
$projectRepository->saveProject($project);
|
||||
|
||||
$view = new View($team, Response::HTTP_OK);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
@@ -308,15 +308,14 @@ final class TeamController extends BaseApiController
|
||||
#[ApiSecurity(name: 'apiUser')]
|
||||
#[ApiSecurity(name: 'apiToken')]
|
||||
#[Rest\Delete(path: '/{id}/projects/{projectId}', name: 'delete_team_project', requirements: ['id' => '\d+', 'projectId' => '\d+'])]
|
||||
public function deleteProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project): Response
|
||||
public function deleteProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project, ProjectRepository $projectRepository): Response
|
||||
{
|
||||
if (!$team->hasProject($project)) {
|
||||
throw new BadRequestHttpException('Project is not assigned to the team');
|
||||
}
|
||||
|
||||
$team->removeProject($project);
|
||||
|
||||
$this->repository->saveTeam($team);
|
||||
$projectRepository->saveProject($project);
|
||||
|
||||
$view = new View($team, Response::HTTP_OK);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
@@ -334,15 +333,14 @@ final class TeamController extends BaseApiController
|
||||
#[Rest\Post(path: '/{id}/activities/{activityId}', name: 'post_team_activity', requirements: ['id' => '\d+', 'activityId' => '\d+'])]
|
||||
#[ApiSecurity(name: 'apiUser')]
|
||||
#[ApiSecurity(name: 'apiToken')]
|
||||
public function postActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity): Response
|
||||
public function postActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity, ActivityRepository $activityRepository): Response
|
||||
{
|
||||
if ($team->hasActivity($activity)) {
|
||||
throw new BadRequestHttpException('Team has already access to activity');
|
||||
}
|
||||
|
||||
$team->addActivity($activity);
|
||||
|
||||
$this->repository->saveTeam($team);
|
||||
$activityRepository->saveActivity($activity);
|
||||
|
||||
$view = new View($team, Response::HTTP_OK);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
@@ -360,15 +358,14 @@ final class TeamController extends BaseApiController
|
||||
#[ApiSecurity(name: 'apiUser')]
|
||||
#[ApiSecurity(name: 'apiToken')]
|
||||
#[Rest\Delete(path: '/{id}/activities/{activityId}', name: 'delete_team_activity', requirements: ['id' => '\d+', 'activityId' => '\d+'])]
|
||||
public function deleteActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity): Response
|
||||
public function deleteActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity, ActivityRepository $activityRepository): Response
|
||||
{
|
||||
if (!$team->hasActivity($activity)) {
|
||||
throw new BadRequestHttpException('Activity is not assigned to the team');
|
||||
}
|
||||
|
||||
$team->removeActivity($activity);
|
||||
|
||||
$this->repository->saveTeam($team);
|
||||
$activityRepository->saveActivity($activity);
|
||||
|
||||
$view = new View($team, Response::HTTP_OK);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
|
||||
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.0.10';
|
||||
public const VERSION = '2.0.11';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 20010;
|
||||
public const VERSION_ID = 20011;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -68,7 +68,7 @@ final class CalendarController extends AbstractController
|
||||
$defaultStart = null;
|
||||
if ($this->configuration->getTimesheetDefaultBeginTime() !== 'now') {
|
||||
$defaultStart = $factory->createDateTime($this->configuration->getTimesheetDefaultBeginTime());
|
||||
$defaultStart = $defaultStart->format('h:i:s');
|
||||
$defaultStart = $defaultStart->format('H:i:s');
|
||||
}
|
||||
|
||||
$config = $this->calendarService->getConfiguration();
|
||||
|
||||
@@ -36,10 +36,17 @@ final class QuickEntryController extends AbstractController
|
||||
public function quickEntry(Request $request, ?string $begin = null)
|
||||
{
|
||||
$factory = $this->getDateTimeFactory();
|
||||
|
||||
if ($begin !== null) {
|
||||
try {
|
||||
$begin = $factory->createDateTime($begin);
|
||||
} catch (\Exception $ex) {
|
||||
$begin = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($begin === null) {
|
||||
$begin = $factory->createDateTime();
|
||||
} else {
|
||||
$begin = $factory->createDateTime($begin);
|
||||
}
|
||||
|
||||
$startWeek = $factory->getStartOfWeek($begin);
|
||||
|
||||
@@ -77,7 +77,7 @@ final class TagController extends AbstractController
|
||||
|
||||
#[Route(path: '/{id}/edit', name: 'tags_edit', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('manage_tag')]
|
||||
public function editAction(Tag $tag, TagRepository $repository, Request $request)
|
||||
public function editAction(Tag $tag, TagRepository $repository, Request $request): Response
|
||||
{
|
||||
$editForm = $this->createForm(TagEditForm::class, $tag, [
|
||||
'action' => $this->generateUrl('tags_edit', ['id' => $tag->getId()]),
|
||||
@@ -109,7 +109,7 @@ final class TagController extends AbstractController
|
||||
|
||||
#[Route(path: '/create', name: 'tags_create', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('manage_tag')]
|
||||
public function createAction(TagRepository $repository, Request $request)
|
||||
public function createAction(TagRepository $repository, Request $request): Response
|
||||
{
|
||||
$tag = new Tag();
|
||||
|
||||
@@ -143,7 +143,7 @@ final class TagController extends AbstractController
|
||||
|
||||
#[Route(path: '/multi-delete', name: 'tags_multi_delete', methods: ['POST'])]
|
||||
#[IsGranted('delete_tag')]
|
||||
public function multiDelete(TagRepository $repository, Request $request)
|
||||
public function multiDelete(TagRepository $repository, Request $request): Response
|
||||
{
|
||||
$form = $this->getMultiUpdateForm($repository);
|
||||
$form->handleRequest($request);
|
||||
|
||||
@@ -10,14 +10,15 @@
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Team;
|
||||
use App\Form\TeamCustomerForm;
|
||||
use App\Form\TeamEditForm;
|
||||
use App\Form\TeamProjectForm;
|
||||
use App\Form\Toolbar\TeamToolbarForm;
|
||||
use App\Form\Type\CustomerType;
|
||||
use App\Form\Type\ProjectType;
|
||||
use App\Repository\Query\TeamQuery;
|
||||
use App\Repository\TeamRepository;
|
||||
use App\Utils\DataTable;
|
||||
use App\Utils\PageSetup;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -90,7 +91,7 @@ final class TeamController extends AbstractController
|
||||
#[Route(path: '/{id}/duplicate', name: 'team_duplicate', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('create_team')]
|
||||
#[IsGranted('edit', 'team')]
|
||||
public function duplicateTeam(Team $team, Request $request)
|
||||
public function duplicateTeam(Team $team, Request $request): Response
|
||||
{
|
||||
$newTeam = clone $team;
|
||||
|
||||
@@ -105,14 +106,14 @@ final class TeamController extends AbstractController
|
||||
|
||||
#[Route(path: '/{id}/edit', name: 'admin_team_edit', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('edit', 'team')]
|
||||
public function editAction(Team $team, Request $request)
|
||||
public function editAction(Team $team, Request $request): Response
|
||||
{
|
||||
return $this->renderEditScreen($team, $request);
|
||||
}
|
||||
|
||||
#[Route(path: '/{id}/edit_member', name: 'admin_team_member', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('edit', 'team')]
|
||||
public function editMemberAction(Team $team, Request $request)
|
||||
public function editMemberAction(Team $team, Request $request): Response
|
||||
{
|
||||
$editForm = $this->createForm(TeamEditForm::class, $team, [
|
||||
'action' => $this->generateUrl('admin_team_member', ['id' => $team->getId()]),
|
||||
@@ -176,37 +177,21 @@ final class TeamController extends AbstractController
|
||||
}
|
||||
|
||||
if (null !== $team->getId()) {
|
||||
$customerForm = $this->createForm(TeamCustomerForm::class, $team, [
|
||||
'method' => 'POST',
|
||||
]);
|
||||
$customerForm->handleRequest($request);
|
||||
$customerForm = $this->createFormWithName('team_customer_form', FormType::class, $team)
|
||||
->add('customers', CustomerType::class, [
|
||||
'label' => false,
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'query_builder_for_user' => false,
|
||||
]);
|
||||
|
||||
if ($customerForm->isSubmitted() && $customerForm->isValid()) {
|
||||
try {
|
||||
$this->repository->saveTeam($team);
|
||||
$this->flashSuccess('action.update.success');
|
||||
|
||||
return $this->redirectToRoute('admin_team_edit', ['id' => $team->getId()]);
|
||||
} catch (\Exception $ex) {
|
||||
$this->flashUpdateException($ex);
|
||||
}
|
||||
}
|
||||
|
||||
$projectForm = $this->createForm(TeamProjectForm::class, $team, [
|
||||
'method' => 'POST',
|
||||
]);
|
||||
$projectForm->handleRequest($request);
|
||||
|
||||
if ($projectForm->isSubmitted() && $projectForm->isValid()) {
|
||||
try {
|
||||
$this->repository->saveTeam($team);
|
||||
$this->flashSuccess('action.update.success');
|
||||
|
||||
return $this->redirectToRoute('admin_team_edit', ['id' => $team->getId()]);
|
||||
} catch (\Exception $ex) {
|
||||
$this->flashUpdateException($ex);
|
||||
}
|
||||
}
|
||||
$projectForm = $this->createFormWithName('team_project_form', FormType::class, $team)
|
||||
->add('projects', ProjectType::class, [
|
||||
'label' => false,
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'query_builder_for_user' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
$page = new PageSetup('teams');
|
||||
|
||||
@@ -280,15 +280,19 @@ abstract class TimesheetAbstractController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
protected function multiUpdate(Request $request)
|
||||
protected function multiUpdate(Request $request): Response
|
||||
{
|
||||
$dto = new TimesheetMultiUpdateDTO();
|
||||
|
||||
// initial request from the listing posts a different form
|
||||
$form = $this->getMultiUpdateActionForm();
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$dto->setEntities($form->getData()->getEntities());
|
||||
$data = $form->getData();
|
||||
if ($data instanceof MultiUpdateTableDTO) {
|
||||
$dto->setEntities($data->getEntities());
|
||||
}
|
||||
}
|
||||
|
||||
// using a new timesheet to make sure we ONLY use meta-fields which are registered via events
|
||||
@@ -321,14 +325,14 @@ abstract class TimesheetAbstractController extends AbstractController
|
||||
|
||||
$dto->setEntities($timesheets);
|
||||
|
||||
if (\count($dto->getEntities()) === 0) {
|
||||
if (\count($timesheets) === 0) {
|
||||
return $this->redirectToRoute($this->getTimesheetRoute());
|
||||
}
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
/** @var Timesheet $timesheet */
|
||||
$execute = false;
|
||||
foreach ($dto->getEntities() as $timesheet) {
|
||||
/** @var Timesheet $timesheet */
|
||||
foreach ($timesheets as $timesheet) {
|
||||
if ($dto->isReplaceTags()) {
|
||||
foreach ($timesheet->getTags() as $tag) {
|
||||
$timesheet->removeTag($tag);
|
||||
@@ -391,13 +395,17 @@ abstract class TimesheetAbstractController extends AbstractController
|
||||
|
||||
if ($execute) {
|
||||
try {
|
||||
$this->service->updateMultipleTimesheets($dto->getEntities());
|
||||
$this->service->updateMultipleTimesheets($timesheets);
|
||||
$this->flashSuccess('action.update.success');
|
||||
|
||||
return $this->redirectToRoute($this->getTimesheetRoute());
|
||||
} catch (\Exception $ex) {
|
||||
$this->flashUpdateException($ex);
|
||||
}
|
||||
} else {
|
||||
$this->flashSuccess(sprintf('No changes for %s entries detected.', \count($timesheets)));
|
||||
|
||||
return $this->redirectToRoute($this->getTimesheetRoute());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ use Doctrine\Common\Collections\Collection;
|
||||
class MultiUpdateTableDTO
|
||||
{
|
||||
/**
|
||||
* @var iterable<object>|Collection<object>
|
||||
* @var array<object>|Collection<object>
|
||||
*/
|
||||
private iterable|Collection $entities = [];
|
||||
private array|Collection $entities = [];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
@@ -26,16 +26,16 @@ class MultiUpdateTableDTO
|
||||
/**
|
||||
* @return object[]
|
||||
*/
|
||||
public function getEntities(): iterable|Collection
|
||||
public function getEntities(): array|Collection
|
||||
{
|
||||
return $this->entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<object>|Collection<object> $entities
|
||||
* @param array<object>|Collection<object> $entities
|
||||
* @return MultiUpdateTableDTO
|
||||
*/
|
||||
public function setEntities(iterable|Collection $entities): MultiUpdateTableDTO
|
||||
public function setEntities(array|Collection $entities): MultiUpdateTableDTO
|
||||
{
|
||||
$this->entities = $entities;
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ final class TimesheetMultiUpdate extends AbstractType
|
||||
|
||||
// meta fields only if at least one exists
|
||||
if ($entry !== null && $entry->getMetaFields()->count() > 0) {
|
||||
$builder->add('metaFields', MetaFieldsCollectionType::class);
|
||||
$builder->add('metaFields', MetaFieldsCollectionType::class, ['fields_required' => false]);
|
||||
|
||||
$choices = [];
|
||||
foreach ($entry->getMetaFields() as $field) {
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Team;
|
||||
use App\Form\Type\CustomerType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
final class TeamCustomerForm extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('customers', CustomerType::class, [
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'by_reference' => false,
|
||||
'query_builder_for_user' => false,
|
||||
'required' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Team::class,
|
||||
'csrf_protection' => true,
|
||||
'csrf_field_name' => '_token',
|
||||
'csrf_token_id' => 'admin_team_customer',
|
||||
'attr' => [
|
||||
'data-form-event' => 'kimai.teamUpdate'
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Team;
|
||||
use App\Form\Type\ProjectType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
final class TeamProjectForm extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('projects', ProjectType::class, [
|
||||
'multiple' => true,
|
||||
'expanded' => false,
|
||||
'by_reference' => false,
|
||||
'attr' => ['size' => '20'],
|
||||
'query_builder_for_user' => false,
|
||||
'required' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Team::class,
|
||||
'csrf_protection' => true,
|
||||
'csrf_field_name' => '_token',
|
||||
'csrf_token_id' => 'admin_team_project',
|
||||
'attr' => [
|
||||
'data-form-event' => 'kimai.teamUpdate'
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -28,15 +28,15 @@ final class ExportToolbarForm extends AbstractType
|
||||
$this->addDateRange($builder, ['timezone' => $options['timezone']]);
|
||||
$this->addCustomerMultiChoice($builder, ['start_date_param' => null, 'end_date_param' => null, 'ignore_date' => true], true);
|
||||
$this->addProjectMultiChoice($builder, ['ignore_date' => true], true, true);
|
||||
$this->addActivityMultiChoice($builder, [], true);
|
||||
$this->addActivitySelect($builder, [], true, true, false);
|
||||
$this->addTagInputField($builder);
|
||||
if ($options['include_user']) {
|
||||
$this->addUsersChoice($builder);
|
||||
$this->addTeamsChoice($builder);
|
||||
}
|
||||
$this->addExportStateChoice($builder);
|
||||
$this->addTimesheetStateChoice($builder);
|
||||
$this->addBillableChoice($builder);
|
||||
$this->addExportStateChoice($builder);
|
||||
$builder->add('renderer', HiddenType::class, []);
|
||||
if ($options['include_export']) {
|
||||
$builder->add('markAsExported', HiddenType::class, [
|
||||
|
||||
@@ -25,21 +25,21 @@ final class InvoiceToolbarForm extends AbstractType
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$this->addTemplateChoice($builder);
|
||||
$this->addDateRange($builder, ['timezone' => $options['timezone']]);
|
||||
$this->addCustomerMultiChoice($builder, ['required' => false, 'start_date_param' => null, 'end_date_param' => null, 'ignore_date' => true, 'placeholder' => ''], true);
|
||||
$this->addProjectMultiChoice($builder, ['ignore_date' => true], false, true);
|
||||
$this->addSearchTermInputField($builder);
|
||||
$this->addDateRange($builder, ['timezone' => $options['timezone']]);
|
||||
$this->addCustomerMultiChoice($builder, ['start_date_param' => null, 'end_date_param' => null, 'ignore_date' => true], true);
|
||||
$this->addProjectMultiChoice($builder, ['ignore_date' => true], true, true);
|
||||
$this->addActivitySelect($builder, [], true, true, false);
|
||||
$this->addTagInputField($builder);
|
||||
if ($options['include_user']) {
|
||||
$this->addUsersChoice($builder);
|
||||
$this->addTeamsChoice($builder);
|
||||
}
|
||||
$this->addActivityMultiChoice($builder, $options, true);
|
||||
$this->addTagInputField($builder);
|
||||
$this->addExportStateChoice($builder);
|
||||
$builder->add('invoiceDate', DatePickerType::class, [
|
||||
'required' => true,
|
||||
]);
|
||||
$this->addTemplateChoice($builder);
|
||||
}
|
||||
|
||||
protected function addTemplateChoice(FormBuilderInterface $builder): void
|
||||
|
||||
@@ -45,14 +45,6 @@ use Symfony\Component\Form\FormEvents;
|
||||
*/
|
||||
trait ToolbarFormTrait
|
||||
{
|
||||
protected function addUserChoice(FormBuilderInterface $builder): void
|
||||
{
|
||||
$builder->add('user', UserType::class, [
|
||||
'label' => 'user',
|
||||
'required' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addUsersChoice(FormBuilderInterface $builder, string $field = 'users', array $options = []): void
|
||||
{
|
||||
$builder->add($field, UserType::class, array_merge([
|
||||
@@ -67,14 +59,6 @@ trait ToolbarFormTrait
|
||||
], $options));
|
||||
}
|
||||
|
||||
protected function addTeamChoice(FormBuilderInterface $builder): void
|
||||
{
|
||||
$builder->add('team', TeamType::class, [
|
||||
'label' => 'team',
|
||||
'required' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addTeamsChoice(FormBuilderInterface $builder, string $field = 'teams', array $options = []): void
|
||||
{
|
||||
$builder->add($field, TeamType::class, array_merge([
|
||||
@@ -89,11 +73,6 @@ trait ToolbarFormTrait
|
||||
], $options));
|
||||
}
|
||||
|
||||
protected function addCustomerChoice(FormBuilderInterface $builder, array $options = [], bool $multiProject = false): void
|
||||
{
|
||||
$this->addCustomerSelect($builder, $options, false, $multiProject);
|
||||
}
|
||||
|
||||
protected function addCustomerMultiChoice(FormBuilderInterface $builder, array $options = [], bool $multiProject = false): void
|
||||
{
|
||||
$this->addCustomerSelect($builder, $options, true, $multiProject);
|
||||
@@ -190,16 +169,6 @@ trait ToolbarFormTrait
|
||||
$builder->add('daterange', DateRangeType::class, $params);
|
||||
}
|
||||
|
||||
protected function addDateRangeChoice(FormBuilderInterface $builder, $allowEmpty = true, $required = false): void
|
||||
{
|
||||
$this->addDateRange($builder, [], $allowEmpty, $required);
|
||||
}
|
||||
|
||||
protected function addProjectChoice(FormBuilderInterface $builder, array $options = [], bool $multiCustomer = false, bool $multiActivity = false): void
|
||||
{
|
||||
$this->addProjectSelect($builder, $options, false, $multiCustomer, $multiActivity);
|
||||
}
|
||||
|
||||
protected function addProjectMultiChoice(FormBuilderInterface $builder, array $options = [], bool $multiCustomer = false, bool $multiActivity = false): void
|
||||
{
|
||||
$this->addProjectSelect($builder, $options, true, $multiCustomer, $multiActivity);
|
||||
@@ -271,46 +240,45 @@ trait ToolbarFormTrait
|
||||
);
|
||||
}
|
||||
|
||||
protected function addActivityChoice(FormBuilderInterface $builder, array $options = [], bool $multiProject = false): void
|
||||
{
|
||||
$this->addActivitySelect($builder, $options, false, $multiProject);
|
||||
}
|
||||
|
||||
protected function addActivityMultiChoice(FormBuilderInterface $builder, array $options = [], bool $multiProject = false): void
|
||||
{
|
||||
$this->addActivitySelect($builder, $options, true, $multiProject);
|
||||
}
|
||||
|
||||
private function addActivitySelect(FormBuilderInterface $builder, array $options = [], bool $multiActivity = false, bool $multiProject = false): void
|
||||
private function addActivitySelect(FormBuilderInterface $builder, array $options = [], bool $multiActivity = false, bool $multiProject = false, bool $autoFill = true): void
|
||||
{
|
||||
$name = 'activity';
|
||||
if ($multiActivity) {
|
||||
$name = 'activities';
|
||||
}
|
||||
$name = $multiActivity ? 'activities' : 'activity';
|
||||
|
||||
// just a fake field for having this field at the right position in the frontend
|
||||
$builder->add($name, ActivityType::class, [
|
||||
$activityOptions = [
|
||||
'required' => false,
|
||||
'documentation' => [
|
||||
'type' => 'array',
|
||||
'items' => ['type' => 'integer', 'description' => 'Activity ID'],
|
||||
'description' => 'Array of activity IDs',
|
||||
],
|
||||
'choices' => [],
|
||||
'multiple' => $multiActivity,
|
||||
]);
|
||||
];
|
||||
|
||||
if (!$autoFill) {
|
||||
$activityOptions['attr'] = [
|
||||
'data-autoselect' => 'false'
|
||||
];
|
||||
}
|
||||
|
||||
// just a fake field for having this field at the right position in the frontend
|
||||
$builder->add($name, ActivityType::class, array_merge($activityOptions, [
|
||||
'choices' => [],
|
||||
]));
|
||||
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($name, $multiActivity, $multiProject) {
|
||||
function (FormEvent $event) use ($name, $multiProject, $activityOptions) {
|
||||
/** @var array<string, mixed> $data */
|
||||
$data = $event->getData();
|
||||
$event->getForm()->add($name, ActivityType::class, [
|
||||
'multiple' => $multiActivity,
|
||||
'required' => false,
|
||||
'query_builder' => function (ActivityRepository $repo) use ($data, $multiActivity, $multiProject) {
|
||||
$event->getForm()->add($name, ActivityType::class, array_merge($activityOptions, [
|
||||
'query_builder' => function (ActivityRepository $repo) use ($name, $data, $multiProject) {
|
||||
$query = new ActivityFormTypeQuery();
|
||||
|
||||
$name = $multiActivity ? 'activities' : 'activity';
|
||||
if (\array_key_exists($name, $data) && $data[$name] !== null && $data[$name] !== '') {
|
||||
// we need to pre-fetch the activities to see if they are global, see ActivityFormTypeQuery::isGlobalsOnly()
|
||||
$activities = \is_array($data[$name]) ? $data[$name] : [$data[$name]];
|
||||
@@ -323,9 +291,9 @@ trait ToolbarFormTrait
|
||||
}
|
||||
}
|
||||
|
||||
$name = $multiProject ? 'projects' : 'project';
|
||||
if (\array_key_exists($name, $data) && $data[$name] !== null && $data[$name] !== '') {
|
||||
$projects = \is_array($data[$name]) ? $data[$name] : [$data[$name]];
|
||||
$projectName = $multiProject ? 'projects' : 'project';
|
||||
if (\array_key_exists($projectName, $data) && $data[$projectName] !== null && $data[$projectName] !== '') {
|
||||
$projects = \is_array($data[$projectName]) ? $data[$projectName] : [$data[$projectName]];
|
||||
foreach ($projects as $project) {
|
||||
$project = \is_string($project) ? (int) $project : $project;
|
||||
if (!\is_int($project) && !($project instanceof Project)) {
|
||||
@@ -337,7 +305,7 @@ trait ToolbarFormTrait
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
},
|
||||
]);
|
||||
]));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ final class DateRangeType extends AbstractType
|
||||
$factory = DateTimeFactory::createByUser($user);
|
||||
|
||||
$view->vars['ranges'] = [
|
||||
'today' => [$factory->createDateTime('00:00:00'), $factory->createDateTime('23:59:59')],
|
||||
'yesterday' => [$factory->createDateTime('-1 day 00:00:00'), $factory->createDateTime('-1 day 23:59:59')],
|
||||
'thisWeek' => [$factory->getStartOfWeek(), $factory->getEndOfWeek()],
|
||||
'lastWeek' => [$factory->getStartOfWeek('-1 week'), $factory->getEndOfWeek('-1 week')],
|
||||
|
||||
@@ -27,7 +27,7 @@ final class MetaFieldsCollectionType extends AbstractType
|
||||
{
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SET_DATA,
|
||||
function (FormEvent $event) {
|
||||
function (FormEvent $event) use ($options) {
|
||||
/** @var ArrayCollection<MetaTableTypeInterface> $collection */
|
||||
$collection = $event->getData();
|
||||
foreach ($collection as $collectionItem) {
|
||||
@@ -42,6 +42,11 @@ final class MetaFieldsCollectionType extends AbstractType
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($options['fields_required'] !== null) {
|
||||
// TODO required select-fields can receive an empty value
|
||||
$collectionItem->setIsRequired((bool) $options['fields_required']);
|
||||
}
|
||||
|
||||
$collection->set($collectionItem->getName(), $collectionItem);
|
||||
}
|
||||
},
|
||||
@@ -57,8 +62,11 @@ final class MetaFieldsCollectionType extends AbstractType
|
||||
'entry_options' => ['label' => false],
|
||||
'allow_add' => false,
|
||||
'allow_delete' => false,
|
||||
'fields_required' => null,
|
||||
'label' => false,
|
||||
]);
|
||||
|
||||
$resolver->setAllowedTypes('fields_required', ['null', 'bool']);
|
||||
}
|
||||
|
||||
public function getParent(): string
|
||||
|
||||
@@ -532,10 +532,6 @@ final class ServiceInvoice
|
||||
$model->addEntries($settings['entries']);
|
||||
$this->prepareModelQueryDates($model);
|
||||
|
||||
if ($model->getCalculator()->getTotal() < 0.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$models[] = $model;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,11 +48,12 @@ final class DurationFixedBeginMode implements TrackingModeInterface
|
||||
$timesheet->setBegin(new DateTime('now', $this->getTimezone($timesheet)));
|
||||
}
|
||||
|
||||
$newBegin = clone $timesheet->getBegin();
|
||||
/** @var DateTime $newBegin */
|
||||
$newBegin = clone $timesheet->getBegin(); // @phpstan-ignore-line
|
||||
|
||||
// this prevents the problem that "now" is being ignored in modify()
|
||||
$beginTime = (new DateTime($this->configuration->getTimesheetDefaultBeginTime(), $newBegin->getTimezone()))->format('H:i:s');
|
||||
$newBegin->modify($beginTime);
|
||||
$beginTime = new DateTime($this->configuration->getTimesheetDefaultBeginTime(), $newBegin->getTimezone());
|
||||
$newBegin->setTime((int) $beginTime->format('H'), (int) $beginTime->format('i'), 0, 0);
|
||||
|
||||
$timesheet->setBegin($newBegin);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
<th>
|
||||
{{ 'user'|trans }}
|
||||
</th>
|
||||
<th>
|
||||
<th class="text-end">
|
||||
{{ 'hourlyRate'|trans }}
|
||||
</th>
|
||||
<th class="d-none d-sm-table-cell">
|
||||
<th class="d-none d-sm-table-cell text-end">
|
||||
{{ 'internalRate'|trans }}
|
||||
</th>
|
||||
<th>
|
||||
<th class="text-center">
|
||||
{{ 'fixedRate'|trans }}
|
||||
</th>
|
||||
<th class="actions"></th>
|
||||
@@ -40,13 +40,17 @@
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<td class="text-end">
|
||||
{{ rate.rate|money(currency) }}
|
||||
</td>
|
||||
<td class="d-none d-sm-table-cell">
|
||||
{{ rate.internalRate|money(currency) }}
|
||||
<td class="d-none d-sm-table-cell text-end">
|
||||
{% if rate.internalRate is not null %}
|
||||
{{ rate.internalRate|money(currency) }}
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<td class="text-center">
|
||||
{{ widgets.label_boolean(rate.fixed) }}
|
||||
</td>
|
||||
<td class="actions">
|
||||
|
||||
@@ -1,3 +1,35 @@
|
||||
{# added for the team project form, to show divider for the customer name between all projects #}
|
||||
{% block choice_widget_expanded -%}
|
||||
{%- if '-inline' in label_attr.class|default('') -%}
|
||||
{%- for child in form %}
|
||||
{{- form_widget(child, {
|
||||
parent_label_class: label_attr.class|default(''),
|
||||
translation_domain: choice_translation_domain,
|
||||
}) -}}
|
||||
{% endfor -%}
|
||||
{%- else -%}
|
||||
<div {{ block('widget_container_attributes') }}>
|
||||
{% if form.vars.choices|length != form.children|length %}
|
||||
{% for name, choices in form.vars.choices %}
|
||||
<fieldset class="form-fieldset">
|
||||
<legend>{{ name }}</legend>
|
||||
{% for key, choice in choices %}
|
||||
{{- form_widget(form[key]) -}}
|
||||
{{- form_label(form[key]) -}}
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{%- for child in form %}
|
||||
{{- form_widget(child, {
|
||||
parent_label_class: label_attr.class|default(''),
|
||||
translation_domain: choice_translation_domain,
|
||||
}) -}}
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
</div>
|
||||
{%- endif -%}
|
||||
{%- endblock choice_widget_expanded %}
|
||||
|
||||
{% block quick_entry_week_row %}
|
||||
<tr{% with {attr: row_attr|merge({class: (row_attr.class|default('') ~ ' form-group qe-entry-week-row' ~ (not valid ? ' is-invalid'))|trim})} %}{{ block('attributes') }}{% endwith %}>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
{% set fallback = app.request is not null ? app.request.locale : 'en' %}
|
||||
{% set language = model.template.language|default(fallback) %}
|
||||
<html lang="{{ language }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<title>{% block title %}{{ model.invoiceNumber }}-{{ model.customer.company|default(model.customer.name)|u.snake }}{% endblock %}</title>
|
||||
<style type="text/css">
|
||||
{{ encore_entry_css_source('invoice')|raw }}
|
||||
</style>
|
||||
</head>
|
||||
<body class="invoice_print">
|
||||
<div class="wrapper">
|
||||
<section class="invoice">
|
||||
{% block invoice %}{% endblock %}
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,148 +1,166 @@
|
||||
{% extends 'invoice/layout.html.twig' %}
|
||||
|
||||
{% block invoice %}
|
||||
<!DOCTYPE html>
|
||||
{% set fallback = app.request is not null ? app.request.locale : 'en' %}
|
||||
{% set language = model.template.language|default(fallback) %}
|
||||
{% set isDecimal = true %}
|
||||
{% set currency = model.currency %}
|
||||
{% set project = model.query.project %}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h2 class="page-header">
|
||||
<span contenteditable="true">{{ model.template.title }}</span>
|
||||
<small class="pull-right">{{ 'date'|trans }}: {{ model.invoiceDate|date_short }}</small>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<html lang="{{ language }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<title>{% block title %}{{ model.invoiceNumber }}-{{ model.customer.company|default(model.customer.name)|u.snake }}{% endblock %}</title>
|
||||
<style type="text/css">
|
||||
{{ encore_entry_css_source('invoice')|raw }}
|
||||
</style>
|
||||
</head>
|
||||
<body class="invoice_print">
|
||||
<div class="wrapper">
|
||||
<section class="invoice">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-5">
|
||||
{{ 'invoice.to'|trans }}
|
||||
<address contenteditable="true">
|
||||
<strong>{{ model.customer.company|default(model.customer.name) }}</strong><br>
|
||||
{{ model.customer.address|nl2br }}
|
||||
{% if model.customer.vatId is not empty %}
|
||||
<br>
|
||||
{{ 'vat_id'|trans }}: {{ model.customer.vatId }}
|
||||
{% endif %}
|
||||
{% if model.customer.number is not empty %}
|
||||
<br>
|
||||
{{ 'number'|trans }}: {{ model.customer.number }}
|
||||
{% endif %}
|
||||
{% if project is not null and project.orderNumber is not empty %}
|
||||
<br>
|
||||
{{ 'orderNumber'|trans }}: {{ project.orderNumber }}
|
||||
{% endif %}
|
||||
</address>
|
||||
</div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-5">
|
||||
{{ 'invoice.from'|trans }}
|
||||
<address contenteditable="true">
|
||||
<strong>{{ model.template.company }}</strong><br>
|
||||
{{ model.template.address|trim|nl2br }}
|
||||
{% if model.template.vatId is not empty %}
|
||||
<br>
|
||||
{{ 'vat_id'|trans }}:
|
||||
{{ model.template.vatId }}
|
||||
{% endif %}
|
||||
</address>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-5">
|
||||
<p contenteditable="true">
|
||||
<strong>{{ 'invoice.number'|trans }}:</strong>
|
||||
{{ model.invoiceNumber }}
|
||||
|
||||
<br>
|
||||
<strong>{{ 'invoice.due_days'|trans }}:</strong>
|
||||
{{ model.dueDate|date_short }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-sm-7"></div>
|
||||
</div>
|
||||
|
||||
<div class="row invoice-items mt-2 mb-3">
|
||||
<div class="col-xs-12 table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'date'|trans }}</th>
|
||||
<th>{{ 'description'|trans }}</th>
|
||||
<th class="text-end">{{ 'unit_price'|trans }}</th>
|
||||
<th class="text-end">{{ 'amount'|trans }}</th>
|
||||
<th class="text-end">{{ 'total_rate'|trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in model.calculator.entries %}
|
||||
{% set duration = entry.duration|duration(isDecimal) %}
|
||||
{% if entry.fixedRate %}
|
||||
{% set rate = entry.fixedRate %}
|
||||
{% set duration = entry.amount|amount %}
|
||||
{% else %}
|
||||
{% set rate = entry.hourlyRate %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td nowrap class="text-nowrap">{{ entry.begin|date_short }}</td>
|
||||
<td contenteditable="true">
|
||||
{% if entry.description is not empty %}
|
||||
{{ entry.description|nl2br }}
|
||||
{% else %}
|
||||
{% if entry.activity is not null %}{{ entry.activity.name }} / {% endif %}{{ entry.project.name }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td nowrap class="text-nowrap text-end">{{ rate|money(currency) }}</td>
|
||||
<td nowrap class="text-nowrap text-end">{{ duration }}</td>
|
||||
<td nowrap class="text-nowrap text-end">{{ entry.rate|money(currency) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
{% if model.calculator.tax > 0 or not model.isHideZeroTax() %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-end">
|
||||
{{ 'invoice.subtotal'|trans }}
|
||||
</td>
|
||||
<td class="text-end">{{ model.calculator.subtotal|money(currency) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" class="text-end">
|
||||
{{ 'invoice.tax'|trans }} ({{ model.calculator.vat }}%)
|
||||
</td>
|
||||
<td class="text-end">{{ model.calculator.tax|money(currency) }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-end text-nowrap">
|
||||
<strong>{{ 'invoice.total'|trans }}</strong>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<strong>{{ model.calculator.total|money(currency) }}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
{% if model.template.paymentTerms is not empty %}
|
||||
<div contenteditable="true" class="paymentTerms">
|
||||
{{ model.template.paymentTerms|md2html }}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h2 class="page-header">
|
||||
<span contenteditable="true">{{ model.template.title }}</span>
|
||||
<small class="pull-right">{{ 'date'|trans }}: {{ model.invoiceDate|date_short }}</small>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="footer">
|
||||
<p>
|
||||
<strong>{{ 'address'|trans }}</strong>: {{ model.template.company }} – {{ model.template.address|nl2str(' – ') }}
|
||||
<br>
|
||||
<strong>{{ 'invoice_bank_account'|trans }}</strong>: {{ model.template.paymentDetails|nl2str(' – ') }}
|
||||
<br>
|
||||
<strong>{{ 'contact'|trans }}</strong>: {{ model.template.contact|nl2str(' – ') }}
|
||||
</p>
|
||||
</footer>
|
||||
{% endblock %}
|
||||
<div class="row">
|
||||
<div class="col-sm-5">
|
||||
{{ 'invoice.to'|trans }}
|
||||
<address contenteditable="true">
|
||||
<strong>{{ model.customer.company|default(model.customer.name) }}</strong><br>
|
||||
{{ model.customer.address|nl2br }}
|
||||
{% if model.customer.vatId is not empty %}
|
||||
<br>
|
||||
{{ 'vat_id'|trans }}: {{ model.customer.vatId }}
|
||||
{% endif %}
|
||||
{% if model.customer.number is not empty %}
|
||||
<br>
|
||||
{{ 'number'|trans }}: {{ model.customer.number }}
|
||||
{% endif %}
|
||||
{% if project is not null and project.orderNumber is not empty %}
|
||||
<br>
|
||||
{{ 'orderNumber'|trans }}: {{ project.orderNumber }}
|
||||
{% endif %}
|
||||
</address>
|
||||
</div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-5">
|
||||
{{ 'invoice.from'|trans }}
|
||||
<address contenteditable="true">
|
||||
<strong>{{ model.template.company }}</strong><br>
|
||||
{{ model.template.address|trim|nl2br }}
|
||||
{% if model.template.vatId is not empty %}
|
||||
<br>
|
||||
{{ 'vat_id'|trans }}:
|
||||
{{ model.template.vatId }}
|
||||
{% endif %}
|
||||
</address>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-5">
|
||||
<p contenteditable="true">
|
||||
<strong>{{ 'invoice.number'|trans }}:</strong>
|
||||
{{ model.invoiceNumber }}
|
||||
|
||||
<br>
|
||||
<strong>{{ 'invoice.due_days'|trans }}:</strong>
|
||||
{{ model.dueDate|date_short }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-sm-7"></div>
|
||||
</div>
|
||||
|
||||
<div class="row invoice-items mt-2 mb-3">
|
||||
<div class="col-xs-12 table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'date'|trans }}</th>
|
||||
<th>{{ 'description'|trans }}</th>
|
||||
<th class="text-end">{{ 'unit_price'|trans }}</th>
|
||||
<th class="text-end">{{ 'amount'|trans }}</th>
|
||||
<th class="text-end">{{ 'total_rate'|trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in model.calculator.entries %}
|
||||
{% set duration = entry.duration|duration(isDecimal) %}
|
||||
{% if entry.fixedRate %}
|
||||
{% set rate = entry.fixedRate %}
|
||||
{% set duration = entry.amount|amount %}
|
||||
{% else %}
|
||||
{% set rate = entry.hourlyRate %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td nowrap class="text-nowrap">{{ entry.begin|date_short }}</td>
|
||||
<td contenteditable="true">
|
||||
{% if entry.description is not empty %}
|
||||
{{ entry.description|nl2br }}
|
||||
{% else %}
|
||||
{% if entry.activity is not null %}{{ entry.activity.name }} / {% endif %}{{ entry.project.name }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td nowrap class="text-nowrap text-end">{{ rate|money(currency) }}</td>
|
||||
<td nowrap class="text-nowrap text-end">{{ duration }}</td>
|
||||
<td nowrap class="text-nowrap text-end">{{ entry.rate|money(currency) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
{% if model.calculator.tax > 0 or not model.isHideZeroTax() %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-end">
|
||||
{{ 'invoice.subtotal'|trans }}
|
||||
</td>
|
||||
<td class="text-end">{{ model.calculator.subtotal|money(currency) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" class="text-end">
|
||||
{{ 'invoice.tax'|trans }} ({{ model.calculator.vat }}%)
|
||||
</td>
|
||||
<td class="text-end">{{ model.calculator.tax|money(currency) }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-end text-nowrap">
|
||||
<strong>{{ 'invoice.total'|trans }}</strong>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<strong>{{ model.calculator.total|money(currency) }}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
{% if model.template.paymentTerms is not empty %}
|
||||
<div contenteditable="true" class="paymentTerms">
|
||||
{{ model.template.paymentTerms|md2html }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="footer">
|
||||
<p>
|
||||
<strong>{{ 'address'|trans }}</strong>: {{ model.template.company }} – {{ model.template.address|nl2str(' – ') }}
|
||||
<br>
|
||||
<strong>{{ 'invoice_bank_account'|trans }}</strong>: {{ model.template.paymentDetails|nl2str(' – ') }}
|
||||
<br>
|
||||
<strong>{{ 'contact'|trans }}</strong>: {{ model.template.contact|nl2str(' – ') }}
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,21 +7,93 @@
|
||||
{% include 'team/member-form.html.twig' %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{% set formEditTemplate = kimai_context.modalRequest ? 'default/_form_modal.html.twig' : 'default/_form.html.twig' %}
|
||||
|
||||
{% if customerForm is defined and customerForm is not null %}
|
||||
{{ include(formEditTemplate, {
|
||||
'title': 'teams.customer_access'|trans({}, 'teams'),
|
||||
'form': customerForm,
|
||||
}) }}
|
||||
{% embed '@theme/embeds/card.html.twig' with {collapsible: true, collapsed: (team.customers|length == 0)} %}
|
||||
{% from "macros/status.html.twig" import status_count %}
|
||||
{% block box_title %}
|
||||
{{ 'teams.customer_access'|trans({}, 'teams') }}
|
||||
{{ status_count(team.customers|length) }}
|
||||
{% endblock %}
|
||||
{% block box_body %}
|
||||
{{ form(customerForm) }}
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
{% endif %}
|
||||
|
||||
{% if projectForm is defined and projectForm is not null %}
|
||||
{{ include(formEditTemplate, {
|
||||
'title': 'teams.project_access'|trans({}, 'teams'),
|
||||
'form': projectForm,
|
||||
}) }}
|
||||
{% embed '@theme/embeds/card.html.twig' with {collapsible: true, collapsed: (team.projects|length == 0)} %}
|
||||
{% from "macros/status.html.twig" import status_count %}
|
||||
{% block box_title %}
|
||||
{{ 'teams.project_access'|trans({}, 'teams') }}
|
||||
{{ status_count(team.projects|length) }}
|
||||
{% endblock %}
|
||||
{% block box_body %}
|
||||
{{ form(projectForm) }}
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{{ parent() }}
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('kimai.initialized', (event) => {
|
||||
/** @type {KimaiAPI} API */
|
||||
const API = event.detail.kimai.getPlugin('api');
|
||||
/** @type {KimaiAlert} ALERT */
|
||||
const ALERT = event.detail.kimai.getPlugin('alert');
|
||||
|
||||
{% if customerForm is defined and customerForm is not null %}
|
||||
document.getElementById('team_customer_form').addEventListener('change',
|
||||
(event) => {
|
||||
if (event.target.matches('input[type=checkbox]')) {
|
||||
const checkbox = event.target;
|
||||
const customerId = checkbox.value;
|
||||
if (checkbox.checked) {
|
||||
API.post(
|
||||
'{{ path('post_team_customer', {'id': team.id, 'customerId': '000'}) }}'.replace(/000/, customerId),
|
||||
{},
|
||||
(json) => {ALERT.success('action.update.success');},
|
||||
(error) => {ALERT.error('action.update.error', error);}, // TODO test me
|
||||
);
|
||||
} else {
|
||||
API.delete(
|
||||
'{{ path('delete_team_customer', {'id': team.id, 'customerId': '000'}) }}'.replace(/000/, customerId),
|
||||
(json) => {ALERT.success('action.delete.success');},
|
||||
(error) => {ALERT.error('action.delete.error', error);}, // TODO test me
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
{% endif %}
|
||||
|
||||
{% if projectForm is defined and customerForm is not null %}
|
||||
document.getElementById('team_project_form').addEventListener('change',
|
||||
(event) => {
|
||||
if (event.target.matches('input[type=checkbox]')) {
|
||||
const checkbox = event.target;
|
||||
const projectId = checkbox.value;
|
||||
if (checkbox.checked) {
|
||||
API.post(
|
||||
'{{ path('post_team_project', {'id': team.id, 'projectId': '000'}) }}'.replace(/000/, projectId),
|
||||
{},
|
||||
(json) => {ALERT.success('action.update.success');},
|
||||
(error) => {ALERT.error('action.update.error', error);}, // TODO test me
|
||||
);
|
||||
} else {
|
||||
API.delete(
|
||||
'{{ path('delete_team_project', {'id': team.id, 'projectId': '000'}) }}'.replace(/000/, projectId),
|
||||
(json) => {ALERT.success('action.delete.success');},
|
||||
(error) => {ALERT.error('action.delete.error', error);}, // TODO test me
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
{% endif %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -17,8 +17,16 @@
|
||||
{% endif %}
|
||||
{% if form.end_time is defined or form.duration is defined %}
|
||||
<div class="mb-3 row">
|
||||
<label class="col-form-label col-sm-2" for="{{ form.vars.name }}_duration">{{ 'duration'|trans }} / {{ 'endtime'|trans }}</label>
|
||||
{% set size = form.duration is defined ? 5 : 10 %}
|
||||
<label class="col-form-label col-sm-2" for="{{ form.vars.name }}_duration">
|
||||
{% if form.duration is defined %}
|
||||
{{ 'duration'|trans }}
|
||||
{% if form.end_time is defined %} / {% endif %}
|
||||
{% endif %}
|
||||
{% if form.end_time is defined %}
|
||||
{{ 'endtime'|trans }}
|
||||
{% endif %}
|
||||
</label>
|
||||
{% set size = form.duration is defined and form.end_time is defined ? 5 : 10 %}
|
||||
{% if form.duration is defined %}
|
||||
<div class="col-sm-{{ size }}">
|
||||
{{ form_widget(form.duration, {'label': false}) }}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
} %}
|
||||
{% embed formEditTemplate with formOptions %}
|
||||
{% block form_body %}
|
||||
<fieldset>
|
||||
<fieldset class="form-fieldset">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{{ form_row(form.customer) }}
|
||||
@@ -22,27 +22,27 @@
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<fieldset class="form-fieldset">
|
||||
{{ form_row(form.replaceTags) }}
|
||||
{{ form_row(form.tags) }}
|
||||
</fieldset>
|
||||
{% if form.user is defined %}
|
||||
<fieldset>
|
||||
<fieldset class="form-fieldset">
|
||||
{{ form_row(form.user) }}
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
{% if form.exported is defined %}
|
||||
<fieldset>
|
||||
<fieldset class="form-fieldset">
|
||||
{{ form_row(form.exported) }}
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
{% if form.billable is defined %}
|
||||
<fieldset>
|
||||
<fieldset class="form-fieldset">
|
||||
{{ form_row(form.billable) }}
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
{% if form.recalculateRates is defined %}
|
||||
<fieldset>
|
||||
<fieldset class="form-fieldset">
|
||||
{{ form_row(form.recalculateRates) }}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
@@ -55,7 +55,7 @@
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
{% if form.metaFields is defined %}
|
||||
<fieldset>
|
||||
<fieldset class="form-fieldset">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.updateMeta) }}
|
||||
@@ -97,6 +97,9 @@
|
||||
if (elAttr.indexOf('{{ form.metaFields.vars.full_name }}') !== -1) {
|
||||
{# disable all custom fields, each one has to be activated before it can be used #}
|
||||
el.setAttribute('disabled', 'disabled');
|
||||
if (el.tomselect !== undefined) {
|
||||
el.tomselect.disable();
|
||||
}
|
||||
} else if (elAttr.indexOf('{{ form.updateMeta.vars.full_name }}') !== -1) {
|
||||
el.checked = false;
|
||||
el.onclick = function() {
|
||||
@@ -117,8 +120,14 @@
|
||||
}
|
||||
if (metaCheckbox.checked) {
|
||||
current.removeAttribute('disabled');
|
||||
if (current.tomselect !== undefined) {
|
||||
current.tomselect.enable();
|
||||
}
|
||||
} else {
|
||||
current.setAttribute('disabled', 'disabled');
|
||||
if (current.tomselect !== undefined) {
|
||||
current.tomselect.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace App\Tests\API;
|
||||
use App\Entity\Team;
|
||||
use App\Entity\User;
|
||||
use App\Tests\DataFixtures\TeamFixtures;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
@@ -30,12 +31,15 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
return $this->importFixture($fixture);
|
||||
}
|
||||
|
||||
public function testIsSecure()
|
||||
public function testIsSecure(): void
|
||||
{
|
||||
$this->assertUrlIsSecured('/api/teams');
|
||||
}
|
||||
|
||||
public function getRoleTestData()
|
||||
/**
|
||||
* @return array<int, array<int, string>>
|
||||
*/
|
||||
public function getRoleTestData(): array
|
||||
{
|
||||
return [
|
||||
[User::ROLE_USER],
|
||||
@@ -46,12 +50,12 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
/**
|
||||
* @dataProvider getRoleTestData
|
||||
*/
|
||||
public function testIsSecureForRole(string $role)
|
||||
public function testIsSecureForRole(string $role): void
|
||||
{
|
||||
$this->assertUrlIsSecuredForRole($role, '/api/teams');
|
||||
}
|
||||
|
||||
public function testGetCollection()
|
||||
public function testGetCollection(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->importTeamFixtures();
|
||||
@@ -64,7 +68,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
self::assertApiResponseTypeStructure('TeamCollection', $result[0]);
|
||||
}
|
||||
|
||||
public function testGetEntity()
|
||||
public function testGetEntity(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$teams = $this->importTeamFixtures();
|
||||
@@ -77,18 +81,18 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
self::assertApiResponseTypeStructure('TeamEntity', $result);
|
||||
}
|
||||
|
||||
public function testNotFound()
|
||||
public function testNotFound(): void
|
||||
{
|
||||
$this->assertEntityNotFound(User::ROLE_USER, '/api/teams/' . PHP_INT_MAX, 'GET', 'App\\Entity\\Team object not found by the @ParamConverter annotation.');
|
||||
}
|
||||
|
||||
public function testDeleteActionWithUnknownTeam()
|
||||
public function testDeleteActionWithUnknownTeam(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->assertNotFoundForDelete($client, '/api/teams/' . PHP_INT_MAX);
|
||||
}
|
||||
|
||||
public function testPostAction()
|
||||
public function testPostAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -106,7 +110,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertNotEmpty($result['id']);
|
||||
}
|
||||
|
||||
public function testPostActionWithInvalidUser()
|
||||
public function testPostActionWithInvalidUser(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
|
||||
$data = [
|
||||
@@ -118,7 +122,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertApiResponseAccessDenied($response, 'Access denied.');
|
||||
}
|
||||
|
||||
public function testPostActionWithValidationErrors()
|
||||
public function testPostActionWithValidationErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -134,7 +138,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertApiCallValidationError($response, ['name', 'members.0.user']);
|
||||
}
|
||||
|
||||
public function testPatchAction()
|
||||
public function testPatchAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
@@ -188,7 +192,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
self::assertEquals('john_user', $result['members'][0]['user']['username']);
|
||||
}
|
||||
|
||||
public function testPatchActionWithValidationErrors()
|
||||
public function testPatchActionWithValidationErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -214,7 +218,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertApiCallValidationError($response, ['name', 'members.0.user']);
|
||||
}
|
||||
|
||||
public function testDeleteAction()
|
||||
public function testDeleteAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$teams = $this->importTeamFixtures();
|
||||
@@ -233,7 +237,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertEmpty($client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function testPostMemberAction()
|
||||
public function testPostMemberAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -256,7 +260,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
self::assertCount(2, $result['members']);
|
||||
}
|
||||
|
||||
public function testPostMemberActionErrors()
|
||||
public function testPostMemberActionErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -284,7 +288,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertBadRequest($client, '/api/teams/' . $result['id'] . '/members/5', 'POST');
|
||||
}
|
||||
|
||||
public function testDeleteMemberAction()
|
||||
public function testDeleteMemberAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -310,7 +314,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
self::assertCount(3, $result['members']);
|
||||
}
|
||||
|
||||
public function testDeleteMemberActionErrors()
|
||||
public function testDeleteMemberActionErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -343,7 +347,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertBadRequest($client, '/api/teams/' . $result['id'] . '/members/1', 'DELETE');
|
||||
}
|
||||
|
||||
public function testPostCustomerAction()
|
||||
public function testPostCustomerAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -367,7 +371,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
self::assertEquals(1, $result['customers'][0]['id']);
|
||||
}
|
||||
|
||||
public function testPostCustomerActionErrors()
|
||||
public function testPostCustomerActionErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -397,7 +401,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertBadRequest($client, '/api/teams/' . $result['id'] . '/customers/1', 'POST');
|
||||
}
|
||||
|
||||
public function testDeleteCustomerAction()
|
||||
public function testDeleteCustomerAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -427,9 +431,15 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertIsArray($result);
|
||||
self::assertApiResponseTypeStructure('TeamEntity', $result);
|
||||
self::assertCount(0, $result['customers']);
|
||||
|
||||
/** @var EntityManager $em */
|
||||
$em = $this->getEntityManager();
|
||||
$team = $em->getRepository(Team::class)->find($result['id']);
|
||||
self::assertInstanceOf(Team::class, $team);
|
||||
self::assertCount(0, $team->getCustomers());
|
||||
}
|
||||
|
||||
public function testDeleteCustomerActionErrors()
|
||||
public function testDeleteCustomerActionErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -455,7 +465,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertBadRequest($client, '/api/teams/' . $result['id'] . '/customers/1', 'DELETE');
|
||||
}
|
||||
|
||||
public function testPostProjectAction()
|
||||
public function testPostProjectAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -478,7 +488,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
self::assertEquals(1, $result['projects'][0]['id']);
|
||||
}
|
||||
|
||||
public function testPostProjectActionErrors()
|
||||
public function testPostProjectActionErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -510,7 +520,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertBadRequest($client, '/api/teams/' . $result['id'] . '/projects/1', 'POST');
|
||||
}
|
||||
|
||||
public function testDeleteProjectAction()
|
||||
public function testDeleteProjectAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -540,9 +550,15 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertIsArray($result);
|
||||
self::assertApiResponseTypeStructure('TeamEntity', $result);
|
||||
self::assertCount(0, $result['projects']);
|
||||
|
||||
/** @var EntityManager $em */
|
||||
$em = $this->getEntityManager();
|
||||
$team = $em->getRepository(Team::class)->find($result['id']);
|
||||
self::assertInstanceOf(Team::class, $team);
|
||||
self::assertCount(0, $team->getProjects());
|
||||
}
|
||||
|
||||
public function testDeleteProjectActionErrors()
|
||||
public function testDeleteProjectActionErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -568,7 +584,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertBadRequest($client, '/api/teams/' . $result['id'] . '/projects/1', 'DELETE');
|
||||
}
|
||||
|
||||
public function testPostActivityAction()
|
||||
public function testPostActivityAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -591,7 +607,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
self::assertEquals(1, $result['activities'][0]['id']);
|
||||
}
|
||||
|
||||
public function testPostActivityActionErrors()
|
||||
public function testPostActivityActionErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -621,7 +637,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
$this->assertBadRequest($client, '/api/teams/' . $result['id'] . '/activities/1', 'POST');
|
||||
}
|
||||
|
||||
public function testDeleteActivityAction()
|
||||
public function testDeleteActivityAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
@@ -653,7 +669,7 @@ class TeamControllerTest extends APIControllerBaseTest
|
||||
self::assertCount(0, $result['activities']);
|
||||
}
|
||||
|
||||
public function testDeleteActivityActionErrors()
|
||||
public function testDeleteActivityActionErrors(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
|
||||
@@ -48,7 +48,7 @@ class SecurityControllerTest extends ControllerBaseTest
|
||||
$this->assertStringContainsString('<form action="/en/login_check" method="post"', $content);
|
||||
$this->assertStringContainsString('<input type="text" id="username" name="_username"', $content);
|
||||
$this->assertStringContainsString('<input id="password" name="_password" type="password"', $content);
|
||||
$this->assertStringContainsString('">Login</button>', $content);
|
||||
$this->assertStringContainsString('">Log in</button>', $content);
|
||||
$this->assertStringContainsString('<input type="hidden" name="_csrf_token" value="', $content);
|
||||
$this->assertStringNotContainsString('<a href="/en/register/"', $content);
|
||||
$this->assertStringNotContainsString('Register a new account', $content);
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace App\Tests\Controller;
|
||||
use App\Entity\Team;
|
||||
use App\Entity\User;
|
||||
use App\Tests\DataFixtures\TeamFixtures;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Symfony\Component\DomCrawler\Field\ChoiceFormField;
|
||||
use Symfony\Component\HttpKernel\HttpKernelBrowser;
|
||||
|
||||
/**
|
||||
@@ -21,17 +19,17 @@ use Symfony\Component\HttpKernel\HttpKernelBrowser;
|
||||
*/
|
||||
class TeamControllerTest extends ControllerBaseTest
|
||||
{
|
||||
public function testIsSecure()
|
||||
public function testIsSecure(): void
|
||||
{
|
||||
$this->assertUrlIsSecured('/admin/teams/');
|
||||
}
|
||||
|
||||
public function testIsSecureForRole()
|
||||
public function testIsSecureForRole(): void
|
||||
{
|
||||
$this->assertUrlIsSecuredForRole(User::ROLE_TEAMLEAD, '/admin/teams/');
|
||||
}
|
||||
|
||||
public function testIndexAction()
|
||||
public function testIndexAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$em = $this->getEntityManager();
|
||||
@@ -47,7 +45,7 @@ class TeamControllerTest extends ControllerBaseTest
|
||||
$this->assertDataTableRowCount($client, 'datatable_admin_teams', 6);
|
||||
}
|
||||
|
||||
public function testIndexActionWithSearchTermQuery()
|
||||
public function testIndexActionWithSearchTermQuery(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$fixture = new TeamFixtures();
|
||||
@@ -69,7 +67,7 @@ class TeamControllerTest extends ControllerBaseTest
|
||||
$this->assertDataTableRowCount($client, 'datatable_admin_teams', 5);
|
||||
}
|
||||
|
||||
public function testCreateAction()
|
||||
public function testCreateAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/admin/teams/create');
|
||||
@@ -90,7 +88,7 @@ class TeamControllerTest extends ControllerBaseTest
|
||||
$this->assertHasCustomerAndProjectPermissionBoxes($client);
|
||||
}
|
||||
|
||||
protected function assertHasCustomerAndProjectPermissionBoxes(HttpKernelBrowser $client)
|
||||
protected function assertHasCustomerAndProjectPermissionBoxes(HttpKernelBrowser $client): void
|
||||
{
|
||||
$content = $client->getResponse()->getContent();
|
||||
$this->assertStringContainsString('Grant access to customers', $content);
|
||||
@@ -99,7 +97,7 @@ class TeamControllerTest extends ControllerBaseTest
|
||||
$this->assertEquals(1, $client->getCrawler()->filter('form[name=team_project_form]')->count());
|
||||
}
|
||||
|
||||
public function testEditAction()
|
||||
public function testEditAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
@@ -121,11 +119,10 @@ class TeamControllerTest extends ControllerBaseTest
|
||||
$this->assertEquals('Test Team 2', $editForm->get('team_edit_form[name]')->getValue());
|
||||
}
|
||||
|
||||
public function testEditMemberAction()
|
||||
public function testEditMemberAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
$em = $this->getEntityManager();
|
||||
$fixture = new TeamFixtures();
|
||||
$fixture->setAmount(2);
|
||||
$this->importFixture($fixture);
|
||||
@@ -143,65 +140,7 @@ class TeamControllerTest extends ControllerBaseTest
|
||||
$this->assertEquals('Test Team 2', $editForm->get('team_edit_form[name]')->getValue());
|
||||
}
|
||||
|
||||
public function testEditCustomerAccessAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
/** @var EntityManager $em */
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$fixture = new TeamFixtures();
|
||||
$fixture->setAmount(2);
|
||||
$fixture->setAddCustomer(false);
|
||||
$this->importFixture($fixture);
|
||||
|
||||
$team = $em->getRepository(Team::class)->find(1);
|
||||
self::assertEquals(0, \count($team->getCustomers()));
|
||||
|
||||
$this->assertAccessIsGranted($client, '/admin/teams/1/edit');
|
||||
$form = $client->getCrawler()->filter('form[name=team_customer_form]')->form();
|
||||
|
||||
/** @var ChoiceFormField $customer */
|
||||
$customer = $form->get('team_customer_form[customers][0]');
|
||||
$customer->tick();
|
||||
|
||||
$client->submit($form);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/teams/1/edit'));
|
||||
|
||||
$team = $em->getRepository(Team::class)->find(1);
|
||||
self::assertEquals(1, \count($team->getCustomers()));
|
||||
}
|
||||
|
||||
public function testEditProjectAccessAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
/** @var EntityManager $em */
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$fixture = new TeamFixtures();
|
||||
$fixture->setAmount(2);
|
||||
$fixture->setAddCustomer(false);
|
||||
$this->importFixture($fixture);
|
||||
|
||||
$team = $em->getRepository(Team::class)->find(1);
|
||||
self::assertEquals(0, \count($team->getProjects()));
|
||||
|
||||
$this->assertAccessIsGranted($client, '/admin/teams/1/edit');
|
||||
$form = $client->getCrawler()->filter('form[name=team_project_form]')->form();
|
||||
|
||||
/** @var ChoiceFormField $customer */
|
||||
$customer = $form->get('team_project_form[projects]');
|
||||
$customer->select([1]);
|
||||
|
||||
$client->submit($form);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/teams/1/edit'));
|
||||
|
||||
$team = $em->getRepository(Team::class)->find(1);
|
||||
self::assertEquals(1, \count($team->getProjects()));
|
||||
}
|
||||
|
||||
public function testDuplicateAction()
|
||||
public function testDuplicateAction(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Invoice\Calculator\DefaultCalculator;
|
||||
use App\Invoice\InvoiceItemRepositoryInterface;
|
||||
use App\Invoice\InvoiceModel;
|
||||
use App\Invoice\NumberGenerator\DateNumberGenerator;
|
||||
use App\Invoice\Renderer\TwigRenderer;
|
||||
use App\Invoice\ServiceInvoice;
|
||||
@@ -52,7 +53,7 @@ class ServiceInvoiceTest extends TestCase
|
||||
return new ServiceInvoice($repo, new FileHelper(realpath(__DIR__ . '/../../var/data/')), $invoiceRepo, $formattings, (new InvoiceModelFactoryFactory($this))->create());
|
||||
}
|
||||
|
||||
public function testInvalidExceptionOnChangeState()
|
||||
public function testInvalidExceptionOnChangeState(): void
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Unknown invoice status');
|
||||
@@ -60,7 +61,7 @@ class ServiceInvoiceTest extends TestCase
|
||||
$sut->changeInvoiceStatus(new Invoice(), 'foo');
|
||||
}
|
||||
|
||||
public function testEmptyObject()
|
||||
public function testEmptyObject(): void
|
||||
{
|
||||
$sut = $this->getSut([]);
|
||||
|
||||
@@ -78,7 +79,7 @@ class ServiceInvoiceTest extends TestCase
|
||||
$this->assertNull($sut->getNumberGeneratorByName('default'));
|
||||
}
|
||||
|
||||
public function testWithDocumentDirectory()
|
||||
public function testWithDocumentDirectory(): void
|
||||
{
|
||||
$sut = $this->getSut(['templates/invoice/renderer/']);
|
||||
|
||||
@@ -92,7 +93,7 @@ class ServiceInvoiceTest extends TestCase
|
||||
$this->assertInstanceOf(InvoiceDocument::class, $actual);
|
||||
}
|
||||
|
||||
public function testAdd()
|
||||
public function testAdd(): void
|
||||
{
|
||||
$sut = $this->getSut([]);
|
||||
|
||||
@@ -110,7 +111,7 @@ class ServiceInvoiceTest extends TestCase
|
||||
$this->assertEquals(1, \count($sut->getRenderer()));
|
||||
}
|
||||
|
||||
public function testCreateModelThrowsOnMissingTemplate()
|
||||
public function testCreateModelThrowsOnMissingTemplate(): void
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
$this->expectExceptionMessage('Cannot create invoice model without template');
|
||||
@@ -122,7 +123,7 @@ class ServiceInvoiceTest extends TestCase
|
||||
$sut->createModel($query);
|
||||
}
|
||||
|
||||
public function testCreateModelUsesTemplateLanguage()
|
||||
public function testCreateModelUsesTemplateLanguage(): void
|
||||
{
|
||||
$template = new InvoiceTemplate();
|
||||
$template->setNumberGenerator('date');
|
||||
@@ -141,7 +142,7 @@ class ServiceInvoiceTest extends TestCase
|
||||
self::assertEquals('it', $model->getTemplate()->getLanguage());
|
||||
}
|
||||
|
||||
public function testBeginAndEndDateFallback()
|
||||
public function testBeginAndEndDateFallback(): void
|
||||
{
|
||||
$timezone = new \DateTimeZone('Europe/Vienna');
|
||||
$customer = new Customer('foo');
|
||||
@@ -207,7 +208,7 @@ class ServiceInvoiceTest extends TestCase
|
||||
self::assertEquals('2020-11-27T23:59:59+0100', $query->getEnd()->format(DATE_ISO8601));
|
||||
}
|
||||
|
||||
public function testCreateModelsSkipsModelsWithNegativeTotal()
|
||||
public function testCreateModelsIncludesModelsWithNegativeTotal(): void
|
||||
{
|
||||
$timezone = new \DateTimeZone('Europe/Vienna');
|
||||
|
||||
@@ -310,12 +311,18 @@ class ServiceInvoiceTest extends TestCase
|
||||
$sut->addInvoiceItemRepository($repo);
|
||||
$models = $sut->createModels($query);
|
||||
|
||||
self::assertCount(2, $models);
|
||||
self::assertEquals(1.73, $models[0]->getCalculator()->getTotal());
|
||||
self::assertEquals(0.0, $models[1]->getCalculator()->getTotal());
|
||||
self::assertCount(4, $models);
|
||||
self::assertInstanceOf(InvoiceModel::class, $models[0]);
|
||||
self::assertEquals(-0.01, $models[0]->getCalculator()->getTotal());
|
||||
self::assertInstanceOf(InvoiceModel::class, $models[1]);
|
||||
self::assertEquals(-100, $models[1]->getCalculator()->getTotal());
|
||||
self::assertInstanceOf(InvoiceModel::class, $models[2]);
|
||||
self::assertEquals(1.73, $models[2]->getCalculator()->getTotal());
|
||||
self::assertInstanceOf(InvoiceModel::class, $models[3]);
|
||||
self::assertEquals(0.0, $models[3]->getCalculator()->getTotal());
|
||||
}
|
||||
|
||||
private function getNumberGeneratorSut()
|
||||
private function getNumberGeneratorSut(): DateNumberGenerator
|
||||
{
|
||||
$repository = $this->createMock(InvoiceRepository::class);
|
||||
$repository
|
||||
|
||||
@@ -1202,151 +1202,6 @@ parameters:
|
||||
count: 4
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:getRoleTestData\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteActionWithUnknownTeam\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteActivityAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteActivityActionErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteCustomerAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteCustomerActionErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteMemberAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteMemberActionErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteProjectAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testDeleteProjectActionErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testGetCollection\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testGetEntity\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testIsSecure\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testIsSecureForRole\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testNotFound\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPatchAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPatchActionWithValidationErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostActionWithInvalidUser\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostActionWithValidationErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostActivityAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostActivityActionErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostCustomerAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostCustomerActionErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostMemberAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostMemberActionErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostProjectAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\API\\\\TeamControllerTest\\:\\:testPostProjectActionErrors\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: API/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
|
||||
count: 38
|
||||
@@ -4222,76 +4077,11 @@ parameters:
|
||||
count: 2
|
||||
path: Controller/TagControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getCustomers\\(\\) on App\\\\Entity\\\\Team\\|null\\.$#"
|
||||
count: 2
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getProjects\\(\\) on App\\\\Entity\\\\Team\\|null\\.$#"
|
||||
count: 2
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getValue\\(\\) on array\\<array\\<Symfony\\\\Component\\\\DomCrawler\\\\Field\\\\FormField\\>\\|Symfony\\\\Component\\\\DomCrawler\\\\Field\\\\FormField\\>\\|Symfony\\\\Component\\\\DomCrawler\\\\Field\\\\FormField\\.$#"
|
||||
count: 4
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:assertHasCustomerAndProjectPermissionBoxes\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testCreateAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testDuplicateAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testEditAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testEditCustomerAccessAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testEditMemberAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testEditProjectAccessAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testIndexAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testIndexActionWithSearchTermQuery\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testIsSecure\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\TeamControllerTest\\:\\:testIsSecureForRole\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Controller/TeamControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$haystack of method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#"
|
||||
count: 2
|
||||
@@ -7859,12 +7649,7 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getTotal\\(\\) on App\\\\Invoice\\\\CalculatorInterface\\|null\\.$#"
|
||||
count: 2
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\ServiceInvoiceTest\\:\\:getNumberGeneratorSut\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
count: 4
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
@@ -7872,46 +7657,6 @@ parameters:
|
||||
count: 1
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\ServiceInvoiceTest\\:\\:testAdd\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\ServiceInvoiceTest\\:\\:testBeginAndEndDateFallback\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\ServiceInvoiceTest\\:\\:testCreateModelThrowsOnMissingTemplate\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\ServiceInvoiceTest\\:\\:testCreateModelUsesTemplateLanguage\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\ServiceInvoiceTest\\:\\:testCreateModelsSkipsModelsWithNegativeTotal\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\ServiceInvoiceTest\\:\\:testEmptyObject\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\ServiceInvoiceTest\\:\\:testInvalidExceptionOnChangeState\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\ServiceInvoiceTest\\:\\:testWithDocumentDirectory\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/ServiceInvoiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$dataDir of class App\\\\Utils\\\\FileHelper constructor expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
|
||||
Reference in New Issue
Block a user