feat: [client] Client API 사업자 정보 필드 및 toggle 버그 수정

- business_no, business_type, business_item 필드 추가
- toggle 로직 수정: boolean 캐스팅 호환 (is_active === 'Y' → !is_active)
This commit is contained in:
2025-12-04 15:40:24 +09:00
parent f48ac54fe4
commit 165512e121
7 changed files with 279 additions and 2 deletions

View File

@@ -21,6 +21,9 @@ public function rules(): array
'phone' => 'nullable|string|max:20',
'email' => 'nullable|email|max:100',
'address' => 'nullable|string|max:255',
'business_no' => 'nullable|string|max:20',
'business_type' => 'nullable|string|max:50',
'business_item' => 'nullable|string|max:100',
'is_active' => 'nullable|in:Y,N',
];
}

View File

@@ -20,7 +20,9 @@ public function rules(): array
'contact_person' => 'nullable|string|max:100',
'phone' => 'nullable|string|max:20',
'email' => 'nullable|email|max:100',
'address' => 'nullable|string|max:255',
'address' => 'nullable|string|max:255', 'business_no' => 'nullable|string|max:20',
'business_type' => 'nullable|string|max:50',
'business_item' => 'nullable|string|max:100',
'is_active' => 'nullable|in:Y,N',
];
}

View File

@@ -19,6 +19,9 @@ class Client extends Model
'phone',
'email',
'address',
'business_no',
'business_type',
'business_item',
'is_active',
];

View File

@@ -63,6 +63,9 @@ public function store(array $params)
'phone' => 'nullable|string|max:30',
'email' => 'nullable|email|max:80',
'address' => 'nullable|string|max:255',
'business_no' => 'nullable|string|max:20',
'business_type' => 'nullable|string|max:50',
'business_item' => 'nullable|string|max:100',
'is_active' => 'nullable|in:Y,N',
]);
@@ -104,6 +107,9 @@ public function update(int $id, array $params)
'phone' => 'nullable|string|max:30',
'email' => 'nullable|email|max:80',
'address' => 'nullable|string|max:255',
'business_no' => 'nullable|string|max:20',
'business_type' => 'nullable|string|max:50',
'business_item' => 'nullable|string|max:100',
'is_active' => 'nullable|in:Y,N',
]);
@@ -157,7 +163,8 @@ public function toggle(int $id)
throw new NotFoundHttpException(__('error.not_found'));
}
$client->is_active = $client->is_active === 'Y' ? 'N' : 'Y';
// Model에서 is_active가 boolean으로 캐스팅되므로 boolean으로 토글
$client->is_active = ! $client->is_active;
$client->save();
return $client->refresh();

View File

@@ -19,6 +19,9 @@
* @OA\Property(property="phone", type="string", nullable=true, example="010-1234-5678"),
* @OA\Property(property="email", type="string", nullable=true, example="client@example.com"),
* @OA\Property(property="address", type="string", nullable=true, example="서울시 강남구"),
* @OA\Property(property="business_no", type="string", nullable=true, maxLength=20, example="123-45-67890", description="사업자등록번호"),
* @OA\Property(property="business_type", type="string", nullable=true, maxLength=50, example="제조업", description="업태"),
* @OA\Property(property="business_item", type="string", nullable=true, maxLength=100, example="전자부품", description="업종"),
* @OA\Property(property="is_active", type="string", enum={"Y", "N"}, example="Y"),
* @OA\Property(property="created_at", type="string", example="2025-10-01 12:00:00"),
* @OA\Property(property="updated_at", type="string", example="2025-10-01 12:00:00")
@@ -71,6 +74,9 @@
* @OA\Property(property="phone", type="string", nullable=true, maxLength=20, example="010-1234-5678"),
* @OA\Property(property="email", type="string", nullable=true, maxLength=100, example="client@example.com"),
* @OA\Property(property="address", type="string", nullable=true, maxLength=255, example="서울시 강남구"),
* @OA\Property(property="business_no", type="string", nullable=true, maxLength=20, example="123-45-67890", description="사업자등록번호"),
* @OA\Property(property="business_type", type="string", nullable=true, maxLength=50, example="제조업", description="업태"),
* @OA\Property(property="business_item", type="string", nullable=true, maxLength=100, example="전자부품", description="업종"),
* @OA\Property(property="is_active", type="string", enum={"Y", "N"}, example="Y")
* )
*
@@ -85,6 +91,9 @@
* @OA\Property(property="phone", type="string", nullable=true, maxLength=20),
* @OA\Property(property="email", type="string", nullable=true, maxLength=100),
* @OA\Property(property="address", type="string", nullable=true, maxLength=255),
* @OA\Property(property="business_no", type="string", nullable=true, maxLength=20, description="사업자등록번호"),
* @OA\Property(property="business_type", type="string", nullable=true, maxLength=50, description="업태"),
* @OA\Property(property="business_item", type="string", nullable=true, maxLength=100, description="업종"),
* @OA\Property(property="is_active", type="string", enum={"Y", "N"})
* )
*/

View File

@@ -0,0 +1,223 @@
{
"name": "Client API CRUD 테스트",
"description": "거래처(Client) API 전체 CRUD 테스트 - 생성, 조회, 수정, 토글, 삭제 포함. business_no, business_type, business_item 신규 필드 검증 포함.",
"version": "1.0",
"config": {
"baseUrl": "https://api.sam.kr/api/v1",
"apiKey": "{{$env.FLOW_TESTER_API_KEY}}",
"timeout": 30000,
"stopOnFailure": true
},
"variables": {
"user_id": "{{$env.FLOW_TESTER_USER_ID}}",
"user_pwd": "{{$env.FLOW_TESTER_USER_PWD}}",
"test_client_code": "TEST_CLIENT_{{$timestamp}}"
},
"steps": [
{
"id": "login",
"name": "1. 로그인 - 토큰 획득",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.access_token": "@isString"
}
},
"extract": {
"token": "$.access_token"
}
},
{
"id": "create_client",
"name": "2. 거래처 생성 (신규 필드 포함)",
"method": "POST",
"endpoint": "/clients",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"client_code": "{{test_client_code}}",
"name": "테스트 거래처",
"contact_person": "홍길동",
"phone": "02-1234-5678",
"email": "test@example.com",
"address": "서울시 강남구 테헤란로 123",
"business_no": "123-45-67890",
"business_type": "제조업",
"business_item": "전자부품",
"is_active": "Y"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.id": "@isNumber",
"$.data.client_code": "{{test_client_code}}",
"$.data.name": "테스트 거래처",
"$.data.business_no": "123-45-67890",
"$.data.business_type": "제조업",
"$.data.business_item": "전자부품"
}
},
"extract": {
"client_id": "$.data.id"
}
},
{
"id": "list_clients",
"name": "3. 거래처 목록 조회",
"method": "GET",
"endpoint": "/clients",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"params": {
"page": 1,
"size": 20,
"q": "테스트"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.data": "@isArray",
"$.data.current_page": 1
}
}
},
{
"id": "show_client",
"name": "4. 거래처 단건 조회",
"method": "GET",
"endpoint": "/clients/{{create_client.client_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.id": "{{create_client.client_id}}",
"$.data.client_code": "{{test_client_code}}",
"$.data.business_no": "123-45-67890",
"$.data.business_type": "제조업",
"$.data.business_item": "전자부품"
}
}
},
{
"id": "update_client",
"name": "5. 거래처 수정 (신규 필드 변경)",
"method": "PUT",
"endpoint": "/clients/{{create_client.client_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"name": "테스트 거래처 (수정됨)",
"contact_person": "김철수",
"business_no": "987-65-43210",
"business_type": "도소매업",
"business_item": "IT솔루션"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.name": "테스트 거래처 (수정됨)",
"$.data.contact_person": "김철수",
"$.data.business_no": "987-65-43210",
"$.data.business_type": "도소매업",
"$.data.business_item": "IT솔루션"
}
}
},
{
"id": "toggle_client",
"name": "6. 거래처 활성/비활성 토글",
"method": "PATCH",
"endpoint": "/clients/{{create_client.client_id}}/toggle",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.is_active": "N"
}
}
},
{
"id": "toggle_client_back",
"name": "7. 거래처 토글 복원 (Y로)",
"method": "PATCH",
"endpoint": "/clients/{{create_client.client_id}}/toggle",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.is_active": "Y"
}
}
},
{
"id": "list_active_only",
"name": "8. 활성 거래처만 조회",
"method": "GET",
"endpoint": "/clients",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"params": {
"only_active": true
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.data": "@isArray"
}
}
},
{
"id": "delete_client",
"name": "9. 거래처 삭제",
"method": "DELETE",
"endpoint": "/clients/{{create_client.client_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "verify_deleted",
"name": "10. 삭제 확인 (404 예상)",
"method": "GET",
"endpoint": "/clients/{{create_client.client_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [404],
"jsonPath": {
"$.success": false
}
}
}
]
}

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('clients', function (Blueprint $table) {
$table->string('business_no', 20)->nullable()->after('address')->comment('사업자등록번호');
$table->string('business_type', 50)->nullable()->after('business_no')->comment('업태');
$table->string('business_item', 100)->nullable()->after('business_type')->comment('업종');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('clients', function (Blueprint $table) {
$table->dropColumn(['business_no', 'business_type', 'business_item']);
});
}
};