| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 | <?php/** * Refer to LICENSE.txt distributed with the Temando Shipping module for notice of license */namespace Temando\Shipping\Model\Shipping;use Magento\Framework\App\Config\ScopeConfigInterface;use Magento\Framework\Exception\LocalizedException;use Magento\Framework\Exception\NoSuchEntityException;use Magento\Framework\Message\ManagerInterface;use Magento\Quote\Model\Quote\Address\RateRequest;use Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory;use Magento\Quote\Model\Quote\Address\RateResult\MethodFactory;use Magento\Sales\Api\Data\ShipmentTrackInterface;use Magento\Shipping\Model\Carrier\AbstractCarrier;use Magento\Shipping\Model\Carrier\CarrierInterface;use Magento\Shipping\Model\Rate\ResultFactory;use Magento\Shipping\Model\Tracking\Result\StatusFactory;use Psr\Log\LoggerInterface;use Psr\Log\LogLevel;use Temando\Shipping\Model\Checkout\RateRequest\QuotingDataInitializer;use Temando\Shipping\Model\ExperienceInterface;use Temando\Shipping\Model\ResourceModel\Repository\ExperienceRepositoryInterface;use Temando\Shipping\Model\ResourceModel\Repository\ShipmentReferenceRepositoryInterface;use Temando\Shipping\Model\ResourceModel\Repository\ShipmentRepositoryInterface;use Temando\Shipping\Model\Shipping\RateResult\FreeShipping;use Temando\Shipping\Webservice\Processor\OrderQualificationProcessorPool;/** * Temando Shipping Carrier * * @package Temando\Shipping\Model * @author  Christoph Aßmann <christoph.assmann@netresearch.de> * @author  Sebastian Ertner <sebastian.ertner@netresearch.de> * @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * @link    https://www.temando.com/ */class Carrier extends AbstractCarrier implements CarrierInterface{    /**     * @var StatusFactory     */    private $trackStatusFactory;    /**     * @var MethodFactory     */    private $rateMethodFactory;    /**     * @var ResultFactory     */    private $rateResultFactory;    /**     * @var ManagerInterface     */    private $messageManager;    /**     * @var ShipmentRepositoryInterface     */    private $shipmentRepository;    /**     * @var ShipmentReferenceRepositoryInterface     */    private $shipmentReferenceRepository;    /**     * @var ExperienceRepositoryInterface     */    private $experienceRepository;    /**     * @var QuotingDataInitializer     */    private $quotingDataInitializer;    /**     * @var OrderQualificationProcessorPool     */    private $processorPool;    /**     * @var FreeShipping     */    private $freeShipping;    /**     * Carrier constructor.     * @param ScopeConfigInterface $scopeConfig     * @param ErrorFactory $rateErrorFactory     * @param LoggerInterface $logger     * @param StatusFactory $trackStatusFactory     * @param MethodFactory $rateMethodFactory     * @param ResultFactory $rateResultFactory     * @param ManagerInterface $messageManager     * @param ShipmentRepositoryInterface $shipmentRepository     * @param ShipmentReferenceRepositoryInterface $shipmentReferenceRepository     * @param ExperienceRepositoryInterface $experienceRepository     * @param QuotingDataInitializer $quotingDataInitializer     * @param OrderQualificationProcessorPool $processorPool     * @param FreeShipping $freeShipping     * @param mixed[] $data     */    public function __construct(        ScopeConfigInterface $scopeConfig,        ErrorFactory $rateErrorFactory,        LoggerInterface $logger,        StatusFactory $trackStatusFactory,        MethodFactory $rateMethodFactory,        ResultFactory $rateResultFactory,        ManagerInterface $messageManager,        ShipmentRepositoryInterface $shipmentRepository,        ShipmentReferenceRepositoryInterface $shipmentReferenceRepository,        ExperienceRepositoryInterface $experienceRepository,        QuotingDataInitializer $quotingDataInitializer,        OrderQualificationProcessorPool $processorPool,        FreeShipping $freeShipping,        array $data = []    ) {        $this->trackStatusFactory = $trackStatusFactory;        $this->rateMethodFactory = $rateMethodFactory;        $this->rateResultFactory = $rateResultFactory;        $this->messageManager = $messageManager;        $this->shipmentRepository = $shipmentRepository;        $this->shipmentReferenceRepository = $shipmentReferenceRepository;        $this->experienceRepository = $experienceRepository;        $this->quotingDataInitializer = $quotingDataInitializer;        $this->processorPool = $processorPool;        $this->freeShipping = $freeShipping;        parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);    }    /**     * Code of the carrier     */    const CODE = 'temando';    /**     * Carrier's code     *     * @var string     */    protected $_code = self::CODE;    /**     * Fetch shipping rates from API.     *     * @param RateRequest $rateRequest     * @return \Magento\Shipping\Model\Rate\Result     */    public function collectRates(RateRequest $rateRequest)    {        $result = $this->rateResultFactory->create();        $activeFlag = $this->getData('active_flag');        if ($activeFlag && !$this->getConfigFlag($activeFlag)) {            return $result;        }        try {            // create request data from rate request            $order = $this->quotingDataInitializer->getOrder($rateRequest);            // send order to Temando platform, will respond with shipping options            $qualifications = $this->experienceRepository->getExperiencesForOrder($order);            // extract applicable shipping options from order qualifications            $shippingOptions = $this->processorPool->processRatesResponse($rateRequest, $order, $qualifications);        } catch (LocalizedException $e) {            $this->_logger->log(LogLevel::WARNING, $e->getMessage(), ['exception' => $e]);            $shippingOptions = [];        }        foreach ($shippingOptions as $shippingOption) {            /** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */            $method = $this->rateMethodFactory->create();            $method->setCarrier($this->_code);            $method->setCarrierTitle($this->getConfigData('title'));            $method->setMethod($shippingOption->getCode());            $method->setMethodTitle($shippingOption->getLabel());            $method->setPrice($shippingOption->getCost());            $method->setCost($shippingOption->getCost());            $result->append($method);        }        if (empty($result->getAllRates())) {            /** @var \Magento\Quote\Model\Quote\Address\RateResult\Error $error */            $error = $this->_rateErrorFactory->create(['data' => [                'carrier' => $this->_code,                'carrier_title' => $this->getConfigData('title'),                'error_message' => $this->getConfigData('specificerrmsg'),            ]]);            $result->append($error);        } else {            $this->freeShipping->apply($rateRequest, $result);        }        return $result;    }    /**     * Obtain shipping experiences configured at the merchant account for usage     * in cart price rule conditions.     *     * @return string[]     */    public function getAllowedMethods()    {        $experiences = array_reduce(            $this->experienceRepository->getExperiences(),            function (array $carry, ExperienceInterface $experience) {                if ($experience->getStatus() !== ExperienceInterface::STATUS_DISABLED) {                    $carry[$experience->getExperienceId()] = $experience->getName();                }                return $carry;            },            []        );        asort($experiences);        return $experiences;    }    /**     * @return bool     */    public function isTrackingAvailable()    {        return true;    }    /**     * Get tracking information. Original return value annotation is misleading.     *     * @see \Magento\Shipping\Model\Carrier\AbstractCarrier::isTrackingAvailable()     * @see \Magento\Shipping\Model\Carrier\AbstractCarrierOnline::getTrackingInfo()     * @see \Magento\Dhl\Model\Carrier::getTracking()     * @param string $trackingNumber     * @return \Magento\Shipping\Model\Tracking\Result\AbstractResult     */    public function getTrackingInfo($trackingNumber)    {        /** @var \Magento\Shipping\Model\Tracking\Result\Status $tracking */        $tracking = $this->trackStatusFactory->create();        $tracking->setCarrier($this->_code);        $tracking->setTracking($trackingNumber);        try {            $shipmentTrack = $this->shipmentReferenceRepository->getShipmentTrack($this->_code, $trackingNumber);            $carrierTitle = $shipmentTrack->getTitle() ? $shipmentTrack->getTitle() : $this->getConfigData('title');            $trackingUrl = $this->getTrackingUrl($shipmentTrack);            $tracking->setCarrierTitle($carrierTitle);            $tracking->setUrl($trackingUrl);        } catch (LocalizedException $exception) {            $this->messageManager->addErrorMessage($exception->getMessage());            $tracking->setCarrierTitle($this->getConfigData('title'));            $tracking->setUrl('');        }        return $tracking;    }    /**     * Extract tracking URL from platform shipment. If possible, read url from package level.     *     * @param ShipmentTrackInterface $shipmentTrack     * @return string     * @throws NoSuchEntityException     * @throws LocalizedException     */    private function getTrackingUrl(ShipmentTrackInterface $shipmentTrack)    {        $shipmentId = $shipmentTrack->getParentId();        $shipmentReference = $this->shipmentReferenceRepository->getByShipmentId($shipmentId);        $shipment = $this->shipmentRepository->getById($shipmentReference->getExtShipmentId());        // read tracking url from booking fulfillment        $trackingUrl = $shipment->getFulfillment()->getTrackingUrl();        // check if there is a matching tracking url in the packages        foreach ($shipment->getPackages() as $package) {            if (!$package->getTrackingUrl()) {                continue;            }            if ($package->getTrackingReference() === $shipmentTrack->getTrackNumber()) {                $trackingUrl = $package->getTrackingUrl();            }        }        return (string) $trackingUrl;    }}
 |