OrderControllerTest.php 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324
  1. <?php
  2. namespace Tests\Feature;
  3. use App\Jobs\GenerateInstallationPack;
  4. use App\Jobs\GenerateTtnPack;
  5. use App\Models\Dictionary\Area;
  6. use App\Models\Dictionary\District;
  7. use App\Models\File;
  8. use App\Models\MafOrder;
  9. use App\Models\ObjectType;
  10. use App\Models\Order;
  11. use App\Models\OrderStatus;
  12. use App\Models\Permission;
  13. use App\Models\Product;
  14. use App\Models\ProductSKU;
  15. use App\Models\Role;
  16. use App\Models\Setting;
  17. use App\Models\Ttn;
  18. use App\Models\User;
  19. use Illuminate\Foundation\Testing\RefreshDatabase;
  20. use Illuminate\Http\UploadedFile;
  21. use Illuminate\Support\Facades\Bus;
  22. use Illuminate\Support\Facades\Storage;
  23. use Tests\TestCase;
  24. class OrderControllerTest extends TestCase
  25. {
  26. use RefreshDatabase;
  27. protected $seed = true;
  28. private User $adminUser;
  29. private User $managerUser;
  30. private User $brigadierUser;
  31. protected function setUp(): void
  32. {
  33. parent::setUp();
  34. $this->adminUser = User::factory()->create(['role' => Role::ADMIN]);
  35. $this->managerUser = User::factory()->create(['role' => Role::MANAGER]);
  36. $this->brigadierUser = User::factory()->create(['role' => Role::BRIGADIER]);
  37. }
  38. // ==================== Authentication ====================
  39. public function test_guest_cannot_access_orders_index(): void
  40. {
  41. $response = $this->get(route('order.index'));
  42. $response->assertRedirect(route('login'));
  43. }
  44. public function test_authenticated_user_can_access_orders_index(): void
  45. {
  46. $response = $this->actingAs($this->managerUser)
  47. ->get(route('order.index'));
  48. $response->assertStatus(200);
  49. $response->assertViewIs('orders.index');
  50. }
  51. // ==================== Index ====================
  52. public function test_orders_index_displays_orders(): void
  53. {
  54. $order = Order::factory()->create([
  55. 'object_address' => 'ул. Проверочная, д. 101',
  56. ]);
  57. $response = $this->actingAs($this->managerUser)
  58. ->get(route('order.index'));
  59. $response->assertStatus(200);
  60. $response->assertSee($order->object_address);
  61. }
  62. public function test_order_date_column_filter_uses_distinct_values_instead_of_a_range(): void
  63. {
  64. Order::factory()->create(['installation_date' => '2026-09-10']);
  65. Order::factory()->create(['installation_date' => '2026-09-12']);
  66. $response = $this->actingAs($this->managerUser)
  67. ->get(route('order.index'));
  68. $response->assertOk()
  69. ->assertSee('id="filter-list-installation_date"', false)
  70. ->assertDontSee('id="range_from_installation_date"', false);
  71. $this->actingAs($this->managerUser)
  72. ->getJson(route('getFilters', [
  73. 'table' => 'orders',
  74. 'column' => 'installation_date',
  75. ]))
  76. ->assertOk()
  77. ->assertJsonFragment(['2026-09-10'])
  78. ->assertJsonFragment(['2026-09-12']);
  79. }
  80. public function test_orders_index_displays_products_total_column_value(): void
  81. {
  82. $order = Order::factory()->create([
  83. 'object_address' => 'ул. Колоночная, д. 10',
  84. ]);
  85. $product = Product::factory()->create();
  86. ProductSKU::factory()->count(3)->create([
  87. 'order_id' => $order->id,
  88. 'product_id' => $product->id,
  89. ]);
  90. $response = $this->actingAs($this->managerUser)
  91. ->get(route('order.index'));
  92. $response->assertOk();
  93. $response->assertSee('Всего МАФ');
  94. $response->assertSee('ул. Колоночная, д. 10');
  95. $response->assertViewHas('orders', static function ($orders) use ($order) {
  96. return (int) $orders->firstWhere('id', $order->id)?->products_total === 3;
  97. });
  98. }
  99. public function test_orders_index_displays_filtered_footer_stats(): void
  100. {
  101. $district = District::factory()->create(['shortname' => 'ЦАО']);
  102. $area = Area::factory()->create(['district_id' => $district->id, 'name' => 'Тверской']);
  103. $matchingOrder = Order::factory()->create([
  104. 'district_id' => $district->id,
  105. 'area_id' => $area->id,
  106. 'object_address' => 'ул. Итоговая, д. 1',
  107. ]);
  108. $otherOrder = Order::factory()->create([
  109. 'object_address' => 'ул. Неучтенная, д. 2',
  110. ]);
  111. $product = Product::factory()->create();
  112. ProductSKU::factory()->count(2)->create([
  113. 'order_id' => $matchingOrder->id,
  114. 'product_id' => $product->id,
  115. ]);
  116. ProductSKU::factory()->count(5)->create([
  117. 'order_id' => $otherOrder->id,
  118. 'product_id' => $product->id,
  119. ]);
  120. $response = $this->actingAs($this->managerUser)
  121. ->get(route('order.index', ['s' => 'Итоговая']));
  122. $response->assertOk();
  123. $response->assertSee('Адресов: 1', false);
  124. $response->assertSee('МАФ: 2', false);
  125. $response->assertDontSee('МАФ: 7', false);
  126. }
  127. public function test_brigadier_sees_only_assigned_orders(): void
  128. {
  129. $assignedOrder = Order::factory()->create([
  130. 'brigadier_id' => $this->brigadierUser->id,
  131. 'object_address' => 'ул. Бригадирская, д. 10',
  132. ]);
  133. $otherOrder = Order::factory()->create([
  134. 'brigadier_id' => User::factory()->create(['role' => Role::BRIGADIER])->id,
  135. 'object_address' => 'ул. Чужая, д. 20',
  136. ]);
  137. $response = $this->actingAs($this->brigadierUser)
  138. ->get(route('order.index'));
  139. $response->assertStatus(200);
  140. $response->assertSee($assignedOrder->object_address);
  141. $response->assertDontSee($otherOrder->object_address);
  142. }
  143. public function test_brigadier_does_not_see_handed_over_orders_in_index(): void
  144. {
  145. $visibleOrder = Order::factory()->create([
  146. 'brigadier_id' => $this->brigadierUser->id,
  147. 'order_status_id' => Order::STATUS_IN_MOUNT,
  148. 'object_address' => 'ул. Видимая, д. 11',
  149. ]);
  150. $hiddenOrder = Order::factory()->create([
  151. 'brigadier_id' => $this->brigadierUser->id,
  152. 'order_status_id' => Order::STATUS_HANDED_OVER,
  153. 'object_address' => 'ул. Сданная, д. 12',
  154. ]);
  155. $response = $this->actingAs($this->brigadierUser)
  156. ->get(route('order.index'));
  157. $response->assertStatus(200);
  158. $response->assertSee($visibleOrder->object_address);
  159. $response->assertDontSee($hiddenOrder->object_address);
  160. }
  161. // ==================== Create ====================
  162. public function test_can_view_create_order_form(): void
  163. {
  164. $response = $this->actingAs($this->adminUser)
  165. ->get(route('order.create'));
  166. $response->assertStatus(200);
  167. $response->assertViewIs('orders.edit');
  168. }
  169. // ==================== Store ====================
  170. public function test_can_create_new_order(): void
  171. {
  172. $district = District::factory()->create();
  173. $area = Area::factory()->create();
  174. $objectType = ObjectType::factory()->create();
  175. $response = $this->actingAs($this->managerUser)
  176. ->post(route('order.store'), [
  177. 'name' => 'Тестовый заказ',
  178. 'user_id' => $this->managerUser->id,
  179. 'district_id' => $district->id,
  180. 'area_id' => $area->id,
  181. 'object_address' => 'ул. Тестовая, д. 1',
  182. 'object_type_id' => $objectType->id,
  183. 'comment' => 'Тестовый комментарий',
  184. ]);
  185. $response->assertRedirect();
  186. $this->assertDatabaseHas('orders', [
  187. 'object_address' => 'ул. Тестовая, д. 1',
  188. 'order_status_id' => Order::STATUS_NEW,
  189. ]);
  190. }
  191. public function test_order_show_uses_nav_context_for_back_url(): void
  192. {
  193. $order = Order::factory()->create();
  194. $indexResponse = $this->actingAs($this->managerUser)
  195. ->get(route('order.index', [
  196. 'filters' => ['object_address' => 'Test address'],
  197. ]));
  198. $nav = $indexResponse->viewData('nav');
  199. $response = $this->actingAs($this->managerUser)
  200. ->get(route('order.show', [
  201. 'order' => $order,
  202. 'nav' => $nav,
  203. ]));
  204. $response->assertOk();
  205. $response->assertViewHas('nav', $nav);
  206. $response->assertViewHas('back_url', function (string $backUrl): bool {
  207. if (!str_starts_with($backUrl, route('order.index'))) {
  208. return false;
  209. }
  210. $query = parse_url($backUrl, PHP_URL_QUERY);
  211. parse_str((string) $query, $params);
  212. return ($params['filters']['object_address'] ?? null) === 'Test address';
  213. });
  214. }
  215. public function test_order_index_starts_new_navigation_context(): void
  216. {
  217. $response = $this->actingAs($this->managerUser)
  218. ->withSession([
  219. 'navigation' => [
  220. 'existing-card-nav' => [
  221. 'updated_at' => time(),
  222. 'stack' => [
  223. route('order.show', Order::factory()->create()),
  224. route('reclamations.index'),
  225. ],
  226. ],
  227. ],
  228. ])
  229. ->get(route('order.index', ['nav' => 'existing-card-nav']));
  230. $response->assertOk();
  231. $response->assertViewHas('nav', function (string $nav): bool {
  232. return $nav !== 'existing-card-nav';
  233. });
  234. }
  235. public function test_order_store_redirects_to_show_with_nav_token(): void
  236. {
  237. $district = District::factory()->create();
  238. $area = Area::factory()->create();
  239. $objectType = ObjectType::factory()->create();
  240. $response = $this->actingAs($this->managerUser)
  241. ->withSession([
  242. 'navigation' => [
  243. 'order-nav-token' => [
  244. 'updated_at' => time(),
  245. 'stack' => [
  246. route('order.index'),
  247. ],
  248. ],
  249. ],
  250. ])
  251. ->post(route('order.store'), [
  252. 'nav' => 'order-nav-token',
  253. 'name' => 'Тестовый заказ',
  254. 'user_id' => $this->managerUser->id,
  255. 'district_id' => $district->id,
  256. 'area_id' => $area->id,
  257. 'object_address' => 'ул. Навигационная, д. 5',
  258. 'object_type_id' => $objectType->id,
  259. 'comment' => 'Тестовый комментарий',
  260. ]);
  261. $createdOrder = Order::query()->where('object_address', 'ул. Навигационная, д. 5')->firstOrFail();
  262. $response->assertRedirect(route('order.show', [
  263. 'order' => $createdOrder,
  264. 'nav' => 'order-nav-token',
  265. ]));
  266. }
  267. public function test_creating_order_sets_tg_group_name(): void
  268. {
  269. $district = District::factory()->create(['shortname' => 'ЦАО']);
  270. $area = Area::factory()->create(['name' => 'Тверской']);
  271. $objectType = ObjectType::factory()->create();
  272. $this->actingAs($this->managerUser)
  273. ->post(route('order.store'), [
  274. 'name' => 'Тестовый заказ',
  275. 'user_id' => $this->managerUser->id,
  276. 'district_id' => $district->id,
  277. 'area_id' => $area->id,
  278. 'object_address' => 'ул. Пушкина',
  279. 'object_type_id' => $objectType->id,
  280. ]);
  281. $order = Order::where('object_address', 'ул. Пушкина')->first();
  282. $this->assertStringContainsString('ЦАО', $order->tg_group_name);
  283. $this->assertStringContainsString('Тверской', $order->tg_group_name);
  284. }
  285. public function test_can_update_existing_order(): void
  286. {
  287. $order = Order::factory()->create([
  288. 'object_address' => 'Старый адрес',
  289. ]);
  290. $response = $this->actingAs($this->managerUser)
  291. ->post(route('order.store'), [
  292. 'id' => $order->id,
  293. 'name' => $order->name,
  294. 'user_id' => $order->user_id,
  295. 'district_id' => $order->district_id,
  296. 'area_id' => $order->area_id,
  297. 'object_address' => 'Новый адрес',
  298. 'object_type_id' => $order->object_type_id,
  299. ]);
  300. $response->assertRedirect();
  301. $this->assertDatabaseHas('orders', [
  302. 'id' => $order->id,
  303. 'object_address' => 'Новый адрес',
  304. ]);
  305. }
  306. public function test_cannot_set_in_mount_status_when_order_has_unlinked_maf(): void
  307. {
  308. $product = Product::factory()->create();
  309. $order = Order::factory()->readyToMount()->withBrigadier($this->brigadierUser)->create([
  310. 'installation_date' => '2026-04-25',
  311. ]);
  312. ProductSKU::factory()->create([
  313. 'order_id' => $order->id,
  314. 'product_id' => $product->id,
  315. 'maf_order_id' => null,
  316. ]);
  317. $response = $this->actingAs($this->adminUser)
  318. ->post(route('order.update'), [
  319. 'id' => $order->id,
  320. 'order_status_id' => Order::STATUS_IN_MOUNT,
  321. ]);
  322. $response->assertRedirect();
  323. $response->assertSessionHas('danger', function ($messages) {
  324. return in_array('МАФ не привязан к заказу', (array) $messages, true);
  325. });
  326. $this->assertDatabaseHas('orders', [
  327. 'id' => $order->id,
  328. 'order_status_id' => Order::STATUS_READY_TO_MOUNT,
  329. ]);
  330. }
  331. public function test_ajax_cannot_set_in_mount_status_when_maf_order_number_is_empty(): void
  332. {
  333. $product = Product::factory()->create();
  334. $order = Order::factory()->readyToMount()->withBrigadier($this->brigadierUser)->create([
  335. 'installation_date' => '2026-04-25',
  336. ]);
  337. $mafOrder = MafOrder::factory()->create([
  338. 'product_id' => $product->id,
  339. 'order_number' => '',
  340. ]);
  341. ProductSKU::factory()->create([
  342. 'order_id' => $order->id,
  343. 'product_id' => $product->id,
  344. 'maf_order_id' => $mafOrder->id,
  345. ]);
  346. $response = $this->actingAs($this->adminUser)
  347. ->withHeader('X-Requested-With', 'XMLHttpRequest')
  348. ->post(route('order.update'), [
  349. 'id' => $order->id,
  350. 'order_status_id' => Order::STATUS_IN_MOUNT,
  351. ]);
  352. $response->assertStatus(422);
  353. $response->assertJson([
  354. 'message' => 'МАФ не привязан к заказу',
  355. ]);
  356. $this->assertDatabaseHas('orders', [
  357. 'id' => $order->id,
  358. 'order_status_id' => Order::STATUS_READY_TO_MOUNT,
  359. ]);
  360. }
  361. public function test_can_set_in_mount_status_when_all_mafs_are_linked_to_order_numbers(): void
  362. {
  363. $product = Product::factory()->create();
  364. $order = Order::factory()->readyToMount()->withBrigadier($this->brigadierUser)->create([
  365. 'installation_date' => '2026-04-25',
  366. ]);
  367. $mafOrder = MafOrder::factory()->create([
  368. 'product_id' => $product->id,
  369. 'order_number' => 'MO-7788',
  370. ]);
  371. ProductSKU::factory()->create([
  372. 'order_id' => $order->id,
  373. 'product_id' => $product->id,
  374. 'maf_order_id' => $mafOrder->id,
  375. ]);
  376. $response = $this->actingAs($this->adminUser)
  377. ->post(route('order.update'), [
  378. 'id' => $order->id,
  379. 'order_status_id' => Order::STATUS_IN_MOUNT,
  380. ]);
  381. $response->assertRedirect();
  382. $this->assertDatabaseHas('orders', [
  383. 'id' => $order->id,
  384. 'order_status_id' => Order::STATUS_IN_MOUNT,
  385. ]);
  386. }
  387. public function test_manager_can_update_ready_date(): void
  388. {
  389. $order = Order::factory()->create([
  390. 'ready_date' => '2026-04-01',
  391. ]);
  392. $response = $this->actingAs($this->managerUser)
  393. ->post(route('order.store'), [
  394. 'id' => $order->id,
  395. 'ready_date' => '2026-04-25',
  396. ]);
  397. $response->assertRedirect();
  398. $this->assertDatabaseHas('orders', [
  399. 'id' => $order->id,
  400. 'ready_date' => '2026-04-25',
  401. ]);
  402. }
  403. // ==================== Show ====================
  404. public function test_can_view_order_details(): void
  405. {
  406. $order = Order::factory()->create([
  407. 'object_address' => 'ул. Детальная, д. 5',
  408. ]);
  409. $response = $this->actingAs($this->managerUser)
  410. ->get(route('order.show', $order));
  411. $response->assertStatus(200);
  412. $response->assertViewIs('orders.show');
  413. $response->assertSee($order->object_address);
  414. }
  415. public function test_order_details_show_area_and_district(): void
  416. {
  417. $district = District::factory()->create(['name' => 'Центральный округ']);
  418. $area = Area::factory()->create([
  419. 'district_id' => $district->id,
  420. 'name' => 'Тверской район',
  421. ]);
  422. $order = Order::factory()->create([
  423. 'district_id' => $district->id,
  424. 'area_id' => $area->id,
  425. ]);
  426. $response = $this->actingAs($this->managerUser)
  427. ->get(route('order.show', $order));
  428. $response->assertOk();
  429. $response->assertSee('Центральный округ');
  430. $response->assertSee('Тверской район');
  431. }
  432. public function test_order_details_render_inline_maf_fields_and_passport_upload_by_permissions(): void
  433. {
  434. $order = Order::factory()->create();
  435. $product = Product::factory()->create(['article' => 'MAF-INLINE-001']);
  436. $sku = ProductSKU::factory()->create([
  437. 'order_id' => $order->id,
  438. 'product_id' => $product->id,
  439. 'passport_id' => null,
  440. 'rfid' => 'RFID-ORDER-OLD',
  441. 'factory_number' => 'FN-ORDER-OLD',
  442. 'manufacture_date' => '2026-05-19',
  443. 'statement_number' => 'STAT-ORDER-OLD',
  444. 'statement_date' => '2026-05-18',
  445. ]);
  446. $response = $this->actingAs($this->adminUser)
  447. ->get(route('order.show', $order));
  448. $response->assertOk();
  449. $response->assertSee('inline-product-sku-field', false);
  450. $response->assertSee('data-field="rfid"', false);
  451. $response->assertSee('data-field="factory_number"', false);
  452. $response->assertSee('data-field="manufacture_date"', false);
  453. $response->assertSee('data-field="statement_number"', false);
  454. $response->assertSee('data-field="statement_date"', false);
  455. $response->assertSee('Добавить Ведомость');
  456. $response->assertSee(route('order.add-statement-to-mafs', $order), false);
  457. $response->assertSee(route('product_sku.inline-update', $sku->id), false);
  458. $response->assertSee('upload-maf-passport', false);
  459. $response->assertSee(route('product-sku.upload-passport', ['product_sku' => $sku]), false);
  460. }
  461. public function test_order_details_hide_inline_maf_controls_without_permissions(): void
  462. {
  463. $role = Role::query()->create([
  464. 'slug' => 'orders_viewer_without_maf_permissions',
  465. 'name' => 'Orders viewer without MAF permissions',
  466. 'is_system' => false,
  467. 'is_active' => true,
  468. ]);
  469. $permissions = Permission::query()
  470. ->whereIn('slug', ['orders.view', 'orders.scope.manager'])
  471. ->pluck('id')
  472. ->mapWithKeys(fn (int $id): array => [$id => ['effect' => 'allow']]);
  473. $role->permissions()->sync($permissions);
  474. $user = User::factory()->create([
  475. 'role' => $role->slug,
  476. 'role_id' => $role->id,
  477. ]);
  478. $order = Order::factory()->create();
  479. $product = Product::factory()->create(['article' => 'MAF-NO-INLINE-001']);
  480. $sku = ProductSKU::factory()->create([
  481. 'order_id' => $order->id,
  482. 'product_id' => $product->id,
  483. 'passport_id' => null,
  484. 'rfid' => 'RFID-READONLY',
  485. ]);
  486. $response = $this->actingAs($user)
  487. ->get(route('order.show', $order));
  488. $response->assertOk();
  489. $response->assertDontSee(route('product_sku.inline-update', $sku->id), false);
  490. $response->assertDontSee(route('product-sku.upload-passport', ['product_sku' => $sku]), false);
  491. }
  492. public function test_can_add_statement_to_selected_mafs_on_order(): void
  493. {
  494. $order = Order::factory()->create();
  495. $otherOrder = Order::factory()->create();
  496. $product = Product::factory()->create();
  497. $selectedSku = ProductSKU::factory()->create([
  498. 'order_id' => $order->id,
  499. 'product_id' => $product->id,
  500. 'statement_number' => null,
  501. 'statement_date' => null,
  502. ]);
  503. $notSelectedSku = ProductSKU::factory()->create([
  504. 'order_id' => $order->id,
  505. 'product_id' => $product->id,
  506. 'statement_number' => null,
  507. 'statement_date' => null,
  508. ]);
  509. $otherOrderSku = ProductSKU::factory()->create([
  510. 'order_id' => $otherOrder->id,
  511. 'product_id' => $product->id,
  512. 'statement_number' => null,
  513. 'statement_date' => null,
  514. ]);
  515. $response = $this->actingAs($this->adminUser)
  516. ->post(route('order.add-statement-to-mafs', $order), [
  517. 'statement_number' => 'STAT-2026-05',
  518. 'statement_date' => '2026-05-19',
  519. 'skus' => [$selectedSku->id, $otherOrderSku->id],
  520. ]);
  521. $response->assertRedirect();
  522. $response->assertSessionHas('success', 'Ведомость добавлена к МАФ: 1.');
  523. $this->assertDatabaseHas('products_sku', [
  524. 'id' => $selectedSku->id,
  525. 'statement_number' => 'STAT-2026-05',
  526. 'statement_date' => '2026-05-19',
  527. ]);
  528. $this->assertDatabaseHas('products_sku', [
  529. 'id' => $notSelectedSku->id,
  530. 'statement_number' => null,
  531. 'statement_date' => null,
  532. ]);
  533. $this->assertDatabaseHas('products_sku', [
  534. 'id' => $otherOrderSku->id,
  535. 'statement_number' => null,
  536. 'statement_date' => null,
  537. ]);
  538. }
  539. public function test_add_statement_to_all_mafs_marks_order_paid_when_upd_exists(): void
  540. {
  541. $order = Order::factory()->create([
  542. 'order_status_id' => Order::STATUS_HANDED_OVER,
  543. ]);
  544. $firstSku = ProductSKU::factory()->create([
  545. 'order_id' => $order->id,
  546. 'statement_number' => null,
  547. 'statement_date' => null,
  548. 'upd_number' => 'UPD-001',
  549. ]);
  550. $secondSku = ProductSKU::factory()->create([
  551. 'order_id' => $order->id,
  552. 'statement_number' => null,
  553. 'statement_date' => null,
  554. 'upd_number' => 'UPD-002',
  555. ]);
  556. $response = $this->actingAs($this->adminUser)
  557. ->post(route('order.add-statement-to-mafs', $order), [
  558. 'statement_number' => 'STAT-2026-05',
  559. 'statement_date' => '2026-05-19',
  560. 'skus' => [$firstSku->id, $secondSku->id],
  561. ]);
  562. $response->assertRedirect();
  563. $this->assertDatabaseHas('orders', [
  564. 'id' => $order->id,
  565. 'order_status_id' => Order::STATUS_PAID,
  566. ]);
  567. }
  568. public function test_add_statement_to_mafs_requires_field_permissions(): void
  569. {
  570. $order = Order::factory()->create();
  571. $sku = ProductSKU::factory()->create(['order_id' => $order->id]);
  572. $response = $this->actingAs($this->managerUser)
  573. ->post(route('order.add-statement-to-mafs', $order), [
  574. 'statement_number' => 'STAT-DENIED',
  575. 'statement_date' => '2026-05-19',
  576. 'skus' => [$sku->id],
  577. ]);
  578. $response->assertForbidden();
  579. }
  580. public function test_brigadier_cannot_view_handed_over_order_details(): void
  581. {
  582. $order = Order::factory()->create([
  583. 'brigadier_id' => $this->brigadierUser->id,
  584. 'order_status_id' => Order::STATUS_HANDED_OVER,
  585. ]);
  586. $response = $this->actingAs($this->brigadierUser)
  587. ->get(route('order.show', $order));
  588. $response->assertStatus(403);
  589. }
  590. // ==================== Edit ====================
  591. public function test_can_view_edit_order_form(): void
  592. {
  593. $order = Order::factory()->create();
  594. $response = $this->actingAs($this->managerUser)
  595. ->get(route('order.edit', $order));
  596. $response->assertStatus(200);
  597. $response->assertViewIs('orders.edit');
  598. }
  599. public function test_manager_can_edit_ready_date_in_order_edit_form(): void
  600. {
  601. $order = Order::factory()->create();
  602. $response = $this->actingAs($this->managerUser)
  603. ->get(route('order.edit', $order));
  604. $response->assertOk();
  605. $this->assertMatchesRegularExpression(
  606. '/<input[^>]*name="ready_date"(?:(?!disabled).)*>/s',
  607. $response->getContent()
  608. );
  609. }
  610. // ==================== Destroy ====================
  611. public function test_can_delete_order(): void
  612. {
  613. $order = Order::factory()->create();
  614. $orderId = $order->id;
  615. $response = $this->actingAs($this->adminUser)
  616. ->delete(route('order.destroy', $order));
  617. $response->assertRedirect(route('order.index'));
  618. // Order uses SoftDeletes, so check deleted_at is set
  619. $this->assertSoftDeleted('orders', ['id' => $orderId]);
  620. }
  621. public function test_deleting_order_removes_related_product_skus(): void
  622. {
  623. $order = Order::factory()->create();
  624. $product = Product::factory()->create();
  625. $sku = ProductSKU::factory()->create([
  626. 'order_id' => $order->id,
  627. 'product_id' => $product->id,
  628. ]);
  629. $this->actingAs($this->adminUser)
  630. ->delete(route('order.destroy', $order));
  631. // ProductSKU uses SoftDeletes, so check deleted_at is set
  632. $this->assertSoftDeleted('products_sku', ['id' => $sku->id]);
  633. }
  634. // ==================== Search ====================
  635. public function test_search_returns_matching_orders(): void
  636. {
  637. $order = Order::factory()->create([
  638. 'object_address' => 'ул. Уникальная Тестовая, д. 999',
  639. ]);
  640. $otherOrder = Order::factory()->create([
  641. 'object_address' => 'ул. Другая, д. 1',
  642. ]);
  643. $response = $this->actingAs($this->managerUser)
  644. ->get(route('order.index', ['s' => 'Уникальная Тестовая']));
  645. $response->assertStatus(200);
  646. $response->assertSee($order->object_address);
  647. $response->assertDontSee($otherOrder->object_address);
  648. }
  649. public function test_order_search_route_can_search_by_manager_name(): void
  650. {
  651. $manager = User::factory()->create([
  652. 'role' => Role::MANAGER,
  653. 'name' => 'Менеджер Поиска',
  654. ]);
  655. $matchedOrder = Order::factory()->create([
  656. 'user_id' => $manager->id,
  657. 'object_address' => 'ул. Найденная, д. 7',
  658. ]);
  659. $otherOrder = Order::factory()->create([
  660. 'object_address' => 'ул. Не должна попасть, д. 8',
  661. ]);
  662. $response = $this->actingAs($this->adminUser)
  663. ->getJson(route('order.search', ['s' => 'Менеджер Поиска']));
  664. $response->assertOk();
  665. $response->assertJsonPath((string) $matchedOrder->id, $matchedOrder->move_maf_name);
  666. $response->assertJsonMissing([$otherOrder->id => $otherOrder->move_maf_name]);
  667. }
  668. public function test_order_search_route_includes_site_name_and_excludes_current_order(): void
  669. {
  670. $district = District::factory()->create(['name' => 'Северный округ']);
  671. $area = Area::factory()->create([
  672. 'district_id' => $district->id,
  673. 'name' => 'Левобережный',
  674. ]);
  675. $currentOrder = Order::factory()->create([
  676. 'district_id' => $district->id,
  677. 'area_id' => $area->id,
  678. 'name' => 'Текущая площадка',
  679. 'object_address' => 'ул. Проверочная, д. 1',
  680. ]);
  681. $targetOrder = Order::factory()->create([
  682. 'district_id' => $district->id,
  683. 'area_id' => $area->id,
  684. 'name' => 'Площадка назначения',
  685. 'object_address' => 'ул. Проверочная, д. 2',
  686. ]);
  687. $response = $this->actingAs($this->adminUser)
  688. ->getJson(route('order.search', [
  689. 's' => 'Проверочная',
  690. 'current_order_id' => $currentOrder->id,
  691. ]));
  692. $response->assertOk();
  693. $response->assertJsonPath((string) $targetOrder->id, $targetOrder->move_maf_name);
  694. $response->assertJsonMissing([(string) $currentOrder->id => $currentOrder->move_maf_name]);
  695. }
  696. // ==================== MAF Operations ====================
  697. public function test_get_maf_to_order_assigns_available_maf(): void
  698. {
  699. $product = Product::factory()->create();
  700. $order = Order::factory()->create();
  701. $productSku = ProductSKU::factory()->create([
  702. 'order_id' => $order->id,
  703. 'product_id' => $product->id,
  704. 'maf_order_id' => null,
  705. 'status' => 'требуется',
  706. ]);
  707. $mafOrder = MafOrder::factory()->create([
  708. 'product_id' => $product->id,
  709. 'in_stock' => 5,
  710. ]);
  711. // This route requires admin role
  712. $response = $this->actingAs($this->adminUser)
  713. ->get(route('order.get-maf', $order));
  714. $response->assertRedirect(route('order.show', $order));
  715. $response->assertSessionHas('success', function ($messages) {
  716. return str_contains(implode(' ', (array) $messages), 'Привязано МАФ: 1.');
  717. });
  718. $productSku->refresh();
  719. $this->assertEquals($mafOrder->id, $productSku->maf_order_id);
  720. $this->assertEquals('отгружен', $productSku->status);
  721. $mafOrder->refresh();
  722. $this->assertEquals(4, $mafOrder->in_stock);
  723. }
  724. public function test_get_maf_to_order_shows_error_when_not_enough_stock(): void
  725. {
  726. $product = Product::factory()->create();
  727. $order = Order::factory()->create();
  728. $productSku = ProductSKU::factory()->create([
  729. 'order_id' => $order->id,
  730. 'product_id' => $product->id,
  731. 'maf_order_id' => null,
  732. 'status' => 'требуется',
  733. ]);
  734. $response = $this->actingAs($this->adminUser)
  735. ->get(route('order.get-maf', $order));
  736. $response->assertRedirect(route('order.show', $order));
  737. $response->assertSessionHas('danger', function ($messages) {
  738. return str_contains(implode(' ', (array) $messages), 'Не удалось привязать 1 шт. МАФ');
  739. });
  740. $productSku->refresh();
  741. $this->assertNull($productSku->maf_order_id);
  742. $this->assertEquals('требуется', $productSku->status);
  743. }
  744. public function test_revert_maf_returns_maf_to_stock(): void
  745. {
  746. $product = Product::factory()->create();
  747. $order = Order::factory()->create();
  748. $mafOrder = MafOrder::factory()->create([
  749. 'product_id' => $product->id,
  750. 'in_stock' => 3,
  751. ]);
  752. $productSku = ProductSKU::factory()->create([
  753. 'order_id' => $order->id,
  754. 'product_id' => $product->id,
  755. 'maf_order_id' => $mafOrder->id,
  756. 'status' => 'отгружен',
  757. ]);
  758. // This route requires admin role
  759. $response = $this->actingAs($this->adminUser)
  760. ->get(route('order.revert-maf', $order));
  761. $response->assertRedirect(route('order.show', $order));
  762. $response->assertSessionHas('success', function ($messages) {
  763. return str_contains(implode(' ', (array) $messages), 'Отвязано МАФ: 1.');
  764. });
  765. $productSku->refresh();
  766. $this->assertNull($productSku->maf_order_id);
  767. $this->assertEquals('требуется', $productSku->status);
  768. $mafOrder->refresh();
  769. $this->assertEquals(4, $mafOrder->in_stock);
  770. }
  771. public function test_revert_maf_shows_error_when_nothing_is_attached(): void
  772. {
  773. $order = Order::factory()->create();
  774. ProductSKU::factory()->create([
  775. 'order_id' => $order->id,
  776. 'maf_order_id' => null,
  777. 'status' => 'требуется',
  778. ]);
  779. $response = $this->actingAs($this->adminUser)
  780. ->get(route('order.revert-maf', $order));
  781. $response->assertRedirect(route('order.show', $order));
  782. $response->assertSessionHas('danger', function ($messages) {
  783. return str_contains(implode(' ', (array) $messages), 'Нет МАФ для отвязки');
  784. });
  785. }
  786. public function test_store_order_cannot_remove_attached_maf_from_order_list(): void
  787. {
  788. $attachedProduct = Product::factory()->create();
  789. $otherProduct = Product::factory()->create();
  790. $order = Order::factory()->create([
  791. 'order_status_id' => Order::STATUS_NEW,
  792. ]);
  793. $mafOrder = MafOrder::factory()->create([
  794. 'product_id' => $attachedProduct->id,
  795. 'in_stock' => 1,
  796. ]);
  797. $attachedSku = ProductSKU::factory()->create([
  798. 'order_id' => $order->id,
  799. 'product_id' => $attachedProduct->id,
  800. 'maf_order_id' => $mafOrder->id,
  801. 'status' => 'отгружен',
  802. ]);
  803. ProductSKU::factory()->create([
  804. 'order_id' => $order->id,
  805. 'product_id' => $otherProduct->id,
  806. 'maf_order_id' => null,
  807. 'status' => 'требуется',
  808. ]);
  809. $response = $this->actingAs($this->adminUser)
  810. ->post(route('order.store'), [
  811. 'id' => $order->id,
  812. 'products' => [$otherProduct->id],
  813. 'quantity' => [1],
  814. ]);
  815. $response->assertRedirect();
  816. $response->assertSessionHas('danger', function ($messages) {
  817. return str_contains(implode(' ', (array) $messages), 'Нельзя удалить привязанные МАФ');
  818. });
  819. $this->assertDatabaseHas('products_sku', [
  820. 'id' => $attachedSku->id,
  821. 'maf_order_id' => $mafOrder->id,
  822. 'deleted_at' => null,
  823. ]);
  824. }
  825. public function test_store_order_cannot_add_new_positions_when_has_attached_maf(): void
  826. {
  827. $attachedProduct = Product::factory()->create();
  828. $existingProduct = Product::factory()->create();
  829. $newProduct = Product::factory()->create();
  830. $order = Order::factory()->create([
  831. 'order_status_id' => Order::STATUS_NEW,
  832. ]);
  833. $mafOrder = MafOrder::factory()->create([
  834. 'product_id' => $attachedProduct->id,
  835. 'in_stock' => 1,
  836. ]);
  837. ProductSKU::factory()->create([
  838. 'order_id' => $order->id,
  839. 'product_id' => $attachedProduct->id,
  840. 'maf_order_id' => $mafOrder->id,
  841. 'status' => 'отгружен',
  842. ]);
  843. ProductSKU::factory()->create([
  844. 'order_id' => $order->id,
  845. 'product_id' => $existingProduct->id,
  846. 'maf_order_id' => null,
  847. 'status' => 'требуется',
  848. ]);
  849. $response = $this->actingAs($this->adminUser)
  850. ->post(route('order.store'), [
  851. 'id' => $order->id,
  852. 'products' => [$attachedProduct->id, $existingProduct->id, $newProduct->id],
  853. 'quantity' => [1, 1, 1],
  854. ]);
  855. $response->assertRedirect();
  856. $response->assertSessionHas('danger', function ($messages) {
  857. return str_contains(implode(' ', (array) $messages), 'Нельзя добавлять новые позиции МАФ');
  858. });
  859. $this->assertDatabaseMissing('products_sku', [
  860. 'order_id' => $order->id,
  861. 'product_id' => $newProduct->id,
  862. 'deleted_at' => null,
  863. ]);
  864. }
  865. public function test_move_maf_transfers_sku_to_another_order(): void
  866. {
  867. $product = Product::factory()->create();
  868. $order1 = Order::factory()->create();
  869. $order2 = Order::factory()->create();
  870. $productSku = ProductSKU::factory()->create([
  871. 'order_id' => $order1->id,
  872. 'product_id' => $product->id,
  873. ]);
  874. // This route requires admin role
  875. $response = $this->actingAs($this->adminUser)
  876. ->post(route('order.move-maf'), [
  877. 'new_order_id' => $order2->id,
  878. 'ids' => json_encode([$productSku->id]),
  879. ]);
  880. $response->assertStatus(200);
  881. $response->assertJson(['success' => true]);
  882. $productSku->refresh();
  883. $this->assertEquals($order2->id, $productSku->order_id);
  884. }
  885. // ==================== Photo Management ====================
  886. public function test_can_upload_photo_to_order(): void
  887. {
  888. Storage::fake('public');
  889. $order = Order::factory()->create();
  890. // Use create() instead of image() to avoid GD extension requirement
  891. $photo = UploadedFile::fake()->create('photo.jpg', 100, 'image/jpeg');
  892. $response = $this->actingAs($this->managerUser)
  893. ->post(route('order.upload-photo', $order), [
  894. 'photo' => [$photo],
  895. ]);
  896. $response->assertRedirect(route('order.show', $order));
  897. $this->assertCount(1, $order->fresh()->photos);
  898. }
  899. public function test_can_delete_photo_from_order(): void
  900. {
  901. Storage::fake('public');
  902. $order = Order::factory()->create();
  903. $file = File::factory()->create();
  904. $order->photos()->attach($file);
  905. // This route requires admin role
  906. $response = $this->actingAs($this->adminUser)
  907. ->delete(route('order.delete-photo', [$order, $file]));
  908. $response->assertRedirect(route('order.show', $order));
  909. $this->assertCount(0, $order->fresh()->photos);
  910. }
  911. public function test_can_delete_all_photos_from_order(): void
  912. {
  913. Storage::fake('public');
  914. $order = Order::factory()->create();
  915. $files = File::factory()->count(3)->create();
  916. $order->photos()->attach($files->pluck('id'));
  917. // This route requires admin role
  918. $response = $this->actingAs($this->adminUser)
  919. ->delete(route('order.delete-all-photos', $order));
  920. $response->assertRedirect(route('order.show', $order));
  921. $this->assertCount(0, $order->fresh()->photos);
  922. }
  923. // ==================== Document Management ====================
  924. public function test_can_upload_document_to_order(): void
  925. {
  926. Storage::fake('public');
  927. $order = Order::factory()->create();
  928. $document = UploadedFile::fake()->create('document.pdf', 100);
  929. $response = $this->actingAs($this->managerUser)
  930. ->post(route('order.upload-document', $order), [
  931. 'document' => [$document],
  932. ]);
  933. $response->assertRedirect(route('order.show', $order));
  934. $this->assertCount(1, $order->fresh()->documents);
  935. }
  936. public function test_upload_document_preserves_unicode_and_quotes_filename(): void
  937. {
  938. Storage::fake('public');
  939. $order = Order::factory()->create();
  940. $filename = "Документ «смета» 'финал' \"v2\".pdf";
  941. $document = UploadedFile::fake()->create($filename, 100, 'application/pdf');
  942. $response = $this->actingAs($this->managerUser)
  943. ->post(route('order.upload-document', $order), [
  944. 'document' => [$document],
  945. ]);
  946. $response->assertRedirect(route('order.show', $order));
  947. $saved = $order->fresh()->documents->first();
  948. $this->assertNotNull($saved);
  949. $this->assertEquals($filename, $saved->original_name);
  950. $this->assertEquals('orders/' . $order->id . '/document/' . $filename, $saved->path);
  951. Storage::disk('public')->assertExists($saved->path);
  952. }
  953. public function test_upload_statement_preserves_unicode_and_quotes_filename(): void
  954. {
  955. Storage::fake('public');
  956. $order = Order::factory()->create();
  957. $filename = "Акт «приемки» 'этап 1' \"финал\".pdf";
  958. $statement = UploadedFile::fake()->create($filename, 100, 'application/pdf');
  959. $response = $this->actingAs($this->managerUser)
  960. ->post(route('order.upload-statement', $order), [
  961. 'statement' => [$statement],
  962. ]);
  963. $response->assertRedirect(route('order.show', $order));
  964. $saved = $order->fresh()->statements->first();
  965. $this->assertNotNull($saved);
  966. $this->assertEquals($filename, $saved->original_name);
  967. $this->assertEquals('orders/' . $order->id . '/statement/' . $filename, $saved->path);
  968. Storage::disk('public')->assertExists($saved->path);
  969. }
  970. public function test_upload_document_limits_to_5_files(): void
  971. {
  972. Storage::fake('public');
  973. $order = Order::factory()->create();
  974. $documents = [];
  975. for ($i = 0; $i < 7; $i++) {
  976. $documents[] = UploadedFile::fake()->create("document{$i}.pdf", 100);
  977. }
  978. $this->actingAs($this->managerUser)
  979. ->post(route('order.upload-document', $order), [
  980. 'document' => $documents,
  981. ]);
  982. $this->assertCount(5, $order->fresh()->documents);
  983. }
  984. public function test_can_upload_webp_photo(): void
  985. {
  986. Storage::fake('public');
  987. $order = Order::factory()->create();
  988. $photo = UploadedFile::fake()->create('photo.webp', 100, 'image/webp');
  989. $response = $this->actingAs($this->managerUser)
  990. ->post(route('order.upload-photo', $order), [
  991. 'photo' => [$photo],
  992. ]);
  993. $response->assertRedirect();
  994. $saved = $order->fresh()->photos->first();
  995. $this->assertNotNull($saved);
  996. $this->assertSame('photo.webp', $saved->original_name);
  997. }
  998. // ==================== Generation ====================
  999. public function test_generate_installation_pack_is_allowed_for_any_status_when_data_is_valid(): void
  1000. {
  1001. Bus::fake();
  1002. $product = Product::factory()->create();
  1003. $mafOrder = MafOrder::factory()->create(['product_id' => $product->id]);
  1004. $order = Order::factory()->create([
  1005. 'order_status_id' => Order::STATUS_NEW,
  1006. ]);
  1007. ProductSKU::factory()->create([
  1008. 'order_id' => $order->id,
  1009. 'product_id' => $product->id,
  1010. 'maf_order_id' => $mafOrder->id,
  1011. ]);
  1012. $response = $this->actingAs($this->managerUser)
  1013. ->get(route('order.generate-installation-pack', $order));
  1014. $response->assertRedirect(route('order.show', $order));
  1015. $response->assertSessionHas('success');
  1016. Bus::assertDispatched(GenerateInstallationPack::class);
  1017. }
  1018. public function test_generate_installation_pack_still_requires_connected_maf(): void
  1019. {
  1020. Bus::fake();
  1021. $product = Product::factory()->create();
  1022. $order = Order::factory()->create([
  1023. 'order_status_id' => Order::STATUS_IN_MOUNT,
  1024. ]);
  1025. ProductSKU::factory()->create([
  1026. 'order_id' => $order->id,
  1027. 'product_id' => $product->id,
  1028. 'maf_order_id' => null,
  1029. ]);
  1030. $response = $this->actingAs($this->managerUser)
  1031. ->get(route('order.generate-installation-pack', $order));
  1032. $response->assertRedirect(route('order.show', $order));
  1033. $response->assertSessionHas('danger');
  1034. Bus::assertNotDispatched(GenerateInstallationPack::class);
  1035. }
  1036. public function test_admin_can_create_ttn_with_departure_date_and_increment_counter(): void
  1037. {
  1038. Bus::fake();
  1039. Setting::set(Setting::KEY_TTN_NEXT_NUMBER, 10);
  1040. $product = Product::factory()->create();
  1041. $order = Order::factory()->create([
  1042. 'installation_date' => '2026-04-15',
  1043. ]);
  1044. $sku = ProductSKU::factory()->create([
  1045. 'order_id' => $order->id,
  1046. 'product_id' => $product->id,
  1047. ]);
  1048. $response = $this->actingAs($this->adminUser)
  1049. ->post(route('order.create-ttn'), [
  1050. 'order_number' => 'З-100',
  1051. 'order_date' => '2026-04-07',
  1052. 'departure_date' => '2026-04-08',
  1053. 'order_sum' => '150000',
  1054. 'skus' => [$sku->id],
  1055. ]);
  1056. $response->assertRedirect();
  1057. $response->assertSessionHas('success');
  1058. $this->assertDatabaseHas('ttns', [
  1059. 'ttn_number' => 10,
  1060. 'order_number' => 'З-100',
  1061. 'order_date' => '2026-04-07',
  1062. 'departure_date' => '2026-04-08',
  1063. 'order_sum' => '150000',
  1064. ]);
  1065. $this->assertSame(11, Setting::getInt(Setting::KEY_TTN_NEXT_NUMBER));
  1066. $ttn = Ttn::query()->where('ttn_number', 10)->firstOrFail();
  1067. $this->assertSame([(string) $sku->id], array_map('strval', json_decode($ttn->skus, true)));
  1068. Bus::assertDispatched(GenerateTtnPack::class);
  1069. }
  1070. // ==================== Export ====================
  1071. public function test_can_export_orders(): void
  1072. {
  1073. Order::factory()->count(3)->create();
  1074. // This route requires admin role
  1075. $response = $this->actingAs($this->adminUser)
  1076. ->post(route('order.export'));
  1077. $response->assertRedirect(route('order.index'));
  1078. $response->assertSessionHas('success');
  1079. }
  1080. public function test_can_export_single_order(): void
  1081. {
  1082. $order = Order::factory()->create();
  1083. // This route requires admin role
  1084. $response = $this->actingAs($this->adminUser)
  1085. ->post(route('order.export-one', $order));
  1086. $response->assertRedirect(route('order.show', $order));
  1087. $response->assertSessionHas('success');
  1088. }
  1089. }