Release 2.43 (#5694)
This commit is contained in:
@@ -40,7 +40,7 @@ APP_SECRET=change_this_to_something_unique
|
||||
#================================================================================
|
||||
# Running behind reverse proxies? Try these:
|
||||
# TRUSTED_PROXIES=127.0.0.1,127.0.0.2
|
||||
# TRUSTED_HOSTS=localhost,example.com
|
||||
# TRUSTED_HOSTS=localhost|example.com
|
||||
|
||||
#================================================================================
|
||||
# unlikely, that you need to change this one
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
/*!
|
||||
* [KIMAI] KimaiRecentActivities: responsible to reload the users recent activities
|
||||
* [KIMAI] KimaiRemoteModal: load remote content (without forms) into a modal
|
||||
*/
|
||||
|
||||
import KimaiPlugin from '../KimaiPlugin';
|
||||
|
||||
24
composer.lock
generated
24
composer.lock
generated
@@ -3463,16 +3463,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nelmio/api-doc-bundle",
|
||||
"version": "v5.7.0",
|
||||
"version": "v5.7.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nelmio/NelmioApiDocBundle.git",
|
||||
"reference": "2a79732f8d10a5a0faf3934d906ac9e4c720aa2f"
|
||||
"reference": "772d26a9d940c9a8d173f75f0fdbaab47c1c87f2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/2a79732f8d10a5a0faf3934d906ac9e4c720aa2f",
|
||||
"reference": "2a79732f8d10a5a0faf3934d906ac9e4c720aa2f",
|
||||
"url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/772d26a9d940c9a8d173f75f0fdbaab47c1c87f2",
|
||||
"reference": "772d26a9d940c9a8d173f75f0fdbaab47c1c87f2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3574,7 +3574,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nelmio/NelmioApiDocBundle/issues",
|
||||
"source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v5.7.0"
|
||||
"source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v5.7.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3582,7 +3582,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-10T09:23:31+00:00"
|
||||
"time": "2025-11-13T10:32:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nelmio/cors-bundle",
|
||||
@@ -14489,16 +14489,16 @@
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.2.3",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
|
||||
"reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb",
|
||||
"reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -14527,7 +14527,7 @@
|
||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"support": {
|
||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -14535,7 +14535,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-03T12:36:25+00:00"
|
||||
"time": "2025-11-13T13:44:09+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
||||
@@ -3,20 +3,20 @@ nelmio_api_doc:
|
||||
models:
|
||||
use_jms: true
|
||||
names:
|
||||
- { alias: CustomerEditForm, type: App\Form\API\CustomerApiEditForm, groups: [Default, Entity, Customer] }
|
||||
- { alias: CustomerEditForm, type: App\Form\API\CustomerApiEditForm, groups: [Default, Entity, Customer, Customer_Entity] }
|
||||
- { alias: CustomerEntity, type: App\Entity\Customer, groups: [Default, Entity, Customer, Customer_Entity, Not_Expanded] }
|
||||
- { alias: Customer, type: App\Entity\Customer, groups: [Default, Not_Expanded] }
|
||||
- { alias: CustomerRate, type: App\Entity\CustomerRate, groups: [Default, Entity, Customer_Rate] }
|
||||
- { alias: CustomerRateForm, type: App\Form\API\CustomerRateApiForm, groups: [Default, Entity, Customer_Rate] }
|
||||
- { alias: CustomerCollection, type: App\Entity\Customer, groups: [Default, Collection, Customer] }
|
||||
- { alias: ProjectEditForm, type: App\Form\API\ProjectApiEditForm, groups: [Default, Entity, Project] }
|
||||
- { alias: ProjectEditForm, type: App\Form\API\ProjectApiEditForm, groups: [Default, Entity, Project, Project_Entity] }
|
||||
- { alias: ProjectEntity, type: App\Entity\Project, groups: [Default, Entity, Project, Project_Entity, Not_Expanded] }
|
||||
- { alias: Project, type: App\Entity\Project, groups: [Default, Not_Expanded] }
|
||||
- { alias: ProjectExpanded, type: App\Entity\Project, groups: [Default, Expanded] }
|
||||
- { alias: ProjectRate, type: App\Entity\ProjectRate, groups: [Default, Entity, Project_Rate] }
|
||||
- { alias: ProjectRateForm, type: App\Form\API\ProjectRateApiForm, groups: [Default, Entity, Project_Rate] }
|
||||
- { alias: ProjectCollection, type: App\Entity\Project, groups: [Default, Collection, Project] }
|
||||
- { alias: ActivityEditForm, type: App\Form\API\ActivityApiEditForm, groups: [Default, Entity, Activity] }
|
||||
- { alias: ActivityEditForm, type: App\Form\API\ActivityApiEditForm, groups: [Default, Entity, Activity, Activity_Entity] }
|
||||
- { alias: ActivityEntity, type: App\Entity\Activity, groups: [Default, Entity, Activity, Activity_Entity, Not_Expanded] }
|
||||
- { alias: Activity, type: App\Entity\Activity, groups: [Default, Not_Expanded] }
|
||||
- { alias: ActivityExpanded, type: App\Entity\Activity, groups: [Default, Expanded] }
|
||||
|
||||
@@ -36,7 +36,6 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
final class ActivityController extends BaseApiController
|
||||
{
|
||||
public const GROUPS_ENTITY = ['Default', 'Entity', 'Activity', 'Activity_Entity'];
|
||||
public const GROUPS_FORM = ['Default', 'Entity', 'Activity'];
|
||||
public const GROUPS_COLLECTION = ['Default', 'Collection', 'Activity'];
|
||||
public const GROUPS_RATE = ['Default', 'Entity', 'Activity_Rate'];
|
||||
|
||||
@@ -130,8 +129,7 @@ final class ActivityController extends BaseApiController
|
||||
throw $this->createAccessDeniedException('User cannot create activities');
|
||||
}
|
||||
|
||||
$activity = new Activity();
|
||||
$this->activityService->loadMetaFields($activity);
|
||||
$activity = $this->activityService->createNewActivity();
|
||||
|
||||
$form = $this->createForm(ActivityApiEditForm::class, $activity, [
|
||||
'include_budget' => $this->isGranted('budget', $activity),
|
||||
@@ -150,7 +148,7 @@ final class ActivityController extends BaseApiController
|
||||
}
|
||||
|
||||
$view = new View($form);
|
||||
$view->getContext()->setGroups(self::GROUPS_FORM);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
|
||||
return $this->viewHandler->handle($view);
|
||||
}
|
||||
@@ -177,7 +175,7 @@ final class ActivityController extends BaseApiController
|
||||
|
||||
if (false === $form->isValid()) {
|
||||
$view = new View($form, Response::HTTP_OK);
|
||||
$view->getContext()->setGroups(self::GROUPS_FORM);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
|
||||
return $this->viewHandler->handle($view);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
final class CustomerController extends BaseApiController
|
||||
{
|
||||
public const GROUPS_ENTITY = ['Default', 'Entity', 'Customer', 'Customer_Entity'];
|
||||
public const GROUPS_FORM = ['Default', 'Entity', 'Customer'];
|
||||
public const GROUPS_COLLECTION = ['Default', 'Collection', 'Customer'];
|
||||
public const GROUPS_RATE = ['Default', 'Entity', 'Customer_Rate'];
|
||||
|
||||
@@ -139,7 +138,7 @@ final class CustomerController extends BaseApiController
|
||||
}
|
||||
|
||||
$view = new View($form);
|
||||
$view->getContext()->setGroups(self::GROUPS_FORM);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
|
||||
return $this->viewHandler->handle($view);
|
||||
}
|
||||
@@ -166,7 +165,7 @@ final class CustomerController extends BaseApiController
|
||||
|
||||
if (false === $form->isValid()) {
|
||||
$view = new View($form, Response::HTTP_OK);
|
||||
$view->getContext()->setGroups(self::GROUPS_FORM);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
|
||||
return $this->viewHandler->handle($view);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ use Symfony\Component\Validator\Constraints;
|
||||
final class ProjectController extends BaseApiController
|
||||
{
|
||||
public const GROUPS_ENTITY = ['Default', 'Entity', 'Project', 'Project_Entity'];
|
||||
public const GROUPS_FORM = ['Default', 'Entity', 'Project'];
|
||||
public const GROUPS_COLLECTION = ['Default', 'Collection', 'Project'];
|
||||
public const GROUPS_RATE = ['Default', 'Entity', 'Project_Rate'];
|
||||
|
||||
@@ -194,7 +193,7 @@ final class ProjectController extends BaseApiController
|
||||
}
|
||||
|
||||
$view = new View($form);
|
||||
$view->getContext()->setGroups(self::GROUPS_FORM);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
|
||||
return $this->viewHandler->handle($view);
|
||||
}
|
||||
@@ -223,7 +222,7 @@ final class ProjectController extends BaseApiController
|
||||
|
||||
if (false === $form->isValid()) {
|
||||
$view = new View($form, Response::HTTP_OK);
|
||||
$view->getContext()->setGroups(self::GROUPS_FORM);
|
||||
$view->getContext()->setGroups(self::GROUPS_ENTITY);
|
||||
|
||||
return $this->viewHandler->handle($view);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ final class ResetTestCommand extends AbstractResetCommand
|
||||
$user2->setAvatar('https://www.gravatar.com/avatar/00000000000000000000000000000000?d=retro&f=y');
|
||||
$user2->setEnabled(true);
|
||||
$user2->setRoles(['ROLE_USER']);
|
||||
$user2->setUserIdentifier('john_user');
|
||||
$user2->setUserIdentifier(UserFixtures::USERNAME_USER);
|
||||
$user2->setEmail('john_user@example.com');
|
||||
$token2 = new AccessToken($user2, UserFixtures::DEFAULT_API_TOKEN . '_user');
|
||||
$token2->setName('Test fixture');
|
||||
@@ -118,41 +118,41 @@ final class ResetTestCommand extends AbstractResetCommand
|
||||
$token3 = new AccessToken($user3, UserFixtures::DEFAULT_API_TOKEN . '_inactive');
|
||||
$token3->setName('Test fixture');
|
||||
|
||||
$user4 = new User();
|
||||
$user4->setPreferenceValue(UserPreference::HOURLY_RATE, 35);
|
||||
$user4->setAlias('Tony Maier');
|
||||
$user4->setRegisteredAt(new \DateTime('2018-02-06 23:28:57'));
|
||||
$user4->setTitle('Head of Development');
|
||||
$user4->setAvatar('https://en.gravatar.com/userimage/3533186/bf2163b1dd23f3107a028af0195624e9.jpeg');
|
||||
$user4->setEnabled(true);
|
||||
$user4->setRoles(['ROLE_TEAMLEAD']);
|
||||
$user4->setUserIdentifier('tony_teamlead');
|
||||
$user4->setEmail('tony_teamlead@example.com');
|
||||
$token4 = new AccessToken($user4, UserFixtures::DEFAULT_API_TOKEN . '_teamlead');
|
||||
$userTeamlead = new User();
|
||||
$userTeamlead->setPreferenceValue(UserPreference::HOURLY_RATE, 35);
|
||||
$userTeamlead->setAlias('Tony Maier');
|
||||
$userTeamlead->setRegisteredAt(new \DateTime('2018-02-06 23:28:57'));
|
||||
$userTeamlead->setTitle('Head of Development');
|
||||
$userTeamlead->setAvatar('https://en.gravatar.com/userimage/3533186/bf2163b1dd23f3107a028af0195624e9.jpeg');
|
||||
$userTeamlead->setEnabled(true);
|
||||
$userTeamlead->setRoles(['ROLE_TEAMLEAD']);
|
||||
$userTeamlead->setUserIdentifier(UserFixtures::USERNAME_TEAMLEAD);
|
||||
$userTeamlead->setEmail('tony_teamlead@example.com');
|
||||
$token4 = new AccessToken($userTeamlead, UserFixtures::DEFAULT_API_TOKEN . '_teamlead');
|
||||
$token4->setName('Test fixture');
|
||||
|
||||
$user5 = new User();
|
||||
$user5->setPreferenceValue(UserPreference::HOURLY_RATE, 81);
|
||||
$user5->setAlias('Anna Smith');
|
||||
$user5->setRegisteredAt(new \DateTime('2018-02-06 23:28:57'));
|
||||
$user5->setTitle('Administrator');
|
||||
$user5->setEnabled(true);
|
||||
$user5->setRoles(['ROLE_ADMIN']);
|
||||
$user5->setUserIdentifier('anna_admin');
|
||||
$user5->setEmail('anna_admin@example.com');
|
||||
$token5 = new AccessToken($user5, UserFixtures::DEFAULT_API_TOKEN . '_admin');
|
||||
$userAdmin = new User();
|
||||
$userAdmin->setPreferenceValue(UserPreference::HOURLY_RATE, 81);
|
||||
$userAdmin->setAlias('Anna Smith');
|
||||
$userAdmin->setRegisteredAt(new \DateTime('2018-02-06 23:28:57'));
|
||||
$userAdmin->setTitle('Administrator');
|
||||
$userAdmin->setEnabled(true);
|
||||
$userAdmin->setRoles(['ROLE_ADMIN']);
|
||||
$userAdmin->setUserIdentifier(UserFixtures::USERNAME_ADMIN);
|
||||
$userAdmin->setEmail('anna_admin@example.com');
|
||||
$token5 = new AccessToken($userAdmin, UserFixtures::DEFAULT_API_TOKEN . '_admin');
|
||||
$token5->setName('Test fixture');
|
||||
|
||||
$user6 = new User();
|
||||
$user6->setPreferenceValue(UserPreference::HOURLY_RATE, 46);
|
||||
$user6->setRegisteredAt(new \DateTime('2018-02-06 23:28:57'));
|
||||
$user6->setTitle('Super Administrator');
|
||||
$user6->setAvatar('/bundles/avanzuadmintheme/img/avatar.png');
|
||||
$user6->setEnabled(true);
|
||||
$user6->setRoles(['ROLE_SUPER_ADMIN']);
|
||||
$user6->setUserIdentifier('susan_super');
|
||||
$user6->setEmail('susan_super@example.com');
|
||||
$token6 = new AccessToken($user6, UserFixtures::DEFAULT_API_TOKEN . '_super');
|
||||
$userSuperAdmin = new User();
|
||||
$userSuperAdmin->setPreferenceValue(UserPreference::HOURLY_RATE, 46);
|
||||
$userSuperAdmin->setRegisteredAt(new \DateTime('2018-02-06 23:28:57'));
|
||||
$userSuperAdmin->setTitle('Super Administrator');
|
||||
$userSuperAdmin->setAvatar('/bundles/avanzuadmintheme/img/avatar.png');
|
||||
$userSuperAdmin->setEnabled(true);
|
||||
$userSuperAdmin->setRoles(['ROLE_SUPER_ADMIN']);
|
||||
$userSuperAdmin->setUserIdentifier(UserFixtures::USERNAME_SUPER_ADMIN);
|
||||
$userSuperAdmin->setEmail('susan_super@example.com');
|
||||
$token6 = new AccessToken($userSuperAdmin, UserFixtures::DEFAULT_API_TOKEN . '_super');
|
||||
$token6->setName('Test fixture');
|
||||
|
||||
$user7 = new User();
|
||||
@@ -180,9 +180,9 @@ final class ResetTestCommand extends AbstractResetCommand
|
||||
[$user1, $token1],
|
||||
[$user2, $token2],
|
||||
[$user3, $token3],
|
||||
[$user4, $token4],
|
||||
[$user5, $token5],
|
||||
[$user6, $token6],
|
||||
[$userTeamlead, $token4],
|
||||
[$userAdmin, $token5],
|
||||
[$userSuperAdmin, $token6],
|
||||
[$user7, $token7],
|
||||
[$user8, $token8],
|
||||
];
|
||||
|
||||
@@ -17,11 +17,11 @@ final class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.42.0';
|
||||
public const VERSION = '2.43.0';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 24200;
|
||||
public const VERSION_ID = 24300;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -96,7 +96,7 @@ class Customer implements EntityWithMetaFields, EntityWithBudget, CreatedAt
|
||||
#[Exporter\Expose(label: 'contact')]
|
||||
private ?string $contact = null;
|
||||
/**
|
||||
* Unstructured address, better use the fields: address_line1-3, postcode, city, country
|
||||
* Unstructured address, better use the fields: addressLine1-3, postcode, city, country
|
||||
*/
|
||||
#[ORM\Column(name: 'address', type: Types::TEXT, nullable: true)]
|
||||
#[Serializer\Expose]
|
||||
|
||||
@@ -10,7 +10,22 @@
|
||||
namespace App\Form\API;
|
||||
|
||||
use App\Form\ActivityEditForm;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
final class ActivityApiEditForm extends ActivityEditForm
|
||||
final class ActivityApiEditForm extends AbstractType
|
||||
{
|
||||
public function getParent(): string
|
||||
{
|
||||
return ActivityEditForm::class;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
// overwritten, so the docs show these fields
|
||||
$resolver->setDefaults([
|
||||
'include_budget' => true,
|
||||
'include_time' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,22 @@
|
||||
namespace App\Form\API;
|
||||
|
||||
use App\Form\CustomerEditForm;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
final class CustomerApiEditForm extends CustomerEditForm
|
||||
final class CustomerApiEditForm extends AbstractType
|
||||
{
|
||||
public function getParent(): string
|
||||
{
|
||||
return CustomerEditForm::class;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
// overwritten, so the docs show these fields
|
||||
$resolver->setDefaults([
|
||||
'include_budget' => true,
|
||||
'include_time' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,22 @@
|
||||
namespace App\Form\API;
|
||||
|
||||
use App\Form\ProjectEditForm;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
final class ProjectApiEditForm extends ProjectEditForm
|
||||
final class ProjectApiEditForm extends AbstractType
|
||||
{
|
||||
public function getParent(): string
|
||||
{
|
||||
return ProjectEditForm::class;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
// overwritten, so the docs show these fields
|
||||
$resolver->setDefaults([
|
||||
'include_budget' => true,
|
||||
'include_time' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class CustomerEditForm extends AbstractType
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$isNew = false;
|
||||
$isNew = true;
|
||||
$hasAddress = false;
|
||||
|
||||
if (isset($options['data'])) {
|
||||
@@ -54,6 +54,9 @@ class CustomerEditForm extends AbstractType
|
||||
->add('number', TextType::class, [
|
||||
'label' => 'number',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'maxlength' => 50,
|
||||
],
|
||||
])
|
||||
->add('comment', TextareaType::class, [
|
||||
'label' => 'description',
|
||||
@@ -83,19 +86,19 @@ class CustomerEditForm extends AbstractType
|
||||
}
|
||||
|
||||
$builder
|
||||
->add('address_line1', TextType::class, [
|
||||
->add('addressLine1', TextType::class, [
|
||||
'label' => 'address',
|
||||
'required' => false,
|
||||
])
|
||||
->add('address_line2', TextType::class, [
|
||||
->add('addressLine2', TextType::class, [
|
||||
'label' => false,
|
||||
'required' => false,
|
||||
])
|
||||
->add('address_line3', TextType::class, [
|
||||
->add('addressLine3', TextType::class, [
|
||||
'label' => false,
|
||||
'required' => false,
|
||||
])
|
||||
->add('postcode', TextType::class, [
|
||||
->add('postCode', TextType::class, [
|
||||
'label' => 'postcode',
|
||||
'required' => false,
|
||||
])
|
||||
|
||||
@@ -31,6 +31,9 @@ trait EntityFormTrait
|
||||
|
||||
if ($showMoney) {
|
||||
$builder->add('budget', MoneyType::class, [
|
||||
'documentation' => [
|
||||
'description' => 'The money budget',
|
||||
],
|
||||
'empty_data' => '0.00',
|
||||
'label' => 'budget',
|
||||
'required' => false,
|
||||
|
||||
@@ -29,7 +29,7 @@ class ProjectEditForm extends AbstractType
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$customer = null;
|
||||
$isNew = false;
|
||||
$isNew = true;
|
||||
$options['currency'] = null;
|
||||
$customerOptions = [];
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ final class BudgetType extends AbstractType
|
||||
'choices' => [
|
||||
'budgetType_month' => self::TYPE_MONTH,
|
||||
],
|
||||
'documentation' => [
|
||||
'description' => 'The type of budget. Only submit if you want to use a monthly budget.',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,22 +96,22 @@
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{{ form_row(form.address_line1, {attr: {placeholder: 'address_row'|trans({'%row%': 1})}}) }}
|
||||
{{ form_row(form.addressLine1, {attr: {placeholder: 'address_row'|trans({'%row%': 1})}}) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{{ form_row(form.address_line2, {attr: {placeholder: 'address_row'|trans({'%row%': 2})}}) }}
|
||||
{{ form_row(form.addressLine2, {attr: {placeholder: 'address_row'|trans({'%row%': 2})}}) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{{ form_row(form.address_line3, {attr: {placeholder: 'address_row'|trans({'%row%': 3})}}) }}
|
||||
{{ form_row(form.addressLine3, {attr: {placeholder: 'address_row'|trans({'%row%': 3})}}) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
{{ form_row(form.postcode) }}
|
||||
{{ form_row(form.postCode) }}
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
{{ form_row(form.city) }}
|
||||
|
||||
@@ -504,7 +504,7 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase
|
||||
'billable' => 'bool',
|
||||
'color' => '@string',
|
||||
'customer' => 'int',
|
||||
'number' => '@int',
|
||||
'number' => '@string',
|
||||
'orderNumber' => '@string',
|
||||
'globalActivities' => 'bool',
|
||||
'comment' => '@string',
|
||||
@@ -521,7 +521,7 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase
|
||||
'billable' => 'bool',
|
||||
'color' => '@string',
|
||||
'customer' => ['result' => 'object', 'type' => 'Customer'],
|
||||
'number' => '@int',
|
||||
'number' => '@string',
|
||||
'orderNumber' => '@string',
|
||||
'globalActivities' => 'bool',
|
||||
'comment' => '@string',
|
||||
@@ -537,7 +537,7 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase
|
||||
'visible' => 'bool',
|
||||
'billable' => 'bool',
|
||||
'customer' => 'int',
|
||||
'number' => '@int',
|
||||
'number' => '@string',
|
||||
'orderNumber' => '@string',
|
||||
'color' => '@string',
|
||||
'metaFields' => ['result' => 'array', 'type' => 'ProjectMeta'],
|
||||
@@ -557,7 +557,7 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase
|
||||
'visible' => 'bool',
|
||||
'billable' => 'bool',
|
||||
'customer' => 'int',
|
||||
'number' => '@int',
|
||||
'number' => '@string',
|
||||
'color' => '@string',
|
||||
'metaFields' => ['result' => 'array', 'type' => 'ProjectMeta'],
|
||||
'parentTitle' => 'string',
|
||||
@@ -581,7 +581,7 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase
|
||||
'visible' => 'bool',
|
||||
'billable' => 'bool',
|
||||
'project' => '@int',
|
||||
'number' => '@int',
|
||||
'number' => '@string',
|
||||
'color' => '@string',
|
||||
'comment' => '@string',
|
||||
];
|
||||
@@ -593,7 +593,7 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase
|
||||
'visible' => 'bool',
|
||||
'billable' => 'bool',
|
||||
'project' => ['result' => 'object', 'type' => '@ProjectExpanded'],
|
||||
'number' => '@int',
|
||||
'number' => '@string',
|
||||
'color' => '@string',
|
||||
'comment' => '@string',
|
||||
];
|
||||
@@ -606,7 +606,7 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase
|
||||
'visible' => 'bool',
|
||||
'billable' => 'bool',
|
||||
'project' => '@int',
|
||||
'number' => '@int',
|
||||
'number' => '@string',
|
||||
'color' => '@string',
|
||||
'metaFields' => ['result' => 'array', 'type' => 'ProjectMeta'],
|
||||
'parentTitle' => '@string',
|
||||
@@ -622,7 +622,7 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase
|
||||
'visible' => 'bool',
|
||||
'billable' => 'bool',
|
||||
'project' => '@int',
|
||||
'number' => '@int',
|
||||
'number' => '@string',
|
||||
'color' => '@string',
|
||||
'metaFields' => ['result' => 'array', 'type' => 'ProjectMeta'],
|
||||
'parentTitle' => '@string',
|
||||
|
||||
@@ -243,6 +243,24 @@ class ActivityControllerTest extends APIControllerBaseTestCase
|
||||
|
||||
self::assertIsArray($result);
|
||||
self::assertApiResponseTypeStructure('ActivityEntity', $result);
|
||||
|
||||
self::assertCount(14, array_keys($result));
|
||||
self::assertNull($result['parentTitle']);
|
||||
self::assertNotEmpty($result['id']);
|
||||
self::assertIsArray($result['teams']);
|
||||
self::assertEquals([], $result['teams']);
|
||||
self::assertIsArray($result['metaFields']);
|
||||
self::assertEquals([], $result['metaFields']);
|
||||
self::assertEquals('Test', $result['name']);
|
||||
self::assertNull($result['project']);
|
||||
self::assertEquals(1000, $result['budget']);
|
||||
self::assertEquals(100000, $result['timeBudget']);
|
||||
self::assertNull($result['budgetType']);
|
||||
self::assertNull($result['number']);
|
||||
self::assertEquals('Test comment', $result['comment']);
|
||||
self::assertNull($result['color']);
|
||||
self::assertTrue($result['visible']);
|
||||
self::assertTrue($result['billable']);
|
||||
}
|
||||
|
||||
public function testNotFound(): void
|
||||
@@ -256,9 +274,16 @@ class ActivityControllerTest extends APIControllerBaseTestCase
|
||||
$data = [
|
||||
'name' => 'foo',
|
||||
'project' => 1,
|
||||
'visible' => true,
|
||||
'budget' => '999',
|
||||
'timeBudget' => '7200',
|
||||
'timeBudget' => '10,25',
|
||||
'budgetType' => 'month',
|
||||
'number' => 'P-754',
|
||||
'comment' => 'Awesome activity since a short time',
|
||||
'invoiceText' => 'Some invoice text, pay slow please',
|
||||
'color' => '#000000',
|
||||
'visible' => true,
|
||||
'billable' => true,
|
||||
'teams' => [1],
|
||||
];
|
||||
$this->request($client, '/api/activities', 'POST', [], json_encode($data));
|
||||
self::assertTrue($client->getResponse()->isSuccessful());
|
||||
@@ -269,7 +294,22 @@ class ActivityControllerTest extends APIControllerBaseTestCase
|
||||
|
||||
self::assertIsArray($result);
|
||||
self::assertApiResponseTypeStructure('ActivityEntity', $result);
|
||||
self::assertEquals('Test', $result['parentTitle']);
|
||||
self::assertNotEmpty($result['id']);
|
||||
self::assertIsArray($result['teams']);
|
||||
self::assertEquals([['id' => 1, 'name' => 'Test team', 'color' => null]], $result['teams']);
|
||||
self::assertIsArray($result['metaFields']);
|
||||
self::assertEquals([], $result['metaFields']);
|
||||
self::assertEquals('foo', $result['name']);
|
||||
self::assertEquals(1, $result['project']);
|
||||
self::assertEquals('999', $result['budget']);
|
||||
self::assertEquals('36900', $result['timeBudget']);
|
||||
self::assertEquals('month', $result['budgetType']);
|
||||
self::assertEquals('P-754', $result['number']);
|
||||
self::assertEquals('Awesome activity since a short time', $result['comment']);
|
||||
self::assertEquals('#000000', $result['color']);
|
||||
self::assertTrue($result['visible']);
|
||||
self::assertTrue($result['billable']);
|
||||
}
|
||||
|
||||
public function testPostActionWithLeastFields(): void
|
||||
|
||||
@@ -228,6 +228,43 @@ class CustomerControllerTest extends APIControllerBaseTestCase
|
||||
|
||||
self::assertIsArray($result);
|
||||
self::assertApiResponseTypeStructure('CustomerEntity', $result);
|
||||
|
||||
self::assertCount(30, array_keys($result));
|
||||
self::assertNotEmpty($result['id']);
|
||||
self::assertIsArray($result['teams']);
|
||||
self::assertCount(1, $result['teams']);
|
||||
self::assertIsArray($result['teams'][0]);
|
||||
self::assertEquals('Testing customer 1 team', $result['teams'][0]['name']);
|
||||
self::assertIsArray($result['metaFields']);
|
||||
self::assertCount(1, $result['metaFields']);
|
||||
self::assertEquals([['name' => 'foo', 'value' => 'bar']], $result['metaFields']);
|
||||
self::assertEquals('Test', $result['name']);
|
||||
self::assertEquals(1000, $result['budget']);
|
||||
self::assertEquals(100000, $result['timeBudget']);
|
||||
self::assertNull($result['budgetType']);
|
||||
self::assertEquals('1', $result['number']);
|
||||
self::assertEquals('Test comment', $result['comment']);
|
||||
self::assertEquals('Test', $result['company']);
|
||||
self::assertNull($result['vatId']);
|
||||
self::assertEquals('Test', $result['contact']);
|
||||
self::assertEquals('Test', $result['address']);
|
||||
self::assertNull($result['addressLine1']);
|
||||
self::assertNull($result['addressLine2']);
|
||||
self::assertNull($result['addressLine3']);
|
||||
self::assertNull($result['postCode']);
|
||||
self::assertNull($result['city']);
|
||||
self::assertEquals('DE', $result['country']);
|
||||
self::assertEquals('EUR', $result['currency']);
|
||||
self::assertEquals('111', $result['phone']);
|
||||
self::assertEquals('222', $result['fax']);
|
||||
self::assertEquals('333', $result['mobile']);
|
||||
self::assertEquals('test@example.com', $result['email']);
|
||||
self::assertNull($result['homepage']);
|
||||
self::assertEquals('Europe/Berlin', $result['timezone']);
|
||||
self::assertNull($result['buyerReference']);
|
||||
self::assertNull($result['color']);
|
||||
self::assertTrue($result['visible']);
|
||||
self::assertTrue($result['billable']);
|
||||
}
|
||||
|
||||
public function testNotFound(): void
|
||||
@@ -240,12 +277,33 @@ class CustomerControllerTest extends APIControllerBaseTestCase
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$data = [
|
||||
'name' => 'foo',
|
||||
'visible' => true,
|
||||
'budget' => '999',
|
||||
'timeBudget' => '10,25',
|
||||
'budgetType' => 'month',
|
||||
'number' => 'C-754',
|
||||
'comment' => 'Awesome customer since a long time',
|
||||
'company' => 'IT Professional Comp.',
|
||||
'vatId' => 'DE0123456789',
|
||||
'contact' => 'Mr. John Doe',
|
||||
'addressLine1' => 'test address line 1',
|
||||
'addressLine2' => 'foo address line 2',
|
||||
'addressLine3' => 'bar address line 3',
|
||||
'postCode' => '12345',
|
||||
'city' => 'Acme Town',
|
||||
'country' => 'DE',
|
||||
'currency' => 'EUR',
|
||||
'phone' => '666667787778999909087',
|
||||
'fax' => '0987654321',
|
||||
'mobile' => '01234534567890',
|
||||
'email' => 'admin@example.com',
|
||||
'homepage' => 'https://www.example.com/',
|
||||
'timezone' => 'Europe/Berlin',
|
||||
'budget' => '999',
|
||||
'timeBudget' => '7200',
|
||||
'invoiceText' => 'Some random text, pay fast please!',
|
||||
'buyerReference' => 'REF-0123456789',
|
||||
'color' => '#ff0000',
|
||||
'visible' => true,
|
||||
'billable' => true,
|
||||
'teams' => [1],
|
||||
];
|
||||
$this->request($client, '/api/customers', 'POST', [], json_encode($data));
|
||||
self::assertTrue($client->getResponse()->isSuccessful());
|
||||
@@ -257,6 +315,37 @@ class CustomerControllerTest extends APIControllerBaseTestCase
|
||||
self::assertIsArray($result);
|
||||
self::assertApiResponseTypeStructure('CustomerEntity', $result);
|
||||
self::assertNotEmpty($result['id']);
|
||||
self::assertIsArray($result['teams']);
|
||||
self::assertEquals([['id' => 1, 'name' => 'Test team', 'color' => null]], $result['teams']);
|
||||
self::assertIsArray($result['metaFields']);
|
||||
self::assertEquals([], $result['metaFields']);
|
||||
self::assertEquals('foo', $result['name']);
|
||||
self::assertEquals('999', $result['budget']);
|
||||
self::assertEquals('36900', $result['timeBudget']);
|
||||
self::assertEquals('month', $result['budgetType']);
|
||||
self::assertEquals('C-754', $result['number']);
|
||||
self::assertEquals('Awesome customer since a long time', $result['comment']);
|
||||
self::assertEquals('IT Professional Comp.', $result['company']);
|
||||
self::assertEquals('DE0123456789', $result['vatId']);
|
||||
self::assertEquals('Mr. John Doe', $result['contact']);
|
||||
self::assertNull($result['address']);
|
||||
self::assertEquals('test address line 1', $result['addressLine1']);
|
||||
self::assertEquals('foo address line 2', $result['addressLine2']);
|
||||
self::assertEquals('bar address line 3', $result['addressLine3']);
|
||||
self::assertEquals('12345', $result['postCode']);
|
||||
self::assertEquals('Acme Town', $result['city']);
|
||||
self::assertEquals('DE', $result['country']);
|
||||
self::assertEquals('EUR', $result['currency']);
|
||||
self::assertEquals('666667787778999909087', $result['phone']);
|
||||
self::assertEquals('0987654321', $result['fax']);
|
||||
self::assertEquals('01234534567890', $result['mobile']);
|
||||
self::assertEquals('admin@example.com', $result['email']);
|
||||
self::assertEquals('https://www.example.com/', $result['homepage']);
|
||||
self::assertEquals('Europe/Berlin', $result['timezone']);
|
||||
self::assertEquals('REF-0123456789', $result['buyerReference']);
|
||||
self::assertEquals('#ff0000', $result['color']);
|
||||
self::assertTrue($result['visible']);
|
||||
self::assertTrue($result['billable']);
|
||||
}
|
||||
|
||||
public function testPostActionWithLeastFields(): void
|
||||
|
||||
@@ -311,28 +311,28 @@ class ProjectControllerTest extends APIControllerBaseTestCase
|
||||
self::assertIsArray($result);
|
||||
self::assertApiResponseTypeStructure('ProjectEntity', $result);
|
||||
|
||||
$expected = [
|
||||
'parentTitle' => 'first one',
|
||||
'customer' => $customer->getId(),
|
||||
'id' => $project->getId(),
|
||||
'name' => 'first',
|
||||
'orderNumber' => null,
|
||||
// make sure the timezone is properly applied in serializer (see #1858)
|
||||
'orderDate' => '2019-11-29',
|
||||
'start' => '2020-01-07',
|
||||
'end' => '2021-03-23',
|
||||
'comment' => null,
|
||||
'visible' => true,
|
||||
'budget' => 0.0,
|
||||
'timeBudget' => 0,
|
||||
'metaFields' => [],
|
||||
'teams' => [],
|
||||
'color' => null,
|
||||
];
|
||||
|
||||
foreach ($expected as $key => $value) {
|
||||
self::assertEquals($value, $result[$key]);
|
||||
}
|
||||
self::assertCount(19, array_keys($result));
|
||||
self::assertEquals('first one', $result['parentTitle']);
|
||||
self::assertEquals($project->getId(), $result['id']);
|
||||
self::assertIsArray($result['teams']);
|
||||
self::assertEquals([], $result['teams']);
|
||||
self::assertIsArray($result['metaFields']);
|
||||
self::assertEquals([], $result['metaFields']);
|
||||
self::assertEquals('first', $result['name']);
|
||||
self::assertEquals($customer->getId(), $result['customer']);
|
||||
self::assertEquals('2019-11-29', $result['orderDate']);
|
||||
self::assertEquals('2020-01-07', $result['start']);
|
||||
self::assertEquals('2021-03-23', $result['end']);
|
||||
self::assertEquals(0.0, $result['budget']);
|
||||
self::assertEquals(0, $result['timeBudget']);
|
||||
self::assertNull($result['budgetType']);
|
||||
self::assertNull($result['orderNumber']);
|
||||
self::assertNull($result['number']);
|
||||
self::assertNull($result['comment']);
|
||||
self::assertNull($result['color']);
|
||||
self::assertTrue($result['globalActivities']);
|
||||
self::assertTrue($result['billable']);
|
||||
self::assertTrue($result['visible']);
|
||||
}
|
||||
|
||||
public function testNotFound(): void
|
||||
@@ -350,8 +350,17 @@ class ProjectControllerTest extends APIControllerBaseTestCase
|
||||
'start' => '2019-02-01',
|
||||
'end' => '2020-02-08',
|
||||
'budget' => '999',
|
||||
'timeBudget' => '7200',
|
||||
'timeBudget' => '10,25',
|
||||
'budgetType' => 'month',
|
||||
'orderNumber' => '1234567890/WXYZ/SUBPROJECT/1234/CONTRACT/EMPLOYEE1',
|
||||
'number' => 'A-1234',
|
||||
'comment' => 'Awesome project since a short time',
|
||||
'invoiceText' => 'Some invoice text, pay now!',
|
||||
'color' => '#c0c0c0',
|
||||
'globalActivities' => true,
|
||||
'visible' => true,
|
||||
'billable' => true,
|
||||
'teams' => [1],
|
||||
];
|
||||
$this->request($client, '/api/projects', 'POST', [], json_encode($data));
|
||||
self::assertTrue($client->getResponse()->isSuccessful());
|
||||
@@ -362,14 +371,27 @@ class ProjectControllerTest extends APIControllerBaseTestCase
|
||||
|
||||
self::assertIsArray($result);
|
||||
self::assertApiResponseTypeStructure('ProjectEntity', $result);
|
||||
self::assertEquals('Test', $result['parentTitle']);
|
||||
self::assertNotEmpty($result['id']);
|
||||
self::assertIsArray($result['teams']);
|
||||
self::assertEquals([['id' => 1, 'name' => 'Test team', 'color' => null]], $result['teams']);
|
||||
self::assertIsArray($result['metaFields']);
|
||||
self::assertEquals([], $result['metaFields']);
|
||||
self::assertEquals('foo', $result['name']);
|
||||
self::assertEquals(1, $result['customer']);
|
||||
self::assertEquals('2018-04-17', $result['orderDate']);
|
||||
self::assertEquals('2019-02-01', $result['start']);
|
||||
self::assertEquals('2020-02-08', $result['end']);
|
||||
self::assertEquals('999', $result['budget']);
|
||||
self::assertEquals('36900', $result['timeBudget']);
|
||||
self::assertEquals('month', $result['budgetType']);
|
||||
self::assertEquals('1234567890/WXYZ/SUBPROJECT/1234/CONTRACT/EMPLOYEE1', $result['orderNumber']);
|
||||
self::assertFalse($result['globalActivities']);
|
||||
self::assertFalse($result['billable']);
|
||||
self::assertFalse($result['visible']);
|
||||
self::assertEquals('A-1234', $result['number']);
|
||||
self::assertEquals('Awesome project since a short time', $result['comment']);
|
||||
self::assertEquals('#c0c0c0', $result['color']);
|
||||
self::assertTrue($result['globalActivities']);
|
||||
self::assertTrue($result['billable']);
|
||||
self::assertTrue($result['visible']);
|
||||
}
|
||||
|
||||
public function testPostActionWithOtherFields(): void
|
||||
|
||||
Reference in New Issue
Block a user