Order.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. <?php
  2. namespace Dotdigitalgroup\Email\Model\Sync;
  3. /**
  4. * Sync Orders.
  5. */
  6. class Order
  7. {
  8. /**
  9. * @var \Dotdigitalgroup\Email\Model\ResourceModel\Contact\CollectionFactory
  10. */
  11. public $contactCollectionFactory;
  12. /**
  13. * @var array
  14. */
  15. private $accounts = [];
  16. /**
  17. * @var string
  18. */
  19. private $apiUsername;
  20. /**
  21. * @var string
  22. */
  23. private $apiPassword;
  24. /**
  25. * Global number of orders.
  26. *
  27. * @var int
  28. */
  29. public $countOrders = 0;
  30. /**
  31. * @var array
  32. */
  33. private $orderIds;
  34. /**
  35. * @var \Dotdigitalgroup\Email\Helper\Data
  36. */
  37. private $helper;
  38. /**
  39. * @var \Dotdigitalgroup\Email\Model\ResourceModel\Contact
  40. */
  41. private $contactResource;
  42. /**
  43. * @var \Dotdigitalgroup\Email\Model\OrderFactory
  44. */
  45. private $orderFactory;
  46. /**
  47. * @var \Magento\Sales\Model\OrderFactory
  48. */
  49. private $salesOrderFactory;
  50. /**
  51. * @var \Dotdigitalgroup\Email\Model\Connector\OrderFactory
  52. */
  53. private $connectorOrderFactory;
  54. /**
  55. * @var \Dotdigitalgroup\Email\Model\Connector\AccountFactory
  56. */
  57. private $accountFactory;
  58. /**
  59. * @var \Dotdigitalgroup\Email\Model\ImporterFactory
  60. */
  61. private $importerFactory;
  62. /**
  63. * @var \Dotdigitalgroup\Email\Model\ResourceModel\Order
  64. */
  65. private $orderResource;
  66. /**
  67. * @var array
  68. */
  69. public $guests = [];
  70. /**
  71. * Order constructor.
  72. * @param \Dotdigitalgroup\Email\Model\ImporterFactory $importerFactory
  73. * @param \Dotdigitalgroup\Email\Model\OrderFactory $orderFactory
  74. * @param \Dotdigitalgroup\Email\Model\Connector\AccountFactory $accountFactory
  75. * @param \Dotdigitalgroup\Email\Model\Connector\OrderFactory $connectorOrderFactory
  76. * @param \Dotdigitalgroup\Email\Model\ResourceModel\Contact $contactResource
  77. * @param \Dotdigitalgroup\Email\Model\ResourceModel\Contact\CollectionFactory $contactCollectionFactory
  78. * @param \Dotdigitalgroup\Email\Model\ResourceModel\Order $orderResource
  79. * @param \Dotdigitalgroup\Email\Helper\Data $helper
  80. * @param \Magento\Sales\Model\OrderFactory $salesOrderFactory
  81. *
  82. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  83. */
  84. public function __construct(
  85. \Dotdigitalgroup\Email\Model\ImporterFactory $importerFactory,
  86. \Dotdigitalgroup\Email\Model\OrderFactory $orderFactory,
  87. \Dotdigitalgroup\Email\Model\Connector\AccountFactory $accountFactory,
  88. \Dotdigitalgroup\Email\Model\Connector\OrderFactory $connectorOrderFactory,
  89. \Dotdigitalgroup\Email\Model\ResourceModel\Contact $contactResource,
  90. \Dotdigitalgroup\Email\Model\ResourceModel\Contact\CollectionFactory $contactCollectionFactory,
  91. \Dotdigitalgroup\Email\Model\ResourceModel\Order $orderResource,
  92. \Dotdigitalgroup\Email\Helper\Data $helper,
  93. \Magento\Sales\Model\OrderFactory $salesOrderFactory
  94. ) {
  95. $this->importerFactory = $importerFactory;
  96. $this->orderFactory = $orderFactory;
  97. $this->accountFactory = $accountFactory;
  98. $this->connectorOrderFactory = $connectorOrderFactory;
  99. $this->contactResource = $contactResource;
  100. $this->orderResource = $orderResource;
  101. $this->helper = $helper;
  102. $this->salesOrderFactory = $salesOrderFactory;
  103. $this->contactCollectionFactory = $contactCollectionFactory;
  104. }
  105. /**
  106. * Initial sync the transactional data.
  107. *
  108. * @return array
  109. *
  110. * @throws \Magento\Framework\Exception\LocalizedException
  111. */
  112. public function sync()
  113. {
  114. $response = ['success' => true, 'message' => 'Done.'];
  115. // Initialise a return hash containing results of our sync attempt
  116. $this->searchWebsiteAccounts();
  117. foreach ($this->accounts as $account) {
  118. $orders = $account->getOrders();
  119. $ordersForSingleSync = $account->getOrdersForSingleSync();
  120. $numOrders = count($orders);
  121. $numOrdersForSingleSync = count($ordersForSingleSync);
  122. $website = $account->getWebsites();
  123. $this->countOrders += $numOrders;
  124. $this->countOrders += $numOrdersForSingleSync;
  125. //create bulk
  126. if ($numOrders) {
  127. $this->helper->log('--------- Order sync ---------- : ' . $numOrders);
  128. //queue order into importer
  129. $this->importerFactory->create()
  130. ->registerQueue(
  131. \Dotdigitalgroup\Email\Model\Importer::IMPORT_TYPE_ORDERS,
  132. $orders,
  133. \Dotdigitalgroup\Email\Model\Importer::MODE_BULK,
  134. $website[0]
  135. );
  136. }
  137. //create single
  138. if ($numOrdersForSingleSync) {
  139. $this->createSingleImports($ordersForSingleSync, $website);
  140. }
  141. //mark the orders as imported
  142. $this->orderResource->setImported($this->orderIds);
  143. unset($this->accounts[$account->getApiUsername()]);
  144. }
  145. /**
  146. * Add guests to contact table.
  147. */
  148. if (! empty($this->guests)) {
  149. $orderEmails = array_keys($this->guests);
  150. $guestsEmailFound = $this->contactCollectionFactory->create()
  151. ->addFieldToFilter('email', ['in' => $orderEmails])
  152. ->getColumnValues('email');
  153. //remove the contacts that already exists
  154. foreach ($guestsEmailFound as $email) {
  155. unset($this->guests[strtolower($email)]);
  156. }
  157. //insert new guests contacts
  158. $this->contactResource->insertGuests($this->guests);
  159. //mark the existing contacts with is guest in bulk
  160. $this->contactResource->updateContactsAsGuests($guestsEmailFound);
  161. }
  162. if ($this->countOrders) {
  163. $response['message'] = 'Orders updated ' . $this->countOrders;
  164. }
  165. return $response;
  166. }
  167. /**
  168. * Search the configuration data per website.
  169. *
  170. * @throws \Magento\Framework\Exception\LocalizedException
  171. *
  172. * @return null
  173. */
  174. public function searchWebsiteAccounts()
  175. {
  176. $websites = $this->helper->getWebsites();
  177. foreach ($websites as $website) {
  178. $apiEnabled = $this->helper->isEnabled($website);
  179. $storeIds = $website->getStoreIds();
  180. // api and order sync should be enabled, skip website with no store ids
  181. if ($apiEnabled && $this->helper->getWebsiteConfig(
  182. \Dotdigitalgroup\Email\Helper\Config::XML_PATH_CONNECTOR_SYNC_ORDER_ENABLED,
  183. $website
  184. )
  185. && !empty($storeIds)
  186. ) {
  187. $this->apiUsername = $this->helper->getApiUsername($website);
  188. $this->apiPassword = $this->helper->getApiPassword($website);
  189. // limit for orders included to sync
  190. $limit = $this->helper->getWebsiteConfig(
  191. \Dotdigitalgroup\Email\Helper\Config::XML_PATH_CONNECTOR_TRANSACTIONAL_DATA_SYNC_LIMIT,
  192. $website
  193. );
  194. //set account for later use
  195. if (! isset($this->accounts[$this->apiUsername])) {
  196. $account = $this->accountFactory->create();
  197. $account->setApiUsername($this->apiUsername);
  198. $account->setApiPassword($this->apiPassword);
  199. $this->accounts[$this->apiUsername] = $account;
  200. }
  201. $pendingOrders = $this->getPendingConnectorOrders($website, $limit);
  202. if (! empty($pendingOrders)) {
  203. $this->accounts[$this->apiUsername]->setOrders($pendingOrders);
  204. }
  205. $this->accounts[$this->apiUsername]->setWebsites($website->getId());
  206. $modifiedOrders = $this->getModifiedOrders($website, $limit);
  207. if (! empty($modifiedOrders)) {
  208. $this->accounts[$this->apiUsername]->setOrdersForSingleSync($modifiedOrders);
  209. }
  210. }
  211. }
  212. }
  213. /**
  214. * @param \Magento\Store\Api\Data\WebsiteInterface $website
  215. * @param int $limit
  216. *
  217. * @return array
  218. */
  219. public function getPendingConnectorOrders($website, $limit = 100)
  220. {
  221. $orders = [];
  222. $storeIds = $website->getStoreIds();
  223. /** @var \Dotdigitalgroup\Email\Model\Order $orderModel */
  224. $orderModel = $this->orderFactory->create();
  225. //get order statuses set in configuration section
  226. $orderStatuses = $this->helper->getConfigSelectedStatus($website);
  227. //no active store for website
  228. if (empty($storeIds) || empty($orderStatuses)) {
  229. return [];
  230. }
  231. //pending order from email_order
  232. $orderCollection = $orderModel->getOrdersToImport($storeIds, $limit, $orderStatuses);
  233. //no orders found
  234. if (! $orderCollection->getSize()) {
  235. return $orders;
  236. }
  237. $orders = $this->mappOrderData($orderCollection, $orderModel, $orders);
  238. return $orders;
  239. }
  240. /**
  241. * @param \Magento\Store\Api\Data\WebsiteInterface $website
  242. * @param int $limit
  243. *
  244. * @return array
  245. */
  246. protected function getModifiedOrders($website, $limit)
  247. {
  248. $orders = [];
  249. $storeIds = $website->getStoreIds();
  250. /** @var \Dotdigitalgroup\Email\Model\Order $orderModel */
  251. $orderModel = $this->orderFactory->create();
  252. //get order statuses set in configuration section
  253. $orderStatuses = $this->helper->getConfigSelectedStatus($website);
  254. //no active store for website
  255. if (empty($storeIds) || empty($orderStatuses)) {
  256. return [];
  257. }
  258. //pending order from email_order
  259. $orderCollection = $orderModel->getModifiedOrdersToImport($storeIds, $limit, $orderStatuses);
  260. //no orders found
  261. if (! $orderCollection->getSize()) {
  262. return $orders;
  263. }
  264. $orders = $this->mappOrderData($orderCollection, $orderModel, $orders);
  265. return $orders;
  266. }
  267. /**
  268. * @param \Dotdigitalgroup\Email\Model\ResourceModel\Order\Collection $orderCollection
  269. * @param \Dotdigitalgroup\Email\Model\Order $orderModel
  270. * @param array $orders
  271. *
  272. * @return array
  273. */
  274. protected function mappOrderData($orderCollection, $orderModel, $orders)
  275. {
  276. $orderIds = $orderCollection->getColumnValues('order_id');
  277. //get the order collection
  278. $salesOrderCollection = $orderModel->getSalesOrdersWithIds($orderIds);
  279. foreach ($salesOrderCollection as $order) {
  280. if ($order->getId()) {
  281. $storeId = $order->getStoreId();
  282. $websiteId = $this->helper->storeManager->getStore($storeId)->getWebsiteId();
  283. /**
  284. * Add guest to array to add to contacts table.
  285. */
  286. if ($order->getCustomerIsGuest() && $order->getCustomerEmail()) {
  287. $email = $order->getCustomerEmail();
  288. $this->guests[strtolower($email)] = [
  289. 'email' => $email,
  290. 'website_id' => $websiteId,
  291. 'store_id' => $storeId,
  292. 'is_guest' => 1
  293. ];
  294. }
  295. $connectorOrder = $this->connectorOrderFactory->create();
  296. $connectorOrder->setOrderData($order);
  297. $orders[] = $connectorOrder;
  298. }
  299. $this->orderIds[] = $order->getId();
  300. }
  301. return $orders;
  302. }
  303. /**
  304. * @param array $ordersForSingleSync
  305. * @param array $website
  306. *
  307. * @return null
  308. */
  309. protected function createSingleImports($ordersForSingleSync, $website)
  310. {
  311. foreach ($ordersForSingleSync as $order) {
  312. //register in queue with importer
  313. $this->importerFactory->create()
  314. ->registerQueue(
  315. \Dotdigitalgroup\Email\Model\Importer::IMPORT_TYPE_ORDERS,
  316. $order,
  317. \Dotdigitalgroup\Email\Model\Importer::MODE_SINGLE,
  318. $website[0]
  319. );
  320. }
  321. }
  322. }