SynchronizeEdifactOrders.php

PHOTO EMBED

Thu Jan 06 2022 14:52:48 GMT+0000 (UTC)

Saved by @igor #drupal #php

<?php

namespace Drupal\stormtextil_synchronization\Controller;

use Drupal\commerce_shipping\Entity\Shipment;
use Drupal\commerce_shipping\Entity\ShippingMethod;
use Drupal\commerce_shipping\ShipmentItem;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\physical\Weight;
use Drupal\physical\WeightUnit;
use Drupal\profile\Entity\Profile;
use EDI\Parser;
use Drupal\commerce_price\Price;
use Drupal\commerce_order\Entity\OrderItem;
use Drupal\commerce_order\Entity\Order;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class Synchronize Edifact Orders.
 *
 * @package Drupal\stormtextil_synchronization\Controller
 */
class SynchronizeEdifactOrders extends ControllerBase {

  /**
   * The time service.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $config;

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

  /**
   * Constructs Synchronize Edifact Orders.
   *
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The Time service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   * @param \Psr\Log\LoggerInterface $logger
   *   Logger interface.
   */
  public function __construct(TimeInterface $time, ConfigFactoryInterface $configFactory, LoggerInterface $logger) {
    $this->time = $time;
    $this->config = $configFactory;
    $this->logger = $logger;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('datetime.time'),
      $container->get('config.factory'),
      $container->get('logger.channel.default')
    );
  }

  /**
   * Parse the edi file and create an order.
   *
   * @return string[]|void
   *   Response.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   * @throws \Drupal\Core\TypedData\Exception\MissingDataException
   */
  public function parse() {
    // Login information.
    $login_data = $this->config->get('stormtextil_config.settings');
    $ftp_server = $login_data->get('edifact')['server'];
    $ftp_user = $login_data->get('edifact')['username'];
    $ftp_pass = $login_data->get('edifact')['password'];
    // Set up a connection or die.
    $ftp = ftp_connect($ftp_server) or die("Couldn't connect to $ftp_server");
    // Try to login.
    if (ftp_login($ftp, $ftp_user, $ftp_pass)) {
      echo "Connected as $ftp_user@$ftp_server\n";
    }
    else {
      echo "Couldn't connect as $ftp_user\n";
    }
    // Turn passive mode on,
    // e have to use passive mode because the,
    // running docker container is listening on a different port.
    ftp_set_option($ftp, FTP_USEPASVADDRESS, FALSE);
    ftp_pasv($ftp, TRUE);
    // Listing all companies in root folder.
    $companies = ftp_nlist($ftp, '/');
    foreach ($companies as $company) {
      // Check if this is a valid C5 ID.
      if (is_numeric(basename($company))) {
        $company_id = basename($company);
      }
      // Listing all files in stores directory.
      $files = ftp_nlist($ftp, './' . $company_id . '/archive/');
      foreach ($files as $file) {
        if ((preg_match('/^.*\.(edi)$/i', $file))) {
          // Edi file for proceeding the order.
          $ediFile = file_get_contents('ftp://' . $ftp_user . ':' . $ftp_pass . '@' . $ftp_server . '/'
            . $company_id . '/archive/' . basename($file));
          // Parsing the file.
          $parser = new Parser();
          $parsedEdiFile = $parser->loadString($ediFile);

          $lineItems = [];
          $orderItems = [];
          // Looping through all parsed EDI elements and taking
          // data for order information.
          foreach ($parsedEdiFile as $ediElement) {
            switch ($ediElement[0]) {
              // Delivery information.
              case 'NAD':
                if ($ediElement[1] == 'DP') {
                  $organization = $ediElement[3][0];
                  $address_line1 = $ediElement[3][1];
                  $postal_local = explode(" ", $ediElement[3][2]);
                  $postal_code = $postal_local[0];
                  $locality = $postal_local[1];
                  $country_code = $ediElement[3][3];
                }
                elseif ($ediElement[1] == 'BY') {
                  $billing_address = $ediElement[5];
                  $billing_city = $ediElement[6];
                  $billing_company = $ediElement[4];
                  $billing_zip_code = $ediElement[8];
                };
                break;

              // Name that we are going to use in shipment profile.
              case 'CTA':
                $name = explode(" ", $ediElement[2][1]);
                $given_name = $name[0];
                $family_name = $name[1];
                break;

              // Currency code.
              case 'CUX':
                $currency = $ediElement[1][1];
                break;

              // Tax percentage.
              case 'TAX':
                if (!isset($tax)) {
                  $tax = $ediElement[5][3] / 100;
                }
                break;

              // Name of shipping method.
              case 'ALC':
                $shipping_method_name = $ediElement[2];
                break;

              // Shipping price.
              case 'MOA':
                if ($ediElement[1][0] == '8') {
                  $shipping_price = $ediElement[1][1];
                }
                break;

              // Line item variation.
              case 'PIA':
                if ($ediElement[1] == '5') {
                  $sku = $ediElement[2][0];
                  $rawProductVariation = $this->entityTypeManager()
                    ->getStorage('commerce_product_variation')
                    ->loadByProperties([
                      'sku' => $sku,
                    ]);
                  $productVariation = reset($rawProductVariation);
                  $lineItems[$productVariation->getTitle()]['variation'] = $productVariation;
                }
                break;

              // Line item quantity.
              case 'QTY':
                $quantity = $ediElement[1][1];
                $lineItems[$productVariation->getTitle()]['quantity'] = $quantity;
                break;

              // Line item price.
              case 'PRI':
                if ($ediElement[1][0] == 'AAA') {
                  $price = $ediElement[1][1];
                  $lineItems[$productVariation->getTitle()]['price'] = $price;
                }
                break;

              // Number of line items.
              case 'CNT':
                $numberOfLineItems = $ediElement[1][1];
                break;
            }
          }

          // Creating order items.
          foreach ($lineItems as $lineItem) {
            $orderItem = OrderItem::create([
              'type' => 'default',
              'purchased_entity' => $lineItem['variation'],
              'quantity' => $lineItem['quantity'],
              'unit_price' => new Price($lineItem['price'], $currency),
              'overridden_unit_price' => TRUE,
            ]);
            $orderItem->save();
            $orderItems[] = $orderItem;
          }
          // Creating order.
          $order = Order::create([
            'type' => 'default',
            'mail' => $this->currentUser()->getEmail(),
            'uid' => $this->currentUser()->id(),
            'store_id' => 1,
            'order_items' => [$orderItems[0], $orderItems[1]],
            'placed' => $this->time->getCurrentTime(),
          ]);
          $order->save();
          // Creating shipment.
          if ($order->get('shipments')->count() == 0) {
            $first_shipment = Shipment::create([
              'type' => 'default',
              'order_id' => $order->id(),
              'title' => 'Shipment',
              'state' => 'ready',
            ]);
            $first_shipment->save();
          }
          // Caclculating weight for shipment.
          foreach ($orderItems as $order_item) {
            $quantity = $order_item->getQuantity();
            $purchased_entity = $order_item->getPurchasedEntity();

            if ($purchased_entity->get('weight')->isEmpty()) {
              $weight = new Weight(1, WeightUnit::GRAM);
            }
            else {
              $weight_item = $purchased_entity->get('weight')->first();
              $weight = $weight_item->toMeasurement();
            }
            // Creating shipment item.
            $shipment_item = new ShipmentItem([
              'order_item_id' => $order_item->id(),
              'title' => $purchased_entity->label(),
              'quantity' => $quantity,
              'weight' => $weight->multiply($quantity),
              'declared_value' => $order_item->getTotalPrice(),
            ]);
            $first_shipment->addItem($shipment_item);
          }
          // Creating shipping method.
          $shipping_method = ShippingMethod::create([
            'stores' => 1,
            'name' => $shipping_method_name,
            'plugin' => [
              'target_plugin_id' => 'flat_rate',
              'target_plugin_configuration' => [
                'rate_label' => 'Shipping GG',
                'rate_amount' => [
                  'number' => $shipping_price,
                  'currency_code' => $currency,
                ],
              ],
            ],
            'status' => TRUE,
            'weight' => 0,
          ]);
          $shipping_method->save();
          // Adding newly created shipment method to shipment.
          $first_shipment->setShippingMethod($shipping_method);
          // Adding amount to shipment.
          $shipping_method_plugin = $shipping_method->getPlugin();
          $shipping_rates = $shipping_method_plugin->calculateRates($first_shipment);
          $shipping_rate = reset($shipping_rates);
          $shipping_service = $shipping_rate->getService()->getId();
          $amount = reset($shipping_rates)->getAmount();
          $first_shipment->setAmount($amount);
          $first_shipment->save();

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

          // Creating shipment profile using data from EDI file.
          $shipment_profile = Profile::create([
            'uid' => $order->getCustomerId(),
            'type' => 'customer',
          ]);
          $shipment_profile->address->given_name = $given_name;
          $shipment_profile->set('field_contact_person', implode(" ", $name));
          $shipment_profile->address->family_name = $family_name;
          $shipment_profile->address->organization = $organization;
          $shipment_profile->set('field_company', $organization);
          $shipment_profile->address->country_code = $country_code;
          $shipment_profile->set('field_new_country', $country_code);
          $shipment_profile->address->locality = $locality;
          $shipment_profile->set('field_city', $locality);
          $shipment_profile->address->postal_code = $postal_code;
          $shipment_profile->set('field_zip_code', $postal_code);
          $shipment_profile->address->address_line1 = $address_line1;
          $shipment_profile->set('field_address_1', $address_line1);
          $shipment_profile->save();
          $first_shipment->setShippingProfile($shipment_profile);
          $first_shipment->setShippingService($shipping_service);
          $first_shipment->save();
          $order->set('shipments', $first_shipment);
          // Create a billing profile.
          if (empty($order->getBillingProfile())) {
            $billing_profile = Profile::create([
              'type' => 'customer',
              'uid' => $order->getCustomerId(),
            ]);
            $billing_profile->save();
            $billing_profile->set('field_address_1', $billing_address);
            $billing_profile->set('field_city', $billing_city);
            $billing_profile->set('field_company', $billing_company);
            $billing_profile->set('field_zip_code', $billing_zip_code);
            $billing_profile->save();
            $order->setBillingProfile($billing_profile);
            $order->save();
          }
          // Including tax into price.
          $priceWithTax = $order->getTotalPrice()->getNumber() + ($order->getTotalPrice()->getNumber() * $tax);
          $order->set('total_price', new Price(round($priceWithTax, 2), $currency));
          $order->save();
          // Checking the number of line items.
          if ($numberOfLineItems == count($orderItems)) {
            $poruka = 'Order created.';
          }
          else {
            $poruka = 'Order was not created.';
          }
          // @todo Ovo će trebati da se otkomentariše u nekom momentu.
          // ftp_delete($ftp, $file);.
          return [
            '#markup' => $poruka,
          ];
        }
        else {
          // @todo Create a logic for putting wrong files in the error directory.
          $this->logger->error('Wrong file format');
        }
      }
    }
    // Closing ftp connection.
    ftp_close($ftp);
  }

}
content_copyCOPY