Propojení DPD a WooCommerce

Pro weby sítě behejsepsem.cz jsem vytvořil WordPress plugin, který propojuje WooCommerce s přepravní službou DPD.

DPD má WSDL API, jehož specifikace je dostupná na https://www.mojedpd.cz/IT4EMWebServices/eshop/ShipmentServiceImpl?wsdl. Pro integraci služeb, které používají WSDL specifikaci, se mi nejvíce osvědčilo vygenerovat si z definice WSDL PHP SDK, které umožnují pohodlně vytvářet XML requesty namísto toho, aby se nějak ručně psaly. Tento způsob umožňuje i výrazně jednodušší údržbu systému, kdy při změně definice API stačí přegenerovat jednotlivé třídy SDK.

Pro generování tříd používám WsdlToPhp/PackageGenerator, který zatím fungoval u všech projektů, u nichž jsem ho použil. Pro vygenerování PHP SDK pro DPD stačí pustit v terminálu:

wsdltophp generate:package \                                          
urlorpath="https://www.mojedpd.cz/IT4EMWebServices/eshop/ShipmentServiceImpl?wsdl" \
    --destination="DPDManifestAPI" \
    --composer-name="woo-dpd/dpd-manifest-api" \
    --force --namespace="WPProgramator\WOO_DPD\DPDManifestApi"

 

Tento příkaz vygeneruje všechy potřebné třídy pro napojení DPD ShipmentAPI.

Příklad třídy, která zajišťuje samotné napojení, pak vypadá takto:

<?php

namespace WPProgramator\WOO_DPD\DPD;

use WPProgramator\WOO_DPD\DPDManifestApi\StructType\ReferenceVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\ClassMap;
use WPProgramator\WOO_DPD\DPDShipmentApi\ServiceType\Create;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\AddFieldShopShipmentVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\CreateShipment;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\ErrorVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\ParcelResultVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\ShipmentResultVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\ShipmentVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\ParcelVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\AdditionalServiceVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\CodVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\ParcelShopVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\ParcelShopShipmentVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\MoreServicesShopShipmentVO;
use WPProgramator\WOO_DPD\DPDShipmentApi\StructType\ServiceShopShipmentVO;
use WsdlToPhp\PackageBase\AbstractSoapClientBase;
use WPProgramator\WOO_DPD\Order;
use function WPProgramator\WOO_DPD\wpp_woo_dpd_container;

class Shipment {
  /**
   * @var CreateShipment
   */
  private $create_shipment;
  /**
   * @var
   */
  private $shipment_vo;
  /**
   * @var ParcelVO
   */
  private $parcel_vo;

  /**
   * @var ReferenceVO
   */
  private $reference_vo;
  /**
   * @var AdditionalServiceVO
   */
  private $additional_service_vo;
  /**
   * @var CodVO
   */
  private $cod_vo;
  /**
   * @var ParcelShopVO
   */
  private $parcel_shop_vo;
  /**
   * @var ParcelShopShipmentVO
   */
  private $parcel_shop_shipment_vo;
  /**
   * @var DPD
   */
  private $dpd;


  public function __construct(
    DPD $dpd,
    CreateShipment $create_shipment,
    ShipmentVO $shipment_vo,
    ParcelVO $parcel_vo,
    ReferenceVO $reference_vo,
    AdditionalServiceVO $additional_service_vo,
    CodVO $cod_vo,
    ParcelShopVO $parcel_shop_vo,
    ParcelShopShipmentVO $parcel_shop_shipment_vo
  ) {
    $this->dpd                     = $dpd;
    $this->create_shipment         = $create_shipment;
    $this->shipment_vo             = $shipment_vo;
    $this->parcel_vo               = $parcel_vo;
    $this->reference_vo            = $reference_vo;
    $this->additional_service_vo   = $additional_service_vo;
    $this->cod_vo                  = $cod_vo;
    $this->parcel_shop_vo          = $parcel_shop_vo;
    $this->parcel_shop_shipment_vo = $parcel_shop_shipment_vo;
  }

  /**
   * @param $order_id
   */
  public function add_shipments( $order_id ) {
    $this->setup_shipment_service();

    $shipments = $this->create_shipment->getShipmentList();
    if ( is_array( $order_id ) ) {
      foreach ( $order_id as $id ) {
        $shipments[] = $this->get_shipment( $id );
      }
    } else {
      $shipments[] = $this->get_shipment( $order_id );
    }

    $this->create_shipment->setShipmentList( $shipments );

    $create = $this->get_create_service();
    $create->createShipment( $this->create_shipment );
    $result = $create->getResult()->getResult()->getResultList();
    $data   = [];
    foreach ( $result as $item ) {
      /** @var $res ShipmentResultVO */
      /** @var $error ErrorVO */

      $error = $item->getError();
      if ( $error ) {
        $data['errors'][] = new \WP_Error( $error->getCode(), $error->getText() );
      } else {
        /** @var $item ShipmentResultVO */
        $data['shipments'][ $item->getShipmentReference()->getReferenceNumber() ] = [
          'shipment_id'           => $item->getShipmentReference()->getId(),
          'shipment_reference_no' => $item->getShipmentReference()->getReferenceNumber(),
        ];
        foreach ( $item->getParcelResultList() as $parcel_result ) {
          /** @var $parcel_result ParcelResultVO */
          $data['shipments'][ $item->getShipmentReference()->getReferenceNumber() ]['parcels'][] = [
            'parcel_id'           => $parcel_result->getParcelId(),
            'parcel_reference_no' => $parcel_result->getParcelReferenceNumber(),
          ];
        }
      }
    }

    return $data;
  }

  /**
   * Setup the shipment service
   */
  private function setup_shipment_service() {
    $this->create_shipment->setWsUserName( $this->dpd->username )
                          ->setWsPassword( $this->dpd->password )
                          ->setWsLang( $this->dpd->lang )
                          ->setApplicationType( $this->dpd->application_type )
                          ->setPriceOption( 'WithoutPrice' );

  }

  /**
   * Get a single shipment
   *
   * @param $order_id
   *
   * @return ShipmentVO
   */
  private function get_shipment( $order_id ) {
    /** @var Order $order */
    $order           = wpp_woo_dpd_container()->create( 'WPProgramator\WOO_DPD\Order', [ $order_id ] );
    $wc_order        = $order->get_order();
    $street          = $wc_order->get_shipping_address_1() ?: $wc_order->get_billing_address_1();
    $number          = '';
    $splitted_street = $this->split_street( $street );
    if ( $splitted_street ) {
      $street = $splitted_street[1];
      $number = $splitted_street[2];
    }

    $this->shipment_vo = new ShipmentVO();
    // Basic package details
    $shipment = $this->shipment_vo->setShipmentReferenceNumber( $order->get_reference_no() )
                                  ->setPayerId( $this->dpd->payer_id )
                                  ->setSenderAddressId( $this->dpd->sender_address_id )
                                  ->setReceiverName( $wc_order->get_formatted_shipping_full_name() ?: $wc_order->get_formatted_billing_full_name() )
                                  ->setReceiverFirmName( $wc_order->get_billing_company() )
                                  ->setReceiverCountryCode( $wc_order->get_shipping_country() ?: $wc_order->get_billing_country() )
                                  ->setReceiverZipCode( $wc_order->get_shipping_postcode() ?: $wc_order->get_billing_postcode() )
                                  ->setReceiverCity( $wc_order->get_shipping_city() ?: $wc_order->get_billing_city() )
                                  ->setReceiverStreet( $street )
                                  ->setReceiverHouseNo( $number )
                                  ->setReceiverPhoneNo( $wc_order->get_billing_phone() )
                                  ->setMainServiceCode( '1' )
                                  ->setReceiverEmail( $wc_order->get_billing_email() )
                                  ->setMainServiceCode( $this->get_main_service_code( 'private' ) );

    $parcels = [];
    for ( $i = 0; $i < $order->get_packages_no(); $i ++ ) {
      $parcel    = new ParcelVO();
      $parcels[] = $parcel->setParcelReferenceNumber( $this->dpd->store_prefix . '-' . $wc_order->get_order_number() . '-' . rand() )
                          ->setWeight( "1" );
    }

    // Reset the additional services
    $this->shipment_vo->setParcels( $parcels );
    $this->additional_service_vo->setCod( null )
                                ->setParcelShop( null )
                                ->setDocumentReturn( null )
                                ->setHighInsurance( null )
                                ->setExpay( null )
                                ->setIdCheck( null )
                                ->setMoreServices( null )
                                ->setSaturdayDelivery( null )
                                ->setPredictEmail( null )
                                ->setPredictSms( null )
                                ->setTimeFrame( null );

    $additional_service_found = false;

    $this->shipment_vo->setAdditionalServices( null );
    // Support COD payments
    if ( $order->has_cod() ) {
      $cod = $this->cod_vo->setAmount( $wc_order->get_total() )
                          ->setCurrency( $wc_order->get_currency() )
                          ->setPaymentType( 'Cash' );
      $this->additional_service_vo->setCod( $cod );
      $additional_service_found = true;
    }

    // Support Parcel Shop
    if ( $order->is_parcel_shop() ) {
      $data        = $order->get_parcel_shop_data();
      $parcel_shop = $this->parcel_shop_shipment_vo->setParcelShopId( $data['id'] )
                                                   ->setCompanyName( $data['company'] )
                                                   ->setCity( $data['city'] )
                                                   ->setStreet( $data['street'] )
                                                   ->setHouseNo( $data['house_no'] )
                                                   ->setCountryCode( $data['country_code'] )
                                                   ->setZipCode( $data['postal_code'] );

      $this->additional_service_vo->setParcelShop( $parcel_shop );
      $this->shipment_vo->setMainServiceCode( $this->get_main_service_code( 'parcel_shop' ) );
      $additional_service_found = true;
    }

    // Support multiple packages
    if ( $order->get_packages_no() > 1 && $order->has_cod() ) {
      $field = new AddFieldShopShipmentVO();
      $field->setName( 'ComplDel' )
            ->setValue( '1' );
      $service_vo = new ServiceShopShipmentVO();
      $service_vo->setCode( '50106' )
                 ->addField( $field );
      $more_services_shipment_vo = new MoreServicesShopShipmentVO( [ $field ] );
      $this->additional_service_vo->setMoreServices( $more_services_shipment_vo );
    }

    if ( $additional_service_found ) {
      $this->shipment_vo->setAdditionalServices( $this->additional_service_vo );
    }

    return $shipment;
  }

  /**
   * Get number from street
   *
   * @param $street
   *
   * @return bool
   */
  private function split_street( $street ) {
    if ( preg_match( '/([^\d]+)\s?(.+)/i', $street, $result ) ) {
      return $result;
    }

    return false;
  }

  /**
   * Get the main service code
   *
   * @param $service
   *
   * @return string
   */
  public function get_main_service_code( $service ) {
    switch ( $service ) {
      case 'private':
        $code = '109';
        break;
      case 'parcel_shop':
        $code = '50101';
        break;
      default:
        $code = '109';
    }

    return $code;

  }

  /**
   * Setup the service
   * @return Create
   */
  public function get_create_service() {
    $options = array(
      AbstractSoapClientBase::WSDL_URL      => 'https://www.mojedpd.cz/IT4EMWebServices/eshop/ShipmentServiceImpl?wsdl',
      AbstractSoapClientBase::WSDL_CLASSMAP => ClassMap::get(),
    );

    return new Create( $options );
  }
}

WooCommerce plugin pro DPD aktuálně podporuje služby Standard, Private, Parcel Shop, a doplňkové služby Dobírka a Kompletní doručení. Přidání dalších funkcí je díky napojení přes wsdl specifikaci opravdu jednoduché.

Pokud budete mít o propojení WooCommerce s DPD nebo podobné řešení zájem, neváhejte mě kontaktovat.

Přidat komentář