- BadDebtApiTest: 악성채권 API 테스트 14개 - CRUD, 요약통계, 서류첨부, 메모, 필터링 - PopupApiTest: 팝업관리 API 테스트 10개 - CRUD, 활성팝업조회, 기간검증
527 lines
16 KiB
PHP
527 lines
16 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\BadDebt;
|
|
|
|
use App\Models\BadDebts\BadDebt;
|
|
use App\Models\BadDebts\BadDebtDocument;
|
|
use App\Models\BadDebts\BadDebtMemo;
|
|
use App\Models\Members\User;
|
|
use App\Models\Members\UserTenant;
|
|
use App\Models\Orders\Client;
|
|
use App\Models\Tenants\Tenant;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Tests\TestCase;
|
|
|
|
class BadDebtApiTest extends TestCase
|
|
{
|
|
use DatabaseTransactions;
|
|
|
|
private Tenant $tenant;
|
|
|
|
private User $user;
|
|
|
|
private Client $client;
|
|
|
|
private string $apiKey;
|
|
|
|
private string $token;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// 테스트용 API Key 생성
|
|
$this->apiKey = 'test-api-key-'.uniqid();
|
|
\DB::table('api_keys')->insert([
|
|
'key' => $this->apiKey,
|
|
'description' => 'Test API Key',
|
|
'is_active' => true,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
// Tenant 생성 또는 기존 사용
|
|
$this->tenant = Tenant::first() ?? Tenant::withoutEvents(function () {
|
|
return Tenant::create([
|
|
'company_name' => 'Test Company',
|
|
'code' => 'TEST'.uniqid(),
|
|
'email' => 'test@example.com',
|
|
'phone' => '010-1234-5678',
|
|
]);
|
|
});
|
|
|
|
// User 생성
|
|
$testUserId = 'testuser'.uniqid();
|
|
$this->user = User::create([
|
|
'user_id' => $testUserId,
|
|
'name' => 'Test User',
|
|
'email' => $testUserId.'@example.com',
|
|
'password' => bcrypt('password123'),
|
|
]);
|
|
|
|
// UserTenant 관계 생성
|
|
UserTenant::create([
|
|
'user_id' => $this->user->id,
|
|
'tenant_id' => $this->tenant->id,
|
|
'is_active' => true,
|
|
'is_default' => true,
|
|
]);
|
|
|
|
// Client 생성
|
|
$this->client = Client::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'name' => 'Test Client',
|
|
'client_code' => 'CLI'.uniqid(),
|
|
'created_by' => $this->user->id,
|
|
]);
|
|
|
|
// 로그인 및 토큰 획득
|
|
$this->loginAndGetToken();
|
|
}
|
|
|
|
protected function loginAndGetToken(): void
|
|
{
|
|
$response = $this->withHeaders([
|
|
'X-API-KEY' => $this->apiKey,
|
|
'Accept' => 'application/json',
|
|
])->postJson('/api/v1/login', [
|
|
'user_id' => $this->user->user_id,
|
|
'user_pwd' => 'password123',
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$this->token = $response->json('access_token');
|
|
}
|
|
|
|
protected function authenticatedRequest(string $method, string $uri, array $data = [])
|
|
{
|
|
return $this->withHeaders([
|
|
'X-API-KEY' => $this->apiKey,
|
|
'Authorization' => 'Bearer '.$this->token,
|
|
'Accept' => 'application/json',
|
|
])->{$method.'Json'}($uri, $data);
|
|
}
|
|
|
|
// ==================== BadDebt CRUD Tests ====================
|
|
|
|
public function test_can_list_bad_debts(): void
|
|
{
|
|
BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 1000000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'overdue_days' => 30,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('get', '/api/v1/bad-debts');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'message',
|
|
'data' => [
|
|
'data',
|
|
'current_page',
|
|
'total',
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function test_can_get_bad_debt_summary(): void
|
|
{
|
|
// 상태별 악성채권 생성
|
|
BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 1000000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 500000,
|
|
'status' => BadDebt::STATUS_RECOVERED,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('get', '/api/v1/bad-debts/summary');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'message',
|
|
'data' => [
|
|
'total_amount',
|
|
'collecting_amount',
|
|
'legal_action_amount',
|
|
'recovered_amount',
|
|
'bad_debt_amount',
|
|
],
|
|
]);
|
|
|
|
$data = $response->json('data');
|
|
$this->assertEquals(1500000, $data['total_amount']);
|
|
$this->assertEquals(1000000, $data['collecting_amount']);
|
|
$this->assertEquals(500000, $data['recovered_amount']);
|
|
}
|
|
|
|
public function test_can_create_bad_debt(): void
|
|
{
|
|
$response = $this->authenticatedRequest('post', '/api/v1/bad-debts', [
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 2000000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'overdue_days' => 45,
|
|
'occurred_at' => now()->subDays(45)->format('Y-m-d'),
|
|
]);
|
|
|
|
$response->assertStatus(201)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'message',
|
|
'data' => [
|
|
'id',
|
|
'client_id',
|
|
'debt_amount',
|
|
'status',
|
|
],
|
|
]);
|
|
|
|
$this->assertDatabaseHas('bad_debts', [
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 2000000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'tenant_id' => $this->tenant->id,
|
|
]);
|
|
}
|
|
|
|
public function test_can_show_bad_debt(): void
|
|
{
|
|
$badDebt = BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 1500000,
|
|
'status' => BadDebt::STATUS_LEGAL_ACTION,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('get', "/api/v1/bad-debts/{$badDebt->id}");
|
|
|
|
$response->assertStatus(200)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'message',
|
|
'data' => [
|
|
'id',
|
|
'client_id',
|
|
'debt_amount',
|
|
'status',
|
|
'client',
|
|
],
|
|
])
|
|
->assertJson([
|
|
'data' => [
|
|
'debt_amount' => '1500000.00',
|
|
'status' => BadDebt::STATUS_LEGAL_ACTION,
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function test_can_update_bad_debt(): void
|
|
{
|
|
$badDebt = BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 1000000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('put', "/api/v1/bad-debts/{$badDebt->id}", [
|
|
'status' => BadDebt::STATUS_LEGAL_ACTION,
|
|
'debt_amount' => 1200000,
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$this->assertDatabaseHas('bad_debts', [
|
|
'id' => $badDebt->id,
|
|
'status' => BadDebt::STATUS_LEGAL_ACTION,
|
|
'debt_amount' => 1200000,
|
|
]);
|
|
}
|
|
|
|
public function test_can_delete_bad_debt(): void
|
|
{
|
|
$badDebt = BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 500000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('delete', "/api/v1/bad-debts/{$badDebt->id}");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$this->assertSoftDeleted('bad_debts', [
|
|
'id' => $badDebt->id,
|
|
]);
|
|
}
|
|
|
|
public function test_can_toggle_bad_debt_active(): void
|
|
{
|
|
$badDebt = BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 500000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('patch', "/api/v1/bad-debts/{$badDebt->id}/toggle");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$this->assertDatabaseHas('bad_debts', [
|
|
'id' => $badDebt->id,
|
|
'is_active' => false,
|
|
]);
|
|
|
|
// 다시 토글
|
|
$response = $this->authenticatedRequest('patch', "/api/v1/bad-debts/{$badDebt->id}/toggle");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$this->assertDatabaseHas('bad_debts', [
|
|
'id' => $badDebt->id,
|
|
'is_active' => true,
|
|
]);
|
|
}
|
|
|
|
// ==================== Document Tests ====================
|
|
|
|
public function test_can_add_document_to_bad_debt(): void
|
|
{
|
|
$badDebt = BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 500000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
// 테스트용 파일 생성 (files 테이블에)
|
|
$fileId = \DB::table('files')->insertGetId([
|
|
'tenant_id' => $this->tenant->id,
|
|
'original_name' => 'test.pdf',
|
|
'display_name' => 'test.pdf',
|
|
'stored_name' => 'test_'.uniqid().'.pdf',
|
|
'file_name' => 'test.pdf',
|
|
'mime_type' => 'application/pdf',
|
|
'file_size' => 1024,
|
|
'file_path' => 'uploads/test.pdf',
|
|
'created_by' => $this->user->id,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('post', "/api/v1/bad-debts/{$badDebt->id}/documents", [
|
|
'document_type' => 'tax_invoice',
|
|
'file_id' => $fileId,
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
|
|
$this->assertDatabaseHas('bad_debt_documents', [
|
|
'bad_debt_id' => $badDebt->id,
|
|
'document_type' => 'tax_invoice',
|
|
'file_id' => $fileId,
|
|
]);
|
|
}
|
|
|
|
public function test_can_remove_document_from_bad_debt(): void
|
|
{
|
|
$badDebt = BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 500000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$document = BadDebtDocument::create([
|
|
'bad_debt_id' => $badDebt->id,
|
|
'document_type' => 'business_license',
|
|
'file_id' => 1,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('delete', "/api/v1/bad-debts/{$badDebt->id}/documents/{$document->id}");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$this->assertDatabaseMissing('bad_debt_documents', [
|
|
'id' => $document->id,
|
|
]);
|
|
}
|
|
|
|
// ==================== Memo Tests ====================
|
|
|
|
public function test_can_add_memo_to_bad_debt(): void
|
|
{
|
|
$badDebt = BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 500000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('post', "/api/v1/bad-debts/{$badDebt->id}/memos", [
|
|
'content' => '첫 번째 추심 시도 - 연락 안됨',
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
|
|
$this->assertDatabaseHas('bad_debt_memos', [
|
|
'bad_debt_id' => $badDebt->id,
|
|
'content' => '첫 번째 추심 시도 - 연락 안됨',
|
|
'created_by' => $this->user->id,
|
|
]);
|
|
}
|
|
|
|
public function test_can_remove_memo_from_bad_debt(): void
|
|
{
|
|
$badDebt = BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 500000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$memo = BadDebtMemo::create([
|
|
'bad_debt_id' => $badDebt->id,
|
|
'content' => '삭제할 메모',
|
|
'created_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('delete', "/api/v1/bad-debts/{$badDebt->id}/memos/{$memo->id}");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$this->assertDatabaseMissing('bad_debt_memos', [
|
|
'id' => $memo->id,
|
|
]);
|
|
}
|
|
|
|
// ==================== Filter Tests ====================
|
|
|
|
public function test_can_filter_bad_debts_by_status(): void
|
|
{
|
|
BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 1000000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 500000,
|
|
'status' => BadDebt::STATUS_RECOVERED,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('get', '/api/v1/bad-debts?status='.BadDebt::STATUS_COLLECTING);
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$data = $response->json('data.data');
|
|
$this->assertCount(1, $data);
|
|
$this->assertEquals(BadDebt::STATUS_COLLECTING, $data[0]['status']);
|
|
}
|
|
|
|
public function test_can_filter_bad_debts_by_client(): void
|
|
{
|
|
$client2 = Client::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'name' => 'Another Client',
|
|
'client_code' => 'CLI2'.uniqid(),
|
|
'created_by' => $this->user->id,
|
|
]);
|
|
|
|
BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $this->client->id,
|
|
'debt_amount' => 1000000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
BadDebt::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'client_id' => $client2->id,
|
|
'debt_amount' => 500000,
|
|
'status' => BadDebt::STATUS_COLLECTING,
|
|
'is_active' => true,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$response = $this->authenticatedRequest('get', '/api/v1/bad-debts?client_id='.$this->client->id);
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$data = $response->json('data.data');
|
|
$this->assertCount(1, $data);
|
|
$this->assertEquals($this->client->id, $data[0]['client_id']);
|
|
}
|
|
|
|
// ==================== Authentication Tests ====================
|
|
|
|
public function test_cannot_access_bad_debts_without_authentication(): void
|
|
{
|
|
$response = $this->withHeaders([
|
|
'X-API-KEY' => $this->apiKey,
|
|
'Accept' => 'application/json',
|
|
])->getJson('/api/v1/bad-debts');
|
|
|
|
$response->assertStatus(401);
|
|
}
|
|
} |