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.
Václav Greif se programování pro Wordpress věnuje více než 16 let. Za tu dobu nasbíral mnoho zkušeností s tvorbou pluginů pro Wordpress, úpravou šablon a programováním komplexních funkcionalit. Věnuje se programování pro Wordpress a školení programátorů.