public function USPSInternationalRate::quote in Ubercart 8.4
Callback for retrieving USPS shipping quote.
Parameters
$products: Array of cart contents.
$details: Order details other than product information.
$method: The shipping method to create the quote.
Return value
JSON object containing rate, error, and debugging information.
Overrides USPSRateBase::quote
File
- shipping/
uc_usps/ src/ Plugin/ Ubercart/ ShippingQuote/ USPSInternationalRate.php, line 121
Class
- USPSInternationalRate
- Provides a percentage rate shipping quote plugin.
Namespace
Drupal\uc_usps\Plugin\Ubercart\ShippingQuoteCode
public function quote($products, $details, $method) {
$usps_config = \Drupal::config('uc_usps.settings');
$quote_config = \Drupal::config('uc_quote.settings');
// The uc_quote AJAX query can fire before the customer has completely
// filled out the destination address, so check to see whether the address
// has all needed fields. If not, abort.
$destination = (object) $details;
// Country code is always needed.
if (empty($destination->country)) {
// Skip this shipping method.
return [];
}
// Shipments to the US also need zone and postal_code.
if ($destination->country == 'US' && (empty($destination->zone) || empty($destination->postal_code))) {
// Skip this shipping method.
return [];
}
// USPS Production server.
$connection_url = 'http://production.shippingapis.com/ShippingAPI.dll';
// Initialize $debug_data to prevent PHP notices here and in uc_quote.
$debug_data = [
'debug' => NULL,
'error' => [],
];
$services = [];
$addresses = [
$quote_config
->get('store_default_address'),
];
$packages = $this
->packageProducts($products, $addresses);
if (!count($packages)) {
return [];
}
foreach ($packages as $key => $ship_packages) {
$orig = $addresses[$key];
$orig->email = uc_store_email();
if (strpos($method['id'], 'intl') && $destination->country != 'US') {
// Build XML for international rate request.
$request = $this
->intlRateRequest($ship_packages, $orig, $destination);
}
elseif ($destination->country == 'US') {
// Build XML for domestic rate request.
$request = $this
->rateRequest($ship_packages, $orig, $destination);
}
$account = \Drupal::currentUser();
if ($account
->hasPermission('configure quotes') && $quote_config
->get('display_debug')) {
$debug_data['debug'] .= htmlentities(urldecode($request)) . "<br />\n";
}
// Send request
$result = \Drupal::httpClient()
->post($connection_url, NULL, $request)
->send();
if ($account
->hasPermission('configure quotes') && $quote_config
->get('display_debug')) {
$debug_data['debug'] .= htmlentities($result
->getBody(TRUE)) . "<br />\n";
}
$rate_type = $usps_config
->get('online_rates');
$response = new \SimpleXMLElement($result
->getBody(TRUE));
// Map double-encoded HTML markup in service names to Unicode characters.
$service_markup = [
'<sup>&reg;</sup>' => '®',
'<sup>&trade;</sup>' => '™',
'<sup>®</sup>' => '®',
'<sup>™</sup>' => '™',
'**' => '',
];
// Use this map to fix USPS service names.
if (strpos($method['id'], 'intl')) {
// Find and replace markup in International service names.
foreach ($response
->xpath('//Service') as $service) {
$service->SvcDescription = str_replace(array_keys($service_markup), $service_markup, $service->SvcDescription);
}
}
else {
// Find and replace markup in Domestic service names.
foreach ($response
->xpath('//Postage') as $postage) {
$postage->MailService = str_replace(array_keys($service_markup), $service_markup, $postage->MailService);
}
}
if (isset($response->Package)) {
foreach ($response->Package as $package) {
if (isset($package->Error)) {
$debug_data['error'][] = (string) $package->Error[0]->Description . '<br />';
}
else {
if (strpos($method['id'], 'intl')) {
foreach ($package->Service as $service) {
$id = (string) $service['ID'];
$services[$id]['label'] = t('U.S.P.S. @service', [
'@service' => (string) $service->SvcDescription,
]);
// Markup rate before customer sees it.
if (!isset($services[$id]['rate'])) {
$services[$id]['rate'] = 0;
}
$services[$id]['rate'] += $this
->rateMarkup((string) $service->Postage);
}
}
else {
foreach ($package->Postage as $postage) {
$classid = (string) $postage['CLASSID'];
if ($classid === '0') {
if ((string) $postage->MailService == "First-Class Mail® Parcel") {
$classid = 'zeroParcel';
}
elseif ((string) $postage->MailService == "First-Class Mail® Letter") {
$classid = 'zeroFlat';
}
else {
$classid = 'zero';
}
}
if (!isset($services[$classid]['rate'])) {
$services[$classid]['rate'] = 0;
}
$services[$classid]['label'] = t('U.S.P.S. @service', [
'@service' => (string) $postage->MailService,
]);
// Markup rate before customer sees it.
// Rates are stored differently if ONLINE $rate_type is
// requested. First Class doesn't have online rates, so if
// CommercialRate is missing use Rate instead.
if ($rate_type && !empty($postage->CommercialRate)) {
$services[$classid]['rate'] += $this
->rateMarkup((string) $postage->CommercialRate);
}
else {
$services[$classid]['rate'] += $this
->rateMarkup((string) $postage->Rate);
}
}
}
}
}
}
}
// Strip leading 'usps_'
$method_services = substr($method['id'] . '_services', 5);
//$method_services is the name of the callback function
// array_keys($method['quote']['accessorials'])
$usps_services = array_filter($usps_config
->get($method_services));
foreach ($services as $service => $quote) {
if (!in_array($service, $usps_services)) {
unset($services[$service]);
}
}
foreach ($services as $key => $quote) {
if (isset($quote['rate'])) {
$services[$key]['rate'] = $quote['rate'];
$services[$key]['option_label'] = $this
->getDisplayLabel($quote['label']);
}
}
uasort($services, 'uc_quote_price_sort');
// Merge debug data into $services. This is necessary because
// $debug_data is not sortable by a 'rate' key, so it has to be
// kept separate from the $services data until this point.
if (isset($debug_data['debug']) || isset($debug_data['error']) && count($debug_data['error'])) {
$services['data'] = $debug_data;
}
return $services;
}