setUpAuthenticatedUser(); // 테스트용 거래처 $this->client = Client::create([ 'tenant_id' => $this->tenant->id, 'name' => '테스트 거래처', 'client_code' => 'CLI'.uniqid(), 'is_active' => true, 'created_by' => $this->user->id, ]); } // ==================== 목록 조회 ==================== public function test_수주_목록_조회(): void { Order::create([ 'tenant_id' => $this->tenant->id, 'order_no' => 'ORD-'.uniqid(), 'order_type_code' => Order::TYPE_ORDER, 'status_code' => Order::STATUS_DRAFT, 'client_id' => $this->client->id, 'client_name' => $this->client->name, 'quantity' => 10, 'supply_amount' => 1000000, 'tax_amount' => 100000, 'total_amount' => 1100000, 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); $response = $this->api('get', '/api/v1/orders'); $this->assertApiPaginated($response); $data = $response->json('data.data'); $this->assertNotEmpty($data); } public function test_수주_통계_조회(): void { Order::create([ 'tenant_id' => $this->tenant->id, 'order_no' => 'ORD-'.uniqid(), 'order_type_code' => Order::TYPE_ORDER, 'status_code' => Order::STATUS_CONFIRMED, 'client_id' => $this->client->id, 'client_name' => $this->client->name, 'quantity' => 5, 'supply_amount' => 500000, 'tax_amount' => 50000, 'total_amount' => 550000, 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); $response = $this->api('get', '/api/v1/orders/stats'); $response->assertStatus(200) ->assertJsonStructure(['success', 'data']); } // ==================== 생성 ==================== public function test_수주_생성_성공(): void { $response = $this->api('post', '/api/v1/orders', [ 'order_type_code' => Order::TYPE_ORDER, 'status_code' => Order::STATUS_DRAFT, 'client_id' => $this->client->id, 'client_name' => $this->client->name, 'site_name' => '테스트 현장', 'supply_amount' => 2000000, 'tax_amount' => 200000, 'total_amount' => 2200000, 'delivery_date' => now()->addDays(14)->format('Y-m-d'), 'items' => [ [ 'item_name' => '블라인드 A형', 'quantity' => 10, 'unit_price' => 200000, ], ], ]); $response->assertStatus(200); $this->assertTrue($response->json('success')); $this->assertDatabaseHas('orders', [ 'client_id' => $this->client->id, 'site_name' => '테스트 현장', 'tenant_id' => $this->tenant->id, ]); } public function test_수주_생성_빈_데이터_허용_확인(): void { // NOTE: 현재 API는 빈 데이터로도 수주 생성을 허용함 // FormRequest 검증 강화가 필요한 지점 (D4 개선 대상) $response = $this->api('post', '/api/v1/orders', []); $response->assertStatus(200); } // ==================== 상세 조회 ==================== public function test_수주_상세_조회(): void { $order = $this->createOrder(); $response = $this->api('get', "/api/v1/orders/{$order->id}"); $this->assertApiSuccess($response); $data = $response->json('data'); $this->assertEquals($order->id, $data['id']); $this->assertEquals($order->order_no, $data['order_no']); } public function test_존재하지_않는_수주_조회시_404(): void { $response = $this->api('get', '/api/v1/orders/999999'); $response->assertStatus(404); } // ==================== 수정 ==================== public function test_수주_수정_성공(): void { $order = $this->createOrder(); $response = $this->api('put', "/api/v1/orders/{$order->id}", [ 'order_type_code' => Order::TYPE_ORDER, 'status_code' => Order::STATUS_DRAFT, 'client_id' => $this->client->id, 'client_name' => '수정된 거래처명', 'site_name' => '수정된 현장', 'supply_amount' => 3000000, 'tax_amount' => 300000, 'total_amount' => 3300000, 'items' => [ [ 'item_name' => '블라인드 B형', 'quantity' => 20, 'unit_price' => 150000, ], ], ]); $response->assertStatus(200); $this->assertDatabaseHas('orders', [ 'id' => $order->id, 'site_name' => '수정된 현장', ]); } // ==================== 삭제 ==================== public function test_수주_삭제_성공(): void { $order = $this->createOrder(); $response = $this->api('delete', "/api/v1/orders/{$order->id}"); $response->assertStatus(200); $this->assertSoftDeleted('orders', ['id' => $order->id]); } public function test_수주_일괄_삭제(): void { $order1 = $this->createOrder(); $order2 = $this->createOrder(); $response = $this->api('delete', '/api/v1/orders/bulk', [ 'ids' => [$order1->id, $order2->id], ]); $response->assertStatus(200); $this->assertSoftDeleted('orders', ['id' => $order1->id]); $this->assertSoftDeleted('orders', ['id' => $order2->id]); } // ==================== 상태 변경 ==================== public function test_수주_상태_등록에서_확정으로_변경(): void { $order = $this->createOrder(Order::STATUS_DRAFT); $response = $this->api('patch', "/api/v1/orders/{$order->id}/status", [ 'status' => Order::STATUS_CONFIRMED, ]); $response->assertStatus(200); $this->assertDatabaseHas('orders', [ 'id' => $order->id, 'status_code' => Order::STATUS_CONFIRMED, ]); } public function test_수주_상태_취소(): void { $order = $this->createOrder(Order::STATUS_DRAFT); $response = $this->api('patch', "/api/v1/orders/{$order->id}/status", [ 'status' => Order::STATUS_CANCELLED, ]); $response->assertStatus(200); $this->assertDatabaseHas('orders', [ 'id' => $order->id, 'status_code' => Order::STATUS_CANCELLED, ]); } // ==================== 인증 ==================== public function test_미인증_요청시_401(): void { $response = $this->withHeaders([ 'X-API-KEY' => $this->apiKey, 'Accept' => 'application/json', ])->getJson('/api/v1/orders'); $response->assertStatus(401); } // ==================== 헬퍼 ==================== private function createOrder(string $status = Order::STATUS_DRAFT): Order { return Order::create([ 'tenant_id' => $this->tenant->id, 'order_no' => 'ORD-'.uniqid(), 'order_type_code' => Order::TYPE_ORDER, 'status_code' => $status, 'client_id' => $this->client->id, 'client_name' => $this->client->name, 'site_name' => '테스트 현장', 'quantity' => 10, 'supply_amount' => 1000000, 'tax_amount' => 100000, 'total_amount' => 1100000, 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); } }