Speedy's web service (EPS) PHP client library provides easy integration with client applications (eMerchants and third party software) [downloads]. This Library is developed and tested with PHP version 5.4.3 on a 64 bit Windows machine.
Folder "<distribution_name>/speedy-eps-lib" in distribution archive contains library classes to be included and used by client php applications.
Folder "<distribution_name>/examples" contains sample usages of php library.
The library works with EPS web service published at:
The full documentation of can be found here:
To get a test account please send us an e-mail to [email protected] and provide the following info:
Download latest release zip archive, unzip distribution in your php workspace and include php sources in "<distribution_name>/speedy-eps-lib" directory.
This section include some useful code snippets that demonstrates common functionality of Speedy EPS.
See samples in "<distribution_name>/examples" directory of distribution archive for for further reference
User needs to establish a session to access EPS services. Each call to EPS service contains a session Id assigned to established session. The library encapsulates session management and makes this process transparent to the end user.
// Configure client EPS facade class instance to web services
$eps = new EPSFacade(new EPSSOAPInterfaceImpl(), "<your_user_name>", "<your_user_password>");
// Get authenticated user client data
$senderClientData = $eps -> getClientById($eps -> getResultLogin() -> getClientId());
// Get current session data in ResultLogin class instance.
// User can use this method if session details are needed.
$resultLogin = $eps -> getResultLogin(false);
if (isset($resultLogin)) {
// ... session is active and its data is accessible from ResultLogin methods
}
If you want to send a shipment to a country that is not Bulgaria, you can get the country's details from the "listCountriesEx" method.
$searchString = 'Romania'; // The search string can be partial (like 'Rom', 'Germ', etc. This will return multiple results if available).
$paramFilterCountry = new ParamFilterCountry();
$paramFilterCountry -> setName($searchString);
$resultListCountriesEx = $eps -> listCountriesEx($paramFilterCountry, 'EN'); // $resultListCountriesEx will return an array with countries' data.
If in the result of the "listCountriesEx" method, "requireState" is "true" then you have to select a state. To get state data use the "listStates" method.
// Option one
$countryId = 124; // CANADA (countryId obtained from "listCountriesEx")
$name = 'ALBE'; // The name can be partial
$resultListStates = $eps -> listStates($countryId, $name); // $resultListStates will return states in Canada (countryId: 124) which contain 'ALBE' in their names.
// Option two
$countryId = 124; // CANADA (countryId obtained from "listCountriesEx")
$name = NULL;
$resultListStates = $eps -> listStates($countryId, $name); // $resultListStates will return states in Canada (countryId: 124). The result is limited to 10 records.
If in the result of the "listCountriesEx" method, "requirePostCode" is "true" then you have to set post code. To validate post code use the "validatePostCode" method.
$countryId = 56; // BELGIUM (countryId obtained from "listCountriesEx")
$postCode = '1608';
$siteId = NULL;
$resultValidatePostCode = $eps -> validatePostCode($countryId, $postCode, $siteId); // $resultValidatePostCode will return true or false.
Use the "listSitesEx" method to get site parameters. Keep in mind that the post codes and names in Bulgaria are not unique. Some post codes represents more than one site. So the result of the method may return more than one record.
For test purposes in the examples below we will use site with name "DOBRICH". There are 3 sites in Bulgaria which are called "DOBRICH" with different post codes and regions.
// Option one. Find site by post code.
$language = 'EN';
$filter = new ParamFilterSite();
$filter -> setCountryId(100); // BULGARIA
$filter -> setPostCode(9300);
$resultListSiteEx = $eps -> listSitesEx($filter, $language); // $resultListSiteEx will return one record for a site called DOBRICH (with post code 9300), but if you set "1405" for post code you will receive 2 records, "PLANA" and "ZHELEZNITSA".
// Option two. Find site by part of the name.
$language = 'EN';
$filter = new ParamFilterSite();
$filter -> setCountryId(100);
$filter -> setSearchString('DOBRICH'); // The search string can be partial.
$resultListSiteEx = $eps -> listSitesEx($filter, $language); // $resultListSiteEx will return all sites which contain 'DOBRICH' in their names (there are more than one sites called "DOBRICH" in different regions of Bulgaria).
// Option three. Find site by part of the name and the post code.
$language = 'EN';
$filter = new ParamFilterSite();
$filter -> setCountryId(100);
$filter -> setSearchString('DOBR'); // Part of the name
$filter -> setPostCode(9300);
$resultListSiteEx = $eps -> listSitesEx($filter, $language); // $resultListSiteEx will return only one record. In this example, the combination of the searched string and post code is unique.
// Option four. Find site by exact name and post code.
$language = 'EN';
$filter = new ParamFilterSite();
$filter -> setCountryId(100);
$filter -> setName('DOBRICH'); // Full site name
$filter -> setPostCode(9300);
$resultListSiteEx = $eps -> listSitesEx($filter, $language); // $resultListSiteEx will return only one record. In this example, the combination of name and post code is unique.
// Option five. Find site by exact name and part of the name of the region.
$language = 'EN';
$filter = new ParamFilterSite();
$filter -> setCountryId(100);
$filter -> setName('DOBRICH'); // Full site name
$filter -> setRegion('HASK'); // Part of the name of "HASKOVO" region
$resultListSiteEx = $eps -> listSitesEx($filter, $language); // $resultListSiteEx will return only one record for site called DOBRICH in HASKOVO region. In this example, the combination of name and region is unique.
To get a list of offices and office data
// Option 1
$name = NULL;
$siteId = NULL;
$language = 'EN';
$countryId = 100; // BULGARIA
$resultListOffices = $eps -> listOfficesEx($name, $siteId, $language, $countryId); // $resultListOffices will return all offices in Bulgaria (countryId: 100).
// Option 2
$name = NULL;
$siteId = 68134; // SOFIA (siteId obtained from "listSitesEx")
$language = 'EN';
$countryId = 100; // BULGARIA
$resultListOffices = $eps -> listOfficesEx($name, $siteId, $language, $countryId); // $resultListOffices will return all offices in Sofia, Bulgaria (siteId: 68134; countryId: 100).
// Option 3
$name = 'BREZ'; // The name can be partial
$siteId = NULL;
$language = 'EN';
$countryId = 100; // BULGARIA
$resultListOffices = $eps -> listOfficesEx($name, $siteId, $language, $countryId); // $resultListOffices will return all offices in Bulgaria whose names contain 'BREZ'.
When you know the sites of the sender and receiver, use the "listServicesForSites" method to get the valid services.
$currentDate = date('Y-m-d');
$language = 'EN';
$senderId = NULL;
$sndrCountryId = NULL;
$sndrSiteId = 68134; // SOFIA (siteId obtained from "listSitesEx")
$senderOfficeId = NULL;
$sndrPostCode = NULL;
$receiverId = NULL;
$rcptCountryId = NULL;
$rcptSiteId = 10135; // VARNA (siteId obtained from "listSitesEx")
$receiverOfficeId = NULL;
$rcptPostCode = NULL;
$resultListServicesForSites = $eps -> listServicesForSites($currentDate, $sndrSiteId, $rcptSiteId, $sndrCountryId, $sndrPostCode, $rcptCountryId, $rcptPostCode, $language, $senderId, $receiverId, $senderOfficeId, $receiverOfficeId);
// In the resultListServicesForSites you will find all valid services with their parameters.
To get a list of streets and street data.
$name = 'IVA'; // The name can be partial;
$siteId = 68134; // SOFIA (siteId obtained from "listSitesEx")
$language = 'EN';
$resultListStreets = $eps -> listStreets($name, $siteId, $language); // $resultListStreets will return streets in Sofia (siteId: 68134) whose names contain 'IVA' (like "IVA", "IVAN ANDONOV0", "IVAN ARABADZHIYATA" etc.).
To get a list of quarters in the selected site.
$name = 'KRAS'; // The name can be partial;
$siteId = 68134; // SOFIA (siteId obtained from "listSitesEx")
$language = 'EN';
$resultListQuarters = $eps -> listQuarters($name, $siteId, $language); // $resultListQuarters will return quarters in Sofia (siteId: 68134) whose names contain 'KRAS' (like "KRASNO SELO", "KRASNA POLYANA 1" etc.).
To get a list of blocks in the selected site.
$name = 'TRE'; // The name can be partial;
$siteId = 68134; // SOFIA (siteId obtained from "listSitesEx")
$language = 'EN';
$resultListBlocks = $eps -> listBlocks($name, $siteId, $language); // $resultListBlocks will return blocks in Sofia (siteId: 68134) which names contain 'TRE' in their names (like "TREZOR").
The common object is a valid object with an address and it is easy for the customers to recognize it because they don’t know its exact address but know it by name. The advantage of using the common object that it is not necessary to supply steertId, quarterId, etc.
Use the method to get a list of common objects and object data like id, type, name, address.
$name = 'NATIONAL';
$siteId = 68134; // SOFIA (siteId obtained from "listSitesEx")
$language = 'EN';
$resultListCommonObjects = $eps -> listCommonObjects($name, $siteId, $language); // $resultListCommonObjects will return list of common objects which names contain 'NATIONAL' in their names (like "NATIONAL ART GALLERY", "NATIONAL PALACE OF CHILDREN" etc.).
Send a shipment from an obejct. If your contract contains two or more objects (stores, warehouses and so on) you can get their Ids and other data using the "listContractClients" method.
Note: By default your EPS user is "attached" to an object which you have specified when you requested your EPS account.
Example: If you have a store in Sofia and a warehouse in Veliko Tarnovo, and you want to alternate sender address you can supply the object coresponding clientId (each object has an unique clientId).
$resultListContractClients = $eps -> listContractClients(); // $resultListContractClients will return data like 'clientId, 'partnerName', 'objectName', 'address' etc. of all own objects.
Taking date is used to determine available services depending on sender site and is also a factor in courier service price calculation. Therefore the same picking could have different price for different taking dates.
$serviceTypeId = 505; // Example service type from Speedy nomenclature
$bringToOfficeId = null; // The picking will not be brought to office, hence this ID is null. Otherwise it should be ID of valid Speedy office
$fromMoment = time(); // Current time. We are interested for available taking days from current moment
// Get sender site ID
// In this example sender is authenticated client
$senderClientData = $eps -> getClientById($eps -> getResultLogin() -> getClientId());
$senderSiteId = $senderClientData -> getAddress() -> getSiteId();
$arrTakingDates = $eps -> getAllowedDaysForTaking(
$serviceTypeId, is_null($bringToOfficeId) ? $senderSiteId : null, $bringToOfficeId, $fromMoment
);
if (count($arrTakingDates) == 0) {
throw new ClientException('There are no dates available for taking');
} else if (count($arrTakingDates) == 1) {
// There is only one date available for taking
$takingDate = $arrTakingDates[0];
} else {
// There are several dates available. We take first one, but user is free to select taking date from all of them
$takingDate = $arrTakingDates[0];
}
Calculate the price of a picking (before picking registration)
// Init current date
$todayDate = date('Y-m-d');
$calculationData = new StdClass();
$calculationData -> weightDeclared = 5.25; // Decalred weight
$calculationData -> bringToOfficeId = null; // Id of the office that sender should bring the parcel(s). Courier will visit sender address if this value is null
$calculationData -> takeFromOfficeId = null; // Id of the office that recipient should take the parcel(s) from. Courier will visit recipient address if this value is null
$calculationData -> parcelsCount = 1; // Parcels count
$calculationData -> documents = false; // Flag for documents
$calculationData -> palletized = false; // Flag for pallets
$calculationData -> fragile = false; // flag for fragile content
$calculationData -> payerType = ParamCalculation::PAYER_TYPE_RECEIVER; // Determine the payer
$calculationData -> amountCODBase = 25; // Collecton on Delivery amount
$calculationData -> serviceTypeId = 505; // Service type 505 from Speedy nomenclature (serviceTypeId obtained from "listServicesForSites")
$calculationData -> takingDate = strtotime(date("Y-m-d", strtotime($todayDate)) . " +1 day"); // We need taking date to be tomorrow
// Get sender client data
// In this example sender is authenticated client
$senderClientData = $eps -> getClientById($eps -> getResultLogin() -> getClientId());
// In this example receiver address is in city of Sofia
// Lookup for example receiver city of Sofia in Speedy address nomenclature
// We are sure we have results therefore array is not verified for null or empty values.
$arrSites = $eps -> listSitesEx('gr.', 'VARNA');
$receiverSiteId = $arrSites[0] -> getId();
$paramCalculation = new ParamCalculation();
$paramCalculation -> setBroughtToOffice(!is_null($calculationData -> bringToOfficeId));
$paramCalculation -> setToBeCalled(!is_null($calculationData -> takeFromOfficeId));
$paramCalculation -> setParcelsCount($calculationData -> parcelsCount );
$paramCalculation -> setWeightDeclared($calculationData -> weightDeclared);
$paramCalculation -> setDocuments($calculationData -> documents);
$paramCalculation -> setPalletized($calculationData -> palletized);
$paramCalculation -> setFragile($calculationData -> fragile);
$paramCalculation -> setSenderId($senderClientData -> getClientId());
$paramCalculation -> setReceiverSiteId($receiverSiteId);
$paramCalculation -> setPayerType($calculationData -> payerType);
$paramCalculation -> setAmountCodBase($calculationData -> amountCODBase);
$paramCalculation -> setTakingDate($calculationData -> takingDate);
$paramCalculation -> setServiceTypeId($calculationData -> serviceTypeId);
$resultCalculation = $eps -> calculate($paramCalculation);
This example registers Bill Of Lading, but to trigger the process of taking and delivery, the client needs to order a courier.
// Init example picking structure with data
$pickingData = new StdClass();
$pickingData -> weightDeclared = 5.25; // Decalred weight
$pickingData -> bringToOfficeId = null; // Id of the office that sender should bring the parcel(s). Courier will visit sender address if this value is null
$pickingData -> takeFromOfficeId = null; // Id of the office that recipient should take the parcel(s) from. Courier will visit recipient address if this value is null
$pickingData -> parcelsCount = 1; // Parcels count
$pickingData -> documents = false; // Flag for documents
$pickingData -> palletized = false; // Flag for pallets
$pickingData -> fragile = false; // flag for fragile content
$pickingData -> payerType = ParamCalculation::PAYER_TYPE_RECEIVER; // Determine the payer
$pickingData -> amountCODBase = 25; // Collecton on Delivery amount
$pickingData -> backDocumentReq = true; // Back document request flag
$pickingData -> backReceiptReq = false; // Back receipt request flag
$pickingData -> contents = 'CLOTHES'; // Content description
$pickingData -> packing = 'PACKAGE'; // Type of packing
$pickingData -> serviceTypeId = 505; // Service type 505 from Speedy nomenclature (serviceTypeId obtained from "listServicesForSites")
$pickingData -> takingDate = time(); // Taking date is today
// In this example sender is authenticated client.
// Therefore we fill Bill Of Lading sender client data with authenticated client data
$senderClientData = $eps -> getClientById($eps -> getResultLogin() -> getClientId());
$sender = new ParamClientData();
$sender -> setClientId($senderClientData -> getClientId());
$sender -> setContactName('PETAR IVANOV');
$senderPhoneNumber = new ParamPhoneNumber();
$senderPhoneNumber -> setNumber('0881234567');
$sender -> setPhones(array(0 => $senderPhoneNumber));
// In this example receiver address is "VARNA, kv. MLADOST 1, bl. 102, vh. 3, et. 4, ap. 5"
// Lookup for example receiver city of Sofia in Speedy address nomenclature
// We are sure we have results therefore array is not verified for null or empty values.
$arrSites = $eps -> listSitesEx('gr.', 'VARNA');
$receiverSiteId = $arrSites[0] -> getId();
// Lookup example receiver address quarter "MLADOST 1" in city of Varna in Speedy address nomenclature
// We are sure we have results therefore array is not verified for null or empty values.
// EPS supports similar methods for streets also
$arrQuarters = $eps -> listQuarters('MLADOST 1', $receiverSiteId);
$receiverResultQuarter = $arrQuarters[0];
// Finally set receiver address fields
$receiverAddress = new ParamAddress();
$receiverAddress -> setSiteId($receiverSiteId);
$receiverAddress -> setQuarterId($receiverResultQuarter -> getId());
$receiverAddress -> setBlockNo('102');
$receiverAddress -> setEntranceNo('3');
$receiverAddress -> setFloorNo('4');
$receiverAddress -> setApartmentNo('5');
// Note that if you cannot determine address fields from input address text (f.e. you cannot structurally parse the input address)
// clients could use method setAddressNote. In that case setting an address will look like:
//
// $receiverAddress = new ParamAddress();
// $receiverAddress -> setSiteId($receiverSiteId);
// $receiverAddress -> setAddressNote('kv. MLADOST 1, bl. 102, vh. 3, et. 4, ap. 5');
//
// NOTE: Site name should not be placed in addressNote field, because site Id is passed separately and cannot be omitted
// Set receiver client data
$receiver = new ParamClientData();
$receiver -> setAddress($receiverAddress);
$receiver -> setPartnerName('XYZ COMPANY');
$paramPhoneNumber = new ParamPhoneNumber();
$paramPhoneNumber -> setNumber('0888223344');
$receiver -> setPhones(array(0 => $paramPhoneNumber));
$receiver -> setContactName('GEORGI DIMITROV');
$picking = new ParamPicking();
$picking -> setServiceTypeId($pickingData -> serviceTypeId);
$picking -> setBackDocumentsRequest($pickingData -> backDocumentReq);
$picking -> setBackReceiptRequest($pickingData -> backReceiptReq);
$picking -> setWillBringToOffice(!is_null($pickingData -> bringToOfficeId));
$picking -> setOfficeToBeCalledId($pickingData -> takeFromOfficeId);
$picking -> setParcelsCount($pickingData -> parcelsCount);
$picking -> setWeightDeclared($pickingData -> weightDeclared);
$picking -> setContents($pickingData -> contents);
$picking -> setPacking($pickingData -> packing);
$picking -> setDocuments($pickingData -> documents);
$picking -> setPalletized($pickingData -> palletized);
$picking -> setFragile($pickingData -> fragile);
$picking -> setSender($sender);
$picking -> setReceiver($receiver);
$picking -> setPayerType($pickingData -> payerType);
$picking -> setTakingDate($pickingData -> takingDate);
$picking -> setAmountCodBase($pickingData -> amountCODBase);
/* Optional data */
// Set parcels size
$parcelDetails1 = new ParamParcelInfo();
$size = new Size();
$size -> setWidth(5);
$size -> setDepth(6);
$size -> setHeight(7);
$parcelDetails1 -> setSeqNo(1);
$parcelDetails1 -> setParcelId(-1);
$parcelDetails1 -> setSize($size);
$parcelDetails1 -> setWeight(1);
$parcelsArray[] = $parcelDetails1;
$parcelDetails2 = new ParamParcelInfo(); // if there is more than one parcel
$size2 = new Size();
$size2 -> setWidth(11);
$size2 -> setDepth(12);
$size2 -> setHeight(13);
$parcelDetails2 -> setSeqNo(2);
$parcelDetails2 -> setParcelId(-1);
$parcelDetails2 -> setSize($size2);
$parcelDetails2 -> setWeight(2);
$parcelsArray[] = $parcelDetails2;
$parcelsCount = count($parcelsArray);
$picking -> setParcels($parcelsArray);
$picking -> setParcelsCount($parcelsCount);
// If you want to set a retutn voucher.
$returnVoucher = new ParamReturnVoucher();
$returnVoucher -> setServiceTypeId(505);
$returnVoucher -> setPayerType(0); // Note that the sender of the return shipment is the receiver of the primary shipment.
$picking -> setReturnVoucher($returnVoucher);
// If you want to set some options before payment.
$paramOptionsBeforePayment = new ParamOptionsBeforePayment();
$paramOptionsBeforePayment -> setOpen(true);
$paramOptionsBeforePayment -> setTest(false);
$paramOptionsBeforePayment -> setReturnServiceTypeId(505);
$paramOptionsBeforePayment -> setReturnPayerType(0); // Note that the sender of the return shipment is the receiver of the primary shipment.
$picking -> setOptionsBeforePayment($paramOptionsBeforePayment);
// Create bill of lading
$resultBOL = $eps -> createBillOfLading($picking);
// $resultBOL contains response in a ResultBOL class instance
This example demonstrates usage of method to create Bill of Ladding PDF
$pickingId = 299000129; // Example ID of created picking
$paramPDF = new ParamPDF();
$paramPDF -> setIds(array(0 => $pickingId));
$paramPDF -> setType(ParamPDF::PARAM_PDF_TYPE_BOL);
$paramPDF -> setIncludeAutoPrintJS(true);
// Save pdf in a file
$fileNameOnly = $eps -> getUsername().'_picking_'.$pickingId.'_'.time().'.pdf';
$fileName = $outputPDFFolder.$fileNameOnly;
file_put_contents($fileName, $eps -> createPDF($paramPDF), FILE_APPEND | LOCK_EX);
This example demonstrates usage of method to print Bill of Ladding Labels in PDF
$pickingId = 299000129; // Example ID of created picking
$paramPDF = new ParamPDF();
$paramPDF -> setIds(array(0 => $pickingId));
$paramPDF -> setType(ParamPDF::PARAM_PDF_TYPE_LBL);
$paramPDF -> setIncludeAutoPrintJS(true);
// Save pdf in a file
$fileNameOnly = $eps -> getUsername().'_lbl_'.$pickingId.'_'.time().'.pdf';
$fileName = $outputPDFFolder.$fileNameOnly;
file_put_contents($fileName, $eps -> createPDF($paramPDF), FILE_APPEND | LOCK_EX);
Order triggers the process of taking and delivery. Orders are usually submitted at the end of working day (preferably but not mandatory - one order per day). The order includes all Bill Of Ladings created for current day.
$pickingId = 299000129; // Example Id of a created picking
$pickingId2 = 299000130; // Example Id of a created picking
$order = new ParamOrder();
$order -> setBillOfLadingsList(array(0 => $pickingId, 1 => $pickingId2));
$order -> setBillOfLadingsToIncludeType(ParamOrder::ORDER_BOL_INCLUDE_TYPE_EXPLICIT);
$order -> setReadinessTime(1730); // 17:30
$order -> setContactName('PETAR IVANOV');
$paramPhoneNumber = new ParamPhoneNumber();
$paramPhoneNumber -> setNumber('0881234567');
$order -> setPhoneNumber($paramPhoneNumber);
$order -> setWorkingEndTime(1800); // 18:00
$arrResultOrderPickingInfo = $eps -> createOrder($order);
To track a shipment/parcel the following methods can be used: trackPickingEx, trackParcel, trackParcelMultiple. For testing purposes please use the provided bills of lading: 299999990, 299999991, 299999992
$billOfLading = 299999990;
$lang = 'EN';
$returnOnlyLastOperation = false;
$resultTrackPickingEx = $eps -> trackPickingEx($billOfLading, $lang, $returnOnlyLastOperation);
Speedy requires shipment data to be in latin or cyrillic. Any other input will be unreadable. The method allows transliteration of user input in non win1251 characters to win1251.
Note that transliteration may not return the same number of symbols as the original string.
$text = 'ΣΙΔΗΡΑΣ ΜΕΡΑΡΧΙΑΣ 14 ΤΡΙΚΑΛΑ ΘΕΣΣΑΛΙΑΣ 4';
$resultConvertToWin1251 = $eps -> convertToWin1251($text); // $resultConvertToWin1251 will return "SIDERAS MERARKhIAS 14 TRIKALA ThESSALIAS 4".
Starting from release 2.0.0, the version number has the following form: <major>.<minor>.<revision>-<phase>
Before release 2.0.0, the version number had the following form: <major>.<minor>-<phase><revision>
This scheme has three number components:
The phase component has the following values: