documentverification/verifier/models.py
2026-10-15 20:03:19 +05:30

95 lines
3.9 KiB
Python

import uuid
from django.db import models
class VendorConfig(models.Model):
"""
Dynamic configuration for verification vendors stored in database.
Allows toggling active state, priority adjustments, and credential updates via Django admin.
"""
name = models.CharField(max_length=50, unique=True, help_text="Unique vendor identifier, e.g. codeplus")
display_name = models.CharField(max_length=100, help_text="Human-readable name")
is_active = models.BooleanField(default=True)
priority = models.PositiveIntegerField(
default=10,
help_text="Waterfall execution order (lower numbers execute first)",
)
supported_documents = models.JSONField(
default=list,
help_text="List of supported doc types: ['pan', 'aadhaar', 'driving_license', 'voter_id', ...]",
)
base_url = models.CharField(max_length=255, blank=True, null=True)
api_key = models.CharField(max_length=255, blank=True, null=True)
extra_credentials = models.JSONField(default=dict, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["priority", "name"]
verbose_name = "Vendor Configuration"
verbose_name_plural = "Vendor Configurations"
def __str__(self):
return f"{self.display_name} ({self.name}) - Priority: {self.priority} - {'Active' if self.is_active else 'Disabled'}"
class VerificationTransaction(models.Model):
"""
Master record of every document verification request processed by the engine.
"""
STATUS_CHOICES = (
("PENDING", "Pending"),
("SUCCESS", "Success"),
("FAILED", "Failed"),
("ERROR", "Error"),
)
reference_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True)
document_type = models.CharField(max_length=50, db_index=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="PENDING", db_index=True)
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)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["-created_at"]
verbose_name = "Verification Transaction"
verbose_name_plural = "Verification Transactions"
def __str__(self):
return f"[{self.status}] {self.document_type} - {self.reference_id} ({self.successful_vendor or 'none'})"
class VendorAttemptLog(models.Model):
"""
Audit log of each individual vendor attempt in the waterfall cascade.
Allows inspection of which vendor failed, why, latency, and full payload details.
"""
transaction = models.ForeignKey(
VerificationTransaction,
related_name="attempts",
on_delete=models.CASCADE,
)
attempt_number = models.PositiveIntegerField()
vendor_name = models.CharField(max_length=50, db_index=True)
status = models.CharField(max_length=20)
is_success = models.BooleanField(default=False)
data = models.JSONField(default=dict, blank=True)
raw_response = models.JSONField(null=True, blank=True)
error_code = models.CharField(max_length=100, blank=True, null=True)
error_message = models.TextField(blank=True, null=True)
latency_ms = models.FloatField(default=0.0)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["attempt_number"]
verbose_name = "Vendor Attempt Log"
verbose_name_plural = "Vendor Attempt Logs"
def __str__(self):
return f"Tx: {self.transaction.reference_id} | #{self.attempt_number} {self.vendor_name} -> {self.status}"