Support third-party caller association with tickets via phone number lookup and adjust related tests

This commit is contained in:
Julien Fastré 2025-06-25 11:39:20 +02:00
parent c0f320ba1a
commit def180ee70
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
3 changed files with 74 additions and 7 deletions

View File

@ -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<ThirdParty> 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.
*

View File

@ -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);
}
}

View File

@ -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());
}
}