Skip to content

Commit

Permalink
Add allowed shipment templates to the shipping method. This makes it …
Browse files Browse the repository at this point in the history
…more reliable to map shipping methods to shipment templates
  • Loading branch information
loevgaard committed Apr 19, 2024
1 parent 43b247d commit e0978fd
Show file tree
Hide file tree
Showing 10 changed files with 285 additions and 16 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,33 @@ class PaymentMethod extends BasePaymentMethod implements ShipmondoPaymentMethodI
}
```

#### `PaymentMethod` entity

```php
<?php
# src/Entity/Shipping/ShippingMethod.php
declare(strict_types=1);
namespace App\Entity\Shipping;
use Doctrine\ORM\Mapping as ORM;
use Setono\SyliusShipmondoPlugin\Model\ShippingMethodInterface as ShipmondoShippingMethodInterface;
use Setono\SyliusShipmondoPlugin\Model\ShippingMethodTrait as ShipmondoShippingMethodTrait;
use Sylius\Component\Core\Model\ShippingMethod as BaseShippingMethod;
/**
* @ORM\Entity
*
* @ORM\Table(name="sylius_shipping_method")
*/
class ShippingMethod extends BaseShippingMethod implements ShipmondoShippingMethodInterface
{
use ShipmondoShippingMethodTrait;
}
```

### Update your database:

```bash
Expand Down
68 changes: 60 additions & 8 deletions src/Controller/Admin/ShipmondoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
use Setono\Shipmondo\Client\Client;
use Setono\Shipmondo\Client\Endpoint\Endpoint;
use Setono\Shipmondo\Response\PaymentGateways\PaymentGateway;
use Setono\Shipmondo\Response\ShipmentTemplates\ShipmentTemplate;
use Setono\SyliusShipmondoPlugin\Message\Command\RegisterWebhooks;
use Setono\SyliusShipmondoPlugin\Model\PaymentMethodInterface;
use Setono\SyliusShipmondoPlugin\Model\ShippingMethodInterface;
use Setono\SyliusShipmondoPlugin\Registrar\WebhookRegistrarInterface;
use Setono\SyliusShipmondoPlugin\Repository\RegisteredWebhooksRepositoryInterface;
use Sylius\Component\Core\Repository\PaymentMethodRepositoryInterface;
use Sylius\Component\Core\Repository\ShippingMethodRepositoryInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -26,6 +29,7 @@ public function __construct(
private readonly MessageBusInterface $commandBus,
private readonly WebhookRegistrarInterface $webhookRegistrar,
private readonly PaymentMethodRepositoryInterface $paymentMethodRepository,
private readonly ShippingMethodRepositoryInterface $shippingMethodRepository,
private readonly Client $client,
) {
}
Expand All @@ -35,6 +39,9 @@ public function index(Request $request): Response
/** @var list<PaymentMethodInterface> $paymentMethods */
$paymentMethods = $this->paymentMethodRepository->findAll();

/** @var list<ShippingMethodInterface> $shippingMethods */
$shippingMethods = $this->shippingMethodRepository->findAll();

/**
* @var list<PaymentGateway> $shipmondoPaymentMethods
*/
Expand All @@ -46,13 +53,24 @@ public function index(Request $request): Response
}
}

/**
* @var list<ShipmentTemplate> $shipmondoShipmentTemplates
*/
$shipmondoShipmentTemplates = [];

foreach (Endpoint::paginate($this->client->shipmentTemplates()->get(...)) as $collection) {
foreach ($collection as $item) {
$shipmondoShipmentTemplates[] = $item;
}
}

// todo this should be made using Symfony forms
if ($request->isMethod('POST') && $request->request->has('payment_methods')) {
/**
* Example of posted array (the key is Sylius payment method id, they value is Shipmondo payment method id):
* Example of posted array (the key is a Sylius payment method id, the value is a Shipmondo payment method id):
*
* [
* 1 => "1"
* 1 => "1",
* 2 => ""
* ]
*
Expand All @@ -64,21 +82,55 @@ public function index(Request $request): Response
continue;
}

/** @var PaymentMethodInterface|null $paymentMethod */
$paymentMethod = $this->paymentMethodRepository->find($paymentMethodId);
if (null === $paymentMethod) {
/** @var PaymentMethodInterface|null $shippingMethod */
$shippingMethod = $this->paymentMethodRepository->find($paymentMethodId);
if (null === $shippingMethod) {
continue;
}

Assert::isInstanceOf($shippingMethod, PaymentMethodInterface::class);
$shippingMethod->setShipmondoId((int) $shipmondoPaymentMethodId);
$this->paymentMethodRepository->add($shippingMethod);
}
}

// todo this should be made using Symfony forms
if ($request->isMethod('POST') && $request->request->has('shipping_methods')) {
/**
* Example of posted array (the key is a Sylius shipping method id, the value is an array of Shipmondo shipment template ids):
*
* [
* 1 => [
* 0 => "664116",
* 1 => "664115"
* ],
* 2 => [
* 0 => "664114",
* 1 => "664112"
* ]
* ]
*
* @var array<int, list<string>> $postedShippingMethods
*/
$postedShippingMethods = $request->request->all('shipping_methods');
foreach ($postedShippingMethods as $shippingMethodId => $shipmondoShipmentTemplateIds) {
/** @var ShippingMethodInterface|null $shippingMethod */
$shippingMethod = $this->shippingMethodRepository->find($shippingMethodId);
if (null === $shippingMethod) {
continue;
}

Assert::isInstanceOf($paymentMethod, PaymentMethodInterface::class);
$paymentMethod->setShipmondoId((int) $shipmondoPaymentMethodId);
$this->paymentMethodRepository->add($paymentMethod);
Assert::isInstanceOf($shippingMethod, ShippingMethodInterface::class);
$shippingMethod->setAllowedShipmentTemplates($shipmondoShipmentTemplateIds);
$this->shippingMethodRepository->add($shippingMethod);
}
}

return $this->render('@SetonoSyliusShipmondoPlugin/admin/shipmondo/index.html.twig', [
'paymentMethods' => $paymentMethods,
'shippingMethods' => $shippingMethods,
'shipmondoPaymentMethods' => $shipmondoPaymentMethods,
'shipmondoShipmentTemplates' => $shipmondoShipmentTemplates,
'registeredWebhooks' => $this->registeredWebhooksRepository->findOneByVersion($this->webhookRegistrar->getVersion()),
]);
}
Expand Down
29 changes: 25 additions & 4 deletions src/DataMapper/ShipmentTemplateSalesOrderDataMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
use Setono\Shipmondo\Request\SalesOrders\SalesOrder;
use Setono\Shipmondo\Resolver\Shipment;
use Setono\Shipmondo\Resolver\ShipmentTemplateResolver;
use Setono\Shipmondo\Resolver\SimilarTextBasedShipmentsResemblanceChecker;
use Setono\Shipmondo\Response\ShipmentTemplates\ShipmentTemplate;
use Setono\SyliusShipmondoPlugin\Model\OrderInterface;
use Setono\SyliusShipmondoPlugin\Model\ShippingMethodInterface;

final class ShipmentTemplateSalesOrderDataMapper implements SalesOrderDataMapperInterface
{
Expand All @@ -26,29 +26,50 @@ public function map(OrderInterface $order, SalesOrder $salesOrder): void
return;
}

$shippingMethodName = self::getShippingMethodName($order);
$shipment = $order->getShipments()->first();
if (false === $shipment) {
return;
}

$shippingMethod = $shipment->getMethod();
if (!$shippingMethod instanceof ShippingMethodInterface) {
return;
}

$shippingMethodName = $shippingMethod->getName();
if (null === $shippingMethodName) {
return;
}

$allowedShipmentTemplates = $shippingMethod->getAllowedShipmentTemplates();

/** @var list<ShipmentTemplate> $shipmentTemplates */
$shipmentTemplates = [];

foreach (Endpoint::paginate($this->client->shipmentTemplates()->get(...)) as $collection) {
/** @var ShipmentTemplate $shipmentTemplate */
foreach ($collection as $shipmentTemplate) {
if (!in_array($shipmentTemplate->id, $allowedShipmentTemplates, true)) {
continue;
}

$shipmentTemplates[] = $shipmentTemplate;
}
}

if ([] === $shipmentTemplates) {
return;
}

$shipment = new Shipment(
$shippingMethodName,
'DK',
$receiverCountry,
self::getWeight($order),
);

$resolver = new ShipmentTemplateResolver(new SimilarTextBasedShipmentsResemblanceChecker(10));
// todo this should be a service
$resolver = new ShipmentTemplateResolver();
$shipmentTemplate = $resolver->resolve($shipment, $shipmentTemplates);

$salesOrder->shipmentTemplateId = $shipmentTemplate?->id;
Expand All @@ -72,7 +93,7 @@ private static function getWeight(OrderInterface $order): int

private static function getShippingMethodName(OrderInterface $order): ?string
{
$shipment = $order->getshipments()->first();
$shipment = $order->getShipments()->first();
if (false === $shipment) {
return null;
}
Expand Down
27 changes: 27 additions & 0 deletions src/Model/ShippingMethodInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusShipmondoPlugin\Model;

use Setono\Shipmondo\Response\ShipmentTemplates\ShipmentTemplate;
use Sylius\Component\Core\Model\ShippingMethodInterface as BaseShippingMethodInterface;

interface ShippingMethodInterface extends BaseShippingMethodInterface
{
/**
* Returns a list Shipmondo shipment template ids that are allowed for this shipping method
*
* @return list<int>
*/
public function getAllowedShipmentTemplates(): array;

/**
* @param list<string|int|ShipmentTemplate> $allowedShipmentTemplates
*/
public function setAllowedShipmentTemplates(?array $allowedShipmentTemplates): void;

public function addAllowedShipmentTemplate(int|ShipmentTemplate $shipmentTemplate): void;

public function hasAllowedShipmentTemplate(int|ShipmentTemplate $shipmentTemplate): bool;
}
61 changes: 61 additions & 0 deletions src/Model/ShippingMethodTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusShipmondoPlugin\Model;

use Doctrine\ORM\Mapping as ORM;
use Setono\Shipmondo\Response\ShipmentTemplates\ShipmentTemplate;

trait ShippingMethodTrait
{
/**
* @var list<int>
*
* @ORM\Column(type="json", nullable=true)
*/
#[ORM\Column(type: 'json', nullable: true)]
protected ?array $allowedShipmentTemplates = [];

public function getAllowedShipmentTemplates(): array
{
return $this->allowedShipmentTemplates ?? [];
}

public function setAllowedShipmentTemplates(?array $allowedShipmentTemplates): void
{
$this->allowedShipmentTemplates = null;

if (null === $allowedShipmentTemplates) {
return;
}

foreach ($allowedShipmentTemplates as $allowedShipmentTemplate) {
$this->addAllowedShipmentTemplate($allowedShipmentTemplate instanceof ShipmentTemplate ? $allowedShipmentTemplate->id : (int) $allowedShipmentTemplate);
}
}

public function addAllowedShipmentTemplate(int|ShipmentTemplate $shipmentTemplate): void
{
if (null === $this->allowedShipmentTemplates) {
$this->allowedShipmentTemplates = [];
}

$id = $shipmentTemplate instanceof ShipmentTemplate ? $shipmentTemplate->id : $shipmentTemplate;

if ($this->hasAllowedShipmentTemplate($id)) {
return;
}

$this->allowedShipmentTemplates[] = $id;
}

public function hasAllowedShipmentTemplate(int|ShipmentTemplate $shipmentTemplate): bool
{
if (null === $this->allowedShipmentTemplates) {
return false;
}

return in_array($shipmentTemplate instanceof ShipmentTemplate ? $shipmentTemplate->id : $shipmentTemplate, $this->allowedShipmentTemplates, true);
}
}
1 change: 1 addition & 0 deletions src/Resources/config/services/controller.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<argument type="service" id="setono_sylius_shipmondo.command_bus"/>
<argument type="service" id="setono_sylius_shipmondo.registrar.webhook"/>
<argument type="service" id="sylius.repository.payment_method"/>
<argument type="service" id="sylius.repository.shipping_method"/>
<argument type="service" id="setono_sylius_shipmondo.client"/>

<call method="setContainer">
Expand Down
4 changes: 4 additions & 0 deletions src/Resources/translations/messages.en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ setono_sylius_shipmondo:
uploading_to_shipmondo: Uploading to Shipmondo
webhooks: Webhooks
webhooks_registered_information: Webhooks were registered on %date%.
shipping_method_in_sylius: Shipping method in Sylius
shipment_templates_in_shipmondo: Shipment templates in Shipmondo
map_shipping_methods: Map shipping methods
map_shipping_methods_information: Map your shipping methods to the shipment templates in Shipmondo. This way, shipments inside Shipmondo will have a shipment template assigned automatically. If there's no relevant shipment template in Shipmondo, leave it empty.
50 changes: 50 additions & 0 deletions src/Resources/views/admin/shipmondo/index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,54 @@
</div>
</div>
</div>
<div class="ui grid">
<div class="sixteen wide column">
<div class="ui segment">
<h4 class="ui header">{{ 'setono_sylius_shipmondo.ui.map_shipping_methods'|trans }}</h4>

{% if shipmondoShipmentTemplates|length > 0 %}
<form method="post">
<p>{{ 'setono_sylius_shipmondo.ui.map_shipping_methods_information'|trans|raw }}</p>
<table class="ui single line celled table">
<thead>
<tr>
<th>{{ 'setono_sylius_shipmondo.ui.shipping_method_in_sylius'|trans }}</th>
<th>{{ 'setono_sylius_shipmondo.ui.shipment_templates_in_shipmondo'|trans }}</th>
</tr>
</thead>
<tbody>
{% for shippingMethod in shippingMethods %}
<tr>
<td>{{ shippingMethod.name }}</td>
<td>
<select name="shipping_methods[{{ shippingMethod.id }}][]" class="ui fluid search dropdown" multiple>
{% for shipmondoShipmentTemplate in shipmondoShipmentTemplates %}
<option value="{{ shipmondoShipmentTemplate.id }}" {% if shippingMethod.hasAllowedShipmentTemplate(shipmondoShipmentTemplate) %}selected{% endif %}>{{ shipmondoShipmentTemplate.name }}</option>
{% endfor %}
</select>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit" class="ui primary button">{{ 'sylius.ui.save_changes'|trans }}</button>
</form>
{% else %}
<p>{{ 'setono_sylius_shipmondo.ui.map_shipping_methods_empty_information'|trans|raw }}</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}

{% block javascripts %}
{{ parent() }}
<script>
$(() => {
$('.ui.dropdown').dropdown({
fullTextSearch: true,
match: 'text'
});
});
</script>
{% endblock %}
Loading

0 comments on commit e0978fd

Please sign in to comment.