diff --git a/composer.json b/composer.json index 9daaf2d..5156b81 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "symfony/validator": "7.3.*", "symfony/yaml": "7.3.*", "twig/extra-bundle": "^2.12|^3.0", + "twig/intl-extra": "^3.21", "twig/twig": "^2.12|^3.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index fd45297..5be3a41 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bc8674fb48687aeee3da991cd7c8d0ad", + "content-hash": "b2a06a767859688f71a67ddab0976aea", "packages": [ { "name": "api-platform/doctrine-common", @@ -4918,6 +4918,92 @@ ], "time": "2025-06-28T08:24:55+00:00" }, + { + "name": "symfony/intl", + "version": "v7.3.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/intl.git", + "reference": "bd50940329ac1cfc4af0491cc4468f477d967e45" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/intl/zipball/bd50940329ac1cfc4af0491cc4468f477d967e45", + "reference": "bd50940329ac1cfc4af0491cc4468f477d967e45", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/string": "<7.1" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Intl\\": "" + }, + "exclude-from-classmap": [ + "/Tests/", + "/Resources/data/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Eriksen Costa", + "email": "eriksen.costa@infranology.com.br" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides access to the localization data of the ICU library", + "homepage": "https://symfony.com", + "keywords": [ + "i18n", + "icu", + "internationalization", + "intl", + "l10n", + "localization" + ], + "support": { + "source": "https://github.com/symfony/intl/tree/v7.3.1" + }, + "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": "2025-06-06T16:10:07+00:00" + }, { "name": "symfony/monolog-bridge", "version": "v7.3.0", @@ -7375,6 +7461,70 @@ ], "time": "2025-02-19T14:29:33+00:00" }, + { + "name": "twig/intl-extra", + "version": "v3.21.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/intl-extra.git", + "reference": "05bc5d46b9df9e62399eae53e7c0b0633298b146" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/05bc5d46b9df9e62399eae53e7c0b0633298b146", + "reference": "05bc5d46b9df9e62399eae53e7c0b0633298b146", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/intl": "^5.4|^6.4|^7.0", + "twig/twig": "^3.13|^4.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Twig\\Extra\\Intl\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Twig extension for Intl", + "homepage": "https://twig.symfony.com", + "keywords": [ + "intl", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/intl-extra/tree/v3.21.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-01-31T20:45:36+00:00" + }, { "name": "twig/twig", "version": "v3.21.1", diff --git a/ecs.php b/ecs.php index 4815bcb..c26fa01 100644 --- a/ecs.php +++ b/ecs.php @@ -13,5 +13,7 @@ return ECSConfig::configure() __DIR__ . '/tests', ]) ->withRootFiles() - ->withRules([FinalClassFixer::class]) + ->withRules([ + FinalClassFixer::class, + ]) ->withSets([LubiSetList::ECS]); diff --git a/migrations/Version20250629160123.php b/migrations/Version20250629160123.php new file mode 100644 index 0000000..78542b7 --- /dev/null +++ b/migrations/Version20250629160123.php @@ -0,0 +1,56 @@ +addSql(<<<'SQL' + ALTER TABLE order_item ADD COLUMN is_paid BOOLEAN DEFAULT 0 NOT NULL + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE order_item ADD COLUMN price_cents INTEGER DEFAULT 0 NOT NULL + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + CREATE TEMPORARY TABLE __temp__order_item AS SELECT name, extras, created_by, id, food_order_id, menu_item_id FROM order_item + SQL); + $this->addSql(<<<'SQL' + DROP TABLE order_item + SQL); + $this->addSql(<<<'SQL' + CREATE TABLE order_item (name VARCHAR(255) NOT NULL, extras VARCHAR(255) DEFAULT NULL, created_by VARCHAR(255) DEFAULT 'nobody' NOT NULL, id BLOB NOT NULL, food_order_id BLOB DEFAULT NULL, menu_item_id BLOB NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_52EA1F09A5D24A7A FOREIGN KEY (food_order_id) REFERENCES food_order (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_52EA1F099AB44FE0 FOREIGN KEY (menu_item_id) REFERENCES menu_item (id) NOT DEFERRABLE INITIALLY IMMEDIATE) + SQL); + $this->addSql(<<<'SQL' + INSERT INTO order_item (name, extras, created_by, id, food_order_id, menu_item_id) SELECT name, extras, created_by, id, food_order_id, menu_item_id FROM __temp__order_item + SQL); + $this->addSql(<<<'SQL' + DROP TABLE __temp__order_item + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_52EA1F09A5D24A7A ON order_item (food_order_id) + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_52EA1F099AB44FE0 ON order_item (menu_item_id) + SQL); + } +} diff --git a/migrations/Version20250629160639.php b/migrations/Version20250629160639.php new file mode 100644 index 0000000..b567250 --- /dev/null +++ b/migrations/Version20250629160639.php @@ -0,0 +1,53 @@ +addSql(<<<'SQL' + ALTER TABLE menu_item ADD COLUMN price_cents INTEGER DEFAULT 0 NOT NULL + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + CREATE TEMPORARY TABLE __temp__menu_item AS SELECT name, deleted_at, id, food_vendor_id, alias_of_id FROM menu_item + SQL); + $this->addSql(<<<'SQL' + DROP TABLE menu_item + SQL); + $this->addSql(<<<'SQL' + CREATE TABLE menu_item (name VARCHAR(255) NOT NULL, deleted_at DATETIME DEFAULT NULL, id BLOB NOT NULL, food_vendor_id BLOB NOT NULL, alias_of_id BLOB DEFAULT NULL, PRIMARY KEY(id), CONSTRAINT FK_D754D5506EF983E8 FOREIGN KEY (food_vendor_id) REFERENCES food_vendor (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_D754D55061F0AFC5 FOREIGN KEY (alias_of_id) REFERENCES menu_item (id) NOT DEFERRABLE INITIALLY IMMEDIATE) + SQL); + $this->addSql(<<<'SQL' + INSERT INTO menu_item (name, deleted_at, id, food_vendor_id, alias_of_id) SELECT name, deleted_at, id, food_vendor_id, alias_of_id FROM __temp__menu_item + SQL); + $this->addSql(<<<'SQL' + DROP TABLE __temp__menu_item + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_D754D5506EF983E8 ON menu_item (food_vendor_id) + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_D754D55061F0AFC5 ON menu_item (alias_of_id) + SQL); + } +} diff --git a/src/Controller/FoodOrderController.php b/src/Controller/FoodOrderController.php index 626d20a..815fba5 100644 --- a/src/Controller/FoodOrderController.php +++ b/src/Controller/FoodOrderController.php @@ -4,6 +4,7 @@ namespace App\Controller; use App\Entity\FoodOrder; use App\Form\FoodOrderType; +use App\Form\OrderFinalize; use App\Repository\FoodOrderRepository; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -104,11 +105,21 @@ final class FoodOrderController extends AbstractController ], Response::HTTP_SEE_OTHER); } - #[Route('/{id}', name: 'app_food_order_show', methods: ['GET'])] - public function show(FoodOrder $foodOrder): Response + #[Route('/{id}', name: 'app_food_order_show', methods: ['GET', 'POST'])] + public function show(Request $request, FoodOrder $foodOrder, EntityManagerInterface $entityManager): Response { + $form = null; + if ($foodOrder->isClosed()) { + $form = $this->createForm(OrderFinalize::class, $foodOrder); + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $entityManager->persist($foodOrder); + $entityManager->flush(); + } + } return $this->render('food_order/show.html.twig', [ 'food_order' => $foodOrder, + 'form' => $form, ]); } } diff --git a/src/Controller/OrderItemController.php b/src/Controller/OrderItemController.php index f52d202..689f3eb 100644 --- a/src/Controller/OrderItemController.php +++ b/src/Controller/OrderItemController.php @@ -3,7 +3,6 @@ namespace App\Controller; use App\Entity\FoodOrder; -use App\Entity\MenuItem; use App\Entity\OrderItem; use App\Form\OrderItemType; use App\Repository\MenuItemRepository; @@ -75,19 +74,6 @@ final class OrderItemController extends AbstractController $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $menuItem = $menuItemRepository->findOneBy([ - 'name' => $orderItem->getName(), - 'foodVendor' => $foodOrder->getFoodVendor(), - ]); - - if ($menuItem === null) { - $menuItem = new MenuItem; - $menuItem->setName($orderItem->getName()); - $menuItem->setFoodVendor($foodOrder->getFoodVendor()); - $entityManager->persist($menuItem); - } - - $orderItem->setMenuItem($menuItem); $orderItem->setFoodOrder($foodOrder); $entityManager->persist($orderItem); $entityManager->flush(); @@ -121,24 +107,6 @@ final class OrderItemController extends AbstractController $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $menuItem = $menuItemRepository->findOneBy([ - 'name' => $orderItem->getName(), - 'foodVendor' => $foodOrder->getFoodVendor(), - ]); - - if ($menuItem === null) { - $menuItem = new MenuItem; - $menuItem->setName($orderItem->getName()); - $menuItem->setFoodVendor($foodOrder->getFoodVendor()); - $entityManager->persist($menuItem); - } - - if ($menuItem->getAliasOf() !== null) { - $menuItem = $menuItem->getAliasOf(); - $orderItem->setName($menuItem->getName()); - } - - $orderItem->setMenuItem($menuItem); $orderItem->setFoodOrder($foodOrder); $entityManager->persist($orderItem); $entityManager->flush(); diff --git a/src/Entity/MenuItem.php b/src/Entity/MenuItem.php index 21beed9..7ccf40f 100644 --- a/src/Entity/MenuItem.php +++ b/src/Entity/MenuItem.php @@ -11,6 +11,7 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; use Symfony\Bridge\Doctrine\Types\UlidType; use Symfony\Component\Uid\Ulid; +use Symfony\Component\Validator\Constraints\Positive; #[ApiResource] #[ORM\Entity(repositoryClass: MenuItemRepository::class)] @@ -35,6 +36,12 @@ class MenuItem #[ORM\Column(length: 255)] private string|null $name = null; + #[ORM\Column(type: 'integer', options: [ + 'default' => 0, + ])] + #[Positive] + private int $priceCents = 0; + public function __construct( #[ORM\Column(type: UlidType::NAME, unique: true)] #[ORM\CustomIdGenerator(class: UlidGenerator::class)] @@ -95,6 +102,11 @@ class MenuItem return $this->name; } + public function getPriceCents(): int + { + return $this->priceCents; + } + public function isDeleted(): bool { return $this->getDeletedAt() instanceof DateTimeImmutable; @@ -137,4 +149,10 @@ class MenuItem return $this; } + + public function setPriceCents(int $priceCents): self + { + $this->priceCents = $priceCents; + return $this; + } } diff --git a/src/Entity/OrderItem.php b/src/Entity/OrderItem.php index 5b2c045..e91c1c0 100644 --- a/src/Entity/OrderItem.php +++ b/src/Entity/OrderItem.php @@ -28,6 +28,12 @@ class OrderItem #[ORM\ManyToOne(inversedBy: 'orderItems')] private FoodOrder|null $foodOrder = null; + #[Groups('food_order:latest')] + #[ORM\Column(type: 'boolean', options: [ + 'default' => false, + ])] + private bool $isPaid = false; + #[Groups(['food_order:latest'])] #[ORM\JoinColumn(nullable: false)] #[ORM\ManyToOne] @@ -37,6 +43,13 @@ class OrderItem #[ORM\Column(length: 255)] private string|null $name = null; + #[Groups('food_order:latest')] + #[ORM\Column(type: 'integer', options: [ + 'default' => 0, + ])] + #[Positive] + private int $priceCents = 0; + public function __construct( #[Groups(['food_order:latest'])] #[ORM\Column(type: UlidType::NAME, unique: true)] @@ -78,6 +91,16 @@ class OrderItem return $this->name; } + public function getPriceCents(): int + { + return $this->priceCents; + } + + public function isPaid(): bool + { + return $this->isPaid; + } + public function setCreatedBy(string $createdBy): static { $this->createdBy = $createdBy; @@ -99,6 +122,12 @@ class OrderItem return $this; } + public function setIsPaid(bool $isPaid): self + { + $this->isPaid = $isPaid; + return $this; + } + public function setMenuItem(MenuItem|null $menuItem): static { $this->menuItem = $menuItem; @@ -113,4 +142,10 @@ class OrderItem return $this; } + + public function setPriceCents(int $priceCents): self + { + $this->priceCents = $priceCents; + return $this; + } } diff --git a/src/EventListener/OrderItemPreFlush.php b/src/EventListener/OrderItemPreFlush.php new file mode 100644 index 0000000..d872300 --- /dev/null +++ b/src/EventListener/OrderItemPreFlush.php @@ -0,0 +1,52 @@ +getObjectManager()->getUnitOfWork()->getIdentityMap()[OrderItem::class] ?? []) as $orderItem) { + $this->checkOrderItem($orderItem, $eventArgs->getObjectManager()); + } + } + + private function checkOrderItem(OrderItem $orderItem, ObjectManager $objectManager): void + { + $menuItem = $this->menuItemRepository->findOneBy([ + 'name' => $orderItem->getName(), + 'foodVendor' => $orderItem->getFoodOrder() + ->getFoodVendor(), + ]); + if ($menuItem === null) { + $menuItem = new MenuItem; + $menuItem->setName($orderItem->getName()); + $menuItem->setFoodVendor($orderItem->getFoodOrder()->getFoodVendor()); + $objectManager->persist($menuItem); + } + if ($menuItem->getAliasOf() !== null) { + $menuItem = $menuItem->getAliasOf(); + $orderItem->setName($menuItem->getName()); + } + $orderItem->setMenuItem($menuItem); + if ($orderItem->getPriceCents() === 0) { + $orderItem->setPriceCents($menuItem->getPriceCents()); + } elseif ($orderItem->getPriceCents() !== $menuItem->getPriceCents()) { + $menuItem->setPriceCents($orderItem->getPriceCents()); + $objectManager->persist($menuItem); + } + } +} diff --git a/src/Form/MenuItemType.php b/src/Form/MenuItemType.php index 7b89e52..53039b6 100644 --- a/src/Form/MenuItemType.php +++ b/src/Form/MenuItemType.php @@ -8,6 +8,7 @@ use Doctrine\ORM\QueryBuilder; use Override; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -29,6 +30,10 @@ final class MenuItemType extends AbstractType ]), ], ]); + $builder->add('priceCents', MoneyType::class, [ + 'label' => 'Price', + 'divisor' => 100, + ]); $builder->add('aliases', EntityType::class, [ 'class' => MenuItem::class, 'choice_label' => 'name', diff --git a/src/Form/OrderFinalize.php b/src/Form/OrderFinalize.php new file mode 100644 index 0000000..2faafdf --- /dev/null +++ b/src/Form/OrderFinalize.php @@ -0,0 +1,32 @@ +add('orderItems', CollectionType::class, [ + 'entry_type' => OrderItemFinalize::class, + 'entry_options' => [ + 'label' => false, + ], + ]) + ->add('save', SubmitType::class) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => FoodOrder::class, + ]); + } +} diff --git a/src/Form/OrderItemFinalize.php b/src/Form/OrderItemFinalize.php new file mode 100644 index 0000000..f4627a9 --- /dev/null +++ b/src/Form/OrderItemFinalize.php @@ -0,0 +1,44 @@ +add(child: 'name', options: [ + 'label' => 'order item', + 'disabled' => true, + ]) + ->add(child: 'extras', options: [ + 'disabled' => true, + ]) + ->add(child: 'createdBy', options: [ + 'disabled' => true, + ]) + ->add(child: 'priceCents', type: MoneyType::class, options: [ + 'label' => 'price', + 'divisor' => 100, + ]) + ->add(child: 'isPaid', type: CheckboxType::class, options: [ + 'required' => false, + 'label' => 'paid?', + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => OrderItem::class, + ]); + } +} diff --git a/templates/food_order/show.html.twig b/templates/food_order/show.html.twig index 3114a60..368b4b0 100644 --- a/templates/food_order/show.html.twig +++ b/templates/food_order/show.html.twig @@ -39,6 +39,38 @@

Items

+ {% if (food_order.isClosed and form) %} + {{ form_start(form) }} +
+ + + + + + + + + + + + {% for itemForm in form.orderItems %} + + + + + + + + {% endfor %} + + + + + +
Byitemextraspriceis paid
{{ field_value(itemForm.createdBy) }}{{ field_value(itemForm.name) }}{{ field_value(itemForm.extras) }}{{ form_widget(itemForm.priceCents) }}{{ form_widget(itemForm.isPaid) }}
{{ form_row(form.save) }} {{ form_row(form._token) }}
+
+ {{ form_end(form, {render_rest: false}) }} + {% else %} @@ -68,6 +100,7 @@ {% endfor %}
+ {% endif %} New Item {% endblock %} diff --git a/templates/menu_item/show.html.twig b/templates/menu_item/show.html.twig index 631050f..973fd91 100644 --- a/templates/menu_item/show.html.twig +++ b/templates/menu_item/show.html.twig @@ -15,6 +15,10 @@ Name {{ menu_item.name }} + + Price + {{ (menu_item.priceCents / 100)|format_currency('EUR') }} + {% if(menu_item.aliasOf) %} Alias of diff --git a/tests/Feature/Controller/MenuItemControllerTest.php b/tests/Feature/Controller/MenuItemControllerTest.php index fd63447..fc2c537 100644 --- a/tests/Feature/Controller/MenuItemControllerTest.php +++ b/tests/Feature/Controller/MenuItemControllerTest.php @@ -13,7 +13,8 @@ use App\Form\OrderItemType; use App\Repository\FoodOrderRepository; use App\Repository\MenuItemRepository; -use function describe; +use function covers; +use function it; use function pest; use function sprintf; use function test; @@ -55,105 +56,105 @@ pest() $this->manager->flush(); }); +covers( + MenuItemController::class, + OrderItemController::class, + OrderItemType::class, + MenuItemRepository::class, + FoodOrder::class, + FoodVendor::class, + MenuItem::class, + OrderItem::class, + FoodOrderRepository::class, + MenuItemType::class, +); -describe(MenuItemController::class, function (): void { - test('show', function (): void { +it('show', function (): void { - $crawler = $this->client->request('GET', "{$this->path}{$this->menuItem->getId()}"); - $idValue = $crawler->filter( - '.table > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(2)' - )->text(); - $nameValue = $crawler->filter( - '.table > tbody:nth-child(1) > tr:nth-child(2) > td:nth-child(2)' - )->text(); + $crawler = $this->client->request('GET', "{$this->path}{$this->menuItem->getId()}"); + $idValue = $crawler->filter( + '.table > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(2)' + )->text(); + $nameValue = $crawler->filter( + '.table > tbody:nth-child(1) > tr:nth-child(2) > td:nth-child(2)' + )->text(); - $aliasTwoNameValue = $crawler->filter( - '.table > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(2) > ul:nth-child(1) > li:nth-child(1)' - )->text(); - $aliasOneNameValue = $crawler->filter( - '.table > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(2) > ul:nth-child(1) > li:nth-child(2)' - )->text(); - $this->assertResponseStatusCodeSame(200); - $this->assertEquals($idValue, $this->menuItem->getId()); - $this->assertEquals($nameValue, $this->menuItem->getName()); - $this->assertEquals($aliasTwoNameValue, $this->aliasOne->getName()); - $this->assertEquals($aliasOneNameValue, $this->aliasTwo->getName()); - }); + $aliasTwoNameValue = $crawler->filter( + '.table > tbody:nth-child(1) > tr:nth-child(4) > td:nth-child(2) > ul:nth-child(1) > li:nth-child(1)' + )->text(); + $aliasOneNameValue = $crawler->filter( + '.table > tbody:nth-child(1) > tr:nth-child(4) > td:nth-child(2) > ul:nth-child(1) > li:nth-child(2)' + )->text(); + $this->assertResponseStatusCodeSame(200); + $this->assertEquals($idValue, $this->menuItem->getId()); + $this->assertEquals($nameValue, $this->menuItem->getName()); + $this->assertEquals($aliasTwoNameValue, $this->aliasOne->getName()); + $this->assertEquals($aliasOneNameValue, $this->aliasTwo->getName()); +}); - test('edit', function (): void { - $crawler = $this->client->request('GET', sprintf('%s%s/edit', $this->path, $this->menuItem->getId())); - $nameElem = $crawler->filter('#menu_item_name'); - $this->assertEquals( - 'Testing 1 2', - $nameElem->attr('value') - ); - - $form = $crawler->selectButton('Update') - ->form(); - $form['menu_item[name]'] = 'Testing-1'; - $form['menu_item[aliases]'][0]->untick(); - - $this->client->submit($form); - - $this->assertResponseRedirects(sprintf('/menu/item/%s', $this->menuItem->getId())); - $menuItem = $this->repository->find($this->menuItem->getId()); - $this->assertEquals('Testing-1', $menuItem->getName()); - $this->assertEquals(1, $menuItem->getAliases()->count()); - $aliasOne = $this->repository->find($this->aliasOne->getId()); - $this->assertNull($aliasOne->getAliasOf()); - }); - - test('edit invalid', function (): void { - $crawler = $this->client->request('GET', sprintf('%s%s/edit', $this->path, $this->menuItem->getId())); - $nameElem = $crawler->filter('#menu_item_name'); - $this->assertEquals( - 'Testing 1 2', - $nameElem->attr('value') - ); - - $form = $crawler->selectButton('Update') - ->form(); - $form['menu_item[name]'] = 'a'; - - $this->client->submit($form); - - $this->assertResponseStatusCodeSame(422); - }); - - test('delete', function (): void { - $order = new FoodOrder; - $order->setFoodVendor($this->vendor); - - $this->manager->persist($order); - $this->manager->flush(); - $this->assertFalse($this->menuItem->isDeleted()); - - $this->client->request('GET', "{$this->path}{$this->menuItem->getId()}"); - $this->client->submitForm('Delete', []); - - $menuItem = $this->repository->find($this->menuItem->getId()); - - $this->assertTrue($menuItem->isDeleted()); - - $crawler = $this->client->request('GET', '/order/item/new/' . $order->getId()); - $count = $crawler->filter('body > main:nth-child(2) > div:nth-child(5)') - ->children() - ->count(); - $this->assertSame(2, $count); - - $this->assertResponseIsSuccessful(); - - }); -}) - ->covers( - MenuItemController::class, - OrderItemController::class, - OrderItemType::class, - MenuItemRepository::class, - FoodOrder::class, - FoodVendor::class, - MenuItem::class, - OrderItem::class, - FoodOrderRepository::class, - MenuItemType::class, +test('edit', function (): void { + $crawler = $this->client->request('GET', sprintf('%s%s/edit', $this->path, $this->menuItem->getId())); + $nameElem = $crawler->filter('#menu_item_name'); + $this->assertEquals( + 'Testing 1 2', + $nameElem->attr('value') ); + + $form = $crawler->selectButton('Update') + ->form(); + $form['menu_item[name]'] = 'Testing-1'; + $form['menu_item[priceCents]'] = '1.23'; + $form['menu_item[aliases]'][0]->untick(); + + $this->client->submit($form); + + $this->assertResponseRedirects(sprintf('/menu/item/%s', $this->menuItem->getId())); + $menuItem = $this->repository->find($this->menuItem->getId()); + $this->assertEquals('Testing-1', $menuItem->getName()); + $this->assertEquals(123, $menuItem->getPriceCents()); + $this->assertEquals(1, $menuItem->getAliases()->count()); + $aliasOne = $this->repository->find($this->aliasOne->getId()); + $this->assertNull($aliasOne->getAliasOf()); +}); + +test('edit invalid', function (): void { + $crawler = $this->client->request('GET', sprintf('%s%s/edit', $this->path, $this->menuItem->getId())); + $nameElem = $crawler->filter('#menu_item_name'); + $this->assertEquals( + 'Testing 1 2', + $nameElem->attr('value') + ); + + $form = $crawler->selectButton('Update') + ->form(); + $form['menu_item[name]'] = 'a'; + + $this->client->submit($form); + + $this->assertResponseStatusCodeSame(422); +}); + +test('delete', function (): void { + $order = new FoodOrder; + $order->setFoodVendor($this->vendor); + + $this->manager->persist($order); + $this->manager->flush(); + $this->assertFalse($this->menuItem->isDeleted()); + + $this->client->request('GET', "{$this->path}{$this->menuItem->getId()}"); + $this->client->submitForm('Delete', []); + + $menuItem = $this->repository->find($this->menuItem->getId()); + + $this->assertTrue($menuItem->isDeleted()); + + $crawler = $this->client->request('GET', '/order/item/new/' . $order->getId()); + $count = $crawler->filter('body > main:nth-child(2) > div:nth-child(5)') + ->children() + ->count(); + $this->assertSame(2, $count); + + $this->assertResponseIsSuccessful(); + +}); diff --git a/tests/Feature/EventListener/OrderItemPreFlushTest.php b/tests/Feature/EventListener/OrderItemPreFlushTest.php new file mode 100644 index 0000000..0dac100 --- /dev/null +++ b/tests/Feature/EventListener/OrderItemPreFlushTest.php @@ -0,0 +1,45 @@ +beforeEach(function (): void { + $this->setEntityClass(FoodOrder::class); + $this->setPath('/food/order/'); + $this->repository = $this->manager->getRepository($this->entityClass); + $this->vendor = new FoodVendor; + $this->vendor->setName('Food Vendor'); + + $this->manager->persist($this->vendor); + + $this->order = new FoodOrder; + $this->order->setFoodVendor($this->vendor); + + $this->manager->persist($this->order); + $this->manager->flush(); + }); + +it('updates the menu item price', function (): void { + $orderItem = new OrderItem; + $orderItem->setFoodOrder($this->order); + $orderItem->setName('Item'); + $orderItem->setPriceCents(100); + + $this->manager->persist($orderItem); + $this->manager->flush(); + + expect($orderItem->getMenuItem()->getPriceCents()) + ->toBe(100); + + $orderItem->setPriceCents(200); + $this->manager->persist($orderItem); + $this->manager->flush(); + + $id = $orderItem->getId(); + + $orderItem = $this->manager->find(OrderItem::class, $id); + expect($orderItem->getMenuItem()->getPriceCents()) + ->toBe(200); +}); diff --git a/tests/Pest.php b/tests/Pest.php index 846dfad..53d7387 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -14,7 +14,7 @@ use App\Tests\DbWebTest; */ pest() - ->extends(DbWebTest::class)->in('Feature/Controller/*.php'); + ->extends(DbWebTest::class)->in('Feature/Controller/*.php', 'Feature/EventListener/*.php'); /* |-------------------------------------------------------------------------- diff --git a/var/.gitkeep b/var/.gitkeep deleted file mode 100644 index e69de29..0000000