![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/app/code/Cnc/Sales/Console/Command/ |
<?php /** * Copyright (c) 2020 Kaliop Digital Commerce (https://digitalcommerce.kaliop.com) All Rights Reserved. * https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * Cnc * Radosław Stępień <[email protected]> <[email protected]> */ namespace Cnc\Sales\Console\Command; use Cnc\Sales\Model\Config as SalesConfig; use Cnc\Store\Model\Config; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DataObject; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Sales\Api\OrderPaymentRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Status\HistoryFactory; use Magento\Store\Model\StoreManagerInterface; use Magento\Customer\Model\CustomerFactory; use Magento\Sales\Model\OrderFactory; use Magento\Sales\Model\Order\ItemFactory; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class ImportOrders extends Command { const TABLE_NAME_ORDER = 'cnc_tmp_orders_migration'; const TABLE_NAME_ORDER_ITEM = 'cnc_tmp_orders_migration_item'; const TABLE_NAME_ORDER_TOTALS = 'cnc_tmp_orders_migration_totals'; const TABLE_NAME_ORDER_STATUS = 'cnc_tmp_orders_migration_status'; private const BATCH_SIZE = 5000; private const VALUE_NOT_MIGRATED = 0; private const VALUE_MIGRATED = 1; private const SHIPPING_METHOD_MAPPING = [ 'homecl_colissimo' => 'colissimo_homecl', 'pickup_colissimo' => 'colissimo_pickup', 'mondialrelaypickup_' => 'mondialrelay_pickup', 'storepickup_storepickup' => 'storepickup_storepickup', 'custom' => 'custom' ]; private const ORDER_STATUS_MAPPING = [ 1 => SalesConfig::ORDER_STATUS_PENDING_PAYMENT_CODE, 2 => SalesConfig::ORDER_STATUS_PAIEMENT_RECU_CODE, 3 => SalesConfig::ORDER_STATUS_EXPEDIE_PAYE_CODE, 4 => SalesConfig::ORDER_STATUS_CANCELED_CODE, 5 => SalesConfig::ORDER_STATUS_COMPLETE_CODE, 6 => SalesConfig::ORDER_STATUS_EXPEDIE_PAIEMENT_30J_CODE, 7 => SalesConfig::ORDER_STATUS_EXPEDIE_PAIEMENT_RECEP_FACTURE_CODE, 8 => SalesConfig::ORDER_STATUS_PROCESSING_CODE, 9 => SalesConfig::ORDER_STATUS_COMPLETE_CODE, 10 => SalesConfig::ORDER_STATUS_COMPLETE_CODE ]; private const ORDER_STATE_MAPPING = [ 1 => Order::STATE_PENDING_PAYMENT, 2 => Order::STATE_PROCESSING, 3 => Order::STATE_PROCESSING, 4 => Order::STATE_CANCELED, 5 => Order::STATE_COMPLETE, 6 => Order::STATE_PROCESSING, 7 => Order::STATE_PROCESSING, 8 => Order::STATE_PROCESSING, 9 => Order::STATE_COMPLETE, 10 => Order::STATE_COMPLETE ]; /** * @var string[] */ private $unsetDataKeys = [ 'orders_date_finished', 'currency', 'currency_value', ]; /** * @var string[] */ private $unsetItemDataKeys = [ 'products_model', 'products_name', 'products_price', 'final_price', 'products_tax', 'products_quantity', 'products_sockage' ]; /** * @var array */ private $remapItemDataKeys = [ 'orders_products_id' => 'item_id', 'orders_id' => 'order_id', 'products_model' => 'sku', 'products_name' => 'name', 'products_price' => 'price', 'final_price' => 'row_total', 'products_tax' => 'tax_amount', 'products_quantity' => 'qty_ordered', 'products_sockage' => 'additional_data', ]; /** * @var array */ private $totalsDataMapping = [ 'ot_total' => 'grand_total', 'ot_tax' => 'tax_amount', 'ot_subtotal' => 'subtotal', 'ot_shipping' => 'shipping_amount', 'ot_coupon' => 'discount_amount' ]; /** * @var ResourceConnection */ private $resourceConnection; /** * @var OrderFactory */ protected $orderFactory; /** * @var ItemFactory */ protected $orderItemFactory; /** * @var StoreManagerInterface */ protected $storeManager; /** * @var CustomerFactory */ protected $customerFactory; /** * @var OrderPaymentRepositoryInterface */ protected $orderPaymentRepository; /** * @var HistoryFactory */ protected $statusHistoryFactory; /** * @var array */ protected $storeData = []; /** * @var array */ private $orderData = []; /** * @var array */ private $itemData = []; /** * @var array */ private $totalsData = []; /** * @var array */ private $statusesData = []; /** * @var array */ private $itemsOrderData = []; /** * @var array */ private $totalsOrderData = []; /** * @var array */ private $statusesOrderData = []; /** * @var array */ private $migratedOrderEntityIds = []; /** * @var array */ private $migratedOrderItemEntityIds = []; /** * @var array */ private $migratedOrderTotalsEntityIds = []; /** * @var array */ private $migratedOrderStatusEntityIds = []; /** * @var array */ protected $addressOrderData = []; /** * @var array */ protected $paymentOrderData = []; private $output; /** * ImportOrders constructor. * @param ResourceConnection $resourceConnection * @param OrderFactory $orderFactory * @param ItemFactory $orderItemFactory * @param StoreManagerInterface $storeManager * @param CustomerFactory $customerFactory * @param OrderPaymentRepositoryInterface $orderPaymentRepository * @param HistoryFactory $statusHistoryFactory * @param string|null $name */ public function __construct( ResourceConnection $resourceConnection, OrderFactory $orderFactory, ItemFactory $orderItemFactory, StoreManagerInterface $storeManager, CustomerFactory $customerFactory, OrderPaymentRepositoryInterface $orderPaymentRepository, HistoryFactory $statusHistoryFactory, string $name = null ) { parent::__construct($name); $this->resourceConnection = $resourceConnection; $this->orderFactory = $orderFactory; $this->orderItemFactory = $orderItemFactory; $this->storeManager = $storeManager; $this->customerFactory = $customerFactory; $this->orderPaymentRepository = $orderPaymentRepository; $this->statusHistoryFactory = $statusHistoryFactory; } /** * Configure command name and desc */ public function configure() { $this->setName('sales:orders_import:create_orders'); $this->setDescription('Import orders data'); parent::configure(); } /** * @param InputInterface $input * @param OutputInterface $output * @return int|void * @throws LocalizedException */ public function execute(InputInterface $input, OutputInterface $output) { $this->output = $output; $this->initCncStoreData(); while ($this->loadData()) { $this->prepareData(); $this->toMagento(); $this->updateIsMigratedFlag(); } } /** * Load data from tmp tables */ protected function loadData() { $ordersSelect = $this->getConnection()->select() ->from($this->getConnection()->getTableName(self::TABLE_NAME_ORDER)) ->where('is_migrated = ?', self::VALUE_NOT_MIGRATED) ->limit(self::BATCH_SIZE); $this->orderData = $this->getConnection()->fetchAll($ordersSelect); $orderIds = array_column($this->orderData, 'orders_id'); if (empty($orderIds)) { $this->output->writeln('Records to migrate not found.'); return; } $this->itemData = $this->fetchMigrationRecords( self::TABLE_NAME_ORDER_ITEM, 'orders_id', $orderIds ); $this->totalsData = $this->fetchMigrationRecords( self::TABLE_NAME_ORDER_TOTALS, 'orders_id', $orderIds ); $this->statusesData = $this->fetchMigrationRecords( self::TABLE_NAME_ORDER_STATUS, 'orders_id', $orderIds ); $this->migratedOrderEntityIds = $orderIds; $this->migratedOrderItemEntityIds = array_column($this->itemData, 'orders_products_id'); $this->migratedOrderTotalsEntityIds = array_column($this->totalsData, 'orders_total_id'); $this->migratedOrderStatusEntityIds = array_column($this->statusesData, 'orders_status_history_id'); return count($this->orderData); } /** * Prepare data structure before import to magento */ protected function prepareData() { $this->output->writeln('Migration New Orders: Started PREPARING DATA...'); //// Get Order Data foreach ($this->orderData as $key => &$dataRow) { $dataRow['created_at'] = strtotime($dataRow['date_purchased']); $dataRow['updated_at'] = strtotime($dataRow['last_modified']); $dataRow['email_sent'] = 0; //// Get Order Address Data $this->addressOrderData[$dataRow['orders_id']]['shipping'] = [ 'firstname' => explode(' ', $dataRow['delivery_name'], 2)[0] ?? '', 'lastname' => explode(' ', $dataRow['delivery_name'], 2)[1] ?? '', 'company' => $dataRow['delivery_company'] ?? '', 'street' => $dataRow['delivery_street_address'] ?? '', 'city' => $dataRow['delivery_city'] ?? '', 'country_id' => $dataRow['delivery_country'] ?? '', 'region' => $dataRow['delivery_state'] ?? '', 'postcode' => $dataRow['delivery_postcode'] ?? '', 'telephone' => $dataRow['customers_telephone'] ?? '', 'telephone_mobile' => $dataRow['customers_telephone'] ?? '' ]; $this->addressOrderData[$dataRow['orders_id']]['billing'] = [ 'firstname' => explode(' ', $dataRow['billing_name'], 2)[0] ?? '', 'lastname' => explode(' ', $dataRow['billing_name'], 2)[1] ?? '', 'company' => $dataRow['billing_company'] ?? '', 'vat_id' => $dataRow['billing_tva_intracom'] ?? '', 'street' => $dataRow['billing_street_address'] ?? '', 'city' => $dataRow['billing_city'] ?? '', 'country_id' => $dataRow['billing_country'] ?? '', 'region' => $dataRow['billing_state'] ?? '', 'postcode' => $dataRow['billing_postcode'] ?? '', 'telephone' => $dataRow['customers_telephone'] ?? '', 'telephone_mobile' => $dataRow['customers_telephone'] ?? '' ]; //// Get Order Payment Data $this->paymentOrderData[$dataRow['orders_id']] = [ 'method' => $dataRow['payment_method'] ?? '', 'cc_exp_month' => $dataRow['cc_expires'] ?? '', 'cc_number_enc' => $dataRow['cc_number'] ?? '', 'cc_owner' => $dataRow['cc_owner'] ?? '', 'cc_type' => $dataRow['cc_type'] ?? '', ]; foreach ($dataRow as $dataRowKey => $dataRowValue) { if (trim($dataRowValue) == '') { unset($dataRow[$dataRowKey]); } } foreach ($this->unsetDataKeys as $unsetDataKey) { if (isset($dataRow[$unsetDataKey])) { unset($dataRow[$unsetDataKey]); } } } //// Get Order Items Data foreach ($this->itemData as &$dataRow) { foreach ($this->remapItemDataKeys as $remapItemDataKey => $remapToItemDataKey) { if (isset($dataRow[$remapItemDataKey])) { $dataRow[$remapToItemDataKey] = $dataRow[$remapItemDataKey]; } } foreach ($this->unsetItemDataKeys as $unsetItemDataKey) { if (isset($dataRow[$unsetItemDataKey])) { unset($dataRow[$unsetItemDataKey]); } } $this->itemsOrderData[$dataRow['orders_id']][$dataRow['orders_products_id']] = $dataRow; } //// Get Order Totals Data foreach ($this->totalsData as $dataRow) { if ($dataRow['class']) { if ($dataRow['class'] == 'ot_coupon') { $dataRow['value'] = '-' . $dataRow['value']; } if (isset($this->totalsDataMapping[$dataRow['class']])) { $this->totalsOrderData[$dataRow['orders_id']][$this->totalsDataMapping[$dataRow['class']]] = $dataRow['value']; } } } //Group statuses updates by orders IDs foreach ($this->statusesData as $dataRow) { if (isset($dataRow['orders_id'])) { $this->statusesOrderData[$dataRow['orders_id']][] = $dataRow; } } $this->output->writeln('Migration New Orders: Ended PREPARING DATA'); } /** * Import data to magento */ protected function toMagento() { $this->output->writeln('Migration New Orders: Started IMPORTING DATA...'); if (count($this->orderData) > 0) { $this->output->writeln(count($this->orderData) . ' orders to be imported'); $newOrdersImported = 0; foreach ($this->orderData as &$dataRow) { try { $isOrderCreated = $this->createMageOrder($dataRow); if ($isOrderCreated) { $newOrdersImported++; } } catch (\Exception $e) { $this->output->writeln($e->getMessage()); } } $this->output->writeln("Imported {$newOrdersImported} new orders"); } else { $this->output->writeln('No Data founded for executing ORDERS IMPORT'); } $this->output->writeln('Migration New Orders: Ended IMPORTING DATA'); } /** * @param $dataRow * @return bool */ protected function createMageOrder($dataRow) { $storeId = $this->storeData['store_id']; $websiteId = $this->storeData['website_id']; $orderId = $dataRow['orders_id']; $customerId = $dataRow['customers_id']; unset($dataRow['orders_id']); unset($dataRow['customers_id']); // load customer by email address if ($this->isEmailValidated($dataRow['customers_email_address'])) { $email = strtolower($dataRow['customers_email_address']); $customer = $this->getCustomerData($customerId, $email); if (!$customer || !$customer->getEntityId()) { $this->output->writeln("Customer with email {$email} / id {$customerId} does Not exist"); return false; } // Load order $order = $this->orderFactory->create()->setStoreId($storeId); // Set customer data $order->setCustomerId($customer->getEntityId()) ->setStoreId($storeId) ->setCustomerEmail($customer->getEmail()) ->setCustomerFirstname($customer->getFirstname()) ->setCustomerLastname($customer->getLastname()) ->setCustomerGroupId($customer->getGroupId()) ->setCustomerIsGuest(0); // Set currency data $order->setGlobalCurrencyCode('EUR') ->setBaseCurrencyCode('EUR') ->setStoreCurrencyCode('EUR') ->setOrderCurrencyCode('EUR'); // Set payment data $orderPayment = $this->orderPaymentRepository->create(); foreach ($this->paymentOrderData[$orderId] as $key => $data) { $orderPayment->setData($key, $data); } $order->setPayment($orderPayment); // Set address data if (array_key_exists($orderId, $this->addressOrderData)) { $customerAddress = $this->addressOrderData[$orderId]; if (array_key_exists('billing', $customerAddress)) { $billingAddressCustomer = $this->addressOrderData[$orderId]['billing']; } else { $this->output->writeln( "Missing order Billing address data for email - {$email} and orderId - {$orderId}", 'warning' ); return false; } if (array_key_exists('shipping', $customerAddress)) { $shippingAddressCustomer = $this->addressOrderData[$orderId]['shipping']; } else { $this->output->writeln( "Missing order Shipping address data for email - {$email} and orderId - {$orderId}", 'warning' ); return false; } //Init object manager here, because of errors with addition object manager instance in // this console command's constructor method $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); $configLoader = $objectManager->get(\Magento\Framework\ObjectManager\ConfigLoaderInterface::class); $objectManager->configure($configLoader->load('frontend')); $billingAddress = $objectManager->create( \Magento\Sales\Model\Order\Address::class, ['data' => $billingAddressCustomer] ); $shippingAddress = $objectManager->create( \Magento\Sales\Model\Order\Address::class, ['data' => $shippingAddressCustomer] ); $order->setBillingAddress($billingAddress); $order->setShippingAddress($shippingAddress); } else { $this->output->writeln("Missing order address data for email - {$email} and orderId - {$orderId}"); return false; } // Set items if (array_key_exists($orderId, $this->itemsOrderData)) { foreach ($this->itemsOrderData[$orderId] as $item) { $orderItem = $this->orderItemFactory->create(); $item['store_id'] = $storeId; $item['product_type'] = 'simple'; unset($item['order_id']); unset($item['item_id']); unset($item['parent_item_id']); unset($item['quote_item_id']); foreach ($item as $key => $data) { $orderItem->setData($key, $data); } $order->addItem($orderItem); } } else { $this->output->writeln("Missing order items data for email - {$email} and orderId - {$orderId}"); return false; } // Set totals if (array_key_exists($orderId, $this->totalsOrderData)) { foreach ($this->totalsOrderData[$orderId] as $key => $value) { $order->setData($key, $value); } } else { $this->output->writeln("Missing totals data for email - {$email} and orderId - {$orderId}"); return false; } //Unset useless data unset($dataRow['entity_id']); unset($dataRow['customer_true_email']); unset($dataRow['quote_id']); unset($dataRow['quote_address_id']); $dataRow['origin_order_id']= $orderId; //Set old orders_id from oscommerce $dataRow['store_id']= $storeId; $dataRow['is_exported']= 1; if ($dataRow['order_canceled']) { $order->setState('canceled'); $order->setStatus('canceled'); } else { $order->setState(self::ORDER_STATE_MAPPING[$dataRow['orders_status']]); $order->setStatus(self::ORDER_STATUS_MAPPING[$dataRow['orders_status']]); } unset($dataRow['orders_status']); // Set all data foreach ($dataRow as $key => $data) { $order->setData($key, $data); } if (isset($this->statusesOrderData[$orderId])) { foreach ($this->statusesOrderData[$orderId] as $statusHistoryItem) { $statusHistory = $this->statusHistoryFactory->create(); $statusHistory->setIsCustomerNotified(0); $statusHistory->setIsVisibleOnFront(0); $statusHistory->setComment($statusHistoryItem['object'] . ' | ' . $statusHistoryItem['comments']); if (isset(self::ORDER_STATUS_MAPPING[$statusHistoryItem['orders_status_id']])) { $statusHistory->setStatus(self::ORDER_STATUS_MAPPING[$statusHistoryItem['orders_status_id']]); } $statusHistory->setCreatedAt($statusHistoryItem['date_added']); $statusHistory->setEntityName(Order::ENTITY); $order->addStatusHistory($statusHistory); } } try { $order->save(); return true; } catch (\Exception $e) { $this->output->writeln("Can't create order for orderId={$orderId} : {$e->getMessage()}"); return false; } } else { $this->output->writeln("Invalid email {$dataRow['customers_email_address']}"); return false; } } /** * Update correctly migrated orders flag */ protected function updateIsMigratedFlag(): void { $this->updateIsMigratedColumn( self::TABLE_NAME_ORDER, 'orders_id', $this->migratedOrderEntityIds ); $this->updateIsMigratedColumn( self::TABLE_NAME_ORDER_ITEM, 'orders_products_id', $this->migratedOrderItemEntityIds ); $this->updateIsMigratedColumn( self::TABLE_NAME_ORDER_TOTALS, 'orders_total_id', $this->migratedOrderTotalsEntityIds ); } /** * @param string $tableName * @param string $columnName * @param array $entityIds */ protected function updateIsMigratedColumn(string $tableName, string $columnName, array $entityIds): void { $this->getConnection()->update( $this->getConnection()->getTableName($tableName), ['is_migrated' => self::VALUE_MIGRATED], ["{$columnName} IN (?)" => array_values($entityIds)] ); } /** * @throws LocalizedException */ protected function initCncStoreData() { $websiteFr = $this->storeManager->getWebsite(Config::DEFAULT_WEBSITE); $websiteId = $websiteFr->getId(); $storeCode = Config::STORE_CODE_FR_EU; // get array of stores with store code as key $stores = $this->storeManager->getStores(true, true); // check stores array for this store code if (isset($stores[$storeCode])) { $storeId = $stores[$storeCode]->getId(); } else { throw new LocalizedException(__("Store Id Not founded for Store Code - $storeCode")); } $this->storeData = [ 'website_code' => Config::DEFAULT_WEBSITE, 'website_id' => $websiteId, 'store_id' => $storeId ]; } /** * @param $email * @return bool */ protected function isEmailValidated($email) { if (!empty($email)) { try { return \Zend_Validate::is($email, 'EmailAddress'); } catch (\Exception $e) { $this->output->writeln($e->getMessage()); return false; } } return false; } /** * @param string $tableName * @param string $orderIdColumnName * @param array $orderIds * @return array */ protected function fetchMigrationRecords(string $tableName, string $orderIdColumnName, array $orderIds): array { $select = $this->getConnection()->select() ->from($this->getConnection()->getTableName($tableName)) ->where('is_migrated = ?', self::VALUE_NOT_MIGRATED) ->where("{$orderIdColumnName} IN (?)", array_values($orderIds)); return $this->getConnection()->fetchAll($select); } /** * @return AdapterInterface */ private function getConnection(): AdapterInterface { return $this->resourceConnection->getConnection(); } /** * @param $customerId * @param $email * @return DataObject|null */ public function getCustomerData($customerId, $email) { $sql = 'SELECT entity_id, email, customer_id, firstname, lastname, group_id FROM customer_entity WHERE customer_id = ' . $customerId; $data = $this->resourceConnection->getConnection()->fetchRow($sql); if (is_array($data) && $data['entity_id']) { return new DataObject($data); } $sql = 'SELECT entity_id, email, customer_id, firstname, lastname FROM customer_entity WHERE email = \'' . $email . '\''; $data = $this->resourceConnection->getConnection()->fetchRow($sql); return (is_array($data) && $data['entity_id']) ? new DataObject($data) : null; } }