diff --git a/docs/buspronet-schema/crm-selection-queries.md b/docs/buspronet-schema/crm-selection-queries.md index 085b2ff..caf384f 100644 --- a/docs/buspronet-schema/crm-selection-queries.md +++ b/docs/buspronet-schema/crm-selection-queries.md @@ -22,6 +22,7 @@ Symfony roles: | `1293` | `ROLE_MANAGER` | | `1477` | `ROLE_GROUPS_MANAGER` | | `1478` | `ROLE_GROUPS_ADMIN` | +| `1483` | `ROLE_CUSTOMER_EXPERT` | | label `Hausleitung {CODE}` | `ROLE_HOUSE_MANAGER` + hotel code `{CODE}` | | nothing matched | `ROLE_CUSTOMER` | diff --git a/src/BusProNet/XmlParser/CrmAttributesResponseParser.php b/src/BusProNet/XmlParser/CrmAttributesResponseParser.php index ce1d531..dd51a77 100644 --- a/src/BusProNet/XmlParser/CrmAttributesResponseParser.php +++ b/src/BusProNet/XmlParser/CrmAttributesResponseParser.php @@ -26,11 +26,21 @@ class CrmAttributesResponseParser { use TypeConversionTrait; - private const BPN_CRM_ID_ADMIN = 1292; - private const BPN_CRM_ID_MANAGER = 1293; - private const BPN_CRM_ID_TEAMER = 1070; - private const BPN_CRM_ID_GROUPS_MANAGER = 1477; - private const BPN_CRM_ID_GROUPS_ADMIN = 1478; + /** + * The CRM selections that stand for a role, by selection id. "Hausleitung" is deliberately not + * in here: its ids are deployment configuration (see $houseManagerIds) and carry a hotel code + * on top of the role. + * + * @var array selection id => role + */ + private const ROLE_BY_CRM_ID = [ + 1070 => Role::TEAMER, + 1292 => Role::ADMIN, + 1293 => Role::MANAGER, + 1477 => Role::GROUPS_MANAGER, + 1478 => Role::GROUPS_ADMIN, + 1483 => Role::CUSTOMER_EXPERT, + ]; /** * @param array $houseManagerIds "Hausleitung" selection id => hotel code @@ -71,20 +81,11 @@ class CrmAttributesResponseParser $roles[] = Role::HOUSE_MANAGER; $hotelCodes[] = $hotelCode; } - if (self::BPN_CRM_ID_ADMIN === $attribute->id) { - $roles[] = Role::ADMIN; - } - if (self::BPN_CRM_ID_MANAGER === $attribute->id) { - $roles[] = Role::MANAGER; - } - if (self::BPN_CRM_ID_TEAMER === $attribute->id) { - $roles[] = Role::TEAMER; - } - if (self::BPN_CRM_ID_GROUPS_MANAGER === $attribute->id) { - $roles[] = Role::GROUPS_MANAGER; - } - if (self::BPN_CRM_ID_GROUPS_ADMIN === $attribute->id) { - $roles[] = Role::GROUPS_ADMIN; + + $role = self::ROLE_BY_CRM_ID[$attribute->id] ?? null; + + if (null !== $role) { + $roles[] = $role; } } diff --git a/src/Security/Role.php b/src/Security/Role.php index 64dd885..c61c710 100644 --- a/src/Security/Role.php +++ b/src/Security/Role.php @@ -39,6 +39,7 @@ final class Role public const HOUSE_MANAGER = 'ROLE_HOUSE_MANAGER'; public const GROUPS_ADMIN = 'ROLE_GROUPS_ADMIN'; public const GROUPS_MANAGER = 'ROLE_GROUPS_MANAGER'; + public const CUSTOMER_EXPERT = 'ROLE_CUSTOMER_EXPERT'; public const EMPLOYEE = 'ROLE_EMPLOYEE'; /** @@ -63,6 +64,7 @@ final class Role self::HOUSE_MANAGER, self::GROUPS_ADMIN, self::GROUPS_MANAGER, + self::CUSTOMER_EXPERT, self::EMPLOYEE, ]; @@ -92,6 +94,7 @@ final class Role self::HOUSE_MANAGER, self::GROUPS_ADMIN, self::GROUPS_MANAGER, + self::CUSTOMER_EXPERT, ]; /** @@ -287,6 +290,7 @@ final class Role self::HOUSE_MANAGER => 'Hausleitung', self::GROUPS_ADMIN => 'Preisrechner Admin', self::GROUPS_MANAGER => 'Preisrechner', + self::CUSTOMER_EXPERT => 'KO-Experte', self::EMPLOYEE => 'Mitarbeiter:in', ]; diff --git a/tests/BusProNet/XmlParser/CrmAttributesResponseParserTest.php b/tests/BusProNet/XmlParser/CrmAttributesResponseParserTest.php index 9b317e4..0d181b0 100644 --- a/tests/BusProNet/XmlParser/CrmAttributesResponseParserTest.php +++ b/tests/BusProNet/XmlParser/CrmAttributesResponseParserTest.php @@ -40,6 +40,20 @@ class CrmAttributesResponseParserTest extends TestCase self::assertNotContains('ROLE_GROUPS_MANAGER', $roles); } + public function testParseAssignsCustomerExpertRoleWhenSelected(): void + { + $roles = $this->parseRoles($this->selectionXml(1483, true)); + + self::assertContains('ROLE_CUSTOMER_EXPERT', $roles); + } + + public function testParseAssignsNoCustomerExpertRoleWhenNotSelected(): void + { + $roles = $this->parseRoles($this->selectionXml(1483, false)); + + self::assertNotContains('ROLE_CUSTOMER_EXPERT', $roles); + } + public function testParseAssignsNoGroupsRolesWhenNotSelected(): void { $roles = $this->parseRoles($this->selectionXml(1477, false)); diff --git a/tests/Security/RoleTest.php b/tests/Security/RoleTest.php index 7795c31..be821b3 100644 --- a/tests/Security/RoleTest.php +++ b/tests/Security/RoleTest.php @@ -24,6 +24,25 @@ class RoleTest extends TestCase self::assertSame([Role::TEAMER], Role::effectiveOnly($roles)); } + public function testCustomerExpertClaimOnlyProducesANomination(): void + { + $roles = Role::sync([], [Role::CUSTOMER_EXPERT]); + + self::assertSame([Role::pending(Role::CUSTOMER_EXPERT), Role::CUSTOMER], $roles); + self::assertSame([Role::CUSTOMER], Role::effectiveOnly($roles)); + self::assertSame( + [Role::CUSTOMER_EXPERT => 'KO-Experte'], + Role::nominatedFrom($roles), + ); + } + + public function testApprovedCustomerExpertDisplacesTheCustomerFallback(): void + { + $roles = Role::approve([Role::pending(Role::CUSTOMER_EXPERT), Role::CUSTOMER], Role::CUSTOMER_EXPERT); + + self::assertSame([Role::CUSTOMER_EXPERT], $roles); + } + public function testApprovedRoleSurvivesTheNextSyncAndIsNotMarkedAgain(): void { $roles = Role::sync([Role::TEAMER, Role::GROUPS_ADMIN], [Role::GROUPS_ADMIN, Role::TEAMER]);