Magento1OrderReader.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <?php
  2. namespace App\Services\Asteria;
  3. use Illuminate\Support\Collection;
  4. use Illuminate\Support\Facades\DB;
  5. class Magento1OrderReader
  6. {
  7. private const ORDER_COLUMNS = [
  8. 'entity_id',
  9. 'increment_id',
  10. 'customer_id',
  11. 'customer_email',
  12. 'customer_firstname',
  13. 'customer_lastname',
  14. 'customer_is_guest',
  15. 'status',
  16. 'state',
  17. 'store_id',
  18. 'base_currency_code',
  19. 'order_currency_code',
  20. 'store_currency_code',
  21. 'grand_total',
  22. 'base_grand_total',
  23. 'subtotal',
  24. 'base_subtotal',
  25. 'subtotal_incl_tax',
  26. 'base_subtotal_incl_tax',
  27. 'tax_amount',
  28. 'base_tax_amount',
  29. 'discount_amount',
  30. 'base_discount_amount',
  31. 'shipping_amount',
  32. 'base_shipping_amount',
  33. 'shipping_incl_tax',
  34. 'base_shipping_incl_tax',
  35. 'shipping_tax_amount',
  36. 'base_shipping_tax_amount',
  37. 'shipping_method',
  38. 'shipping_description',
  39. 'shipping_discount_amount',
  40. 'base_shipping_discount_amount',
  41. 'remote_ip',
  42. 'x_forwarded_for',
  43. 'coupon_code',
  44. 'giftcard_id',
  45. 'giftcard_amount',
  46. 'base_giftcard_amount',
  47. 'member_amount',
  48. 'base_member_amount',
  49. 'member_free_amount',
  50. 'base_member_free_amount',
  51. 'mw_rewardpoint',
  52. 'mw_rewardpoint_discount',
  53. 'mw_rewardpoint_discount_show',
  54. 'amcheckoutfees_amount',
  55. 'base_amcheckoutfees_amount',
  56. 'total_item_count',
  57. 'total_qty_ordered',
  58. 'total_invoiced',
  59. 'base_total_invoiced',
  60. 'subtotal_invoiced',
  61. 'base_subtotal_invoiced',
  62. 'tax_invoiced',
  63. 'base_tax_invoiced',
  64. 'shipping_invoiced',
  65. 'base_shipping_invoiced',
  66. 'discount_invoiced',
  67. 'base_discount_invoiced',
  68. 'total_refunded',
  69. 'base_total_refunded',
  70. 'subtotal_refunded',
  71. 'base_subtotal_refunded',
  72. 'tax_refunded',
  73. 'base_tax_refunded',
  74. 'shipping_refunded',
  75. 'base_shipping_refunded',
  76. 'discount_refunded',
  77. 'base_discount_refunded',
  78. 'created_at',
  79. 'updated_at',
  80. ];
  81. private const ITEM_COLUMNS = [
  82. 'item_id',
  83. 'order_id',
  84. 'parent_item_id',
  85. 'product_id',
  86. 'product_type',
  87. 'sku',
  88. 'name',
  89. 'qty_ordered',
  90. 'qty_shipped',
  91. 'qty_invoiced',
  92. 'qty_canceled',
  93. 'qty_refunded',
  94. 'price',
  95. 'base_price',
  96. 'price_incl_tax',
  97. 'base_price_incl_tax',
  98. 'row_total',
  99. 'base_row_total',
  100. 'row_total_incl_tax',
  101. 'base_row_total_incl_tax',
  102. 'tax_amount',
  103. 'base_tax_amount',
  104. 'tax_percent',
  105. 'discount_amount',
  106. 'base_discount_amount',
  107. 'discount_percent',
  108. 'weight',
  109. 'row_weight',
  110. 'product_options',
  111. 'created_at',
  112. ];
  113. private const SHIPMENT_COLUMNS = [
  114. 'entity_id',
  115. 'order_id',
  116. 'increment_id',
  117. 'total_qty',
  118. 'total_weight',
  119. 'email_sent',
  120. 'customer_id',
  121. 'created_at',
  122. 'updated_at',
  123. ];
  124. private const SHIPMENT_ITEM_COLUMNS = [
  125. 'entity_id',
  126. 'parent_id',
  127. 'order_item_id',
  128. 'product_id',
  129. 'sku',
  130. 'name',
  131. 'description',
  132. 'qty',
  133. 'weight',
  134. 'price',
  135. 'row_total',
  136. ];
  137. private const SHIPMENT_TRACK_COLUMNS = [
  138. 'entity_id',
  139. 'parent_id',
  140. 'order_id',
  141. 'track_number',
  142. 'title',
  143. 'carrier_code',
  144. 'created_at',
  145. ];
  146. private const ADDRESS_COLUMNS = [
  147. 'entity_id',
  148. 'parent_id',
  149. 'address_type',
  150. 'firstname',
  151. 'lastname',
  152. 'company',
  153. 'street',
  154. 'city',
  155. 'region',
  156. 'postcode',
  157. 'country_id',
  158. 'telephone',
  159. 'email',
  160. ];
  161. private const PAYMENT_COLUMNS = [
  162. 'entity_id',
  163. 'parent_id',
  164. 'method',
  165. 'last_trans_id',
  166. 'cc_type',
  167. 'cc_last4',
  168. 'amount_ordered',
  169. 'base_amount_ordered',
  170. 'additional_information',
  171. 'protection_eligibility',
  172. 'account_status',
  173. 'address_status',
  174. ];
  175. private Magento1Schema $schema;
  176. public function __construct(private string $connection = 'asteria')
  177. {
  178. $this->schema = new Magento1Schema($connection);
  179. }
  180. /**
  181. * @return Collection<int, array<string, mixed>>
  182. */
  183. public function fetchOrders(int $afterEntityId, int $limit): Collection
  184. {
  185. $columns = $this->schema->existingColumns('sales_flat_order', self::ORDER_COLUMNS);
  186. if ($columns === [] || ! in_array('entity_id', $columns, true)) {
  187. return collect();
  188. }
  189. $rows = DB::connection($this->connection)
  190. ->table('sales_flat_order')
  191. ->where('entity_id', '>', $afterEntityId)
  192. ->orderBy('entity_id')
  193. ->limit($limit)
  194. ->get($columns);
  195. return $rows->map(fn ($row) => $this->toArray($row, 'entity_id'))->values();
  196. }
  197. /**
  198. * @param array<int, int> $orderEntityIds
  199. * @return Collection<int, array<string, mixed>>
  200. */
  201. public function fetchItems(array $orderEntityIds): Collection
  202. {
  203. if ($orderEntityIds === []) {
  204. return collect();
  205. }
  206. $columns = $this->schema->existingColumns('sales_flat_order_item', self::ITEM_COLUMNS);
  207. if ($columns === [] || ! in_array('order_id', $columns, true)) {
  208. return collect();
  209. }
  210. $rows = DB::connection($this->connection)
  211. ->table('sales_flat_order_item')
  212. ->whereIn('order_id', $orderEntityIds)
  213. ->orderBy('item_id')
  214. ->get($columns);
  215. return $rows->map(function ($row) {
  216. $item = $this->toArray($row, 'item_id');
  217. $item['order_id'] = (int) ($row->order_id ?? 0);
  218. $item['parent_item_id'] = isset($row->parent_item_id) && $row->parent_item_id !== null && $row->parent_item_id !== ''
  219. ? (int) $row->parent_item_id
  220. : null;
  221. $item['product_id'] = isset($row->product_id) && $row->product_id !== null && $row->product_id !== ''
  222. ? (int) $row->product_id
  223. : null;
  224. return $item;
  225. })->values();
  226. }
  227. /**
  228. * @param array<int, int> $itemIds
  229. * @return Collection<int, array<string, mixed>>
  230. */
  231. public function fetchItemsByItemIds(array $itemIds): Collection
  232. {
  233. $itemIds = array_values(array_unique(array_filter(array_map('intval', $itemIds))));
  234. if ($itemIds === []) {
  235. return collect();
  236. }
  237. $columns = $this->schema->existingColumns('sales_flat_order_item', self::ITEM_COLUMNS);
  238. if ($columns === [] || ! in_array('item_id', $columns, true)) {
  239. return collect();
  240. }
  241. $rows = collect();
  242. foreach (array_chunk($itemIds, 500) as $chunk) {
  243. $rows = $rows->concat(
  244. DB::connection($this->connection)
  245. ->table('sales_flat_order_item')
  246. ->whereIn('item_id', $chunk)
  247. ->orderBy('item_id')
  248. ->get($columns)
  249. );
  250. }
  251. return $rows->map(function ($row) {
  252. $item = $this->toArray($row, 'item_id');
  253. $item['order_id'] = (int) ($row->order_id ?? 0);
  254. $item['parent_item_id'] = isset($row->parent_item_id) && $row->parent_item_id !== null && $row->parent_item_id !== ''
  255. ? (int) $row->parent_item_id
  256. : null;
  257. $item['product_id'] = isset($row->product_id) && $row->product_id !== null && $row->product_id !== ''
  258. ? (int) $row->product_id
  259. : null;
  260. return $item;
  261. })->values();
  262. }
  263. /**
  264. * Magento catalog SKUs keyed by catalog_product_entity.entity_id.
  265. *
  266. * @param array<int, int> $productIds
  267. * @return array<int, string>
  268. */
  269. public function fetchCatalogSkus(array $productIds): array
  270. {
  271. $productIds = array_values(array_unique(array_filter(array_map('intval', $productIds))));
  272. if ($productIds === [] || ! $this->schema->hasTable('catalog_product_entity')) {
  273. return [];
  274. }
  275. $columns = $this->schema->existingColumns('catalog_product_entity', ['entity_id', 'sku']);
  276. if ($columns === [] || ! in_array('entity_id', $columns, true) || ! in_array('sku', $columns, true)) {
  277. return [];
  278. }
  279. $map = [];
  280. foreach (array_chunk($productIds, 500) as $chunk) {
  281. foreach (
  282. DB::connection($this->connection)
  283. ->table('catalog_product_entity')
  284. ->whereIn('entity_id', $chunk)
  285. ->get($columns) as $row
  286. ) {
  287. $sku = trim((string) ($row->sku ?? ''));
  288. if ($sku === '') {
  289. continue;
  290. }
  291. $map[(int) $row->entity_id] = $sku;
  292. }
  293. }
  294. return $map;
  295. }
  296. /**
  297. * @param array<int, int> $orderEntityIds
  298. * @return Collection<int, array<string, mixed>>
  299. */
  300. public function fetchAddresses(array $orderEntityIds): Collection
  301. {
  302. if ($orderEntityIds === []) {
  303. return collect();
  304. }
  305. $columns = $this->schema->existingColumns('sales_flat_order_address', self::ADDRESS_COLUMNS);
  306. if ($columns === [] || ! in_array('parent_id', $columns, true)) {
  307. return collect();
  308. }
  309. $rows = DB::connection($this->connection)
  310. ->table('sales_flat_order_address')
  311. ->whereIn('parent_id', $orderEntityIds)
  312. ->orderBy('entity_id')
  313. ->get($columns);
  314. return $rows->map(function ($row) {
  315. $address = $this->toArray($row, 'entity_id');
  316. $address['parent_id'] = (int) ($row->parent_id ?? 0);
  317. return $address;
  318. })->values();
  319. }
  320. /**
  321. * @param array<int, int> $orderEntityIds
  322. * @return Collection<int, array<string, mixed>>
  323. */
  324. public function fetchPayments(array $orderEntityIds): Collection
  325. {
  326. if ($orderEntityIds === []) {
  327. return collect();
  328. }
  329. $columns = $this->schema->existingColumns('sales_flat_order_payment', self::PAYMENT_COLUMNS);
  330. if ($columns === [] || ! in_array('parent_id', $columns, true)) {
  331. return collect();
  332. }
  333. $rows = DB::connection($this->connection)
  334. ->table('sales_flat_order_payment')
  335. ->whereIn('parent_id', $orderEntityIds)
  336. ->orderBy('entity_id')
  337. ->get($columns);
  338. return $rows->map(function ($row) {
  339. $payment = $this->toArray($row, 'entity_id');
  340. $payment['parent_id'] = (int) ($row->parent_id ?? 0);
  341. return $payment;
  342. })->values();
  343. }
  344. /**
  345. * MW Reward Points rows keyed later by Magento order entity_id.
  346. *
  347. * @param array<int, int> $orderEntityIds
  348. * @return Collection<int, array<string, mixed>>
  349. */
  350. public function fetchRewardPoints(array $orderEntityIds): Collection
  351. {
  352. if ($orderEntityIds === [] || ! $this->schema->hasTable('mw_reward_point_order')) {
  353. return collect();
  354. }
  355. $columns = $this->schema->existingColumns('mw_reward_point_order', [
  356. 'order_id',
  357. 'reward_point',
  358. 'earn_rewardpoint',
  359. 'money',
  360. 'reward_point_money_rate',
  361. ]);
  362. if ($columns === [] || ! in_array('order_id', $columns, true)) {
  363. return collect();
  364. }
  365. $rows = DB::connection($this->connection)
  366. ->table('mw_reward_point_order')
  367. ->whereIn('order_id', $orderEntityIds)
  368. ->get($columns);
  369. return $rows->map(function ($row) {
  370. $data = $this->toArray($row, 'order_id');
  371. $data['order_id'] = (int) ($row->order_id ?? 0);
  372. return $data;
  373. })->values();
  374. }
  375. /**
  376. * @param array<int, int> $orderEntityIds
  377. * @return Collection<int, array<string, mixed>>
  378. */
  379. public function fetchShipments(array $orderEntityIds): Collection
  380. {
  381. if ($orderEntityIds === [] || ! $this->schema->hasTable('sales_flat_shipment')) {
  382. return collect();
  383. }
  384. $columns = $this->schema->existingColumns('sales_flat_shipment', self::SHIPMENT_COLUMNS);
  385. if ($columns === [] || ! in_array('order_id', $columns, true)) {
  386. return collect();
  387. }
  388. $rows = DB::connection($this->connection)
  389. ->table('sales_flat_shipment')
  390. ->whereIn('order_id', $orderEntityIds)
  391. ->orderBy('entity_id')
  392. ->get($columns);
  393. return $rows->map(function ($row) {
  394. $shipment = $this->toArray($row, 'entity_id');
  395. $shipment['order_id'] = (int) ($row->order_id ?? 0);
  396. return $shipment;
  397. })->values();
  398. }
  399. /**
  400. * @param array<int, int> $shipmentIds
  401. * @return Collection<int, array<string, mixed>>
  402. */
  403. public function fetchShipmentItems(array $shipmentIds): Collection
  404. {
  405. if ($shipmentIds === [] || ! $this->schema->hasTable('sales_flat_shipment_item')) {
  406. return collect();
  407. }
  408. $columns = $this->schema->existingColumns('sales_flat_shipment_item', self::SHIPMENT_ITEM_COLUMNS);
  409. if ($columns === [] || ! in_array('parent_id', $columns, true)) {
  410. return collect();
  411. }
  412. $rows = collect();
  413. foreach (array_chunk($shipmentIds, 500) as $chunk) {
  414. $rows = $rows->concat(
  415. DB::connection($this->connection)
  416. ->table('sales_flat_shipment_item')
  417. ->whereIn('parent_id', $chunk)
  418. ->orderBy('entity_id')
  419. ->get($columns)
  420. );
  421. }
  422. return $rows->map(function ($row) {
  423. $item = $this->toArray($row, 'entity_id');
  424. $item['parent_id'] = (int) ($row->parent_id ?? 0);
  425. $item['order_item_id'] = isset($row->order_item_id) && $row->order_item_id !== null && $row->order_item_id !== ''
  426. ? (int) $row->order_item_id
  427. : null;
  428. return $item;
  429. })->values();
  430. }
  431. /**
  432. * @param array<int, int> $shipmentIds
  433. * @return Collection<int, array<string, mixed>>
  434. */
  435. public function fetchShipmentTracks(array $shipmentIds): Collection
  436. {
  437. if ($shipmentIds === [] || ! $this->schema->hasTable('sales_flat_shipment_track')) {
  438. return collect();
  439. }
  440. $columns = $this->schema->existingColumns('sales_flat_shipment_track', self::SHIPMENT_TRACK_COLUMNS);
  441. if ($columns === [] || ! in_array('parent_id', $columns, true)) {
  442. return collect();
  443. }
  444. $rows = collect();
  445. foreach (array_chunk($shipmentIds, 500) as $chunk) {
  446. $rows = $rows->concat(
  447. DB::connection($this->connection)
  448. ->table('sales_flat_shipment_track')
  449. ->whereIn('parent_id', $chunk)
  450. ->orderBy('entity_id')
  451. ->get($columns)
  452. );
  453. }
  454. return $rows->map(function ($row) {
  455. $track = $this->toArray($row, 'entity_id');
  456. $track['parent_id'] = (int) ($row->parent_id ?? 0);
  457. return $track;
  458. })->values();
  459. }
  460. /**
  461. * @return array<string, mixed>
  462. */
  463. private function toArray(object $row, string $idColumn): array
  464. {
  465. $data = (array) $row;
  466. $data[$idColumn] = (int) ($row->{$idColumn} ?? 0);
  467. return $data;
  468. }
  469. }