commerce_amws-8.x-1.x-dev/modules/shipping/src/ShipmentService.php

modules/shipping/src/ShipmentService.php
<?php

namespace Drupal\commerce_amws_shipping;

use Drupal\commerce_amws_order\HelperService;

use Drupal\commerce_order\Adjustment;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_order\Entity\OrderItemInterface;
use Drupal\commerce_price\Price;
use Drupal\commerce_shipping\Entity\ShipmentInterface;
use Drupal\commerce_shipping\ShipmentItem;
use Drupal\physical\WeightUnit;
use Drupal\profile\Entity\ProfileInterface;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;

use Psr\Log\LoggerInterface;

/**
 * Provides functionality related to importing shipping data from Amazon MWS.
 */
class ShipmentService {

  use StringTranslationTrait;

  /**
   * The shipment type used for new shipments.
   */
  const DEFAULT_SHIPMENT_TYPE = 'default';

  /**
   * The shipment state used for new shipments.
   */
  const DEFAULT_SHIPMENT_STATE = 'draft';

  /**
   * The package type used for new shipments.
   */
  const DEFAULT_PACKAGE_TYPE = 'custom_box';

  /**
   * The profile type to be used for creating the order's shipping profile.
   */
  const DEFAULT_SHIPPING_PROFILE_TYPE = 'customer';

  /**
   * The shipping service to be used for new Amazon MWS orders.
   *
   * Hardcoded for now, it should be replaced with configuration at first stage,
   * and ideally later with mapping between Drupal Commerce shipping methods and
   * Amazon MWS shipping services.
   */
  const DEFAULT_SHIPPING_SERVICE = 'default';

  /**
   * The logger.
   *
   * @var \Psr\Logger\LoggerInterface
   */
  protected $logger;

  /**
   * The helper service for converting address information to profile entities.
   *
   * @var \Drupal\commerce_amws_order\HelperService
   */
  protected $orderHelper;

  /**
   * The shipment storage.
   *
   * @var \Drupal\commerce_shipping\ShipmentStorageInterface
   */
  protected $shipmentStorage;

  /**
   * The Amazon MWS shipping configuration.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $shippingConfig;

  /**
   * Constructs a new ShipmentService object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\commerce_amws_order\HelperService $order_helper
   *   The helper service for converting address information to profile
   *   entities.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration object factory.
   * @param \Psr\Logger\LoggerInterface $logger
   *   The logger channel factory.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    HelperService $order_helper,
    ConfigFactoryInterface $config_factory,
    LoggerInterface $logger
  ) {
    $this->shipmentStorage = $entity_type_manager->getStorage('commerce_shipment');
    $this->orderHelper = $order_helper;
    $this->shippingConfig = $config_factory->get('commerce_amws_shipping.settings');
    $this->logger = $logger;
  }

  /**
   * Creates a shipment for an Amazon MWS being imported.
   *
   * The shipping service is defined at the order level by Amazon MWS, even
   * though shipping costs are defined at the order item level. We therefore
   * always create only one shipment per order. Applications can bundle order
   * items in shipments as they wish by adding their own event subscribers.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *   The Drupal Commerce order.
   * @param object $amws_order
   *   The Amazon MWS order object being improted.
   * @param array $amws_order_items
   *   An array containing the Amazon MWS order item objects.
   * @param string $profile_type
   *   The type of the profile that will hold the shipping address.
   */
  public function createShipment(
    OrderInterface $order,
    \stdClass $amws_order,
    array $amws_order_items,
    $profile_type
  ) {
    $amws_address = $amws_order->ShippingAddress;
    if (!$amws_address) {
      throw \InvalidArgumentException(
        'Cannot create a shipment for an order that does not have a shipping address.',
      );
    }

    $shipping_profile = $this->orderHelper->amwsAddressToCustomerProfile(
      $order,
      $amws_address,
      $profile_type,
      FALSE
    );
    $phone_field = $this->shippingConfig->get('phone_field_machine_name');
    if ($phone_field) {
      $shipping_profile->set(
        $phone_field,
        $amws_address->Phone ?? NULL
      );
    }
    $shipping_profile->save();

    $shipment = $this->doCreateShipment(
      $order,
      $amws_order,
      $amws_order_items,
      $shipping_profile
    );

    $order->set('shipments', [$shipment]);
    $order->save();
  }

  /**
   * Performs the actual shipment creation for an Amazon MWS order.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *   The Drupal Commerce order.
   * @param object $amws_order
   *   The Amazon MWS order being improted.
   * @param array $amws_order_items
   *   An array containing the Amazon MWS order item objects.
   * @param \Drupal\profile\Entity\ProfileInterface $shipping_profile
   *   The shipping profile.
   *
   * @return \Drupal\commerce_shipping\Entity\ShipmentInterface
   *   The created shipment.
   */
  protected function doCreateShipment(
    OrderInterface $order,
    \stdClass $amws_order,
    array $amws_order_items,
    ProfileInterface $shipping_profile
  ) {
    $shipment = $this->shipmentStorage->create([
      'type' => self::DEFAULT_SHIPMENT_TYPE,
      'order_id' => $order->id(),
      'package_type' => self::DEFAULT_PACKAGE_TYPE,
      'state' => self::DEFAULT_SHIPMENT_STATE,
    ]);
    $shipment->set('title', 'Shipment');
    $shipment->setShippingProfile($shipping_profile);

    // Shipping method and service.
    $shipping_method_id = $this->shippingConfig->get('shipping_method_id');
    if ($shipping_method_id) {
      $shipment->setShippingMethodId($shipping_method_id);
      $shipment->setShippingService(self::DEFAULT_SHIPPING_SERVICE);
    }
    else {
      $message = sprintf(
        'No appropriate shipping method was found for Amazon MWS order with ID "%s". The ID of the corresponding Drupal Commerce order is "%s".',
        $amws_order->AmazonOrderId,
        $order->id()
      );
      $this->logger->warning($message);
    }

    $shipment->setAmount($this->shippingAmount($amws_order, $amws_order_items));
    $this->doCreateShippingAdjustment($order, $shipment);

    // Shipment items.
    $shipment_items = [];
    foreach ($order->getItems() as $order_item) {
      $shipment_items[] = $this->doCreateShipmentItem($order_item);
    }

    $shipment->setItems($shipment_items);
    $shipment->save();

    return $shipment;
  }

  /**
   * Creates a shipment item for the given order item.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
   *   The order item for which to create the shipment.
   *
   * @return \Drupal\commerce_shipping\ShipmentItem
   *   The created shipment item.
   */
  protected function doCreateShipmentItem(OrderItemInterface $order_item) {
    $quantity = $order_item->getQuantity();

    // Some products may not have weight e.g. gift wraps. We therefore need to
    // create shipment items for them as well with zero weight.
    $purchased_entity = $order_item->getPurchasedEntity();
    if ($purchased_entity->hasField('weight')) {
      $weight = $purchased_entity->get('weight')->first()->toMeasurement();
    }
    else {
      $weight = new Weight('0', WeightUnit::POUND);
    }

    return new ShipmentItem([
      'order_item_id' => $order_item->id(),
      'title' => $order_item->getTitle(),
      'quantity' => $quantity,
      'weight' => $weight->multiply($quantity),
      'declared_value' => $order_item->getUnitPrice()->multiply($quantity),
    ]);
  }

  /**
   * Adds a shipping adjustment to the given order and for the given shipment.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *   The order to which to add the adjustment.
   * @param \Drupal\commerce_shipping\Entity\ShipmentInterface $shipment
   *   The shipment for which the adjustment will be created.
   */
  protected function doCreateShippingAdjustment(
    OrderInterface $order,
    ShipmentInterface $shipment
  ) {
    $amount = $shipment->getAmount();
    if (!$amount || $amount->getNumber() == '0') {
      return;
    }

    $order->addAdjustment(new Adjustment([
      'type' => 'shipping',
      'label' => $this->t('Shipping'),
      'amount' => $amount,
      'source_id' => $shipment->id(),
    ]));
  }

  /**
   * Calculates the shipping amount for the given Amazon MWS order.
   *
   * @param object $amws_order
   *   The Amazon MWS order to calculate the shipping amount for.
   * @param array $amws_order_items
   *   An array containing the Amazon MWS order item objects.
   *
   * @return \Drupal\commerce_price\Price
   *   The shipping amount.
   */
  protected function shippingAmount(
    \stdClass $amws_order,
    array $amws_order_items
  ) {
    $amount = new Price('0', $amws_order->OrderTotal->CurrencyCode);

    // The shipping amount for the order is the sum of the shipping amount for
    // all individual order items.
    foreach ($amws_order_items as $amws_order_item) {
      if (!empty($amws_order_item->ShippingPrice)) {
        $price = new Price(
          $amws_order_item->ShippingPrice->Amount,
          $amws_order_item->ShippingPrice->CurrencyCode
        );
        $amount = $amount->add($price);
      }
      if (!empty($amws_order_item->ShippingDiscount)) {
        $discount = new Price(
          $amws_order_item->ShippingDiscount->Amount,
          $amws_order_item->ShippingDiscount->CurrencyCode
        );
        $amount = $amount->subtract($discount);
      }
    }

    return $amount;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc