Dựa trên tài liệu đặc tả yêu cầu, tôi sẽ viết testcase API cho các chức năng: Đăng ký combo, Hủy combo, và Lấy danh sách SPTC combo. ## 🧪 **TESTCASE API CHO COMBO SPTC** ### **1. API LẤY DANH SÁCH COMBO SPTC** **Endpoint:** `GET /api/v1/combo-sptc/list` **Test Case 1: Lấy danh sách thành công** ```json { "test_case_id": "TC_COMBO_LIST_001", "description": "Lấy danh sách combo SPTC thành công cho KH cá nhân", "preconditions": ["KH đã login", "KH thuộc nhóm careby được gán combo"], "input": { "customer_id": "103C2034255", "customer_type": "Cá nhân", "careby_group": "0012" }, "expected_output": { "status_code": 200, "response": { "success": true, "data": [ { "combo_code": "COMBO001", "combo_name": "Gói ưu đãi VIP", "description": "Mô tả gói combo", "customer_type": "Cá nhân", "online_apply": true, "contract_type": "CT001", "effective_date": "2025-07-01", "expire_date": "2025-12-31", "status": "Hoạt động" } ] } } } ``` **Test Case 2: KH không thuộc nhóm careby** ```json { "test_case_id": "TC_COMBO_LIST_002", "description": "KH không thuộc nhóm careby - không thấy combo", "preconditions": ["KH đã login", "KH không thuộc nhóm careby được gán"], "input": { "customer_id": "103C2034999", "customer_type": "Cá nhân", "careby_group": "0099" }, "expected_output": { "status_code": 200, "response": { "success": true, "data": [] } } } ``` **Test Case 3: Combo chỉ áp dụng offline** ```json { "test_case_id": "TC_COMBO_LIST_003", "description": "Combo chỉ áp dụng offline - không hiển thị online", "preconditions": ["KH đã login", "Combo có online_apply = false"], "input": { "customer_id": "103C2034255", "customer_type": "Cá nhân", "careby_group": "0012" }, "expected_output": { "status_code": 200, "response": { "success": true, "data": [] // Không bao gồm combo offline } } } ``` ### **2. API ĐĂNG KÝ COMBO SPTC** **Endpoint:** `POST /api/v1/combo-sptc/register` **Test Case 1: Đăng ký thành công** ```json { "test_case_id": "TC_COMBO_REGISTER_001", "description": "Đăng ký combo SPTC thành công", "preconditions": [ "KH đã login", "Combo đang hoạt động", "KH thuộc nhóm careby được gán", "KH chưa đăng ký combo trùng AFTYPE" ], "input": { "customer_id": "103C2034255", "combo_code": "COMBO001", "contract_type": "CT001", "otp": "123456", "agree_terms": true, "device_info": { "device_type": "Mobile App", "ip_address": "192.168.1.100", "device_id": "DEVICE123" } }, "expected_output": { "status_code": 200, "response": { "success": true, "message": "Đăng ký combo thành công", "registration_id": "REG00120250715", "status": "Chờ hiệu lực", "effective_date": "2025-07-16" // T+1 } } } ``` **Test Case 2: Đăng ký combo trùng AFTYPE - tự động hủy combo cũ** ```json { "test_case_id": "TC_COMBO_REGISTER_002", "description": "Đăng ký combo mới trùng AFTYPE - hủy combo cũ", "preconditions": [ "KH đã có combo đang hiệu lực COMBO001", "Combo mới COMBO002 trùng AFTYPE với COMBO001" ], "input": { "customer_id": "103C2034255", "combo_code": "COMBO002", "contract_type": "CT002", "otp": "123456", "agree_terms": true }, "expected_output": { "status_code": 200, "response": { "success": true, "message": "Đăng ký combo thành công, combo cũ đã được hủy", "cancelled_combos": ["COMBO001"], "status": "Chờ hiệu lực" } } } ``` **Test Case 3: Đăng ký thất bại - KH trong danh sách loại trừ** ```json { "test_case_id": "TC_COMBO_REGISTER_003", "description": "Đăng ký thất bại - KH bị loại trừ", "preconditions": ["KH nằm trong danh sách tài khoản loại trừ của combo"], "input": { "customer_id": "103C2034999", // TK bị loại trừ "combo_code": "COMBO001", "contract_type": "CT001", "otp": "123456", "agree_terms": true }, "expected_output": { "status_code": 400, "response": { "success": false, "error_code": "CUSTOMER_EXCLUDED", "message": "Khách hàng không được phép đăng ký combo này" } } } ``` **Test Case 4: Đăng ký thất bại - OTP sai** ```json { "test_case_id": "TC_COMBO_REGISTER_004", "description": "Đăng ký thất bại - OTP không hợp lệ", "preconditions": ["KH đã login", "Combo đang hoạt động"], "input": { "customer_id": "103C2034255", "combo_code": "COMBO001", "contract_type": "CT001", "otp": "999999", // OTP sai "agree_terms": true }, "expected_output": { "status_code": 400, "response": { "success": false, "error_code": "INVALID_OTP", "message": "OTP không hợp lệ" } } } ``` ### **3. API HỦY COMBO SPTC** **Endpoint:** `POST /api/v1/combo-sptc/cancel` **Test Case 1: Hủy combo thành công** ```json { "test_case_id": "TC_COMBO_CANCEL_001", "description": "Hủy combo SPTC thành công", "preconditions": [ "KH đã đăng ký combo đang hiệu lực", "Combo chưa hết hạn" ], "input": { "customer_id": "103C2034255", "combo_code": "COMBO001", "cancel_reason": "Không có nhu cầu sử dụng", "otp": "123456" }, "expected_output": { "status_code": 200, "response": { "success": true, "message": "Hủy combo thành công", "cancellation_date": "2025-07-15", "effective_cancel_date": "2025-07-16" // Có hiệu lực từ T+1 } } } ``` **Test Case 2: Hủy combo không tồn tại** ```json { "test_case_id": "TC_COMBO_CANCEL_002", "description": "Hủy combo không tồn tại", "preconditions": ["KH đã login"], "input": { "customer_id": "103C2034255", "combo_code": "COMBO999", // Combo không tồn tại "cancel_reason": "Không có nhu cầu", "otp": "123456" }, "expected_output": { "status_code": 404, "response": { "success": false, "error_code": "COMBO_NOT_FOUND", "message": "Combo không tồn tại hoặc không thuộc sở hữu" } } } ``` **Test Case 3: Hủy combo đã hết hạn** ```json { "test_case_id": "TC_COMBO_CANCEL_003", "description": "Hủy combo đã hết hạn", "preconditions": ["Combo đã hết hiệu lực"], "input": { "customer_id": "103C2034255", "combo_code": "COMBO001", "cancel_reason": "Không có nhu cầu", "otp": "123456" }, "expected_output": { "status_code": 400, "response": { "success": false, "error_code": "COMBO_EXPIRED", "message": "Combo đã hết hiệu lực, không thể hủy" } } } ``` ### **4. API LẤY CHI TIẾT COMBO** **Endpoint:** `GET /api/v1/combo-sptc/detail/{combo_code}` **Test Case 1: Lấy chi tiết combo thành công** ```json { "test_case_id": "TC_COMBO_DETAIL_001", "description": "Lấy chi tiết combo SPTC thành công", "preconditions": ["Combo tồn tại và đang hoạt động"], "input": { "combo_code": "COMBO001", "customer_id": "103C2034255" }, "expected_output": { "status_code": 200, "response": { "success": true, "data": { "combo_code": "COMBO001", "combo_name": "Gói ưu đãi VIP", "description": "Mô tả chi tiết gói combo", "customer_type": "Cá nhân", "online_apply": true, "contract_type": "CT001", "effective_date": "2025-07-01", "expire_date": "2025-12-31", "status": "Hoạt động", "policies": [ { "policy_type": "Chính sách ưu đãi phí môi giới", "policy_code": "POLICY001", "policy_name": "Ưu đãi phí giao dịch" }, { "policy_type": "Chính sách ưu đãi phí margin", "policy_code": "POLICY002", "policy_name": "Ưu đãi lãi suất vay" } ], "account_types": [ { "product_type": "1", "account_type": "0002" }, { "product_type": "3", "account_type": "0004" } ] } } } } ``` ### **5. API KIỂM TRA ĐIỀU KIỆN ĐĂNG KÝ** **Endpoint:** `POST /api/v1/combo-sptc/check-eligibility` **Test Case 1: Kiểm tra điều kiện thành công** ```json { "test_case_id": "TC_ELIGIBILITY_001", "description": "Kiểm tra điều kiện đăng ký thành công", "preconditions": ["KH và combo đều hợp lệ"], "input": { "customer_id": "103C2034255", "combo_code": "COMBO001" }, "expected_output": { "status_code": 200, "response": { "success": true, "eligible": true, "message": "Khách hàng đủ điều kiện đăng ký", "conflicts": [], // Danh sách combo sẽ bị hủy nếu có "required_actions": ["XÁC_THỰC_OTP", "ĐỒNG_Ý_ĐIỀU_KHOẢN"] } } } ``` **Test Case 2: Kiểm tra có xung đột AFTYPE** ```json { "test_case_id": "TC_ELIGIBILITY_002", "description": "Kiểm tra có xung đột AFTYPE với combo hiện tại", "preconditions": ["KH đang có combo hiệu lực trùng AFTYPE"], "input": { "customer_id": "103C2034255", "combo_code": "COMBO002" }, "expected_output": { "status_code": 200, "response": { "success": true, "eligible": true, "message": "Khách hàng đủ điều kiện đăng ký", "conflicts": [ { "combo_code": "COMBO001", "combo_name": "Gói hiện tại", "conflict_type": "TRÙNG_AFTYPE", "action": "HỦY_TỰ_ĐỘNG" } ] } } } ``` ## 🔧 **Test Data Preparation** ```sql -- Dữ liệu test cần chuẩn bị INSERT INTO combo_sptc (combo_code, combo_name, customer_type, online_apply, status) VALUES ('COMBO001', 'Gói VIP', 'Cá nhân', true, 'Hoạt động'); INSERT INTO customer_careby (customer_id, careby_group) VALUES ('103C2034255', '0012'); INSERT INTO combo_careby (combo_code, careby_group, include_exclude) VALUES ('COMBO001', '0012', 'Bao gồm'); ``` Các testcase này bao phủ các scenario chính theo đặc tả yêu cầu, bao gồm: - ✅ Quy trình đăng ký/hủy combo - ✅ Kiểm tra điều kiện AFTYPE trùng - ✅ Xử lý nhóm careby và tài khoản loại trừ - ✅ Tích hợp OTP và điều khoản hợp đồng - ✅ Logging thông tin đăng ký theo yêu cầu