View source
<?php
namespace Drupal\uc_usps\Plugin\Ubercart\ShippingQuote;
use Drupal\Core\Form\FormStateInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\uc_order\OrderInterface;
use Drupal\uc_quote\ShippingQuotePluginBase;
use Drupal\node\Entity\Node;
abstract class USPSRateBase extends ShippingQuotePluginBase {
public function defaultConfiguration() {
return [
'base_rate' => 0,
'product_rate' => 0,
'field' => '',
];
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$fields = [
'' => $this
->t('- None -'),
];
$result = \Drupal::entityQuery('field_config')
->condition('field_type', 'number')
->execute();
foreach (FieldConfig::loadMultiple($result) as $field) {
$fields[$field
->getName()] = $field
->label();
}
$form['base_rate'] = [
'#type' => 'uc_price',
'#title' => $this
->t('Base price'),
'#description' => $this
->t('The starting price for shipping costs.'),
'#default_value' => $this->configuration['base_rate'],
'#required' => TRUE,
];
$form['product_rate'] = [
'#type' => 'number',
'#title' => $this
->t('Default product shipping rate'),
'#min' => 0,
'#step' => 'any',
'#description' => $this
->t('The percentage of the item price to add to the shipping cost for an item.'),
'#default_value' => $this->configuration['product_rate'],
'#field_suffix' => $this
->t('% (percent)'),
'#required' => TRUE,
];
$form['field'] = [
'#type' => 'select',
'#title' => $this
->t('Product shipping rate override field'),
'#description' => $this
->t('Overrides the default shipping rate per product for this percentage rate shipping method, when the field is attached to a product content type and has a value.'),
'#options' => $fields,
'#default_value' => $this->configuration['field'],
];
return $form;
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['base_rate'] = $form_state
->getValue('base_rate');
$this->configuration['product_rate'] = $form_state
->getValue('product_rate');
$this->configuration['field'] = $form_state
->getValue('field');
}
public function getDescription() {
return $this
->t('USPS Web Tools® rate');
}
public function getDisplayLabel($label) {
$build['image'] = [
'#theme' => 'image',
'#uri' => drupal_get_path('module', 'uc_usps') . '/images/uc_usps_logo.jpg',
'#alt' => $this
->t('U.S.P.S. logo'),
'#attributes' => [
'class' => [
'usps-logo',
],
],
];
$build['label'] = [
'#plain_text' => preg_replace('/^U\\.S\\.P\\.S\\./', '', $label),
];
return $build;
}
public function getQuotes(OrderInterface $order) {
$rate = $this->configuration['base_rate'];
$field = $this->configuration['field'];
foreach ($order->products as $product) {
if (isset($product->nid->entity->{$field}->value)) {
$product_rate = $product->nid->entity->{$field}->value * $product->qty->value;
}
else {
$product_rate = $this->configuration['product_rate'] * $product->qty->value;
}
$rate += $product->price->value * floatval($product_rate) / 100;
}
return [
$rate,
];
}
protected function packageProducts(array $products, array $addresses) {
$last_key = 0;
$packages = [];
$usps_config = \Drupal::config('uc_usps.settings');
if ($usps_config
->get('all_in_one') && count($products) > 1) {
$packages[$last_key] = [
0 => $this
->newPackage(),
];
foreach ($products as $product) {
if ($product->nid->value) {
$key = NULL;
$address = uc_quote_get_default_shipping_address($product->nid->value);
foreach ($addresses as $index => $value) {
if ($address
->isSamePhysicalLocation($value)) {
$key = $index;
break;
}
}
if (!isset($key)) {
$addresses[++$last_key] = $address;
$key = $last_key;
$packages[$key] = [
0 => $this
->newPackage(),
];
}
}
$temp = Node::load($product->nid->value);
$product->length = $temp->length->value;
$product->width = $temp->width->value;
$product->height = $temp->height->value;
$product->length_units = $temp->length_units;
$product->usps['container'] = isset($temp->usps['container']) ? $temp->usps['container'] : 'VARIABLE';
$packages[$key][0]->price += $product->price * $product->qty;
$packages[$key][0]->weight += $product->weight * $product->qty * uc_weight_conversion($product->weight_units, 'lb');
}
foreach ($packages as $key => $package) {
$packages[$key][0]->pounds = floor($package[0]->weight);
$packages[$key][0]->ounces = LB_TO_OZ * ($package[0]->weight - $packages[$key][0]->pounds);
$packages[$key][0]->container = 'VARIABLE';
$packages[$key][0]->size = 'REGULAR';
$packages[$key][0]->machinable = ($packages[$key][0]->pounds == 0 ? $packages[$key][0]->ounces >= 6 : TRUE) && $packages[$key][0]->pounds <= 35 && ($packages[$key][0]->pounds == 35 ? $packages[$key][0]->ounces == 0 : TRUE);
$packages[$key][0]->qty = 1;
}
}
else {
foreach ($products as $product) {
if ($product->nid) {
$address = uc_quote_get_default_shipping_address($product->nid);
if (in_array($address, $addresses)) {
foreach ($addresses as $index => $value) {
if ($address == $value) {
$key = $index;
break;
}
}
}
else {
$addresses[++$last_key] = $address;
$key = $last_key;
}
}
if (!isset($product->pkg_qty) || !$product->pkg_qty) {
$product->pkg_qty = 1;
}
$num_of_pkgs = (int) ($product->qty / $product->pkg_qty);
if ($num_of_pkgs) {
$package = clone $product;
$package->description = $product->model;
$weight = $product->weight * $product->pkg_qty;
switch ($product->weight_units) {
case 'g':
$weight = $weight * G_TO_KG;
case 'kg':
$weight = $weight * KG_TO_LB;
case 'lb':
$package->pounds = floor($weight);
$package->ounces = LB_TO_OZ * ($weight - $package->pounds);
break;
case 'oz':
$package->pounds = floor($weight * OZ_TO_LB);
$package->ounces = $weight - $package->pounds * LB_TO_OZ;
break;
}
$temp = Node::load($product->nid);
$product->length = $temp->length;
$product->width = $temp->width;
$product->height = $temp->height;
$product->length_units = $temp->length_units;
$product->usps['container'] = isset($temp->usps['container']) ? $temp->usps['container'] : 'VARIABLE';
$package->container = $product->usps['container'];
$length_conversion = uc_length_conversion($product->length_units, 'in');
$package->length = max($product->length, $product->width) * $length_conversion;
$package->width = min($product->length, $product->width) * $length_conversion;
$package->height = $product->height * $length_conversion;
if ($package->length < $package->height) {
list($package->length, $package->height) = [
$package->height,
$package->length,
];
}
$package->girth = 2 * $package->width + 2 * $package->height;
$package->size = $package->length <= 12 ? 'REGULAR' : 'LARGE';
$package->machinable = $package->length >= 6 && $package->length <= 34 && $package->width >= 0.25 && $package->width <= 17 && $package->height >= 3.5 && $package->height <= 17 && ($package->pounds == 0 ? $package->ounces >= 6 : TRUE) && $package->pounds <= 35 && ($package->pounds == 35 ? $package->ounces == 0 : TRUE);
$package->price = $product->price * $product->pkg_qty;
$package->qty = $num_of_pkgs;
$packages[$key][] = $package;
}
$remaining_qty = $product->qty % $product->pkg_qty;
if ($remaining_qty) {
$package = clone $product;
$package->description = $product->model;
$weight = $product->weight * $remaining_qty;
switch ($product->weight_units) {
case 'g':
$weight = $weight * G_TO_KG;
case 'kg':
$weight = $weight * KG_TO_LB;
case 'lb':
$package->pounds = floor($weight);
$package->ounces = LB_TO_OZ * ($weight - $package->pounds);
break;
case 'oz':
$package->pounds = floor($weight * OZ_TO_LB);
$package->ounces = $weight - $package->pounds * LB_TO_OZ;
break;
}
$package->container = $product->usps['container'];
$length_conversion = uc_length_conversion($product->length_units, 'in');
$package->length = max($product->length, $product->width) * $length_conversion;
$package->width = min($product->length, $product->width) * $length_conversion;
$package->height = $product->height * $length_conversion;
if ($package->length < $package->height) {
list($package->length, $package->height) = [
$package->height,
$package->length,
];
}
$package->girth = 2 * $package->width + 2 * $package->height;
$package->size = $package->length <= 12 ? 'REGULAR' : 'LARGE';
$package->machinable = $package->length >= 6 && $package->length <= 34 && $package->width >= 0.25 && $package->width <= 17 && $package->height >= 3.5 && $package->height <= 17 && ($package->pounds == 0 ? $package->ounces >= 6 : TRUE) && $package->pounds <= 35 && ($package->pounds == 35 ? $package->ounces == 0 : TRUE);
$package->price = $product->price * $remaining_qty;
$package->qty = 1;
$packages[$key][] = $package;
}
}
}
return $packages;
}
protected function newPackage() {
$package = new \stdClass();
$package->price = 0;
$package->qty = 1;
$package->pounds = 0;
$package->ounces = 0;
$package->container = 0;
$package->size = 0;
$package->machinable = TRUE;
$package->length = 0;
$package->width = 0;
$package->height = 0;
$package->girth = 0;
return $package;
}
protected function rateMarkup($rate) {
$usps_config = \Drupal::config('uc_usps.settings');
$markup = trim($usps_config
->get('rate_markup'));
$type = $usps_config
->get('rate_markup_type');
if (is_numeric($markup)) {
switch ($type) {
case 'percentage':
return $rate + $rate * floatval($markup) / 100;
case 'multiplier':
return $rate * floatval($markup);
case 'currency':
return $rate + floatval($markup);
}
}
else {
return $rate;
}
}
protected function weightMarkup($weight) {
$usps_config = \Drupal::config('uc_usps.settings');
$markup = trim($usps_config
->get('weight_markup'));
$type = $usps_config
->get('weight_markup_type');
if (is_numeric($markup)) {
switch ($type) {
case 'percentage':
return $weight + $weight * floatval($markup) / 100;
case 'multiplier':
return $weight * floatval($markup);
case 'mass':
return $weight + floatval($markup);
}
}
else {
return $weight;
}
}
public function quote($products, $details, $method) {
$usps_config = \Drupal::config('uc_usps.settings');
$quote_config = \Drupal::config('uc_quote.settings');
$destination = (object) $details;
if (empty($destination->country)) {
return [];
}
if ($destination->country == 'US' && (empty($destination->zone) || empty($destination->postal_code))) {
return [];
}
$connection_url = 'http://production.shippingapis.com/ShippingAPI.dll';
$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') {
$request = $this
->intlRateRequest($ship_packages, $orig, $destination);
}
elseif ($destination->country == 'US') {
$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";
}
$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));
$service_markup = [
'<sup>&reg;</sup>' => '®',
'<sup>&trade;</sup>' => '™',
'<sup>®</sup>' => '®',
'<sup>™</sup>' => '™',
'**' => '',
];
if (strpos($method['id'], 'intl')) {
foreach ($response
->xpath('//Service') as $service) {
$service->SvcDescription = str_replace(array_keys($service_markup), $service_markup, $service->SvcDescription);
}
}
else {
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,
]);
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,
]);
if ($rate_type && !empty($postage->CommercialRate)) {
$services[$classid]['rate'] += $this
->rateMarkup((string) $postage->CommercialRate);
}
else {
$services[$classid]['rate'] += $this
->rateMarkup((string) $postage->Rate);
}
}
}
}
}
}
}
$method_services = substr($method['id'] . '_services', 5);
$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');
if (isset($debug_data['debug']) || isset($debug_data['error']) && count($debug_data['error'])) {
$services['data'] = $debug_data;
}
return $services;
}
}