feat: multiple hotelcodes assignable to users

This commit is contained in:
Björn Fromme
2025-01-08 10:07:19 +01:00
parent 5a07d95837
commit c15188c43c
16 changed files with 256 additions and 67 deletions
+1
View File
@@ -26,6 +26,7 @@
"oneup/uploader-bundle": "^4.0", "oneup/uploader-bundle": "^4.0",
"phpdocumentor/reflection-docblock": "^5.3", "phpdocumentor/reflection-docblock": "^5.3",
"phpstan/phpdoc-parser": "^1.22", "phpstan/phpdoc-parser": "^1.22",
"scienta/doctrine-json-functions": "^6.3",
"setasign/fpdf": "^1.8", "setasign/fpdf": "^1.8",
"setasign/fpdi": "^2.5", "setasign/fpdi": "^2.5",
"spatie/icalendar-generator": "^2.5", "spatie/icalendar-generator": "^2.5",
Generated
+73 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "1e48d4a4ffe643c14cf370b7083adddb", "content-hash": "804c55640363108581ce07cf9dedaece",
"packages": [ "packages": [
{ {
"name": "beberlei/doctrineextensions", "name": "beberlei/doctrineextensions",
@@ -2979,6 +2979,78 @@
}, },
"time": "2024-09-11T13:17:53+00:00" "time": "2024-09-11T13:17:53+00:00"
}, },
{
"name": "scienta/doctrine-json-functions",
"version": "6.3.0",
"source": {
"type": "git",
"url": "https://github.com/ScientaNL/DoctrineJsonFunctions.git",
"reference": "554b2fd281e976a791501fc4753ffd4c5891ec62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ScientaNL/DoctrineJsonFunctions/zipball/554b2fd281e976a791501fc4753ffd4c5891ec62",
"reference": "554b2fd281e976a791501fc4753ffd4c5891ec62",
"shasum": ""
},
"require": {
"doctrine/dbal": "^3.2 || ^4",
"doctrine/lexer": "^2.0 || ^3.0",
"doctrine/orm": "^2.19 || ^3",
"ext-pdo": "*",
"php": "^8.1"
},
"require-dev": {
"doctrine/coding-standard": "^9.0 || ^10.0 || ^11.0 || ^12.0",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^1.12",
"phpstan/phpstan-doctrine": "^1.4",
"phpstan/phpstan-phpunit": "^1.4",
"phpunit/phpunit": "^10.1",
"psalm/plugin-phpunit": "^0.18",
"slevomat/coding-standard": "~8",
"symfony/cache": "^5.4 || ^6.4 || ^7",
"vimeo/psalm": "^5.2",
"webmozart/assert": "^1.11"
},
"suggest": {
"dunglas/doctrine-json-odm": "To serialize / deserialize objects as JSON documents."
},
"type": "library",
"autoload": {
"psr-4": {
"Scienta\\DoctrineJsonFunctions\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Doctrine Json Functions Contributors",
"homepage": "https://github.com/ScientaNL/DoctrineJsonFunctions/contributors"
}
],
"description": "A set of extensions to Doctrine that add support for json query functions.",
"keywords": [
"database",
"doctrine",
"dql",
"json",
"mariadb",
"mysql",
"orm",
"postgres",
"postgresql",
"sqlite"
],
"support": {
"issues": "https://github.com/ScientaNL/DoctrineJsonFunctions/issues",
"source": "https://github.com/ScientaNL/DoctrineJsonFunctions/tree/6.3.0"
},
"time": "2024-11-08T12:33:19+00:00"
},
{ {
"name": "setasign/fpdf", "name": "setasign/fpdf",
"version": "1.8.6", "version": "1.8.6",
+1
View File
@@ -23,6 +23,7 @@ doctrine:
string_functions: string_functions:
DATE_FORMAT: DoctrineExtensions\Query\Mysql\DateFormat DATE_FORMAT: DoctrineExtensions\Query\Mysql\DateFormat
FIELD: DoctrineExtensions\Query\Mysql\Field FIELD: DoctrineExtensions\Query\Mysql\Field
JSON_CONTAINS: Scienta\DoctrineJsonFunctions\Query\AST\Functions\Mysql\JsonContains
datetime_functions: datetime_functions:
DATEDIFF: DoctrineExtensions\Query\Mysql\DateDiff DATEDIFF: DoctrineExtensions\Query\Mysql\DateDiff
when@test: when@test:
+46
View File
@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250107163840 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user ADD hotel_codes JSON NOT NULL COMMENT \'(DC2Type:json)\'');
}
public function postUp(Schema $schema): void
{
$this->connection->executeQuery('UPDATE user SET hotel_codes="[]" WHERE hotel_code IS NULL');
$rows = $this->connection->fetchAllAssociative('SELECT id, hotel_code FROM user WHERE hotel_code IS NOT NULL');
foreach ($rows as $row) {
$this->connection->update('user', [
'hotel_codes' => json_encode([$row['hotel_code']]),
], [
'id' => $row['id'],
]);
}
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user DROP hotel_codes');
}
}
@@ -9,7 +9,7 @@ class CrmAttributesResponse
private bool $manager = false; private bool $manager = false;
private bool $houseManager = false; private bool $houseManager = false;
private bool $teamer = false; private bool $teamer = false;
private ?string $hotelCode = null; private array $hotelCodes = [];
public function getAttributeGroups(): ?array public function getAttributeGroups(): ?array
{ {
@@ -70,14 +70,14 @@ class CrmAttributesResponse
return $this; return $this;
} }
public function getHotelCode(): ?string public function getHotelCodes(): array
{ {
return $this->hotelCode; return $this->hotelCodes;
} }
public function setHotelCode(?string $hotelCode): static public function setHotelCodes(array $hotelCodes): static
{ {
$this->hotelCode = $hotelCode; $this->hotelCodes = $hotelCodes;
return $this; return $this;
} }
+4 -4
View File
@@ -142,7 +142,7 @@ class ResponseParser
{ {
$groups = []; $groups = [];
$isAdmin = $isManager = $isHouseManager = $isTeamer = false; $isAdmin = $isManager = $isHouseManager = $isTeamer = false;
$hotelCode = null; $hotelCodes = [];
foreach ($xml->selektionsmerkmale->selektionsgruppe as $item) { foreach ($xml->selektionsmerkmale->selektionsgruppe as $item) {
$group = new CrmAttributeGroup(); $group = new CrmAttributeGroup();
@@ -164,7 +164,7 @@ class ResponseParser
if (1 === preg_match('/^Hausleitung ([A-Z0-9]+)$/', $attributeLabel, $matches) && true === $attribute->isSelected()) { if (1 === preg_match('/^Hausleitung ([A-Z0-9]+)$/', $attributeLabel, $matches) && true === $attribute->isSelected()) {
$isHouseManager = true; $isHouseManager = true;
$hotelCode = $matches[1]; $hotelCodes[] = $matches[1];
} }
if ($this->config['bpn_crm_id_admin'] === $attribute->getId() && true === $attribute->isSelected()) { if ($this->config['bpn_crm_id_admin'] === $attribute->getId() && true === $attribute->isSelected()) {
$isAdmin = true; $isAdmin = true;
@@ -183,7 +183,7 @@ class ResponseParser
// Apply additional role and hotel code for testing purposes when provided // Apply additional role and hotel code for testing purposes when provided
if ($isAdmin && null !== $this->config['bpn_default_hotel_code']) { if ($isAdmin && null !== $this->config['bpn_default_hotel_code']) {
$isHouseManager = true; $isHouseManager = true;
$hotelCode = $this->config['bpn_default_hotel_code']; $hotelCodes[] = $this->config['bpn_default_hotel_code'];
} }
$response = new CrmAttributesResponse(); $response = new CrmAttributesResponse();
@@ -193,7 +193,7 @@ class ResponseParser
->setManager($isManager) ->setManager($isManager)
->setTeamer($isTeamer) ->setTeamer($isTeamer)
->setHouseManager($isHouseManager) ->setHouseManager($isHouseManager)
->setHotelCode($hotelCode) ->setHotelCodes($hotelCodes)
; ;
return $response; return $response;
+4 -4
View File
@@ -55,7 +55,7 @@ class UserDataHandler
array $roles, array $roles,
bool $isTeamer = false, bool $isTeamer = false,
array $crmSelections = [], array $crmSelections = [],
?string $hotelCode = null array $hotelCodes = []
): User { ): User {
$user = new User(); $user = new User();
$user $user
@@ -64,7 +64,7 @@ class UserDataHandler
->setEmail($profileResponse->getCommunication()->getEmail()) ->setEmail($profileResponse->getCommunication()->getEmail())
->setBusProPersonId($profileResponse->getPersonId()) ->setBusProPersonId($profileResponse->getPersonId())
->setBusProAddressId($profileResponse->getAddressId()) ->setBusProAddressId($profileResponse->getAddressId())
->setHotelCode($hotelCode) ->setHotelCodes($hotelCodes)
->setRoles($roles) ->setRoles($roles)
; ;
@@ -95,12 +95,12 @@ class UserDataHandler
array $roles, array $roles,
bool $isTeamer = false, bool $isTeamer = false,
array $crmSelections = [], array $crmSelections = [],
?string $hotelCode = null array $hotelCodes = []
): void { ): void {
$user $user
->setEmail($profileResponse->getCommunication()->getEmail()) ->setEmail($profileResponse->getCommunication()->getEmail())
->setRoles($roles) ->setRoles($roles)
->setHotelCode($hotelCode) ->setHotelCodes($hotelCodes)
; ;
if (true === $isTeamer) { if (true === $isTeamer) {
@@ -28,7 +28,7 @@ class IndexController extends AbstractController
$query = $this $query = $this
->dispositionRepository ->dispositionRepository
->getDispositionsWithPendingFeedbackQuery($user->getHotelCode()) ->getDispositionsWithPendingFeedbackQuery($user->getHotelCodes())
; ;
$pagination = $this->paginator->paginate( $pagination = $this->paginator->paginate(
@@ -32,12 +32,12 @@ class IndexController extends AbstractController
$newDispositions = $this $newDispositions = $this
->dispositionRepository ->dispositionRepository
->findNewDispositionsByHotelCode($user->getHotelCode()) ->findNewDispositionsByHotelCodes($user->getHotelCodes())
; ;
$pendingFeedbacks = $this $pendingFeedbacks = $this
->dispositionRepository ->dispositionRepository
->findDispositionsWithPendingFeedbackByHotelCode($user->getHotelCode()) ->findDispositionsWithPendingFeedbackByHotelCodes($user->getHotelCodes())
; ;
return $this->render('house_manager/index.html.twig', [ return $this->render('house_manager/index.html.twig', [
+21 -4
View File
@@ -54,6 +54,9 @@ class User implements UserInterface, TimestampableEntityInterface
#[ORM\Column(length: 32, nullable: true)] #[ORM\Column(length: 32, nullable: true)]
private ?string $hotelCode = null; private ?string $hotelCode = null;
#[ORM\Column(type: 'json')]
private array $hotelCodes = [];
#[ORM\Column] #[ORM\Column]
private bool $muteNotifications = false; private bool $muteNotifications = false;
@@ -256,14 +259,14 @@ class User implements UserInterface, TimestampableEntityInterface
return $this; return $this;
} }
public function getHotelCode(): ?string public function getHotelCodes(): array
{ {
return $this->hotelCode; return $this->hotelCodes;
} }
public function setHotelCode(?string $hotelCode): static public function setHotelCodes(array $hotelCodes): static
{ {
$this->hotelCode = $hotelCode; $this->hotelCodes = $hotelCodes;
return $this; return $this;
} }
@@ -279,4 +282,18 @@ class User implements UserInterface, TimestampableEntityInterface
return $this; return $this;
} }
public function hasHotelCodeMatch(string $hotelCode): bool
{
foreach ($this->hotelCodes as $userHotelCode) {
if (
str_starts_with($hotelCode, $userHotelCode)
|| str_ends_with($hotelCode, $userHotelCode)
) {
return true;
}
}
return false;
}
} }
+17 -7
View File
@@ -148,8 +148,10 @@ class DispositionRepository extends ServiceEntityRepository
; ;
} }
public function findNewDispositionsByHotelCode(string $hotelCode): array public function findNewDispositionsByHotelCodes(mixed $hotelCode): array
{ {
$hotelCodes = (array) $hotelCode;
$qb = $this->createQueryBuilder('disposition'); $qb = $this->createQueryBuilder('disposition');
return $qb return $qb
@@ -157,12 +159,15 @@ class DispositionRepository extends ServiceEntityRepository
->innerJoin('disposition.assignment', 'assignment') ->innerJoin('disposition.assignment', 'assignment')
->innerJoin('assignment.destination', 'destination') ->innerJoin('assignment.destination', 'destination')
->where($qb->expr()->andX( ->where($qb->expr()->andX(
$qb->expr()->like('destination.hotelCode', ':hotelCode'), $qb->expr()->orX(
$qb->expr()->in($qb->expr()->substring('destination.hotelCode', 1, 3), ':hotelCodes'),
$qb->expr()->in($qb->expr()->substring('destination.hotelCode', -3, 3), ':hotelCodes'),
),
$qb->expr()->gte('destination.dateTo', ':dateTo'), $qb->expr()->gte('destination.dateTo', ':dateTo'),
$qb->expr()->eq('disposition.status', ':status') $qb->expr()->eq('disposition.status', ':status')
)) ))
->orderBy('destination.dateFrom', 'ASC') ->orderBy('destination.dateFrom', 'ASC')
->setParameter('hotelCode', '%'.$hotelCode.'%') ->setParameter('hotelCodes', $hotelCodes)
->setParameter('dateTo', new \DateTimeImmutable()) ->setParameter('dateTo', new \DateTimeImmutable())
->setParameter('status', Disposition::STATUS_CONFIRMED) ->setParameter('status', Disposition::STATUS_CONFIRMED)
->getQuery() ->getQuery()
@@ -170,8 +175,10 @@ class DispositionRepository extends ServiceEntityRepository
; ;
} }
public function getDispositionsWithPendingFeedbackQuery(?string $hotelCode = null, ?int $offsetDays = null): Query public function getDispositionsWithPendingFeedbackQuery(mixed $hotelCode = null, ?int $offsetDays = null): Query
{ {
$hotelCodes = (array) $hotelCode;
$qb = $this->createQueryBuilder('disposition'); $qb = $this->createQueryBuilder('disposition');
$qb $qb
@@ -201,8 +208,11 @@ class DispositionRepository extends ServiceEntityRepository
if (null !== $hotelCode) { if (null !== $hotelCode) {
$qb $qb
->andWhere($qb->expr()->like('destination.hotelCode', ':hotelCode')) ->andWhere($qb->expr()->orX(
->setParameter('hotelCode', '%'.$hotelCode.'%') $qb->expr()->in($qb->expr()->substring('destination.hotelCode', 1, 3), ':hotelCodes'),
$qb->expr()->in($qb->expr()->substring('destination.hotelCode', -3, 3), ':hotelCodes'),
))
->setParameter('hotelCodes', $hotelCodes)
; ;
} }
@@ -217,7 +227,7 @@ class DispositionRepository extends ServiceEntityRepository
; ;
} }
public function findDispositionsWithPendingFeedbackByHotelCode(string $hotelCode): array public function findDispositionsWithPendingFeedbackByHotelCodes(mixed $hotelCode): array
{ {
return $this return $this
->getDispositionsWithPendingFeedbackQuery($hotelCode) ->getDispositionsWithPendingFeedbackQuery($hotelCode)
+28 -25
View File
@@ -32,16 +32,14 @@ class UserRepository extends ServiceEntityRepository
$qb = $this->createQueryBuilder('u'); $qb = $this->createQueryBuilder('u');
return $qb return $qb
->where($qb->expr()->orX( ->where("JSON_CONTAINS(u.roles, :role_admin) = 1")
$qb->expr()->like('u.roles', ':role_admin'), ->orWhere("JSON_CONTAINS(u.roles, :role_manager) = 1")
$qb->expr()->like('u.roles', ':role_manager'), ->orWhere("JSON_CONTAINS(u.roles, :role_house_manager) = 1")
$qb->expr()->like('u.roles', ':role_house_manager')
))
->orderBy('u.lastName', 'ASC') ->orderBy('u.lastName', 'ASC')
->setParameters([ ->setParameters([
'role_admin' => '%"ROLE_ADMIN"%', 'role_admin' => json_encode('ROLE_ADMIN'),
'role_manager' => '%"ROLE_MANAGER"%', 'role_manager' => json_encode('ROLE_MANAGER'),
'role_house_manager' => '%"ROLE_HOUSE_MANAGER"%', 'role_house_manager' => json_encode('ROLE_HOUSE_MANAGER'),
]) ])
->getQuery() ->getQuery()
->getResult() ->getResult()
@@ -50,22 +48,29 @@ class UserRepository extends ServiceEntityRepository
/** /**
* @param string $role * @param string $role
* @param string $hotelCode * @param string[]|string $hotelCode
* @return User[] * @return User[]
*/ */
public function getUsersByRoleAndHotelCode(string $role, string $hotelCode): array public function getUsersByRoleAndHotelCode(string $role, mixed $hotelCode): array
{ {
$hotelCodeBase = substr($hotelCode, 0, 3); $hotelCodes = (array) $hotelCode;
$hotelCodesBase = array_map(function ($code) {
return substr($code, 0, 3);
}, $hotelCodes);
$qb = $this->createQueryBuilder('user'); $qb = $this->createQueryBuilder('user');
foreach ($hotelCodesBase as $index => $code) {
$qb
->orWhere('JSON_CONTAINS(user.hotelCodes, :hotelCode_'.$index.') = 1')
->setParameter('hotelCode_'.$index, json_encode($code))
;
}
return $qb return $qb
->where($qb->expr()->andX( ->andWhere('JSON_CONTAINS(user.roles, :role) = 1')
$qb->expr()->eq('user.hotelCode', ':hotelCode'), ->setParameter('role', json_encode($role))
$qb->expr()->like('user.roles', ':role')
))
->setParameter('hotelCode', $hotelCodeBase)
->setParameter('role', '%"'.$role.'"%')
->getQuery() ->getQuery()
->getResult() ->getResult()
; ;
@@ -76,17 +81,15 @@ class UserRepository extends ServiceEntityRepository
$qb = $this->createQueryBuilder('user'); $qb = $this->createQueryBuilder('user');
$users = $qb $users = $qb
->where($qb->expr()->andX( ->where($qb->expr()->orX(
$qb->expr()->orX( $qb->expr()->like('user.lastName', ':search'),
$qb->expr()->like('user.lastName', ':search'), $qb->expr()->like('user.firstName', ':search'),
$qb->expr()->like('user.firstName', ':search'), ))
)), ->andWhere('JSON_CONTAINS(user.roles, :role) = 1')
$qb->expr()->like('user.roles', ':role')
)
->orderBy('user.lastName', 'ASC') ->orderBy('user.lastName', 'ASC')
->addOrderBy('user.firstName', 'ASC') ->addOrderBy('user.firstName', 'ASC')
->setParameter('search', '%'.$this->escapeLikeWildcards($search).'%') ->setParameter('search', '%'.$this->escapeLikeWildcards($search).'%')
->setParameter('role', '%"'.$this->escapeLikeWildcards($role).'"%') ->setParameter('role', json_encode($role))
->getQuery() ->getQuery()
->getResult() ->getResult()
; ;
+2 -2
View File
@@ -137,7 +137,7 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent
if (null !== $user) { if (null !== $user) {
$this $this
->userDataHandler ->userDataHandler
->updateLocalUser($user, $profileResponse, $roles, $isTeamer, $crmSelections, $crmAttributes->getHotelCode()) ->updateLocalUser($user, $profileResponse, $roles, $isTeamer, $crmSelections, $crmAttributes->getHotelCodes())
; ;
return $user; return $user;
@@ -145,7 +145,7 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent
return $this return $this
->userDataHandler ->userDataHandler
->createLocalUser($profileResponse, $roles, $isTeamer, $crmSelections, $crmAttributes->getHotelCode()) ->createLocalUser($profileResponse, $roles, $isTeamer, $crmSelections, $crmAttributes->getHotelCodes())
; ;
} }
} }
+2 -1
View File
@@ -5,6 +5,7 @@ namespace App\Security\Voter;
use App\BusProNet\DataProvider\HotelDataProvider; use App\BusProNet\DataProvider\HotelDataProvider;
use App\BusProNet\Model\Hotel; use App\BusProNet\Model\Hotel;
use App\Entity\Disposition; use App\Entity\Disposition;
use App\Entity\User;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter; use Symfony\Component\Security\Core\Authorization\Voter\Voter;
@@ -93,4 +94,4 @@ class DispositionVoter extends Voter
return $this->security->getUser()->getTeamer() === $disposition->getTeamer(); return $this->security->getUser()->getTeamer() === $disposition->getTeamer();
} }
} }
+23 -11
View File
@@ -38,24 +38,30 @@ class FeedbackReminderService
continue; continue;
} }
// Get hotel base code to find hotel manager later // Get hotel code to find hotel manager later
$hotelBaseCode = substr($hotel->getCode(), 0, 3); $hotelCode = $hotel->getCode();
if (false === array_key_exists($hotelBaseCode, $sortedFeedbacks)) { if (false === array_key_exists($hotelCode, $sortedFeedbacks)) {
$sortedFeedbacks[$hotelBaseCode] = []; $sortedFeedbacks[$hotelCode] = [];
} }
// Sort feedback by hotel base code // Sort feedback by hotel base code
$sortedFeedbacks[$hotelBaseCode][] = $disposition; $sortedFeedbacks[$hotelCode][] = $disposition;
} }
// Determine hotel managers to notify // find hotel managers by hotel codes starting or ending with base code
$hotelBaseCodes = array_keys($sortedFeedbacks); $hotelCodes = array_keys($sortedFeedbacks);
$hotelBaseCodes = [];
foreach ($hotelCodes as $hotelCode) {
$hotelBaseCodes[] = substr($hotelCode, 0, 3);
$hotelBaseCodes[] = substr($hotelCode, -3, 3);
}
/** @var User[] $hotelManagers */ /** @var User[] $hotelManagers */
$hotelManagers = $this->userRepository->findBy([ $hotelManagers = $this
'hotelCode' => $hotelBaseCodes, ->userRepository
]); ->getUsersByRoleAndHotelCode('ROLE_HOTEL_MANAGER', $hotelBaseCodes)
;
if (0 === count($hotelManagers)) { if (0 === count($hotelManagers)) {
return 'No feedback reminders to be sent to hotel managers'; return 'No feedback reminders to be sent to hotel managers';
@@ -65,8 +71,14 @@ class FeedbackReminderService
if (true === $manager->isMuteNotifications()) { if (true === $manager->isMuteNotifications()) {
continue; continue;
} }
$feedbackKeys = array_filter(array_keys($sortedFeedbacks), function (string $key) use ($manager) {
return $manager->hasHotelCodeMatch($key);
});
$feedbacksForManager = array_filter($sortedFeedbacks, function ($key) use ($feedbackKeys) {
return in_array($key, $feedbackKeys);
}, ARRAY_FILTER_USE_KEY);
$this->mailer->createAndSendEmail([ $this->mailer->createAndSendEmail([
'feedbacks' => $sortedFeedbacks[$manager->getHotelCode()], 'feedbacks' => $feedbacksForManager,
], [ ], [
'to' => $manager->getEmail(), 'to' => $manager->getEmail(),
'subject' => 'Reminder: Offene Feedbacks', 'subject' => 'Reminder: Offene Feedbacks',
+26
View File
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Tests\Entity;
use App\Entity\User;
use PHPUnit\Framework\TestCase;
class UserTest extends TestCase
{
public function testHotelCodeMatching(): void
{
$user = new User();
$user->setHotelCodes(['ABC', 'DEF', 'GHI']);
$isMatch = $user->hasHotelCodeMatch('ABCXXX');
$this->assertTrue($isMatch);
$isMatch = $user->hasHotelCodeMatch('XXXGHI');
$this->assertTrue($isMatch);
$isMatch = $user->hasHotelCodeMatch('XXDEFXX');
$this->assertFalse($isMatch);
}
}