Skip to content

Commit

Permalink
Add pickup point functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
loevgaard committed May 8, 2024
1 parent 341e6ef commit 736d3eb
Show file tree
Hide file tree
Showing 22 changed files with 531 additions and 5 deletions.
5 changes: 1 addition & 4 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ indent_size = 2
[*.md]
trim_trailing_whitespace = false

[*.sh]
indent_style = tab

[*.{yaml,yml}]
trim_trailing_whitespace = false

[{webpack.config.js,.eslintrc.js}]
[*.js]
indent_size = 2
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class PaymentMethod extends BasePaymentMethod implements ShipmondoPaymentMethodI
}
```

#### `PaymentMethod` entity
#### `ShippingMethod` entity

```php
<?php
Expand All @@ -161,6 +161,33 @@ class ShippingMethod extends BaseShippingMethod implements ShipmondoShippingMeth
}
```

#### `Shipment` entity

```php
<?php
# src/Entity/Shipping/Shipment.php
declare(strict_types=1);
namespace App\Entity\Shipping;
use Doctrine\ORM\Mapping as ORM;
use Setono\SyliusShipmondoPlugin\Model\ShipmentInterface as ShipmondoShipmentInterface;
use Setono\SyliusShipmondoPlugin\Model\ShipmentTrait as ShipmondoShipmentTrait;
use Sylius\Component\Core\Model\Shipment as BaseShipment;
/**
* @ORM\Entity
*
* @ORM\Table(name="sylius_shipment")
*/
class Shipment extends BaseShipment implements ShipmondoShipmentInterface
{
use ShipmondoShipmentTrait;
}
```

### Update your database:

```bash
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"symfony/remote-event": "^6.4",
"symfony/routing": "^6.4",
"symfony/string": "^6.4",
"symfony/validator": "^6.4",
"symfony/webhook": "^6.4",
"symfony/workflow": "^6.4",
"twig/twig": "^2.16 || ^3.8",
Expand Down
121 changes: 121 additions & 0 deletions src/Controller/Shop/GetPickupPointsAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusShipmondoPlugin\Controller\Shop;

use Setono\Shipmondo\Client\ClientInterface;
use Setono\Shipmondo\Request\PickupPoints\PickupPointsCollectionQuery;
use Setono\Shipmondo\Response\PickupPoints\PickupPoint;
use Setono\SyliusShipmondoPlugin\Model\OrderInterface;
use Setono\SyliusShipmondoPlugin\Model\ShipmentInterface;
use Setono\SyliusShipmondoPlugin\Model\ShippingMethodInterface;
use Sylius\Component\Core\Repository\ShippingMethodRepositoryInterface;
use Sylius\Component\Order\Context\CartContextInterface;
use Sylius\Component\Order\Context\CartNotFoundException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;
use Webmozart\Assert\Assert;

final class GetPickupPointsAction
{
public function __construct(
private readonly ShippingMethodRepositoryInterface $shippingMethodRepository,
private readonly CartContextInterface $cartContext,
private readonly ClientInterface $client,
private readonly Environment $twig,
) {
}

public function __invoke(Request $request): Response
{
$shippingMethodCode = $request->query->getString('shippingMethod');

if ('' === $shippingMethodCode) {
return new JsonResponse(status: Response::HTTP_BAD_REQUEST);
}

$shippingMethod = $this->shippingMethodRepository->findOneBy([
'code' => $shippingMethodCode,
'enabled' => true,
]);

if (!$shippingMethod instanceof ShippingMethodInterface) {
return new JsonResponse(status: Response::HTTP_BAD_REQUEST);
}

try {
$order = $this->cartContext->getCart();
} catch (CartNotFoundException) {
return new JsonResponse(status: Response::HTTP_BAD_REQUEST);
}

if (!$order instanceof OrderInterface) {
return new JsonResponse(status: Response::HTTP_BAD_REQUEST);
}

$shippingAddress = $order->getShippingAddress();
if (null === $shippingAddress) {
return new JsonResponse(status: Response::HTTP_BAD_REQUEST);
}

try {
$pickupPoints = $this->client->pickupPoints()->get(new PickupPointsCollectionQuery(
carrierCode: (string) $shippingMethod->getCarrierCode(),
countryCode: (string) $shippingAddress->getCountryCode(),
zipCode: (string) $shippingAddress->getPostcode(),
address: (string) $shippingAddress->getStreet(),
))->items;
} catch (\InvalidArgumentException) {
return new JsonResponse(status: Response::HTTP_BAD_REQUEST);
}

// The customer might already have chosen a pickup point,
// so we need to check if the shipment has a chosen pickup point and put that pickup point at the top of the list
$chosenPickupPoint = self::resolveChosenPickupPoint($order);

usort($pickupPoints, static function (PickupPoint $a, PickupPoint $b) use ($chosenPickupPoint) {
if ($a->id === $chosenPickupPoint) {
return -1;
}

if ($b->id === $chosenPickupPoint) {
return 1;
}

return 0;
});

return new JsonResponse([
'pickupPoints' => $pickupPoints,
'html' => $this->twig->render('@SetonoSyliusShipmondoPlugin/shop/ajax/pickup_points.html.twig', [
'pickupPoints' => $pickupPoints,
]),
]);
}

/**
* Will return the id of the chosen pickup point if the shipment has one
*
* todo this only works if the order has _one_ shipment
*/
private static function resolveChosenPickupPoint(OrderInterface $order): ?string
{
$shipment = $order->getShipments()->first();
if (!$shipment instanceof ShipmentInterface) {
return null;
}

$pickupPoint = $shipment->getShipmondoPickupPoint();
if (null === $pickupPoint) {
return null;
}

$id = $pickupPoint['id'] ?? null;
Assert::nullOrString($id);

return $id;
}
}
7 changes: 7 additions & 0 deletions src/DependencyInjection/SetonoSyliusShipmondoExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ public function prepend(ContainerBuilder $container): void
],
],
],
'sylius.shop.layout.javascripts' => [
'blocks' => [
'javascripts' => [
'template' => '@SetonoSyliusShipmondoPlugin/shop/_javascripts.html.twig',
],
],
],
],
]);
}
Expand Down
50 changes: 50 additions & 0 deletions src/Form/Extension/ShipmentTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusShipmondoPlugin\Form\Extension;

use Setono\SyliusShipmondoPlugin\Model\ShipmentInterface;
use Sylius\Bundle\CoreBundle\Form\Type\Checkout\ShipmentType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;

/**
* @extends AbstractTypeExtension<ShipmentInterface>
*/
final class ShipmentTypeExtension extends AbstractTypeExtension
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('shipmondoPickupPoint', HiddenType::class);
$builder->get('shipmondoPickupPoint')->addModelTransformer(new CallbackTransformer(
function (?array $pickupPoint): ?string {
if (null === $pickupPoint) {
return null;
}

return json_encode($pickupPoint, \JSON_THROW_ON_ERROR);
},
function (?string $json): ?array {
if (null === $json) {
return null;
}

$data = json_decode($json, true, 512, \JSON_THROW_ON_ERROR);

if (!is_array($data)) {
return null;
}

return $data;
},
));
}

public static function getExtendedTypes(): iterable
{
yield ShipmentType::class;
}
}
14 changes: 14 additions & 0 deletions src/Model/ShipmentInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusShipmondoPlugin\Model;

use Sylius\Component\Core\Model\ShipmentInterface as BaseShipmentInterface;

interface ShipmentInterface extends BaseShipmentInterface
{
public function setShipmondoPickupPoint(?array $shipmondoPickupPoint): void;

public function getShipmondoPickupPoint(): ?array;
}
23 changes: 23 additions & 0 deletions src/Model/ShipmentTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusShipmondoPlugin\Model;

use Doctrine\ORM\Mapping as ORM;

trait ShipmentTrait
{
/** @ORM\Column(type="json", nullable=true) */
protected ?array $shipmondoPickupPoint = null;

public function setShipmondoPickupPoint(?array $shipmondoPickupPoint): void
{
$this->shipmondoPickupPoint = $shipmondoPickupPoint;
}

public function getShipmondoPickupPoint(): ?array
{
return $this->shipmondoPickupPoint;
}
}
6 changes: 6 additions & 0 deletions src/Resources/config/routes.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
setono_sylius_shipmondo_global:
resource: "@SetonoSyliusShipmondoPlugin/Resources/config/routes/global.yaml"

setono_sylius_shipmondo_shop:
resource: "@SetonoSyliusShipmondoPlugin/Resources/config/routes/shop.yaml"
prefix: /{_locale}
requirements:
_locale: ^[A-Za-z]{2,4}(_([A-Za-z]{4}|[0-9]{3}))?(_([A-Za-z]{2}|[0-9]{3}))?$

setono_sylius_shipmondo_admin:
resource: "@SetonoSyliusShipmondoPlugin/Resources/config/routes/admin.yaml"
prefix: /admin
5 changes: 5 additions & 0 deletions src/Resources/config/routes/shop.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
setono_sylius_shipmondo_shop_ajax_get_pickup_points:
path: /ajax/get-pickup-points
methods: [GET]
defaults:
_controller: setono_sylius_shipmondo.controller.shop.get_pickup_points
3 changes: 3 additions & 0 deletions src/Resources/config/routes_no_locale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

setono_sylius_shipmondo_global:
resource: "@SetonoSyliusShipmondoPlugin/Resources/config/routes/global.yaml"

setono_sylius_shipmondo_shop:
resource: "@SetonoSyliusShipmondoPlugin/Resources/config/routes/shop.yaml"

setono_sylius_shipmondo_admin:
resource: "@SetonoSyliusShipmondoPlugin/Resources/config/routes/admin.yaml"
Expand Down
1 change: 1 addition & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<import resource="services/message.xml"/>
<import resource="services/provider.xml"/>
<import resource="services/registrar.xml"/>
<import resource="services/twig.xml"/>
<import resource="services/uploader.xml"/>
<import resource="services/webhook.xml"/>
</imports>
Expand Down
8 changes: 8 additions & 0 deletions src/Resources/config/services/controller.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,13 @@

<tag name="controller.service_arguments"/>
</service>

<service id="setono_sylius_shipmondo.controller.shop.get_pickup_points"
class="Setono\SyliusShipmondoPlugin\Controller\Shop\GetPickupPointsAction" public="true">
<argument type="service" id="sylius.repository.shipping_method"/>
<argument type="service" id="sylius.context.cart"/>
<argument type="service" id="setono_sylius_shipmondo.client"/>
<argument type="service" id="twig"/>
</service>
</services>
</container>
5 changes: 5 additions & 0 deletions src/Resources/config/services/form.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@
class="Setono\SyliusShipmondoPlugin\Form\Extension\ShippingMethodTypeExtension">
<tag name="form.type_extension"/>
</service>

<service id="setono_sylius_shipmondo.form.type_extension.shipment"
class="Setono\SyliusShipmondoPlugin\Form\Extension\ShipmentTypeExtension">
<tag name="form.type_extension"/>
</service>
</services>
</container>
17 changes: 17 additions & 0 deletions src/Resources/config/services/twig.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="setono_sylius_shipmondo.twig.extension"
class="Setono\SyliusShipmondoPlugin\Twig\Extension">
<tag name="twig.extension"/>
</service>

<service id="setono_sylius_shipmondo.twig.runtime"
class="Setono\SyliusShipmondoPlugin\Twig\Runtime">
<argument type="service" id="sylius.repository.shipping_method"/>

<tag name="twig.runtime"/>
</service>
</services>
</container>
Loading

0 comments on commit 736d3eb

Please sign in to comment.