From 68d703d1e31270b46cc2db2f19083193ac5eb159 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Wed, 8 Apr 2020 14:50:15 +0200 Subject: [PATCH] added internal rates (#1591) --- composer.lock | 1764 +++++++++++++---- config/packages/fos_rest.yaml | 2 + config/packages/nelmio_api_doc.yaml | 11 +- config/serializer/App/Entity.ActivityRate.yml | 21 + config/serializer/App/Entity.CustomerRate.yml | 21 + config/serializer/App/Entity.ProjectRate.yml | 21 + config/serializer/App/Entity.Timesheet.yml | 2 + phpstan.neon | 2 - src/API/ActivityController.php | 175 +- src/API/ConfigurationController.php | 2 + src/API/CustomerController.php | 177 +- src/API/ProjectController.php | 176 +- src/API/StatusController.php | 3 + src/API/TagController.php | 1 + src/API/TeamController.php | 1 + src/API/TimesheetController.php | 16 +- src/API/UserController.php | 1 + src/Command/CreateReleaseCommand.php | 3 +- src/Controller/AbstractController.php | 9 +- src/Controller/ActivityController.php | 19 - src/Controller/CustomerController.php | 19 - src/Controller/ProfileController.php | 1 - src/Controller/ProjectController.php | 19 - src/Entity/Activity.php | 8 +- src/Entity/Configuration.php | 3 +- src/Entity/Customer.php | 21 +- src/Entity/InvoiceTemplate.php | 2 +- src/Entity/MetaTableTypeTrait.php | 3 +- src/Entity/Project.php | 4 +- src/Entity/Rate.php | 20 + src/Entity/RateInterface.php | 5 + src/Entity/Tag.php | 2 +- src/Entity/Team.php | 2 +- src/Entity/Timesheet.php | 21 +- src/Entity/UserPreference.php | 4 +- src/Event/UserPreferenceEvent.php | 2 +- .../RegistrationSubscriber.php | 25 +- .../UserPreferenceSubscriber.php | 9 + .../Base/AbstractSpreadsheetRenderer.php | 29 +- src/Export/Base/RendererTrait.php | 7 + src/Form/API/ActivityRateApiForm.php | 28 + src/Form/API/CustomerRateApiForm.php | 28 + src/Form/API/ProjectRateApiForm.php | 28 + src/Form/AbstractRateForm.php | 56 + src/Form/ActivityRateForm.php | 24 +- src/Form/CustomerRateForm.php | 25 +- src/Form/ProjectRateForm.php | 25 +- .../Calculator/AbstractMergedCalculator.php | 5 + .../AbstractSumInvoiceCalculator.php | 14 +- .../Hydrator/InvoiceItemDefaultHydrator.php | 4 + src/Invoice/InvoiceItem.php | 16 + src/Invoice/InvoiceItemInterface.php | 8 + .../ConfigurableNumberGenerator.php | 9 +- src/Migrations/Version20200323163038.php | 42 + src/Migrations/Version20200323163039.php | 35 + src/Model/TimesheetCountedStatistic.php | 25 + src/Repository/ActivityRepository.php | 2 + src/Repository/CustomerRepository.php | 2 + src/Repository/ProjectRepository.php | 2 + src/Timesheet/Calculator/RateCalculator.php | 49 +- templates/activity/details.html.twig | 61 +- templates/activity/embed_budget.html.twig | 10 +- templates/customer/details.html.twig | 61 +- templates/customer/embed_budget.html.twig | 5 +- templates/embeds/rates-table.html.twig | 60 + templates/export/actions.html.twig | 5 +- templates/export/index.html.twig | 66 +- templates/export/pdf-layout.html.twig | 305 +++ .../export/renderer/default-budget.pdf.twig | 23 +- .../export/renderer/default-internal.pdf.twig | 2 + templates/export/renderer/default.html.twig | 123 +- templates/export/renderer/default.pdf.twig | 275 +-- templates/invoice/index.html.twig | 7 +- templates/invoice/renderer/default.html.twig | 11 +- .../invoice/renderer/freelancer.html.twig | 11 +- templates/project/details.html.twig | 61 +- templates/project/embed_budget.html.twig | 7 +- tests/API/APIControllerBaseTest.php | 60 +- tests/API/ActivityControllerTest.php | 56 +- tests/API/CustomerControllerTest.php | 53 +- tests/API/ProjectControllerTest.php | 54 +- tests/API/RateControllerTestTrait.php | 205 ++ tests/API/StatusControllerTest.php | 6 +- tests/API/TagControllerTest.php | 13 +- tests/API/TeamControllerTest.php | 26 +- tests/API/TimesheetControllerTest.php | 148 +- tests/API/UserControllerTest.php | 21 +- tests/Command/InvoiceCreateCommandTest.php | 4 +- tests/Controller/ActivityControllerTest.php | 40 +- tests/Controller/CustomerControllerTest.php | 45 +- tests/Controller/DoctorControllerTest.php | 4 + tests/Controller/ExportControllerTest.php | 14 +- tests/Controller/HomepageControllerTest.php | 2 +- tests/Controller/InvoiceControllerTest.php | 16 +- tests/Controller/LayoutControllerTest.php | 4 +- tests/Controller/PermissionControllerTest.php | 22 +- tests/Controller/PluginControllerTest.php | 4 + tests/Controller/ProfileControllerTest.php | 45 +- tests/Controller/ProjectControllerTest.php | 50 +- .../SystemConfigurationControllerTest.php | 4 + tests/Controller/TagControllerTest.php | 4 +- tests/Controller/TeamControllerTest.php | 18 +- tests/Controller/TimesheetControllerTest.php | 24 +- .../TimesheetTeamControllerTest.php | 27 +- tests/Controller/UserControllerTest.php | 6 +- tests/Entity/ActivityRateTest.php | 8 + tests/Entity/CustomerRateTest.php | 8 + tests/Entity/ProjectRateTest.php | 8 + tests/Entity/TimesheetTest.php | 10 +- .../DashboardSubscriberTest.php | 4 +- .../RegistrationSubscriberTest.php | 34 +- .../ResetPasswordSubscriberTest.php | 3 + .../UserPreferenceSubscriberTest.php | 96 + tests/Export/Renderer/CsvRendererTest.php | 31 +- tests/Export/Timesheet/CsvRendererTest.php | 31 +- .../InvoiceItemDefaultHydratorTest.php | 3 + tests/Invoice/InvoiceItemTest.php | 1 + tests/Invoice/Renderer/DebugRendererTest.php | 3 + tests/Invoice/templates/default.pdf.twig | 11 +- tests/KernelTestTrait.php | 26 +- tests/Model/TimesheetCountedStatisticTest.php | 42 + .../Calculator/RateCalculatorTest.php | 126 +- tests/phpstan.neon | 2 - translations/export.de.xlf | 4 + translations/export.en.xlf | 4 + translations/messages.de.xlf | 16 + translations/messages.en.xlf | 16 + var/data/kimai_test.sqlite | Bin 770048 -> 770048 bytes 128 files changed, 4044 insertions(+), 1571 deletions(-) create mode 100644 config/serializer/App/Entity.ActivityRate.yml create mode 100644 config/serializer/App/Entity.CustomerRate.yml create mode 100644 config/serializer/App/Entity.ProjectRate.yml create mode 100644 src/Form/API/ActivityRateApiForm.php create mode 100644 src/Form/API/CustomerRateApiForm.php create mode 100644 src/Form/API/ProjectRateApiForm.php create mode 100644 src/Form/AbstractRateForm.php create mode 100644 src/Migrations/Version20200323163038.php create mode 100644 src/Migrations/Version20200323163039.php create mode 100644 templates/embeds/rates-table.html.twig create mode 100644 templates/export/pdf-layout.html.twig create mode 100644 templates/export/renderer/default-internal.pdf.twig create mode 100644 tests/API/RateControllerTestTrait.php create mode 100644 tests/EventSubscriber/UserPreferenceSubscriberTest.php create mode 100644 tests/Model/TimesheetCountedStatisticTest.php diff --git a/composer.lock b/composer.lock index b81e32cd..ed39a231 100644 --- a/composer.lock +++ b/composer.lock @@ -107,20 +107,21 @@ }, { "name": "doctrine/annotations", - "version": "v1.8.0", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" + "reference": "5eb79f3dbdffed6544e1fc287572c0f462bd29bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/5eb79f3dbdffed6544e1fc287572c0f462bd29bb", + "reference": "5eb79f3dbdffed6544e1fc287572c0f462bd29bb", "shasum": "" }, "require": { "doctrine/lexer": "1.*", + "ext-tokenizer": "*", "php": "^7.1" }, "require-dev": { @@ -130,7 +131,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.9.x-dev" } }, "autoload": { @@ -171,7 +172,7 @@ "docblock", "parser" ], - "time": "2019-10-01T18:55:10+00:00" + "time": "2020-04-02T12:33:25+00:00" }, { "name": "doctrine/cache", @@ -1005,16 +1006,16 @@ }, { "name": "doctrine/orm", - "version": "v2.7.1", + "version": "v2.7.2", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "445796af0e873d9bd04f2502d322a7d5009b6846" + "reference": "dafe298ce5d0b995ebe1746670704c0a35868a6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/445796af0e873d9bd04f2502d322a7d5009b6846", - "reference": "445796af0e873d9bd04f2502d322a7d5009b6846", + "url": "https://api.github.com/repos/doctrine/orm/zipball/dafe298ce5d0b995ebe1746670704c0a35868a6a", + "reference": "dafe298ce5d0b995ebe1746670704c0a35868a6a", "shasum": "" }, "require": { @@ -1085,20 +1086,34 @@ "database", "orm" ], - "time": "2020-02-15T14:35:56+00:00" + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine/orm", + "type": "tidelift" + } + ], + "time": "2020-03-19T06:41:02+00:00" }, { "name": "doctrine/persistence", - "version": "1.3.6", + "version": "1.3.7", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "5dd3ac5eebef2d0b074daa4440bb18f93132dee4" + "reference": "0af483f91bada1c9ded6c2cfd26ab7d5ab2094e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/5dd3ac5eebef2d0b074daa4440bb18f93132dee4", - "reference": "5dd3ac5eebef2d0b074daa4440bb18f93132dee4", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/0af483f91bada1c9ded6c2cfd26ab7d5ab2094e0", + "reference": "0af483f91bada1c9ded6c2cfd26ab7d5ab2094e0", "shasum": "" }, "require": { @@ -1106,7 +1121,7 @@ "doctrine/cache": "^1.0", "doctrine/collections": "^1.0", "doctrine/event-manager": "^1.0", - "doctrine/reflection": "^1.1", + "doctrine/reflection": "^1.2", "php": "^7.1" }, "conflict": { @@ -1168,20 +1183,34 @@ "orm", "persistence" ], - "time": "2020-01-16T22:06:23+00:00" + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fpersistence", + "type": "tidelift" + } + ], + "time": "2020-03-21T15:13:52+00:00" }, { "name": "doctrine/reflection", - "version": "v1.1.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/reflection.git", - "reference": "bc420ead87fdfe08c03ecc3549db603a45b06d4c" + "reference": "55e71912dfcd824b2fdd16f2d9afe15684cfce79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/reflection/zipball/bc420ead87fdfe08c03ecc3549db603a45b06d4c", - "reference": "bc420ead87fdfe08c03ecc3549db603a45b06d4c", + "url": "https://api.github.com/repos/doctrine/reflection/zipball/55e71912dfcd824b2fdd16f2d9afe15684cfce79", + "reference": "55e71912dfcd824b2fdd16f2d9afe15684cfce79", "shasum": "" }, "require": { @@ -1202,7 +1231,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1246,7 +1275,7 @@ "reflection", "static" ], - "time": "2020-01-08T19:53:19+00:00" + "time": "2020-03-27T11:06:43+00:00" }, { "name": "egulias/email-validator", @@ -1393,16 +1422,16 @@ }, { "name": "friendsofsymfony/rest-bundle", - "version": "2.7.2", + "version": "2.7.3", "source": { "type": "git", "url": "https://github.com/FriendsOfSymfony/FOSRestBundle.git", - "reference": "22fbbc35a2964564bfde765007655174262315c9" + "reference": "21a27cebe54f02f6499d78db8978162ce7183112" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/22fbbc35a2964564bfde765007655174262315c9", - "reference": "22fbbc35a2964564bfde765007655174262315c9", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/21a27cebe54f02f6499d78db8978162ce7183112", + "reference": "21a27cebe54f02f6499d78db8978162ce7183112", "shasum": "" }, "require": { @@ -1466,6 +1495,7 @@ "FOS\\RestBundle\\": "" }, "exclude-from-classmap": [ + "Resources/", "Tests/" ] }, @@ -1492,7 +1522,7 @@ "keywords": [ "rest" ], - "time": "2020-03-04T21:18:53+00:00" + "time": "2020-03-28T08:23:35+00:00" }, { "name": "gedmo/doctrine-extensions", @@ -2484,7 +2514,7 @@ }, { "name": "illuminate/cache", - "version": "v7.2.2", + "version": "v7.5.1", "source": { "type": "git", "url": "https://github.com/illuminate/cache.git", @@ -2535,16 +2565,16 @@ }, { "name": "illuminate/contracts", - "version": "v7.2.2", + "version": "v7.5.1", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "075d70c8d621e474d10279bf62c19e121be30e95" + "reference": "2db7e8a936cc09e396d14902178ea177f4dc42ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/075d70c8d621e474d10279bf62c19e121be30e95", - "reference": "075d70c8d621e474d10279bf62c19e121be30e95", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/2db7e8a936cc09e396d14902178ea177f4dc42ac", + "reference": "2db7e8a936cc09e396d14902178ea177f4dc42ac", "shasum": "" }, "require": { @@ -2575,20 +2605,20 @@ ], "description": "The Illuminate Contracts package.", "homepage": "https://laravel.com", - "time": "2020-03-16T13:40:39+00:00" + "time": "2020-04-04T15:13:36+00:00" }, { "name": "illuminate/support", - "version": "v7.2.2", + "version": "v7.5.1", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "91066b0b829ea0ab1315eeaefbe7f191cc31d7a1" + "reference": "99b3538c63b3ce5374d5f8fad181fac07efaedec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/91066b0b829ea0ab1315eeaefbe7f191cc31d7a1", - "reference": "91066b0b829ea0ab1315eeaefbe7f191cc31d7a1", + "url": "https://api.github.com/repos/illuminate/support/zipball/99b3538c63b3ce5374d5f8fad181fac07efaedec", + "reference": "99b3538c63b3ce5374d5f8fad181fac07efaedec", "shasum": "" }, "require": { @@ -2606,7 +2636,7 @@ "suggest": { "illuminate/filesystem": "Required to use the composer class (^7.0).", "moontoast/math": "Required to use ordered UUIDs (^1.1).", - "ramsey/uuid": "Required to use Str::uuid() (^3.7).", + "ramsey/uuid": "Required to use Str::uuid() (^3.7|^4.0).", "symfony/process": "Required to use the composer class (^5.0).", "symfony/var-dumper": "Required to use the dd function (^5.0).", "vlucas/phpdotenv": "Required to use the Env class and env helper (^4.0)." @@ -2637,7 +2667,7 @@ ], "description": "The Illuminate Support package.", "homepage": "https://laravel.com", - "time": "2020-03-17T14:26:31+00:00" + "time": "2020-04-06T13:34:26+00:00" }, { "name": "intervention/image", @@ -2818,16 +2848,16 @@ }, { "name": "jms/serializer", - "version": "3.5.0", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "0e286681396d8139406e596c6c802d37ab0b2124" + "reference": "e82527ceddedf8dd988a4ce900f4b14fedf4d6f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/0e286681396d8139406e596c6c802d37ab0b2124", - "reference": "0e286681396d8139406e596c6c802d37ab0b2124", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/e82527ceddedf8dd988a4ce900f4b14fedf4d6f2", + "reference": "e82527ceddedf8dd988a4ce900f4b14fedf4d6f2", "shasum": "" }, "require": { @@ -2868,7 +2898,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.5-dev" + "dev-master": "3.6-dev" } }, "autoload": { @@ -2899,7 +2929,13 @@ "serialization", "xml" ], - "time": "2020-02-22T21:06:01+00:00" + "funding": [ + { + "url": "https://github.com/goetas", + "type": "github" + } + ], + "time": "2020-03-21T20:26:09+00:00" }, { "name": "jms/serializer-bundle", @@ -3093,16 +3129,16 @@ }, { "name": "kimai/user-bundle", - "version": "1.1", + "version": "1.2", "source": { "type": "git", "url": "https://github.com/kimai/user-bundle.git", - "reference": "a52680e843f2a2408df967029c4ea471c41622ee" + "reference": "96de1dfb65cc535292c72f0ca31c3e3a0dcf8c93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kimai/user-bundle/zipball/a52680e843f2a2408df967029c4ea471c41622ee", - "reference": "a52680e843f2a2408df967029c4ea471c41622ee", + "url": "https://api.github.com/repos/kimai/user-bundle/zipball/96de1dfb65cc535292c72f0ca31c3e3a0dcf8c93", + "reference": "96de1dfb65cc535292c72f0ca31c3e3a0dcf8c93", "shasum": "" }, "require": { @@ -3155,7 +3191,7 @@ ], "description": "Kimai UserBundle", "homepage": "https://www.kimai.org", - "time": "2020-03-17T18:39:24+00:00" + "time": "2020-04-07T23:16:45+00:00" }, { "name": "laravolt/avatar", @@ -3766,16 +3802,16 @@ }, { "name": "nelmio/api-doc-bundle", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/nelmio/NelmioApiDocBundle.git", - "reference": "0fcf2d5c9a9b4e230e5bcf6b3f4ad469ba738ed2" + "reference": "ab014fe032beb1a7875939ff4162e8d05ad778ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/0fcf2d5c9a9b4e230e5bcf6b3f4ad469ba738ed2", - "reference": "0fcf2d5c9a9b4e230e5bcf6b3f4ad469ba738ed2", + "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/ab014fe032beb1a7875939ff4162e8d05ad778ab", + "reference": "ab014fe032beb1a7875939ff4162e8d05ad778ab", "shasum": "" }, "require": { @@ -3850,7 +3886,7 @@ "documentation", "rest" ], - "time": "2020-02-23T16:51:12+00:00" + "time": "2020-03-31T10:05:08+00:00" }, { "name": "nelmio/cors-bundle", @@ -3912,16 +3948,16 @@ }, { "name": "nesbot/carbon", - "version": "2.31.0", + "version": "2.32.2", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "bbc0ab53f41a4c6f223c18efcdbd9bc725eb5d2d" + "reference": "f10e22cf546704fab1db4ad4b9dedbc5c797a0dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bbc0ab53f41a4c6f223c18efcdbd9bc725eb5d2d", - "reference": "bbc0ab53f41a4c6f223c18efcdbd9bc725eb5d2d", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/f10e22cf546704fab1db4ad4b9dedbc5c797a0dc", + "reference": "f10e22cf546704fab1db4ad4b9dedbc5c797a0dc", "shasum": "" }, "require": { @@ -3930,6 +3966,7 @@ "symfony/translation": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { + "doctrine/orm": "^2.7", "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", "kylekatarnls/multi-tester": "^1.1", "phpmd/phpmd": "^2.8", @@ -3978,7 +4015,17 @@ "datetime", "time" ], - "time": "2020-03-01T11:11:58+00:00" + "funding": [ + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2020-03-31T13:43:19+00:00" }, { "name": "ocramius/package-versions", @@ -4856,16 +4903,16 @@ }, { "name": "psr/log", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", "shasum": "" }, "require": { @@ -4899,7 +4946,7 @@ "psr", "psr-3" ], - "time": "2019-11-01T11:05:21+00:00" + "time": "2020-03-23T09:12:05+00:00" }, { "name": "psr/simple-cache", @@ -5029,25 +5076,25 @@ }, { "name": "sensio/framework-extra-bundle", - "version": "v5.5.3", + "version": "v5.5.4", "source": { "type": "git", "url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git", - "reference": "98f0807137b13d0acfdf3c255a731516e97015de" + "reference": "d0585d4825a87a5030ca8cd34adb4a17e1066c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/98f0807137b13d0acfdf3c255a731516e97015de", - "reference": "98f0807137b13d0acfdf3c255a731516e97015de", + "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/d0585d4825a87a5030ca8cd34adb4a17e1066c17", + "reference": "d0585d4825a87a5030ca8cd34adb4a17e1066c17", "shasum": "" }, "require": { "doctrine/annotations": "^1.0", "php": ">=7.1.3", - "symfony/config": "^4.3|^5.0", - "symfony/dependency-injection": "^4.3|^5.0", - "symfony/framework-bundle": "^4.3|^5.0", - "symfony/http-kernel": "^4.3|^5.0" + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/framework-bundle": "^4.4|^5.0", + "symfony/http-kernel": "^4.4|^5.0" }, "conflict": { "doctrine/doctrine-cache-bundle": "<1.3.1" @@ -5056,24 +5103,19 @@ "doctrine/doctrine-bundle": "^1.11|^2.0", "doctrine/orm": "^2.5", "nyholm/psr7": "^1.1", - "symfony/browser-kit": "^4.3|^5.0", - "symfony/dom-crawler": "^4.3|^5.0", - "symfony/expression-language": "^4.3|^5.0", - "symfony/finder": "^4.3|^5.0", + "symfony/browser-kit": "^4.4|^5.0", + "symfony/dom-crawler": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", "symfony/monolog-bridge": "^4.0|^5.0", "symfony/monolog-bundle": "^3.2", "symfony/phpunit-bridge": "^4.3.5|^5.0", "symfony/psr-http-message-bridge": "^1.1", - "symfony/security-bundle": "^4.3|^5.0", - "symfony/twig-bundle": "^4.3|^5.0", - "symfony/yaml": "^4.3|^5.0", + "symfony/security-bundle": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0", "twig/twig": "^1.34|^2.4|^3.0" }, - "suggest": { - "symfony/expression-language": "", - "symfony/psr-http-message-bridge": "To use the PSR-7 converters", - "symfony/security-bundle": "" - }, "type": "symfony-bundle", "extra": { "branch-alias": { @@ -5103,20 +5145,20 @@ "annotations", "controllers" ], - "time": "2019-12-27T08:57:19+00:00" + "time": "2020-04-06T12:20:39+00:00" }, { "name": "setasign/fpdi", - "version": "v2.3.1", + "version": "v2.3.2", "source": { "type": "git", "url": "https://github.com/Setasign/FPDI.git", - "reference": "f58e64e51f61922d4c3ba4c6c91366ac520cb442" + "reference": "527761458f504882ab844f15754523825647f291" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/f58e64e51f61922d4c3ba4c6c91366ac520cb442", - "reference": "f58e64e51f61922d4c3ba4c6c91366ac520cb442", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/527761458f504882ab844f15754523825647f291", + "reference": "527761458f504882ab844f15754523825647f291", "shasum": "" }, "require": { @@ -5133,10 +5175,7 @@ "tecnickcom/tcpdf": "~6.2" }, "suggest": { - "setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured.", - "setasign/fpdi-fpdf": "Use this package to automatically evaluate dependencies to FPDF.", - "setasign/fpdi-tcpdf": "Use this package to automatically evaluate dependencies to TCPDF.", - "setasign/fpdi-tfpdf": "Use this package to automatically evaluate dependencies to tFPDF." + "setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured." }, "type": "library", "autoload": { @@ -5167,20 +5206,26 @@ "fpdi", "pdf" ], - "time": "2020-03-10T15:28:15+00:00" + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/setasign/fpdi", + "type": "tidelift" + } + ], + "time": "2020-03-23T15:53:59+00:00" }, { "name": "symfony/amazon-mailer", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/amazon-mailer.git", - "reference": "ac5202e52d676a0a4a99a8dc67d03590692e5306" + "reference": "97089e9e80aeb7404541907d99dc1226a8a6c3b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/ac5202e52d676a0a4a99a8dc67d03590692e5306", - "reference": "ac5202e52d676a0a4a99a8dc67d03590692e5306", + "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/97089e9e80aeb7404541907d99dc1226a8a6c3b8", + "reference": "97089e9e80aeb7404541907d99dc1226a8a6c3b8", "shasum": "" }, "require": { @@ -5220,20 +5265,34 @@ ], "description": "Symfony Amazon Mailer Bridge", "homepage": "https://symfony.com", - "time": "2020-01-08T17:36:30+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/asset", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "5c1afa35f0ff6a4fa5d037b4a5ef1bf60513e65b" + "reference": "e3574559efcb51601022fa46fd88dd13a8febdc2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/5c1afa35f0ff6a4fa5d037b4a5ef1bf60513e65b", - "reference": "5c1afa35f0ff6a4fa5d037b4a5ef1bf60513e65b", + "url": "https://api.github.com/repos/symfony/asset/zipball/e3574559efcb51601022fa46fd88dd13a8febdc2", + "reference": "e3574559efcb51601022fa46fd88dd13a8febdc2", "shasum": "" }, "require": { @@ -5276,20 +5335,34 @@ ], "description": "Symfony Asset Component", "homepage": "https://symfony.com", - "time": "2020-02-24T13:10:00+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/cache", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "28511cbd8c760a19f4b4b70961d2cd957733b3d9" + "reference": "f777b570291aebe51081b9827e05f3a747665e87" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/28511cbd8c760a19f4b4b70961d2cd957733b3d9", - "reference": "28511cbd8c760a19f4b4b70961d2cd957733b3d9", + "url": "https://api.github.com/repos/symfony/cache/zipball/f777b570291aebe51081b9827e05f3a747665e87", + "reference": "f777b570291aebe51081b9827e05f3a747665e87", "shasum": "" }, "require": { @@ -5355,7 +5428,21 @@ "caching", "psr6" ], - "time": "2020-02-20T16:31:44+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/cache-contracts", @@ -5417,16 +5504,16 @@ }, { "name": "symfony/config", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9" + "reference": "3f4a3de1af498ed0ea653d4dc2317794144e6ca4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", - "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", + "url": "https://api.github.com/repos/symfony/config/zipball/3f4a3de1af498ed0ea653d4dc2317794144e6ca4", + "reference": "3f4a3de1af498ed0ea653d4dc2317794144e6ca4", "shasum": "" }, "require": { @@ -5477,20 +5564,34 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:32:40+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/console", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9" + "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", - "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", + "url": "https://api.github.com/repos/symfony/console/zipball/10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", + "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", "shasum": "" }, "require": { @@ -5553,20 +5654,34 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2020-02-24T13:10:00+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T11:41:10+00:00" }, { "name": "symfony/css-selector", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22" + "reference": "afc26133a6fbdd4f8842e38893e0ee4685c7c94b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22", - "reference": "d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/afc26133a6fbdd4f8842e38893e0ee4685c7c94b", + "reference": "afc26133a6fbdd4f8842e38893e0ee4685c7c94b", "shasum": "" }, "require": { @@ -5606,20 +5721,34 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:01:01+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/debug", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "a980d87a659648980d89193fd8b7a7ca89d97d21" + "reference": "346636d2cae417992ecfd761979b2ab98b339a45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/a980d87a659648980d89193fd8b7a7ca89d97d21", - "reference": "a980d87a659648980d89193fd8b7a7ca89d97d21", + "url": "https://api.github.com/repos/symfony/debug/zipball/346636d2cae417992ecfd761979b2ab98b339a45", + "reference": "346636d2cae417992ecfd761979b2ab98b339a45", "shasum": "" }, "require": { @@ -5662,20 +5791,34 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2020-02-23T14:41:43+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "ebb2e882e8c9e2eb990aa61ddcd389848466e342" + "reference": "755b18859be26b90f4bf63753432d3387458bf31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/ebb2e882e8c9e2eb990aa61ddcd389848466e342", - "reference": "ebb2e882e8c9e2eb990aa61ddcd389848466e342", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/755b18859be26b90f4bf63753432d3387458bf31", + "reference": "755b18859be26b90f4bf63753432d3387458bf31", "shasum": "" }, "require": { @@ -5735,20 +5878,34 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2020-02-29T09:50:10+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T10:09:30+00:00" }, { "name": "symfony/doctrine-bridge", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "1b4564758fe91f5d53dfbdfd9007d15e43fa465f" + "reference": "7889c9df9fe4d95042c2f6e79901c9e6517343d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/1b4564758fe91f5d53dfbdfd9007d15e43fa465f", - "reference": "1b4564758fe91f5d53dfbdfd9007d15e43fa465f", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/7889c9df9fe4d95042c2f6e79901c9e6517343d9", + "reference": "7889c9df9fe4d95042c2f6e79901c9e6517343d9", "shasum": "" }, "require": { @@ -5829,20 +5986,34 @@ ], "description": "Symfony Doctrine Bridge", "homepage": "https://symfony.com", - "time": "2020-02-24T17:16:47+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/dotenv", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "9bba981ecb1f57c04520d4165b3e6a17ac49319f" + "reference": "a78e698cfb8aca8ef6814639eb5ffc17180a4326" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/9bba981ecb1f57c04520d4165b3e6a17ac49319f", - "reference": "9bba981ecb1f57c04520d4165b3e6a17ac49319f", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/a78e698cfb8aca8ef6814639eb5ffc17180a4326", + "reference": "a78e698cfb8aca8ef6814639eb5ffc17180a4326", "shasum": "" }, "require": { @@ -5886,20 +6057,34 @@ "env", "environment" ], - "time": "2020-02-29T10:04:02+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/error-handler", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "89aa4b9ac6f1f35171b8621b24f60477312085be" + "reference": "7e9828fc98aa1cf27b422fe478a84f5b0abb7358" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/89aa4b9ac6f1f35171b8621b24f60477312085be", - "reference": "89aa4b9ac6f1f35171b8621b24f60477312085be", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/7e9828fc98aa1cf27b422fe478a84f5b0abb7358", + "reference": "7e9828fc98aa1cf27b422fe478a84f5b0abb7358", "shasum": "" }, "require": { @@ -5942,20 +6127,34 @@ ], "description": "Symfony ErrorHandler Component", "homepage": "https://symfony.com", - "time": "2020-02-26T11:45:31+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T14:07:33+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "4ad8e149799d3128621a3a1f70e92b9897a8930d" + "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4ad8e149799d3128621a3a1f70e92b9897a8930d", - "reference": "4ad8e149799d3128621a3a1f70e92b9897a8930d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abc8e3618bfdb55e44c8c6a00abd333f831bbfed", + "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed", "shasum": "" }, "require": { @@ -6012,7 +6211,21 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:32:40+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -6074,16 +6287,16 @@ }, { "name": "symfony/expression-language", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "70649e0abcac6ad1109f6243886bca0445e278b9" + "reference": "c4171e39e6cfc72e2bedb44922310d7d2bd2ab91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/70649e0abcac6ad1109f6243886bca0445e278b9", - "reference": "70649e0abcac6ad1109f6243886bca0445e278b9", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/c4171e39e6cfc72e2bedb44922310d7d2bd2ab91", + "reference": "c4171e39e6cfc72e2bedb44922310d7d2bd2ab91", "shasum": "" }, "require": { @@ -6121,20 +6334,34 @@ ], "description": "Symfony ExpressionLanguage Component", "homepage": "https://symfony.com", - "time": "2020-02-24T13:10:00+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/filesystem", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd" + "reference": "fe297193bf2e6866ed900ed2d5869362768df6a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/266c9540b475f26122b61ef8b23dd9198f5d1cfd", - "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/fe297193bf2e6866ed900ed2d5869362768df6a7", + "reference": "fe297193bf2e6866ed900ed2d5869362768df6a7", "shasum": "" }, "require": { @@ -6171,20 +6398,34 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2020-01-21T08:20:44+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/finder", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357" + "reference": "5729f943f9854c5781984ed4907bbb817735776b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ea69c129aed9fdeca781d4b77eb20b62cf5d5357", - "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357", + "url": "https://api.github.com/repos/symfony/finder/zipball/5729f943f9854c5781984ed4907bbb817735776b", + "reference": "5729f943f9854c5781984ed4907bbb817735776b", "shasum": "" }, "require": { @@ -6220,7 +6461,21 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2020-02-14T07:42:58+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/flex", @@ -6273,16 +6528,16 @@ }, { "name": "symfony/form", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "677927dad3b9f93117db62fc1df4de82027dc282" + "reference": "6dfd2d0f47b9a4abee73807f7172e2b8a0006571" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/677927dad3b9f93117db62fc1df4de82027dc282", - "reference": "677927dad3b9f93117db62fc1df4de82027dc282", + "url": "https://api.github.com/repos/symfony/form/zipball/6dfd2d0f47b9a4abee73807f7172e2b8a0006571", + "reference": "6dfd2d0f47b9a4abee73807f7172e2b8a0006571", "shasum": "" }, "require": { @@ -6353,20 +6608,34 @@ ], "description": "Symfony Form Component", "homepage": "https://symfony.com", - "time": "2020-02-29T10:05:28+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/framework-bundle", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "df5528926e6e1954975f3d73a91f029ba3d9c76b" + "reference": "80cdda836cfbe3ccb2bdd4a974f632473f0807a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/df5528926e6e1954975f3d73a91f029ba3d9c76b", - "reference": "df5528926e6e1954975f3d73a91f029ba3d9c76b", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/80cdda836cfbe3ccb2bdd4a974f632473f0807a6", + "reference": "80cdda836cfbe3ccb2bdd4a974f632473f0807a6", "shasum": "" }, "require": { @@ -6484,20 +6753,34 @@ ], "description": "Symfony FrameworkBundle", "homepage": "https://symfony.com", - "time": "2020-02-28T13:15:16+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T11:41:10+00:00" }, { "name": "symfony/google-mailer", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/google-mailer.git", - "reference": "7dd2d4722ed7e9fe3be27b0afe1865dc81643815" + "reference": "09cb25c097470eee608069a016f8b58cf52f8f23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/google-mailer/zipball/7dd2d4722ed7e9fe3be27b0afe1865dc81643815", - "reference": "7dd2d4722ed7e9fe3be27b0afe1865dc81643815", + "url": "https://api.github.com/repos/symfony/google-mailer/zipball/09cb25c097470eee608069a016f8b58cf52f8f23", + "reference": "09cb25c097470eee608069a016f8b58cf52f8f23", "shasum": "" }, "require": { @@ -6537,20 +6820,34 @@ ], "description": "Symfony Google Mailer Bridge", "homepage": "https://symfony.com", - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/http-client", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "65ccb6ca4a5a7bf7c244b8a28195fa188521b3d2" + "reference": "9a8f5c968dc68d58044f8e9ff39d03074489b55d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/65ccb6ca4a5a7bf7c244b8a28195fa188521b3d2", - "reference": "65ccb6ca4a5a7bf7c244b8a28195fa188521b3d2", + "url": "https://api.github.com/repos/symfony/http-client/zipball/9a8f5c968dc68d58044f8e9ff39d03074489b55d", + "reference": "9a8f5c968dc68d58044f8e9ff39d03074489b55d", "shasum": "" }, "require": { @@ -6605,7 +6902,21 @@ ], "description": "Symfony HttpClient component", "homepage": "https://symfony.com", - "time": "2020-02-25T13:55:11+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/http-client-contracts", @@ -6666,16 +6977,16 @@ }, { "name": "symfony/http-foundation", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "7e41b4fcad4619535f45f8bfa7744c4f384e1648" + "reference": "62f92509c9abfd1f73e17b8cf1b72c0bdac6611b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7e41b4fcad4619535f45f8bfa7744c4f384e1648", - "reference": "7e41b4fcad4619535f45f8bfa7744c4f384e1648", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/62f92509c9abfd1f73e17b8cf1b72c0bdac6611b", + "reference": "62f92509c9abfd1f73e17b8cf1b72c0bdac6611b", "shasum": "" }, "require": { @@ -6717,20 +7028,34 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2020-02-13T19:40:01+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T14:07:33+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "8c8734486dada83a6041ab744709bdc1651a8462" + "reference": "f356a489e51856b99908005eb7f2c51a1dfc95dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8c8734486dada83a6041ab744709bdc1651a8462", - "reference": "8c8734486dada83a6041ab744709bdc1651a8462", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f356a489e51856b99908005eb7f2c51a1dfc95dc", + "reference": "f356a489e51856b99908005eb7f2c51a1dfc95dc", "shasum": "" }, "require": { @@ -6807,20 +7132,34 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2020-02-29T10:31:38+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T14:59:15+00:00" }, { "name": "symfony/inflector", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/inflector.git", - "reference": "f419ab2853cc00471ffd7fc18e544b5f5a90adb1" + "reference": "53cfa47fe9142f39b5605df67bada3893dd4f46c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/inflector/zipball/f419ab2853cc00471ffd7fc18e544b5f5a90adb1", - "reference": "f419ab2853cc00471ffd7fc18e544b5f5a90adb1", + "url": "https://api.github.com/repos/symfony/inflector/zipball/53cfa47fe9142f39b5605df67bada3893dd4f46c", + "reference": "53cfa47fe9142f39b5605df67bada3893dd4f46c", "shasum": "" }, "require": { @@ -6865,20 +7204,34 @@ "symfony", "words" ], - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/intl", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "f675f139e20b9e0ff05bac662c081fe9ef7b2f88" + "reference": "63238a53b1cf0cd3e2b0b22cabc7c0b6f3fd4562" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/f675f139e20b9e0ff05bac662c081fe9ef7b2f88", - "reference": "f675f139e20b9e0ff05bac662c081fe9ef7b2f88", + "url": "https://api.github.com/repos/symfony/intl/zipball/63238a53b1cf0cd3e2b0b22cabc7c0b6f3fd4562", + "reference": "63238a53b1cf0cd3e2b0b22cabc7c0b6f3fd4562", "shasum": "" }, "require": { @@ -6940,20 +7293,34 @@ "l10n", "localization" ], - "time": "2020-02-04T09:32:40+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/mailchimp-mailer", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/mailchimp-mailer.git", - "reference": "2eaf7d50595c4902c693349c70b917d150b25ba7" + "reference": "51fe2f8366be279c8ae3a1f643169daa1c71b5ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailchimp-mailer/zipball/2eaf7d50595c4902c693349c70b917d150b25ba7", - "reference": "2eaf7d50595c4902c693349c70b917d150b25ba7", + "url": "https://api.github.com/repos/symfony/mailchimp-mailer/zipball/51fe2f8366be279c8ae3a1f643169daa1c71b5ca", + "reference": "51fe2f8366be279c8ae3a1f643169daa1c71b5ca", "shasum": "" }, "require": { @@ -6993,20 +7360,34 @@ ], "description": "Symfony Mailchimp Mailer Bridge", "homepage": "https://symfony.com", - "time": "2020-02-04T22:28:01+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/mailer", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "f79a2cc091c14c2d78cade2f8b772f568fb63c43" + "reference": "449856e70ccb1c91ebd75d6fb287ffe21be9fafe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/f79a2cc091c14c2d78cade2f8b772f568fb63c43", - "reference": "f79a2cc091c14c2d78cade2f8b772f568fb63c43", + "url": "https://api.github.com/repos/symfony/mailer/zipball/449856e70ccb1c91ebd75d6fb287ffe21be9fafe", + "reference": "449856e70ccb1c91ebd75d6fb287ffe21be9fafe", "shasum": "" }, "require": { @@ -7061,20 +7442,34 @@ ], "description": "Symfony Mailer Component", "homepage": "https://symfony.com", - "time": "2020-02-07T16:56:37+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/mailgun-mailer", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/mailgun-mailer.git", - "reference": "de87b7fc1fd650fa5437eda8aedfa7cd63a76a03" + "reference": "58bfc335d089e3f362fb54c4ed876f569e6eb77c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/de87b7fc1fd650fa5437eda8aedfa7cd63a76a03", - "reference": "de87b7fc1fd650fa5437eda8aedfa7cd63a76a03", + "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/58bfc335d089e3f362fb54c4ed876f569e6eb77c", + "reference": "58bfc335d089e3f362fb54c4ed876f569e6eb77c", "shasum": "" }, "require": { @@ -7114,20 +7509,34 @@ ], "description": "Symfony Mailgun Mailer Bridge", "homepage": "https://symfony.com", - "time": "2020-01-08T17:36:30+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/mime", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "304db017bafd71c122cd5223a9ac2d03dc24da32" + "reference": "6dde9dc70155e91b850b1d009d1f841c54bc4aba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/304db017bafd71c122cd5223a9ac2d03dc24da32", - "reference": "304db017bafd71c122cd5223a9ac2d03dc24da32", + "url": "https://api.github.com/repos/symfony/mime/zipball/6dde9dc70155e91b850b1d009d1f841c54bc4aba", + "reference": "6dde9dc70155e91b850b1d009d1f841c54bc4aba", "shasum": "" }, "require": { @@ -7176,20 +7585,34 @@ "mime", "mime-type" ], - "time": "2020-02-04T09:32:40+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "b14ee2f0488b3ad879fd000bc3dcce1cd2f6cfff" + "reference": "2df4a774d99ae6e87c8b67891430f935312be412" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/b14ee2f0488b3ad879fd000bc3dcce1cd2f6cfff", - "reference": "b14ee2f0488b3ad879fd000bc3dcce1cd2f6cfff", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/2df4a774d99ae6e87c8b67891430f935312be412", + "reference": "2df4a774d99ae6e87c8b67891430f935312be412", "shasum": "" }, "require": { @@ -7243,7 +7666,21 @@ ], "description": "Symfony Monolog Bridge", "homepage": "https://symfony.com", - "time": "2020-02-04T09:32:40+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/monolog-bundle", @@ -7310,16 +7747,16 @@ }, { "name": "symfony/options-resolver", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "9a02d6662660fe7bfadad63b5f0b0718d4c8b6b0" + "reference": "9072131b5e6e21203db3249c7db26b52897bc73e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/9a02d6662660fe7bfadad63b5f0b0718d4c8b6b0", - "reference": "9a02d6662660fe7bfadad63b5f0b0718d4c8b6b0", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/9072131b5e6e21203db3249c7db26b52897bc73e", + "reference": "9072131b5e6e21203db3249c7db26b52897bc73e", "shasum": "" }, "require": { @@ -7360,20 +7797,34 @@ "configuration", "options" ], - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38" + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", - "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14", "shasum": "" }, "require": { @@ -7385,7 +7836,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -7418,20 +7869,34 @@ "polyfill", "portable" ], - "time": "2020-01-13T11:15:53+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "699871accfb394eb6f34ba1210df437f79b14d58" + "reference": "b6786f69dd7b062390582f20520ab4918283217e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/699871accfb394eb6f34ba1210df437f79b14d58", - "reference": "699871accfb394eb6f34ba1210df437f79b14d58", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b6786f69dd7b062390582f20520ab4918283217e", + "reference": "b6786f69dd7b062390582f20520ab4918283217e", "shasum": "" }, "require": { @@ -7443,7 +7908,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -7478,20 +7943,34 @@ "portable", "shim" ], - "time": "2020-01-13T11:15:53+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-09T19:04:49+00:00" }, { "name": "symfony/polyfill-intl-icu", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "727b3bb5bfa7ca9eeb86416784cf1c08a6289b86" + "reference": "9c281272735eb66476e0fa7381e03fb0d4b60197" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/727b3bb5bfa7ca9eeb86416784cf1c08a6289b86", - "reference": "727b3bb5bfa7ca9eeb86416784cf1c08a6289b86", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/9c281272735eb66476e0fa7381e03fb0d4b60197", + "reference": "9c281272735eb66476e0fa7381e03fb0d4b60197", "shasum": "" }, "require": { @@ -7504,7 +7983,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -7536,20 +8015,34 @@ "portable", "shim" ], - "time": "2020-01-13T11:15:53+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a" + "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6842f1a39cf7d580655688069a03dd7cd83d244a", - "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", + "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", "shasum": "" }, "require": { @@ -7563,7 +8056,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -7598,20 +8091,34 @@ "portable", "shim" ], - "time": "2020-01-17T12:01:36+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-09T19:04:49+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "e62b4845992282d14037950542fc8e8650ae2a65" + "reference": "e62715f03f90dd8d2f3eb5daa21b4d19d71aebde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/e62b4845992282d14037950542fc8e8650ae2a65", - "reference": "e62b4845992282d14037950542fc8e8650ae2a65", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/e62715f03f90dd8d2f3eb5daa21b4d19d71aebde", + "reference": "e62715f03f90dd8d2f3eb5daa21b4d19d71aebde", "shasum": "" }, "require": { @@ -7623,7 +8130,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -7661,20 +8168,34 @@ "portable", "shim" ], - "time": "2020-01-13T11:15:53+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675" + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675", - "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", "shasum": "" }, "require": { @@ -7683,7 +8204,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -7719,20 +8240,34 @@ "portable", "shim" ], - "time": "2020-01-13T11:15:53+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/postmark-mailer", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/postmark-mailer.git", - "reference": "afaaca6f9652ca82086392b9955ed94ca6fc0a9e" + "reference": "8238aab3973427af95ed71d607f383986ab9098b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/postmark-mailer/zipball/afaaca6f9652ca82086392b9955ed94ca6fc0a9e", - "reference": "afaaca6f9652ca82086392b9955ed94ca6fc0a9e", + "url": "https://api.github.com/repos/symfony/postmark-mailer/zipball/8238aab3973427af95ed71d607f383986ab9098b", + "reference": "8238aab3973427af95ed71d607f383986ab9098b", "shasum": "" }, "require": { @@ -7772,20 +8307,34 @@ ], "description": "Symfony Postmark Mailer Bridge", "homepage": "https://symfony.com", - "time": "2020-01-30T10:46:32+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/property-access", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "090b4bc92ded1ec512f7e2ed1691210769dffdb3" + "reference": "75cbf0f388d82685ce06515951397bc1370901d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/090b4bc92ded1ec512f7e2ed1691210769dffdb3", - "reference": "090b4bc92ded1ec512f7e2ed1691210769dffdb3", + "url": "https://api.github.com/repos/symfony/property-access/zipball/75cbf0f388d82685ce06515951397bc1370901d7", + "reference": "75cbf0f388d82685ce06515951397bc1370901d7", "shasum": "" }, "require": { @@ -7839,20 +8388,34 @@ "property path", "reflection" ], - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/property-info", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "e6355ba81c738be31c3c3b3cd7929963f98da576" + "reference": "b6baecd501adec01a9d68f9c90b83659656065af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/e6355ba81c738be31c3c3b3cd7929963f98da576", - "reference": "e6355ba81c738be31c3c3b3cd7929963f98da576", + "url": "https://api.github.com/repos/symfony/property-info/zipball/b6baecd501adec01a9d68f9c90b83659656065af", + "reference": "b6baecd501adec01a9d68f9c90b83659656065af", "shasum": "" }, "require": { @@ -7915,20 +8478,34 @@ "type", "validator" ], - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/routing", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "4124d621d0e445732520037f888a0456951bde8c" + "reference": "0f562fa613e288d7dbae6c63abbc9b33ed75a8f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/4124d621d0e445732520037f888a0456951bde8c", - "reference": "4124d621d0e445732520037f888a0456951bde8c", + "url": "https://api.github.com/repos/symfony/routing/zipball/0f562fa613e288d7dbae6c63abbc9b33ed75a8f8", + "reference": "0f562fa613e288d7dbae6c63abbc9b33ed75a8f8", "shasum": "" }, "require": { @@ -7991,20 +8568,34 @@ "uri", "url" ], - "time": "2020-02-25T12:41:09+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T11:41:10+00:00" }, { "name": "symfony/security-bundle", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "21c4270b37f76e6c3c22f92597f397593ed1c9db" + "reference": "1c317cd29a75e4806479241ffd31d8035e243420" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/21c4270b37f76e6c3c22f92597f397593ed1c9db", - "reference": "21c4270b37f76e6c3c22f92597f397593ed1c9db", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/1c317cd29a75e4806479241ffd31d8035e243420", + "reference": "1c317cd29a75e4806479241ffd31d8035e243420", "shasum": "" }, "require": { @@ -8074,20 +8665,34 @@ ], "description": "Symfony SecurityBundle", "homepage": "https://symfony.com", - "time": "2020-02-26T10:27:30+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T11:41:10+00:00" }, { "name": "symfony/security-core", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "6251c8e432640106e6f2f045ac3b365f1af36d44" + "reference": "e99ad8bcd5d1202a1cff7b3e0e76d9077d81cbe6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/6251c8e432640106e6f2f045ac3b365f1af36d44", - "reference": "6251c8e432640106e6f2f045ac3b365f1af36d44", + "url": "https://api.github.com/repos/symfony/security-core/zipball/e99ad8bcd5d1202a1cff7b3e0e76d9077d81cbe6", + "reference": "e99ad8bcd5d1202a1cff7b3e0e76d9077d81cbe6", "shasum": "" }, "require": { @@ -8147,20 +8752,34 @@ ], "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", - "time": "2020-02-24T13:10:00+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T11:51:53+00:00" }, { "name": "symfony/security-csrf", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "da4664d94164e2b50ce75f2453724c6c33222505" + "reference": "286a71ff176e1b0dd071f0e73dcec0970a56634b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/da4664d94164e2b50ce75f2453724c6c33222505", - "reference": "da4664d94164e2b50ce75f2453724c6c33222505", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/286a71ff176e1b0dd071f0e73dcec0970a56634b", + "reference": "286a71ff176e1b0dd071f0e73dcec0970a56634b", "shasum": "" }, "require": { @@ -8206,20 +8825,34 @@ ], "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/security-guard", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/security-guard.git", - "reference": "7dcc99e3fa89387a1914496118b4aa0927f282e1" + "reference": "606a741712d8adb49aee9b59d57010724db06797" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-guard/zipball/7dcc99e3fa89387a1914496118b4aa0927f282e1", - "reference": "7dcc99e3fa89387a1914496118b4aa0927f282e1", + "url": "https://api.github.com/repos/symfony/security-guard/zipball/606a741712d8adb49aee9b59d57010724db06797", + "reference": "606a741712d8adb49aee9b59d57010724db06797", "shasum": "" }, "require": { @@ -8260,28 +8893,42 @@ ], "description": "Symfony Security Component - Guard", "homepage": "https://symfony.com", - "time": "2020-02-24T13:10:00+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/security-http", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "c38fe1cd72360dfaa39c82fcb9e4666b041f8834" + "reference": "b413064160255c31077bb082d25b7bd89275971b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/c38fe1cd72360dfaa39c82fcb9e4666b041f8834", - "reference": "c38fe1cd72360dfaa39c82fcb9e4666b041f8834", + "url": "https://api.github.com/repos/symfony/security-http/zipball/b413064160255c31077bb082d25b7bd89275971b", + "reference": "b413064160255c31077bb082d25b7bd89275971b", "shasum": "" }, "require": { "php": "^7.1.3", - "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4.40|^4.4.7|^5.0.7", "symfony/http-kernel": "^4.4", "symfony/property-access": "^3.4|^4.0|^5.0", - "symfony/security-core": "^4.4" + "symfony/security-core": "^4.4.7" }, "conflict": { "symfony/event-dispatcher": ">=5", @@ -8326,20 +8973,34 @@ ], "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", - "time": "2020-02-26T10:27:30+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T11:51:53+00:00" }, { "name": "symfony/sendgrid-mailer", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/sendgrid-mailer.git", - "reference": "96a6c3081c9fb47a6784320147370939626aa6cd" + "reference": "fdf3c73f60164984f4f933c3ce0cc5dc44e7ed7b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/sendgrid-mailer/zipball/96a6c3081c9fb47a6784320147370939626aa6cd", - "reference": "96a6c3081c9fb47a6784320147370939626aa6cd", + "url": "https://api.github.com/repos/symfony/sendgrid-mailer/zipball/fdf3c73f60164984f4f933c3ce0cc5dc44e7ed7b", + "reference": "fdf3c73f60164984f4f933c3ce0cc5dc44e7ed7b", "shasum": "" }, "require": { @@ -8379,20 +9040,34 @@ ], "description": "Symfony Sendgrid Mailer Bridge", "homepage": "https://symfony.com", - "time": "2020-01-04T13:10:16+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/serializer", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "bc76d242fea5ff09c3ca34c90f3bb9341a2470a4" + "reference": "2a508a535f2323defb325cf28301064fcbb061b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/bc76d242fea5ff09c3ca34c90f3bb9341a2470a4", - "reference": "bc76d242fea5ff09c3ca34c90f3bb9341a2470a4", + "url": "https://api.github.com/repos/symfony/serializer/zipball/2a508a535f2323defb325cf28301064fcbb061b9", + "reference": "2a508a535f2323defb325cf28301064fcbb061b9", "shasum": "" }, "require": { @@ -8461,7 +9136,21 @@ ], "description": "Symfony Serializer Component", "homepage": "https://symfony.com", - "time": "2020-02-29T10:05:28+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/service-contracts", @@ -8523,16 +9212,16 @@ }, { "name": "symfony/stopwatch", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "abc08d7c48987829bac301347faa10f7e8bbf4fb" + "reference": "e0324d3560e4128270e3f08617480d9233d81cfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/abc08d7c48987829bac301347faa10f7e8bbf4fb", - "reference": "abc08d7c48987829bac301347faa10f7e8bbf4fb", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e0324d3560e4128270e3f08617480d9233d81cfc", + "reference": "e0324d3560e4128270e3f08617480d9233d81cfc", "shasum": "" }, "require": { @@ -8569,20 +9258,34 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/string", - "version": "v5.0.5", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "a45ae78382337833e3b0ab3097d1769074950007" + "reference": "48a2f4b3597514e6c885c0ddb22d3bbdb60517d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/a45ae78382337833e3b0ab3097d1769074950007", - "reference": "a45ae78382337833e3b0ab3097d1769074950007", + "url": "https://api.github.com/repos/symfony/string/zipball/48a2f4b3597514e6c885c0ddb22d3bbdb60517d0", + "reference": "48a2f4b3597514e6c885c0ddb22d3bbdb60517d0", "shasum": "" }, "require": { @@ -8633,20 +9336,34 @@ "utf-8", "utf8" ], - "time": "2020-02-26T22:30:10+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-16T13:02:39+00:00" }, { "name": "symfony/translation", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "0a19a77fba20818a969ef03fdaf1602de0546353" + "reference": "4e54d336f2eca5facad449d0b0118bb449375b76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/0a19a77fba20818a969ef03fdaf1602de0546353", - "reference": "0a19a77fba20818a969ef03fdaf1602de0546353", + "url": "https://api.github.com/repos/symfony/translation/zipball/4e54d336f2eca5facad449d0b0118bb449375b76", + "reference": "4e54d336f2eca5facad449d0b0118bb449375b76", "shasum": "" }, "require": { @@ -8709,7 +9426,21 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:32:40+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/translation-contracts", @@ -8770,16 +9501,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "e76e963d8aeb1370a1236ca237a8028141402fc0" + "reference": "bef4da6724c5a89bb3408d3bc785be7cd5b9efed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/e76e963d8aeb1370a1236ca237a8028141402fc0", - "reference": "e76e963d8aeb1370a1236ca237a8028141402fc0", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/bef4da6724c5a89bb3408d3bc785be7cd5b9efed", + "reference": "bef4da6724c5a89bb3408d3bc785be7cd5b9efed", "shasum": "" }, "require": { @@ -8869,20 +9600,34 @@ ], "description": "Symfony Twig Bridge", "homepage": "https://symfony.com", - "time": "2020-02-14T08:28:51+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/twig-bundle", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "d3e3e46e9e683e946746219570299ba07506260a" + "reference": "44e3e82867bf4dcf52732dd7e0c83826f9da1095" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d3e3e46e9e683e946746219570299ba07506260a", - "reference": "d3e3e46e9e683e946746219570299ba07506260a", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/44e3e82867bf4dcf52732dd7e0c83826f9da1095", + "reference": "44e3e82867bf4dcf52732dd7e0c83826f9da1095", "shasum": "" }, "require": { @@ -8944,20 +9689,34 @@ ], "description": "Symfony TwigBundle", "homepage": "https://symfony.com", - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/validator", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "3a3a07fe2f42492eccca6771f1a460c9900cd851" + "reference": "2bf1de9d5cac5e5ebc159203c53dcf5b2058d340" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/3a3a07fe2f42492eccca6771f1a460c9900cd851", - "reference": "3a3a07fe2f42492eccca6771f1a460c9900cd851", + "url": "https://api.github.com/repos/symfony/validator/zipball/2bf1de9d5cac5e5ebc159203c53dcf5b2058d340", + "reference": "2bf1de9d5cac5e5ebc159203c53dcf5b2058d340", "shasum": "" }, "require": { @@ -9037,20 +9796,34 @@ ], "description": "Symfony Validator Component", "homepage": "https://symfony.com", - "time": "2020-02-29T10:05:28+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T11:41:10+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "2572839911702b0405479410ea7a1334bfab0b96" + "reference": "5a0c2d93006131a36cf6f767d10e2ca8333b0d4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2572839911702b0405479410ea7a1334bfab0b96", - "reference": "2572839911702b0405479410ea7a1334bfab0b96", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/5a0c2d93006131a36cf6f767d10e2ca8333b0d4a", + "reference": "5a0c2d93006131a36cf6f767d10e2ca8333b0d4a", "shasum": "" }, "require": { @@ -9113,20 +9886,34 @@ "debug", "dump" ], - "time": "2020-02-24T13:10:00+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/var-exporter", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "1a76a943f2af334da13bc9f33f49392fa530eec9" + "reference": "6e4939b084defee0ab60a21e6a02e3a198afd91f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1a76a943f2af334da13bc9f33f49392fa530eec9", - "reference": "1a76a943f2af334da13bc9f33f49392fa530eec9", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/6e4939b084defee0ab60a21e6a02e3a198afd91f", + "reference": "6e4939b084defee0ab60a21e6a02e3a198afd91f", "shasum": "" }, "require": { @@ -9173,7 +9960,21 @@ "instantiate", "serialize" ], - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/webpack-encore-bundle", @@ -9230,16 +10031,16 @@ }, { "name": "symfony/yaml", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "94d005c176db2080e98825d98e01e8b311a97a88" + "reference": "ef166890d821518106da3560086bfcbeb4fadfec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/94d005c176db2080e98825d98e01e8b311a97a88", - "reference": "94d005c176db2080e98825d98e01e8b311a97a88", + "url": "https://api.github.com/repos/symfony/yaml/zipball/ef166890d821518106da3560086bfcbeb4fadfec", + "reference": "ef166890d821518106da3560086bfcbeb4fadfec", "shasum": "" }, "require": { @@ -9285,7 +10086,21 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2020-02-03T10:46:43+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-30T11:41:10+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -10788,16 +11603,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.12.17", + "version": "0.12.18", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "b2c37bda79fdb11d801ce208ce391cffc0f572e6" + "reference": "1ce27fe29c8660a27926127d350d53d80c4d4286" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b2c37bda79fdb11d801ce208ce391cffc0f572e6", - "reference": "b2c37bda79fdb11d801ce208ce391cffc0f572e6", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1ce27fe29c8660a27926127d350d53d80c4d4286", + "reference": "1ce27fe29c8660a27926127d350d53d80c4d4286", "shasum": "" }, "require": { @@ -10823,7 +11638,21 @@ "MIT" ], "description": "PHPStan - PHP Static Analysis Tool", - "time": "2020-03-17T15:39:11+00:00" + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpstan", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2020-03-22T16:51:47+00:00" }, { "name": "phpstan/phpstan-doctrine", @@ -11269,16 +12098,16 @@ }, { "name": "phpunit/phpunit", - "version": "8.5.2", + "version": "8.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0" + "reference": "67750516bc02f300e2742fed2f50177f8f37bedf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/018b6ac3c8ab20916db85fa91bf6465acb64d1e0", - "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/67750516bc02f300e2742fed2f50177f8f37bedf", + "reference": "67750516bc02f300e2742fed2f50177f8f37bedf", "shasum": "" }, "require": { @@ -11348,7 +12177,17 @@ "testing", "xunit" ], - "time": "2020-01-08T08:49:49+00:00" + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-03-31T08:52:04+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -11967,16 +12806,16 @@ }, { "name": "symfony/browser-kit", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "090ce406505149d6852a7c03b0346dec3b8cf612" + "reference": "e4b0dc1b100bf75b5717c5b451397f230a618a42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/090ce406505149d6852a7c03b0346dec3b8cf612", - "reference": "090ce406505149d6852a7c03b0346dec3b8cf612", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/e4b0dc1b100bf75b5717c5b451397f230a618a42", + "reference": "e4b0dc1b100bf75b5717c5b451397f230a618a42", "shasum": "" }, "require": { @@ -12022,20 +12861,34 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2020-02-23T10:00:59+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-28T10:15:50+00:00" }, { "name": "symfony/debug-bundle", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "570c3c69e69f7709f184ee3acbebe45e5ff1adce" + "reference": "dc847e4971b9f76b30e02d421b303d349d5aeed2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/570c3c69e69f7709f184ee3acbebe45e5ff1adce", - "reference": "570c3c69e69f7709f184ee3acbebe45e5ff1adce", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/dc847e4971b9f76b30e02d421b303d349d5aeed2", + "reference": "dc847e4971b9f76b30e02d421b303d349d5aeed2", "shasum": "" }, "require": { @@ -12088,7 +12941,21 @@ ], "description": "Symfony DebugBundle", "homepage": "https://symfony.com", - "time": "2020-01-04T13:00:46+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/dom-crawler", @@ -12153,16 +13020,16 @@ }, { "name": "symfony/maker-bundle", - "version": "v1.14.6", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "bc4df88792fbaaeb275167101dc714218475db5f" + "reference": "31396f2e61803f0e2debbb43ba5aa21acbc6e15a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/bc4df88792fbaaeb275167101dc714218475db5f", - "reference": "bc4df88792fbaaeb275167101dc714218475db5f", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/31396f2e61803f0e2debbb43ba5aa21acbc6e15a", + "reference": "31396f2e61803f0e2debbb43ba5aa21acbc6e15a", "shasum": "" }, "require": { @@ -12217,20 +13084,34 @@ "scaffold", "scaffolding" ], - "time": "2020-03-04T13:57:29+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-04-05T10:50:59+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "a270dbfe54994138a8037937fd5934827b8605bf" + "reference": "6937c1a1590da7c314537b4f3f741c9255a7072e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/a270dbfe54994138a8037937fd5934827b8605bf", - "reference": "a270dbfe54994138a8037937fd5934827b8605bf", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/6937c1a1590da7c314537b4f3f741c9255a7072e", + "reference": "6937c1a1590da7c314537b4f3f741c9255a7072e", "shasum": "" }, "require": { @@ -12282,20 +13163,34 @@ ], "description": "Symfony PHPUnit Bridge", "homepage": "https://symfony.com", - "time": "2020-02-24T14:58:55+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/process", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7" + "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/bf9166bac906c9e69fb7a11d94875e7ced97bcd7", - "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7", + "url": "https://api.github.com/repos/symfony/process/zipball/3e40e87a20eaf83a1db825e1fa5097ae89042db3", + "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3", "shasum": "" }, "require": { @@ -12331,7 +13226,21 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2020-02-07T20:06:44+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/profiler-pack", @@ -12363,16 +13272,16 @@ }, { "name": "symfony/web-profiler-bundle", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "76c21d0137f0b9c6bbbc93ac2672cadfdf2e625a" + "reference": "4c432f5c21c700270819daacf95323302fa8f004" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/76c21d0137f0b9c6bbbc93ac2672cadfdf2e625a", - "reference": "76c21d0137f0b9c6bbbc93ac2672cadfdf2e625a", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/4c432f5c21c700270819daacf95323302fa8f004", + "reference": "4c432f5c21c700270819daacf95323302fa8f004", "shasum": "" }, "require": { @@ -12425,7 +13334,21 @@ ], "description": "Symfony WebProfilerBundle", "homepage": "https://symfony.com", - "time": "2020-02-14T07:42:58+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "theseer/tokenizer", @@ -12486,5 +13409,6 @@ "platform-dev": [], "platform-overrides": { "php": "7.2.9" - } + }, + "plugin-api-version": "1.1.0" } diff --git a/config/packages/fos_rest.yaml b/config/packages/fos_rest.yaml index 915d573b..48a48cc3 100644 --- a/config/packages/fos_rest.yaml +++ b/config/packages/fos_rest.yaml @@ -15,6 +15,8 @@ fos_rest: # enabled: false # service: null routing_loader: + # TODO activate once 2.8 is released + #parse_controller_name: false default_format: json include_format: true # prefix_methods: true diff --git a/config/packages/nelmio_api_doc.yaml b/config/packages/nelmio_api_doc.yaml index 28ca088c..b71a7371 100644 --- a/config/packages/nelmio_api_doc.yaml +++ b/config/packages/nelmio_api_doc.yaml @@ -4,14 +4,20 @@ nelmio_api_doc: names: - { alias: CustomerEditForm, type: App\Form\API\CustomerApiEditForm, groups: [Default, Entity, Customer] } - { alias: CustomerEntity, type: App\Entity\Customer, groups: [Default, Entity, Customer] } + - { alias: CustomerRate, type: App\Entity\CustomerRate, groups: [Default, Entity, CustomerRate] } + - { alias: CustomerRateForm, type: App\Form\API\CustomerRateApiForm, groups: [Default, Entity, CustomerRate] } - { alias: CustomerMetaField, type: App\Entity\CustomerMeta, groups: [Default, Customer] } - { alias: CustomerCollection, type: App\Entity\Customer, groups: [Default, Collection, Customer] } - { alias: ProjectEditForm, type: App\Form\API\ProjectApiEditForm, groups: [Default, Entity, Project] } - { alias: ProjectEntity, type: App\Entity\Project, groups: [Default, Entity, Project] } + - { alias: ProjectRate, type: App\Entity\ProjectRate, groups: [Default, Entity, ProjectRate] } + - { alias: ProjectRateForm, type: App\Form\API\ProjectRateApiForm, groups: [Default, Entity, ProjectRate] } - { alias: ProjectMetaField, type: App\Entity\ProjectMeta, groups: [Default, Project] } - { alias: ProjectCollection, type: App\Entity\Project, groups: [Default, Collection, Project] } - { alias: ActivityEditForm, type: App\Form\API\ActivityApiEditForm, groups: [Default, Entity, Activity] } - { alias: ActivityEntity, type: App\Entity\Activity, groups: [Default, Entity, Activity] } + - { alias: ActivityRate, type: App\Entity\ActivityRate, groups: [Default, Entity, ActivityRate] } + - { alias: ActivityRateForm, type: App\Form\API\ActivityRateApiForm, groups: [Default, Entity, ActivityRate] } - { alias: ActivityMetaField, type: App\Entity\ActivityMeta, groups: [Default, Activity] } - { alias: ActivityCollection, type: App\Entity\Activity, groups: [Default, Collection, Activity] } - { alias: TagEditForm, type: App\Form\API\TagApiEditForm, groups: [Default, Entity, Tag] } @@ -23,6 +29,7 @@ nelmio_api_doc: - { alias: TimesheetSubCollection, type: App\Entity\Timesheet, groups: [Default, Subresource, Timesheet] } - { alias: UserCreateForm, type: App\Form\API\UserApiCreateForm, groups: [Default, Entity, User, User_Entity] } - { alias: UserEditForm, type: App\Form\API\UserApiEditForm, groups: [Default, Entity, User, User_Entity] } + - { alias: User, type: App\Entity\User, groups: [Default, Entity, User] } - { alias: UserEntity, type: App\Entity\User, groups: [Default, Entity, User, User_Entity] } - { alias: UserCollection, type: App\Entity\User, groups: [Default, Collection, User] } - { alias: TeamEditForm, type: App\Form\API\TeamApiEditForm, groups: [Default, Entity, Team] } @@ -42,8 +49,8 @@ nelmio_api_doc: title: Kimai 2 - API Docs description: | JSON API for the Kimai 2 time-tracking software. Read more about its usage in the [API documentation](https://www.kimai.org/documentation/rest-api.html) and then download a [Swagger file](doc.json) for import e.g. in Postman. - Be aware: it is not yet considered stable and BC breaks might happen, but we try to avoid them. - version: '0.4' + Be aware: it is not yet considered stable and BC breaks might happen. + version: '0.5' securityDefinitions: apiUser: type: apiKey diff --git a/config/serializer/App/Entity.ActivityRate.yml b/config/serializer/App/Entity.ActivityRate.yml new file mode 100644 index 00000000..0ac75421 --- /dev/null +++ b/config/serializer/App/Entity.ActivityRate.yml @@ -0,0 +1,21 @@ +App\Entity\ActivityRate: + exclusion_policy: All + custom_accessor_order: [id, rate, internalRate, isFixed, user] + properties: + id: + include: true + groups: [Default] + activity: + exclude: true + user: + include: true + groups: [Default] + rate: + include: true + groups: [Default] + internalRate: + include: true + groups: [Default] + isFixed: + include: true + groups: [Default] diff --git a/config/serializer/App/Entity.CustomerRate.yml b/config/serializer/App/Entity.CustomerRate.yml new file mode 100644 index 00000000..e6bf8fa6 --- /dev/null +++ b/config/serializer/App/Entity.CustomerRate.yml @@ -0,0 +1,21 @@ +App\Entity\CustomerRate: + exclusion_policy: All + custom_accessor_order: [id, rate, internalRate, isFixed, user] + properties: + id: + include: true + groups: [Default] + customer: + exclude: true + user: + include: true + groups: [Default] + rate: + include: true + groups: [Default] + internalRate: + include: true + groups: [Default] + isFixed: + include: true + groups: [Default] diff --git a/config/serializer/App/Entity.ProjectRate.yml b/config/serializer/App/Entity.ProjectRate.yml new file mode 100644 index 00000000..14886799 --- /dev/null +++ b/config/serializer/App/Entity.ProjectRate.yml @@ -0,0 +1,21 @@ +App\Entity\ProjectRate: + exclusion_policy: All + custom_accessor_order: [id, rate, internalRate, isFixed, user] + properties: + id: + include: true + groups: [Default] + project: + exclude: true + user: + include: true + groups: [Default] + rate: + include: true + groups: [Default] + internalRate: + include: true + groups: [Default] + isFixed: + include: true + groups: [Default] diff --git a/config/serializer/App/Entity.Timesheet.yml b/config/serializer/App/Entity.Timesheet.yml index 2c58dbbe..b86e35cf 100644 --- a/config/serializer/App/Entity.Timesheet.yml +++ b/config/serializer/App/Entity.Timesheet.yml @@ -14,6 +14,8 @@ App\Entity\Timesheet: include: true rate: include: true + internalRate: + include: true fixedRate: include: true groups: [Entity] diff --git a/phpstan.neon b/phpstan.neon index 1a2d48d2..bb9d3fa2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -7,8 +7,6 @@ parameters: tmpDir: %rootDir%/../../../var/cache/phpstan autoload_directories: - %rootDir%/../../../src/Migrations - symfony: - container_xml_path: '%rootDir%/../../../var/cache/dev/srcApp_KernelDevDebugContainer.xml' ignoreErrors: - '#Call to an undefined method Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface::scalarNode\(\).#' - '#Call to an undefined method Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface::integerNode\(\).#' diff --git a/src/API/ActivityController.php b/src/API/ActivityController.php index b60614d4..7d16b9e3 100644 --- a/src/API/ActivityController.php +++ b/src/API/ActivityController.php @@ -12,8 +12,11 @@ declare(strict_types=1); namespace App\API; use App\Entity\Activity; +use App\Entity\ActivityRate; use App\Event\ActivityMetaDefinitionEvent; use App\Form\API\ActivityApiEditForm; +use App\Form\API\ActivityRateApiForm; +use App\Repository\ActivityRateRepository; use App\Repository\ActivityRepository; use App\Repository\Query\ActivityQuery; use App\Utils\SearchTerm; @@ -32,6 +35,7 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * @RouteResource("Activity") + * @SWG\Tag(name="Activity") * * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')") */ @@ -49,12 +53,17 @@ class ActivityController extends BaseApiController * @var EventDispatcherInterface */ private $dispatcher; + /** + * @var ActivityRateRepository + */ + private $activityRateRepository; - public function __construct(ViewHandlerInterface $viewHandler, ActivityRepository $repository, EventDispatcherInterface $dispatcher) + public function __construct(ViewHandlerInterface $viewHandler, ActivityRepository $repository, EventDispatcherInterface $dispatcher, ActivityRateRepository $activityRateRepository) { $this->viewHandler = $viewHandler; $this->repository = $repository; $this->dispatcher = $dispatcher; + $this->activityRateRepository = $activityRateRepository; } /** @@ -276,7 +285,7 @@ class ActivityController extends BaseApiController } /** - * Sets the value of a meta-field for an existing activity. + * Sets the value of a meta-field for an existing activity * * @SWG\Response( * response=200, @@ -327,4 +336,166 @@ class ActivityController extends BaseApiController return $this->viewHandler->handle($view); } + + /** + * Returns a collection of all rates for one activity + * + * @SWG\Response( + * response=200, + * description="Returns a collection of activity rate entities", + * @SWG\Schema( + * type="array", + * @SWG\Items(ref="#/definitions/ActivityRate") + * ) + * ) + * @SWG\Parameter( + * name="id", + * in="path", + * type="integer", + * description="The activity whose rates will be returned", + * required=true, + * ) + * + * @ApiSecurity(name="apiUser") + * @ApiSecurity(name="apiToken") + */ + public function getRatesAction(int $id): Response + { + /** @var Activity|null $activity */ + $activity = $this->repository->find($id); + + if (null === $activity) { + throw new NotFoundException(); + } + + if (!$this->isGranted('edit', $activity)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + $rates = $this->activityRateRepository->getRatesForActivity($activity); + + $view = new View($rates, 200); + $view->getContext()->setGroups(['Default', 'Entity', 'ActivityRate']); + + return $this->viewHandler->handle($view); + } + + /** + * Deletes one rate for an activity + * + * @SWG\Delete( + * @SWG\Response( + * response=204, + * description="Returns no content: 204 on successful delete" + * ) + * ) + * @SWG\Parameter( + * name="id", + * in="path", + * type="integer", + * description="The activity whose rate will be removed", + * required=true, + * ) + * @SWG\Parameter( + * name="rateId", + * in="path", + * type="integer", + * description="The rate to remove", + * required=true, + * ) + * + * @ApiSecurity(name="apiUser") + * @ApiSecurity(name="apiToken") + */ + public function deleteRateAction(string $id, string $rateId): Response + { + /** @var Activity|null $activity */ + $activity = $this->repository->find($id); + + if (null === $activity) { + throw new NotFoundException(); + } + + if (!$this->isGranted('edit', $activity)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + /** @var ActivityRate|null $rate */ + $rate = $this->activityRateRepository->find($rateId); + + if (null === $rate || $rate->getActivity() !== $activity) { + throw new NotFoundException(); + } + + $this->activityRateRepository->deleteRate($rate); + + $view = new View(null, Response::HTTP_NO_CONTENT); + + return $this->viewHandler->handle($view); + } + + /** + * Adds a new rate to an activity + * + * @SWG\Post( + * @SWG\Response( + * response=200, + * description="Returns the new created rate", + * @SWG\Schema(ref="#/definitions/ActivityRate") + * ) + * ) + * @SWG\Parameter( + * name="id", + * in="path", + * type="integer", + * description="The activity to add the rate for", + * required=true, + * ) + * @SWG\Parameter( + * name="body", + * in="body", + * required=true, + * @SWG\Schema(ref="#/definitions/ActivityRateForm") + * ) + * + * @ApiSecurity(name="apiUser") + * @ApiSecurity(name="apiToken") + */ + public function postRateAction(int $id, Request $request): Response + { + /** @var Activity|null $activity */ + $activity = $this->repository->find($id); + + if (null === $activity) { + throw new NotFoundException(); + } + + if (!$this->isGranted('edit', $activity)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + $rate = new ActivityRate(); + $rate->setActivity($activity); + + $form = $this->createForm(ActivityRateApiForm::class, $rate, [ + 'method' => 'POST', + ]); + + $form->setData($rate); + $form->submit($request->request->all(), false); + + if (false === $form->isValid()) { + $view = new View($form, Response::HTTP_OK); + $view->getContext()->setGroups(['Default', 'Entity', 'ActivityRate']); + + return $this->viewHandler->handle($view); + } + + $this->activityRateRepository->saveRate($rate); + + $view = new View($rate, Response::HTTP_OK); + $view->getContext()->setGroups(['Default', 'Entity', 'ActivityRate']); + + return $this->viewHandler->handle($view); + } } diff --git a/src/API/ConfigurationController.php b/src/API/ConfigurationController.php index 8ed79c04..b8df98fd 100644 --- a/src/API/ConfigurationController.php +++ b/src/API/ConfigurationController.php @@ -25,6 +25,8 @@ use Swagger\Annotations as SWG; use Symfony\Component\HttpFoundation\Response; /** + * @SWG\Tag(name="Default") + * * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')") */ final class ConfigurationController extends BaseApiController diff --git a/src/API/CustomerController.php b/src/API/CustomerController.php index 39c358d1..75cdaaca 100644 --- a/src/API/CustomerController.php +++ b/src/API/CustomerController.php @@ -12,9 +12,12 @@ declare(strict_types=1); namespace App\API; use App\Entity\Customer; +use App\Entity\CustomerRate; use App\Entity\User; use App\Event\CustomerMetaDefinitionEvent; use App\Form\API\CustomerApiEditForm; +use App\Form\API\CustomerRateApiForm; +use App\Repository\CustomerRateRepository; use App\Repository\CustomerRepository; use App\Repository\Query\CustomerQuery; use App\Utils\SearchTerm; @@ -33,6 +36,7 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * @RouteResource("Customer") + * @SWG\Tag(name="Customer") * * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')") */ @@ -50,12 +54,17 @@ class CustomerController extends BaseApiController * @var EventDispatcherInterface */ private $dispatcher; + /** + * @var CustomerRateRepository + */ + private $customerRateRepository; - public function __construct(ViewHandlerInterface $viewHandler, CustomerRepository $repository, EventDispatcherInterface $dispatcher) + public function __construct(ViewHandlerInterface $viewHandler, CustomerRepository $repository, EventDispatcherInterface $dispatcher, CustomerRateRepository $customerRateRepository) { $this->viewHandler = $viewHandler; $this->repository = $repository; $this->dispatcher = $dispatcher; + $this->customerRateRepository = $customerRateRepository; } /** @@ -66,7 +75,7 @@ class CustomerController extends BaseApiController * description="Returns a collection of customer entities", * @SWG\Schema( * type="array", - * @SWG\Items(ref="#/definitions/CustomerCollection") + * @SWG\Items(ref="#/definitions/CustomerEntity") * ) * ) * @Rest\QueryParam(name="visible", requirements="\d+", strict=true, nullable=true, description="Visibility status to filter activities (1=visible, 2=hidden, 3=both)") @@ -249,7 +258,7 @@ class CustomerController extends BaseApiController } /** - * Sets the value of a meta-field for an existing customer. + * Sets the value of a meta-field for an existing customer * * @SWG\Response( * response=200, @@ -300,4 +309,166 @@ class CustomerController extends BaseApiController return $this->viewHandler->handle($view); } + + /** + * Returns a collection of all rates for one customer + * + * @SWG\Response( + * response=200, + * description="Returns a collection of customer rate entities", + * @SWG\Schema( + * type="array", + * @SWG\Items(ref="#/definitions/CustomerRate") + * ) + * ) + * @SWG\Parameter( + * name="id", + * in="path", + * type="integer", + * description="The customer whose rates will be returned", + * required=true, + * ) + * + * @ApiSecurity(name="apiUser") + * @ApiSecurity(name="apiToken") + */ + public function getRatesAction(int $id): Response + { + /** @var Customer|null $customer */ + $customer = $this->repository->find($id); + + if (null === $customer) { + throw new NotFoundException(); + } + + if (!$this->isGranted('edit', $customer)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + $rates = $this->customerRateRepository->getRatesForCustomer($customer); + + $view = new View($rates, 200); + $view->getContext()->setGroups(['Default', 'Entity', 'CustomerRate']); + + return $this->viewHandler->handle($view); + } + + /** + * Deletes one rate for an customer + * + * @SWG\Delete( + * @SWG\Response( + * response=204, + * description="Returns no content: 204 on successful delete" + * ) + * ) + * @SWG\Parameter( + * name="id", + * in="path", + * type="integer", + * description="The customer whose rate will be removed", + * required=true, + * ) + * @SWG\Parameter( + * name="rateId", + * in="path", + * type="integer", + * description="The rate to remove", + * required=true, + * ) + * + * @ApiSecurity(name="apiUser") + * @ApiSecurity(name="apiToken") + */ + public function deleteRateAction(string $id, string $rateId): Response + { + /** @var Customer|null $customer */ + $customer = $this->repository->find($id); + + if (null === $customer) { + throw new NotFoundException(); + } + + if (!$this->isGranted('edit', $customer)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + /** @var CustomerRate|null $rate */ + $rate = $this->customerRateRepository->find($rateId); + + if (null === $rate || $rate->getCustomer() !== $customer) { + throw new NotFoundException(); + } + + $this->customerRateRepository->deleteRate($rate); + + $view = new View(null, Response::HTTP_NO_CONTENT); + + return $this->viewHandler->handle($view); + } + + /** + * Adds a new rate to a customer + * + * @SWG\Post( + * @SWG\Response( + * response=200, + * description="Returns the new created rate", + * @SWG\Schema(ref="#/definitions/CustomerRate") + * ) + * ) + * @SWG\Parameter( + * name="id", + * in="path", + * type="integer", + * description="The customer to add the rate for", + * required=true, + * ) + * @SWG\Parameter( + * name="body", + * in="body", + * required=true, + * @SWG\Schema(ref="#/definitions/CustomerRateForm") + * ) + * + * @ApiSecurity(name="apiUser") + * @ApiSecurity(name="apiToken") + */ + public function postRateAction(int $id, Request $request): Response + { + /** @var Customer|null $customer */ + $customer = $this->repository->find($id); + + if (null === $customer) { + throw new NotFoundException(); + } + + if (!$this->isGranted('edit', $customer)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + $rate = new CustomerRate(); + $rate->setCustomer($customer); + + $form = $this->createForm(CustomerRateApiForm::class, $rate, [ + 'method' => 'POST', + ]); + + $form->setData($rate); + $form->submit($request->request->all(), false); + + if (false === $form->isValid()) { + $view = new View($form, Response::HTTP_OK); + $view->getContext()->setGroups(['Default', 'Entity', 'CustomerRate']); + + return $this->viewHandler->handle($view); + } + + $this->customerRateRepository->saveRate($rate); + + $view = new View($rate, Response::HTTP_OK); + $view->getContext()->setGroups(['Default', 'Entity', 'CustomerRate']); + + return $this->viewHandler->handle($view); + } } diff --git a/src/API/ProjectController.php b/src/API/ProjectController.php index a2f10356..13a6dafd 100644 --- a/src/API/ProjectController.php +++ b/src/API/ProjectController.php @@ -11,10 +11,14 @@ declare(strict_types=1); namespace App\API; +use App\Entity\Customer; use App\Entity\Project; +use App\Entity\ProjectRate; use App\Entity\User; use App\Event\ProjectMetaDefinitionEvent; use App\Form\API\ProjectApiEditForm; +use App\Form\API\ProjectRateApiForm; +use App\Repository\ProjectRateRepository; use App\Repository\ProjectRepository; use App\Repository\Query\ProjectQuery; use App\Timesheet\UserDateTimeFactory; @@ -35,6 +39,7 @@ use Symfony\Component\Validator\Constraints; /** * @RouteResource("Project") + * @SWG\Tag(name="Project") * * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')") */ @@ -56,13 +61,18 @@ class ProjectController extends BaseApiController * @var UserDateTimeFactory */ private $dateTime; + /** + * @var ProjectRateRepository + */ + private $projectRateRepository; - public function __construct(ViewHandlerInterface $viewHandler, ProjectRepository $repository, EventDispatcherInterface $dispatcher, UserDateTimeFactory $dateTime) + public function __construct(ViewHandlerInterface $viewHandler, ProjectRepository $repository, EventDispatcherInterface $dispatcher, UserDateTimeFactory $dateTime, ProjectRateRepository $projectRateRepository) { $this->viewHandler = $viewHandler; $this->repository = $repository; $this->dispatcher = $dispatcher; $this->dateTime = $dateTime; + $this->projectRateRepository = $projectRateRepository; } /** @@ -299,7 +309,7 @@ class ProjectController extends BaseApiController } /** - * Sets the value of a meta-field for an existing project. + * Sets the value of a meta-field for an existing project * * @SWG\Response( * response=200, @@ -350,4 +360,166 @@ class ProjectController extends BaseApiController return $this->viewHandler->handle($view); } + + /** + * Returns a collection of all rates for one project + * + * @SWG\Response( + * response=200, + * description="Returns a collection of project rate entities", + * @SWG\Schema( + * type="array", + * @SWG\Items(ref="#/definitions/ProjectRate") + * ) + * ) + * @SWG\Parameter( + * name="id", + * in="path", + * type="integer", + * description="The project whose rates will be returned", + * required=true, + * ) + * + * @ApiSecurity(name="apiUser") + * @ApiSecurity(name="apiToken") + */ + public function getRatesAction(int $id): Response + { + /** @var Project|null $project */ + $project = $this->repository->find($id); + + if (null === $project) { + throw new NotFoundException(); + } + + if (!$this->isGranted('edit', $project)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + $rates = $this->projectRateRepository->getRatesForProject($project); + + $view = new View($rates, 200); + $view->getContext()->setGroups(['Default', 'Entity', 'ProjectRate']); + + return $this->viewHandler->handle($view); + } + + /** + * Deletes one rate for an project + * + * @SWG\Delete( + * @SWG\Response( + * response=204, + * description="Returns no content: 204 on successful delete" + * ) + * ) + * @SWG\Parameter( + * name="id", + * in="path", + * type="integer", + * description="The project whose rate will be removed", + * required=true, + * ) + * @SWG\Parameter( + * name="rateId", + * in="path", + * type="integer", + * description="The rate to remove", + * required=true, + * ) + * + * @ApiSecurity(name="apiUser") + * @ApiSecurity(name="apiToken") + */ + public function deleteRateAction(string $id, string $rateId): Response + { + /** @var Project|null $project */ + $project = $this->repository->find($id); + + if (null === $project) { + throw new NotFoundException(); + } + + if (!$this->isGranted('edit', $project)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + /** @var ProjectRate|null $rate */ + $rate = $this->projectRateRepository->find($rateId); + + if (null === $rate || $rate->getProject() !== $project) { + throw new NotFoundException(); + } + + $this->projectRateRepository->deleteRate($rate); + + $view = new View(null, Response::HTTP_NO_CONTENT); + + return $this->viewHandler->handle($view); + } + + /** + * Adds a new rate to an project + * + * @SWG\Post( + * @SWG\Response( + * response=200, + * description="Returns the new created rate", + * @SWG\Schema(ref="#/definitions/ProjectRate") + * ) + * ) + * @SWG\Parameter( + * name="id", + * in="path", + * type="integer", + * description="The project to add the rate for", + * required=true, + * ) + * @SWG\Parameter( + * name="body", + * in="body", + * required=true, + * @SWG\Schema(ref="#/definitions/ProjectRateForm") + * ) + * + * @ApiSecurity(name="apiUser") + * @ApiSecurity(name="apiToken") + */ + public function postRateAction(int $id, Request $request): Response + { + /** @var Project|null $project */ + $project = $this->repository->find($id); + + if (null === $project) { + throw new NotFoundException(); + } + + if (!$this->isGranted('edit', $project)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + $rate = new ProjectRate(); + $rate->setProject($project); + + $form = $this->createForm(ProjectRateApiForm::class, $rate, [ + 'method' => 'POST', + ]); + + $form->setData($rate); + $form->submit($request->request->all(), false); + + if (false === $form->isValid()) { + $view = new View($form, Response::HTTP_OK); + $view->getContext()->setGroups(['Default', 'Entity', 'ProjectRate']); + + return $this->viewHandler->handle($view); + } + + $this->projectRateRepository->saveRate($rate); + + $view = new View($rate, Response::HTTP_OK); + $view->getContext()->setGroups(['Default', 'Entity', 'ProjectRate']); + + return $this->viewHandler->handle($view); + } } diff --git a/src/API/StatusController.php b/src/API/StatusController.php index f92558e9..25c8db2a 100644 --- a/src/API/StatusController.php +++ b/src/API/StatusController.php @@ -20,6 +20,9 @@ use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use Swagger\Annotations as SWG; use Symfony\Component\HttpFoundation\Response; +/** + * @SWG\Tag(name="Default") + */ class StatusController extends BaseApiController { /** diff --git a/src/API/TagController.php b/src/API/TagController.php index 04245f00..2d48989d 100644 --- a/src/API/TagController.php +++ b/src/API/TagController.php @@ -28,6 +28,7 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * @RouteResource("Tag") + * @SWG\Tag(name="Tag") * * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')") */ diff --git a/src/API/TeamController.php b/src/API/TeamController.php index df1531d2..252af08b 100644 --- a/src/API/TeamController.php +++ b/src/API/TeamController.php @@ -33,6 +33,7 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; /** * @RouteResource("Team") + * @SWG\Tag(name="Team") * * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')") */ diff --git a/src/API/TimesheetController.php b/src/API/TimesheetController.php index d8b8e6e2..97315265 100644 --- a/src/API/TimesheetController.php +++ b/src/API/TimesheetController.php @@ -45,6 +45,7 @@ use Symfony\Component\Validator\Validator\ValidatorInterface; /** * @RouteResource("Timesheet") + * @SWG\Tag(name="Timesheet") * * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')") */ @@ -169,8 +170,9 @@ class TimesheetController extends BaseApiController if (!empty($customers)) { $query->setCustomers($customers); } - } elseif (!empty($customer = $paramFetcher->get('customer'))) { - @trigger_error('Timesheet API parameter "customer" is deprecated and will be removed with 2.0, use "customers" instead', E_USER_DEPRECATED); + } + + if (!empty($customer = $paramFetcher->get('customer'))) { $query->addCustomer($customer); } @@ -181,8 +183,9 @@ class TimesheetController extends BaseApiController if (!empty($projects)) { $query->setProjects($projects); } - } elseif (!empty($project = $paramFetcher->get('project'))) { - @trigger_error('Timesheet API parameter "project" is deprecated and will be removed with 2.0, use "projects" instead', E_USER_DEPRECATED); + } + + if (!empty($project = $paramFetcher->get('project'))) { $query->addProject($project); } @@ -193,8 +196,9 @@ class TimesheetController extends BaseApiController if (!empty($activities)) { $query->setActivities($activities); } - } elseif (!empty($activity = $paramFetcher->get('activity'))) { - @trigger_error('Timesheet API parameter "activity" is deprecated and will be removed with 2.0, use "activities" instead', E_USER_DEPRECATED); + } + + if (!empty($activity = $paramFetcher->get('activity'))) { $query->addActivity($activity); } diff --git a/src/API/UserController.php b/src/API/UserController.php index 1d99ad76..73da67c9 100644 --- a/src/API/UserController.php +++ b/src/API/UserController.php @@ -33,6 +33,7 @@ use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; /** * @RouteResource("User") + * @SWG\Tag(name="User") * * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')") */ diff --git a/src/Command/CreateReleaseCommand.php b/src/Command/CreateReleaseCommand.php index e5b584f0..0bbc0ea0 100644 --- a/src/Command/CreateReleaseCommand.php +++ b/src/Command/CreateReleaseCommand.php @@ -125,7 +125,8 @@ class CreateReleaseCommand extends Command 'Dockerfile', 'phpunit.xml.dist', 'webpack.config.js', - 'assets/', + // this seems to be required, see https://github.com/kevinpapst/kimai2/issues/1586 + //'assets/', 'tests/', 'var/cache/*', 'var/data/kimai_test.sqlite', diff --git a/src/Controller/AbstractController.php b/src/Controller/AbstractController.php index 62c3cfa2..f365ea01 100644 --- a/src/Controller/AbstractController.php +++ b/src/Controller/AbstractController.php @@ -18,6 +18,7 @@ use Symfony\Contracts\Translation\TranslatorInterface; /** * The abstract base controller. + * @method null|User getUser() */ abstract class AbstractController extends BaseAbstractController implements ServiceSubscriberInterface { @@ -42,14 +43,6 @@ abstract class AbstractController extends BaseAbstractController implements Serv return $this->container->get('logger'); } - /** - * @return User|null - */ - protected function getUser() - { - return parent::getUser(); - } - /** * Adds a "successful" flash message to the stack. * diff --git a/src/Controller/ActivityController.php b/src/Controller/ActivityController.php index afb0673d..2cbc9ec6 100644 --- a/src/Controller/ActivityController.php +++ b/src/Controller/ActivityController.php @@ -134,25 +134,6 @@ final class ActivityController extends AbstractController ]); } - /** - * @Route(path="/{id}/rate_delete/{rate}", name="admin_activity_rate_delete", methods={"GET"}) - * @Security("is_granted('edit', activity)") - */ - public function deleteRateAction(Activity $activity, ActivityRate $rate, ActivityRateRepository $repository) - { - if ($rate->getActivity() !== $activity) { - $this->flashError('action.delete.error', ['%reason%' => 'Invalid activity']); - } else { - try { - $repository->deleteRate($rate); - } catch (\Exception $ex) { - $this->flashError('action.delete.error', ['%reason%' => $ex->getMessage()]); - } - } - - return $this->redirectToRoute('activity_details', ['id' => $activity->getId()]); - } - /** * @Route(path="/{id}/rate", name="admin_activity_rate_add", methods={"GET", "POST"}) * @Security("is_granted('edit', activity)") diff --git a/src/Controller/CustomerController.php b/src/Controller/CustomerController.php index e0005368..9dc09d9e 100644 --- a/src/Controller/CustomerController.php +++ b/src/Controller/CustomerController.php @@ -315,25 +315,6 @@ final class CustomerController extends AbstractController ]); } - /** - * @Route(path="/{id}/rate_delete/{rate}", name="admin_customer_rate_delete", methods={"GET"}) - * @Security("is_granted('edit', customer)") - */ - public function deleteRateAction(Customer $customer, CustomerRate $rate, CustomerRateRepository $repository) - { - if ($rate->getCustomer() !== $customer) { - $this->flashError('action.delete.error', ['%reason%' => 'Invalid customer']); - } else { - try { - $repository->deleteRate($rate); - } catch (\Exception $ex) { - $this->flashError('action.delete.error', ['%reason%' => $ex->getMessage()]); - } - } - - return $this->redirectToRoute('customer_details', ['id' => $customer->getId()]); - } - /** * @Route(path="/{id}/rate", name="admin_customer_rate_add", methods={"GET", "POST"}) * @Security("is_granted('edit', customer)") diff --git a/src/Controller/ProfileController.php b/src/Controller/ProfileController.php index 8401875c..c2c696d8 100644 --- a/src/Controller/ProfileController.php +++ b/src/Controller/ProfileController.php @@ -58,7 +58,6 @@ class ProfileController extends AbstractController } /** - * @Route(path="/", name="fos_user_profile_show", methods={"GET"}) * @Route(path="/", name="my_profile", methods={"GET"}) */ public function profileAction() diff --git a/src/Controller/ProjectController.php b/src/Controller/ProjectController.php index aaf1c1df..0654f477 100644 --- a/src/Controller/ProjectController.php +++ b/src/Controller/ProjectController.php @@ -314,25 +314,6 @@ final class ProjectController extends AbstractController ]); } - /** - * @Route(path="/{id}/rate_delete/{rate}", name="admin_project_rate_delete", methods={"GET"}) - * @Security("is_granted('edit', project)") - */ - public function deleteRateAction(Project $project, ProjectRate $rate, ProjectRateRepository $repository) - { - if ($rate->getProject() !== $project) { - $this->flashError('action.delete.error', ['%reason%' => 'Invalid project']); - } else { - try { - $repository->deleteRate($rate); - } catch (\Exception $ex) { - $this->flashError('action.delete.error', ['%reason%' => $ex->getMessage()]); - } - } - - return $this->redirectToRoute('project_details', ['id' => $project->getId()]); - } - /** * @Route(path="/{id}/rate", name="admin_project_rate_add", methods={"GET", "POST"}) * @Security("is_granted('edit', project)") diff --git a/src/Entity/Activity.php b/src/Entity/Activity.php index d5d1d32a..8e95014d 100644 --- a/src/Entity/Activity.php +++ b/src/Entity/Activity.php @@ -38,7 +38,6 @@ class Activity implements EntityWithMetaFields * @ORM\GeneratedValue(strategy="IDENTITY") */ private $id; - /** * @var Project|null * @@ -46,25 +45,20 @@ class Activity implements EntityWithMetaFields * @ORM\JoinColumn(onDelete="CASCADE") */ private $project; - /** * @var string * - * Do not increase length to more than 190 chars, otherwise "Index column size too large." will be triggered. - * * @ORM\Column(name="name", type="string", length=150, nullable=false) * @Assert\NotBlank() - * @Assert\Length(min=2, max=150) + * @Assert\Length(min=2, max=150, allowEmptyString=false) */ private $name; - /** * @var string * * @ORM\Column(name="comment", type="text", nullable=true) */ private $comment; - /** * @var bool * diff --git a/src/Entity/Configuration.php b/src/Entity/Configuration.php index 6f559dbf..68c94ce2 100644 --- a/src/Entity/Configuration.php +++ b/src/Entity/Configuration.php @@ -37,7 +37,8 @@ class Configuration * @var string * * @ORM\Column(name="name", type="string", length=100, nullable=false) - * @Assert\Length(min=2, max=100) + * @Assert\NotNull() + * @Assert\Length(min=2, max=100, allowEmptyString=false) */ private $name; diff --git a/src/Entity/Customer.php b/src/Entity/Customer.php index a92dba92..ed3b43fe 100644 --- a/src/Entity/Customer.php +++ b/src/Entity/Customer.php @@ -36,18 +36,14 @@ class Customer implements EntityWithMetaFields * @ORM\GeneratedValue(strategy="IDENTITY") */ private $id; - /** * @var string * - * Do not increase length to more than 190 chars, otherwise "Index column size too large." will be triggered. - * * @ORM\Column(name="name", type="string", length=150, nullable=false) * @Assert\NotBlank() - * @Assert\Length(min=2, max=150) + * @Assert\Length(min=2, max=150, allowEmptyString=false) */ private $name; - /** * @var string * @@ -55,14 +51,12 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=50) */ private $number; - /** * @var string * * @ORM\Column(name="comment", type="text", nullable=true) */ private $comment; - /** * @var bool * @@ -70,7 +64,6 @@ class Customer implements EntityWithMetaFields * @Assert\NotNull() */ private $visible = true; - /** * @var string * @@ -78,7 +71,6 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=255) */ private $company; - /** * @var string * @@ -86,7 +78,6 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=50) */ private $vatId; - /** * @var string * @@ -94,14 +85,12 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=255) */ private $contact; - /** * @var string * * @ORM\Column(name="address", type="text", nullable=true) */ private $address; - /** * @var string * @@ -110,7 +99,6 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=2) */ private $country; - /** * @var string * @@ -119,7 +107,6 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=3) */ private $currency = self::DEFAULT_CURRENCY; - /** * @var string * @@ -127,7 +114,6 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=255) */ private $phone; - /** * @var string * @@ -135,7 +121,6 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=255) */ private $fax; - /** * @var string * @@ -143,7 +128,6 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=255) */ private $mobile; - /** * @var string * @@ -153,7 +137,6 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=254) */ private $email; - /** * @var string * @@ -161,7 +144,6 @@ class Customer implements EntityWithMetaFields * @Assert\Length(max=255) */ private $homepage; - /** * @var string * @@ -183,7 +165,6 @@ class Customer implements EntityWithMetaFields * @ORM\OneToMany(targetEntity="App\Entity\CustomerMeta", mappedBy="customer", cascade={"persist"}) */ private $meta; - /** * @var Team[]|ArrayCollection * diff --git a/src/Entity/InvoiceTemplate.php b/src/Entity/InvoiceTemplate.php index 19e522aa..c020f4f3 100644 --- a/src/Entity/InvoiceTemplate.php +++ b/src/Entity/InvoiceTemplate.php @@ -36,7 +36,7 @@ class InvoiceTemplate * * @ORM\Column(name="name", type="string", length=60, nullable=false) * @Assert\NotBlank() - * @Assert\Length(min=1, max=60) + * @Assert\Length(min=1, max=60, allowEmptyString=false) */ private $name; diff --git a/src/Entity/MetaTableTypeTrait.php b/src/Entity/MetaTableTypeTrait.php index 07f34c01..1dcdf9d1 100644 --- a/src/Entity/MetaTableTypeTrait.php +++ b/src/Entity/MetaTableTypeTrait.php @@ -31,7 +31,8 @@ trait MetaTableTypeTrait * @var string * * @ORM\Column(name="name", type="string", length=50, nullable=false) - * @Assert\Length(min=2, max=50) + * @Assert\NotNull() + * @Assert\Length(min=2, max=50, allowEmptyString=false) */ private $name; diff --git a/src/Entity/Project.php b/src/Entity/Project.php index 7d27367a..6d655d3e 100644 --- a/src/Entity/Project.php +++ b/src/Entity/Project.php @@ -48,11 +48,9 @@ class Project implements EntityWithMetaFields /** * @var string * - * Do not increase length to more than 190 chars, otherwise "Index column size too large." will be triggered. - * * @ORM\Column(name="name", type="string", length=150, nullable=false) * @Assert\NotNull() - * @Assert\Length(min=2, max=150) + * @Assert\Length(min=2, max=150, allowEmptyString=false) */ private $name; /** diff --git a/src/Entity/Rate.php b/src/Entity/Rate.php index aac5581f..27aa0fdd 100644 --- a/src/Entity/Rate.php +++ b/src/Entity/Rate.php @@ -10,6 +10,7 @@ namespace App\Entity; use Doctrine\ORM\Mapping as ORM; +use Swagger\Annotations as SWG; use Symfony\Component\Validator\Constraints as Assert; trait Rate @@ -27,6 +28,7 @@ trait Rate * * @ORM\ManyToOne(targetEntity="App\Entity\User") * @ORM\JoinColumn(onDelete="CASCADE", nullable=true) + * @SWG\Property(ref="#/definitions/User") */ private $user; /** @@ -36,6 +38,12 @@ trait Rate * @Assert\GreaterThanOrEqual(0) */ private $rate = 0.00; + /** + * @var float|null + * + * @ORM\Column(name="internal_rate", type="float", nullable=true) + */ + private $internalRate; /** * @var bool * @@ -78,6 +86,18 @@ trait Rate return $this->rate; } + public function setInternalRate(?float $rate): self + { + $this->internalRate = $rate; + + return $this; + } + + public function getInternalRate(): ?float + { + return $this->internalRate; + } + public function isFixed(): bool { return $this->isFixed; diff --git a/src/Entity/RateInterface.php b/src/Entity/RateInterface.php index dbe6527e..6a00b3d0 100644 --- a/src/Entity/RateInterface.php +++ b/src/Entity/RateInterface.php @@ -9,12 +9,17 @@ namespace App\Entity; +/** + * @internal + */ interface RateInterface { public function getUser(): ?User; public function getRate(): float; + public function getInternalRate(): ?float; + public function isFixed(): bool; public function getScore(): int; diff --git a/src/Entity/Tag.php b/src/Entity/Tag.php index 2add9e9e..d83b4516 100644 --- a/src/Entity/Tag.php +++ b/src/Entity/Tag.php @@ -39,7 +39,7 @@ class Tag * * @ORM\Column(name="name", type="string", length=100, nullable=false) * @Assert\NotBlank() - * @Assert\Length(min=2, max=100) + * @Assert\Length(min=2, max=100, allowEmptyString=false) * @Assert\Regex(pattern="/,/",match=false,message="Tag name cannot contain comma") */ private $name; diff --git a/src/Entity/Team.php b/src/Entity/Team.php index c8aeae78..f3b76710 100644 --- a/src/Entity/Team.php +++ b/src/Entity/Team.php @@ -39,7 +39,7 @@ class Team * * @ORM\Column(name="name", type="string", length=100, nullable=false) * @Assert\NotBlank() - * @Assert\Length(min=2, max=100) + * @Assert\Length(min=2, max=100, allowEmptyString=false) */ private $name; /** diff --git a/src/Entity/Timesheet.php b/src/Entity/Timesheet.php index 6d79706e..8f49d53b 100644 --- a/src/Entity/Timesheet.php +++ b/src/Entity/Timesheet.php @@ -131,7 +131,14 @@ class Timesheet implements EntityWithMetaFields, ExportItemInterface private $rate = 0.00; /** - * @var float + * @var float|null + * + * @ORM\Column(name="internal_rate", type="float", nullable=true) + */ + private $internalRate; + + /** + * @var float|null * * @ORM\Column(name="fixed_rate", type="float", nullable=true) * @Assert\GreaterThanOrEqual(0) @@ -363,6 +370,18 @@ class Timesheet implements EntityWithMetaFields, ExportItemInterface return $this->rate; } + public function setInternalRate(?float $rate): Timesheet + { + $this->internalRate = $rate; + + return $this; + } + + public function getInternalRate(): ?float + { + return $this->internalRate; + } + /** * @param Tag $tag * @return Timesheet diff --git a/src/Entity/UserPreference.php b/src/Entity/UserPreference.php index d551e514..97bd767a 100644 --- a/src/Entity/UserPreference.php +++ b/src/Entity/UserPreference.php @@ -27,6 +27,7 @@ use Symfony\Component\Validator\Constraints as Assert; class UserPreference { public const HOURLY_RATE = 'hourly_rate'; + public const INTERNAL_RATE = 'internal_rate'; public const SKIN = 'skin'; public const LOCALE = 'language'; public const TIMEZONE = 'timezone'; @@ -51,7 +52,8 @@ class UserPreference * @var string * * @ORM\Column(name="name", type="string", length=50, nullable=false) - * @Assert\Length(min=2, max=50) + * @Assert\NotNull() + * @Assert\Length(min=2, max=50, allowEmptyString=false) */ private $name; /** diff --git a/src/Event/UserPreferenceEvent.php b/src/Event/UserPreferenceEvent.php index 89bf7ba8..0512faf0 100644 --- a/src/Event/UserPreferenceEvent.php +++ b/src/Event/UserPreferenceEvent.php @@ -67,7 +67,7 @@ final class UserPreferenceEvent extends Event foreach ($this->preferences as $pref) { if (strtolower($pref->getName()) === strtolower($preference->getName())) { throw new \InvalidArgumentException( - 'Cannot add preference, one with the name "' . $preference->getName() . '" is already existing' + 'Cannot add user preference, one with the name "' . $preference->getName() . '" is already existing' ); } } diff --git a/src/EventSubscriber/RegistrationSubscriber.php b/src/EventSubscriber/RegistrationSubscriber.php index 636825dc..3481905a 100644 --- a/src/EventSubscriber/RegistrationSubscriber.php +++ b/src/EventSubscriber/RegistrationSubscriber.php @@ -14,6 +14,8 @@ use FOS\UserBundle\Event\FormEvent; use FOS\UserBundle\FOSUserEvents; use FOS\UserBundle\Model\UserManagerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** * This class intercepts the registration to make sure: @@ -21,19 +23,21 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; * - the first-ever registered user will get the SUPER_ADMIN role * - the user uses the current request locale as initial language setting */ -class RegistrationSubscriber implements EventSubscriberInterface +final class RegistrationSubscriber implements EventSubscriberInterface { /** * @var UserManagerInterface */ - protected $userManager; - + private $userManager; /** - * @param UserManagerInterface $userManager + * @var UrlGeneratorInterface */ - public function __construct(UserManagerInterface $userManager) + private $router; + + public function __construct(UserManagerInterface $userManager, UrlGeneratorInterface $router) { $this->userManager = $userManager; + $this->router = $router; } /** @@ -42,7 +46,8 @@ class RegistrationSubscriber implements EventSubscriberInterface public static function getSubscribedEvents(): array { return [ - FOSUserEvents::REGISTRATION_SUCCESS => ['onRegistrationSuccess', 200] + FOSUserEvents::REGISTRATION_SUCCESS => ['onRegistrationSuccess', 200], + FOSUserEvents::RESETTING_RESET_SUCCESS => ['onResettingSuccess', 200], ]; } @@ -62,4 +67,12 @@ class RegistrationSubscriber implements EventSubscriberInterface $user->setLanguage($event->getRequest()->getLocale()); $user->setRoles($roles); } + + /** + * @param FormEvent $event + */ + public function onResettingSuccess(FormEvent $event) + { + $event->setResponse(new RedirectResponse($this->router->generate('my_profile'))); + } } diff --git a/src/EventSubscriber/UserPreferenceSubscriber.php b/src/EventSubscriber/UserPreferenceSubscriber.php index ba51a19c..3198ccbd 100644 --- a/src/EventSubscriber/UserPreferenceSubscriber.php +++ b/src/EventSubscriber/UserPreferenceSubscriber.php @@ -111,6 +111,15 @@ class UserPreferenceSubscriber implements EventSubscriberInterface ->setOptions($hourlyRateOptions) ->addConstraint(new Range(['min' => 0])), + (new UserPreference()) + ->setName(UserPreference::INTERNAL_RATE) + ->setValue(null) + ->setOrder(101) + ->setType(MoneyType::class) + ->setEnabled($enableHourlyRate) + ->setOptions(array_merge($hourlyRateOptions, ['label' => 'label.rate_internal', 'required' => false])) + ->addConstraint(new Range(['min' => 0])), + (new UserPreference()) ->setName(UserPreference::TIMEZONE) ->setValue($this->getDefaultTimezone()) diff --git a/src/Export/Base/AbstractSpreadsheetRenderer.php b/src/Export/Base/AbstractSpreadsheetRenderer.php index b2b2ed55..16f57c8d 100644 --- a/src/Export/Base/AbstractSpreadsheetRenderer.php +++ b/src/Export/Base/AbstractSpreadsheetRenderer.php @@ -70,6 +70,7 @@ abstract class AbstractSpreadsheetRenderer 'end' => [], 'duration' => [], 'rate' => [], + 'rate_internal' => [], 'user' => [], 'customer' => [], 'project' => [], @@ -226,6 +227,20 @@ abstract class AbstractSpreadsheetRenderer }; } + if ($showRates && isset($columns['rate_internal']) && !isset($columns['rate_internal']['render'])) { + $columns['rate_internal']['render'] = function (Worksheet $sheet, int $row, int $column, ExportItemInterface $entity) { + $currency = ''; + if (null !== $entity->getProject()) { + $currency = $entity->getProject()->getCustomer()->getCurrency(); + } + $rate = $entity->getRate(); + if (method_exists($entity, 'getInternalRate')) { + $rate = $entity->getInternalRate(); + } + $this->setRate($sheet, $column, $row, $rate, $currency); + }; + } + if (isset($columns['user']) && !isset($columns['user']['render'])) { $columns['user']['render'] = function (Worksheet $sheet, int $row, int $column, ExportItemInterface $entity) { $user = ''; @@ -468,7 +483,7 @@ abstract class AbstractSpreadsheetRenderer } if (!$showRates) { - $removes = ['rate', 'fixedRate', 'hourlyRate']; + $removes = ['rate', 'fixedRate', 'hourlyRate', 'rate_internal']; foreach ($removes as $removeMe) { if (array_key_exists($removeMe, $columns)) { unset($columns[$removeMe]); @@ -514,6 +529,7 @@ abstract class AbstractSpreadsheetRenderer $durationColumn = null; $rateColumn = null; + $internalRateColumn = null; foreach ($exportItems as $exportItem) { $entryHeaderColumn = 1; @@ -523,6 +539,8 @@ abstract class AbstractSpreadsheetRenderer $durationColumn = $entryHeaderColumn; } elseif ($label === 'rate') { $rateColumn = $entryHeaderColumn; + } elseif ($label === 'rate_internal') { + $internalRateColumn = $entryHeaderColumn; } if (!array_key_exists('render', $settings) || !is_callable($settings['render'])) { @@ -554,6 +572,15 @@ abstract class AbstractSpreadsheetRenderer $style->getFont()->setBold(true); } + if (null !== $internalRateColumn) { + $startCoordinate = $sheet->getCellByColumnAndRow($internalRateColumn, 2)->getCoordinate(); + $endCoordinate = $sheet->getCellByColumnAndRow($internalRateColumn, $entryHeaderRow - 1)->getCoordinate(); + $this->setRateTotal($sheet, $internalRateColumn, $entryHeaderRow, $startCoordinate, $endCoordinate); + $style = $sheet->getStyleByColumnAndRow($internalRateColumn, $entryHeaderRow); + $style->getBorders()->getTop()->setBorderStyle(Border::BORDER_THIN); + $style->getFont()->setBold(true); + } + return $spreadsheet; } diff --git a/src/Export/Base/RendererTrait.php b/src/Export/Base/RendererTrait.php index 9f0ba64f..3128b7d7 100644 --- a/src/Export/Base/RendererTrait.php +++ b/src/Export/Base/RendererTrait.php @@ -54,6 +54,7 @@ trait RendererTrait 'activities' => [], 'currency' => $currency, 'rate' => 0, + 'rate_internal' => 0, 'duration' => 0, ]; } @@ -63,6 +64,7 @@ trait RendererTrait 'activity' => $activityName, 'currency' => $currency, 'rate' => 0, + 'rate_internal' => 0, 'duration' => 0, ]; } @@ -73,6 +75,11 @@ trait RendererTrait } $summary[$id]['rate'] += $exportItem->getRate(); + if (method_exists($exportItem, 'getInternalRate')) { + $summary[$id]['rate_internal'] += $exportItem->getInternalRate(); + } else { + $summary[$id]['rate_internal'] += $exportItem->getRate(); + } $summary[$id]['duration'] += $duration; $summary[$id]['activities'][$activityId]['rate'] += $exportItem->getRate(); $summary[$id]['activities'][$activityId]['duration'] += $duration; diff --git a/src/Form/API/ActivityRateApiForm.php b/src/Form/API/ActivityRateApiForm.php new file mode 100644 index 00000000..64968d8a --- /dev/null +++ b/src/Form/API/ActivityRateApiForm.php @@ -0,0 +1,28 @@ +setDefaults([ + 'csrf_protection' => false, + ]); + } +} diff --git a/src/Form/API/CustomerRateApiForm.php b/src/Form/API/CustomerRateApiForm.php new file mode 100644 index 00000000..b815d755 --- /dev/null +++ b/src/Form/API/CustomerRateApiForm.php @@ -0,0 +1,28 @@ +setDefaults([ + 'csrf_protection' => false, + ]); + } +} diff --git a/src/Form/API/ProjectRateApiForm.php b/src/Form/API/ProjectRateApiForm.php new file mode 100644 index 00000000..33513548 --- /dev/null +++ b/src/Form/API/ProjectRateApiForm.php @@ -0,0 +1,28 @@ +setDefaults([ + 'csrf_protection' => false, + ]); + } +} diff --git a/src/Form/AbstractRateForm.php b/src/Form/AbstractRateForm.php new file mode 100644 index 00000000..81b53e83 --- /dev/null +++ b/src/Form/AbstractRateForm.php @@ -0,0 +1,56 @@ +add('user', UserType::class, [ + 'required' => false, + ]) + ->add('rate', MoneyType::class, [ + // documentation is for NelmioApiDocBundle + 'documentation' => [ + 'type' => 'number', + 'description' => 'Rate', + ], + 'label' => 'label.rate', + 'attr' => [ + 'autofocus' => 'autofocus' + ], + 'currency' => $currency, + 'help' => 'help.rate', + ]) + ->add('internalRate', MoneyType::class, [ + // documentation is for NelmioApiDocBundle + 'documentation' => [ + 'type' => 'number', + 'description' => 'Internal rate', + ], + 'label' => 'label.rate_internal', + 'currency' => $currency, + 'required' => false, + 'help' => 'help.rate_internal', + ]) + ->add('isFixed', YesNoType::class, [ + 'label' => 'label.fixedRate', + 'help' => 'help.fixedRate', + ]) + ; + } +} diff --git a/src/Form/ActivityRateForm.php b/src/Form/ActivityRateForm.php index dacd409b..8f1e23cd 100644 --- a/src/Form/ActivityRateForm.php +++ b/src/Form/ActivityRateForm.php @@ -11,14 +11,10 @@ namespace App\Form; use App\Entity\ActivityRate; use App\Entity\Rate; -use App\Form\Type\UserType; -use App\Form\Type\YesNoType; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -class ActivityRateForm extends AbstractType +class ActivityRateForm extends AbstractRateForm { /** * {@inheritdoc} @@ -27,7 +23,7 @@ class ActivityRateForm extends AbstractType { $currency = null; - if ($options['data']) { + if (!empty($options['data'])) { /** @var ActivityRate $rate */ $rate = $options['data']; @@ -36,21 +32,7 @@ class ActivityRateForm extends AbstractType } } - $builder - ->add('user', UserType::class, [ - 'required' => false, - ]) - ->add('rate', MoneyType::class, [ - 'label' => 'label.rate', - 'attr' => [ - 'autofocus' => 'autofocus' - ], - 'currency' => $currency, - ]) - ->add('isFixed', YesNoType::class, [ - 'label' => 'label.fixedRate' - ]) - ; + $this->addFields($builder, $currency); } /** diff --git a/src/Form/CustomerRateForm.php b/src/Form/CustomerRateForm.php index aae0c23a..a104356b 100644 --- a/src/Form/CustomerRateForm.php +++ b/src/Form/CustomerRateForm.php @@ -11,14 +11,10 @@ namespace App\Form; use App\Entity\CustomerRate; use App\Entity\Rate; -use App\Form\Type\UserType; -use App\Form\Type\YesNoType; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -class CustomerRateForm extends AbstractType +class CustomerRateForm extends AbstractRateForm { /** * {@inheritdoc} @@ -26,7 +22,8 @@ class CustomerRateForm extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { $currency = null; - if ($options['data']) { + + if (!empty($options['data'])) { /** @var CustomerRate $rate */ $rate = $options['data']; @@ -35,21 +32,7 @@ class CustomerRateForm extends AbstractType } } - $builder - ->add('user', UserType::class, [ - 'required' => false, - ]) - ->add('rate', MoneyType::class, [ - 'label' => 'label.rate', - 'attr' => [ - 'autofocus' => 'autofocus' - ], - 'currency' => $currency, - ]) - ->add('isFixed', YesNoType::class, [ - 'label' => 'label.fixedRate' - ]) - ; + $this->addFields($builder, $currency); } /** diff --git a/src/Form/ProjectRateForm.php b/src/Form/ProjectRateForm.php index 301ed9c2..f66ad9a5 100644 --- a/src/Form/ProjectRateForm.php +++ b/src/Form/ProjectRateForm.php @@ -11,14 +11,10 @@ namespace App\Form; use App\Entity\ProjectRate; use App\Entity\Rate; -use App\Form\Type\UserType; -use App\Form\Type\YesNoType; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -class ProjectRateForm extends AbstractType +class ProjectRateForm extends AbstractRateForm { /** * {@inheritdoc} @@ -26,7 +22,8 @@ class ProjectRateForm extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { $currency = null; - if ($options['data']) { + + if (!empty($options['data'])) { /** @var ProjectRate $rate */ $rate = $options['data']; @@ -35,21 +32,7 @@ class ProjectRateForm extends AbstractType } } - $builder - ->add('user', UserType::class, [ - 'required' => false, - ]) - ->add('rate', MoneyType::class, [ - 'label' => 'label.rate', - 'attr' => [ - 'autofocus' => 'autofocus' - ], - 'currency' => $currency, - ]) - ->add('isFixed', YesNoType::class, [ - 'label' => 'label.fixedRate' - ]) - ; + $this->addFields($builder, $currency); } /** diff --git a/src/Invoice/Calculator/AbstractMergedCalculator.php b/src/Invoice/Calculator/AbstractMergedCalculator.php index e8c83080..bdec849f 100644 --- a/src/Invoice/Calculator/AbstractMergedCalculator.php +++ b/src/Invoice/Calculator/AbstractMergedCalculator.php @@ -57,6 +57,11 @@ abstract class AbstractMergedCalculator extends AbstractCalculator $invoiceItem->setAmount($invoiceItem->getAmount() + $amount); $invoiceItem->setUser($entry->getUser()); $invoiceItem->setRate($invoiceItem->getRate() + $entry->getRate()); + if (method_exists($entry, 'getInternalRate')) { + $invoiceItem->setInternalRate($invoiceItem->getInternalRate() + $entry->getInternalRate()); + } else { + $invoiceItem->setInternalRate($invoiceItem->getInternalRate() + $entry->getRate()); + } $invoiceItem->setDuration($duration); if (null !== $entry->getFixedRate()) { diff --git a/src/Invoice/Calculator/AbstractSumInvoiceCalculator.php b/src/Invoice/Calculator/AbstractSumInvoiceCalculator.php index 4a96c126..d58da6e4 100644 --- a/src/Invoice/Calculator/AbstractSumInvoiceCalculator.php +++ b/src/Invoice/Calculator/AbstractSumInvoiceCalculator.php @@ -53,17 +53,11 @@ abstract class AbstractSumInvoiceCalculator extends AbstractMergedCalculator imp return array_values($invoiceItems); } - /** - * @deprecated since 1.9 - use mergeSumInvoiceItem() instead - */ - protected function mergeSumTimesheet(InvoiceItem $invoiceItem, InvoiceItemInterface $entry) - { - } - protected function mergeSumInvoiceItem(InvoiceItem $invoiceItem, InvoiceItemInterface $entry) { - @trigger_error('mergeSumTimesheet() is deprecated and will be removed with 2.0', E_USER_DEPRECATED); - - $this->mergeSumTimesheet($invoiceItem, $entry); + if (method_exists($this, 'mergeSumTimesheet')) { + @trigger_error('mergeSumTimesheet() is deprecated and will be removed with 2.0 - use mergeSumInvoiceItem() instead', E_USER_DEPRECATED); + $this->mergeSumTimesheet($invoiceItem, $entry); + } } } diff --git a/src/Invoice/Hydrator/InvoiceItemDefaultHydrator.php b/src/Invoice/Hydrator/InvoiceItemDefaultHydrator.php index 8cebdfbc..32c409fb 100644 --- a/src/Invoice/Hydrator/InvoiceItemDefaultHydrator.php +++ b/src/Invoice/Hydrator/InvoiceItemDefaultHydrator.php @@ -30,6 +30,7 @@ class InvoiceItemDefaultHydrator implements InvoiceItemHydrator $formatter = $this->model->getFormatter(); $rate = $item->getRate(); + $internalRate = $item->getInternalRate(); $appliedRate = $item->getHourlyRate(); $amount = $formatter->getFormattedDuration($item->getDuration()); $description = $item->getDescription(); @@ -65,6 +66,9 @@ class InvoiceItemDefaultHydrator implements InvoiceItemHydrator 'entry.rate' => $formatter->getFormattedMoney($appliedRate, $currency), 'entry.rate_nc' => $formatter->getFormattedMoney($appliedRate, null), 'entry.rate_plain' => $appliedRate, + 'entry.rate_internal' => $formatter->getFormattedMoney($internalRate, $currency), + 'entry.rate_internal_nc' => $formatter->getFormattedMoney($internalRate, null), + 'entry.rate_internal_plain' => $internalRate, 'entry.total' => $formatter->getFormattedMoney($rate, $currency), 'entry.total_nc' => $formatter->getFormattedMoney($rate, null), 'entry.total_plain' => $rate, diff --git a/src/Invoice/InvoiceItem.php b/src/Invoice/InvoiceItem.php index c44067f4..937cc304 100644 --- a/src/Invoice/InvoiceItem.php +++ b/src/Invoice/InvoiceItem.php @@ -30,6 +30,10 @@ final class InvoiceItem * @var float */ private $rate = 0.00; + /** + * @var float + */ + private $rateInternal = 0.00; /** * @var float */ @@ -152,6 +156,18 @@ final class InvoiceItem return $this; } + public function getInternalRate(): float + { + return $this->rateInternal; + } + + public function setInternalRate(float $rateInternal): InvoiceItem + { + $this->rateInternal = $rateInternal; + + return $this; + } + public function getAmount(): float { return $this->amount; diff --git a/src/Invoice/InvoiceItemInterface.php b/src/Invoice/InvoiceItemInterface.php index c27ad021..efd82067 100644 --- a/src/Invoice/InvoiceItemInterface.php +++ b/src/Invoice/InvoiceItemInterface.php @@ -14,6 +14,9 @@ use App\Entity\MetaTableTypeInterface; use App\Entity\Project; use App\Entity\User; +/** + * @method float|null getInternalRate() + */ interface InvoiceItemInterface { public function getActivity(): ?Activity; @@ -26,6 +29,11 @@ interface InvoiceItemInterface public function getRate(): float; + // will be activated with 2.0 + /* + public function getInternalRate(): ?float; + */ + public function getUser(): ?User; public function getBegin(): ?\DateTime; diff --git a/src/Invoice/NumberGenerator/ConfigurableNumberGenerator.php b/src/Invoice/NumberGenerator/ConfigurableNumberGenerator.php index 73163231..d44dfdf0 100644 --- a/src/Invoice/NumberGenerator/ConfigurableNumberGenerator.php +++ b/src/Invoice/NumberGenerator/ConfigurableNumberGenerator.php @@ -25,14 +25,14 @@ final class ConfigurableNumberGenerator implements NumberGeneratorInterface */ private $repository; /** - * @var string + * @var SystemConfiguration */ - private $format; + private $configuration; public function __construct(InvoiceRepository $repository, SystemConfiguration $configuration) { $this->repository = $repository; - $this->format = $configuration->find('invoice.number_format'); + $this->configuration = $configuration; } /** @@ -56,9 +56,8 @@ final class ConfigurableNumberGenerator implements NumberGeneratorInterface */ public function getInvoiceNumber(): string { - $format = $this->format; + $format = $this->configuration->find('invoice.number_format'); $invoiceDate = $this->model->getInvoiceDate(); - $timestamp = $invoiceDate->getTimestamp(); $result = $format; preg_match_all('/{[^}]*?}/', $format, $matches); diff --git a/src/Migrations/Version20200323163038.php b/src/Migrations/Version20200323163038.php new file mode 100644 index 00000000..fe489ade --- /dev/null +++ b/src/Migrations/Version20200323163038.php @@ -0,0 +1,42 @@ +getTable('kimai2_activities_rates')->addColumn('internal_rate', 'float', ['notnull' => false]); + $schema->getTable('kimai2_projects_rates')->addColumn('internal_rate', 'float', ['notnull' => false]); + $schema->getTable('kimai2_customers_rates')->addColumn('internal_rate', 'float', ['notnull' => false]); + $schema->getTable('kimai2_timesheet')->addColumn('internal_rate', 'float', ['notnull' => false]); + } + + public function down(Schema $schema): void + { + $schema->getTable('kimai2_timesheet')->dropColumn('internal_rate'); + $schema->getTable('kimai2_activities_rates')->dropColumn('internal_rate'); + $schema->getTable('kimai2_projects_rates')->dropColumn('internal_rate'); + $schema->getTable('kimai2_customers_rates')->dropColumn('internal_rate'); + } +} diff --git a/src/Migrations/Version20200323163039.php b/src/Migrations/Version20200323163039.php new file mode 100644 index 00000000..3c1d33b4 --- /dev/null +++ b/src/Migrations/Version20200323163039.php @@ -0,0 +1,35 @@ +addSql('UPDATE kimai2_timesheet SET internal_rate = rate'); + } + + public function down(Schema $schema): void + { + } +} diff --git a/src/Model/TimesheetCountedStatistic.php b/src/Model/TimesheetCountedStatistic.php index f4e9ac5e..0c7d1f45 100644 --- a/src/Model/TimesheetCountedStatistic.php +++ b/src/Model/TimesheetCountedStatistic.php @@ -23,6 +23,10 @@ class TimesheetCountedStatistic * @var float */ protected $recordRate = 0.0; + /** + * @var float + */ + protected $recordInternalRate = 0.0; /** * Returns the total amount of included timesheet records. @@ -86,4 +90,25 @@ class TimesheetCountedStatistic return $this; } + + /** + * Returns the total internal rate of all included timesheet records. + * + * @return float + */ + public function getRecordInternalRate() + { + return $this->recordInternalRate; + } + + /** + * @param float $recordInternalRate + * @return $this + */ + public function setRecordInternalRate($recordInternalRate) + { + $this->recordInternalRate = (float) $recordInternalRate; + + return $this; + } } diff --git a/src/Repository/ActivityRepository.php b/src/Repository/ActivityRepository.php index cc04c452..0efb2519 100644 --- a/src/Repository/ActivityRepository.php +++ b/src/Repository/ActivityRepository.php @@ -97,6 +97,7 @@ class ActivityRepository extends EntityRepository ->addSelect('COUNT(t.id) as recordAmount') ->addSelect('SUM(t.duration) as recordDuration') ->addSelect('SUM(t.rate) as recordRate') + ->addSelect('SUM(t.internalRate) as recordInternalRate') ->from(Timesheet::class, 't') ->where('t.activity = :activity') ; @@ -107,6 +108,7 @@ class ActivityRepository extends EntityRepository $stats->setRecordAmount($timesheetResult[0]['recordAmount']); $stats->setRecordDuration($timesheetResult[0]['recordDuration']); $stats->setRecordRate($timesheetResult[0]['recordRate']); + $stats->setRecordInternalRate($timesheetResult[0]['recordInternalRate']); } return $stats; diff --git a/src/Repository/CustomerRepository.php b/src/Repository/CustomerRepository.php index ee252fed..2d197598 100644 --- a/src/Repository/CustomerRepository.php +++ b/src/Repository/CustomerRepository.php @@ -89,6 +89,7 @@ class CustomerRepository extends EntityRepository ->addSelect('COUNT(t.id) as recordAmount') ->addSelect('SUM(t.duration) as recordDuration') ->addSelect('SUM(t.rate) as recordRate') + ->addSelect('SUM(t.internalRate) as recordInternalRate') ->from(Timesheet::class, 't') ->join(Project::class, 'p', Query\Expr\Join::WITH, 't.project = p.id') ->andWhere('p.customer = :customer') @@ -99,6 +100,7 @@ class CustomerRepository extends EntityRepository $stats->setRecordAmount($timesheetResult[0]['recordAmount']); $stats->setRecordDuration($timesheetResult[0]['recordDuration']); $stats->setRecordRate($timesheetResult[0]['recordRate']); + $stats->setRecordInternalRate($timesheetResult[0]['recordInternalRate']); } $qb = $this->getEntityManager()->createQueryBuilder(); diff --git a/src/Repository/ProjectRepository.php b/src/Repository/ProjectRepository.php index 6f4ff0b2..0fb8c3c5 100644 --- a/src/Repository/ProjectRepository.php +++ b/src/Repository/ProjectRepository.php @@ -84,6 +84,7 @@ class ProjectRepository extends EntityRepository ->addSelect('COUNT(t.id) as recordAmount') ->addSelect('SUM(t.duration) as recordDuration') ->addSelect('SUM(t.rate) as recordRate') + ->addSelect('SUM(t.internalRate) as recordInternalRate') ->andWhere('t.project = :project') ->setParameter('project', $project) ; @@ -103,6 +104,7 @@ class ProjectRepository extends EntityRepository $stats->setRecordAmount($timesheetResult[0]['recordAmount']); $stats->setRecordDuration($timesheetResult[0]['recordDuration']); $stats->setRecordRate($timesheetResult[0]['recordRate']); + $stats->setRecordInternalRate($timesheetResult[0]['recordInternalRate']); } $qb = $this->getEntityManager()->createQueryBuilder(); diff --git a/src/Timesheet/Calculator/RateCalculator.php b/src/Timesheet/Calculator/RateCalculator.php index 5771023d..e7a5aa3b 100644 --- a/src/Timesheet/Calculator/RateCalculator.php +++ b/src/Timesheet/Calculator/RateCalculator.php @@ -44,45 +44,70 @@ class RateCalculator implements CalculatorInterface { if (null === $record->getEnd()) { $record->setRate(0); + $record->setInternalRate(0); return; } $fixedRate = $record->getFixedRate(); $hourlyRate = $record->getHourlyRate(); + $fixedInternalRate = null; + $internalRate = null; - if (null === $fixedRate && null === $hourlyRate) { - $rate = $this->getBestFittingRate($record); + $rate = $this->getBestFittingRate($record); - if (null !== $rate) { - if ($rate->isFixed()) { - $fixedRate = $rate->getRate(); - } else { - $hourlyRate = $rate->getRate(); + if (null !== $rate) { + if ($rate->isFixed()) { + $fixedRate = $fixedRate ?? $rate->getRate(); + $fixedInternalRate = $rate->getRate(); + if (null !== $rate->getInternalRate()) { + $fixedInternalRate = $rate->getInternalRate(); + } + } else { + $hourlyRate = $hourlyRate ?? $rate->getRate(); + $internalRate = $rate->getRate(); + if (null !== $rate->getInternalRate()) { + $internalRate = $rate->getInternalRate(); } } } if (null !== $fixedRate) { - $record->setRate($fixedRate); $record->setFixedRate($fixedRate); + $record->setRate($fixedRate); + if (null === $fixedInternalRate) { + $fixedInternalRate = (float) $record->getUser()->getPreferenceValue(UserPreference::INTERNAL_RATE, $fixedRate); + } + $record->setInternalRate($fixedInternalRate); return; } + // user preferences => fallback if nothing else was configured if (null === $hourlyRate) { $hourlyRate = (float) $record->getUser()->getPreferenceValue(UserPreference::HOURLY_RATE, 0.00); } + if (null === $internalRate) { + $internalRate = $record->getUser()->getPreferenceValue(UserPreference::INTERNAL_RATE, 0.00); + if (null === $internalRate) { + $internalRate = $hourlyRate; + } else { + $internalRate = (float) $internalRate; + } + } $factor = $this->getRateFactor($record); - $hourlyRate = (float) ($hourlyRate * $factor); + $factoredHourlyRate = (float) ($hourlyRate * $factor); + $factoredInternalRate = (float) ($internalRate * $factor); $totalRate = 0; + $totalInternalRate = 0; if (null !== $record->getDuration()) { - $totalRate = Util::calculateRate($hourlyRate, $record->getDuration()); + $totalRate = Util::calculateRate($factoredHourlyRate, $record->getDuration()); + $totalInternalRate = Util::calculateRate($factoredInternalRate, $record->getDuration()); } - - $record->setHourlyRate($hourlyRate); + $record->setHourlyRate($factoredHourlyRate); + $record->setInternalRate($totalInternalRate); $record->setRate($totalRate); } diff --git a/templates/activity/details.html.twig b/templates/activity/details.html.twig index 78fd0f63..40422bcc 100644 --- a/templates/activity/details.html.twig +++ b/templates/activity/details.html.twig @@ -77,64 +77,7 @@ {% endif %} {% if can_edit %} - {% embed '@AdminLTE/Widgets/box-widget.html.twig' %} - {% import "macros/widgets.html.twig" as widgets %} - {% block box_attributes %}id="activity_rates_box"{% endblock %} - {% block box_title %} - {{ 'rates.title'|trans }} - {% endblock %} - {% block box_tools %} - - {% endblock %} - {% block box_body %} - {% if rates is empty %} - {{ 'rates.empty'|trans }} - {% else %} - - - - - - - - - - - {% for rate in rates %} - - - - - - - {% endfor %} - -
- {{ 'label.user'|trans }} - - {{ 'label.hourlyRate'|trans }} - - {{ 'label.fixedRate'|trans }} -
- {% if rate.user is not null %} - {{ widgets.user_avatar(rate.user) }} - {% else %} - – - {% endif %} - - {% if not rate.fixed %} - {{ rate.rate|money(currency) }} - {% endif %} - - {% if rate.fixed %} - {{ rate.rate|money(currency) }} - {% endif %} - - -
- {% endif %} - {% endblock %} - {% endembed %} + {{ include('embeds/rates-table.html.twig', {'id': 'activity_rates_box', 'entity': activity, 'create_url': path('admin_activity_rate_add', {'id': activity.id}), 'delete_route': 'delete_activity_rate', 'currency': currency}) }} {% endif %} {% endblock %} @@ -143,7 +86,7 @@ {{ parent() }} {% endblock %} diff --git a/templates/activity/embed_budget.html.twig b/templates/activity/embed_budget.html.twig index 45439304..f3576db9 100644 --- a/templates/activity/embed_budget.html.twig +++ b/templates/activity/embed_budget.html.twig @@ -11,6 +11,11 @@ '%duration%': '' ~ stats.recordDuration|duration ~ '' } %} + {% set currency = null %} + {% if activity.project is not null %} + {% set currency = activity.project.customer.currency %} + {% endif %} + {% if activity.project is not null %} {% set params = params|merge({ '%project%': '' ~ activity.project.name ~ '', @@ -20,12 +25,9 @@

{{ 'admin_activity.short_stats'|trans(params)|raw }} + {{ 'label.rate_internal'|trans }}: {{ stats.recordInternalRate|money(currency) }}.

- {% set currency = null %} - {% if activity.project is not null %} - {% set currency = activity.project.customer.currency %} - {% endif %} {{ progress.progressbar(activity.budget, stats.recordRate, 'label.budget'|trans, stats.recordRate|money(currency) ~ ' / ' ~ activity.budget|money(currency) ) }} {{ progress.progressbar(activity.timeBudget, stats.recordDuration, 'label.timeBudget'|trans, stats.recordDuration|duration ~ ' / ' ~ activity.timeBudget|duration ) }} diff --git a/templates/customer/details.html.twig b/templates/customer/details.html.twig index 52f907bc..d1111390 100644 --- a/templates/customer/details.html.twig +++ b/templates/customer/details.html.twig @@ -125,64 +125,7 @@ {% endif %} {% if can_edit %} - {% embed '@AdminLTE/Widgets/box-widget.html.twig' %} - {% import "macros/widgets.html.twig" as widgets %} - {% block box_attributes %}id="customer_rates_box"{% endblock %} - {% block box_title %} - {{ 'rates.title'|trans }} - {% endblock %} - {% block box_tools %} - - {% endblock %} - {% block box_body %} - {% if rates is empty %} - {{ 'rates.empty'|trans }} - {% else %} - - - - - - - - - - - {% for rate in rates %} - - - - - - - {% endfor %} - -
- {{ 'label.user'|trans }} - - {{ 'label.hourlyRate'|trans }} - - {{ 'label.fixedRate'|trans }} -
- {% if rate.user is not null %} - {{ widgets.user_avatar(rate.user) }} - {% else %} - – - {% endif %} - - {% if not rate.fixed %} - {{ rate.rate|money(customer.currency) }} - {% endif %} - - {% if rate.fixed %} - {{ rate.rate|money(customer.currency) }} - {% endif %} - - -
- {% endif %} - {% endblock %} - {% endembed %} + {{ include('embeds/rates-table.html.twig', {'id': 'customer_rates_box', 'entity': customer, 'create_url': path('admin_customer_rate_add', {'id': customer.id}), 'delete_route': 'delete_customer_rate', 'currency': customer.currency}) }} {% endif %} {% if teams is not null %} @@ -207,7 +150,7 @@ {{ parent() }} {% endblock %} diff --git a/templates/customer/embed_budget.html.twig b/templates/customer/embed_budget.html.twig index 898c3102..c30511f6 100644 --- a/templates/customer/embed_budget.html.twig +++ b/templates/customer/embed_budget.html.twig @@ -12,11 +12,14 @@ '%rate%': '' ~ stats.recordRate|money ~ '' } %} + {% set currency = customer.currency %} +

{{ 'admin_customer.short_stats'|trans(params)|raw }} + {{ 'label.rate_internal'|trans }}: {{ stats.recordInternalRate|money(currency) }}.

- {{ progress.progressbar(customer.budget, stats.recordRate, 'label.budget'|trans, stats.recordRate|money(customer.currency) ~ ' / ' ~ customer.budget|money(customer.currency) ) }} + {{ progress.progressbar(customer.budget, stats.recordRate, 'label.budget'|trans, stats.recordRate|money(currency) ~ ' / ' ~ customer.budget|money(currency) ) }} {{ progress.progressbar(customer.timeBudget, stats.recordDuration, 'label.timeBudget'|trans, stats.recordDuration|duration ~ ' / ' ~ customer.timeBudget|duration ) }} {% endblock %} {% endembed %} diff --git a/templates/embeds/rates-table.html.twig b/templates/embeds/rates-table.html.twig new file mode 100644 index 00000000..589bfb2a --- /dev/null +++ b/templates/embeds/rates-table.html.twig @@ -0,0 +1,60 @@ +{% embed '@AdminLTE/Widgets/box-widget.html.twig' with {'id': id, 'entity': entity, 'create_url': create_url, 'delete_route': delete_route, 'currency': currency} %} + {% import "macros/widgets.html.twig" as widgets %} + {% block box_attributes %}id="{{ id }}"{% endblock %} + {% block box_title %} + {{ 'rates.title'|trans }} + {% endblock %} + {% block box_tools %} + + {% endblock %} + {% block box_body %} + {% if rates is empty %} + {{ 'rates.empty'|trans }} + {% else %} + + + + + + + + + + + + {% for rate in rates %} + + + + + + + + {% endfor %} + +
+ {{ 'label.user'|trans }} + + {{ 'label.hourlyRate'|trans }} + + {{ 'label.rate_internal'|trans }} + + {{ 'label.fixedRate'|trans }} +
+ {% if rate.user is not null %} + {{ widgets.user_avatar(rate.user) }} + {% else %} + – + {% endif %} + + {{ rate.rate|money(currency) }} + + {{ rate.internalRate|money(currency) }} + + {{ widgets.label_boolean(rate.fixed) }} + + +
+ {% endif %} + {% endblock %} +{% endembed %} \ No newline at end of file diff --git a/templates/export/actions.html.twig b/templates/export/actions.html.twig index ab935549..22aba17c 100644 --- a/templates/export/actions.html.twig +++ b/templates/export/actions.html.twig @@ -2,9 +2,10 @@ {% macro export(view) %} {% import "macros/widgets.html.twig" as widgets %} - {% set actions = {} %} + {% set actions = {'visibility': '#modal_export'} %} + {% if view == 'preview' %} - {% set actions = {'off': {'id':'export-toggle-button'}} %} + {% set actions = actions|merge({'off': {'id':'export-toggle-button'}}) %} {% endif %} {% set actions = actions|merge({'help': {'url': 'export.html'|docu_link, 'target': '_blank'}}) %} diff --git a/templates/export/index.html.twig b/templates/export/index.html.twig index 05ec9565..bb0b6653 100644 --- a/templates/export/index.html.twig +++ b/templates/export/index.html.twig @@ -5,15 +5,16 @@ {% import "export/actions.html.twig" as actions %} {% set columns = { - 'date': 'alwaysVisible', - 'user': 'hidden-xs hidden-sm', - 'project': 'hidden-xs hidden-sm', - 'activity': 'hidden-xs hidden-sm', - 'description': 'hidden-xs hidden-sm', - 'unit_price': 'hidden-xs', - 'duration': '', - 'total_rate': '', - 'exported': 'alwaysVisible', + 'date': {'class': 'alwaysVisible text-nowrap', 'orderBy': false}, + 'user': {'class': 'hidden-xs hidden-sm', 'orderBy': false}, + 'project': {'class': 'hidden-xs hidden-sm', 'orderBy': false}, + 'activity': {'class': 'hidden-xs hidden-sm hidden-md', 'orderBy': false}, + 'description': {'class': 'hidden-xs hidden-sm hidden-md timesheet-description', 'orderBy': false}, + 'unit_price': {'class': 'hidden hidden-xs text-nowrap', 'orderBy': false}, + 'duration': {'class': 'text-nowrap', 'orderBy': false}, + 'rate_internal': {'class': 'hidden-xs text-nowrap', 'orderBy': false}, + 'total_rate': {'class': 'text-nowrap', 'orderBy': false}, + 'exported': {'class': 'alwaysVisible', 'orderBy': false}, } %} {% set tableName = 'export' %} @@ -22,6 +23,10 @@ {% block page_subtitle %}{{ 'export.subtitle'|trans }}{% endblock %} {% block page_actions %}{{ actions.export((preview_show ? 'preview' : 'index')) }}{% endblock %} +{% block main_before %} + {{ tables.data_table_column_modal(tableName, columns) }} +{% endblock %} + {% block main %} {% embed '@AdminLTE/Widgets/box-widget.html.twig' %} @@ -84,24 +89,25 @@ {% else %} {{ tables.datatable_header(tableName, columns, query, {}) }} {% set totalAmount = {} %} + {% set totalInternalAmount = {} %} {% set totalDuration = 0 %} {% for entry in entries %} {% set currency = entry.project.customer.currency %} {% set duration = entry.duration|duration %} {% if totalAmount[currency] is not defined %} {% set totalAmount = totalAmount|merge({(currency): 0}) %} + {% set totalInternalAmount = totalInternalAmount|merge({(currency): 0}) %} {% endif %} {% if entry.fixedRate is not null %} {% set rate = entry.fixedRate %} - {% set duration = 1 %} - {% set totalDuration = totalDuration + 1 %} {% else %} {% set rate = entry.hourlyRate %} - {% set totalDuration = totalDuration + entry.duration %} {% endif %} + {% set totalDuration = totalDuration + entry.duration %} {% set totalAmount = totalAmount|merge({(currency): totalAmount[currency] + entry.rate}) %} + {% set totalInternalAmount = totalInternalAmount|merge({(currency): totalInternalAmount[currency] + entry.internalRate}) %} - {{ entry.begin|date_short }} + {{ entry.begin|date_short }} {{ widgets.label_user(entry.user) }} {{ widgets.label_project(entry.project) }} @@ -109,19 +115,22 @@ {{ widgets.label_customer(entry.project.customer) }} {{ widgets.label_activity(entry.activity) }} - + {{ entry.description|escape|desc2html }} - + {{ rate|money(currency) }} - + {{ duration }} - + + {{ entry.internalRate|money(currency) }} + + {{ entry.rate|money(currency) }} - + {% if is_granted('edit_export', entry) %} {% if entry.exported %}