From 8de54e1fa7ffe3b911c93080f4abd0210bbc22b0 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Sun, 22 Sep 2024 16:17:45 +0200 Subject: [PATCH] Added API endpoints to fetch invoices (#5070) * added serializer attributes for API usage * new setters to fill invoice data from fixture * re-usable fixture helper methods * added API endpoints to fetch invoices * adjust tests --- config/packages/nelmio_api_doc.yaml | 2 + src/API/InvoiceController.php | 124 ++++++++++++++++++ src/Entity/Invoice.php | 102 ++++++++++++-- src/Invoice/InvoiceModelFactory.php | 6 +- tests/API/APIControllerBaseTest.php | 23 +++- tests/API/ActivityControllerTest.php | 2 +- tests/API/ApiDocControllerTest.php | 4 +- tests/API/CustomerControllerTest.php | 2 +- tests/API/InvoiceControllerTest.php | 106 +++++++++++++++ tests/API/ProjectControllerTest.php | 2 +- tests/API/TeamControllerTest.php | 2 +- tests/API/TimesheetControllerTest.php | 2 +- tests/DataFixtures/ActivityFixtures.php | 18 +-- tests/DataFixtures/CustomerFixtures.php | 2 - tests/DataFixtures/FixturesTrait.php | 91 +++++++++++++ tests/DataFixtures/InvoiceFixtures.php | 76 +++++++++++ .../DataFixtures/InvoiceTemplateFixtures.php | 1 - tests/DataFixtures/ProjectFixtures.php | 18 +-- tests/DataFixtures/TeamFixtures.php | 54 +------- tests/DataFixtures/TimesheetFixtures.php | 50 +------ 20 files changed, 532 insertions(+), 155 deletions(-) create mode 100644 src/API/InvoiceController.php create mode 100644 tests/API/InvoiceControllerTest.php create mode 100644 tests/DataFixtures/FixturesTrait.php create mode 100644 tests/DataFixtures/InvoiceFixtures.php diff --git a/config/packages/nelmio_api_doc.yaml b/config/packages/nelmio_api_doc.yaml index 4c2d6a0e..e06ca83b 100644 --- a/config/packages/nelmio_api_doc.yaml +++ b/config/packages/nelmio_api_doc.yaml @@ -40,6 +40,8 @@ nelmio_api_doc: - { alias: TeamCollection, type: App\Entity\Team, groups: [Default, Collection, Team] } - { alias: TeamMember, type: App\Entity\TeamMember, groups: [Team_Entity] } - { alias: TeamMembership, type: App\Entity\TeamMember, groups: [User_Entity] } + - { alias: Invoice, type: App\Entity\Invoice, groups: [Default, Entity, Invoice, Invoice_Entity] } + - { alias: InvoiceCollection, type: App\Entity\Invoice, groups: [Default, Collection, Invoice] } areas: path_patterns: - ^/api(?!/doc) diff --git a/src/API/InvoiceController.php b/src/API/InvoiceController.php new file mode 100644 index 00000000..541b4a75 --- /dev/null +++ b/src/API/InvoiceController.php @@ -0,0 +1,124 @@ +getUser(); + + $query = new InvoiceArchiveQuery(); + $query->setCurrentUser($user); + $factory = $this->getDateTimeFactory(); + + $begin = $paramFetcher->get('begin'); + if (\is_string($begin) && $begin !== '') { + $query->setBegin($factory->createDateTime($begin)); + } + + $end = $paramFetcher->get('end'); + if (\is_string($end) && $end !== '') { + $query->setEnd($factory->createDateTime($end)); + } + + /** @var array $status */ + $status = $paramFetcher->get('status'); + if (\is_array($status)) { + foreach ($status as $s) { + $query->addStatus($s); + } + } + + $page = $paramFetcher->get('page'); + if (\is_string($page) && $page !== '') { + $query->setPage((int) $page); + } + + $size = $paramFetcher->get('size'); + if (is_numeric($size)) { + $query->setPageSize((int) $size); + } + + /** @var array $customers */ + $customers = $paramFetcher->get('customers'); + foreach ($customerRepository->findByIds(array_unique($customers)) as $customer) { + $query->addCustomer($customer); + } + + $query->setIsApiCall(true); + $data = $this->repository->getPagerfantaForQuery($query); + $results = (array) $data->getCurrentPageResults(); + + $view = new View($results, 200); + $view->getContext()->setGroups(self::GROUPS_COLLECTION); + $this->addPagination($view, $data); + + return $this->viewHandler->handle($view); + } + + /** + * Returns one invoice. + * + * Needs permission: view_invoice + */ + #[IsGranted('view_invoice')] + #[OA\Response(response: 200, description: 'Returns one invoice', content: new OA\JsonContent(ref: '#/components/schemas/Invoice'))] + #[Route(methods: ['GET'], path: '/{id}', name: 'get_invoice', requirements: ['id' => '\d+'])] + public function getAction(Invoice $invoice): Response + { + $view = new View($invoice, 200); + $view->getContext()->setGroups(self::GROUPS_ENTITY); + + return $this->viewHandler->handle($view); + } +} diff --git a/src/Entity/Invoice.php b/src/Entity/Invoice.php index 30ae0f5e..350136cd 100644 --- a/src/Entity/Invoice.php +++ b/src/Entity/Invoice.php @@ -25,6 +25,7 @@ use Symfony\Component\Validator\Constraints as Assert; #[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')] #[UniqueEntity('invoiceNumber')] #[UniqueEntity('invoiceFilename')] +#[Serializer\ExclusionPolicy('all')] #[Exporter\Order(['id', 'createdAt', 'invoiceNumber', 'status', 'customer', 'subtotal', 'total', 'tax', 'currency', 'vat', 'dueDays', 'dueDate', 'paymentDate', 'user', 'invoiceFilename', 'customerNumber', 'comment'])] #[Exporter\Expose(name: 'customer', label: 'customer', exp: 'object.getCustomer() === null ? null : object.getCustomer().getName()')] #[Exporter\Expose(name: 'customerNumber', label: 'number', exp: 'object.getCustomer() === null ? null : object.getCustomer().getNumber()')] @@ -44,56 +45,78 @@ class Invoice implements EntityWithMetaFields #[ORM\Column(name: 'id', type: 'integer')] #[ORM\Id] #[ORM\GeneratedValue(strategy: 'IDENTITY')] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] #[Exporter\Expose(label: 'id', type: 'integer')] private ?int $id = null; #[ORM\Column(name: 'invoice_number', type: 'string', length: 50, nullable: false)] #[Assert\NotNull] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] #[Exporter\Expose(label: 'invoice.number', type: 'string')] private ?string $invoiceNumber = null; #[ORM\Column(name: 'comment', type: 'text', nullable: true)] #[Serializer\Expose] - #[Serializer\Groups(['Customer_Entity'])] + #[Serializer\Groups(['Invoice'])] #[Exporter\Expose(label: 'comment')] private ?string $comment = null; #[ORM\ManyToOne(targetEntity: Customer::class)] #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] #[Assert\NotNull] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] private ?Customer $customer = null; #[ORM\ManyToOne(targetEntity: User::class)] #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] #[Assert\NotNull] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] private ?User $user = null; #[ORM\Column(name: 'created_at', type: 'datetime', nullable: false)] #[Assert\NotNull] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] #[Exporter\Expose(label: 'date', type: 'datetime')] private ?\DateTime $createdAt = null; #[ORM\Column(name: 'timezone', type: 'string', length: 64, nullable: false)] private ?string $timezone = null; #[ORM\Column(name: 'total', type: 'float', nullable: false)] #[Assert\NotNull] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] #[Exporter\Expose(label: 'total_rate', type: 'float')] private float $total = 0.00; #[ORM\Column(name: 'tax', type: 'float', nullable: false)] #[Assert\NotNull] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] #[Exporter\Expose(label: 'invoice.tax', type: 'float')] private float $tax = 0.00; #[ORM\Column(name: 'currency', type: 'string', length: 3, nullable: false)] #[Assert\NotNull] #[Assert\Length(max: 3)] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] #[Exporter\Expose(label: 'currency', type: 'string')] private ?string $currency = null; #[ORM\Column(name: 'due_days', type: 'integer', length: 3, nullable: false)] #[Assert\NotNull] #[Assert\Range(min: 0, max: 999)] + #[Serializer\Expose] + #[Serializer\Groups(['Invoice'])] #[Exporter\Expose(label: 'due_days', type: 'integer')] private int $dueDays = 30; #[ORM\Column(name: 'vat', type: 'float', nullable: false)] #[Assert\NotNull] #[Assert\Range(min: 0.0, max: 99.99)] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] #[Exporter\Expose(label: 'tax_rate', type: 'float')] private float $vat = 0.00; #[ORM\Column(name: 'status', type: 'string', length: 20, nullable: false)] #[Assert\NotNull] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] #[Exporter\Expose(label: 'status', type: 'string')] private string $status = self::STATUS_NEW; #[ORM\Column(name: 'invoice_filename', type: 'string', length: 150, nullable: false)] @@ -103,6 +126,8 @@ class Invoice implements EntityWithMetaFields private ?string $invoiceFilename = null; private bool $localized = false; #[ORM\Column(name: 'payment_date', type: 'date', nullable: true)] + #[Serializer\Expose] + #[Serializer\Groups(['Default'])] private ?\DateTime $paymentDate = null; /** * Meta fields registered with the invoice @@ -191,7 +216,6 @@ class Invoice implements EntityWithMetaFields public function setModel(InvoiceModel $model): Invoice { $template = $model->getTemplate(); - if ($template === null) { throw new \InvalidArgumentException('Missing invoice template'); } @@ -200,19 +224,25 @@ class Invoice implements EntityWithMetaFields throw new \InvalidArgumentException('Missing due-days or vat setting'); } - $this->customer = $model->getCustomer(); - $this->user = $model->getUser(); - $this->total = $model->getCalculator()->getTotal(); - $this->tax = $model->getCalculator()->getTax(); - $this->invoiceNumber = $model->getInvoiceNumber(); - $this->currency = $model->getCurrency(); + $customer = $model->getCustomer(); + if ($customer === null) { + throw new \InvalidArgumentException('Missing invoice customer'); + } - $createdAt = $model->getInvoiceDate(); - $this->createdAt = \DateTime::createFromInterface($createdAt); - $this->timezone = $createdAt->getTimezone()->getName(); + $user = $model->getUser(); + if ($user === null) { + throw new \InvalidArgumentException('Missing invoice user'); + } - $this->dueDays = $template->getDueDays(); - $this->vat = $template->getVat(); + $this->setCustomer($customer); + $this->setUser($user); + $this->setTotal($model->getCalculator()->getTotal()); + $this->setTax($model->getCalculator()->getTax()); + $this->setInvoiceNumber($model->getInvoiceNumber()); + $this->setCurrency($model->getCurrency()); + $this->setCreatedAt($model->getInvoiceDate()); + $this->setDueDays($template->getDueDays()); + $this->setVat($template->getVat()); return $this; } @@ -380,6 +410,52 @@ class Invoice implements EntityWithMetaFields return $this; } + public function setVat(float $vat): void + { + $this->vat = $vat; + } + + public function setInvoiceNumber(string $invoiceNumber): void + { + $this->invoiceNumber = $invoiceNumber; + } + + public function setCustomer(Customer $customer): void + { + $this->customer = $customer; + } + + public function setUser(User $user): void + { + $this->user = $user; + } + + public function setCreatedAt(\DateTimeInterface $createdAt): void + { + $this->createdAt = \DateTime::createFromInterface($createdAt); + $this->timezone = $createdAt->getTimezone()->getName(); + } + + public function setTotal(float $total): void + { + $this->total = $total; + } + + public function setTax(float $tax): void + { + $this->tax = $tax; + } + + public function setCurrency(string $currency): void + { + $this->currency = $currency; + } + + public function setDueDays(int $dueDays): void + { + $this->dueDays = $dueDays; + } + public function __clone() { if ($this->id) { diff --git a/src/Invoice/InvoiceModelFactory.php b/src/Invoice/InvoiceModelFactory.php index 1c264c9c..e24916ee 100644 --- a/src/Invoice/InvoiceModelFactory.php +++ b/src/Invoice/InvoiceModelFactory.php @@ -19,9 +19,9 @@ use App\Repository\Query\InvoiceQuery; final class InvoiceModelFactory { public function __construct( - private CustomerStatisticService $customerStatisticService, - private ProjectStatisticService $projectStatisticService, - private ActivityStatisticService $activityStatisticService + private readonly CustomerStatisticService $customerStatisticService, + private readonly ProjectStatisticService $projectStatisticService, + private readonly ActivityStatisticService $activityStatisticService ) { } diff --git a/tests/API/APIControllerBaseTest.php b/tests/API/APIControllerBaseTest.php index f7aeee3c..defc1223 100644 --- a/tests/API/APIControllerBaseTest.php +++ b/tests/API/APIControllerBaseTest.php @@ -107,10 +107,10 @@ abstract class APIControllerBaseTest extends ControllerBaseTest return $client->request($method, $this->createUrl($url), $parameters, [], $server, $content); } - protected function assertEntityNotFound(string $role, string $url, string $method = 'GET', ?string $message = null): void + protected function assertEntityNotFound(string $role, string $url): void { $client = $this->getClientForAuthenticatedUser($role); - $this->request($client, $url, $method); + $this->request($client, $url); $this->assertApiException($client->getResponse(), [ 'code' => Response::HTTP_NOT_FOUND, 'message' => 'Not Found' @@ -272,6 +272,25 @@ abstract class APIControllerBaseTest extends ControllerBaseTest protected static function getExpectedResponseStructure(string $type): array { switch ($type) { + case 'Invoice': + case 'InvoiceCollection': + return [ + 'id' => 'int', + 'comment' => '@string', + 'createdAt' => 'datetime', + 'currency' => 'string', + 'customer' => ['result' => 'object', 'type' => '@Customer'], + 'user' => ['result' => 'object', 'type' => '@User'], + 'dueDays' => 'int', + 'invoiceNumber' => 'string', + 'metaFields' => 'array', + 'paymentDate' => '@datetime', + 'status' => 'string', + 'tax' => 'float', + 'total' => 'float', + 'vat' => 'float', + ]; + case 'PageActionItem': return [ 'id' => 'string', diff --git a/tests/API/ActivityControllerTest.php b/tests/API/ActivityControllerTest.php index a9f4066d..2a2cc659 100644 --- a/tests/API/ActivityControllerTest.php +++ b/tests/API/ActivityControllerTest.php @@ -245,7 +245,7 @@ class ActivityControllerTest extends APIControllerBaseTest public function testNotFound(): void { - $this->assertEntityNotFound(User::ROLE_USER, '/api/activities/' . PHP_INT_MAX, 'GET', 'App\\Entity\\Activity object not found by the @ParamConverter annotation.'); + $this->assertEntityNotFound(User::ROLE_USER, '/api/activities/' . PHP_INT_MAX); } public function testPostAction(): void diff --git a/tests/API/ApiDocControllerTest.php b/tests/API/ApiDocControllerTest.php index 98c3b943..c236e3c0 100644 --- a/tests/API/ApiDocControllerTest.php +++ b/tests/API/ApiDocControllerTest.php @@ -38,7 +38,7 @@ class ApiDocControllerTest extends ControllerBaseTest } } - $expectedKeys = ['Actions', 'Activity', 'Default', 'Customer', 'Project', 'Tag', 'Team', 'Timesheet', 'User']; + $expectedKeys = ['Actions', 'Activity', 'Default', 'Customer', 'Project', 'Tag', 'Team', 'Timesheet', 'User', 'Invoice']; $actual = array_keys($tags); sort($actual); @@ -70,6 +70,8 @@ class ApiDocControllerTest extends ControllerBaseTest '/api/customers/{id}/meta', '/api/customers/{id}/rates', '/api/customers/{id}/rates/{rateId}', + '/api/invoices', + '/api/invoices/{id}', '/api/projects', '/api/projects/{id}', '/api/projects/{id}/meta', diff --git a/tests/API/CustomerControllerTest.php b/tests/API/CustomerControllerTest.php index 467a69d3..b3fe2e39 100644 --- a/tests/API/CustomerControllerTest.php +++ b/tests/API/CustomerControllerTest.php @@ -190,7 +190,7 @@ class CustomerControllerTest extends APIControllerBaseTest public function testNotFound(): void { - $this->assertEntityNotFound(User::ROLE_USER, '/api/customers/' . PHP_INT_MAX, 'GET', 'App\\Entity\\Customer object not found by the @ParamConverter annotation.'); + $this->assertEntityNotFound(User::ROLE_USER, '/api/customers/' . PHP_INT_MAX); } public function testPostAction(): void diff --git a/tests/API/InvoiceControllerTest.php b/tests/API/InvoiceControllerTest.php new file mode 100644 index 00000000..3cd2d414 --- /dev/null +++ b/tests/API/InvoiceControllerTest.php @@ -0,0 +1,106 @@ +setAmount($amount); + if (\is_array($status)) { + $fixture->setStatus($status); + } + + return $this->importFixture($fixture); + } + + public function testIsSecure(): void + { + $this->assertUrlIsSecured('/api/invoices'); + } + + public function testGetCollection(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + $this->importInvoiceFixtures(10); + + $this->assertAccessIsGranted($client, '/api/invoices'); + + $content = $client->getResponse()->getContent(); + $this->assertIsString($content); + $result = json_decode($content, true); + + $this->assertIsArray($result); + $this->assertNotEmpty($result); + $this->assertEquals(10, \count($result)); + self::assertApiResponseTypeStructure('InvoiceCollection', $result[0]); + } + + public function testGetCollectionWithQuery(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + $this->importInvoiceFixtures(5, [Invoice::STATUS_PENDING]); + $this->importInvoiceFixtures(2, [Invoice::STATUS_NEW]); + $this->importInvoiceFixtures(7, [Invoice::STATUS_PAID]); + $this->importInvoiceFixtures(1, [Invoice::STATUS_CANCELED]); + + $query = ['order' => 'ASC', 'orderBy' => 'name', 'status' => [Invoice::STATUS_PAID]]; + $this->assertAccessIsGranted($client, '/api/invoices', 'GET', $query); + + $content = $client->getResponse()->getContent(); + $this->assertIsString($content); + $result = json_decode($content, true); + + $this->assertIsArray($result); + $this->assertNotEmpty($result); + $this->assertEquals(7, \count($result)); + self::assertApiResponseTypeStructure('InvoiceCollection', $result[0]); + } + + public function testGetEntityIsSecure(): void + { + $client = $this->getClientForAuthenticatedUser(); + $invoices = $this->importInvoiceFixtures(1); + + $this->assertApiAccessDenied($client, '/api/invoices/' . $invoices[0]->getId()); + } + + public function testGetEntity(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); + $invoices = $this->importInvoiceFixtures(1); + + $this->assertAccessIsGranted($client, '/api/invoices/' . $invoices[0]->getId()); + + $content = $client->getResponse()->getContent(); + $this->assertIsString($content); + $result = json_decode($content, true); + + $this->assertIsArray($result); + self::assertApiResponseTypeStructure('Invoice', $result); + } + + public function testNotFound(): void + { + $this->assertEntityNotFound(User::ROLE_USER, '/api/invoices/' . PHP_INT_MAX); + } +} diff --git a/tests/API/ProjectControllerTest.php b/tests/API/ProjectControllerTest.php index d6ba97a3..b0182265 100644 --- a/tests/API/ProjectControllerTest.php +++ b/tests/API/ProjectControllerTest.php @@ -326,7 +326,7 @@ class ProjectControllerTest extends APIControllerBaseTest public function testNotFound(): void { - $this->assertEntityNotFound(User::ROLE_USER, '/api/projects/' . PHP_INT_MAX, 'GET', 'App\\Entity\\Project object not found by the @ParamConverter annotation.'); + $this->assertEntityNotFound(User::ROLE_USER, '/api/projects/' . PHP_INT_MAX); } public function testPostAction(): void diff --git a/tests/API/TeamControllerTest.php b/tests/API/TeamControllerTest.php index f93e8ab6..919e2a45 100644 --- a/tests/API/TeamControllerTest.php +++ b/tests/API/TeamControllerTest.php @@ -83,7 +83,7 @@ class TeamControllerTest extends APIControllerBaseTest public function testNotFound(): void { - $this->assertEntityNotFound(User::ROLE_USER, '/api/teams/' . PHP_INT_MAX, 'GET', 'App\\Entity\\Team object not found by the @ParamConverter annotation.'); + $this->assertEntityNotFound(User::ROLE_USER, '/api/teams/' . PHP_INT_MAX); } public function testDeleteActionWithUnknownTeam(): void diff --git a/tests/API/TimesheetControllerTest.php b/tests/API/TimesheetControllerTest.php index 722a695f..735dea70 100644 --- a/tests/API/TimesheetControllerTest.php +++ b/tests/API/TimesheetControllerTest.php @@ -448,7 +448,7 @@ class TimesheetControllerTest extends APIControllerBaseTest public function testGetEntityNotFound(): void { - $this->assertEntityNotFound(User::ROLE_USER, '/api/timesheets/' . PHP_INT_MAX, 'GET', 'App\\Entity\\Timesheet object not found by the @ParamConverter annotation.'); + $this->assertEntityNotFound(User::ROLE_USER, '/api/timesheets/' . PHP_INT_MAX); } public function testPostAction(): void diff --git a/tests/DataFixtures/ActivityFixtures.php b/tests/DataFixtures/ActivityFixtures.php index 1a61f888..93ea23cc 100644 --- a/tests/DataFixtures/ActivityFixtures.php +++ b/tests/DataFixtures/ActivityFixtures.php @@ -19,6 +19,8 @@ use Faker\Factory; */ final class ActivityFixtures implements TestFixture { + use FixturesTrait; + private int $amount = 0; private bool $isGlobal = false; private ?bool $isVisible = null; @@ -127,20 +129,4 @@ final class ActivityFixtures implements TestFixture return $created; } - - /** - * @param ObjectManager $manager - * @return array - */ - private function getAllProjects(ObjectManager $manager): array - { - $all = []; - /** @var Project[] $entries */ - $entries = $manager->getRepository(Project::class)->findAll(); - foreach ($entries as $temp) { - $all[$temp->getId()] = $temp; - } - - return $all; - } } diff --git a/tests/DataFixtures/CustomerFixtures.php b/tests/DataFixtures/CustomerFixtures.php index 704183d9..1572867c 100644 --- a/tests/DataFixtures/CustomerFixtures.php +++ b/tests/DataFixtures/CustomerFixtures.php @@ -34,7 +34,6 @@ final class CustomerFixtures implements TestFixture * Will be called prior to persisting the object. * * @param callable $callback - * @return CustomerFixtures */ public function setCallback(callable $callback): CustomerFixtures { @@ -63,7 +62,6 @@ final class CustomerFixtures implements TestFixture } /** - * @param ObjectManager $manager * @return Customer[] */ public function load(ObjectManager $manager): array diff --git a/tests/DataFixtures/FixturesTrait.php b/tests/DataFixtures/FixturesTrait.php new file mode 100644 index 00000000..22c31da1 --- /dev/null +++ b/tests/DataFixtures/FixturesTrait.php @@ -0,0 +1,91 @@ + + */ + private function getAllUsers(ObjectManager $manager): array + { + $all = []; + /** @var User[] $entries */ + $entries = $manager->getRepository(User::class)->findAll(); + foreach ($entries as $temp) { + if ($temp->getId() === null) { + continue; + } + $all[$temp->getId()] = $temp; + } + + return $all; + } + + /** + * @return array + */ + private function getAllCustomers(ObjectManager $manager): array + { + $all = []; + /** @var Customer[] $entries */ + $entries = $manager->getRepository(Customer::class)->findAll(); + foreach ($entries as $temp) { + if ($temp->getId() === null) { + continue; + } + $all[$temp->getId()] = $temp; + } + + return $all; + } + + /** + * @return array + */ + private function getAllProjects(ObjectManager $manager): array + { + $all = []; + /** @var Project[] $entries */ + $entries = $manager->getRepository(Project::class)->findAll(); + foreach ($entries as $temp) { + if ($temp->getId() === null) { + continue; + } + $all[$temp->getId()] = $temp; + } + + return $all; + } + + /** + * @return array + */ + private function getAllActivities(ObjectManager $manager): array + { + $all = []; + /** @var Activity[] $entries */ + $entries = $manager->getRepository(Activity::class)->findAll(); + foreach ($entries as $temp) { + if ($temp->getId() === null) { + continue; + } + $all[$temp->getId()] = $temp; + } + + return $all; + } +} diff --git a/tests/DataFixtures/InvoiceFixtures.php b/tests/DataFixtures/InvoiceFixtures.php new file mode 100644 index 00000000..be070759 --- /dev/null +++ b/tests/DataFixtures/InvoiceFixtures.php @@ -0,0 +1,76 @@ +amount = $amount; + } + + public function setStatus(array $status): void + { + $this->status = $status; + } + + /** + * @return Invoice[] + */ + public function load(ObjectManager $manager): array + { + $created = []; + + $faker = Factory::create(); + + $customers = $this->getAllCustomers($manager); + $users = $this->getAllUsers($manager); + + for ($i = 0; $i < $this->amount; $i++) { + $total = $faker->randomFloat(2, 50, 5000); + $vat = $faker->randomFloat(2, 0, 23) / 10; + $tax = $total * $vat; + + $invoice = new Invoice(); + $invoice->setStatus($this->status[array_rand($this->status)]); + $invoice->setTotal($total); + $invoice->setVat($vat); + $invoice->setTax($tax); + $invoice->setCustomer($customers[array_rand($customers)]); + + $invoice->setInvoiceNumber($i . '_ ' . $faker->text(10)); + $invoice->setCreatedAt($faker->dateTimeBetween('-1 year', 'now')); + $invoice->setUser($users[array_rand($users)]); + $invoice->setDueDays($faker->randomNumber(2)); + $invoice->setFilename($faker->text(30)); + $invoice->setComment($faker->text(300)); + $invoice->setCurrency($faker->currencyCode()); + + $manager->persist($invoice); + $created[] = $invoice; + } + + $manager->flush(); + + return $created; + } +} diff --git a/tests/DataFixtures/InvoiceTemplateFixtures.php b/tests/DataFixtures/InvoiceTemplateFixtures.php index 870e799d..ff260a66 100644 --- a/tests/DataFixtures/InvoiceTemplateFixtures.php +++ b/tests/DataFixtures/InvoiceTemplateFixtures.php @@ -19,7 +19,6 @@ use Faker\Factory; class InvoiceTemplateFixtures implements TestFixture { /** - * @param ObjectManager $manager * @return InvoiceTemplate[] */ public function load(ObjectManager $manager): array diff --git a/tests/DataFixtures/ProjectFixtures.php b/tests/DataFixtures/ProjectFixtures.php index 655eced3..f31d72fb 100644 --- a/tests/DataFixtures/ProjectFixtures.php +++ b/tests/DataFixtures/ProjectFixtures.php @@ -19,6 +19,8 @@ use Faker\Factory; */ final class ProjectFixtures implements TestFixture { + use FixturesTrait; + private int $amount = 0; private ?bool $isVisible = null; /** @@ -114,20 +116,4 @@ final class ProjectFixtures implements TestFixture return $created; } - - /** - * @param ObjectManager $manager - * @return array - */ - private function getAllCustomers(ObjectManager $manager): array - { - $all = []; - /** @var Customer[] $entries */ - $entries = $manager->getRepository(Customer::class)->findAll(); - foreach ($entries as $temp) { - $all[$temp->getId()] = $temp; - } - - return $all; - } } diff --git a/tests/DataFixtures/TeamFixtures.php b/tests/DataFixtures/TeamFixtures.php index 783bc683..b1e4fe32 100644 --- a/tests/DataFixtures/TeamFixtures.php +++ b/tests/DataFixtures/TeamFixtures.php @@ -9,7 +9,6 @@ namespace App\Tests\DataFixtures; -use App\Entity\Customer; use App\Entity\Team; use App\Entity\User; use Doctrine\Persistence\ObjectManager; @@ -19,22 +18,15 @@ use Doctrine\Persistence\ObjectManager; */ final class TeamFixtures implements TestFixture { - /** - * @var int - */ - private $amount = 0; - /** - * @var bool - */ - private $addCustomer = true; + use FixturesTrait; + + private int $amount = 0; + private bool $addCustomer = true; /** * @var User[] */ - private $skipUser = []; - /** - * @var bool - */ - private $addUser = true; + private array $skipUser = []; + private bool $addUser = true; /** * @var callable */ @@ -44,7 +36,6 @@ final class TeamFixtures implements TestFixture * Will be called prior to persisting the object. * * @param callable $callback - * @return TeamFixtures */ public function setCallback(callable $callback): TeamFixtures { @@ -87,7 +78,6 @@ final class TeamFixtures implements TestFixture } /** - * @param ObjectManager $manager * @return Team[] */ public function load(ObjectManager $manager): array @@ -135,36 +125,4 @@ final class TeamFixtures implements TestFixture return $created; } - - /** - * @param ObjectManager $manager - * @return array - */ - private function getAllCustomers(ObjectManager $manager) - { - $all = []; - /** @var Customer[] $entries */ - $entries = $manager->getRepository(Customer::class)->findAll(); - foreach ($entries as $temp) { - $all[$temp->getId()] = $temp; - } - - return $all; - } - - /** - * @param ObjectManager $manager - * @return array - */ - private function getAllUsers(ObjectManager $manager): array - { - $all = []; - /** @var User[] $entries */ - $entries = $manager->getRepository(User::class)->findAll(); - foreach ($entries as $temp) { - $all[$temp->getId()] = $temp; - } - - return $all; - } } diff --git a/tests/DataFixtures/TimesheetFixtures.php b/tests/DataFixtures/TimesheetFixtures.php index e4988cde..9e6da43c 100644 --- a/tests/DataFixtures/TimesheetFixtures.php +++ b/tests/DataFixtures/TimesheetFixtures.php @@ -24,6 +24,8 @@ use Faker\Factory; */ final class TimesheetFixtures implements TestFixture { + use FixturesTrait; + private int $running = 0; /** * @var Activity[] @@ -307,54 +309,6 @@ final class TimesheetFixtures implements TestFixture return $start; } - /** - * @param ObjectManager $manager - * @return array - */ - private function getAllActivities(ObjectManager $manager): array - { - $all = []; - /** @var Activity[] $entries */ - $entries = $manager->getRepository(Activity::class)->findAll(); - foreach ($entries as $temp) { - $all[$temp->getId()] = $temp; - } - - return $all; - } - - /** - * @param ObjectManager $manager - * @return array - */ - private function getAllProjects(ObjectManager $manager): array - { - $all = []; - /** @var Project[] $entries */ - $entries = $manager->getRepository(Project::class)->findAll(); - foreach ($entries as $temp) { - $all[$temp->getId()] = $temp; - } - - return $all; - } - - /** - * @param ObjectManager $manager - * @return array - */ - private function getAllUsers(ObjectManager $manager): array - { - $all = []; - /** @var User[] $entries */ - $entries = $manager->getRepository(User::class)->findAll(); - foreach ($entries as $temp) { - $all[$temp->getId()] = $temp; - } - - return $all; - } - /** * @param \DateTime $start * @param array $tagArray