From d6fdec2a8ba41824e6d83127eff9b40cf709dba8 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 14 Apr 2024 18:23:14 +0200 Subject: [PATCH] TASK-37: Add ability to accept new clients from CRM --- features/crm-user-sync.feature | 34 ++++++++ src/Controller/ClientController.php | 40 +++++++++ src/Entity/Client.php | 14 ++++ .../ClientAlreadyExistsException.php | 7 ++ src/Repository/ClientRepository.php | 29 ++----- src/Service/ClientService.php | 28 +++++++ tests/Behat/ClientsContext.php | 82 +++++++++++++++++++ 7 files changed, 211 insertions(+), 23 deletions(-) create mode 100644 features/crm-user-sync.feature create mode 100644 src/Controller/ClientController.php create mode 100644 src/Exception/ClientAlreadyExistsException.php create mode 100644 src/Service/ClientService.php create mode 100644 tests/Behat/ClientsContext.php diff --git a/features/crm-user-sync.feature b/features/crm-user-sync.feature new file mode 100644 index 0000000..95d4aea --- /dev/null +++ b/features/crm-user-sync.feature @@ -0,0 +1,34 @@ +Feature: + The CRM system is able to send information about new Clients to the service + + Background: + Given there exist following clients: + | clientId | name | initialBalance | currentBalance | + | 018edd2e-894a-78d7-b10c-16e05ca933a3 | Kacper | 10000 | 5000 | + + Scenario: CRM is able to create new clients + Given the request has the following body: + """ + { + "clientId": "018edd37-c145-7143-ba91-c191084e4fba", + "name": "Jan", + "balance": 100000 + } + """ + When I send a POST request to "/clients" + Then the response status should be 201 + And client with id "018edd37-c145-7143-ba91-c191084e4fba" should exist + And client with id "018edd37-c145-7143-ba91-c191084e4fba" should have balance of 100000 + + Scenario: CRM should not be able to override existing user + Given the request has the following body: + """ + { + "clientId": "018edd2e-894a-78d7-b10c-16e05ca933a3", + "name": "Kacper", + "balance": 100000 + } + """ + When I send a POST request to "/clients" + Then the response status should be 409 + And client with id "018edd2e-894a-78d7-b10c-16e05ca933a3" should exist diff --git a/src/Controller/ClientController.php b/src/Controller/ClientController.php new file mode 100644 index 0000000..16cdd3c --- /dev/null +++ b/src/Controller/ClientController.php @@ -0,0 +1,40 @@ +<?php + +namespace App\Controller; + +use App\Contract\ClientDto; +use App\Entity\Client; +use App\Exception\ClientAlreadyExistsException; +use App\Service\ClientService; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\HttpKernel\Attribute\MapRequestPayload; +use Symfony\Component\Routing\Attribute\Route; + +#[Route(path: '/clients', name: 'clients_')] +#[AsController] +readonly class ClientController +{ + public function __construct( + private ClientService $clientService, + ) { + } + + #[Route(name: 'create', methods: ['POST'])] + public function create(#[MapRequestPayload] ClientDto $clientDto): Response + { + $client = new Client( + clientId: $clientDto->getClientId(), + name: $clientDto->getName(), + initialBalance: $clientDto->getBalance(), + ); + + try { + $this->clientService->createNewClient($client); + } catch (ClientAlreadyExistsException) { + return new Response(status: Response::HTTP_CONFLICT); + } + + return new Response(status: Response::HTTP_CREATED); + } +} diff --git a/src/Entity/Client.php b/src/Entity/Client.php index c657ae3..1e6d81f 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -18,9 +18,13 @@ class Client #[ORM\Column] private ?string $name = null, + #[ORM\Column] + private ?int $initialBalance = null, + #[ORM\Column] private ?int $currentBalance = null, ) { + $this->currentBalance ??= $this->initialBalance; } public function getClientId(): ?Uuid @@ -38,6 +42,16 @@ class Client $this->name = $name; } + public function getInitialBalance(): ?int + { + return $this->initialBalance; + } + + public function setInitialBalance(?int $initialBalance): void + { + $this->initialBalance = $initialBalance; + } + public function getBalance(): ?int { return $this->currentBalance; diff --git a/src/Exception/ClientAlreadyExistsException.php b/src/Exception/ClientAlreadyExistsException.php new file mode 100644 index 0000000..aa0c6b8 --- /dev/null +++ b/src/Exception/ClientAlreadyExistsException.php @@ -0,0 +1,7 @@ +<?php + +namespace App\Exception; + +class ClientAlreadyExistsException extends \LogicException +{ +} diff --git a/src/Repository/ClientRepository.php b/src/Repository/ClientRepository.php index d9d20a0..8609770 100644 --- a/src/Repository/ClientRepository.php +++ b/src/Repository/ClientRepository.php @@ -21,28 +21,11 @@ class ClientRepository extends ServiceEntityRepository parent::__construct($registry, Client::class); } - // /** - // * @return Client[] Returns an array of Client objects - // */ - // public function findByExampleField($value): array - // { - // return $this->createQueryBuilder('c') - // ->andWhere('c.exampleField = :val') - // ->setParameter('val', $value) - // ->orderBy('c.id', 'ASC') - // ->setMaxResults(10) - // ->getQuery() - // ->getResult() - // ; - // } + public function save(Client $client): Client + { + $this->getEntityManager()->persist($client); + $this->getEntityManager()->flush(); - // public function findOneBySomeField($value): ?Client - // { - // return $this->createQueryBuilder('c') - // ->andWhere('c.exampleField = :val') - // ->setParameter('val', $value) - // ->getQuery() - // ->getOneOrNullResult() - // ; - // } + return $client; + } } diff --git a/src/Service/ClientService.php b/src/Service/ClientService.php new file mode 100644 index 0000000..c2beaf8 --- /dev/null +++ b/src/Service/ClientService.php @@ -0,0 +1,28 @@ +<?php + +namespace App\Service; + +use App\Entity\Client; +use App\Exception\ClientAlreadyExistsException; +use App\Repository\ClientRepository; + +class ClientService +{ + public function __construct( + public readonly ClientRepository $clientRepository + ) { + } + + public function createNewClient(Client $client): Client + { + $existing = $this->clientRepository->find($client->getClientId()); + + if ($existing !== null) { + throw new ClientAlreadyExistsException( + message: sprintf('Client with id "%s" already exists.', $client->getClientId()->toRfc4122()) + ); + } + + return $this->clientRepository->save($client); + } +} diff --git a/tests/Behat/ClientsContext.php b/tests/Behat/ClientsContext.php new file mode 100644 index 0000000..4916768 --- /dev/null +++ b/tests/Behat/ClientsContext.php @@ -0,0 +1,82 @@ +<?php + +namespace App\Tests\Behat; + +use App\Entity\Client; +use App\Repository\ClientRepository; +use Behat\Behat\Context\Context; +use Behat\Behat\Tester\Exception\PendingException; +use Behat\Gherkin\Node\TableNode; +use Doctrine\ORM\EntityManagerInterface; +use PHPUnit\Framework\Assert; +use Symfony\Component\Uid\Uuid; + +class ClientsContext implements Context +{ + private array $clients; + + public function __construct( + protected readonly ClientRepository $clientRepository, + ) {} + + /** + * @BeforeScenario + */ + public function clean() + { + $this->clientRepository + ->createQueryBuilder('c') + ->delete() + ->getQuery() + ->execute(); + + $this->clients = []; + } + + /** + * @Given /^there exist following clients:$/ + */ + public function thereExistFollowingClients(TableNode $table) + { + foreach ($table as $row) { + $client = $this->getClient($row['clientId']); + + if (!$client) { + $client = new Client( + clientId: Uuid::fromRfc4122($row['clientId']), + name: $row['name'], + initialBalance: intval($row['initialBalance']), + currentBalance: intval($row['currentBalance']), + ); + + $this->clientRepository->save($client); + } + + $this->clients[$client->getClientId()->toRfc4122()] = $client; + } + } + + public function getClient(string $id): ?Client + { + return $this->clients[$id] ??= $this->clientRepository->find(Uuid::fromRfc4122($id)); + } + + /** + * @Given /^client with id "([^"]+)" should exist$/ + */ + public function clientWithIdShouldExist(string $clientId) + { + Assert::assertNotNull($this->getClient($clientId)); + } + + /** + * @Given /^client with id "([^"]+)" should have balance of (\d+)$/ + */ + public function clientWithIdShouldHaveBalanceOf(string $clientId, int $balance) + { + $client = $this->getClient($clientId); + + Assert::assertEquals($client->getBalance(), $balance); + } + +}