diff --git a/tests/Factory/AbstractPsFactory.php b/tests/Factory/AbstractPsFactory.php index 51aee84b..a71d2779 100644 --- a/tests/Factory/AbstractPsFactory.php +++ b/tests/Factory/AbstractPsFactory.php @@ -23,12 +23,22 @@ public function __call($name, $arguments) $attribute = Str::snake(Str::after($name, 'with')); $value = $arguments[0]; - return $this->with([$attribute => $value]); + return $this->addAttribute($attribute, $value, $arguments[1] ?? []); } throw new BadMethodCallException(sprintf('Method %s does not exist', $name)); } + /** + * @param string $key + * + * @return mixed + */ + public function getAttribute(string $key) + { + return $this->attributes->get($key); + } + /** * @param array $data * @@ -40,4 +50,15 @@ public function with(array $data): PsFactoryInterface return $this; } + + /** + * @param string $attribute + * @param mixed $value + * + * @return $this + */ + protected function addAttribute(string $attribute, $value): self + { + return $this->with([$attribute => $value]); + } } diff --git a/tests/Factory/AbstractPsObjectModelFactory.php b/tests/Factory/AbstractPsObjectModelFactory.php index bac679f7..89681fb1 100644 --- a/tests/Factory/AbstractPsObjectModelFactory.php +++ b/tests/Factory/AbstractPsObjectModelFactory.php @@ -7,16 +7,55 @@ use MyParcelNL\Pdk\Tests\Factory\Contract\FactoryInterface; use MyParcelNL\PrestaShop\Tests\Factory\Contract\PsFactoryInterface; use MyParcelNL\PrestaShop\Tests\Factory\Contract\PsObjectModelFactoryInterface; +use MyParcelNL\PrestaShop\Tests\Mock\MockPsObjectModel; use MyParcelNL\PrestaShop\Tests\Mock\MockPsObjectModels; +use MyParcelNL\Sdk\src\Support\Str; use ObjectModel; /** * @template T of ObjectModel + * @method self withDateAdd(string $dateAdd) + * @method self withDateUpd(string $dateUpd) + * @method self withDeleted(bool $deleted) * @implements PsObjectModelFactoryInterface * @extends AbstractPsFactory */ abstract class AbstractPsObjectModelFactory extends AbstractPsModelFactory implements PsObjectModelFactoryInterface { + /** + * @var PsObjectModelFactoryInterface[] + */ + private $additionalModelsToStore = []; + + /** + * @var null|int + */ + private $id; + + /** + * @param null|int $id + */ + public function __construct(?int $id = null) + { + $this->id = $id; + + parent::__construct(); + } + + /** + * @return T + */ + public function store(): ObjectModel + { + $result = parent::store(); + + foreach ($this->additionalModelsToStore as $modelToStore) { + $modelToStore->store(); + } + + return $result; + } + /** * @param int $id * @@ -27,12 +66,36 @@ public function withId(int $id): self return $this->with(['id' => $id]); } + /** + * @param string $attribute + * @param mixed $value + * @param array $attributes + * + * @return \MyParcelNL\PrestaShop\Tests\Factory\AbstractPsFactory + */ + protected function addAttribute(string $attribute, $value, array $attributes = []): AbstractPsFactory + { + if (Str::startsWith($attribute, 'id_')) { + return $this->withModel(Str::after($attribute, 'id_'), $value, $attributes); + } + + if ($value instanceof PsObjectModelFactoryInterface || $value instanceof MockPsObjectModel) { + return $this->withModel($attribute, $value, $attributes); + } + + return parent::addAttribute($attribute, $value); + } + /** * @return $this */ protected function createDefault(): FactoryInterface { - return $this->withId($this->getNextId()); + return $this + ->withId($this->id ?? $this->getNextId()) + ->withDeleted(false) + ->withDateAdd('2023-01-01 00:00:00') + ->withDateUpd('2023-01-01 00:00:00'); } /** @@ -86,19 +149,45 @@ protected function save($model): void } /** - * @param string $key - * @param ObjectModel|PsObjectModelFactoryInterface $input + * @param string $key + * @param int|ObjectModel|PsObjectModelFactoryInterface $input + * @param array $attributes * * @return $this */ - protected function withModel(string $key, $input): self + protected function withModel(string $key, $input, array $attributes = []): self { + if (is_int($input)) { + $model = Str::after($key, 'id_'); + + return $this->withModel($model, MockPsObjectModels::get($model, $input), $attributes); + } + if ($input instanceof PsFactoryInterface) { - return $this->withModel($key, $input->make()); + $this->additionalModelsToStore[] = $input; + + $model = $input + ->with($attributes) + ->make(); + + return $this->withModel($key, $model); } - $idKey = sprintf('id_%s', $key); + $idKey = sprintf('id_%s', Str::snake($key)); + + return $this->with([$idKey => $input->id]); + } - return $this->with([$idKey => $input]); + /** + * @param string $key + * @param int|ObjectModel|PsObjectModelFactoryInterface $input + * @param array $attributes + * @param string $foreignKey + * + * @return $this + */ + protected function withRelation(string $key, $input, array $attributes, string $foreignKey): self + { + return $this->withModel($key, $input, array_replace($attributes, [$foreignKey => $this->getId()])); } } diff --git a/tests/Factory/Contract/PsFactoryInterface.php b/tests/Factory/Contract/PsFactoryInterface.php index 553d8f31..2f2fb822 100644 --- a/tests/Factory/Contract/PsFactoryInterface.php +++ b/tests/Factory/Contract/PsFactoryInterface.php @@ -8,6 +8,13 @@ interface PsFactoryInterface extends FactoryInterface { + /** + * @param string $key + * + * @return mixed + */ + public function getAttribute(string $key); + /** * @param array $data * diff --git a/tests/Mock/BaseMock.php b/tests/Mock/BaseMock.php index ee8c2dda..0c53f18a 100644 --- a/tests/Mock/BaseMock.php +++ b/tests/Mock/BaseMock.php @@ -5,6 +5,7 @@ namespace MyParcelNL\PrestaShop\Tests\Mock; use MyParcelNL\Pdk\Base\Contract\Arrayable; +use MyParcelNL\Pdk\Base\Support\Arr; use MyParcelNL\Sdk\src\Support\Str; abstract class BaseMock implements Arrayable @@ -42,7 +43,7 @@ public function __call($name, $arguments) if (Str::startsWith($name, 'get')) { $attribute = Str::snake(substr($name, 3)); - return $this->attributes[$attribute] ?? null; + return $this->getAttribute($attribute); } // If no matching attribute is found, return $this to silently ignore the call @@ -56,7 +57,7 @@ public function __call($name, $arguments) */ public function __get(string $name) { - return $this->attributes[$name] ?? null; + return $this->getAttribute($name); } /** @@ -66,7 +67,7 @@ public function __get(string $name) */ public function __isset($name): bool { - return isset($this->attributes[$name]); + return null !== $this->getAttribute($name); } /** @@ -77,7 +78,18 @@ public function __isset($name): bool */ public function __set(string $name, $value): void { - $this->attributes[$name] = $value; + $this->setAttribute($name, $value); + } + + /** + * @param string $key + * @param null $default + * + * @return mixed + */ + public function getAttribute(string $key, $default = null) + { + return Arr::get($this->attributes, $key, $default); } /** @@ -88,6 +100,19 @@ public function getAttributes(): array return $this->attributes; } + /** + * @param string $key + * @param mixed $value + * + * @return $this + */ + public function setAttribute(string $key, $value): self + { + $this->attributes[$key] = $value; + + return $this; + } + /** * @return array */ @@ -103,6 +128,8 @@ public function toArray(): array */ protected function fill(array $attributes): void { - $this->attributes = $attributes; + foreach ($attributes as $key => $value) { + $this->setAttribute($key, $value); + } } } diff --git a/tests/Mock/MockItems.php b/tests/Mock/MockItems.php index 93a9a0ba..1e0d08a5 100644 --- a/tests/Mock/MockItems.php +++ b/tests/Mock/MockItems.php @@ -10,7 +10,7 @@ abstract class MockItems implements StaticMockInterface { /** - * @var Collection + * @var Collection */ private static $items; @@ -21,13 +21,14 @@ abstract class MockItems implements StaticMockInterface */ public static function add(object $object): bool { - $all = static::all(); + $class = get_class($object); + $byClass = self::getByClass($class); - if ($all->has($object->id)) { + if ($byClass->has($object->id)) { return false; } - $object->id = self::getId($object); + $object->id = self::getOrCreateId($object); static::update($object); @@ -45,7 +46,7 @@ public static function addOrUpdate(object $entity): void } /** - * @return \MyParcelNL\Pdk\Base\Support\Collection + * @return Collection */ public static function all(): Collection { @@ -68,14 +69,17 @@ public static function delete(int $id): void } /** - * @param int $id + * @param string $class + * @param int $id * * @return null|object */ - public static function get(int $id): ?object + public static function get(string $class, int $id): ?object { - return static::all() - ->get($id); + return static::getByClass($class) + ->first(function (object $item) use ($id) { + return $item->id === $id; + }); } /** @@ -86,8 +90,7 @@ public static function get(int $id): ?object public static function getByClass(string $class): Collection { return static::all() - ->whereInstanceOf($class) - ->values(); + ->get($class, new Collection()); } public static function reset(): void @@ -102,7 +105,14 @@ public static function reset(): void */ public static function update(object $entity): bool { - static::all() + $class = get_class($entity); + $all = static::all(); + + if (! $all->has($class)) { + $all->put($class, new Collection()); + } + + $all->get($class) ->put($entity->id, $entity); return true; @@ -113,15 +123,14 @@ public static function update(object $entity): bool * * @return int */ - protected static function getId(object $object): int + protected static function getOrCreateId(object $object): int { if (isset($object->id)) { return $object->id; } - $count = self::all() - ->count(); + $byClass = self::getByClass(get_class($object)); - return $count + 1; + return $byClass->count() + 1; } } diff --git a/tests/Mock/MockPsCarrier.php b/tests/Mock/MockPsCarrier.php index 5db325e0..68b16578 100644 --- a/tests/Mock/MockPsCarrier.php +++ b/tests/Mock/MockPsCarrier.php @@ -4,10 +4,14 @@ namespace MyParcelNL\PrestaShop\Tests\Mock; +use Carrier; use MyParcelNL\Pdk\Base\Support\Arr; use ObjectModel; use Zone; +/** + * @method static Carrier[] getCarriers() + */ abstract class MockPsCarrier extends ObjectModel { public const PS_CARRIERS_ONLY = 1; @@ -20,6 +24,25 @@ abstract class MockPsCarrier extends ObjectModel 'zones' => [], ]; + /** + * @param int $reference + * @param null|int $id_lang + * + * @return \Carrier + * @see \CarrierCore::getCarrierByReference() + */ + public static function getCarrierByReference(int $reference, int $id_lang = null): ?Carrier + { + $found = Arr::first( + static::getCarriers(), + static function (array $carrier) use ($reference) { + return $carrier['id_reference'] === $reference; + } + ); + + return $found ? new Carrier($found['id'], $id_lang) : null; + } + /** * @param int $idZone * diff --git a/tests/Mock/MockPsEntityRepository.php b/tests/Mock/MockPsEntityRepository.php index 82157875..422966bc 100644 --- a/tests/Mock/MockPsEntityRepository.php +++ b/tests/Mock/MockPsEntityRepository.php @@ -35,13 +35,7 @@ public function __construct(string $entity) */ public function find($id, $lockMode = null, $lockVersion = null): ?object { - $entry = MockPsEntities::get($id); - - if (! $entry instanceof $this->entity) { - return null; - } - - return $entry; + return MockPsEntities::get($this->entity, $id); } /** diff --git a/tests/Mock/MockPsObjectModel.php b/tests/Mock/MockPsObjectModel.php index 0697c521..f86bd3ef 100644 --- a/tests/Mock/MockPsObjectModel.php +++ b/tests/Mock/MockPsObjectModel.php @@ -10,6 +10,8 @@ abstract class MockPsObjectModel extends BaseMock implements EntityInterface { + protected $hasCustomIdKey = false; + /** * @param null|int $id * @param null|int $id_lang @@ -18,29 +20,32 @@ abstract class MockPsObjectModel extends BaseMock implements EntityInterface */ public function __construct(?int $id = null, ?int $id_lang = null, ?int $id_shop = null, ?int $translator = null) { - $this->setId($id); + $this->updateId($id); - $this->attributes['id_lang'] = $id_lang; - $this->attributes['id_shop'] = $id_shop; + $this->setAttribute('id_lang', $id_lang); + $this->setAttribute('id_shop', $id_shop); if ($id) { - $existing = MockPsObjectModels::get($id); - - if (! $existing instanceof static) { - return; - } + /** @var $this $existing */ + $existing = MockPsObjectModels::get(static::class, $id); $this->hydrate($existing->toArray()); } } - public static function getDefinition() + /** + * @return string[] + */ + public static function getDefinition(): array { return [ 'table' => self::getObjectModelIdentifier(), ]; } + /** + * @return string + */ public static function getRepositoryClassName(): string { return sprintf('%sRepository', static::class); @@ -65,16 +70,32 @@ public function add(bool $auto_date = true, bool $null_values = false): bool return MockPsObjectModels::add($this); } + /** + * @return void + */ public function delete(): void { - MockPsObjectModels::delete($this->attributes['id']); + MockPsObjectModels::delete($this->getId()); } + /** + * @return null|int + */ + public function getId(): ?int + { + return $this->getAttribute('id'); + } + + /** + * @param array $keyValueData + * + * @return void + */ public function hydrate(array $keyValueData): void { $this->fill($keyValueData); - $this->setId(); + $this->updateId(); } public function save(): void @@ -93,24 +114,61 @@ public function update($null_values = false): bool return true; } + /** + * @param int $id + * + * @return $this + */ + public function withId(int $id): self + { + return $this->updateId($id); + } + + /** + * @return string + */ + protected function getAdditionalIdKey(): string + { + return sprintf('id_%s', self::getObjectModelIdentifier()); + } + + /** + * @param int $id + * + * @return $this + */ + protected function setId(int $id): self + { + $this->setAttribute('id', $id); + + return $this->hasCustomIdKey ? $this->setAdditionalId($id) : $this; + } + + /** + * @param int $id + * + * @return $this + */ + private function setAdditionalId(int $id): MockPsObjectModel + { + $idKey = $this->getAdditionalIdKey(); + + return $this->setAttribute($idKey, $id); + } + /** * @param null|int $id * - * @return void + * @return $this */ - private function setId(?int $id = null): void + private function updateId(?int $id = null): self { - if (! $id) { - $id = $this->attributes['id'] ?? null; + $id = $id ?? $this->getId(); - if (! $id) { - return; - } + if (! $id) { + return $this; } - $idKey = sprintf('id_%s', self::getObjectModelIdentifier()); - - $this->attributes['id'] = $id; - $this->attributes[$idKey] = $id; + return $this->setId($id); } } diff --git a/tests/Unit/Pdk/Order/Repository/PdkOrderRepositoryTest.php b/tests/Unit/Pdk/Order/Repository/PdkOrderRepositoryTest.php index d44ce694..1c9b6b6a 100644 --- a/tests/Unit/Pdk/Order/Repository/PdkOrderRepositoryTest.php +++ b/tests/Unit/Pdk/Order/Repository/PdkOrderRepositoryTest.php @@ -6,6 +6,7 @@ namespace MyParcelNL\PrestaShop\Pdk\Order\Repository; use MyParcelNL\Pdk\App\Order\Contract\PdkOrderRepositoryInterface; +use MyParcelNL\Pdk\App\Order\Model\PdkOrder; use MyParcelNL\Pdk\Base\Support\Arr; use MyParcelNL\Pdk\Facade\Pdk; use MyParcelNL\PrestaShop\Tests\Uses\UsesMockPsPdkInstance; @@ -21,15 +22,17 @@ /** @var \MyParcelNL\Pdk\App\Order\Contract\PdkOrderRepositoryInterface $orderRepository */ $orderRepository = Pdk::get(PdkOrderRepositoryInterface::class); - $psOrder = $orderFactory->store(); - $pdkOrder = $orderRepository->get($psOrder); + /** @var Order $psOrder */ + $psOrder = $orderFactory->store(); - $array = $pdkOrder->toArrayWithoutNull(); + $pdkOrder = $orderRepository->get($psOrder); assertMatchesJsonSnapshot( json_encode( - Arr::except($array, ['deliveryOptions.carrier.capabilities', 'deliveryOptions.carrier.returnCapabilities']), - JSON_PRETTY_PRINT + Arr::except( + $pdkOrder->toArrayWithoutNull(), + ['deliveryOptions.carrier.capabilities', 'deliveryOptions.carrier.returnCapabilities'] + ) ) ); })->with([ @@ -37,3 +40,15 @@ return psFactory(Order::class); }, ]); + +it('creates a pdk order from order id', function () { + /** @var Order $psOrder */ + $psOrder = psFactory(Order::class)->store(); + + /** @var \MyParcelNL\Pdk\App\Order\Contract\PdkOrderRepositoryInterface $orderRepository */ + $orderRepository = Pdk::get(PdkOrderRepositoryInterface::class); + + $pdkOrder = $orderRepository->get($psOrder->id); + + expect($pdkOrder)->toBeInstanceOf(PdkOrder::class); +}); diff --git a/tests/Unit/Service/PsCarrierServiceTest.php b/tests/Unit/Service/PsCarrierServiceTest.php index b14afec2..45bba59d 100644 --- a/tests/Unit/Service/PsCarrierServiceTest.php +++ b/tests/Unit/Service/PsCarrierServiceTest.php @@ -6,11 +6,14 @@ namespace MyParcelNL\PrestaShop\Service; use Carrier as PsCarrier; +use MyParcelNL\Pdk\Account\Collection\ShopCollection; use MyParcelNL\Pdk\Account\Model\Shop; use MyParcelNL\Pdk\App\Api\Backend\PdkBackendActions; use MyParcelNL\Pdk\Base\Support\Collection; use MyParcelNL\Pdk\Carrier\Collection\CarrierCollection; +use MyParcelNL\Pdk\Carrier\Collection\CarrierCollectionFactory; use MyParcelNL\Pdk\Carrier\Model\Carrier; +use MyParcelNL\Pdk\Carrier\Model\CarrierFactory; use MyParcelNL\Pdk\Facade\Actions; use MyParcelNL\Pdk\Facade\Pdk; use MyParcelNL\Pdk\Tests\Api\Response\ExampleAclResponse; @@ -19,19 +22,31 @@ use MyParcelNL\Pdk\Tests\Api\Response\ExampleGetCarrierOptionsResponse; use MyParcelNL\Pdk\Tests\Bootstrap\MockApi; use MyParcelNL\Pdk\Tests\Bootstrap\TestBootstrapper; +use MyParcelNL\Pdk\Tests\Factory\Collection\FactoryCollection; use MyParcelNL\PrestaShop\Contract\PsCarrierServiceInterface; +use MyParcelNL\PrestaShop\Entity\MyparcelnlCarrierMapping; use MyParcelNL\PrestaShop\Repository\PsCarrierMappingRepository; -use MyParcelNL\PrestaShop\Tests\Bootstrap\PsTestBootstrapper; use MyParcelNL\PrestaShop\Tests\Uses\UsesMockPsPdkInstance; use Psr\Log\LoggerInterface; use RangePrice; use RangeWeight; use function MyParcelNL\Pdk\Tests\factory; use function MyParcelNL\Pdk\Tests\usesShared; +use function MyParcelNL\PrestaShop\psFactory; use function Spatie\Snapshots\assertMatchesJsonSnapshot; usesShared(new UsesMockPsPdkInstance()); +function setupAccountAndCarriers(CarrierCollectionFactory $factory): Collection +{ + TestBootstrapper::hasAccount( + TestBootstrapper::API_KEY_VALID, + factory(ShopCollection::class)->push(factory(Shop::class)->withCarriers($factory)) + ); + + return new Collection($factory->make()); +} + function doSnapshotTest(Collection $carrierMappings, Collection $psCarriers): void { /** @var \MyParcelNL\Pdk\Tests\Bootstrap\MockLogger $logger */ @@ -49,26 +64,49 @@ function doSnapshotTest(Collection $carrierMappings, Collection $psCarriers): vo $id = $data['id']; $psCarrier = new PsCarrier($id); + $zones = (new Collection($psCarrier->getZones()))->values(); + return array_merge($data, [ - 'zones' => $psCarrier->getZones(), - 'rangeWeights' => RangeWeight::getRanges($id), - 'rangePrices' => RangePrice::getRanges($id), + 'zones' => $zones->toArrayWithoutNull(), + 'rangeWeights' => (new Collection(RangeWeight::getRanges($id)))->toArrayWithoutNull(), + 'rangePrices' => (new Collection(RangePrice::getRanges($id)))->toArrayWithoutNull(), ]); }) + ->values() ->toArrayWithoutNull(), - 'carrierMappings' => $carrierMappings->toArray(), + 'carrierMappings' => $carrierMappings->toArrayWithoutNull(), ]) ); } it('creates carriers on account update', function () { - TestBootstrapper::hasAccount(); - PsTestBootstrapper::hasCarrierImages(); + $carriers = setupAccountAndCarriers( + factory(CarrierCollection::class)->push( + factory(Carrier::class) + ->fromPostNL() + ->withHuman('PostNL'), + factory(Carrier::class) + ->fromDhlForYou() + ->withSubscriptionId(8123) + ->withHuman('Dhl custom'), + factory(Carrier::class) + ->fromDhlForYou() + ->withHuman('Dhl') + ) + ); + + $carrierOptions = $carriers->map(function (Carrier $carrier) { + return [ + 'carrier_id' => $carrier->id, + 'enabled' => (int) $carrier->enabled, + 'subscription_id' => $carrier->subscriptionId, + ]; + }); MockApi::enqueue( new ExampleGetAccountsResponse(), new ExampleGetCarrierConfigurationResponse(), - new ExampleGetCarrierOptionsResponse(), + new ExampleGetCarrierOptionsResponse($carrierOptions->toArrayWithoutNull()), new ExampleAclResponse() ); @@ -79,38 +117,127 @@ function doSnapshotTest(Collection $carrierMappings, Collection $psCarriers): vo $carrierMappings = $repository->all(); $psCarriers = new Collection(PsCarrier::getCarriers(0)); + expect($carrierMappings->count()) + ->toBe(3) + ->and($psCarriers->count()) + ->toBe(3); + doSnapshotTest($carrierMappings, $psCarriers); }); it('does not create duplicate carriers', function () { - TestBootstrapper::hasAccount(); - - factory(Shop::class) - ->withCarriers( - factory(CarrierCollection::class)->push( - ['name' => Carrier::CARRIER_POSTNL_NAME], - ['name' => Carrier::CARRIER_DHL_FOR_YOU_NAME], - ['name' => Carrier::CARRIER_DHL_EUROPLUS_NAME] - ) + setupAccountAndCarriers( + factory(CarrierCollection::class)->push( + factory(Carrier::class) + ->withName('postnl') + ->withId(12) + ->withSubscriptionId(23) ) - ->store(); - - PsTestBootstrapper::hasCarrierImages(); + ); /** @var PsCarrierServiceInterface $service */ $service = Pdk::get(PsCarrierServiceInterface::class); $service->updateCarriers(); $service->updateCarriers(); $service->updateCarriers(); - $service->updateCarriers(); /** @var PsCarrierMappingRepository $repository */ $repository = Pdk::get(PsCarrierMappingRepository::class); $carrierMappings = $repository->all(); - expect($carrierMappings->count())->toBe(3); + $psCarriers = new Collection(PsCarrier::getCarriers(0)); + + expect($psCarriers->count()) + ->toBe(1) + ->and($carrierMappings->count()) + ->toBe(1); +}); +it('updates existing carrier if mapping already exists', function () { + (new FactoryCollection([ + psFactory(PsCarrier::class)->withId(10), + psFactory(PsCarrier::class)->withId(11), + + psFactory(MyparcelnlCarrierMapping::class) + ->fromPostNL() + ->withCarrierId(10), + psFactory(MyparcelnlCarrierMapping::class) + ->fromDhlForYou(8123) + ->withCarrierId(11), + ]))->store(); + + setupAccountAndCarriers( + factory(CarrierCollection::class)->push( + factory(Carrier::class) + ->fromPostNL() + ->withHuman('This Is PostNL'), + factory(Carrier::class) + ->fromDhlForYou() + ->withSubscriptionId(8123) + ->withHuman('This Is DhLForYou') + ) + ); + + /** @var PsCarrierServiceInterface $service */ + $service = Pdk::get(PsCarrierServiceInterface::class); + $service->updateCarriers(); + + // expect 2 carriers to exist $psCarriers = new Collection(PsCarrier::getCarriers(0)); - doSnapshotTest($carrierMappings, $psCarriers); + expect($psCarriers->count()) + ->toBe(2) + ->and($psCarriers->first()) + ->toHaveKeysAndValues([ + 'id' => 10, + 'id_reference' => 100, + 'name' => 'This Is PostNL', + ]) + ->and($psCarriers->last()) + ->toHaveKeysAndValues([ + 'id' => 11, + 'id_reference' => 9008123, + 'name' => 'This Is DhLForYou', + ]); }); + +it('uses existing carrier if reference id matches', function (CarrierFactory $factory) { + setupAccountAndCarriers(factory(CarrierCollection::class)->push($factory)); + + $carrier = $factory->make(); + + /** @see \MyParcelNL\PrestaShop\Carrier\Service\CarrierBuilder::createCarrierIdReference() */ + $referenceId = (int) (str_pad((string) $carrier->id, 3, '0') . $carrier->subscriptionId); + + psFactory(PsCarrier::class) + ->withIdReference($referenceId) + ->store(); + + /** @var PsCarrierServiceInterface $service */ + $service = Pdk::get(PsCarrierServiceInterface::class); + $service->updateCarriers(); + + $psCarriers = new Collection(PsCarrier::getCarriers(0)); + + expect($psCarriers->count()) + ->toBe(1) + ->and($psCarriers->first()) + ->toHaveKeysAndValues([ + 'id' => 1, + 'id_reference' => $referenceId, + 'name' => $carrier->human, + ]); +})->with([ + 'only id' => function () { + return factory(Carrier::class) + ->fromPostNL() + ->withHuman('Carrier'); + }, + + 'id and subscription id' => function () { + return factory(Carrier::class) + ->fromDhlForYou() + ->withHuman('Carrier') + ->withSubscriptionId(8123); + }, +]); diff --git a/tests/Uses/UsesMockPlugin.php b/tests/Uses/UsesMockPlugin.php index 53bf9730..6e73367b 100644 --- a/tests/Uses/UsesMockPlugin.php +++ b/tests/Uses/UsesMockPlugin.php @@ -5,7 +5,6 @@ namespace MyParcelNL\PrestaShop\Tests\Uses; use MyParcelNL; -use MyParcelNL\PrestaShop\Tests\Mock\MockMyParcelNL; use MyParcelNL\PrestaShop\Tests\Mock\MockPsModule; final class UsesMockPlugin extends UsesMockPsPdkInstance @@ -16,7 +15,7 @@ final class UsesMockPlugin extends UsesMockPsPdkInstance */ protected function setup(): void { - if (! class_exists(MockMyParcelNL::class)) { + if (! class_exists(MyParcelNL::class)) { require_once __DIR__ . '/../../myparcelnl.php'; } diff --git a/tests/__snapshots__/PsCarrierServiceTest__it_creates_carriers_on_account_update__1.json b/tests/__snapshots__/PsCarrierServiceTest__it_creates_carriers_on_account_update__1.json index 0cf577cd..06d1e91b 100644 --- a/tests/__snapshots__/PsCarrierServiceTest__it_creates_carriers_on_account_update__1.json +++ b/tests/__snapshots__/PsCarrierServiceTest__it_creates_carriers_on_account_update__1.json @@ -15,8 +15,7 @@ "id_zone": 2 } ], - "id": 2, - "name": "DHL Parcel Connect", + "name": "PostNL", "active": 1, "id_reference": 100, "deleted": 0, @@ -25,12 +24,55 @@ "range_behavior": 1, "shipping_external": true, "shipping_method": 2, + "id": 1, + "rangeWeights": [ + { + "id_carrier": 1, + "delimiter1": "0", + "delimiter2": "10000", + "id": 1 + } + ], + "rangePrices": [ + { + "id_carrier": 1, + "delimiter1": "0", + "delimiter2": "10000", + "id": 1 + } + ] + }, + { + "zones": [ + { + "active": 1, + "name": "Europe", + "id": 1, + "id_zone": 1 + }, + { + "active": 1, + "name": "North America", + "id": 2, + "id_zone": 2 + } + ], + "name": "DHL For You", + "active": 1, + "id_reference": 900, + "deleted": 0, + "is_module": true, + "need_range": 1, + "range_behavior": 1, + "shipping_external": true, + "shipping_method": 2, + "id": 2, "rangeWeights": [ { "id_carrier": 2, "delimiter1": "0", "delimiter2": "10000", - "id": 4 + "id": 2 } ], "rangePrices": [ @@ -38,7 +80,7 @@ "id_carrier": 2, "delimiter1": "0", "delimiter2": "10000", - "id": 3 + "id": 2 } ] }, @@ -57,42 +99,46 @@ "id_zone": 2 } ], - "name": "DHL Europlus", + "name": "DHL For You", "active": 1, - "id_reference": 110, + "id_reference": 9008123, "deleted": 0, "is_module": true, "need_range": 1, "range_behavior": 1, "shipping_external": true, "shipping_method": 2, - "id": 6, + "id": 3, "rangeWeights": [ { - "id_carrier": 6, + "id_carrier": 3, "delimiter1": "0", "delimiter2": "10000", - "id": 6 + "id": 3 } ], "rangePrices": [ { - "id_carrier": 6, + "id_carrier": 3, "delimiter1": "0", "delimiter2": "10000", - "id": 6 + "id": 3 } ] } ], "carrierMappings": [ { - "carrierId": 2, + "carrierId": 1, "myparcelCarrier": "postnl" }, { - "carrierId": 6, - "myparcelCarrier": "dhleuroplus" + "carrierId": 2, + "myparcelCarrier": "dhlforyou" + }, + { + "carrierId": 3, + "myparcelCarrier": "dhlforyou:8123" } ] } diff --git a/tests/factories/AddressFactory.php b/tests/factories/AddressFactory.php index b4d3ba2d..299bc6f2 100644 --- a/tests/factories/AddressFactory.php +++ b/tests/factories/AddressFactory.php @@ -2,14 +2,61 @@ declare(strict_types=1); +use MyParcelNL\Pdk\Tests\Factory\Contract\FactoryInterface; use MyParcelNL\PrestaShop\Tests\Factory\AbstractPsObjectModelFactory; /** + * @see \AddressCore + * @method self withAddress1(string $address1) + * @method self withAddress2(string $address2) + * @method self withAlias(string $alias) + * @method self withCity(string $city) + * @method self withCompany(string $company) + * @method self withCountry(int|Country|CountryFactory $country) + * @method self withCustomer(int|Customer|CustomerFactory $customer) + * @method self withDni(string $dni) + * @method self withFirstname(string $firstname) + * @method self withIdCountry(int $idCountry) + * @method self withIdCustomer(int $idCustomer) + * @method self withIdManufacturer(int $idManufacturer) + * @method self withIdState(int $idState) + * @method self withIdSupplier(int $idSupplier) + * @method self withIdWarehouse(int $idWarehouse) + * @method self withLastname(string $lastname) + * @method self withManufacturer(int|Manufacturer|ManufacturerFactory $manufacturer) + * @method self withOther(string $other) + * @method self withPhone(string $phone) + * @method self withPhoneMobile(string $phoneMobile) + * @method self withPostcode(string $postcode) + * @method self withState(int|State|StateFactory $state) + * @method self withSupplier(int|Supplier|SupplierFactory $supplier) + * @method self withVatNumber(string $vatNumber) + * @method self withWarehouse(int|Warehouse|WarehouseFactory $warehouse) */ final class AddressFactory extends AbstractPsObjectModelFactory { + /** + * @return $this + */ + protected function createDefault(): FactoryInterface + { + return parent::createDefault() + ->withCity('Hoofddorp') + ->withPostcode('2132JE') + ->withAddress1('Antareslaan 31') + ->withFirstname('Meredith') + ->withLastname('Mailbox') + ->withCountry(1) + ->withCustomer(1) + ->withManufacturer(1) + ->withState(1) + ->withSupplier(1) + ->withWarehouse(1); + } + protected function getObjectModelClass(): string { return Address::class; } } + diff --git a/tests/factories/CarrierFactory.php b/tests/factories/CarrierFactory.php index 5e04c288..482c763b 100644 --- a/tests/factories/CarrierFactory.php +++ b/tests/factories/CarrierFactory.php @@ -2,11 +2,12 @@ declare(strict_types=1); +use MyParcelNL\Pdk\Tests\Factory\Contract\FactoryInterface; use MyParcelNL\PrestaShop\Tests\Factory\AbstractPsObjectModelFactory; /** + * @see \CarrierCore * @method self withIdCarrier(int $id) - * @method self withIdReference(int $id) * @method self withName(string $name) * @method self withUrl(string $url) * @method self withActive(int $active) @@ -28,6 +29,23 @@ */ final class CarrierFactory extends AbstractPsObjectModelFactory { + /** + * Defined manually to avoid this being treated as the id of a class. + * + * @param int $id + * + * @return self + */ + public function withIdReference(int $id): self + { + return $this->with(['id_reference' => $id]); + } + + protected function createDefault(): FactoryInterface + { + return $this->withActive(1); + } + protected function getObjectModelClass(): string { return Carrier::class; diff --git a/tests/factories/CustomerFactory.php b/tests/factories/CustomerFactory.php index f4dcd6ab..fea07a3e 100644 --- a/tests/factories/CustomerFactory.php +++ b/tests/factories/CustomerFactory.php @@ -1,11 +1,65 @@ withFirstname('Felicia') + ->withLastname('Parcel') + ->withDefaultGroup(1) + ->withGender(1) + ->withLang(1) + ->withRisk(1) + ->withShop(1) + ->withShopGroup(1); + } + protected function getObjectModelClass(): string { return Customer::class; diff --git a/tests/factories/MyParcelNL/PrestaShop/Entity/MyparcelnlCarrierMappingFactory.php b/tests/factories/MyParcelNL/PrestaShop/Entity/MyparcelnlCarrierMappingFactory.php index d96f9078..5d0833d5 100644 --- a/tests/factories/MyParcelNL/PrestaShop/Entity/MyparcelnlCarrierMappingFactory.php +++ b/tests/factories/MyParcelNL/PrestaShop/Entity/MyparcelnlCarrierMappingFactory.php @@ -4,6 +4,7 @@ namespace MyParcelNL\PrestaShop\Entity; +use MyParcelNL\Pdk\Carrier\Model\Carrier; use MyParcelNL\PrestaShop\Tests\Factory\AbstractPsEntityFactory; /** @@ -12,8 +13,56 @@ */ final class MyparcelnlCarrierMappingFactory extends AbstractPsEntityFactory { + public function fromBpost(int $subscriptionId = null): self + { + return $this->fromCarrier(Carrier::CARRIER_BPOST_NAME, $subscriptionId); + } + + public function fromDhlEuroplus(int $subscriptionId = null): self + { + return $this->fromCarrier(Carrier::CARRIER_DHL_EUROPLUS_NAME, $subscriptionId); + } + + public function fromDhlForYou(int $subscriptionId = null): self + { + return $this->fromCarrier(Carrier::CARRIER_DHL_FOR_YOU_NAME, $subscriptionId); + } + + public function fromDhlParcelConnect(int $subscriptionId = null): self + { + return $this->fromCarrier(Carrier::CARRIER_DHL_PARCEL_CONNECT_NAME, $subscriptionId); + } + + public function fromDpd(int $subscriptionId = null): self + { + return $this->fromCarrier(Carrier::CARRIER_DPD_NAME, $subscriptionId); + } + + public function fromPostNL(int $subscriptionId = null): self + { + return $this->fromCarrier(Carrier::CARRIER_POSTNL_NAME, $subscriptionId); + } + + public function fromUps(int $subscriptionId = null): self + { + return $this->fromCarrier(Carrier::CARRIER_UPS_NAME, $subscriptionId); + } + protected function getEntityClass(): string { return MyparcelnlCarrierMapping::class; } + + /** + * @param string $name + * @param null|int $subscriptionId + * + * @return $this + */ + private function fromCarrier(string $name, ?int $subscriptionId): self + { + $identifier = $subscriptionId ? "$name:$subscriptionId" : $name; + + return $this->withMyparcelCarrier($identifier); + } } diff --git a/tests/factories/OrderFactory.php b/tests/factories/OrderFactory.php index cc23ff24..210c04f3 100644 --- a/tests/factories/OrderFactory.php +++ b/tests/factories/OrderFactory.php @@ -4,13 +4,16 @@ use MyParcelNL\Pdk\Tests\Factory\Contract\FactoryInterface; use MyParcelNL\PrestaShop\Tests\Factory\AbstractPsObjectModelFactory; -use MyParcelNL\PrestaShop\Tests\Factory\Contract\PsObjectModelFactoryInterface; /** + * @see \OrderCore * @method self add() - * @method self withCarrierTaxRate(float $carrierTaxRate) + * @method self withCarrier(int|Carrier|CarrierFactory $carrier, array $attributes = []) + * @method self withCart(int|Cart|CartFactory $cart, array $attributes = []) * @method self withConversionRate(float $conversionRate) + * @method self withCurrency(int|Currency|CurrencyFactory $currency, array $attributes = []) * @method self withCurrentState(int $currentState) + * @method self withCustomer(int|Customer|CustomerFactory $customer, array $attributes = []) * @method self withDateAdd(string $dateAdd) * @method self withDateUpd(string $dateUpd) * @method self withDeliveryDate(string $deliveryDate) @@ -28,6 +31,7 @@ * @method self withIdShopGroup(int $idShopGroup) * @method self withInvoiceDate(string $invoiceDate) * @method self withInvoiceNumber(int $invoiceNumber) + * @method self withLang(int|Lang|LangFactory $lang, array $attributes = []) * @method self withMobileTheme(bool $mobileTheme) * @method self withModule(string $module) * @method self withNote(string $note) @@ -37,6 +41,8 @@ * @method self withRoundMode(int $roundMode) * @method self withRoundType(int $roundType) * @method self withSecureKey(string $secureKey) + * @method self withShop(int|Shop|ShopFactory $shop, array $attributes = []) + * @method self withShopGroup(int|ShopGroup|ShopGroupFactory $shopGroup, array $attributes = []) * @method self withTotalDiscounts(float $totalDiscounts) * @method self withTotalDiscountsTaxExcl(float $totalDiscountsTaxExcl) * @method self withTotalDiscountsTaxIncl(float $totalDiscountsTaxIncl) @@ -57,93 +63,25 @@ final class OrderFactory extends AbstractPsObjectModelFactory { /** - * @param \Address|\AddressFactory $addressDelivery + * @param int|Address|AddressFactory $input + * @param array $attributes * - * @return self + * @return $this */ - public function withAddressDelivery($addressDelivery): PsObjectModelFactoryInterface + public function withAddressDelivery($input, array $attributes = []): self { - return $this->withModel('addressDelivery', $addressDelivery); + return $this->withRelation('address_delivery', $input, $attributes, 'id_customer'); } /** - * @param \Address|\AddressFactory $addressInvoice + * @param int|Address|AddressFactory $input + * @param array $attributes * - * @return self + * @return $this */ - public function withAddressInvoice($addressInvoice): PsObjectModelFactoryInterface + public function withAddressInvoice($input, array $attributes = []): self { - return $this->withModel('addressInvoice', $addressInvoice); - } - - /** - * @param Carrier|CarrierFactory $carrier - * - * @return self - */ - public function withCarrier($carrier): PsObjectModelFactoryInterface - { - return $this->withModel('carrier', $carrier); - } - - /** - * @param Cart|CartFactory $cart - * - * @return self - */ - public function withCart($cart): PsObjectModelFactoryInterface - { - return $this->withModel('cart', $cart); - } - - /** - * @param Currency|CurrencyFactory $currency - * - * @return self - */ - public function withCurrency($currency): PsObjectModelFactoryInterface - { - return $this->withModel('currency', $currency); - } - - /** - * @param Customer|CustomerFactory $customer - * - * @return self - */ - public function withCustomer($customer): PsObjectModelFactoryInterface - { - return $this->withModel('customer', $customer); - } - - /** - * @param Lang|LangFactory $lang - * - * @return self - */ - public function withLang($lang): PsObjectModelFactoryInterface - { - return $this->withModel('lang', $lang); - } - - /** - * @param Shop|ShopFactory $shop - * - * @return self - */ - public function withShop($shop): PsObjectModelFactoryInterface - { - return $this->withModel('shop', $shop); - } - - /** - * @param ShopGroup|ShopGroupFactory $shopGroup - * - * @return self - */ - public function withShopGroup($shopGroup): PsObjectModelFactoryInterface - { - return $this->withModel('shopGroup', $shopGroup); + return $this->withRelation('address_invoice', $input, $attributes, 'id_customer'); } /** @@ -152,8 +90,15 @@ public function withShopGroup($shopGroup): PsObjectModelFactoryInterface protected function createDefault(): FactoryInterface { return parent::createDefault() - ->withDateAdd(date('Y-m-d H:i:s')) - ->withDateUpd(date('Y-m-d H:i:s')); + ->withAddressDelivery(1) + ->withAddressInvoice(2) + ->withCarrier(1) + ->withCart(1) + ->withCurrency(1) + ->withCustomer(1) + ->withLang(1) + ->withShop(1) + ->withShopGroup(1); } protected function getObjectModelClass(): string diff --git a/tests/mock_class_map.php b/tests/mock_class_map.php index 8db6d20a..1604c2f3 100644 --- a/tests/mock_class_map.php +++ b/tests/mock_class_map.php @@ -210,7 +210,10 @@ abstract class WarehouseCore extends ObjectModel { } final class Warehouse extends WarehouseCore { } /** @see \ZoneCore */ -abstract class ZoneCore extends ObjectModel { } +abstract class ZoneCore extends ObjectModel +{ + protected $hasCustomIdKey = true; +} /** @see \Zone */ final class Zone extends ZoneCore { }