OrderControllerTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. <?php
  2. namespace Tests\Feature;
  3. use App\Models\Dictionary\Area;
  4. use App\Models\Dictionary\District;
  5. use App\Models\File;
  6. use App\Models\MafOrder;
  7. use App\Models\ObjectType;
  8. use App\Models\Order;
  9. use App\Models\OrderStatus;
  10. use App\Models\Product;
  11. use App\Models\ProductSKU;
  12. use App\Models\Role;
  13. use App\Models\User;
  14. use Illuminate\Foundation\Testing\RefreshDatabase;
  15. use Illuminate\Http\UploadedFile;
  16. use Illuminate\Support\Facades\Storage;
  17. use Tests\TestCase;
  18. class OrderControllerTest extends TestCase
  19. {
  20. use RefreshDatabase;
  21. protected $seed = true;
  22. private User $adminUser;
  23. private User $managerUser;
  24. private User $brigadierUser;
  25. protected function setUp(): void
  26. {
  27. parent::setUp();
  28. $this->adminUser = User::factory()->create(['role' => Role::ADMIN]);
  29. $this->managerUser = User::factory()->create(['role' => Role::MANAGER]);
  30. $this->brigadierUser = User::factory()->create(['role' => Role::BRIGADIER]);
  31. }
  32. // ==================== Authentication ====================
  33. public function test_guest_cannot_access_orders_index(): void
  34. {
  35. $response = $this->get(route('order.index'));
  36. $response->assertRedirect(route('login'));
  37. }
  38. public function test_authenticated_user_can_access_orders_index(): void
  39. {
  40. $response = $this->actingAs($this->managerUser)
  41. ->get(route('order.index'));
  42. $response->assertStatus(200);
  43. $response->assertViewIs('orders.index');
  44. }
  45. // ==================== Index ====================
  46. public function test_orders_index_displays_orders(): void
  47. {
  48. $order = Order::factory()->create([
  49. 'object_address' => 'ул. Проверочная, д. 101',
  50. ]);
  51. $response = $this->actingAs($this->managerUser)
  52. ->get(route('order.index'));
  53. $response->assertStatus(200);
  54. $response->assertSee($order->object_address);
  55. }
  56. public function test_brigadier_sees_only_assigned_orders(): void
  57. {
  58. $assignedOrder = Order::factory()->create([
  59. 'brigadier_id' => $this->brigadierUser->id,
  60. 'object_address' => 'ул. Бригадирская, д. 10',
  61. ]);
  62. $otherOrder = Order::factory()->create([
  63. 'brigadier_id' => User::factory()->create(['role' => Role::BRIGADIER])->id,
  64. 'object_address' => 'ул. Чужая, д. 20',
  65. ]);
  66. $response = $this->actingAs($this->brigadierUser)
  67. ->get(route('order.index'));
  68. $response->assertStatus(200);
  69. $response->assertSee($assignedOrder->object_address);
  70. $response->assertDontSee($otherOrder->object_address);
  71. }
  72. public function test_brigadier_does_not_see_handed_over_orders_in_index(): void
  73. {
  74. $visibleOrder = Order::factory()->create([
  75. 'brigadier_id' => $this->brigadierUser->id,
  76. 'order_status_id' => Order::STATUS_IN_MOUNT,
  77. 'object_address' => 'ул. Видимая, д. 11',
  78. ]);
  79. $hiddenOrder = Order::factory()->create([
  80. 'brigadier_id' => $this->brigadierUser->id,
  81. 'order_status_id' => Order::STATUS_HANDED_OVER,
  82. 'object_address' => 'ул. Сданная, д. 12',
  83. ]);
  84. $response = $this->actingAs($this->brigadierUser)
  85. ->get(route('order.index'));
  86. $response->assertStatus(200);
  87. $response->assertSee($visibleOrder->object_address);
  88. $response->assertDontSee($hiddenOrder->object_address);
  89. }
  90. // ==================== Create ====================
  91. public function test_can_view_create_order_form(): void
  92. {
  93. $response = $this->actingAs($this->adminUser)
  94. ->get(route('order.create'));
  95. $response->assertStatus(200);
  96. $response->assertViewIs('orders.edit');
  97. }
  98. // ==================== Store ====================
  99. public function test_can_create_new_order(): void
  100. {
  101. $district = District::factory()->create();
  102. $area = Area::factory()->create();
  103. $objectType = ObjectType::factory()->create();
  104. $response = $this->actingAs($this->managerUser)
  105. ->post(route('order.store'), [
  106. 'name' => 'Тестовый заказ',
  107. 'user_id' => $this->managerUser->id,
  108. 'district_id' => $district->id,
  109. 'area_id' => $area->id,
  110. 'object_address' => 'ул. Тестовая, д. 1',
  111. 'object_type_id' => $objectType->id,
  112. 'comment' => 'Тестовый комментарий',
  113. ]);
  114. $response->assertRedirect();
  115. $this->assertDatabaseHas('orders', [
  116. 'object_address' => 'ул. Тестовая, д. 1',
  117. 'order_status_id' => Order::STATUS_NEW,
  118. ]);
  119. }
  120. public function test_creating_order_sets_tg_group_name(): void
  121. {
  122. $district = District::factory()->create(['shortname' => 'ЦАО']);
  123. $area = Area::factory()->create(['name' => 'Тверской']);
  124. $objectType = ObjectType::factory()->create();
  125. $this->actingAs($this->managerUser)
  126. ->post(route('order.store'), [
  127. 'name' => 'Тестовый заказ',
  128. 'user_id' => $this->managerUser->id,
  129. 'district_id' => $district->id,
  130. 'area_id' => $area->id,
  131. 'object_address' => 'ул. Пушкина',
  132. 'object_type_id' => $objectType->id,
  133. ]);
  134. $order = Order::where('object_address', 'ул. Пушкина')->first();
  135. $this->assertStringContainsString('ЦАО', $order->tg_group_name);
  136. $this->assertStringContainsString('Тверской', $order->tg_group_name);
  137. }
  138. public function test_can_update_existing_order(): void
  139. {
  140. $order = Order::factory()->create([
  141. 'object_address' => 'Старый адрес',
  142. ]);
  143. $response = $this->actingAs($this->managerUser)
  144. ->post(route('order.store'), [
  145. 'id' => $order->id,
  146. 'name' => $order->name,
  147. 'user_id' => $order->user_id,
  148. 'district_id' => $order->district_id,
  149. 'area_id' => $order->area_id,
  150. 'object_address' => 'Новый адрес',
  151. 'object_type_id' => $order->object_type_id,
  152. ]);
  153. $response->assertRedirect();
  154. $this->assertDatabaseHas('orders', [
  155. 'id' => $order->id,
  156. 'object_address' => 'Новый адрес',
  157. ]);
  158. }
  159. // ==================== Show ====================
  160. public function test_can_view_order_details(): void
  161. {
  162. $order = Order::factory()->create([
  163. 'object_address' => 'ул. Детальная, д. 5',
  164. ]);
  165. $response = $this->actingAs($this->managerUser)
  166. ->get(route('order.show', $order));
  167. $response->assertStatus(200);
  168. $response->assertViewIs('orders.show');
  169. $response->assertSee($order->object_address);
  170. }
  171. public function test_brigadier_cannot_view_handed_over_order_details(): void
  172. {
  173. $order = Order::factory()->create([
  174. 'brigadier_id' => $this->brigadierUser->id,
  175. 'order_status_id' => Order::STATUS_HANDED_OVER,
  176. ]);
  177. $response = $this->actingAs($this->brigadierUser)
  178. ->get(route('order.show', $order));
  179. $response->assertStatus(403);
  180. }
  181. // ==================== Edit ====================
  182. public function test_can_view_edit_order_form(): void
  183. {
  184. $order = Order::factory()->create();
  185. $response = $this->actingAs($this->managerUser)
  186. ->get(route('order.edit', $order));
  187. $response->assertStatus(200);
  188. $response->assertViewIs('orders.edit');
  189. }
  190. // ==================== Destroy ====================
  191. public function test_can_delete_order(): void
  192. {
  193. $order = Order::factory()->create();
  194. $orderId = $order->id;
  195. $response = $this->actingAs($this->adminUser)
  196. ->delete(route('order.destroy', $order));
  197. $response->assertRedirect(route('order.index'));
  198. // Order uses SoftDeletes, so check deleted_at is set
  199. $this->assertSoftDeleted('orders', ['id' => $orderId]);
  200. }
  201. public function test_deleting_order_removes_related_product_skus(): void
  202. {
  203. $order = Order::factory()->create();
  204. $product = Product::factory()->create();
  205. $sku = ProductSKU::factory()->create([
  206. 'order_id' => $order->id,
  207. 'product_id' => $product->id,
  208. ]);
  209. $this->actingAs($this->adminUser)
  210. ->delete(route('order.destroy', $order));
  211. // ProductSKU uses SoftDeletes, so check deleted_at is set
  212. $this->assertSoftDeleted('products_sku', ['id' => $sku->id]);
  213. }
  214. // ==================== Search ====================
  215. public function test_search_returns_matching_orders(): void
  216. {
  217. $order = Order::factory()->create([
  218. 'object_address' => 'ул. Уникальная Тестовая, д. 999',
  219. ]);
  220. $otherOrder = Order::factory()->create([
  221. 'object_address' => 'ул. Другая, д. 1',
  222. ]);
  223. $response = $this->actingAs($this->managerUser)
  224. ->get(route('order.index', ['s' => 'Уникальная Тестовая']));
  225. $response->assertStatus(200);
  226. $response->assertSee($order->object_address);
  227. $response->assertDontSee($otherOrder->object_address);
  228. }
  229. public function test_order_search_route_can_search_by_manager_name(): void
  230. {
  231. $manager = User::factory()->create([
  232. 'role' => Role::MANAGER,
  233. 'name' => 'Менеджер Поиска',
  234. ]);
  235. $matchedOrder = Order::factory()->create([
  236. 'user_id' => $manager->id,
  237. 'object_address' => 'ул. Найденная, д. 7',
  238. ]);
  239. $otherOrder = Order::factory()->create([
  240. 'object_address' => 'ул. Не должна попасть, д. 8',
  241. ]);
  242. $response = $this->actingAs($this->adminUser)
  243. ->getJson(route('order.search', ['s' => 'Менеджер Поиска']));
  244. $response->assertOk();
  245. $response->assertJsonPath((string) $matchedOrder->id, $matchedOrder->common_name);
  246. $response->assertJsonMissing([$otherOrder->id => $otherOrder->common_name]);
  247. }
  248. // ==================== MAF Operations ====================
  249. public function test_get_maf_to_order_assigns_available_maf(): void
  250. {
  251. $product = Product::factory()->create();
  252. $order = Order::factory()->create();
  253. $productSku = ProductSKU::factory()->create([
  254. 'order_id' => $order->id,
  255. 'product_id' => $product->id,
  256. 'maf_order_id' => null,
  257. 'status' => 'требуется',
  258. ]);
  259. $mafOrder = MafOrder::factory()->create([
  260. 'product_id' => $product->id,
  261. 'in_stock' => 5,
  262. ]);
  263. // This route requires admin role
  264. $response = $this->actingAs($this->adminUser)
  265. ->get(route('order.get-maf', $order));
  266. $response->assertRedirect(route('order.show', $order));
  267. $response->assertSessionHas('success', function ($messages) {
  268. return str_contains(implode(' ', (array) $messages), 'Привязано МАФ: 1.');
  269. });
  270. $productSku->refresh();
  271. $this->assertEquals($mafOrder->id, $productSku->maf_order_id);
  272. $this->assertEquals('отгружен', $productSku->status);
  273. $mafOrder->refresh();
  274. $this->assertEquals(4, $mafOrder->in_stock);
  275. }
  276. public function test_get_maf_to_order_shows_error_when_not_enough_stock(): void
  277. {
  278. $product = Product::factory()->create();
  279. $order = Order::factory()->create();
  280. $productSku = ProductSKU::factory()->create([
  281. 'order_id' => $order->id,
  282. 'product_id' => $product->id,
  283. 'maf_order_id' => null,
  284. 'status' => 'требуется',
  285. ]);
  286. $response = $this->actingAs($this->adminUser)
  287. ->get(route('order.get-maf', $order));
  288. $response->assertRedirect(route('order.show', $order));
  289. $response->assertSessionHas('danger', function ($messages) {
  290. return str_contains(implode(' ', (array) $messages), 'Не удалось привязать 1 шт. МАФ');
  291. });
  292. $productSku->refresh();
  293. $this->assertNull($productSku->maf_order_id);
  294. $this->assertEquals('требуется', $productSku->status);
  295. }
  296. public function test_revert_maf_returns_maf_to_stock(): void
  297. {
  298. $product = Product::factory()->create();
  299. $order = Order::factory()->create();
  300. $mafOrder = MafOrder::factory()->create([
  301. 'product_id' => $product->id,
  302. 'in_stock' => 3,
  303. ]);
  304. $productSku = ProductSKU::factory()->create([
  305. 'order_id' => $order->id,
  306. 'product_id' => $product->id,
  307. 'maf_order_id' => $mafOrder->id,
  308. 'status' => 'отгружен',
  309. ]);
  310. // This route requires admin role
  311. $response = $this->actingAs($this->adminUser)
  312. ->get(route('order.revert-maf', $order));
  313. $response->assertRedirect(route('order.show', $order));
  314. $response->assertSessionHas('success', function ($messages) {
  315. return str_contains(implode(' ', (array) $messages), 'Отвязано МАФ: 1.');
  316. });
  317. $productSku->refresh();
  318. $this->assertNull($productSku->maf_order_id);
  319. $this->assertEquals('требуется', $productSku->status);
  320. $mafOrder->refresh();
  321. $this->assertEquals(4, $mafOrder->in_stock);
  322. }
  323. public function test_revert_maf_shows_error_when_nothing_is_attached(): void
  324. {
  325. $order = Order::factory()->create();
  326. ProductSKU::factory()->create([
  327. 'order_id' => $order->id,
  328. 'maf_order_id' => null,
  329. 'status' => 'требуется',
  330. ]);
  331. $response = $this->actingAs($this->adminUser)
  332. ->get(route('order.revert-maf', $order));
  333. $response->assertRedirect(route('order.show', $order));
  334. $response->assertSessionHas('danger', function ($messages) {
  335. return str_contains(implode(' ', (array) $messages), 'Нет МАФ для отвязки');
  336. });
  337. }
  338. public function test_store_order_cannot_remove_attached_maf_from_order_list(): void
  339. {
  340. $attachedProduct = Product::factory()->create();
  341. $otherProduct = Product::factory()->create();
  342. $order = Order::factory()->create([
  343. 'order_status_id' => Order::STATUS_NEW,
  344. ]);
  345. $mafOrder = MafOrder::factory()->create([
  346. 'product_id' => $attachedProduct->id,
  347. 'in_stock' => 1,
  348. ]);
  349. $attachedSku = ProductSKU::factory()->create([
  350. 'order_id' => $order->id,
  351. 'product_id' => $attachedProduct->id,
  352. 'maf_order_id' => $mafOrder->id,
  353. 'status' => 'отгружен',
  354. ]);
  355. ProductSKU::factory()->create([
  356. 'order_id' => $order->id,
  357. 'product_id' => $otherProduct->id,
  358. 'maf_order_id' => null,
  359. 'status' => 'требуется',
  360. ]);
  361. $response = $this->actingAs($this->adminUser)
  362. ->post(route('order.store'), [
  363. 'id' => $order->id,
  364. 'products' => [$otherProduct->id],
  365. 'quantity' => [1],
  366. ]);
  367. $response->assertRedirect();
  368. $response->assertSessionHas('danger', function ($messages) {
  369. return str_contains(implode(' ', (array) $messages), 'Нельзя удалить привязанные МАФ');
  370. });
  371. $this->assertDatabaseHas('products_sku', [
  372. 'id' => $attachedSku->id,
  373. 'maf_order_id' => $mafOrder->id,
  374. 'deleted_at' => null,
  375. ]);
  376. }
  377. public function test_store_order_cannot_add_new_positions_when_has_attached_maf(): void
  378. {
  379. $attachedProduct = Product::factory()->create();
  380. $existingProduct = Product::factory()->create();
  381. $newProduct = Product::factory()->create();
  382. $order = Order::factory()->create([
  383. 'order_status_id' => Order::STATUS_NEW,
  384. ]);
  385. $mafOrder = MafOrder::factory()->create([
  386. 'product_id' => $attachedProduct->id,
  387. 'in_stock' => 1,
  388. ]);
  389. ProductSKU::factory()->create([
  390. 'order_id' => $order->id,
  391. 'product_id' => $attachedProduct->id,
  392. 'maf_order_id' => $mafOrder->id,
  393. 'status' => 'отгружен',
  394. ]);
  395. ProductSKU::factory()->create([
  396. 'order_id' => $order->id,
  397. 'product_id' => $existingProduct->id,
  398. 'maf_order_id' => null,
  399. 'status' => 'требуется',
  400. ]);
  401. $response = $this->actingAs($this->adminUser)
  402. ->post(route('order.store'), [
  403. 'id' => $order->id,
  404. 'products' => [$attachedProduct->id, $existingProduct->id, $newProduct->id],
  405. 'quantity' => [1, 1, 1],
  406. ]);
  407. $response->assertRedirect();
  408. $response->assertSessionHas('danger', function ($messages) {
  409. return str_contains(implode(' ', (array) $messages), 'Нельзя добавлять новые позиции МАФ');
  410. });
  411. $this->assertDatabaseMissing('products_sku', [
  412. 'order_id' => $order->id,
  413. 'product_id' => $newProduct->id,
  414. 'deleted_at' => null,
  415. ]);
  416. }
  417. public function test_move_maf_transfers_sku_to_another_order(): void
  418. {
  419. $product = Product::factory()->create();
  420. $order1 = Order::factory()->create();
  421. $order2 = Order::factory()->create();
  422. $productSku = ProductSKU::factory()->create([
  423. 'order_id' => $order1->id,
  424. 'product_id' => $product->id,
  425. ]);
  426. // This route requires admin role
  427. $response = $this->actingAs($this->adminUser)
  428. ->post(route('order.move-maf'), [
  429. 'new_order_id' => $order2->id,
  430. 'ids' => json_encode([$productSku->id]),
  431. ]);
  432. $response->assertStatus(200);
  433. $response->assertJson(['success' => true]);
  434. $productSku->refresh();
  435. $this->assertEquals($order2->id, $productSku->order_id);
  436. }
  437. // ==================== Photo Management ====================
  438. public function test_can_upload_photo_to_order(): void
  439. {
  440. Storage::fake('public');
  441. $order = Order::factory()->create();
  442. // Use create() instead of image() to avoid GD extension requirement
  443. $photo = UploadedFile::fake()->create('photo.jpg', 100, 'image/jpeg');
  444. $response = $this->actingAs($this->managerUser)
  445. ->post(route('order.upload-photo', $order), [
  446. 'photo' => [$photo],
  447. ]);
  448. $response->assertRedirect(route('order.show', $order));
  449. $this->assertCount(1, $order->fresh()->photos);
  450. }
  451. public function test_can_delete_photo_from_order(): void
  452. {
  453. Storage::fake('public');
  454. $order = Order::factory()->create();
  455. $file = File::factory()->create();
  456. $order->photos()->attach($file);
  457. // This route requires admin role
  458. $response = $this->actingAs($this->adminUser)
  459. ->delete(route('order.delete-photo', [$order, $file]));
  460. $response->assertRedirect(route('order.show', $order));
  461. $this->assertCount(0, $order->fresh()->photos);
  462. }
  463. public function test_can_delete_all_photos_from_order(): void
  464. {
  465. Storage::fake('public');
  466. $order = Order::factory()->create();
  467. $files = File::factory()->count(3)->create();
  468. $order->photos()->attach($files->pluck('id'));
  469. // This route requires admin role
  470. $response = $this->actingAs($this->adminUser)
  471. ->delete(route('order.delete-all-photos', $order));
  472. $response->assertRedirect(route('order.show', $order));
  473. $this->assertCount(0, $order->fresh()->photos);
  474. }
  475. // ==================== Document Management ====================
  476. public function test_can_upload_document_to_order(): void
  477. {
  478. Storage::fake('public');
  479. $order = Order::factory()->create();
  480. $document = UploadedFile::fake()->create('document.pdf', 100);
  481. $response = $this->actingAs($this->managerUser)
  482. ->post(route('order.upload-document', $order), [
  483. 'document' => [$document],
  484. ]);
  485. $response->assertRedirect(route('order.show', $order));
  486. $this->assertCount(1, $order->fresh()->documents);
  487. }
  488. public function test_upload_document_preserves_unicode_and_quotes_filename(): void
  489. {
  490. Storage::fake('public');
  491. $order = Order::factory()->create();
  492. $filename = "Документ «смета» 'финал' \"v2\".pdf";
  493. $document = UploadedFile::fake()->create($filename, 100, 'application/pdf');
  494. $response = $this->actingAs($this->managerUser)
  495. ->post(route('order.upload-document', $order), [
  496. 'document' => [$document],
  497. ]);
  498. $response->assertRedirect(route('order.show', $order));
  499. $saved = $order->fresh()->documents->first();
  500. $this->assertNotNull($saved);
  501. $this->assertEquals($filename, $saved->original_name);
  502. $this->assertEquals('orders/' . $order->id . '/document/' . $filename, $saved->path);
  503. Storage::disk('public')->assertExists($saved->path);
  504. }
  505. public function test_upload_statement_preserves_unicode_and_quotes_filename(): void
  506. {
  507. Storage::fake('public');
  508. $order = Order::factory()->create();
  509. $filename = "Акт «приемки» 'этап 1' \"финал\".pdf";
  510. $statement = UploadedFile::fake()->create($filename, 100, 'application/pdf');
  511. $response = $this->actingAs($this->managerUser)
  512. ->post(route('order.upload-statement', $order), [
  513. 'statement' => [$statement],
  514. ]);
  515. $response->assertRedirect(route('order.show', $order));
  516. $saved = $order->fresh()->statements->first();
  517. $this->assertNotNull($saved);
  518. $this->assertEquals($filename, $saved->original_name);
  519. $this->assertEquals('orders/' . $order->id . '/statement/' . $filename, $saved->path);
  520. Storage::disk('public')->assertExists($saved->path);
  521. }
  522. public function test_upload_document_limits_to_5_files(): void
  523. {
  524. Storage::fake('public');
  525. $order = Order::factory()->create();
  526. $documents = [];
  527. for ($i = 0; $i < 7; $i++) {
  528. $documents[] = UploadedFile::fake()->create("document{$i}.pdf", 100);
  529. }
  530. $this->actingAs($this->managerUser)
  531. ->post(route('order.upload-document', $order), [
  532. 'document' => $documents,
  533. ]);
  534. $this->assertCount(5, $order->fresh()->documents);
  535. }
  536. // ==================== Generation ====================
  537. public function test_generate_installation_pack_requires_correct_status(): void
  538. {
  539. $order = Order::factory()->create([
  540. 'order_status_id' => Order::STATUS_NEW,
  541. ]);
  542. $response = $this->actingAs($this->managerUser)
  543. ->get(route('order.generate-installation-pack', $order));
  544. $response->assertRedirect(route('order.show', $order));
  545. $response->assertSessionHas('danger');
  546. }
  547. public function test_generate_installation_pack_succeeds_with_correct_status(): void
  548. {
  549. $product = Product::factory()->create();
  550. $mafOrder = MafOrder::factory()->create(['product_id' => $product->id]);
  551. $order = Order::factory()->create([
  552. 'order_status_id' => Order::STATUS_READY_TO_MOUNT,
  553. ]);
  554. // Create SKU with MAF assigned
  555. ProductSKU::factory()->create([
  556. 'order_id' => $order->id,
  557. 'product_id' => $product->id,
  558. 'maf_order_id' => $mafOrder->id,
  559. ]);
  560. $response = $this->actingAs($this->managerUser)
  561. ->get(route('order.generate-installation-pack', $order));
  562. $response->assertRedirect(route('order.show', $order));
  563. $response->assertSessionHas('success');
  564. }
  565. // ==================== Export ====================
  566. public function test_can_export_orders(): void
  567. {
  568. Order::factory()->count(3)->create();
  569. // This route requires admin role
  570. $response = $this->actingAs($this->adminUser)
  571. ->post(route('order.export'));
  572. $response->assertRedirect(route('order.index'));
  573. $response->assertSessionHas('success');
  574. }
  575. public function test_can_export_single_order(): void
  576. {
  577. $order = Order::factory()->create();
  578. // This route requires admin role
  579. $response = $this->actingAs($this->adminUser)
  580. ->post(route('order.export-one', $order));
  581. $response->assertRedirect(route('order.show', $order));
  582. $response->assertSessionHas('success');
  583. }
  584. }