diff --git a/src/BusProNet/Model/Communication.php b/src/BusProNet/Model/Communication.php index 2a3c17d..474feca 100644 --- a/src/BusProNet/Model/Communication.php +++ b/src/BusProNet/Model/Communication.php @@ -39,7 +39,9 @@ class Communication public function setEmail(?string $email): static { - $this->email = $email; + // BusPro compares addresses case-insensitively; normalize on the way in so the DTO + // carries the same shape the entities store. + $this->email = null === $email ? null : mb_strtolower(trim($email)); return $this; } diff --git a/src/Entity/Contact.php b/src/Entity/Contact.php index 8e56752..9f096cc 100644 --- a/src/Entity/Contact.php +++ b/src/Entity/Contact.php @@ -75,7 +75,7 @@ class Contact public function setEmail(string $email): static { - $this->email = $email; + $this->email = mb_strtolower(trim($email)); return $this; } diff --git a/src/Entity/Embeddable/Communication.php b/src/Entity/Embeddable/Communication.php index 2513c81..a023d71 100644 --- a/src/Entity/Embeddable/Communication.php +++ b/src/Entity/Embeddable/Communication.php @@ -108,7 +108,7 @@ class Communication public function setEmail(?string $email): static { - $this->email = $email; + $this->email = null === $email ? null : mb_strtolower(trim($email)); return $this; } diff --git a/src/Security/BpnAuthenticator.php b/src/Security/BpnAuthenticator.php index b8b06db..808760d 100644 --- a/src/Security/BpnAuthenticator.php +++ b/src/Security/BpnAuthenticator.php @@ -43,7 +43,7 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent public function authenticate(Request $request): Passport { - $email = trim($request->request->getString('_username')); + $email = mb_strtolower(trim($request->request->getString('_username'))); $passwordPlain = trim($request->request->getString('_password')); // Very lame hashing applied here as required by BPN diff --git a/tests/BusProNet/UserDataHandlerTest.php b/tests/BusProNet/UserDataHandlerTest.php index f07f4f7..eec0db4 100644 --- a/tests/BusProNet/UserDataHandlerTest.php +++ b/tests/BusProNet/UserDataHandlerTest.php @@ -200,6 +200,37 @@ class UserDataHandlerTest extends TestCase $this->assertSame(['team' => ['selected' => true]], $teamer->getCrmSelections()); } + /** + * BusPro compares addresses case-insensitively and MyE&P lowercases them on login, so a + * mixed-case address coming back from the API must land lowercased on both the user and + * the teamer - otherwise the login identity and the mailing address drift apart. + */ + public function testUpdateLocalUserNormalizesTheAddressBusProReports(): void + { + $user = (new User()) + ->setFirstName('Old') + ->setLastName('Name') + ->setEmail('old@example.com') + ->setBusProAddressId(1) + ->setBusProPersonId(2) + ; + + $teamer = (new Teamer()) + ->setCommunication((new Communication())->setEmail('old@example.com')) + ; + $user->setTeamer($teamer); + + $profileResponse = $this->createProfileResponse() + ->setCommunication((new BusProCommunication())->setEmail('New.User@Example.COM')) + ; + + $handler = new UserDataHandler($this->entityManager, $this->logger); + $handler->updateLocalUser($user, $profileResponse, true, [], ['ROLE_TEAMER'], []); + + $this->assertSame('new.user@example.com', $user->getEmail()); + $this->assertSame('new.user@example.com', $teamer->getCommunication()?->getEmail()); + } + /** * @dataProvider pendingRolesProvider */ diff --git a/tests/Entity/ContactTest.php b/tests/Entity/ContactTest.php new file mode 100644 index 0000000..0808817 --- /dev/null +++ b/tests/Entity/ContactTest.php @@ -0,0 +1,22 @@ +setEmail(' Buero@EP-Reisen.DE '); + + $this->assertSame('buero@ep-reisen.de', $contact->getEmail()); + } +} diff --git a/tests/Entity/Embeddable/CommunicationTest.php b/tests/Entity/Embeddable/CommunicationTest.php new file mode 100644 index 0000000..9623d93 --- /dev/null +++ b/tests/Entity/Embeddable/CommunicationTest.php @@ -0,0 +1,43 @@ +setEmail(' Max.Mustermann@EP-Reisen.DE '); + + $this->assertSame('max.mustermann@ep-reisen.de', $communication->getEmail()); + } + + public function testSetEmailKeepsNull(): void + { + $communication = (new Communication())->setEmail(null); + + $this->assertNull($communication->getEmail()); + } + + /** + * The outbound BusPro payload must carry the normalized form, not the raw input. + */ + public function testPayloadCarriesTheNormalizedAddress(): void + { + $communication = (new Communication()) + ->setEmail('Max.Mustermann@EP-Reisen.DE') + ->setMobile('0170 1234567') + ; + + $this->assertSame('max.mustermann@ep-reisen.de', $communication->toPayload()['email']); + } +}