diff --git a/modules/dangerous/src/Plugin/Commerce/EntityTrait/PurchasableEntityDangerousGoods.php b/modules/dangerous/src/Plugin/Commerce/EntityTrait/PurchasableEntityDangerousGoods.php index 34555eb..1a94bd9 100644 --- a/modules/dangerous/src/Plugin/Commerce/EntityTrait/PurchasableEntityDangerousGoods.php +++ b/modules/dangerous/src/Plugin/Commerce/EntityTrait/PurchasableEntityDangerousGoods.php @@ -5,7 +5,9 @@ use Drupal\commerce\Plugin\Commerce\EntityTrait\EntityTraitBase; use Drupal\commerce_fedex\Plugin\Commerce\ShippingMethod\FedEx; use Drupal\entity\BundleFieldDefinition; +use Drupal\Core\Field\FieldStorageDefinitionInterface; use NicholasCreativeMedia\FedExPHP\Enums\DangerousGoodsAccessibilityType; +use NicholasCreativeMedia\FedExPHP\Enums\HazardousCommodityOptionType; /** * Provides the "fedex_dangerous" trait. @@ -25,13 +27,23 @@ public function buildFieldDefinitions() { $id = $this->getPluginId(); $fields[$id . '_accessibility'] = BundleFieldDefinition::create('list_string') - ->setLabel($this->t('Require Dangerous Goods/Hazardous Materials Shipping')) + ->setLabel($this->t('Require Dangerous Goods Shipping')) ->setCardinality(1) ->setSetting('allowed_values', [0 => "None"] + FedEx::enumToList(DangerousGoodsAccessibilityType::getValidValues())) ->setDisplayOptions('form', [ 'type' => 'options_select', 'weight' => 95, ]); + + $fields[$id . '_options'] = BundleFieldDefinition::create('list_string') + ->setLabel($this->t('Dangerous Goods Options')) + ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) + ->setSetting('allowed_values', FedEx::enumToList(HazardousCommodityOptionType::getValidValues())) + ->setDisplayOptions('form', [ + 'type' => 'options_select', + 'weight' => 96, + ]); + return $fields; } diff --git a/modules/dangerous/src/Plugin/Commerce/FedEx/DangerousGoodsPlugin.php b/modules/dangerous/src/Plugin/Commerce/FedEx/DangerousGoodsPlugin.php index 358c7f8..bba7268 100644 --- a/modules/dangerous/src/Plugin/Commerce/FedEx/DangerousGoodsPlugin.php +++ b/modules/dangerous/src/Plugin/Commerce/FedEx/DangerousGoodsPlugin.php @@ -6,8 +6,19 @@ use Drupal\commerce_shipping\Entity\ShipmentInterface; use Drupal\commerce_shipping\ShipmentItem; use Drupal\Core\Form\FormStateInterface; +use NicholasCreativeMedia\FedExPHP\Enums\HazardousCommodityOptionType; +use NicholasCreativeMedia\FedExPHP\Enums\HazardousCommodityPackingGroupType; +use NicholasCreativeMedia\FedExPHP\Enums\HazardousCommodityQuantityType; +use NicholasCreativeMedia\FedExPHP\Enums\HazardousContainerPackingType; use NicholasCreativeMedia\FedExPHP\Enums\PackageSpecialServiceType; +use NicholasCreativeMedia\FedExPHP\Enums\RadioactiveContainerClassType; +use NicholasCreativeMedia\FedExPHP\Structs\DangerousGoodsContainer; use NicholasCreativeMedia\FedExPHP\Structs\DangerousGoodsDetail; +use NicholasCreativeMedia\FedExPHP\Structs\HazardousCommodityContent; +use NicholasCreativeMedia\FedExPHP\Structs\HazardousCommodityDescription; +use NicholasCreativeMedia\FedExPHP\Structs\HazardousCommodityInnerReceptacleDetail; +use NicholasCreativeMedia\FedExPHP\Structs\HazardousCommodityPackingDetail; +use NicholasCreativeMedia\FedExPHP\Structs\HazardousCommodityQuantityDetail; use NicholasCreativeMedia\FedExPHP\Structs\PackageSpecialServicesRequested; use NicholasCreativeMedia\FedExPHP\Structs\RequestedPackageLineItem; @@ -58,37 +69,79 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s * {@inheritdoc} */ public function adjustPackage(RequestedPackageLineItem $package, array $shipment_items, ShipmentInterface $shipment) { - $status = $this->getDangerousStatus(reset($shipment_items)); + $dangerous_goods = $this->getDangerousGoodsItems($shipment_items); + if (!empty($dangerous_goods)) { + /** @var ShipmentItem $item */ + $item = reset($dangerous_goods); + $status = $this->getDangerousStatus($item); + $special_services_requested = $package->getSpecialServicesRequested(); + if (empty($special_services_requested)) { + $special_services_requested = new PackageSpecialServicesRequested(); + } + $special_services_requested->addToSpecialServiceTypes(PackageSpecialServiceType::VALUE_DANGEROUS_GOODS); + $dangerous_goods_detail = $special_services_requested->getDangerousGoodsDetail(); + if (empty($dangerous_goods_detail)) { + $dangerous_goods_detail = new DangerousGoodsDetail(); + } + $dangerous_goods_detail->setOptions($this->getDangerousOptions($dangerous_goods)); + if ($this->isHazardous($dangerous_goods)) { + $commodity = new HazardousCommodityContent(); - if ($status === static::NOT_DANGEROUS) { - return $package; - } + $description = new HazardousCommodityDescription(); + $description->setLabelText($item->getTitle()); + $description->setId((string) $item->getOrderItemId()); + $description->setSequenceNumber(1); + $description->setPackingGroup(HazardousCommodityPackingGroupType::VALUE_DEFAULT); + $description->setPackingDetails(new HazardousCommodityPackingDetail(FALSE)); + $commodity->setDescription($description); - $special_services_requested = $package->getSpecialServicesRequested(); - if (empty($special_services_requested)) { - $special_services_requested = new PackageSpecialServicesRequested(); - } - $special_services_requested->addToSpecialServiceTypes(PackageSpecialServiceType::VALUE_DANGEROUS_GOODS); - $dangerous_goods_detail = $special_services_requested->getDangerousGoodsDetail(); - if (empty($dangerous_goods_detail)) { - $dangerous_goods_detail = new DangerousGoodsDetail(); + $container = new DangerousGoodsContainer(); + $container->addToHazardousCommodities($commodity); + $container->setNumberOfContainers(1); + $container->setPackingType(HazardousContainerPackingType::VALUE_ALL_PACKED_IN_ONE); + $dangerous_goods_detail->addToContainers($container); + } else { + $dangerous_goods_detail->setAccessibility($status); + } + $special_services_requested->setDangerousGoodsDetail($dangerous_goods_detail); + $package->setSpecialServicesRequested($special_services_requested); } - $dangerous_goods_detail->setAccessibility($status); - $special_services_requested->setDangerousGoodsDetail($dangerous_goods_detail); - $package->setSpecialServicesRequested($special_services_requested); - return $package; } + /** + * Determines if the shipment items contain hazardous materials. + * + * @param array $shipment_items + * The shipment items to check. + * + * @return bool + * TRUE if hazardous, FALSE otherwise. + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + */ + protected function isHazardous(array $shipment_items) { + $options = $this->getDangerousOptions($shipment_items); + return array_search(HazardousCommodityOptionType::VALUE_HAZARDOUS_MATERIALS, $options) !== FALSE; + } + /** * {@inheritdoc} */ public function splitPackage(array $shipment_items, ShipmentInterface $shipment) { $packages = []; + $main_package = []; foreach ($shipment_items as $shipment_item) { - $packages[$this->getDangerousStatus($shipment_item)][] = $shipment_item; + if ($this->getDangerousStatus($shipment_item) === self::NOT_DANGEROUS) { + $main_package[] = $shipment_item; + } else { + $packages[][] = $shipment_item; + } + } + if (!empty($main_package)) { + $packages = [$main_package] + $packages; } - return array_values($packages); + return $packages; } /** @@ -99,6 +152,8 @@ public function splitPackage(array $shipment_items, ShipmentInterface $shipment) * * @return mixed * The DG status. + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException */ protected function getDangerousStatus(ShipmentItem $shipment_item) { $storage = \Drupal::entityTypeManager()->getStorage('commerce_order_item'); @@ -111,4 +166,53 @@ protected function getDangerousStatus(ShipmentItem $shipment_item) { return $purchased_entity->get('fedex_dangerous_accessibility')->value; } + /** + * Gets only the dangerous goods items from a list of shipment items. + * + * @param array $shipment_items + * All of the shipment items. + * + * @return array + * The dangerous goods items from the shipment items list. + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + */ + protected function getDangerousGoodsItems(array $shipment_items) { + $dangerous_items = []; + foreach ($shipment_items as $shipment_item) { + if ($this->getDangerousStatus($shipment_item) !== self::NOT_DANGEROUS) { + $dangerous_items[] = $shipment_item; + } + } + return $dangerous_items; + } + + /** + * Gets the type of this dangerous goods item. + * + * @param ShipmentItem[] $shipment_items + * The item to check. + * + * @return mixed + * 'dangerous', 'hazardous', or FALSE. + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + */ + protected function getDangerousOptions(array $shipment_items) { + $storage = \Drupal::entityTypeManager()->getStorage('commerce_order_item'); + $options = []; + $field = 'fedex_dangerous_options'; + foreach ($shipment_items as $shipment_item) { + /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */ + $order_item = $storage->load($shipment_item->getOrderItemId()); + $purchased_entity = $order_item->getPurchasedEntity(); + if ($purchased_entity->hasField($field) && !$purchased_entity->get($field)->isEmpty()) { + foreach ($purchased_entity->get($field)->getValue() as $item) { + $options[] = $item['value']; + } + } + } + + return array_unique($options); + } } diff --git a/src/Plugin/Commerce/ShippingMethod/FedEx.php b/src/Plugin/Commerce/ShippingMethod/FedEx.php index 84bd96a..3a074c1 100644 --- a/src/Plugin/Commerce/ShippingMethod/FedEx.php +++ b/src/Plugin/Commerce/ShippingMethod/FedEx.php @@ -482,7 +482,7 @@ public function calculateRates(ShipmentInterface $shipment) { } } - if (in_array($highest_severity, $allowed_severities)) { + if (in_array($highest_severity, $allowed_severities) && is_array($response->getRateReplyDetails())) { $multiplier = (!empty($this->configuration['options']['rate_multiplier'])) ? $this->configuration['options']['rate_multiplier'] : 1.0;