RepairMigratedVariantSkusCommandTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. namespace Webkul\BagistoApi\Tests\Unit\Migration;
  3. use Illuminate\Support\Facades\DB;
  4. use Illuminate\Support\Facades\Schema;
  5. use Longyi\Core\Models\ProductOption;
  6. use Longyi\Core\Models\ProductOptionValue;
  7. use Longyi\Core\Models\ProductVariant;
  8. use Webkul\BagistoApi\Tests\BagistoApiTestCase;
  9. use Webkul\Product\Models\Product;
  10. class RepairMigratedVariantSkusCommandTest extends BagistoApiTestCase
  11. {
  12. public function setUp(): void
  13. {
  14. parent::setUp();
  15. if (! Schema::hasColumn('products', 'migrated_from_asteria_id')
  16. || ! Schema::hasTable('product_variants')
  17. || ! Schema::hasTable('product_variant_option_values')
  18. ) {
  19. $this->markTestSkipped('Flexible variant tables are missing.');
  20. }
  21. }
  22. public function test_it_rewrites_sort_order_skus_from_option_value_labels(): void
  23. {
  24. [$product, $variant] = $this->seedVariant('REPAIR-WIG-001', 'REPAIR-WIG-001-1-1', 991900001);
  25. $variantId = (int) $variant->id;
  26. $this->artisan('products:repair-variant-skus', [
  27. '--sku' => 'REPAIR-WIG-001',
  28. ])->assertSuccessful();
  29. $fresh = ProductVariant::query()->find($variantId);
  30. $this->assertNotNull($fresh);
  31. $this->assertSame($variantId, (int) $fresh->id);
  32. $this->assertSame('REPAIR-WIG-001-12IN-1B', $fresh->sku);
  33. $this->assertSame('REPAIR-WIG-001', $product->fresh()->sku);
  34. }
  35. public function test_dry_run_does_not_write_skus(): void
  36. {
  37. [, $variant] = $this->seedVariant('REPAIR-WIG-002', 'REPAIR-WIG-002-1-1', 991900002);
  38. $this->artisan('products:repair-variant-skus', [
  39. '--sku' => 'REPAIR-WIG-002',
  40. '--dry-run' => true,
  41. ])->assertSuccessful();
  42. $this->assertSame('REPAIR-WIG-002-1-1', $variant->fresh()->sku);
  43. }
  44. public function test_it_leaves_products_that_were_not_migrated_from_asteria(): void
  45. {
  46. [, $variant] = $this->seedVariant('REPAIR-WIG-003', 'REPAIR-WIG-003-1-1', null);
  47. $this->artisan('products:repair-variant-skus', [
  48. '--sku' => 'REPAIR-WIG-003',
  49. ])->assertSuccessful();
  50. $this->assertSame('REPAIR-WIG-003-1-1', $variant->fresh()->sku);
  51. }
  52. public function test_it_rewrites_order_invoice_and_shipment_skus(): void
  53. {
  54. [$product, $variant] = $this->seedVariant('REPAIR-WIG-004', 'REPAIR-WIG-004-1-1', 991900004);
  55. $newSku = 'REPAIR-WIG-004-12IN-1B';
  56. $now = now();
  57. $orderId = DB::table('orders')->insertGetId([
  58. 'increment_id' => 'REPAIR-ORD-004',
  59. 'status' => 'processing',
  60. 'is_guest' => 1,
  61. 'created_at' => $now,
  62. 'updated_at' => $now,
  63. ]);
  64. $nativeId = DB::table('order_items')->insertGetId([
  65. 'order_id' => $orderId,
  66. 'product_id' => $product->id,
  67. 'sku' => 'REPAIR-WIG-004-1-1',
  68. 'name' => 'Wig',
  69. 'qty_ordered' => 1,
  70. 'additional' => json_encode([
  71. 'variant_id' => $variant->id,
  72. 'variant_sku' => 'REPAIR-WIG-004-1-1',
  73. 'attributes' => [
  74. 'hair_length' => [
  75. 'attribute_name' => 'Hair Length',
  76. 'option_label' => 'Hair Length',
  77. 'value_label' => '12"',
  78. ],
  79. 'hair_color' => [
  80. 'attribute_name' => 'Hair Color',
  81. 'option_label' => 'Hair Color',
  82. 'value_label' => 'Natural Black',
  83. ],
  84. ],
  85. ], JSON_UNESCAPED_UNICODE),
  86. 'created_at' => $now,
  87. 'updated_at' => $now,
  88. ]);
  89. $migratedId = DB::table('order_items')->insertGetId([
  90. 'order_id' => $orderId,
  91. 'product_id' => $product->id,
  92. 'sku' => 'REPAIR-WIG-004',
  93. 'name' => 'Wig',
  94. 'qty_ordered' => 1,
  95. 'additional' => json_encode([
  96. 'attributes' => [
  97. ['attribute_name' => 'Hair Length', 'option_label' => '12"', 'attribute_type' => 'drop_down'],
  98. ['attribute_name' => 'Free Gift', 'option_label' => 'Yes', 'attribute_type' => 'drop_down'],
  99. ['attribute_name' => 'Hair Color', 'option_label' => 'Natural Black', 'attribute_type' => 'drop_down'],
  100. ],
  101. ], JSON_UNESCAPED_UNICODE),
  102. 'created_at' => $now,
  103. 'updated_at' => $now,
  104. ]);
  105. $invoiceId = DB::table('invoice_items')->insertGetId([
  106. 'order_item_id' => $nativeId,
  107. 'sku' => 'REPAIR-WIG-004-1-1',
  108. 'name' => 'Wig',
  109. 'qty' => 1,
  110. 'created_at' => $now,
  111. 'updated_at' => $now,
  112. ]);
  113. $shipmentId = DB::table('shipment_items')->insertGetId([
  114. 'shipment_id' => 1,
  115. 'order_item_id' => $migratedId,
  116. 'sku' => 'REPAIR-WIG-004',
  117. 'name' => 'Wig',
  118. 'qty' => 1,
  119. 'created_at' => $now,
  120. 'updated_at' => $now,
  121. ]);
  122. $this->artisan('products:repair-variant-skus', [
  123. '--sku' => 'REPAIR-WIG-004',
  124. '--dry-run' => true,
  125. ])->assertSuccessful();
  126. $this->assertSame('REPAIR-WIG-004-1-1', DB::table('order_items')->where('id', $nativeId)->value('sku'));
  127. $this->artisan('products:repair-variant-skus', [
  128. '--sku' => 'REPAIR-WIG-004',
  129. ])->assertSuccessful();
  130. $this->assertSame($newSku, $variant->fresh()->sku);
  131. $this->assertSame($newSku, DB::table('order_items')->where('id', $nativeId)->value('sku'));
  132. $this->assertSame($newSku, DB::table('order_items')->where('id', $migratedId)->value('sku'));
  133. $this->assertSame($newSku, DB::table('invoice_items')->where('id', $invoiceId)->value('sku'));
  134. $this->assertSame($newSku, DB::table('shipment_items')->where('id', $shipmentId)->value('sku'));
  135. $nativeAdditional = json_decode((string) DB::table('order_items')->where('id', $nativeId)->value('additional'), true);
  136. $this->assertSame($newSku, $nativeAdditional['variant_sku']);
  137. $migratedAdditional = json_decode((string) DB::table('order_items')->where('id', $migratedId)->value('additional'), true);
  138. $this->assertArrayNotHasKey('variant_sku', $migratedAdditional);
  139. }
  140. public function test_it_can_reuse_a_sku_held_by_a_variant_renamed_in_a_later_batch(): void
  141. {
  142. $now = now();
  143. $product = new Product;
  144. $product->sku = 'SWAP';
  145. $product->type = 'flexible_variant';
  146. $product->migrated_from_asteria_id = 991900201;
  147. $product->save();
  148. $option = ProductOption::query()->create([
  149. 'label' => 'Length',
  150. 'type' => 'select',
  151. 'code' => 'swap_length',
  152. ]);
  153. DB::table('product_product_options')->insert([
  154. 'product_id' => $product->id,
  155. 'product_option_id' => $option->id,
  156. 'position' => 0,
  157. 'is_required' => 1,
  158. 'created_at' => $now,
  159. 'updated_at' => $now,
  160. ]);
  161. $count = 201;
  162. $valueIds = [];
  163. for ($i = 0; $i < $count; $i++) {
  164. $valueIds[] = DB::table('product_option_values')->insertGetId([
  165. 'product_option_id' => $option->id,
  166. 'label' => 'L'.$i,
  167. 'code' => 'N'.$i,
  168. 'position' => $i,
  169. 'created_at' => $now,
  170. 'updated_at' => $now,
  171. ]);
  172. }
  173. $variantIds = [];
  174. for ($i = 0; $i < $count; $i++) {
  175. $current = $i === $count - 1 ? 'SWAP-N0' : 'OLD-'.$i;
  176. $variantIds[] = DB::table('product_variants')->insertGetId([
  177. 'product_id' => $product->id,
  178. 'sku' => $current,
  179. 'price' => 10,
  180. 'quantity' => 1,
  181. 'status' => 1,
  182. 'sort_order' => $i,
  183. 'created_at' => $now,
  184. 'updated_at' => $now,
  185. ]);
  186. }
  187. $pivots = [];
  188. foreach ($variantIds as $i => $variantId) {
  189. $pivots[] = [
  190. 'product_variant_id' => $variantId,
  191. 'product_option_value_id' => $valueIds[$i],
  192. 'created_at' => $now,
  193. 'updated_at' => $now,
  194. ];
  195. }
  196. DB::table('product_variant_option_values')->insert($pivots);
  197. $this->artisan('products:repair-variant-skus', [
  198. '--sku' => 'SWAP',
  199. ])->assertSuccessful();
  200. $this->assertSame('SWAP-N0', DB::table('product_variants')->where('id', $variantIds[0])->value('sku'));
  201. $this->assertSame('SWAP-N200', DB::table('product_variants')->where('id', $variantIds[$count - 1])->value('sku'));
  202. }
  203. /**
  204. * @return array{0: Product, 1: ProductVariant}
  205. */
  206. private function seedVariant(string $parentSku, string $variantSku, ?int $asteriaId): array
  207. {
  208. $suffix = str_replace('-', '_', strtolower($parentSku));
  209. $product = new Product;
  210. $product->sku = $parentSku;
  211. $product->type = 'flexible_variant';
  212. $product->migrated_from_asteria_id = $asteriaId;
  213. $product->save();
  214. $length = ProductOption::query()->create([
  215. 'label' => 'Hair Length',
  216. 'type' => 'select',
  217. 'code' => $suffix.'_length',
  218. ]);
  219. $color = ProductOption::query()->create([
  220. 'label' => 'Hair Color',
  221. 'type' => 'select',
  222. 'code' => $suffix.'_color',
  223. ]);
  224. $twelve = ProductOptionValue::query()->create([
  225. 'product_option_id' => $length->id,
  226. 'label' => '12"',
  227. 'code' => '12IN',
  228. 'position' => 1,
  229. ]);
  230. $black = ProductOptionValue::query()->create([
  231. 'product_option_id' => $color->id,
  232. 'label' => 'Natural Black',
  233. 'code' => '1B',
  234. 'position' => 1,
  235. ]);
  236. $now = now();
  237. DB::table('product_product_options')->insert([
  238. [
  239. 'product_id' => $product->id,
  240. 'product_option_id' => $length->id,
  241. 'position' => 0,
  242. 'is_required' => 1,
  243. 'created_at' => $now,
  244. 'updated_at' => $now,
  245. ],
  246. [
  247. 'product_id' => $product->id,
  248. 'product_option_id' => $color->id,
  249. 'position' => 1,
  250. 'is_required' => 1,
  251. 'created_at' => $now,
  252. 'updated_at' => $now,
  253. ],
  254. ]);
  255. $variant = ProductVariant::query()->create([
  256. 'product_id' => $product->id,
  257. 'sku' => $variantSku,
  258. 'price' => 99,
  259. 'quantity' => 1,
  260. 'status' => 1,
  261. 'sort_order' => 0,
  262. ]);
  263. DB::table('product_variant_option_values')->insert([
  264. [
  265. 'product_variant_id' => $variant->id,
  266. 'product_option_value_id' => $twelve->id,
  267. 'created_at' => $now,
  268. 'updated_at' => $now,
  269. ],
  270. [
  271. 'product_variant_id' => $variant->id,
  272. 'product_option_value_id' => $black->id,
  273. 'created_at' => $now,
  274. 'updated_at' => $now,
  275. ],
  276. ]);
  277. return [$product, $variant];
  278. }
  279. }