diff --git a/src/Event/MollieOrderShipmentTrackingEvent.php b/src/Event/MollieOrderShipmentTrackingEvent.php deleted file mode 100644 index 645816ba2..000000000 --- a/src/Event/MollieOrderShipmentTrackingEvent.php +++ /dev/null @@ -1,128 +0,0 @@ -orderId = $orderId; - $this->context = $context; - $this->trackingCarrier = $trackingCarrier; - $this->trackingCode = $trackingCode; - $this->trackingUrl = $trackingUrl; - } - - /** - * @return string - */ - public function getOrderId(): string - { - return $this->orderId; - } - - /** - * @param string $orderId - */ - public function setOrderId(string $orderId): void - { - $this->orderId = $orderId; - } - - /** - * @return Context - */ - public function getContext(): Context - { - return $this->context; - } - - /** - * @param Context $context - */ - public function setContext(Context $context): void - { - $this->context = $context; - } - - /** - * @return string - */ - public function getTrackingCarrier(): string - { - return $this->trackingCarrier; - } - - /** - * @param string $trackingCarrier - */ - public function setTrackingCarrier(string $trackingCarrier): void - { - $this->trackingCarrier = $trackingCarrier; - } - - /** - * @return string - */ - public function getTrackingCode(): string - { - return $this->trackingCode; - } - - /** - * @param string $trackingCode - */ - public function setTrackingCode(string $trackingCode): void - { - $this->trackingCode = $trackingCode; - } - - /** - * @return string - */ - public function getTrackingUrl(): string - { - return $this->trackingUrl; - } - - /** - * @param string $trackingUrl - */ - public function setTrackingUrl(string $trackingUrl): void - { - $this->trackingUrl = $trackingUrl; - } -} diff --git a/src/Facade/MollieShipment.php b/src/Facade/MollieShipment.php index b6bf37498..1021bf181 100644 --- a/src/Facade/MollieShipment.php +++ b/src/Facade/MollieShipment.php @@ -11,6 +11,7 @@ use Kiener\MolliePayments\Service\MolliePaymentExtractor; use Kiener\MolliePayments\Service\OrderDeliveryService; use Kiener\MolliePayments\Service\OrderService; +use Kiener\MolliePayments\Service\TrackingInfoStructFactory; use Kiener\MolliePayments\Service\Transition\DeliveryTransitionServiceInterface; use Kiener\MolliePayments\Struct\MollieApi\ShipmentTrackingInfoStruct; use Psr\Log\LoggerInterface; @@ -20,6 +21,7 @@ use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity; use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionEntity; use Shopware\Core\Checkout\Order\OrderEntity; +use Shopware\Core\Checkout\Shipping\ShippingMethodEntity; use Shopware\Core\Content\Product\ProductEntity; use Shopware\Core\Framework\Context; use Shopware\Core\Framework\Uuid\Uuid; @@ -61,11 +63,17 @@ class MollieShipment implements MollieShipmentInterface */ private $orderDataExtractor; + /** + * @var TrackingInfoStructFactory + */ + private $trackingInfoStructFactory; + /** * @var LoggerInterface */ private $logger; + /** * @param MolliePaymentExtractor $extractor * @param DeliveryTransitionServiceInterface $deliveryTransitionService @@ -76,7 +84,7 @@ class MollieShipment implements MollieShipmentInterface * @param OrderDataExtractor $orderDataExtractor * @param LoggerInterface $logger */ - public function __construct(MolliePaymentExtractor $extractor, DeliveryTransitionServiceInterface $deliveryTransitionService, Order $mollieApiOrderService, Shipment $mollieApiShipmentService, OrderDeliveryService $orderDeliveryService, OrderService $orderService, OrderDataExtractor $orderDataExtractor, LoggerInterface $logger) + public function __construct(MolliePaymentExtractor $extractor, DeliveryTransitionServiceInterface $deliveryTransitionService, Order $mollieApiOrderService, Shipment $mollieApiShipmentService, OrderDeliveryService $orderDeliveryService, OrderService $orderService, OrderDataExtractor $orderDataExtractor, TrackingInfoStructFactory $trackingInfoStructFactory, LoggerInterface $logger) { $this->extractor = $extractor; $this->deliveryTransitionService = $deliveryTransitionService; @@ -86,6 +94,7 @@ public function __construct(MolliePaymentExtractor $extractor, DeliveryTransitio $this->orderService = $orderService; $this->orderDataExtractor = $orderDataExtractor; $this->logger = $logger; + $this->trackingInfoStructFactory = $trackingInfoStructFactory; } /** @@ -170,7 +179,9 @@ public function setShipment(string $orderDeliveryId, Context $context): bool return false; } - $addedMollieShipment = $this->mollieApiOrderService->setShipment($mollieOrderId, $order->getSalesChannelId()); + $trackingInfoStruct = $this->trackingInfoStructFactory->createFromDelivery($delivery); + + $addedMollieShipment = $this->mollieApiOrderService->setShipment($mollieOrderId, $trackingInfoStruct, $order->getSalesChannelId()); if ($addedMollieShipment) { $values = [CustomFieldsInterface::DELIVERY_SHIPPED => true]; @@ -250,7 +261,7 @@ public function shipOrder( $shipment = $this->mollieApiShipmentService->shipOrder( $mollieOrderId, $order->getSalesChannelId(), - $this->createTrackingInfoStruct($trackingCarrier, $trackingCode, $trackingUrl) + $this->trackingInfoStructFactory->create($trackingCarrier, $trackingCode, $trackingUrl) ); $delivery = $this->orderDataExtractor->extractDelivery($order, $context); @@ -371,7 +382,7 @@ public function shipItem( $order->getSalesChannelId(), $mollieOrderLineId, $quantity, - $this->createTrackingInfoStruct($trackingCarrier, $trackingCode, $trackingUrl) + $this->trackingInfoStructFactory->create($trackingCarrier, $trackingCode, $trackingUrl) ); $delivery = $this->orderDataExtractor->extractDelivery($order, $context); @@ -463,21 +474,4 @@ private function findMatchingLineItems(OrderEntity $order, string $itemIdentifie return false; }); } - - private function createTrackingInfoStruct(string $trackingCarrier, string $trackingCode, string $trackingUrl): ?ShipmentTrackingInfoStruct - { - if (empty($trackingCarrier) && empty($trackingCode)) { - return null; - } - - if (empty($trackingCarrier)) { - throw new \InvalidArgumentException('Missing Argument for Tracking Carrier!'); - } - - if (empty($trackingCode)) { - throw new \InvalidArgumentException('Missing Argument for Tracking Code!'); - } - - return new ShipmentTrackingInfoStruct($trackingCarrier, $trackingCode, $trackingUrl); - } } diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index f822b00ad..1c529d7fd 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -178,6 +178,9 @@ %env(default::APP_URL)% + + + diff --git a/src/Resources/config/services/facades.xml b/src/Resources/config/services/facades.xml index b9b93894d..941f4edef 100644 --- a/src/Resources/config/services/facades.xml +++ b/src/Resources/config/services/facades.xml @@ -13,9 +13,11 @@ + + diff --git a/src/Resources/config/services/subscriber.xml b/src/Resources/config/services/subscriber.xml index eb89fc689..e76ae36f7 100644 --- a/src/Resources/config/services/subscriber.xml +++ b/src/Resources/config/services/subscriber.xml @@ -21,11 +21,6 @@ - - - - - diff --git a/src/Service/MollieApi/Order.php b/src/Service/MollieApi/Order.php index a329c4764..3e1a7e145 100644 --- a/src/Service/MollieApi/Order.php +++ b/src/Service/MollieApi/Order.php @@ -14,6 +14,7 @@ use Kiener\MolliePayments\Service\MollieApi\RequestAnonymizer\MollieRequestAnonymizer; use Kiener\MolliePayments\Service\Router\RoutingBuilder; use Kiener\MolliePayments\Service\SettingsService; +use Kiener\MolliePayments\Struct\MollieApi\ShipmentTrackingInfoStruct; use Mollie\Api\Exceptions\ApiException; use Mollie\Api\Resources\Order as MollieOrder; use Mollie\Api\Resources\OrderLine; @@ -25,7 +26,9 @@ use Psr\Log\LoggerInterface; use RuntimeException; use Shopware\Core\Checkout\Customer\CustomerEntity; +use Shopware\Core\Checkout\Order\Aggregate\OrderDelivery\OrderDeliveryEntity; use Shopware\Core\Checkout\Order\OrderEntity; +use Shopware\Core\Checkout\Shipping\ShippingMethodEntity; use Shopware\Core\System\SalesChannel\SalesChannelContext; class Order @@ -391,14 +394,17 @@ public function getPaymentUrl(string $mollieOrderId, string $salesChannelId): ?s return $mollieOrder->status === 'created' ? $mollieOrder->getCheckoutUrl() : null; } - public function setShipment(string $mollieOrderId, string $salesChannelId): bool + public function setShipment(string $mollieOrderId, ?ShipmentTrackingInfoStruct $trackingInfoStruct, string $salesChannelId): bool { $mollieOrder = $this->getMollieOrder($mollieOrderId, $salesChannelId); - + $shipment = []; + if ($trackingInfoStruct instanceof ShipmentTrackingInfoStruct) { + $shipment['tracking'] = $trackingInfoStruct->toArray(); + } /** @var OrderLine $orderLine */ foreach ($mollieOrder->lines() as $orderLine) { if ($orderLine->shippableQuantity > 0) { - $mollieOrder->shipAll(); + $mollieOrder->shipAll($shipment); return true; } diff --git a/src/Service/OrderDeliveryService.php b/src/Service/OrderDeliveryService.php index 0d50472c0..fb3eaad9e 100644 --- a/src/Service/OrderDeliveryService.php +++ b/src/Service/OrderDeliveryService.php @@ -27,6 +27,7 @@ public function getDelivery(string $orderDeliveryId, Context $context): ?OrderDe { $criteria = new Criteria([$orderDeliveryId]); $criteria->addAssociation('order.transactions.paymentMethod'); + $criteria->addAssociation('shippingMethod'); $result = $this->orderDeliveryRepository->search($criteria, $context); return $result->first(); diff --git a/src/Service/TrackingInfoStructFactory.php b/src/Service/TrackingInfoStructFactory.php new file mode 100644 index 000000000..2a5158a58 --- /dev/null +++ b/src/Service/TrackingInfoStructFactory.php @@ -0,0 +1,86 @@ += 100 + */ + const MAX_TRACKING_CODE_LENGTH = 99; + + public function createFromDelivery(OrderDeliveryEntity $orderDeliveryEntity): ?ShipmentTrackingInfoStruct + { + $trackingCodes = $orderDeliveryEntity->getTrackingCodes(); + $shippingMethod = $orderDeliveryEntity->getShippingMethod(); + if ($shippingMethod === null) { + return null; + } + /** + * Currently we create one shipping in mollie for one order. one shipping object can have only one tracking code. + * When we have multiple Tracking Codes, we do not know which tracking code we should send to mollie. So we just dont send any tracking information at all + * + * https://docs.mollie.com/reference/v2/shipments-api/create-shipment + */ + if (count($trackingCodes) !== 1) { + return null; + } + + return $this->createInfoStruct((string)$shippingMethod->getName(), $trackingCodes[0], (string)$shippingMethod->getTrackingUrl()); + } + + public function create(string $trackingCarrier, string $trackingCode, string $trackingUrl): ?ShipmentTrackingInfoStruct + { + return $this->createInfoStruct($trackingCarrier, $trackingCode, $trackingUrl); + } + + private function createInfoStruct(string $trackingCarrier, string $trackingCode, string $trackingUrl): ?ShipmentTrackingInfoStruct + { + if (empty($trackingCarrier) && empty($trackingCode)) { + return null; + } + + if (empty($trackingCarrier)) { + throw new \InvalidArgumentException('Missing Argument for Tracking Carrier!'); + } + + if (empty($trackingCode)) { + throw new \InvalidArgumentException('Missing Argument for Tracking Code!'); + } + + # we just have to completely remove those codes, so that no tracking happens, but a shipping works. + # still, if we find multiple codes (because separators exist), then we use the first one only + if (mb_strlen($trackingCode) > self::MAX_TRACKING_CODE_LENGTH) { + if (strpos($trackingCode, ',') !== false) { + $trackingCode = trim(explode(',', $trackingCode)[0]); + } elseif (strpos($trackingCode, ';') !== false) { + $trackingCode = trim(explode(';', $trackingCode)[0]); + } + + # if we are still too long, then simply remove the code + if (mb_strlen($trackingCode) > self::MAX_TRACKING_CODE_LENGTH) { + return new ShipmentTrackingInfoStruct($trackingCarrier, '', ''); + } + } + + + $trackingUrl = trim(sprintf($trackingUrl, $trackingCode)); + + if (filter_var($trackingUrl, FILTER_VALIDATE_URL) === false) { + $trackingUrl = ''; + } + + /** + * following characters are not allowed in the tracking URL {,},<,>,# + */ + if (preg_match_all('/[{}<>#]/m', $trackingUrl)) { + $trackingUrl = ''; + } + + return new ShipmentTrackingInfoStruct($trackingCarrier, $trackingCode, $trackingUrl); + } +} diff --git a/src/Subscriber/ShippingSubscriber.php b/src/Subscriber/ShippingSubscriber.php deleted file mode 100644 index 0afdd4f33..000000000 --- a/src/Subscriber/ShippingSubscriber.php +++ /dev/null @@ -1,79 +0,0 @@ -shipmentFacade = $shipmentFacade; - $this->logger = $logger; - } - - public static function getSubscribedEvents() - { - return [ - MollieOrderShipmentTrackingEvent::class => 'onShipOrderWithTracking', - ]; - } - - /** - * @param MollieOrderShipmentTrackingEvent $event - */ - public function onShipOrderWithTracking(MollieOrderShipmentTrackingEvent $event): void - { - try { - $this->shipmentFacade->shipOrderByOrderId( - $event->getOrderId(), - $event->getTrackingCarrier(), - $event->getTrackingCode(), - $event->getTrackingUrl(), - $event->getContext() - ); - } catch (CouldNotExtractMollieOrderIdException $e) { - // We need to catch CouldNotExtractMollieOrderIdException, because if it's not a Mollie Order - // it obviously cannot get shipped with Mollie. We also don't have to log this, except for debugging. - // But if we don't catch it, the rest of the process might break. - $this->logger->debug($e->getMessage(), [ - 'orderId' => $event->getOrderId(), - 'trackingCarrier' => $event->getTrackingCarrier(), - 'trackingCode' => $event->getTrackingCode(), - 'trackingUrl' => $event->getTrackingUrl(), - ]); - } catch (\Exception $e) { - // We log the error, but don't rethrow so the rest of the proces can continue. - $this->logger->error( - sprintf( - "Error when shipping order from Mollie Event: \"%s\" in \"%s\" on line %s", - $e->getMessage(), - $e->getFile(), - $e->getLine() - ), - [ - 'orderId' => $event->getOrderId(), - 'trackingCarrier' => $event->getTrackingCarrier(), - 'trackingCode' => $event->getTrackingCode(), - 'trackingUrl' => $event->getTrackingUrl(), - ] - ); - } - } -} diff --git a/tests/PHPUnit/Facade/MollieShipment/CreateTrackingStructTest.php b/tests/PHPUnit/Facade/MollieShipment/CreateTrackingStructTest.php index 0664c1208..49c03c301 100644 --- a/tests/PHPUnit/Facade/MollieShipment/CreateTrackingStructTest.php +++ b/tests/PHPUnit/Facade/MollieShipment/CreateTrackingStructTest.php @@ -10,6 +10,7 @@ use Kiener\MolliePayments\Service\MolliePaymentExtractor; use Kiener\MolliePayments\Service\OrderDeliveryService; use Kiener\MolliePayments\Service\OrderService; +use Kiener\MolliePayments\Service\TrackingInfoStructFactory; use Kiener\MolliePayments\Service\Transition\DeliveryTransitionService; use Kiener\MolliePayments\Struct\MollieApi\ShipmentTrackingInfoStruct; use Mollie\Api\Resources\Shipment as ShipmentResource; @@ -71,6 +72,7 @@ public function setUp(): void 'extractDelivery' => $this->delivery ]); + $this->shipmentFacade = new MollieShipment( $this->createMock(MolliePaymentExtractor::class), $this->createMock(DeliveryTransitionService::class), @@ -79,6 +81,7 @@ public function setUp(): void $this->createMock(OrderDeliveryService::class), $this->orderService, $this->orderDataExtractor, + new TrackingInfoStructFactory(), new NullLogger(), ); @@ -120,6 +123,6 @@ public function testTrackingInfoStructWithCorrectData() $this->assertInstanceOf(ShipmentTrackingInfoStruct::class, $trackingInfoStruct); }); - $this->shipmentFacade->shipOrder($this->order, 'Mollie', '123456789', '', $this->context); + $this->shipmentFacade->shipOrder($this->order, 'Mollie', '123456789', 'https://foo.bar?code=%s', $this->context); } } diff --git a/tests/PHPUnit/Facade/MollieShipment/SetShipmentTest.php b/tests/PHPUnit/Facade/MollieShipment/SetShipmentTest.php index 3530ddde3..bef93d763 100644 --- a/tests/PHPUnit/Facade/MollieShipment/SetShipmentTest.php +++ b/tests/PHPUnit/Facade/MollieShipment/SetShipmentTest.php @@ -11,6 +11,7 @@ use Kiener\MolliePayments\Service\MolliePaymentExtractor; use Kiener\MolliePayments\Service\OrderDeliveryService; use Kiener\MolliePayments\Service\OrderService; +use Kiener\MolliePayments\Service\TrackingInfoStructFactory; use Kiener\MolliePayments\Service\Transition\DeliveryTransitionService; use Monolog\Logger; use PHPUnit\Framework\TestCase; @@ -100,6 +101,8 @@ public function setup(): void $this->createMock(CustomerService::class) ); + $trackingStructFactory = new TrackingInfoStructFactory(); + $this->mollieShipment = new MollieShipment( $this->extractor, $this->deliveryTransitionService, @@ -108,6 +111,7 @@ public function setup(): void $this->orderDeliveryService, $this->orderService, $this->orderDataExtractor, + $trackingStructFactory, $this->logger ); $this->orderNumber = 'fooOrderNumber'; @@ -188,7 +192,7 @@ public function testThatOrderDeliveryCustomFieldsAreNotWrittenWhenApiCallUnsucce $deliveryId = $delivery->getId(); $this->orderDeliveryService->method('getDelivery')->willReturn($delivery); $this->mollieApiOrderService->method('setShipment') - ->with($mollieOrderId, $salesChannelId) + ->with($mollieOrderId, null, $salesChannelId) ->willReturn(false); // custom fields for shipping are never written @@ -201,6 +205,7 @@ public function testThatOrderDeliveryCustomFieldsAreNotWrittenWhenApiCallUnsucce public function testThatOrderDeliveryCustomFieldsAreWrittenWhenApiCallSuccessful(): void { $transaction = $this->createTransaction('Kiener\MolliePayments\Handler\Method\FooMethod'); + $order = $this->createOrder($transaction); $mollieOrderId = 'foo'; $customFields[CustomFieldsInterface::MOLLIE_KEY][CustomFieldsInterface::ORDER_KEY] = $mollieOrderId; @@ -211,10 +216,11 @@ public function testThatOrderDeliveryCustomFieldsAreWrittenWhenApiCallSuccessful $order->setSalesChannel($salesChannel); $order->setSalesChannelId($salesChannelId); $delivery = $this->createDelivery($order); + $deliveryId = $delivery->getId(); $this->orderDeliveryService->method('getDelivery')->willReturn($delivery); $this->mollieApiOrderService->method('setShipment') - ->with($mollieOrderId, $salesChannelId) + ->with($mollieOrderId, null,$salesChannelId) ->willReturn(true); // custom fields for shipping are written @@ -236,7 +242,7 @@ private function createDelivery(?OrderEntity $order): OrderDeliveryEntity { $delivery = new OrderDeliveryEntity(); $delivery->setId(Uuid::randomHex()); - + $delivery->setTrackingCodes([]); if ($order instanceof OrderEntity) { $delivery->setOrder($order); } diff --git a/tests/PHPUnit/Service/TrackingInfoStructFactoryTest.php b/tests/PHPUnit/Service/TrackingInfoStructFactoryTest.php new file mode 100644 index 000000000..b747f326a --- /dev/null +++ b/tests/PHPUnit/Service/TrackingInfoStructFactoryTest.php @@ -0,0 +1,170 @@ +factory = new TrackingInfoStructFactory(); + } + + + public function testInfoStructCreatedByDelivery(): void + { + $expectedCode = '1234'; + $expectedCarrier = 'Test carrier'; + $expectedUrl = 'https://test.foo?code=1234'; + $deliveryEntity = new OrderDeliveryEntity(); + $deliveryEntity->setUniqueIdentifier('testDelivery'); + $deliveryEntity->setTrackingCodes([ + $expectedCode + ]); + + $shippingMethod = new ShippingMethodEntity(); + $shippingMethod->setName($expectedCarrier); + $shippingMethod->setUniqueIdentifier('testShippingMethod'); + $shippingMethod->setTrackingUrl('https://test.foo?code=%s'); + + $deliveryEntity->setShippingMethod($shippingMethod); + $trackingInfoStruct = $this->factory->createFromDelivery($deliveryEntity); + + $this->assertNotNull($trackingInfoStruct); + $this->assertSame($expectedCode, $trackingInfoStruct->getCode()); + $this->assertSame($expectedUrl, $trackingInfoStruct->getUrl()); + $this->assertSame($expectedCarrier, $trackingInfoStruct->getCarrier()); + } + + public function testOnlyOneCodeAccepted(): void + { + + $deliveryEntity = new OrderDeliveryEntity(); + $deliveryEntity->setUniqueIdentifier('testDelivery'); + $deliveryEntity->setTrackingCodes([ + '1234', + 'test' + ]); + + $shippingMethod = new ShippingMethodEntity(); + $shippingMethod->setName('Test carrier'); + $shippingMethod->setUniqueIdentifier('testShippingMethod'); + $shippingMethod->setTrackingUrl('https://test.foo?code=%s'); + + $deliveryEntity->setShippingMethod($shippingMethod); + $trackingInfoStruct = $this->factory->createFromDelivery($deliveryEntity); + + $this->assertNull($trackingInfoStruct); + } + + public function testInfoStructCreatedByArguments(): void + { + $expectedCode = '1234'; + $expectedCarrier = 'Test carrier'; + $trackingInfoStruct = $this->factory->create($expectedCarrier, $expectedCode, 'https://test.foo?code=%s'); + $expectedUrl = 'https://test.foo?code=1234'; + + $this->assertNotNull($trackingInfoStruct); + $this->assertSame($expectedCode, $trackingInfoStruct->getCode()); + $this->assertSame($expectedUrl, $trackingInfoStruct->getUrl()); + $this->assertSame($expectedCarrier, $trackingInfoStruct->getCarrier()); + + } + + public function testUrlWithCodeIsInvalid(): void + { + $expectedCode = '/123 4%foo=bar?test'; + $expectedCarrier = 'Test carrier'; + $trackingInfoStruct = $this->factory->create($expectedCarrier, $expectedCode, 'https://test.foo?code=%s'); + $expectedUrl = ''; + + $this->assertNotNull($trackingInfoStruct); + $this->assertSame($expectedCode, $trackingInfoStruct->getCode()); + $this->assertSame($expectedUrl, $trackingInfoStruct->getUrl()); + $this->assertSame($expectedCarrier, $trackingInfoStruct->getCarrier()); + } + + public function testInfoStructWithCommaSeparator(): void + { + $expectedCode = '1234'; + $givenCode = $expectedCode . ',' . str_repeat('-', 100); + $expectedCarrier = 'Test carrier'; + $trackingInfoStruct = $this->factory->create($expectedCarrier, $givenCode, 'https://test.foo?code=%s'); + $expectedUrl = 'https://test.foo?code=1234'; + + $this->assertNotNull($trackingInfoStruct); + $this->assertSame($expectedCode, $trackingInfoStruct->getCode()); + $this->assertSame($expectedUrl, $trackingInfoStruct->getUrl()); + $this->assertSame($expectedCarrier, $trackingInfoStruct->getCarrier()); + } + + public function testInfoStructWithSemicolonSeparator(): void + { + $expectedCode = '1234'; + $givenCode = $expectedCode . ';' . str_repeat('-', 100); + $expectedCarrier = 'Test carrier'; + $trackingInfoStruct = $this->factory->create($expectedCarrier, $givenCode, 'https://test.foo?code=%s'); + $expectedUrl = 'https://test.foo?code=1234'; + + $this->assertNotNull($trackingInfoStruct); + $this->assertSame($expectedCode, $trackingInfoStruct->getCode()); + $this->assertSame($expectedUrl, $trackingInfoStruct->getUrl()); + $this->assertSame($expectedCarrier, $trackingInfoStruct->getCarrier()); + } + + public function testCommaSeparatorHasHigherPriority(): void + { + $expectedCode = '1234'; + $givenCode = $expectedCode . ',5678;' . str_repeat('-', 100); + $expectedCarrier = 'Test carrier'; + $trackingInfoStruct = $this->factory->create($expectedCarrier, $givenCode, 'https://test.foo?code=%s'); + $expectedUrl = 'https://test.foo?code=1234'; + + $this->assertNotNull($trackingInfoStruct); + $this->assertSame($expectedCode, $trackingInfoStruct->getCode()); + $this->assertSame($expectedUrl, $trackingInfoStruct->getUrl()); + $this->assertSame($expectedCarrier, $trackingInfoStruct->getCarrier()); + } + + /** + * @dataProvider invalidCodes + * @param string $url + * @param string $trackingCode + * @return void + */ + public function testInvalidTrackingCodeCharacter(string $trackingCode): void + { + + $trackingInfoStruct = $this->factory->create('test', $trackingCode, 'https://foo.bar/%s'); + $expected = ''; + + $this->assertSame($expected, $trackingInfoStruct->getUrl()); + + } + + public function invalidCodes(): array + { + return [ + ['some{code'], + ['some}code'], + ['somecode'], + ['some#code'], + ['some#<>{},' . str_repeat('1', 200)], + [str_repeat('1', 200)], + ]; + } +} \ No newline at end of file