<?php
namespace App\EventSubscriber\Shipping;
use App\Ecommerce\Model\Order;
use App\Model\Customer;
use App\Model\Product;
use App\Repository\OrderRepository;
use Factory\CartBundle\Classes\Traits\Controller\GetCartTrait;
use Factory\ShippingBundle\Classes\Carrier\DeAddress;
use Factory\ShippingBundle\Classes\Carrier\SimplePackage;
use Factory\ShippingBundle\Classes\Carrier\UsAddress;
use Factory\ShippingBundle\Classes\ShippingEvents;
use Factory\ShippingBundle\Contract\Carrier\AddressContract;
use Factory\ShippingBundle\Contract\Carrier\PackageContract;
use Factory\ShippingBundle\Event\ShippingEvent;
use Pimcore;
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Pimcore\Model\DataObject\Data\QuantityValue;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Pimcore\Model\WebsiteSetting;
class CsrCarrierRatesSubscriber implements EventSubscriberInterface
{
use GetCartTrait;
/**
* @var RequestStack
*/
protected $requestStack;
/**
* @var OrderRepository
*/
protected $orderRepository;
public static function getSubscribedEvents()
{
return [
ShippingEvents::GET_SINGLE_CARRIER_RATES_BEFORE => [
['updatePackageAndAddress', 10]
]
];
}
public function __construct(RequestStack $requestStack, OrderRepository $orderRepository)
{
$this->requestStack = $requestStack;
$this->orderRepository = $orderRepository;
}
/**
* This method is used by GetCartTrait
*
* @param string $serviceName
*
* @return object
*/
protected function get(string $serviceName)
{
return Pimcore::getContainer()->get($serviceName);
}
/**
* @return null|Customer
*/
protected function getUser()
{
$order = $this->getOrderFromReferer();
if ($order && $order->getCustomer()) {
return $order->getCustomer();
}
return null;
}
public function updatePackageAndAddress(ShippingEvent $event)
{
if (!$this->getUser()) {
return;
}
$event->setArgument(
'package',
$this->getPackage($event->getArgument('package'), $event)
);
$event->setArgument(
'sourceAddress',
$this->getSourceAddress($event->getArgument('sourceAddress'), $event,'default')
);
$event->setArgument(
'destinationAddress',
$this->getDestinationAddress($event->getArgument('destinationAddress'), $event)
);
$event->setArgument(
'options',
$this->getOptions($event->getArgument('options'), $event)
);
}
protected function getPackage(PackageContract $package, ShippingEvent $event)
{
$weights = [];
foreach ($this->getPackageItems() as $item) {
$weights[] = [
'weight' => $item->getProduct()->getWeight(),
'quantity' => $item->getCount()
];
}
$package->setWeight($this->addQuantityValues($weights,'lb'));
return $package;
}
protected function getSourceAddress(AddressContract $sourceAddress, ShippingEvent $event, string $destRegion = 'default')
{
if ($setting = WebsiteSetting::getByName($destRegion.'_storage_city')) {
$sourceAddress->setCity($setting->getData() ?? '');
}
if ($setting = WebsiteSetting::getByName($destRegion.'_storage_zip_code')) {
$sourceAddress->setZipCode($setting->getData() ?? '');
}
if ($setting = WebsiteSetting::getByName($destRegion.'_storage_country')) {
$sourceAddress->setCountryCode($setting->getData() ?? '');
}
return $sourceAddress;
}
protected function getDestinationAddress(AddressContract $destinationAddress, ShippingEvent $event)
{
$address = $this->getAddress();
$destinationAddress->setCity($address->getCity());
$destinationAddress->setZipCode($address->getZipCode());
$destinationAddress->setCountryCode($address->getCountry());
$destinationAddress->setState($address->getState());
return $destinationAddress;
}
protected function getOptions(array $options, ShippingEvent $event)
{
return [];
}
protected function getAddress()
{
if ($this->isCsrOrdering()) {
$addressId = 'delivery';
} else {
$addressId = $this->getRequest()->cookies->get('__shipping_address_id');
}
$address = $this->getUser()->getDefaultShippingAddressObject();
if ($addressId == 'delivery') {
$address = $this->getAddressFromOrder();
} else {
$address = $this->getUser()->getAddress($addressId);
}
if (!$address) {
throw new \Exception("Customer must have default shipping address!");
}
return $address;
}
protected function getAddressFromOrder()
{
$order = $this->getOrderFromReferer();
if (!$order) {
return null;
}
return $this->orderRepository->createAddressFromOrder('delivery', $order);
}
protected function getOrderFromReferer()
{
if ($this->isCsrOrdering()) {
return Order::getById($this->getRequest()->get('order'));
}
return null;
}
/**
* @param array $values
*
* @return QuantityValue
*/
private function addQuantityValues(array $values, string $unit)
{
$value = 0;
foreach ($values as $val) {
$value += $this->convert($val['weight'], $unit)->getValue() * $val['quantity'];
}
return new QuantityValue($value, $unit);
}
/**
* @return Product[]
*/
private function getPackageItems()
{
$order = $this->getOrderFromReferer();
return $order->getItems();
}
/**
* @return boolean
*/
private function isOrderingQuoteProcess(): bool
{
$httpReferer = $this->getRequest()->server->get('HTTP_REFERER');
return preg_match('/\/(order\-quote)\/(.*)/', $httpReferer, $matches);
}
private function isCsrOrdering(): bool
{
return !!$this->getRequest()->get('order');
}
protected function getRequest(): Request
{
return $this->requestStack->getCurrentRequest();
}
/**
* @param QuantityValue $value
* @param string $targetUnit
*
* @return QuantityValue
*/
private function convert(QuantityValue $value, string $targetUnit)
{
return $value;
}
}