You are here

protected function USPSRateBase::packageProducts in Ubercart 8.4

Organizes products into packages for shipment.

Parameters

OrderProduct[] $products: An array of product objects as they are represented in the cart or order.

Address[] $addresses: Reference to an array of addresses which are the pickup locations of each package. They are determined from the shipping addresses of their component products.

Return value

array Array of packaged products. Packages are separated by shipping address, weight or quantity limits imposed by the shipping method or the products.

3 calls to USPSRateBase::packageProducts()
USPSDomesticRate::quote in shipping/uc_usps/src/Plugin/Ubercart/ShippingQuote/USPSDomesticRate.php
Callback for retrieving USPS shipping quote.
USPSInternationalRate::quote in shipping/uc_usps/src/Plugin/Ubercart/ShippingQuote/USPSInternationalRate.php
Callback for retrieving USPS shipping quote.
USPSRateBase::quote in shipping/uc_usps/src/Plugin/Ubercart/ShippingQuote/USPSRateBase.php
Callback for retrieving USPS shipping quote.

File

shipping/uc_usps/src/Plugin/Ubercart/ShippingQuote/USPSRateBase.php, line 136

Class

USPSRateBase
Common functionality for USPS shipping quotes plugins.

Namespace

Drupal\uc_usps\Plugin\Ubercart\ShippingQuote

Code

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) {

    // "All in one" packaging strategy.
    // Only need to do this if more than one product line item in order.
    $packages[$last_key] = [
      0 => $this
        ->newPackage(),
    ];
    foreach ($products as $product) {
      if ($product->nid->value) {

        // Packages are grouped by the address from which they will be
        // shipped. We will keep track of the different addresses in an array
        // and use their keys for the array of packages.
        $key = NULL;
        $address = uc_quote_get_default_shipping_address($product->nid->value);
        foreach ($addresses as $index => $value) {
          if ($address
            ->isSamePhysicalLocation($value)) {

            // This is an existing address.
            $key = $index;
            break;
          }
        }
        if (!isset($key)) {

          // This is a new address. Increment the address counter $last_key
          // instead of using [] so that it can be used in $packages and
          // $addresses.
          $addresses[++$last_key] = $address;
          $key = $last_key;
          $packages[$key] = [
            0 => $this
              ->newPackage(),
          ];
        }
      }

      // Grab some product properties directly from the (cached) product
      // data. They are not normally available here because the $product
      // object is being read out of the $order object rather than from
      // the database, and the $order object only carries around a limited
      // number of product properties.
      $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 are "machinable" if heavier than 6oz. and less than 35lbs.
      $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 {

    // !$usps_config->get('all_in_one') || count($products) = 1
    // "Each in own" packaging strategy, or only one product line item in order.
    foreach ($products as $product) {
      if ($product->nid) {
        $address = uc_quote_get_default_shipping_address($product->nid);
        if (in_array($address, $addresses)) {

          // This is an existing address.
          foreach ($addresses as $index => $value) {
            if ($address == $value) {
              $key = $index;
              break;
            }
          }
        }
        else {

          // This is a new address.
          $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':

            // Convert to kg and fall through.
            $weight = $weight * G_TO_KG;
          case 'kg':

            // Convert to lb and fall through.
            $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;
        }

        // Grab some product properties directly from the (cached) product
        // data. They are not normally available here because the $product
        // object is being read out of the $order object rather than from
        // the database, and the $order object only carries around a limited
        // number of product properties.
        $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':

            // Convert to kg and fall through.
            $weight = $weight * G_TO_KG;
          case 'kg':

            // Convert to lb and fall through.
            $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;
}