diff --git a/config/schema/commerce_fedex_freight.yml b/config/schema/commerce_fedex_freight.yml new file mode 100644 index 0000000..018d143 --- /dev/null +++ b/config/schema/commerce_fedex_freight.yml @@ -0,0 +1,10 @@ +commerce_fedex.fedex_plugin.plugin.freight: + type: commerce_fedex_service + label: 'Commerce Fedex Freight Service' + mapping: + default_freight_class: + type: string + label: 'Default freight class' + default_packaging_type: + type: string + label: 'Default packaging type' diff --git a/modules/freight/commerce_fedex_freight.info.yml b/modules/freight/commerce_fedex_freight.info.yml new file mode 100644 index 0000000..48b0ecb --- /dev/null +++ b/modules/freight/commerce_fedex_freight.info.yml @@ -0,0 +1,7 @@ +name: 'Commerce FedEx: Freight Shipping (Experimental)' +type: module +description: 'Provides the ability to get FedEx Freight rates for shipments over 150 lbs. WARNING: Experimental! This module is not ready for use.' +package: Commerce (shipping) +core: 8.x +dependencies: + - commerce_fedex diff --git a/modules/freight/commerce_fedex_freight.services.yml b/modules/freight/commerce_fedex_freight.services.yml new file mode 100644 index 0000000..ae6947d --- /dev/null +++ b/modules/freight/commerce_fedex_freight.services.yml @@ -0,0 +1,5 @@ +services: + commerce_fedex_dangerous.fedex_event_subscriber: + class: '\Drupal\commerce_fedex_freight\EventSubscriber\FedExEventSubscriber' + tags: + - { name: 'event_subscriber' } diff --git a/modules/freight/config/schema/commerce_fedex_freight.yml b/modules/freight/config/schema/commerce_fedex_freight.yml new file mode 100644 index 0000000..018d143 --- /dev/null +++ b/modules/freight/config/schema/commerce_fedex_freight.yml @@ -0,0 +1,10 @@ +commerce_fedex.fedex_plugin.plugin.freight: + type: commerce_fedex_service + label: 'Commerce Fedex Freight Service' + mapping: + default_freight_class: + type: string + label: 'Default freight class' + default_packaging_type: + type: string + label: 'Default packaging type' diff --git a/modules/freight/src/EventSubscriber/FedExEventSubscriber.php b/modules/freight/src/EventSubscriber/FedExEventSubscriber.php new file mode 100644 index 0000000..c0780a6 --- /dev/null +++ b/modules/freight/src/EventSubscriber/FedExEventSubscriber.php @@ -0,0 +1,45 @@ +addService('FEDEX_1_DAY_FREIGHT', 'FedEx 1 Day Freight') + ->addService('FEDEX_2_DAY_FREIGHT', 'FedEx 2 Day Freight') + ->addService('FEDEX_3_DAY_FREIGHT', 'FedEx 3 Day Freight') + ->addService('FEDEX_FREIGHT_ECONOMY', 'FedEx Freight Economy') + ->addService('FEDEX_FREIGHT_PRIORITY', 'FedEx Freight Priority'); + } + + /** + * Function getSubscribedEvents. + * + * @return array + * The subscribed events. + */ + public static function getSubscribedEvents() { + $events = []; + $events[CommerceFedExEvents::SERVICES][] = ['onServices']; + + return $events; + } + +} diff --git a/modules/freight/src/Plugin/Commerce/FedEx/FreightPlugin.php b/modules/freight/src/Plugin/Commerce/FedEx/FreightPlugin.php new file mode 100644 index 0000000..a4242f8 --- /dev/null +++ b/modules/freight/src/Plugin/Commerce/FedEx/FreightPlugin.php @@ -0,0 +1,261 @@ + FreightClassType::VALUE_CLASS_050, + 'default_packaging_type' => PhysicalPackagingType::VALUE_BOX, + 'payment_type' => PaymentType::VALUE_SENDER, + 'contact_name' => '', + 'minimum_weight' => 150, + ] + parent::defaultConfiguration(); + + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form = parent::buildConfigurationForm($form, $form_state); + + $form['default_freight_class'] = [ + '#type' => 'select', + '#title' => $this->t('Default freight class'), + '#description' => $this->t('Select the default freight class to use for freight shipments.'), + '#default_value' => $this->configuration['default_freight_class'], + '#options' => $this->getFreightClassOptions(), + ]; + + $form['default_packaging_type'] = [ + '#type' => 'select', + '#title' => $this->t('Default packaging type'), + '#description' => $this->t('Select the default packaging type to use for freight shipments.'), + '#default_value' => $this->configuration['default_packaging_type'], + '#options' => $this->getPackagingTypeOptions(), + ]; + + $form['payment_type'] = [ + '#type' => 'select', + '#title' => $this->t('Payment type'), + '#description' => $this->t('Select the payment type for FedEx Freight shipments'), + '#default_value' => $this->configuration['payment_type'], + '#options' => $this->getPaymentTypeOptions(), + ]; + + $form['contact_name'] = [ + '#type' => 'textfield', + '#title' => $this->t('Contact name'), + '#description' => $this->t('Enter the contact name for FedEx Freight shipments'), + '#default_value' => $this->configuration['contact_name'], + ]; + + $form['minimum_weight'] = [ + '#type' => 'number', + '#title' => $this->t('Minimum weight (lb)'), + '#description' => $this->t('Shipments over this weight will switch to requesting freight shipping.'), + '#default_value' => $this->configuration['minimum_weight'], + ]; + + return $form; + } + + private function getFreightClassOptions() { + return [ + FreightClassType::VALUE_CLASS_050 => $this->t('Class 50'), + FreightClassType::VALUE_CLASS_055 => $this->t('Class 55'), + FreightClassType::VALUE_CLASS_060 => $this->t('Class 60'), + FreightClassType::VALUE_CLASS_065 => $this->t('Class 65'), + FreightClassType::VALUE_CLASS_070 => $this->t('Class 70'), + FreightClassType::VALUE_CLASS_077_5 => $this->t('Class 77.5'), + FreightClassType::VALUE_CLASS_085 => $this->t('Class 85'), + FreightClassType::VALUE_CLASS_092_5 => $this->t('Class 92.5'), + FreightClassType::VALUE_CLASS_100 => $this->t('Class 100'), + FreightClassType::VALUE_CLASS_110 => $this->t('Class 110'), + FreightClassType::VALUE_CLASS_125 => $this->t('Class 125'), + FreightClassType::VALUE_CLASS_150 => $this->t('Class 150'), + FreightClassType::VALUE_CLASS_175 => $this->t('Class 175'), + FreightClassType::VALUE_CLASS_200 => $this->t('Class 200'), + FreightClassType::VALUE_CLASS_250 => $this->t('Class 250'), + FreightClassType::VALUE_CLASS_300 => $this->t('Class 300'), + FreightClassType::VALUE_CLASS_400 => $this->t('Class 400'), + FreightClassType::VALUE_CLASS_500 => $this->t('Class 500'), + ]; + } + + private function getPackagingTypeOptions() { + return [ + PhysicalPackagingType::VALUE_BAG => $this->t('Bag'), + PhysicalPackagingType::VALUE_BARREL => $this->t('Barrel'), + PhysicalPackagingType::VALUE_BASKET => $this->t('Basket'), + PhysicalPackagingType::VALUE_BOX => $this->t('Box'), + PhysicalPackagingType::VALUE_BUCKET => $this->t('Bucket'), + PhysicalPackagingType::VALUE_BUNDLE => $this->t('Bundle'), + PhysicalPackagingType::VALUE_CARTON => $this->t('Carton'), + PhysicalPackagingType::VALUE_CASE => $this->t('Case'), + PhysicalPackagingType::VALUE_CONTAINER => $this->t('Container'), + PhysicalPackagingType::VALUE_CRATE => $this->t('Crate'), + PhysicalPackagingType::VALUE_CYLINDER => $this->t('Cylinder'), + PhysicalPackagingType::VALUE_DRUM => $this->t('Drum'), + PhysicalPackagingType::VALUE_ENVELOPE => $this->t('Envelope'), + PhysicalPackagingType::VALUE_HAMPER => $this->t('Hamper'), + PhysicalPackagingType::VALUE_OTHER => $this->t('Other'), + PhysicalPackagingType::VALUE_PAIL => $this->t('Pail'), + PhysicalPackagingType::VALUE_PALLET => $this->t('Pallet'), + PhysicalPackagingType::VALUE_PIECE => $this->t('Piece'), + PhysicalPackagingType::VALUE_REEL => $this->t('Reel'), + PhysicalPackagingType::VALUE_ROLL => $this->t('Roll'), + PhysicalPackagingType::VALUE_SKID => $this->t('Skid'), + PhysicalPackagingType::VALUE_TANK => $this->t('Tank'), + PhysicalPackagingType::VALUE_TUBE => $this->t('Tube'), + ]; + } + + protected function getPaymentTypeOptions() { + return [ + PaymentType::VALUE_ACCOUNT => $this->t('Account'), + PaymentType::VALUE_COLLECT => $this->t('Collect'), + PaymentType::VALUE_RECIPIENT => $this->t('Recipient'), + PaymentType::VALUE_SENDER => $this->t('Sender'), + PaymentType::VALUE_THIRD_PARTY => $this->t('Third party'), + ]; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + parent::submitConfigurationForm($form, $form_state); + $this->configuration['default_freight_class'] = $form_state->getValue('default_freight_class'); + $this->configuration['default_packaging_type'] = $form_state->getValue('default_packaging_type'); + $this->configuration['payment_type'] = $form_state->getValue('payment_type'); + $this->configuration['contact_name'] = $form_state->getValue('contact_name'); + $this->configuration['minimum_weight'] = $form_state->getValue('minimum_weight'); + } + + /** + * {@inheritdoc} + */ + public function alterRateRequest(RateRequest $rate_request, RateService $rate_service, ShipmentInterface $shipment, $configuration) { + $requestedShipment = $rate_request->getRequestedShipment(); + + if ($requestedShipment) { + $weight = $requestedShipment->getTotalWeight(); + + if (!$weight) { + $weight = $requestedShipment->getRequestedPackageLineItems()[0]->getWeight(); + } + + if ($weight instanceof Weight) { + $weight = new \Drupal\physical\Weight((string) $weight->getValue(), strtolower($weight->getUnits())); + $minimum_weight = $this->configuration['minimum_weight']; + $weight = $weight->convert('lb'); + + if ((float)$weight->getNumber() >= (float)$minimum_weight) { + $requestedShipment + ->setShippingChargesPayment($this->getShippingChargesPayment($shipment, $configuration)) + ->setFreightShipmentDetail($this->getFreightShipmentDetail($requestedShipment, $shipment, $configuration)) + ->setRequestedPackageLineItems([]); + } + } + } + } + + protected function getShippingChargesPayment(ShipmentInterface $shipment, $configuration) { + $party = new Party(); + $party->setAccountNumber($configuration['api_information']['account_number']); + $party->setContact(new Contact($this->configuration['contact_name'])); + $party->setAddress($this->getFreightAddress($shipment->getOrder()->getStore()->getAddress())); + return new Payment($this->configuration['payment_type'], new Payor($party)); + } + + protected function getFreightAddress(AddressInterface $address) { + return new Address( + array_filter([ + $address->getAddressLine1(), + $address->getAddressLine2(), + ]), + $address->getLocality(), + $address->getAdministrativeArea(), + $address->getPostalCode(), + NULL, + $address->getCountryCode(), + NULL, + FALSE + ); + } + + protected function getFreightShipmentDetail(RequestedShipment $requestedShipment, ShipmentInterface $shipment, $configuration) { + $freightDetail = new FreightShipmentDetail(); + + $freightDetail + ->setRole(FreightShipmentRoleType::VALUE_SHIPPER) + ->setCollectTermsType(FreightCollectTermsType::VALUE_STANDARD) + ->setLineItems($this->getFreightShipmentLineItems($requestedShipment, $shipment)) + ->setFedExFreightAccountNumber($configuration['api_information']['account_number']) + ->setFedExFreightBillingContactAndAddress($this->getBillingContactAndAddress($requestedShipment, $shipment)); + + return $freightDetail; + } + + protected function getBillingContactAndAddress(RequestedShipment $requestedShipment, ShipmentInterface $shipment) { + $contactAndAddress = new ContactAndAddress(); + $contactAndAddress + ->setContact(new Contact($this->configuration['contact_name'])) + ->setAddress($this->getFreightAddress($shipment->getOrder()->getStore()->getAddress())); + return $contactAndAddress; + } + + protected function getFreightShipmentLineItems(RequestedShipment $requestedShipment, ShipmentInterface $shipment) { + $weight = $shipment->getWeight(); + $dimensions = FedEx::packageToFedexDimensions($shipment->getPackageType()); + + $lineItem = new FreightShipmentLineItem(); + $lineItem + ->setFreightClass($this->configuration['default_freight_class']) + ->setPackaging($this->configuration['default_packaging_type']) + ->setWeight(FedEx::physicalWeightToFedex($weight)) + ->setDimensions($dimensions); + + return [$lineItem]; + } + +} diff --git a/src/Event/CommerceFedExEvents.php b/src/Event/CommerceFedExEvents.php index 1064b2e..2cb29f4 100644 --- a/src/Event/CommerceFedExEvents.php +++ b/src/Event/CommerceFedExEvents.php @@ -27,4 +27,13 @@ final class CommerceFedExEvents { */ const BEFORE_PACK = 'commerce_fedex.before_pack'; + /** + * Name of the event fired when altering the available shipping services. + * + * @Event + * + * @see \Drupal\commerce_fedex\Event\ServicesEvent.php + */ + const SERVICES = 'commerce_fedex.services'; + } diff --git a/src/Event/RateRequestEvent.php b/src/Event/RateRequestEvent.php index 96a3dad..535dc62 100644 --- a/src/Event/RateRequestEvent.php +++ b/src/Event/RateRequestEvent.php @@ -35,6 +35,13 @@ class RateRequestEvent extends Event { */ protected $shipment; + /** + * The current FedEx plugin configuration values. + * + * @var array + */ + protected $configuration; + /** * Constructs a new BeforePackEvent object. * @@ -45,10 +52,11 @@ class RateRequestEvent extends Event { * @param \Drupal\commerce_shipping\Entity\ShipmentInterface $shipment * The shipment being requested. */ - public function __construct(RateRequest $rate_request, RateService $rate_service, ShipmentInterface $shipment) { + public function __construct(RateRequest $rate_request, RateService $rate_service, ShipmentInterface $shipment, $configuration) { $this->rateRequest = $rate_request; $this->rateService = $rate_service; $this->shipment = $shipment; + $this->configuration = $configuration; } /** @@ -120,4 +128,13 @@ public function setShipment(ShipmentInterface $shipment) { return $this; } + /** + * Gets the FedEx configuration array. + * + * @return array + */ + public function getConfiguration() { + return $this->configuration; + } + } diff --git a/src/Event/ServicesEvent.php b/src/Event/ServicesEvent.php new file mode 100644 index 0000000..960a775 --- /dev/null +++ b/src/Event/ServicesEvent.php @@ -0,0 +1,60 @@ +services = $services; + } + + /** + * Gets the services. + * + * @return \Drupal\commerce_shipping\ShippingService[] + * The services array. + */ + public function getServices() { + return $this->services; + } + + /** + * Sets the services. + * + * @param \Drupal\commerce_shipping\ShippingService[] $services + * The services array. + * + * @return $this + */ + public function setServices(array $services) { + $this->services = $services; + return $this; + } + + public function addService($id, $label) { + $this->services[$id] = new ShippingService($id, $label); + return $this; + } + +} diff --git a/src/Plugin/Commerce/FedEx/FedExPluginBase.php b/src/Plugin/Commerce/FedEx/FedExPluginBase.php index 907c7e8..20fcdf2 100644 --- a/src/Plugin/Commerce/FedEx/FedExPluginBase.php +++ b/src/Plugin/Commerce/FedEx/FedExPluginBase.php @@ -8,6 +8,8 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; +use NicholasCreativeMedia\FedExPHP\Services\RateService; +use NicholasCreativeMedia\FedExPHP\Structs\RateRequest; use NicholasCreativeMedia\FedExPHP\Structs\RequestedPackageLineItem; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -122,4 +124,9 @@ public function splitPackage(array $shipment_items, ShipmentInterface $shipment) return [$shipment_items]; } + /** + * {@inheritdoc} + */ + public function alterRateRequest(RateRequest $rate_request, RateService $rate_service, ShipmentInterface $shipment, $configuration) {} + } diff --git a/src/Plugin/Commerce/FedEx/FedExPluginInterface.php b/src/Plugin/Commerce/FedEx/FedExPluginInterface.php index b375b2e..588a3ae 100644 --- a/src/Plugin/Commerce/FedEx/FedExPluginInterface.php +++ b/src/Plugin/Commerce/FedEx/FedExPluginInterface.php @@ -6,6 +6,8 @@ use Drupal\Component\Plugin\ConfigurableInterface; use Drupal\Component\Plugin\PluginInspectionInterface; use Drupal\Core\Plugin\PluginFormInterface; +use NicholasCreativeMedia\FedExPHP\Services\RateService; +use NicholasCreativeMedia\FedExPHP\Structs\RateRequest; use NicholasCreativeMedia\FedExPHP\Structs\RequestedPackageLineItem; /** @@ -43,4 +45,20 @@ public function adjustPackage(RequestedPackageLineItem $package, array $items, S */ public function splitPackage(array $shipment_items, ShipmentInterface $shipment); + /** + * Function alterRateRequest. + * + * @param RateRequest $rate_request + * The rate request object. + * @param \NicholasCreativeMedia\FedExPHP\Services\RateService $rate_service + * The current rate service object. + * @param \Drupal\commerce_shipping\Entity\ShipmentInterface $shipment + * The current shipment object. + * @param $configuration + * The FedEx plugin configuration array. + * + * @return void + */ + public function alterRateRequest(RateRequest $rate_request, RateService $rate_service, ShipmentInterface $shipment, $configuration); + } diff --git a/src/Plugin/Commerce/FedEx/FreightPlugin.php b/src/Plugin/Commerce/FedEx/FreightPlugin.php new file mode 100644 index 0000000..a4242f8 --- /dev/null +++ b/src/Plugin/Commerce/FedEx/FreightPlugin.php @@ -0,0 +1,261 @@ + FreightClassType::VALUE_CLASS_050, + 'default_packaging_type' => PhysicalPackagingType::VALUE_BOX, + 'payment_type' => PaymentType::VALUE_SENDER, + 'contact_name' => '', + 'minimum_weight' => 150, + ] + parent::defaultConfiguration(); + + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form = parent::buildConfigurationForm($form, $form_state); + + $form['default_freight_class'] = [ + '#type' => 'select', + '#title' => $this->t('Default freight class'), + '#description' => $this->t('Select the default freight class to use for freight shipments.'), + '#default_value' => $this->configuration['default_freight_class'], + '#options' => $this->getFreightClassOptions(), + ]; + + $form['default_packaging_type'] = [ + '#type' => 'select', + '#title' => $this->t('Default packaging type'), + '#description' => $this->t('Select the default packaging type to use for freight shipments.'), + '#default_value' => $this->configuration['default_packaging_type'], + '#options' => $this->getPackagingTypeOptions(), + ]; + + $form['payment_type'] = [ + '#type' => 'select', + '#title' => $this->t('Payment type'), + '#description' => $this->t('Select the payment type for FedEx Freight shipments'), + '#default_value' => $this->configuration['payment_type'], + '#options' => $this->getPaymentTypeOptions(), + ]; + + $form['contact_name'] = [ + '#type' => 'textfield', + '#title' => $this->t('Contact name'), + '#description' => $this->t('Enter the contact name for FedEx Freight shipments'), + '#default_value' => $this->configuration['contact_name'], + ]; + + $form['minimum_weight'] = [ + '#type' => 'number', + '#title' => $this->t('Minimum weight (lb)'), + '#description' => $this->t('Shipments over this weight will switch to requesting freight shipping.'), + '#default_value' => $this->configuration['minimum_weight'], + ]; + + return $form; + } + + private function getFreightClassOptions() { + return [ + FreightClassType::VALUE_CLASS_050 => $this->t('Class 50'), + FreightClassType::VALUE_CLASS_055 => $this->t('Class 55'), + FreightClassType::VALUE_CLASS_060 => $this->t('Class 60'), + FreightClassType::VALUE_CLASS_065 => $this->t('Class 65'), + FreightClassType::VALUE_CLASS_070 => $this->t('Class 70'), + FreightClassType::VALUE_CLASS_077_5 => $this->t('Class 77.5'), + FreightClassType::VALUE_CLASS_085 => $this->t('Class 85'), + FreightClassType::VALUE_CLASS_092_5 => $this->t('Class 92.5'), + FreightClassType::VALUE_CLASS_100 => $this->t('Class 100'), + FreightClassType::VALUE_CLASS_110 => $this->t('Class 110'), + FreightClassType::VALUE_CLASS_125 => $this->t('Class 125'), + FreightClassType::VALUE_CLASS_150 => $this->t('Class 150'), + FreightClassType::VALUE_CLASS_175 => $this->t('Class 175'), + FreightClassType::VALUE_CLASS_200 => $this->t('Class 200'), + FreightClassType::VALUE_CLASS_250 => $this->t('Class 250'), + FreightClassType::VALUE_CLASS_300 => $this->t('Class 300'), + FreightClassType::VALUE_CLASS_400 => $this->t('Class 400'), + FreightClassType::VALUE_CLASS_500 => $this->t('Class 500'), + ]; + } + + private function getPackagingTypeOptions() { + return [ + PhysicalPackagingType::VALUE_BAG => $this->t('Bag'), + PhysicalPackagingType::VALUE_BARREL => $this->t('Barrel'), + PhysicalPackagingType::VALUE_BASKET => $this->t('Basket'), + PhysicalPackagingType::VALUE_BOX => $this->t('Box'), + PhysicalPackagingType::VALUE_BUCKET => $this->t('Bucket'), + PhysicalPackagingType::VALUE_BUNDLE => $this->t('Bundle'), + PhysicalPackagingType::VALUE_CARTON => $this->t('Carton'), + PhysicalPackagingType::VALUE_CASE => $this->t('Case'), + PhysicalPackagingType::VALUE_CONTAINER => $this->t('Container'), + PhysicalPackagingType::VALUE_CRATE => $this->t('Crate'), + PhysicalPackagingType::VALUE_CYLINDER => $this->t('Cylinder'), + PhysicalPackagingType::VALUE_DRUM => $this->t('Drum'), + PhysicalPackagingType::VALUE_ENVELOPE => $this->t('Envelope'), + PhysicalPackagingType::VALUE_HAMPER => $this->t('Hamper'), + PhysicalPackagingType::VALUE_OTHER => $this->t('Other'), + PhysicalPackagingType::VALUE_PAIL => $this->t('Pail'), + PhysicalPackagingType::VALUE_PALLET => $this->t('Pallet'), + PhysicalPackagingType::VALUE_PIECE => $this->t('Piece'), + PhysicalPackagingType::VALUE_REEL => $this->t('Reel'), + PhysicalPackagingType::VALUE_ROLL => $this->t('Roll'), + PhysicalPackagingType::VALUE_SKID => $this->t('Skid'), + PhysicalPackagingType::VALUE_TANK => $this->t('Tank'), + PhysicalPackagingType::VALUE_TUBE => $this->t('Tube'), + ]; + } + + protected function getPaymentTypeOptions() { + return [ + PaymentType::VALUE_ACCOUNT => $this->t('Account'), + PaymentType::VALUE_COLLECT => $this->t('Collect'), + PaymentType::VALUE_RECIPIENT => $this->t('Recipient'), + PaymentType::VALUE_SENDER => $this->t('Sender'), + PaymentType::VALUE_THIRD_PARTY => $this->t('Third party'), + ]; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + parent::submitConfigurationForm($form, $form_state); + $this->configuration['default_freight_class'] = $form_state->getValue('default_freight_class'); + $this->configuration['default_packaging_type'] = $form_state->getValue('default_packaging_type'); + $this->configuration['payment_type'] = $form_state->getValue('payment_type'); + $this->configuration['contact_name'] = $form_state->getValue('contact_name'); + $this->configuration['minimum_weight'] = $form_state->getValue('minimum_weight'); + } + + /** + * {@inheritdoc} + */ + public function alterRateRequest(RateRequest $rate_request, RateService $rate_service, ShipmentInterface $shipment, $configuration) { + $requestedShipment = $rate_request->getRequestedShipment(); + + if ($requestedShipment) { + $weight = $requestedShipment->getTotalWeight(); + + if (!$weight) { + $weight = $requestedShipment->getRequestedPackageLineItems()[0]->getWeight(); + } + + if ($weight instanceof Weight) { + $weight = new \Drupal\physical\Weight((string) $weight->getValue(), strtolower($weight->getUnits())); + $minimum_weight = $this->configuration['minimum_weight']; + $weight = $weight->convert('lb'); + + if ((float)$weight->getNumber() >= (float)$minimum_weight) { + $requestedShipment + ->setShippingChargesPayment($this->getShippingChargesPayment($shipment, $configuration)) + ->setFreightShipmentDetail($this->getFreightShipmentDetail($requestedShipment, $shipment, $configuration)) + ->setRequestedPackageLineItems([]); + } + } + } + } + + protected function getShippingChargesPayment(ShipmentInterface $shipment, $configuration) { + $party = new Party(); + $party->setAccountNumber($configuration['api_information']['account_number']); + $party->setContact(new Contact($this->configuration['contact_name'])); + $party->setAddress($this->getFreightAddress($shipment->getOrder()->getStore()->getAddress())); + return new Payment($this->configuration['payment_type'], new Payor($party)); + } + + protected function getFreightAddress(AddressInterface $address) { + return new Address( + array_filter([ + $address->getAddressLine1(), + $address->getAddressLine2(), + ]), + $address->getLocality(), + $address->getAdministrativeArea(), + $address->getPostalCode(), + NULL, + $address->getCountryCode(), + NULL, + FALSE + ); + } + + protected function getFreightShipmentDetail(RequestedShipment $requestedShipment, ShipmentInterface $shipment, $configuration) { + $freightDetail = new FreightShipmentDetail(); + + $freightDetail + ->setRole(FreightShipmentRoleType::VALUE_SHIPPER) + ->setCollectTermsType(FreightCollectTermsType::VALUE_STANDARD) + ->setLineItems($this->getFreightShipmentLineItems($requestedShipment, $shipment)) + ->setFedExFreightAccountNumber($configuration['api_information']['account_number']) + ->setFedExFreightBillingContactAndAddress($this->getBillingContactAndAddress($requestedShipment, $shipment)); + + return $freightDetail; + } + + protected function getBillingContactAndAddress(RequestedShipment $requestedShipment, ShipmentInterface $shipment) { + $contactAndAddress = new ContactAndAddress(); + $contactAndAddress + ->setContact(new Contact($this->configuration['contact_name'])) + ->setAddress($this->getFreightAddress($shipment->getOrder()->getStore()->getAddress())); + return $contactAndAddress; + } + + protected function getFreightShipmentLineItems(RequestedShipment $requestedShipment, ShipmentInterface $shipment) { + $weight = $shipment->getWeight(); + $dimensions = FedEx::packageToFedexDimensions($shipment->getPackageType()); + + $lineItem = new FreightShipmentLineItem(); + $lineItem + ->setFreightClass($this->configuration['default_freight_class']) + ->setPackaging($this->configuration['default_packaging_type']) + ->setWeight(FedEx::physicalWeightToFedex($weight)) + ->setDimensions($dimensions); + + return [$lineItem]; + } + +} diff --git a/src/Plugin/Commerce/ShippingMethod/FedEx.php b/src/Plugin/Commerce/ShippingMethod/FedEx.php index 84bd96a..414c471 100644 --- a/src/Plugin/Commerce/ShippingMethod/FedEx.php +++ b/src/Plugin/Commerce/ShippingMethod/FedEx.php @@ -6,6 +6,7 @@ use Drupal\address\Plugin\Field\FieldType\AddressItem; use Drupal\commerce_fedex\Event\CommerceFedExEvents; use Drupal\commerce_fedex\Event\RateRequestEvent; +use Drupal\commerce_fedex\Event\ServicesEvent; use Drupal\commerce_fedex\FedExAddressResolver; use Drupal\commerce_fedex\FedExRequestInterface; use Drupal\commerce_fedex\FedExPluginManager; @@ -17,6 +18,7 @@ use Drupal\commerce_shipping\Plugin\Commerce\ShippingMethod\ShippingMethodBase; use Drupal\commerce_shipping\ShipmentItem; use Drupal\commerce_shipping\ShippingRate; +use Drupal\Core\Annotation\Translation; use Drupal\Core\Form\SubformState; use Drupal\Core\Plugin\DefaultLazyPluginCollection; use Drupal\physical\Volume; @@ -27,12 +29,18 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\state_machine\WorkflowManagerInterface; use NicholasCreativeMedia\FedExPHP\Enums\DropoffType; +use NicholasCreativeMedia\FedExPHP\Enums\FreightClassType; +use NicholasCreativeMedia\FedExPHP\Enums\FreightShipmentRoleType; use NicholasCreativeMedia\FedExPHP\Enums\LinearUnits; +use NicholasCreativeMedia\FedExPHP\Enums\PackagingType; use NicholasCreativeMedia\FedExPHP\Enums\PhysicalPackagingType; use NicholasCreativeMedia\FedExPHP\Enums\RateRequestType; +use NicholasCreativeMedia\FedExPHP\Enums\ServiceType; use NicholasCreativeMedia\FedExPHP\Services\RateService; use NicholasCreativeMedia\FedExPHP\Structs\Address; use NicholasCreativeMedia\FedExPHP\Structs\Dimensions; +use NicholasCreativeMedia\FedExPHP\Structs\FreightShipmentDetail; +use NicholasCreativeMedia\FedExPHP\Structs\FreightShipmentLineItem; use NicholasCreativeMedia\FedExPHP\Structs\Money; use NicholasCreativeMedia\FedExPHP\Structs\Party; use NicholasCreativeMedia\FedExPHP\Structs\RequestedPackageLineItem; @@ -174,6 +182,11 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition } $this->updatePlugins()->getPlugins(); + + // Allow other modules to alter the available services + $servicesEvent = new ServicesEvent($this->services); + $this->eventDispatcher->dispatch(CommerceFedExEvents::SERVICES, $servicesEvent); + $this->services = $servicesEvent->getServices(); } /** @@ -214,6 +227,7 @@ public function defaultConfiguration() { 'insurance' => FALSE, 'rate_multiplier' => 1.0, 'round' => PHP_ROUND_HALF_UP, + 'service_type' => '', 'log' => [], ], 'plugins' => [], @@ -574,6 +588,17 @@ public static function enumToList(array $enums) { }, $enums)); } + protected function getShipper(AddressInterface $address) { + $party = $this->getAddressForFedEx($address); + + if (isset($this->configuration['api_information']['account_number'])) { + $accountNumber = $this->configuration['api_information']['account_number']; + $party->setAccountNumber($accountNumber); + } + + return $party; + } + /** * Gets a FedEx address object from the provided Drupal address object. * @@ -813,7 +838,7 @@ protected function getFedExShipment(ShipmentInterface $shipment) { $fedex_shipment = new RequestedShipment(); $fedex_shipment - ->setShipper($this->getAddressForFedEx($shipper_address)) + ->setShipper($this->getShipper($shipper_address)) ->setRecipient($this->getAddressForFedEx($recipient_address)) ->setRequestedPackageLineItems($line_items) ->setPackageCount($count) @@ -892,8 +917,14 @@ protected function getRateRequest(RateService $rate_service, ShipmentInterface $ $rate_request->setRequestedShipment($this->getFedExShipment($shipment)); $rate_request->setVersion($rate_service->version); + foreach ($this->fedExServiceManager->getDefinitions() as $plugin_id => $definition) { + /** @var \Drupal\commerce_fedex\Plugin\Commerce\FedEx\FedExPluginInterface $plugin */ + $plugin = $this->plugins->get($plugin_id); + $plugin->alterRateRequest($rate_request, $rate_service, $shipment, $this->configuration); + } + // Allow other modules to alter the rate request before it's submitted. - $rateRequestEvent = new RateRequestEvent($rate_request, $rate_service, $shipment); + $rateRequestEvent = new RateRequestEvent($rate_request, $rate_service, $shipment, $this->configuration); $this->eventDispatcher->dispatch(CommerceFedExEvents::BEFORE_RATE_REQUEST, $rateRequestEvent); return $rate_request;