feat: add verification models, serializers, views, and core engine tests for multi-vendor document validation
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 29s
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 29s
This commit is contained in:
parent
5e11485ba8
commit
1ff0bd9f93
7 changed files with 614 additions and 0 deletions
522
CODEPLUS_API_DOCUMENTATION.md
Normal file
522
CODEPLUS_API_DOCUMENTATION.md
Normal file
|
|
@ -0,0 +1,522 @@
|
|||
# Codeplus (apihub.services) Document Verification Engine Documentation
|
||||
|
||||
This document covers all active verification functions implemented in the **Multi-Vendor Verification Engine** using the **Codeplus** (`apihub.services`) adapter.
|
||||
|
||||
---
|
||||
|
||||
## 1. Architecture & Failover Waterfall
|
||||
|
||||
The verification engine provides seamless waterfall cascading across onboarded vendors:
|
||||
- Every request is dispatched to the highest-priority active vendor.
|
||||
- If the vendor encounters an error (e.g. HTTP 5xx, timeout, network failure, or API failure status), the engine logs the failure and automatically cascades to the next vendor.
|
||||
- **Every attempt, raw vendor response, final normalized data, latency, and client response are permanently recorded in PostgreSQL.**
|
||||
|
||||
### Database Storage Architecture
|
||||
|
||||
1. **`VerificationTransaction` (`verifier_verificationtransaction`):**
|
||||
- `reference_id`: Unique UUID generated for each client request.
|
||||
- `document_type`: Type of document requested (`pan`, `bank_account`, `gstin`, etc.).
|
||||
- `status`: Final outcome (`SUCCESS`, `FAILED`, `ERROR`).
|
||||
- `successful_vendor`: Name of the vendor that resolved the verification (e.g. `codeplus`).
|
||||
- `input_payload`: Masked, audit-safe input data.
|
||||
- `final_data`: Normalized result payload.
|
||||
- `response_payload`: Complete response payload returned to the client.
|
||||
- `attempts_count`: Total number of vendors attempted in the waterfall.
|
||||
- `total_latency_ms`: Total execution time in milliseconds.
|
||||
- `created_at` / `updated_at`: Timestamps.
|
||||
|
||||
2. **`VendorAttemptLog` (`verifier_vendorattemptlog`):**
|
||||
- `transaction`: Foreign key to `VerificationTransaction`.
|
||||
- `attempt_number`: Sequential attempt sequence (`1`, `2`, ...).
|
||||
- `vendor_name`: Vendor adapter invoked (`codeplus`).
|
||||
- `status`: Vendor status (`SUCCESS`, `FAILED`, `ERROR`, `SKIPPED`).
|
||||
- `is_success`: Boolean indicator.
|
||||
- `data`: Extracted vendor data block.
|
||||
- `raw_response`: Full unaltered JSON/HTTP response returned by the upstream API.
|
||||
- `error_code` & `error_message`: Upstream failure codes and diagnostics.
|
||||
- `latency_ms`: Execution latency for this specific vendor hit.
|
||||
|
||||
---
|
||||
|
||||
## 2. Global Authentication & Configuration
|
||||
|
||||
The Codeplus adapter uses the following headers for all upstream calls:
|
||||
```http
|
||||
X-Client-Api-ID: CAPI-YYR0YJIE0VMTDENY
|
||||
X-Client-Api-Secret: s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
Environment variables configured in `docverify/settings.py` / `.env`:
|
||||
- `CODEPLUS_BASE_URL`: `https://apihub.services`
|
||||
- `CODEPLUS_CLIENT_API_ID`: `CAPI-YYR0YJIE0VMTDENY`
|
||||
- `CODEPLUS_CLIENT_API_SECRET`: `s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs`
|
||||
|
||||
---
|
||||
|
||||
## 3. Summary of Available Functions
|
||||
|
||||
| Function Name | Upstream Endpoint | Internal `document_type` | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Pan Verification (v5 Recommended)** | `POST /v5/pan-verify` | `pan`, `pan_v5`, `pan_verify` | Full PAN holder details with name, DOB, gender, masked Aadhaar & address. |
|
||||
| **Detailed PAN API** | `POST /v4/pan-detailed` | `pan_detailed` | Comprehensive PAN data including address, contact info, and profile. |
|
||||
| **PAN Advanced API** | `POST /v4/pan-advanced` | `pan_advanced` | Standard government database verification for PAN validity and taxpayer status. |
|
||||
| **Bank Verification (Full Details)** | `POST /v4/bank-verify` | `bank_account` | Penny drop routing for account holder name, MICR, IFSC, and branch details. |
|
||||
| **Fetch GST By PAN** | `POST /v4/fetch-gst` | `gst_by_pan`, `fetch_gst` | Retrieves all registered GSTIN entities associated with a business PAN. |
|
||||
| **Fetch MSME By PAN** | `POST /v4/msme-pan` | `msme`, `msme_by_pan`, `udyam` | Retrieves Udyam registration number and enterprise details linked to a PAN. |
|
||||
| **GST Verification (v5)** | `POST /v5/gst-verify` | `gstin`, `gst`, `gst_verify` | Verifies single GSTIN and returns legal business name and active status. |
|
||||
|
||||
---
|
||||
|
||||
## 4. API Reference & Sample Requests
|
||||
|
||||
### Function 1: Pan Verification (v5 Recommended)
|
||||
|
||||
- **Engine Request:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8092/api/verify/ \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"document_type": "pan",
|
||||
"data": {
|
||||
"pan": "ABCDE1234F"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
- **Direct Upstream cURL:**
|
||||
```bash
|
||||
curl --location 'https://apihub.services/v5/pan-verify' \
|
||||
--header 'X-Client-Api-ID: CAPI-YYR0YJIE0VMTDENY' \
|
||||
--header 'X-Client-Api-Secret: s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{"pan": "ABCDE1234F"}'
|
||||
```
|
||||
|
||||
- **Sample Engine Response (HTTP 200):**
|
||||
```json
|
||||
{
|
||||
"reference_id": "8a7c29e1-2244-48f1-9c6a-4933a1e94b21",
|
||||
"is_success": true,
|
||||
"status": "SUCCESS",
|
||||
"document_type": "pan",
|
||||
"successful_vendor": "codeplus",
|
||||
"data": {
|
||||
"document_type": "PAN",
|
||||
"pan": "ABCDE1234F",
|
||||
"pan_type": "Individual",
|
||||
"full_name": "RAHUL KUMAR",
|
||||
"first_name": "RAHUL",
|
||||
"middle_name": null,
|
||||
"last_name": "KUMAR",
|
||||
"gender": "male",
|
||||
"dob": "15/06/1995",
|
||||
"aadhaar_number": "XXXXXXXX1234",
|
||||
"aadhaar_linked": true,
|
||||
"address_details": {
|
||||
"building_name": "12/45",
|
||||
"locality": "Central Area",
|
||||
"street_name": "MG Road",
|
||||
"pincode": "641001",
|
||||
"city": "COIMBATORE",
|
||||
"state": "Tamil Nadu",
|
||||
"country": "India"
|
||||
},
|
||||
"service": "PAN_VERIFICATION",
|
||||
"result_code": 101,
|
||||
"client_ref_num": "REQ_1787136465034_demo12345",
|
||||
"provider_transaction_id": "TXN_1787136465045_demo12345",
|
||||
"transaction_id": "TXN_1787136465045_demo12345",
|
||||
"request_id": "REQ_1787136465034_demo12345",
|
||||
"timestamp": "2026-08-19T10:47:45.735Z"
|
||||
},
|
||||
"attempts_count": 1,
|
||||
"attempts": [
|
||||
{
|
||||
"attempt_number": 1,
|
||||
"vendor_name": "codeplus",
|
||||
"is_success": true,
|
||||
"status": "SUCCESS",
|
||||
"latency_ms": 310.2
|
||||
}
|
||||
],
|
||||
"error_message": null,
|
||||
"total_latency_ms": 315.4
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Function 2: Detailed PAN API
|
||||
|
||||
- **Engine Request:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8092/api/verify/ \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"document_type": "pan_detailed",
|
||||
"data": {
|
||||
"pan_number": "ABCDE1234F"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
- **Direct Upstream cURL:**
|
||||
```bash
|
||||
curl --location 'https://apihub.services/v4/pan-detailed' \
|
||||
--header 'X-Client-Api-ID: CAPI-YYR0YJIE0VMTDENY' \
|
||||
--header 'X-Client-Api-Secret: s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{"pan_number": "ABCDE1234F"}'
|
||||
```
|
||||
|
||||
- **Sample Upstream Response:**
|
||||
```json
|
||||
{
|
||||
"request_id": "7f3a1c92-5b84-4d21-a7e6-91c2f0d84b56",
|
||||
"transaction_id": "b6e8d4a1-2c73-49f5-9a10-5f7c3e821d64",
|
||||
"status": 200,
|
||||
"data": {
|
||||
"code": "1000",
|
||||
"message": "Valid PAN.",
|
||||
"pan_data": {
|
||||
"document_type": "PAN",
|
||||
"document_id": "ABCDE1234F",
|
||||
"name": "RAHUL KUMAR",
|
||||
"first_name": "RAHUL",
|
||||
"last_name": "KUMAR",
|
||||
"category": "P",
|
||||
"date_of_birth": "1995-06-15",
|
||||
"masked_aadhaar_number": "XXXXXXXX1234",
|
||||
"address_data": {
|
||||
"line_1": "12/45",
|
||||
"line_2": "MG Road",
|
||||
"street": "Central Area",
|
||||
"city": "COIMBATORE",
|
||||
"state": "TAMIL NADU",
|
||||
"pincode": "641001"
|
||||
},
|
||||
"email": "ra******@example.com",
|
||||
"phone": "98XXXXXX10",
|
||||
"gender": "MALE",
|
||||
"aadhaar_linked": true,
|
||||
"taxpayer_profile": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Function 3: PAN Advanced API
|
||||
|
||||
- **Engine Request:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8092/api/verify/ \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"document_type": "pan_advanced",
|
||||
"data": {
|
||||
"pan": "ABCDE1234F"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
- **Direct Upstream cURL:**
|
||||
```bash
|
||||
curl --location 'https://apihub.services/v4/pan-advanced' \
|
||||
--header 'X-Client-Api-ID: CAPI-YYR0YJIE0VMTDENY' \
|
||||
--header 'X-Client-Api-Secret: s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{"pan": "ABCDE1234F"}'
|
||||
```
|
||||
|
||||
- **Sample Upstream Response:**
|
||||
```json
|
||||
{
|
||||
"request_id": "8a42f1c7-63d9-4e15-b820-7c91a5d34628",
|
||||
"transaction_id": "d5b73e91-2a46-4c08-9f61-83e2b7a51439",
|
||||
"status": 200,
|
||||
"data": {
|
||||
"code": "1000",
|
||||
"message": "Valid PAN.",
|
||||
"pan_data": {
|
||||
"document_type": "PAN",
|
||||
"document_id": "ABCDE1234F",
|
||||
"name": "RAHUL KUMAR",
|
||||
"first_name": "RAHUL",
|
||||
"last_name": "KUMAR",
|
||||
"category": "P",
|
||||
"category_type": "Individual",
|
||||
"is_individual": true,
|
||||
"individual_tax_compliance_status": "Operative",
|
||||
"aadhaar_linked": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Function 4: Bank Verification (Full Details)
|
||||
|
||||
- **Engine Request:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8092/api/verify/ \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"document_type": "bank_account",
|
||||
"data": {
|
||||
"account_number": "123456789012",
|
||||
"ifsc": "HDFC0001234"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
- **Direct Upstream cURL:**
|
||||
```bash
|
||||
curl --location 'https://apihub.services/v4/bank-verify' \
|
||||
--header 'X-Client-Api-ID: CAPI-YYR0YJIE0VMTDENY' \
|
||||
--header 'X-Client-Api-Secret: s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"account_number": "123456789012",
|
||||
"ifsc": "HDFC0001234"
|
||||
}'
|
||||
```
|
||||
|
||||
- **Sample Engine Response (HTTP 200):**
|
||||
```json
|
||||
{
|
||||
"reference_id": "4b5d21a9-9941-4198-89c0-e74bf1a998bc",
|
||||
"is_success": true,
|
||||
"status": "SUCCESS",
|
||||
"document_type": "bank_account",
|
||||
"successful_vendor": "codeplus",
|
||||
"data": {
|
||||
"document_type": "BANK_ACCOUNT",
|
||||
"account_number": "123456789012",
|
||||
"ifsc": "HDFC0001234",
|
||||
"beneficiary_name": "PRIYA SHARMA",
|
||||
"micr": "641240002",
|
||||
"bank_name": "HDFC BANK",
|
||||
"branch": "MAIN BRANCH",
|
||||
"city": "COIMBATORE",
|
||||
"state": "TAMIL NADU",
|
||||
"pincode": "641001",
|
||||
"account_exists": true
|
||||
},
|
||||
"attempts_count": 1,
|
||||
"attempts": [
|
||||
{
|
||||
"attempt_number": 1,
|
||||
"vendor_name": "codeplus",
|
||||
"is_success": true,
|
||||
"status": "SUCCESS",
|
||||
"latency_ms": 420.5
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Function 5: Fetch GST By PAN
|
||||
|
||||
- **Engine Request:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8092/api/verify/ \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"document_type": "gst_by_pan",
|
||||
"data": {
|
||||
"pan": "ABCDE1234F"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
- **Direct Upstream cURL:**
|
||||
```bash
|
||||
curl --location 'https://apihub.services/v4/fetch-gst' \
|
||||
--header 'X-Client-Api-ID: CAPI-YYR0YJIE0VMTDENY' \
|
||||
--header 'X-Client-Api-Secret: s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{"pan": "ABCDE1234F"}'
|
||||
```
|
||||
|
||||
- **Sample Upstream Response:**
|
||||
```json
|
||||
{
|
||||
"request_id": "b27c9087-f061-4d38-b7aa-96498f8e667e",
|
||||
"status": 200,
|
||||
"data": {
|
||||
"code": "1002",
|
||||
"message": "Found 3 records",
|
||||
"results": [
|
||||
{
|
||||
"document_type": "GSTIN",
|
||||
"document_id": "20AXXXXXXXXXXX",
|
||||
"status": "Active",
|
||||
"state": "Jharkhand",
|
||||
"state_code": "20"
|
||||
},
|
||||
{
|
||||
"document_type": "GSTIN",
|
||||
"document_id": "27AXXXXXXXXXXX",
|
||||
"status": "Active",
|
||||
"state": "Maharashtra",
|
||||
"state_code": "27"
|
||||
},
|
||||
{
|
||||
"document_type": "GSTIN",
|
||||
"document_id": "29AXXXXXXXXXXX",
|
||||
"status": "Active",
|
||||
"state": "Karnataka",
|
||||
"state_code": "29"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Function 6: Fetch MSME By PAN
|
||||
|
||||
- **Engine Request:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8092/api/verify/ \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"document_type": "msme",
|
||||
"data": {
|
||||
"pan": "ABCDE1234F",
|
||||
"detailed_response": true
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
- **Direct Upstream cURL:**
|
||||
```bash
|
||||
curl --location 'https://apihub.services/v4/msme-pan' \
|
||||
--header 'X-Client-Api-ID: CAPI-YYR0YJIE0VMTDENY' \
|
||||
--header 'X-Client-Api-Secret: s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{"pan": "ABCDE1234F", "detailed_response": true}'
|
||||
```
|
||||
|
||||
- **Sample Engine Response (No Record Found):**
|
||||
```json
|
||||
{
|
||||
"reference_id": "c19b38fa-0123-4567-89ab-cdef01234567",
|
||||
"is_success": true,
|
||||
"status": "SUCCESS",
|
||||
"document_type": "msme",
|
||||
"successful_vendor": "codeplus",
|
||||
"data": {
|
||||
"document_type": "MSME",
|
||||
"pan": "ABCDE1234F",
|
||||
"has_msme": false,
|
||||
"code": "1011",
|
||||
"message": "No record found.",
|
||||
"udyam_data": {
|
||||
"code": "1011",
|
||||
"message": "No record found."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Function 7: GST Verification (v5)
|
||||
|
||||
- **Engine Request:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8092/api/verify/ \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"document_type": "gstin",
|
||||
"data": {
|
||||
"gst_number": "27ABCDE1234F1Z5"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
- **Direct Upstream cURL:**
|
||||
```bash
|
||||
curl --location 'https://apihub.services/v5/gst-verify' \
|
||||
--header 'X-Client-Api-ID: CAPI-YYR0YJIE0VMTDENY' \
|
||||
--header 'X-Client-Api-Secret: s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{"gst_number": "27ABCDE1234F1Z5"}'
|
||||
```
|
||||
|
||||
- **Sample Engine Response (HTTP 200):**
|
||||
```json
|
||||
{
|
||||
"reference_id": "5f6e7d8c-9b0a-1122-3344-556677889900",
|
||||
"is_success": true,
|
||||
"status": "SUCCESS",
|
||||
"document_type": "gstin",
|
||||
"successful_vendor": "codeplus",
|
||||
"data": {
|
||||
"document_type": "GSTIN",
|
||||
"gst_number": "27ABCDE1234F1Z5",
|
||||
"legal_name": "ABCDE PRIVATE LIMITED",
|
||||
"registration_status": "ACTIVE",
|
||||
"service": "GST_VERIFICATION",
|
||||
"message": "GST verification completed"
|
||||
},
|
||||
"attempts_count": 1,
|
||||
"attempts": [
|
||||
{
|
||||
"attempt_number": 1,
|
||||
"vendor_name": "codeplus",
|
||||
"is_success": true,
|
||||
"status": "SUCCESS",
|
||||
"latency_ms": 285.6
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Transaction Audit API
|
||||
|
||||
Retrieve the complete historical audit log, raw responses, and latency for any transaction:
|
||||
|
||||
- **Endpoint:** `GET /api/transactions/<uuid:reference_id>/`
|
||||
|
||||
- **cURL:**
|
||||
```bash
|
||||
curl -X GET http://localhost:8092/api/transactions/8a7c29e1-2244-48f1-9c6a-4933a1e94b21/
|
||||
```
|
||||
|
||||
- **Response:**
|
||||
```json
|
||||
{
|
||||
"reference_id": "8a7c29e1-2244-48f1-9c6a-4933a1e94b21",
|
||||
"document_type": "pan",
|
||||
"status": "SUCCESS",
|
||||
"successful_vendor": "codeplus",
|
||||
"final_data": { ... },
|
||||
"response_payload": { ... },
|
||||
"attempts_count": 1,
|
||||
"total_latency_ms": 315.4,
|
||||
"created_at": "2026-10-15T19:58:00Z",
|
||||
"attempts": [
|
||||
{
|
||||
"attempt_number": 1,
|
||||
"vendor_name": "codeplus",
|
||||
"status": "SUCCESS",
|
||||
"is_success": true,
|
||||
"error_code": null,
|
||||
"error_message": null,
|
||||
"latency_ms": 310.2,
|
||||
"created_at": "2026-10-15T19:58:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
|
@ -46,6 +46,7 @@ class VerificationTransactionAdmin(admin.ModelAdmin):
|
|||
"successful_vendor",
|
||||
"input_payload",
|
||||
"final_data",
|
||||
"response_payload",
|
||||
"attempts_count",
|
||||
"total_latency_ms",
|
||||
"created_at",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 6.1 on 2026-10-15 14:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('verifier', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='verificationtransaction',
|
||||
name='response_payload',
|
||||
field=models.JSONField(blank=True, default=dict),
|
||||
),
|
||||
]
|
||||
|
|
@ -50,6 +50,7 @@ class VerificationTransaction(models.Model):
|
|||
successful_vendor = models.CharField(max_length=50, blank=True, null=True)
|
||||
input_payload = models.JSONField(default=dict, blank=True)
|
||||
final_data = models.JSONField(default=dict, blank=True)
|
||||
response_payload = models.JSONField(default=dict, blank=True)
|
||||
attempts_count = models.PositiveIntegerField(default=0)
|
||||
total_latency_ms = models.FloatField(default=0.0)
|
||||
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ class VerificationTransactionSerializer(serializers.ModelSerializer):
|
|||
"status",
|
||||
"successful_vendor",
|
||||
"final_data",
|
||||
"response_payload",
|
||||
"attempts_count",
|
||||
"total_latency_ms",
|
||||
"created_at",
|
||||
|
|
|
|||
|
|
@ -532,3 +532,70 @@ class VerificationAPITests(TestCase):
|
|||
response = self.client.post(url, {}, format="json")
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
self.assertFalse(response.data["is_success"])
|
||||
|
||||
def test_verify_api_database_persistence(self):
|
||||
"""Ensure full transaction and attempt logs (including raw response and client response) are saved in DB."""
|
||||
from unittest.mock import patch
|
||||
from verifier.vendors import codeplus_vendor
|
||||
|
||||
mock_v5_response = {
|
||||
"success": True,
|
||||
"message": "PAN verification completed",
|
||||
"data": {
|
||||
"transactionId": "TXN_TEST_DB_123",
|
||||
"service": "PAN_VERIFICATION",
|
||||
"success": True,
|
||||
"resultCode": 101,
|
||||
"status": "SUCCESS",
|
||||
"pan": "ABCDE1234F",
|
||||
"fullName": "DATABASE PERSISTENCE USER",
|
||||
"dob": "01/01/1990",
|
||||
"aadhaarLinked": True,
|
||||
},
|
||||
"requestId": "REQ_TEST_DB_123",
|
||||
"statusCode": 200,
|
||||
}
|
||||
|
||||
class MockResponse:
|
||||
status_code = 200
|
||||
def json(self):
|
||||
return mock_v5_response
|
||||
|
||||
url = reverse("verifier:verify_document")
|
||||
with patch.object(codeplus_vendor.session, "post", return_value=MockResponse()):
|
||||
res = self.client.post(
|
||||
url,
|
||||
{
|
||||
"document_type": "pan",
|
||||
"data": {"pan": "ABCDE1234F"},
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(res.status_code, status.HTTP_200_OK)
|
||||
ref_id = res.data["reference_id"]
|
||||
|
||||
# Verify transaction in PostgreSQL DB
|
||||
tx = VerificationTransaction.objects.get(reference_id=ref_id)
|
||||
self.assertEqual(tx.document_type, "pan")
|
||||
self.assertEqual(tx.status, "SUCCESS")
|
||||
self.assertEqual(tx.successful_vendor, "codeplus")
|
||||
self.assertEqual(tx.final_data["full_name"], "DATABASE PERSISTENCE USER")
|
||||
self.assertEqual(tx.response_payload["reference_id"], str(ref_id))
|
||||
self.assertEqual(tx.attempts_count, 1)
|
||||
|
||||
# Verify attempt log in DB
|
||||
attempts = tx.attempts.all()
|
||||
self.assertEqual(attempts.count(), 1)
|
||||
attempt_1 = attempts.first()
|
||||
self.assertEqual(attempt_1.vendor_name, "codeplus")
|
||||
self.assertTrue(attempt_1.is_success)
|
||||
self.assertEqual(attempt_1.raw_response["statusCode"], 200)
|
||||
|
||||
# Verify GET /api/transactions/<ref_id>/
|
||||
detail_url = reverse("verifier:transaction_detail", kwargs={"reference_id": ref_id})
|
||||
detail_res = self.client.get(detail_url)
|
||||
self.assertEqual(detail_res.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(detail_res.data["reference_id"], str(ref_id))
|
||||
self.assertEqual(len(detail_res.data["attempts"]), 1)
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,10 @@ class DocumentVerifyView(APIView):
|
|||
"total_latency_ms": round(engine_result.total_latency_ms, 2),
|
||||
}
|
||||
|
||||
# Store complete client response payload in database record
|
||||
transaction.response_payload = response_payload
|
||||
transaction.save(update_fields=["response_payload"])
|
||||
|
||||
http_status = status.HTTP_200_OK if engine_result.is_success else status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||
return Response(response_payload, status=http_status)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue