From e13b6a2d6d7de353ef851e82b82418779cd5eae2 Mon Sep 17 00:00:00 2001 From: Edie Lemoine Date: Fri, 15 Nov 2024 10:56:27 +0100 Subject: [PATCH] feat(checkout): show carriers only for countries they ship to (#273) * feat(checkout): show carriers only for countries they ship to * style: fix code style * refactor: fix phpmd warnings * Update src/Hooks/HasPsCarrierListHooks.php Co-authored-by: Florian Riecker- de Vries <93703843+FlorianSDV@users.noreply.github.com> * test: fix tests * test: fix return types --------- Co-authored-by: Florian Riecker- de Vries <93703843+FlorianSDV@users.noreply.github.com> --- config/pdk.php | 279 +++++++++++++++++- myparcelnl.php | 6 +- src/Carrier/Service/CarrierBuilder.php | 24 +- src/Contract/PsCountryServiceInterface.php | 36 +++ src/Exception/CreateCarrierException.php | 9 + src/Hooks/HasPsCarrierListHooks.php | 122 ++++++++ ...rHooks.php => HasPsCarrierUpdateHooks.php} | 2 +- .../Backend/Account/PsUpdateAccountAction.php | 33 ++- src/Pdk/Base/PsPdkBootstrapper.php | 12 + .../Installer/Service/PsInstallerService.php | 2 +- src/Service/PsCarrierService.php | 11 +- src/Service/PsCountryService.php | 98 ++++++ src/Service/PsSpecificObjectModelService.php | 37 ++- tests/Mock/MockItems.php | 8 +- tests/Mock/MockPsCountries.php | 41 +++ tests/Mock/MockPsCountry.php | 74 +++++ tests/Mock/MockPsObjectModel.php | 78 ++++- tests/Mock/MockPsOrder.php | 3 +- tests/TestCase.php | 2 + .../Unit/Hooks/HasPsCarrierListHooksTest.php | 177 +++++++++++ ...st.php => HasPsCarrierUpdateHooksTest.php} | 6 +- tests/Uses/UsesMockPsPdkInstance.php | 53 +++- .../EntryTest__it_has_hooks__1.json | 1 + ...eTest__it_installs_registers_hooks__1.json | 6 +- tests/factories/CookieFactory.php | 28 ++ tests/factories/CountryFactory.php | 1 + tests/factories/EmployeeFactory.php | 16 + tests/factories/StateFactory.php | 1 + tests/mock_class_map.php | 8 +- tests/mock_namespaced_class_map.php | 6 +- 30 files changed, 1105 insertions(+), 75 deletions(-) create mode 100644 src/Contract/PsCountryServiceInterface.php create mode 100644 src/Exception/CreateCarrierException.php create mode 100644 src/Hooks/HasPsCarrierListHooks.php rename src/Hooks/{HasPsCarrierHooks.php => HasPsCarrierUpdateHooks.php} (98%) create mode 100644 src/Service/PsCountryService.php create mode 100644 tests/Mock/MockPsCountries.php create mode 100644 tests/Mock/MockPsCountry.php create mode 100644 tests/Unit/Hooks/HasPsCarrierListHooksTest.php rename tests/Unit/Hooks/{HasPsCarrierHooksTest.php => HasPsCarrierUpdateHooksTest.php} (95%) create mode 100644 tests/factories/CookieFactory.php create mode 100644 tests/factories/EmployeeFactory.php diff --git a/config/pdk.php b/config/pdk.php index 056195b9..a7d362e3 100644 --- a/config/pdk.php +++ b/config/pdk.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use MyParcelNL\Pdk\Account\Platform; use MyParcelNL\Pdk\Api\Contract\ClientAdapterInterface; use MyParcelNL\Pdk\App\Account\Contract\PdkAccountRepositoryInterface; use MyParcelNL\Pdk\App\Action\Backend\Account\UpdateAccountAction; @@ -23,6 +24,8 @@ use MyParcelNL\Pdk\Audit\Service\AuditService; use MyParcelNL\Pdk\Base\Contract\CronServiceInterface; use MyParcelNL\Pdk\Base\Contract\WeightServiceInterface; +use MyParcelNL\Pdk\Base\Service\CountryCodes; +use MyParcelNL\Pdk\Carrier\Model\Carrier; use MyParcelNL\Pdk\Facade\Pdk; use MyParcelNL\Pdk\Frontend\Contract\FrontendRenderServiceInterface; use MyParcelNL\Pdk\Frontend\Contract\ScriptServiceInterface; @@ -32,6 +35,7 @@ use MyParcelNL\PrestaShop\Configuration\Contract\PsConfigurationServiceInterface; use MyParcelNL\PrestaShop\Configuration\Service\Ps17PsConfigurationService; use MyParcelNL\PrestaShop\Contract\PsCarrierServiceInterface; +use MyParcelNL\PrestaShop\Contract\PsCountryServiceInterface; use MyParcelNL\PrestaShop\Contract\PsObjectModelServiceInterface; use MyParcelNL\PrestaShop\Contract\PsOrderServiceInterface; use MyParcelNL\PrestaShop\Database\CreateAuditTableDatabaseMigration; @@ -76,6 +80,7 @@ use MyParcelNL\PrestaShop\Router\Service\Ps8RouterService; use MyParcelNL\PrestaShop\Script\Service\PsScriptService; use MyParcelNL\PrestaShop\Service\PsCarrierService; +use MyParcelNL\PrestaShop\Service\PsCountryService; use MyParcelNL\PrestaShop\Service\PsObjectModelService; use MyParcelNL\PrestaShop\Service\PsOrderService; use Psr\Log\LoggerInterface; @@ -176,12 +181,280 @@ /** * Custom services */ - PsCarrierServiceInterface::class => get(PsCarrierService::class), PsConfigurationServiceInterface::class => get(Ps17PsConfigurationService::class), - PsObjectModelServiceInterface::class => get(PsObjectModelService::class), - PsOrderServiceInterface::class => get(PsOrderService::class), PsRouterServiceInterface::class => psVersionFactory([ ['class' => Ps8RouterService::class, 'version' => 8], ['class' => Ps17RouterService::class], ]), + + /** + * Object model services + */ + PsObjectModelServiceInterface::class => get(PsObjectModelService::class), + + PsCarrierServiceInterface::class => get(PsCarrierService::class), + PsCountryServiceInterface::class => get(PsCountryService::class), + PsOrderServiceInterface::class => get(PsOrderService::class), + + /** + * Countries per platform and carrier. + * This is intended as a temporary solution until we can use the Carrier Capabilities service. This is copied from the Delivery Options. + * + * @TODO Replace when Carrier Capabilities is available. + */ + 'countriesPerPlatformAndCarrier' => value([ + Platform::MYPARCEL_NAME => [ + Carrier::CARRIER_POSTNL_NAME => [ + 'deliveryCountries' => [ + CountryCodes::CC_NL, // Netherlands + CountryCodes::CC_BE, // Belgium + ], + 'pickupCountries' => [ + CountryCodes::CC_NL, // Netherlands + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_DK, // Denmark + CountryCodes::CC_SE, // Sweden + CountryCodes::CC_DE, // Germany + ], + 'fakeDelivery' => true, + ], + Carrier::CARRIER_DHL_FOR_YOU_NAME => [ + 'deliveryCountries' => [ + CountryCodes::CC_NL, // Netherlands + CountryCodes::CC_BE, // Belgium + ], + 'pickupCountries' => [ + CountryCodes::CC_NL, // Netherlands + ], + ], + Carrier::CARRIER_DHL_PARCEL_CONNECT_NAME => [ + 'deliveryCountries' => [ + CountryCodes::CC_AT, // Austria + CountryCodes::CC_BG, // Bulgaria + CountryCodes::CC_HR, // Croatia + CountryCodes::CC_CZ, // Czech Republic + CountryCodes::CC_EE, // Estonia + CountryCodes::CC_FI, // Finland + CountryCodes::CC_DE, // Germany + CountryCodes::CC_GR, // Greece + CountryCodes::CC_HU, // Hungary + CountryCodes::CC_IE, // Ireland + CountryCodes::CC_IT, // Italy + CountryCodes::CC_LV, // Latvia + CountryCodes::CC_LT, // Lithuania + CountryCodes::CC_LU, // Luxembourg + CountryCodes::CC_PL, // Poland + CountryCodes::CC_PT, // Portugal + CountryCodes::CC_RO, // Romania + CountryCodes::CC_SK, // Slovakia + CountryCodes::CC_SI, // Slovenia + CountryCodes::CC_ES, // Spain + ], + 'pickupCountries' => [ + CountryCodes::CC_AT, // Austria + CountryCodes::CC_BG, // Bulgaria + CountryCodes::CC_HR, // Croatia + CountryCodes::CC_CZ, // Czech Republic + CountryCodes::CC_DK, // Denmark + CountryCodes::CC_FR, // France + CountryCodes::CC_DE, // Germany + CountryCodes::CC_GR, // Greece + CountryCodes::CC_HU, // Hungary + CountryCodes::CC_IT, // Italy + CountryCodes::CC_LU, // Luxembourg + CountryCodes::CC_PL, // Poland + CountryCodes::CC_PT, // Portugal + CountryCodes::CC_RO, // Romania + CountryCodes::CC_SK, // Slovakia + CountryCodes::CC_SI, // Slovenia + CountryCodes::CC_ES, // Spain + CountryCodes::CC_SE, // Sweden + ], + ], + Carrier::CARRIER_DHL_EUROPLUS_NAME => [ + 'deliveryCountries' => [ + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_BG, // Bulgaria + CountryCodes::CC_DK, // Denmark + CountryCodes::CC_DE, // Germany + CountryCodes::CC_EE, // Estonia + CountryCodes::CC_FI, // Finland + CountryCodes::CC_FR, // France + CountryCodes::CC_GR, // Greece + CountryCodes::CC_HU, // Hungary + CountryCodes::CC_IE, // Ireland + CountryCodes::CC_IT, // Italy + CountryCodes::CC_HR, // Croatia + CountryCodes::CC_LV, // Latvia + CountryCodes::CC_LT, // Lithuania + CountryCodes::CC_LU, // Luxembourg + CountryCodes::CC_NL, // Netherlands + CountryCodes::CC_AT, // Austria + CountryCodes::CC_PL, // Poland + CountryCodes::CC_PT, // Portugal + CountryCodes::CC_RO, // Romania + CountryCodes::CC_SI, // Slovenia + CountryCodes::CC_SK, // Slovakia + CountryCodes::CC_ES, // Spain + CountryCodes::CC_CZ, // Czech Republic + CountryCodes::CC_SE, // Sweden + CountryCodes::CC_GB, // United Kingdom + ], + 'pickupCountries' => [], + ], + Carrier::CARRIER_UPS_NAME => [ + 'deliveryCountries' => [ + CountryCodes::CC_BG, // Bulgaria + CountryCodes::CC_DE, // Germany + CountryCodes::CC_EE, // Estonia + CountryCodes::CC_FI, // Finland + CountryCodes::CC_GR, // Greece + CountryCodes::CC_HU, // Hungary + CountryCodes::CC_IE, // Ireland + CountryCodes::CC_IT, // Italy + CountryCodes::CC_HR, // Croatia + CountryCodes::CC_LV, // Latvia + CountryCodes::CC_LT, // Lithuania + CountryCodes::CC_LU, // Luxembourg + CountryCodes::CC_AT, // Austria + CountryCodes::CC_PL, // Poland + CountryCodes::CC_PT, // Portugal + CountryCodes::CC_RO, // Romania + CountryCodes::CC_SI, // Slovenia + CountryCodes::CC_SK, // Slovakia + CountryCodes::CC_ES, // Spain + CountryCodes::CC_CZ, // Czech Republic + ], + 'pickupCountries' => [ + CountryCodes::CC_DE, // Germany + ], + 'fakeDelivery' => true, + ], + Carrier::CARRIER_DPD_NAME => [ + 'deliveryCountries' => [ + CountryCodes::CC_AT, // Austria + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_BG, // Bulgaria + CountryCodes::CC_CZ, // Czech Republic + CountryCodes::CC_DK, // Denmark + CountryCodes::CC_EE, // Estonia + CountryCodes::CC_FI, // Finland + CountryCodes::CC_FR, // France + CountryCodes::CC_DE, // Germany + CountryCodes::CC_GR, // Greece + CountryCodes::CC_HU, // Hungary + CountryCodes::CC_IE, // Ireland + CountryCodes::CC_IT, // Italy + CountryCodes::CC_LV, // Latvia + CountryCodes::CC_LI, // Liechtenstein + CountryCodes::CC_LT, // Lithuania + CountryCodes::CC_LU, // Luxembourg + CountryCodes::CC_NL, // Netherlands + CountryCodes::CC_PL, // Poland + CountryCodes::CC_PT, // Portugal + CountryCodes::CC_RO, // Romania + CountryCodes::CC_SK, // Slovakia + CountryCodes::CC_SI, // Slovenia + CountryCodes::CC_ES, // Spain + CountryCodes::CC_SE, // Sweden + ], + 'pickupCountries' => [ + CountryCodes::CC_AT, // Austria + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_CZ, // Czech Republic + CountryCodes::CC_DK, // Denmark + CountryCodes::CC_EE, // Estonia + CountryCodes::CC_FI, // Finland + CountryCodes::CC_FR, // France + CountryCodes::CC_DE, // Germany + CountryCodes::CC_HU, // Hungary + CountryCodes::CC_LV, // Latvia + CountryCodes::CC_LT, // Lithuania + CountryCodes::CC_LU, // Luxembourg + CountryCodes::CC_NL, // Netherlands + CountryCodes::CC_PL, // Poland + CountryCodes::CC_PT, // Portugal + CountryCodes::CC_SK, // Slovakia + CountryCodes::CC_SI, // Slovenia + CountryCodes::CC_ES, // Spain + CountryCodes::CC_GB, // United Kingdom + ], + ], + ], + + Platform::SENDMYPARCEL_NAME => [ + Carrier::CARRIER_BPOST_NAME => [ + 'deliveryCountries' => [ + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_NL, // Netherlands + ], + 'pickupCountries' => [ + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_NL, // Netherlands + ], + 'fakeDelivery' => true, + ], + Carrier::CARRIER_POSTNL_NAME => [ + 'deliveryCountries' => [ + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_NL, // Netherlands + ], + 'pickupCountries' => [ + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_NL, // Netherlands + ], + 'fakeDelivery' => true, + ], + Carrier::CARRIER_DPD_NAME => [ + 'deliveryCountries' => [ + CountryCodes::CC_AT, // Austria + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_BG, // Bulgaria + CountryCodes::CC_CZ, // Czech Republic + CountryCodes::CC_DK, // Denmark + CountryCodes::CC_EE, // Estonia + CountryCodes::CC_FI, // Finland + CountryCodes::CC_FR, // France + CountryCodes::CC_DE, // Germany + CountryCodes::CC_GR, // Greece + CountryCodes::CC_HU, // Hungary + CountryCodes::CC_IE, // Ireland + CountryCodes::CC_IT, // Italy + CountryCodes::CC_LV, // Latvia + CountryCodes::CC_LI, // Liechtenstein + CountryCodes::CC_LT, // Lithuania + CountryCodes::CC_LU, // Luxembourg + CountryCodes::CC_NL, // Netherlands + CountryCodes::CC_PL, // Poland + CountryCodes::CC_PT, // Portugal + CountryCodes::CC_RO, // Romania + CountryCodes::CC_SK, // Slovakia + CountryCodes::CC_SI, // Slovenia + CountryCodes::CC_ES, // Spain + CountryCodes::CC_SE, // Sweden + ], + 'pickupCountries' => [ + CountryCodes::CC_AT, // Austria + CountryCodes::CC_BE, // Belgium + CountryCodes::CC_CZ, // Czech Republic + CountryCodes::CC_DK, // Denmark + CountryCodes::CC_EE, // Estonia + CountryCodes::CC_FI, // Finland + CountryCodes::CC_FR, // France + CountryCodes::CC_DE, // Germany + CountryCodes::CC_HU, // Hungary + CountryCodes::CC_LV, // Latvia + CountryCodes::CC_LT, // Lithuania + CountryCodes::CC_LU, // Luxembourg + CountryCodes::CC_NL, // Netherlands + CountryCodes::CC_PL, // Poland + CountryCodes::CC_PT, // Portugal + CountryCodes::CC_SK, // Slovakia + CountryCodes::CC_SI, // Slovenia + CountryCodes::CC_ES, // Spain + CountryCodes::CC_GB, // United Kingdom + ], + ], + ], + ]), ]; diff --git a/myparcelnl.php b/myparcelnl.php index 7ade8b33..d3fa5f0e 100644 --- a/myparcelnl.php +++ b/myparcelnl.php @@ -16,7 +16,8 @@ use MyParcelNL\PrestaShop\Hooks\HasPdkProductHooks; use MyParcelNL\PrestaShop\Hooks\HasPdkRenderHooks; use MyParcelNL\PrestaShop\Hooks\HasPdkScriptHooks; -use MyParcelNL\PrestaShop\Hooks\HasPsCarrierHooks; +use MyParcelNL\PrestaShop\Hooks\HasPsCarrierListHooks; +use MyParcelNL\PrestaShop\Hooks\HasPsCarrierUpdateHooks; use MyParcelNL\PrestaShop\Hooks\HasPsShippingCostHooks; use function MyParcelNL\PrestaShop\bootPdk; @@ -41,7 +42,8 @@ class MyParcelNL extends CarrierModule use HasPdkProductHooks; use HasPdkRenderHooks; use HasPdkScriptHooks; - use HasPsCarrierHooks; + use HasPsCarrierListHooks; + use HasPsCarrierUpdateHooks; use HasPsShippingCostHooks; private static ?string $versionFromComposer = null; diff --git a/src/Carrier/Service/CarrierBuilder.php b/src/Carrier/Service/CarrierBuilder.php index bae8ef96..3765c684 100644 --- a/src/Carrier/Service/CarrierBuilder.php +++ b/src/Carrier/Service/CarrierBuilder.php @@ -10,17 +10,18 @@ use Language as PsLanguage; use MyParcelNL\Pdk\Base\FileSystemInterface; use MyParcelNL\Pdk\Base\Support\Arr; +use MyParcelNL\Pdk\Base\Support\Collection; use MyParcelNL\Pdk\Carrier\Model\Carrier; use MyParcelNL\Pdk\Facade\Language; use MyParcelNL\Pdk\Facade\Pdk; use MyParcelNL\PrestaShop\Contract\PsCarrierServiceInterface; use MyParcelNL\PrestaShop\Contract\PsObjectModelServiceInterface; use MyParcelNL\PrestaShop\Entity\MyparcelnlCarrierMapping; +use MyParcelNL\PrestaShop\Exception\CreateCarrierException; use MyParcelNL\PrestaShop\Repository\PsCarrierMappingRepository; use RangePrice; use RangeWeight; -use RuntimeException; -use Zone; +use Zone as PsZone; final class CarrierBuilder { @@ -53,6 +54,7 @@ public function __construct(Carrier $myParcelCarrier) /** * @return \Carrier * @throws \Doctrine\ORM\ORMException + * @throws \MyParcelNL\PrestaShop\Exception\CreateCarrierException */ public function create(): PsCarrier { @@ -102,13 +104,14 @@ private function addCarrierMapping(): void /** * @return void + * @throws \MyParcelNL\PrestaShop\Exception\CreateCarrierException */ private function addGroups(): void { $groups = Group::getGroups(Context::getContext()->language->id); if (! $this->psCarrier->setGroups(Arr::pluck($groups, 'id_group'))) { - throw new RuntimeException("Failed to add groups to carrier $this->psCarrier->id"); + throw new CreateCarrierException("Failed to add groups to carrier $this->psCarrier->id"); } } @@ -137,21 +140,22 @@ private function addRanges(): void /** * @return void + * @throws \MyParcelNL\PrestaShop\Exception\CreateCarrierException */ private function addZones(): void { - $existingZones = $this->psCarrier->getZones(); + $existingZones = new Collection($this->psCarrier->getZones()); - if ($existingZones) { - return; - } + foreach (PsZone::getZones() as $zone) { + $alreadyHasZone = $existingZones->contains(function (array $existingZone) use ($zone) { + return $existingZone['id_zone'] === $zone['id_zone']; + }); - foreach (Zone::getZones() as $zone) { - if ($this->psCarrier->addZone($zone['id_zone'])) { + if ($alreadyHasZone || $this->psCarrier->addZone($zone['id_zone'])) { continue; } - throw new RuntimeException("Failed to add zone {$zone['id_zone']} to carrier {$this->psCarrier->id}"); + throw new CreateCarrierException("Failed to add zone {$zone['id_zone']} to carrier {$this->psCarrier->id}"); } } diff --git a/src/Contract/PsCountryServiceInterface.php b/src/Contract/PsCountryServiceInterface.php new file mode 100644 index 00000000..1e42c0f8 --- /dev/null +++ b/src/Contract/PsCountryServiceInterface.php @@ -0,0 +1,36 @@ + + */ +interface PsCountryServiceInterface extends PsSpecificObjectModelServiceInterface +{ + /** + * @TODO: Replace this when Carrier Capabilities service is implemented. + * + * @param string $carrierName + * + * @return array + */ + public function getCountriesForCarrier(string $carrierName): array; + + /** + * @param string $isoCode + * + * @return ?int + */ + public function getCountryIdByIsoCode(string $isoCode): ?int; + + /** + * @param array $isoCodes + * + * @return int[] + */ + public function getCountryIdsByIsoCodes(array $isoCodes): array; +} diff --git a/src/Exception/CreateCarrierException.php b/src/Exception/CreateCarrierException.php new file mode 100644 index 00000000..cc8955ec --- /dev/null +++ b/src/Exception/CreateCarrierException.php @@ -0,0 +1,9 @@ +all(); + + if ($mappings->isEmpty()) { + return; + } + + $country = $this->getCountryFromCart($params['cart'] ?? $this->context->cart ?? new Cart()); + $deliveryOptionList = $params['delivery_option_list'] ?? []; + + foreach ($deliveryOptionList as $addressId => $item) { + foreach ($item as $key => $value) { + $carrierMapping = $this->getCarrierMapping($value['carrier_list'] ?? [], $mappings); + + if (! $carrierMapping) { + continue; + } + + $carrierName = $carrierMapping->getMyparcelCarrier(); + $allowedCountryIds = $this->getAllowedCountryIdsForCarrier($carrierName); + + if (in_array($country->id, array_values($allowedCountryIds), true)) { + continue; + } + + // Delete the carrier from the list if it can't ship to the current country. + unset($params['delivery_option_list'][$addressId][$key]); + } + } + } + + /** + * @param string $carrierName + * + * @return int[] + */ + private function getAllowedCountryIdsForCarrier(string $carrierName): array + { + /** @var \MyParcelNL\PrestaShop\Contract\PsCountryServiceInterface $psCountryService */ + $psCountryService = Pdk::get(PsCountryServiceInterface::class); + + $isoCodes = $psCountryService->getCountriesForCarrier($carrierName); + + return $psCountryService->getCountryIdsByIsoCodes($isoCodes); + } + + /** + * @param array $carrierList + * @param \MyParcelNL\Pdk\Base\Support\Collection $mappings + * + * @return null|\MyParcelNL\PrestaShop\Entity\MyparcelnlCarrierMapping + */ + private function getCarrierMapping( + array $carrierList, + Collection $mappings + ): ?MyparcelnlCarrierMapping { + $carrierArray = Arr::first($carrierList); + + /** @var \Carrier $psCarrier */ + $psCarrier = $carrierArray['instance'] ?? null; + + return $mappings + ->filter(function (MyparcelnlCarrierMapping $mapping) use ($psCarrier) { + return $mapping->getCarrierId() === $psCarrier->id; + }) + ->first(); + } + + /** + * @param \Cart $cart + * + * @return \Country + * @throws \PrestaShopDatabaseException + * @throws \PrestaShopException + */ + private function getCountryFromCart(Cart $cart): Country + { + $configurationService = Pdk::get(PsConfigurationServiceInterface::class); + + if ($cart->id_address_delivery) { + $address = new Address($cart->id_address_delivery); + $country = new Country($address->id_country); + } else { + $country = $this->context->country ?? new Country((int) $configurationService->get('PS_COUNTRY_DEFAULT')); + } + + return $country; + } +} diff --git a/src/Hooks/HasPsCarrierHooks.php b/src/Hooks/HasPsCarrierUpdateHooks.php similarity index 98% rename from src/Hooks/HasPsCarrierHooks.php rename to src/Hooks/HasPsCarrierUpdateHooks.php index d48c38a0..c618f012 100644 --- a/src/Hooks/HasPsCarrierHooks.php +++ b/src/Hooks/HasPsCarrierUpdateHooks.php @@ -15,7 +15,7 @@ /** * @property \Context $context */ -trait HasPsCarrierHooks +trait HasPsCarrierUpdateHooks { /** * Prevents carrier id from de-synchronising with our mappings when user modifies it. diff --git a/src/Pdk/Action/Backend/Account/PsUpdateAccountAction.php b/src/Pdk/Action/Backend/Account/PsUpdateAccountAction.php index 07e3f9ba..e9df0147 100644 --- a/src/Pdk/Action/Backend/Account/PsUpdateAccountAction.php +++ b/src/Pdk/Action/Backend/Account/PsUpdateAccountAction.php @@ -8,9 +8,27 @@ use MyParcelNL\Pdk\Facade\Pdk; use MyParcelNL\Pdk\Settings\Model\AccountSettings; use MyParcelNL\PrestaShop\Contract\PsCarrierServiceInterface; +use MyParcelNL\PrestaShop\Facade\EntityManager; +use MyParcelNL\PrestaShop\Facade\MyParcelModule; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; final class PsUpdateAccountAction extends UpdateAccountAction { + private ?string $mode; + + /** + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function handle(Request $request): Response + { + $this->mode = $request->query->has('mode') ? (string) $request->query->get('mode') : null; + + return parent::handle($request); + } + /** * @param \MyParcelNL\Pdk\Settings\Model\AccountSettings $accountSettings * @@ -20,8 +38,17 @@ protected function updateAndSaveAccount(AccountSettings $accountSettings): void { parent::updateAndSaveAccount($accountSettings); - /** @var PsCarrierServiceInterface $carrierService */ - $carrierService = Pdk::get(PsCarrierServiceInterface::class); - $carrierService->updateCarriers(); + /** @var string $uninstallMode */ + $uninstallMode = Pdk::get('updateAccountModeUninstall'); + + if ($this->mode !== $uninstallMode) { + /** @var PsCarrierServiceInterface $carrierService */ + $carrierService = Pdk::get(PsCarrierServiceInterface::class); + $carrierService->updateCarriers(); + + MyParcelModule::registerHooks(); + } + + EntityManager::flush(); } } diff --git a/src/Pdk/Base/PsPdkBootstrapper.php b/src/Pdk/Base/PsPdkBootstrapper.php index 913946b5..dbe469e1 100644 --- a/src/Pdk/Base/PsPdkBootstrapper.php +++ b/src/Pdk/Base/PsPdkBootstrapper.php @@ -9,6 +9,7 @@ use Module; use MyParcelNL; use MyParcelNL\Pdk\Base\PdkBootstrapper; +use MyParcelNL\Pdk\Base\Service\CountryCodes; use MyParcelNL\Pdk\Base\Support\Collection; use MyParcelNL\Pdk\Facade\Pdk; use MyParcelNL\Pdk\Settings\Model\CheckoutSettings; @@ -116,6 +117,17 @@ protected function getConfig(string $version, string $name, string $path): array 'legacyControllerSettings' => value('MyParcelNLAdminSettings'), + 'updateAccountModeUninstall' => value('uninstall'), + + /** + * @TODO: Move to pdk + */ + 'countryCodesZoneRow' => factory(function () { + $nonRowCountries = array_merge(CountryCodes::EU_COUNTRIES, CountryCodes::UNIQUE_COUNTRIES); + + return array_diff(CountryCodes::ALL, $nonRowCountries); + }), + /** * Settings that are not available in the module. */ diff --git a/src/Pdk/Installer/Service/PsInstallerService.php b/src/Pdk/Installer/Service/PsInstallerService.php index 28d938c4..f2fcc77b 100644 --- a/src/Pdk/Installer/Service/PsInstallerService.php +++ b/src/Pdk/Installer/Service/PsInstallerService.php @@ -119,7 +119,7 @@ protected function executeUninstallation(...$args): void $accountRepository = Pdk::get(PdkSettingsRepositoryInterface::class); $accountRepository->storeSettings(new AccountSettings()); - Actions::execute(PdkBackendActions::UPDATE_ACCOUNT); + Actions::execute(PdkBackendActions::UPDATE_ACCOUNT, ['mode' => Pdk::get('updateAccountModeUninstall')]); } /** diff --git a/src/Service/PsCarrierService.php b/src/Service/PsCarrierService.php index 898b54e9..c88a8d40 100644 --- a/src/Service/PsCarrierService.php +++ b/src/Service/PsCarrierService.php @@ -20,8 +20,6 @@ use MyParcelNL\PrestaShop\Contract\PsCarrierServiceInterface; use MyParcelNL\PrestaShop\Contract\PsObjectModelServiceInterface; use MyParcelNL\PrestaShop\Entity\MyparcelnlCarrierMapping; -use MyParcelNL\PrestaShop\Facade\EntityManager; -use MyParcelNL\PrestaShop\Facade\MyParcelModule; use MyParcelNL\PrestaShop\Repository\PsCarrierMappingRepository; /** @@ -83,10 +81,11 @@ public function createOrUpdateCarriers(CarrierCollection $carriers): Collection return (new Collection($carriers))->map( static function (Carrier $carrier): PsCarrier { $builder = new CarrierBuilder($carrier); + $created = $builder->create(); - Logger::debug('Created carrier ' . $carrier->externalIdentifier); + Logger::debug(sprintf('Created carrier %s', $carrier->externalIdentifier)); - return $builder->create(); + return $created; } ); } @@ -179,10 +178,6 @@ public function updateCarriers(): void $createdCarriers = $this->createOrUpdateCarriers($carriers); $this->deleteUnusedCarriers($createdCarriers); - - // Refresh the hooks - MyParcelModule::registerHooks(); - EntityManager::flush(); } /** diff --git a/src/Service/PsCountryService.php b/src/Service/PsCountryService.php new file mode 100644 index 00000000..519761e6 --- /dev/null +++ b/src/Service/PsCountryService.php @@ -0,0 +1,98 @@ + + */ +final class PsCountryService extends PsSpecificObjectModelService implements PsCountryServiceInterface +{ + /** + * @var array + */ + private static array $countryIdIsoCache = []; + + /** + * @TODO: Remove this when Carrier Capabilities service is implemented. + * + * @param string $carrierName + * + * @return array + */ + public function getCountriesForCarrier(string $carrierName): array + { + // Resolve carrier identifier + [$resolvedCarrierName] = explode(':', $carrierName); + + $platform = Platform::getPlatform(); + $allCarrierCountries = Pdk::get('countriesPerPlatformAndCarrier')[$platform] ?? []; + $countriesForCarrier = $allCarrierCountries[$resolvedCarrierName] ?? []; + + if (true === ($countriesForCarrier['fakeDelivery'] ?? null)) { + $allCountries = CountryCodes::ALL; + } else { + $allCountries = array_merge( + $countriesForCarrier['deliveryCountries'] ?? [], + $countriesForCarrier['pickupCountries'] ?? [] + ); + + // remove duplicates and sort + $allCountries = array_unique($allCountries); + sort($allCountries); + } + + return $allCountries; + } + + /** + * @param string $isoCode + * + * @return ?int + */ + public function getCountryIdByIsoCode(string $isoCode): ?int + { + // Also cache "false" values to prevent multiple queries for non-existing countries + if (null === (self::$countryIdIsoCache[$isoCode] ?? null)) { + self::$countryIdIsoCache[$isoCode] = Country::getByIso(Str::upper($isoCode)); + } + + return self::$countryIdIsoCache[$isoCode] ?: null; + } + + /** + * @param array $isoCodes + * + * @return int[] + */ + public function getCountryIdsByIsoCodes(array $isoCodes): array + { + return array_reduce($isoCodes, function (array $carry, string $countryIso) { + $countryId = $this->getCountryIdByIsoCode($countryIso); + + if ($countryId) { + $carry[$countryIso] = $countryId; + } + + return $carry; + }, []); + } + + /** + * @return string + */ + protected function getClass(): string + { + return PsCountry::class; + } +} diff --git a/src/Service/PsSpecificObjectModelService.php b/src/Service/PsSpecificObjectModelService.php index 7c81f213..7c2acc71 100644 --- a/src/Service/PsSpecificObjectModelService.php +++ b/src/Service/PsSpecificObjectModelService.php @@ -4,19 +4,19 @@ namespace MyParcelNL\PrestaShop\Service; +use Country as T; +use MyParcelNL\Pdk\Facade\Logger; use MyParcelNL\PrestaShop\Contract\PsObjectModelServiceInterface; use MyParcelNL\PrestaShop\Contract\PsSpecificObjectModelServiceInterface; use ObjectModel; /** - * @template T of \ObjectModel + * @template T of ObjectModel + * @extends \MyParcelNL\PrestaShop\Contract\PsSpecificObjectModelServiceInterface */ abstract class PsSpecificObjectModelService implements PsSpecificObjectModelServiceInterface { - /** - * @var \MyParcelNL\PrestaShop\Contract\PsObjectModelServiceInterface - */ - private $psObjectModelService; + private PsObjectModelServiceInterface $psObjectModelService; /** * @param \MyParcelNL\PrestaShop\Contract\PsObjectModelServiceInterface $psObjectModelService @@ -32,9 +32,9 @@ public function __construct(PsObjectModelServiceInterface $psObjectModelService) abstract protected function getClass(): string; /** - * @param \T $model + * @param T $model * - * @return \T + * @return T * @throws \PrestaShopDatabaseException * @throws \PrestaShopException */ @@ -100,9 +100,24 @@ public function getId($input): ?int } /** - * @param \T $model + * @param T $model + * + * @return void + * @throws \PrestaShopException + */ + public function save(ObjectModel $model): void + { + $action = $model->id ? 'Saved' : 'Updated'; + + $model->save(); + + Logger::debug(sprintf('%s %s with id %s', $action, $this->getClass(), $model->id)); + } + + /** + * @param T $model * - * @return \T + * @return T * @throws \PrestaShopDatabaseException * @throws \PrestaShopException */ @@ -112,10 +127,10 @@ public function update(ObjectModel $model): bool } /** - * @param \T $model + * @param T $model * @param null|bool $existing * - * @return \T + * @return T */ public function updateOrAdd(ObjectModel $model, ?bool $existing = null): ObjectModel { diff --git a/tests/Mock/MockItems.php b/tests/Mock/MockItems.php index 1e0d08a5..cf3bbcfa 100644 --- a/tests/Mock/MockItems.php +++ b/tests/Mock/MockItems.php @@ -6,6 +6,7 @@ use MyParcelNL\Pdk\Base\Support\Collection; use MyParcelNL\PrestaShop\Tests\Bootstrap\Contract\StaticMockInterface; +use MyParcelNL\Sdk\src\Support\Str; abstract class MockItems implements StaticMockInterface { @@ -21,8 +22,7 @@ abstract class MockItems implements StaticMockInterface */ public static function add(object $object): bool { - $class = get_class($object); - $byClass = self::getByClass($class); + $byClass = self::getByClass(get_class($object)); if ($byClass->has($object->id)) { return false; @@ -90,7 +90,7 @@ public static function get(string $class, int $id): ?object public static function getByClass(string $class): Collection { return static::all() - ->get($class, new Collection()); + ->get(Str::lower($class), new Collection()); } public static function reset(): void @@ -105,7 +105,7 @@ public static function reset(): void */ public static function update(object $entity): bool { - $class = get_class($entity); + $class = Str::lower(get_class($entity)); $all = static::all(); if (! $all->has($class)) { diff --git a/tests/Mock/MockPsCountries.php b/tests/Mock/MockPsCountries.php new file mode 100644 index 00000000..002fdb6f --- /dev/null +++ b/tests/Mock/MockPsCountries.php @@ -0,0 +1,41 @@ + + */ + private static array $zones = []; + + /** + * @param int $zoneId + * + * @return int[] + */ + public static function getCountriesByZoneId(int $zoneId): array + { + return self::$zones[$zoneId] ?? []; + } + + public static function reset(): void + { + self::$zones = []; + } + + /** + * @param int $zoneId + * @param int[] $countryIds + * + * @return void + */ + public static function setZoneCountries(int $zoneId, array $countryIds): void + { + self::$zones[$zoneId] = $countryIds; + } +} diff --git a/tests/Mock/MockPsCountry.php b/tests/Mock/MockPsCountry.php new file mode 100644 index 00000000..64edf474 --- /dev/null +++ b/tests/Mock/MockPsCountry.php @@ -0,0 +1,74 @@ + + */ +abstract class MockPsCountry extends ObjectModel +{ + /** + * Get a country ID with its iso code. + * + * @param string $isoCode Country iso code + * @param bool $active return only active countries + * + * @return int|bool + * @see \CountryCore::getByIso() + */ + public static function getByIso(string $isoCode, bool $active = false) + { + $wheres = ['iso_code' => $isoCode]; + + if ($active) { + $wheres[] = ['active' => true]; + } + + $found = self::firstWhere($wheres); + + if (! $found) { + return false; + } + + return $found->id; + } + + /** + * @param int $zoneId + * @param int $langId + * + * @return array[] + * @see \CountryCore::getCountriesByZoneId() + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public static function getCountriesByZoneId(int $zoneId, int $langId): array + { + $ids = MockPsCountries::getCountriesByZoneId($zoneId); + + return array_map(static function (int $id) { + return (new static($id))->toArray(); + }, $ids); + } + + protected static function getTable(): string + { + return 'country'; + } + + /** + * @param array $countryIds + * @param int $zoneId + * + * @return void + * @see \CountryCore::affectZoneToSelection() + */ + public function affectZoneToSelection(array $countryIds, int $zoneId): void + { + MockPsCountries::setZoneCountries($zoneId, $countryIds); + } +} diff --git a/tests/Mock/MockPsObjectModel.php b/tests/Mock/MockPsObjectModel.php index 65fd3962..24da7bec 100644 --- a/tests/Mock/MockPsObjectModel.php +++ b/tests/Mock/MockPsObjectModel.php @@ -6,11 +6,14 @@ use Exception; use MyParcelNL\Pdk\Base\Contract\Arrayable; +use MyParcelNL\Pdk\Base\Support\Collection; use MyParcelNL\Pdk\Base\Support\Utils; use MyParcelNL\Sdk\src\Support\Str; +use ObjectModel; use PrestaShop\PrestaShop\Core\Foundation\Database\EntityInterface; /** + * @template T of ObjectModel * @property bool $deleted */ abstract class MockPsObjectModel extends BaseMock implements EntityInterface @@ -44,6 +47,52 @@ public function __construct(?int $id = null, ?int $id_lang = null, ?int $id_shop } } + /** + * @return \MyParcelNL\Pdk\Base\Support\Collection + */ + public static function all(): Collection + { + return MockPsObjectModels::getByClass(static::class); + } + + /** + * @param array $wheres + * + * @return \MyParcelNL\Pdk\Base\Support\Collection + */ + public static function findBy(array $wheres): Collection + { + $all = MockPsObjectModels::getByClass(static::class); + + foreach ($wheres as $key => $value) { + $all = $all->filter(function (ObjectModel $model) use ($value, $key) { + return $model->getAttribute($key) === $value; + }); + } + + return $all; + } + + /** + * @return null|T + */ + public static function first(): ?ObjectModel + { + return MockPsObjectModels::getByClass(static::class) + ->first(); + } + + /** + * @param array $wheres + * + * @return T|null + */ + public static function firstWhere(array $wheres): ?ObjectModel + { + return self::findBy($wheres) + ->first(); + } + /** * @param $class * @param $field @@ -86,8 +135,11 @@ protected static function getTable(): string * @param bool $null_values * * @return bool + * @see \ObjectModel::add() + * @noinspection PhpMissingReturnTypeInspection + * @noinspection ReturnTypeCanBeDeclaredInspection */ - public function add(bool $auto_date = true, bool $null_values = false): bool + public function add(bool $auto_date = true, bool $null_values = false) { MockPsDb::insertRow(static::getTable(), $this->getStorable()); @@ -96,6 +148,9 @@ public function add(bool $auto_date = true, bool $null_values = false): bool /** * @return bool + * @see \ObjectModel::delete() + * @noinspection PhpMissingReturnTypeInspection + * @noinspection ReturnTypeCanBeDeclaredInspection */ public function delete() { @@ -128,21 +183,29 @@ public function getId(): ?int * @param array $keyValueData * * @return void + * @noinspection ReturnTypeCanBeDeclaredInspection */ - public function hydrate(array $keyValueData): void + public function hydrate(array $keyValueData) { $this->fill($keyValueData); $this->updateId(); } - public function save(): void + /** + * @return int + * @see \ObjectModel::save() + * @noinspection PhpMissingReturnTypeInspection + * @noinspection ReturnTypeCanBeDeclaredInspection + */ + public function save() { - $this->update(); + return (int) $this->update(); } /** * @return bool + * @see \ObjectModel::softDelete() * @noinspection PhpMissingReturnTypeInspection * @noinspection ReturnTypeCanBeDeclaredInspection */ @@ -155,8 +218,11 @@ public function softDelete() } /** - * @return void - * @see \ObjectModel::update() + * @param bool $null_values + * + * @return bool + * @see \ObjectModel::update() + * @noinspection PhpMissingParamTypeInspection */ public function update($null_values = false): bool { diff --git a/tests/Mock/MockPsOrder.php b/tests/Mock/MockPsOrder.php index d7bd4981..410337f6 100644 --- a/tests/Mock/MockPsOrder.php +++ b/tests/Mock/MockPsOrder.php @@ -35,8 +35,7 @@ public function getCurrentOrderState(): ?OrderState * @param int|null $idEmployee * * @return bool - * @throws \PrestaShopDatabaseException - * @throws \PrestaShopException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function setCurrentState(int $state, int $idEmployee = null): bool { diff --git a/tests/TestCase.php b/tests/TestCase.php index 65149acd..4ba917a3 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -11,6 +11,7 @@ use MyParcelNL\PrestaShop\Tests\Mock\MockItems; use MyParcelNL\PrestaShop\Tests\Mock\MockPsConfiguration; use MyParcelNL\PrestaShop\Tests\Mock\MockPsContext; +use MyParcelNL\PrestaShop\Tests\Mock\MockPsCountries; use MyParcelNL\PrestaShop\Tests\Mock\MockPsDb; use MyParcelNL\PrestaShop\Tests\Mock\MockPsEntities; use MyParcelNL\PrestaShop\Tests\Mock\MockPsEntityManager; @@ -29,6 +30,7 @@ protected function getStaticResetServices(): array MockItems::class, MockPsConfiguration::class, MockPsContext::class, + MockPsCountries::class, MockPsDb::class, MockPsEntities::class, MockPsEntityManager::class, diff --git a/tests/Unit/Hooks/HasPsCarrierListHooksTest.php b/tests/Unit/Hooks/HasPsCarrierListHooksTest.php new file mode 100644 index 00000000..071332e0 --- /dev/null +++ b/tests/Unit/Hooks/HasPsCarrierListHooksTest.php @@ -0,0 +1,177 @@ + [ + // Some option for a built-in carrier + 'carrier_list' => [ + ['instance' => psFactory(PsCarrier::class)->store()], + ], + ], + ]; + + $carrierIdMapping = []; + // start after the last index in the carrier list + $index = 23; + + foreach ($allCarriers as $carrierName) { + // Create a PsCarrier + $psCarrier = psFactory(PsCarrier::class)->store(); + + // Add the mapping + psFactory(MyparcelnlCarrierMapping::class) + ->withCarrierId($psCarrier->id) + ->withMyparcelCarrier($carrierName) + ->store(); + + // Map the carrier name to the PsCarrier id + $carrierIdMapping[$carrierName] = $psCarrier->id; + + // Add the carrier to the mocked delivery options list + $deliveryOptionCarrierList["$index,"] = [ + 'carrier_list' => [['instance' => $psCarrier]], + ]; + + $index++; + } + + // Create a delivery address for the current country + $deliveryAddress = psFactory(Address::class) + ->withIdCountry(Country::getByIso($isoCode)) + ->store(); + + // Create a mocked params array that resembles the one passed to the hook. + $params = [ + 'altern' => 1, + 'cookie' => psFactory(Cookie::class)->make(), + 'cart' => psFactory(Cart::class) + ->withAddressDelivery($deliveryAddress->id) + ->make(), + 'delivery_option_list' => [ + 2 => $deliveryOptionCarrierList, + ], + ]; + + $class = new WithHasPsCarrierListHooks(); + + // Should delete some carriers, modifies the array in place. + $class->hookActionFilterDeliveryOptionList($params); + + $carriers = Arr::first($params['delivery_option_list']); + + $flippedMap = array_flip($carrierIdMapping); + $filteredCarrierNames = array_values(array_filter(array_map(function ($carrier) use ($flippedMap) { + $carrierList = $carrier['carrier_list']; + $firstCarrier = Arr::first($carrierList); + + return $flippedMap[$firstCarrier['instance']->id]; + }, $carriers))); + + expect($filteredCarrierNames) + ->toEqual($filteredCarriers) + ->and($carriers) + ->toHaveLength(count($filteredCarriers) + 1); + + $reset(); +})->with([ + 'NL' => [ + 'country' => 'NL', + 'filteredCarriers' => [ + Carrier::CARRIER_DHL_FOR_YOU_NAME, + Carrier::CARRIER_DHL_FOR_YOU_NAME . ':1234', + Carrier::CARRIER_DPD_NAME, + Carrier::CARRIER_POSTNL_NAME, + Carrier::CARRIER_UPS_NAME, + ], + ], + + 'BE' => [ + 'country' => 'BE', + 'filteredCarriers' => [ + Carrier::CARRIER_DHL_FOR_YOU_NAME, + Carrier::CARRIER_DHL_FOR_YOU_NAME . ':1234', + Carrier::CARRIER_DPD_NAME, + Carrier::CARRIER_POSTNL_NAME, + Carrier::CARRIER_UPS_NAME, + ], + ], + + 'BE (sendmyparcel)' => [ + 'country' => 'BE', + 'filteredCarriers' => [ + Carrier::CARRIER_BPOST_NAME, + Carrier::CARRIER_DPD_NAME, + Carrier::CARRIER_POSTNL_NAME, + ], + 'platform' => Platform::SENDMYPARCEL_NAME, + ], + + 'FR' => [ + 'country' => 'FR', + 'filteredCarriers' => [ + Carrier::CARRIER_DHL_PARCEL_CONNECT_NAME, + Carrier::CARRIER_DPD_NAME, + Carrier::CARRIER_POSTNL_NAME, + Carrier::CARRIER_UPS_NAME, + ], + ], + + 'US' => [ + 'country' => 'US', + 'filteredCarriers' => [ + Carrier::CARRIER_POSTNL_NAME, + Carrier::CARRIER_UPS_NAME, + ], + ], + + 'AX' => [ + 'country' => 'AX', + 'filteredCarriers' => [ + Carrier::CARRIER_POSTNL_NAME, + Carrier::CARRIER_UPS_NAME, + ], + ], +]); diff --git a/tests/Unit/Hooks/HasPsCarrierHooksTest.php b/tests/Unit/Hooks/HasPsCarrierUpdateHooksTest.php similarity index 95% rename from tests/Unit/Hooks/HasPsCarrierHooksTest.php rename to tests/Unit/Hooks/HasPsCarrierUpdateHooksTest.php index b571dd50..71e46b68 100644 --- a/tests/Unit/Hooks/HasPsCarrierHooksTest.php +++ b/tests/Unit/Hooks/HasPsCarrierUpdateHooksTest.php @@ -19,9 +19,9 @@ usesShared(new UsesMockPsPdkInstance()); -class WithHasPsCarrierHooks +class WithHasPsCarrierUpdateHooks { - use HasPsCarrierHooks; + use HasPsCarrierUpdateHooks; } it('re-synchronises carrier id and logo when it is updated', function () { @@ -43,7 +43,7 @@ class WithHasPsCarrierHooks $fileSystem->put(_PS_SHIP_IMG_DIR_ . '14' . $fileExtension, '[IMAGE]'); } - $class = new WithHasPsCarrierHooks(); + $class = new WithHasPsCarrierUpdateHooks(); $class->hookActionCarrierUpdate([ 'id_carrier' => 14, diff --git a/tests/Uses/UsesMockPsPdkInstance.php b/tests/Uses/UsesMockPsPdkInstance.php index e5aebb5a..975e9b25 100644 --- a/tests/Uses/UsesMockPsPdkInstance.php +++ b/tests/Uses/UsesMockPsPdkInstance.php @@ -15,13 +15,16 @@ use Manufacturer; use MyParcelNL\Pdk\Base\Facade; use MyParcelNL\Pdk\Base\FileSystemInterface; +use MyParcelNL\Pdk\Base\Service\CountryCodes; use MyParcelNL\Pdk\Facade\Config; use MyParcelNL\Pdk\Facade\Pdk; use MyParcelNL\Pdk\Tests\Factory\Collection\FactoryCollection; use MyParcelNL\Pdk\Tests\Factory\SharedFactoryState; use MyParcelNL\Pdk\Tests\Uses\UsesEachMockPdkInstance; use MyParcelNL\PrestaShop\Tests\Bootstrap\MockPsPdkBootstrapper; +use MyParcelNL\PrestaShop\Tests\Mock\MockPsCountries; use MyParcelNL\PrestaShop\Tests\Mock\MockPsModule; +use MyParcelNL\Sdk\src\Support\Str; use OrderState; use OrderStateFactory; use Risk; @@ -35,20 +38,6 @@ class UsesMockPsPdkInstance extends UsesEachMockPdkInstance { - /** - * @return void - * @throws \MyParcelNL\Pdk\Tests\Factory\Exception\InvalidFactoryException - */ - public function createZones(): void - { - (new FactoryCollection([ - psFactory(Zone::class) - ->withName('Europe'), - psFactory(Zone::class) - ->withName('North America'), - ]))->store(); - } - /** * @return void * @throws \MyParcelNL\Pdk\Tests\Factory\Exception\InvalidFactoryException @@ -75,7 +64,7 @@ protected function addDefaultData(): void psFactory(Warehouse::class), ]))->store(); - $this->createZones(); + $this->createZonesAndCountries(); $this->createOrderStates(); /** @var FileSystemInterface $fileSystem */ @@ -180,4 +169,38 @@ private function createOrderStates(): void }) ->store(); } + + /** + * @return void + * @throws \MyParcelNL\Pdk\Tests\Factory\Exception\InvalidFactoryException + */ + private function createZonesAndCountries(): void + { + $euZone = psFactory(Zone::class) + ->withName('Europe') + ->store(); + $naZone = psFactory(Zone::class) + ->withName('North America') + ->store(); + + // Array keys are set for easier debugging. + $euCountryIds = []; + $naCountryIds = []; + + foreach (CountryCodes::ALL as $countryIso) { + $psCountry = psFactory(Country::class) + ->withIsoCode(Str::upper($countryIso)) + ->store(); + + // Simulate some countries in the EU and NA zones in prestashop by default. + if (in_array($countryIso, [CountryCodes::CC_US, CountryCodes::CC_CA], true)) { + $naCountryIds[$countryIso] = $psCountry->id; + } elseif (in_array($countryIso, CountryCodes::EU_COUNTRIES, true)) { + $euCountryIds[$countryIso] = $psCountry->id; + } + } + + MockPsCountries::setZoneCountries($euZone->id, $euCountryIds); + MockPsCountries::setZoneCountries($naZone->id, $naCountryIds); + } } diff --git a/tests/__snapshots__/EntryTest__it_has_hooks__1.json b/tests/__snapshots__/EntryTest__it_has_hooks__1.json index caad6d8f..337a4e4d 100644 --- a/tests/__snapshots__/EntryTest__it_has_hooks__1.json +++ b/tests/__snapshots__/EntryTest__it_has_hooks__1.json @@ -12,5 +12,6 @@ "displayAdminEndContent", "displayBackOfficeHeader", "displayHeader", + "actionFilterDeliveryOptionList", "actionCarrierUpdate" ] diff --git a/tests/__snapshots__/PsInstallerServiceTest__it_installs_registers_hooks__1.json b/tests/__snapshots__/PsInstallerServiceTest__it_installs_registers_hooks__1.json index c7ea9455..4e39020c 100644 --- a/tests/__snapshots__/PsInstallerServiceTest__it_installs_registers_hooks__1.json +++ b/tests/__snapshots__/PsInstallerServiceTest__it_installs_registers_hooks__1.json @@ -52,7 +52,11 @@ "id": 13 }, "14": { - "name": "actionCarrierUpdate", + "name": "actionFilterDeliveryOptionList", "id": 14 + }, + "15": { + "name": "actionCarrierUpdate", + "id": 15 } } diff --git a/tests/factories/CookieFactory.php b/tests/factories/CookieFactory.php new file mode 100644 index 00000000..34211d82 --- /dev/null +++ b/tests/factories/CookieFactory.php @@ -0,0 +1,28 @@ + * @see \CountryCore + * @method $this withIsoCode(string $isoCode) */ final class CountryFactory extends AbstractPsObjectModelFactory { diff --git a/tests/factories/EmployeeFactory.php b/tests/factories/EmployeeFactory.php new file mode 100644 index 00000000..ccb452b6 --- /dev/null +++ b/tests/factories/EmployeeFactory.php @@ -0,0 +1,16 @@ +withActive(true) ->withIdCountry(1) ->withIdZone(1); } diff --git a/tests/mock_class_map.php b/tests/mock_class_map.php index 00c660ea..2ab9832e 100644 --- a/tests/mock_class_map.php +++ b/tests/mock_class_map.php @@ -8,6 +8,7 @@ use MyParcelNL\PrestaShop\Tests\Mock\MockPsConfiguration; use MyParcelNL\PrestaShop\Tests\Mock\MockPsContext; use MyParcelNL\PrestaShop\Tests\Mock\MockPsController; +use MyParcelNL\PrestaShop\Tests\Mock\MockPsCountry; use MyParcelNL\PrestaShop\Tests\Mock\MockPsCustomerMessage; use MyParcelNL\PrestaShop\Tests\Mock\MockPsDb; use MyParcelNL\PrestaShop\Tests\Mock\MockPsDbQuery; @@ -134,8 +135,13 @@ abstract class CartCore extends ObjectModel { } final class Cart extends CartCore { } +/** @see \CookieCore */ +abstract class CookieCore extends ObjectModel { } + +final class Cookie extends CookieCore { } + /** @see \CountryCore */ -abstract class CountryCore extends ObjectModel { } +abstract class CountryCore extends MockPsCountry { } final class Country extends CountryCore { } diff --git a/tests/mock_namespaced_class_map.php b/tests/mock_namespaced_class_map.php index a762c935..420d038b 100644 --- a/tests/mock_namespaced_class_map.php +++ b/tests/mock_namespaced_class_map.php @@ -12,9 +12,7 @@ public static function getRepositoryClassName(): string; public function delete(); - public function hydrate(array $keyValueData): void; + public function hydrate(array $keyValueData); - public function save(): void; - - public function softDelete(); + public function save(); }