From def180ee704f90e09246c0acbe5e5adfc25f49e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 25 Jun 2025 11:39:20 +0200 Subject: [PATCH] Support third-party caller association with tickets via phone number lookup and adjust related tests --- .../Repository/ThirdPartyRepository.php | 42 ++++++++++++++++++- .../AssociateByPhonenumberCommandHandler.php | 13 ++++-- ...sociateByPhonenumberCommandHandlerTest.php | 26 +++++++++++- 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php index 111be4089..de9cdd270 100644 --- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php +++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php @@ -18,12 +18,15 @@ use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ObjectRepository; +use libphonenumber\PhoneNumber; +use libphonenumber\PhoneNumberFormat; +use libphonenumber\PhoneNumberUtil; class ThirdPartyRepository implements ObjectRepository { private readonly EntityRepository $repository; - public function __construct(EntityManagerInterface $em, private readonly Connection $connection) + public function __construct(EntityManagerInterface $em, private readonly Connection $connection, private readonly PhoneNumberUtil $phonenumberUtil) { $this->repository = $em->getRepository(ThirdParty::class); } @@ -122,6 +125,43 @@ class ThirdPartyRepository implements ObjectRepository return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } + /** + * Finds third-party records by phone number. + * + * The search is performed agains every phonenumber field (there are two phonenumber on a thirdParty). + * + * @param string|PhoneNumber $phonenumber The phone number to search for. Can be a string or a PhoneNumber object. + * @param int $firstResult the index of the first result to retrieve (pagination start) + * @param int $maxResults the maximum number of results to retrieve (pagination limit) + * + * @return list the result set containing matching third-party records + */ + public function findByPhonenumber(string|PhoneNumber $phonenumber, int $firstResult = 0, int $maxResults = 20): array + { + if ('' === $phonenumber) { + return []; + } + + $qb = $this->createQueryBuilder('tp'); + $qb->select('tp'); + + $qb->where( + $qb->expr()->orX( + $qb->expr()->eq('t.telephone', ':phonenumber'), + $qb->expr()->eq('t.telephone2', ':phonenumber') + ) + ); + + $qb->setParameter( + 'phonenumber', + is_string($phonenumber) ? $phonenumber : $this->phonenumberUtil->format($phonenumber, PhoneNumberFormat::E164) + ); + + $qb->setFirstResult($firstResult)->setMaxResults($maxResults); + + return $qb->getQuery()->getResult(); + } + /** * Search amongst parties associated to $centers, with $terms parameters. * diff --git a/src/Bundle/ChillTicketBundle/src/Action/Ticket/Handler/AssociateByPhonenumberCommandHandler.php b/src/Bundle/ChillTicketBundle/src/Action/Ticket/Handler/AssociateByPhonenumberCommandHandler.php index d794250c5..a5518504f 100644 --- a/src/Bundle/ChillTicketBundle/src/Action/Ticket/Handler/AssociateByPhonenumberCommandHandler.php +++ b/src/Bundle/ChillTicketBundle/src/Action/Ticket/Handler/AssociateByPhonenumberCommandHandler.php @@ -13,8 +13,9 @@ namespace Chill\TicketBundle\Action\Ticket\Handler; use Chill\MainBundle\Phonenumber\PhonenumberHelper; use Chill\PersonBundle\Repository\PersonACLAwareRepositoryInterface; +use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; use Chill\TicketBundle\Action\Ticket\AssociateByPhonenumberCommand; -use Chill\TicketBundle\Entity\PersonHistory; +use Chill\TicketBundle\Entity\CallerHistory; use Chill\TicketBundle\Entity\Ticket; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Clock\ClockInterface; @@ -23,6 +24,7 @@ class AssociateByPhonenumberCommandHandler { public function __construct( private readonly PersonACLAwareRepositoryInterface $personRepository, + private readonly ThirdPartyRepository $thirdPartyRepository, private readonly PhonenumberHelper $phonenumberHelper, private readonly ClockInterface $clock, private readonly EntityManagerInterface $entityManager, @@ -31,10 +33,13 @@ class AssociateByPhonenumberCommandHandler public function __invoke(Ticket $ticket, AssociateByPhonenumberCommand $command): void { $phone = $this->phonenumberHelper->parse($command->phonenumber); - $persons = $this->personRepository->findByPhone($phone); + $callers = [ + ...$this->personRepository->findByPhone($phone), + ...$this->thirdPartyRepository->findByPhonenumber($phone), + ]; - foreach ($persons as $person) { - $history = new PersonHistory($person, $ticket, $this->clock->now()); + if (count($callers) > 0) { + $history = new CallerHistory($callers[0], $ticket, $this->clock->now()); $this->entityManager->persist($history); } } diff --git a/src/Bundle/ChillTicketBundle/tests/Action/Ticket/Handler/AssociateByPhonenumberCommandHandlerTest.php b/src/Bundle/ChillTicketBundle/tests/Action/Ticket/Handler/AssociateByPhonenumberCommandHandlerTest.php index 5ade6ec82..067443bd9 100644 --- a/src/Bundle/ChillTicketBundle/tests/Action/Ticket/Handler/AssociateByPhonenumberCommandHandlerTest.php +++ b/src/Bundle/ChillTicketBundle/tests/Action/Ticket/Handler/AssociateByPhonenumberCommandHandlerTest.php @@ -14,10 +14,13 @@ namespace Chill\TicketBundle\Tests\Action\Ticket\Handler; use Chill\MainBundle\Phonenumber\PhonenumberHelper; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Repository\PersonACLAwareRepositoryInterface; +use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; use Chill\TicketBundle\Action\Ticket\AssociateByPhonenumberCommand; use Chill\TicketBundle\Action\Ticket\Handler\AssociateByPhonenumberCommandHandler; use Chill\TicketBundle\Entity\Ticket; use Doctrine\ORM\EntityManagerInterface; +use libphonenumber\PhoneNumber; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -37,6 +40,7 @@ class AssociateByPhonenumberCommandHandlerTest extends TestCase private function getHandler( PersonACLAwareRepositoryInterface $personACLAwareRepository, + ThirdPartyRepository $thirdPartyRepository, ): AssociateByPhonenumberCommandHandler { $entityManager = $this->prophesize(EntityManagerInterface::class); $phonenumberHelper = new PhonenumberHelper( @@ -51,6 +55,7 @@ class AssociateByPhonenumberCommandHandlerTest extends TestCase return new AssociateByPhonenumberCommandHandler( $personACLAwareRepository, + $thirdPartyRepository, $phonenumberHelper, new MockClock(), $entityManager->reveal() @@ -63,12 +68,29 @@ class AssociateByPhonenumberCommandHandlerTest extends TestCase $personAclAwareRepository = $this->prophesize(PersonACLAwareRepositoryInterface::class); $personAclAwareRepository->findByPhone(Argument::any())->willReturn([$person]); + $thirdPartyRepository = $this->prophesize(ThirdPartyRepository::class); + $thirdPartyRepository->findByPhonenumber(Argument::type(PhoneNumber::class))->willReturn([]); - $handler = $this->getHandler($personAclAwareRepository->reveal()); + $handler = $this->getHandler($personAclAwareRepository->reveal(), $thirdPartyRepository->reveal()); $ticket = new Ticket(); $handler($ticket, new AssociateByPhonenumberCommand('+3281136917')); - self::assertSame($person, $ticket->getPersons()[0]); + self::assertSame($person, $ticket->getCaller()); + } + + public function testHandleWithThirdPartyFoundByPhonenumber(): void + { + $personAclAwareRepository = $this->prophesize(PersonACLAwareRepositoryInterface::class); + $personAclAwareRepository->findByPhone(Argument::any())->willReturn([]); + $thirdPartyRepository = $this->prophesize(ThirdPartyRepository::class); + $thirdPartyRepository->findByPhonenumber(Argument::type(PhoneNumber::class))->willReturn([$thirdParty = new ThirdParty()]); + + $handler = $this->getHandler($personAclAwareRepository->reveal(), $thirdPartyRepository->reveal()); + + $ticket = new Ticket(); + $handler($ticket, new AssociateByPhonenumberCommand('081136917')); + + self::assertSame($thirdParty, $ticket->getCaller()); } }