Files
kyc/kyc_app/schemas/public_schema.py
Ruslan Bakiev 10f5c609de
All checks were successful
Build Docker Image / build (push) Successful in 2m14s
Rename GraphQL endpoints: companyTeaser → kycProfileTeaser, companyFull → kycProfileFull
2026-01-21 09:40:34 +07:00

209 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Public GraphQL Schema for KYC profile data.
This endpoint provides:
- kycProfileTeaser: public data (no auth required)
- kycProfileFull: full data (requires authentication)
Data is read from MongoDB company_documents collection.
Queries are by KYC Profile UUID.
"""
import graphene
from django.conf import settings
from pymongo import MongoClient
from ..models import KYCProfile, KYCDetailsRussia
def get_mongo_client():
"""Get MongoDB client."""
if not settings.MONGODB_URI:
return None
return MongoClient(settings.MONGODB_URI)
def get_company_documents(inn: str) -> list:
"""Get all documents for a company by INN."""
client = get_mongo_client()
if not client:
return []
try:
db = client[settings.MONGODB_DB]
collection = db["company_documents"]
return list(collection.find({"inn": inn}))
finally:
client.close()
def get_inn_by_profile_uuid(profile_uuid: str) -> str | None:
"""Get INN from KYCProfile by its UUID."""
try:
profile = KYCProfile.objects.get(uuid=profile_uuid)
# Get country details (KYCDetailsRussia) via GenericForeignKey
if profile.country_details and isinstance(profile.country_details, KYCDetailsRussia):
return profile.country_details.inn
return None
except KYCProfile.DoesNotExist:
return None
def aggregate_company_data(documents: list) -> dict:
"""Aggregate data from multiple source documents into summary."""
if not documents:
return {}
summary = {
"inn": None,
"ogrn": None,
"name": None,
"company_type": None,
"registration_year": None,
"is_active": True,
"address": None,
"director": None,
"capital": None,
"activities": [],
"sources": [],
"last_updated": None,
}
for doc in documents:
source = doc.get("source", "unknown")
summary["sources"].append(source)
data = doc.get("data", {})
# Extract common fields
if not summary["inn"]:
summary["inn"] = doc.get("inn")
if not summary["ogrn"] and data.get("ogrn"):
summary["ogrn"] = data["ogrn"]
if not summary["name"] and data.get("name"):
summary["name"] = data["name"]
# Parse company type from name
if not summary["company_type"] and summary["name"]:
name = summary["name"].upper()
if "ООО" in name or "ОБЩЕСТВО С ОГРАНИЧЕННОЙ" in name:
summary["company_type"] = "ООО"
elif "АО" in name or "АКЦИОНЕРНОЕ ОБЩЕСТВО" in name:
summary["company_type"] = "АО"
elif "ИП" in name or "ИНДИВИДУАЛЬНЫЙ ПРЕДПРИНИМАТЕЛЬ" in name:
summary["company_type"] = "ИП"
elif "ПАО" in name:
summary["company_type"] = "ПАО"
# Track last update
collected_at = doc.get("collected_at")
if collected_at:
if not summary["last_updated"] or collected_at > summary["last_updated"]:
summary["last_updated"] = collected_at
return summary
class CompanyTeaserType(graphene.ObjectType):
"""Public company data (teaser)."""
company_type = graphene.String(description="Company type: ООО, АО, ИП, etc.")
registration_year = graphene.Int(description="Year of registration")
is_active = graphene.Boolean(description="Is company active")
sources_count = graphene.Int(description="Number of data sources")
class CompanyFullType(graphene.ObjectType):
"""Full company data (requires auth)."""
inn = graphene.String()
ogrn = graphene.String()
name = graphene.String()
company_type = graphene.String()
registration_year = graphene.Int()
is_active = graphene.Boolean()
address = graphene.String()
director = graphene.String()
capital = graphene.String()
activities = graphene.List(graphene.String)
sources = graphene.List(graphene.String)
last_updated = graphene.DateTime()
class PublicQuery(graphene.ObjectType):
"""Public queries - no authentication required."""
# Query by KYC Profile UUID (preferred - used by frontend)
kyc_profile_teaser = graphene.Field(
CompanyTeaserType,
profile_uuid=graphene.String(required=True),
description="Get public KYC profile teaser data by UUID",
)
kyc_profile_full = graphene.Field(
CompanyFullType,
profile_uuid=graphene.String(required=True),
description="Get full KYC profile data by UUID (requires auth)",
)
health = graphene.String()
def resolve_health(self, info):
return "ok"
def resolve_kyc_profile_teaser(self, info, profile_uuid: str):
"""Return public teaser data by KYC Profile UUID."""
inn = get_inn_by_profile_uuid(profile_uuid)
if not inn:
return None
documents = get_company_documents(inn)
if not documents:
return None
summary = aggregate_company_data(documents)
return CompanyTeaserType(
company_type=summary.get("company_type"),
registration_year=summary.get("registration_year"),
is_active=summary.get("is_active", True),
sources_count=len(summary.get("sources", [])),
)
def resolve_kyc_profile_full(self, info, profile_uuid: str):
"""Return full KYC profile data by UUID (requires auth)."""
# Check authentication
user_id = getattr(info.context, 'user_id', None)
if not user_id:
return None # Not authenticated
inn = get_inn_by_profile_uuid(profile_uuid)
if not inn:
return None
documents = get_company_documents(inn)
if not documents:
return None
summary = aggregate_company_data(documents)
return CompanyFullType(
inn=summary.get("inn"),
ogrn=summary.get("ogrn"),
name=summary.get("name"),
company_type=summary.get("company_type"),
registration_year=summary.get("registration_year"),
is_active=summary.get("is_active", True),
address=summary.get("address"),
director=summary.get("director"),
capital=summary.get("capital"),
activities=summary.get("activities", []),
sources=summary.get("sources", []),
last_updated=summary.get("last_updated"),
)
public_schema = graphene.Schema(query=PublicQuery)