"""Identity check (KYC), level 1: the recommended fields from docs/product/account-types.md section 6. Stored at identity/{uid}. A submission is "submitted" until a person on our side reviews it; nothing here verifies anything or gates any action yet. ID numbers and uploads are not collected at this level. """ from __future__ import annotations import re from datetime import datetime, timezone from backend import accounts from backend import firestore_client as db # (key, label, required) in the order they are shown. FIELDS = { accounts.ORGANIZATION: [ ("legal_name", "Legal name", True), ("trading_name", "Trading name", False), ("registration_number", "Registration number (RC)", True), ("country", "Country of registration", True), ("address", "Registered address", True), ("business_type", "Business type", True), ("contact_name", "Contact person", True), ("contact_role", "Their role", True), ("contact_phone", "Their phone", True), ("website", "Website or social page", True), ], accounts.INDIVIDUAL: [ ("legal_name", "Legal name", True), ("date_of_birth", "Date of birth", True), ("phone", "Phone", True), ("address", "Home or work address", True), ("occupation", "What you send mail for", False), ("website", "Website or social page", False), ], } # Filled in by the map picker alongside country and address; kept if present, never required. PHONE_KEYS = ("phone", "contact_phone") PLACE_EXTRAS = ("state", "lga", "postal_code") def _path(uid: str) -> str: return f"identity/{uid}" def describe(uid: str) -> dict: account_type = accounts.account_type_of(uid) if not account_type: raise accounts.AccountError("Choose an account type first") doc = db.get_doc(_path(uid)) or {} return { "status": doc.get("status", "not_started"), "values": doc.get("values", {}), "submitted_at": doc.get("submitted_at"), "fields": [{"key": k, "label": l, "required": r} for k, l, r in FIELDS[account_type]], } def status_of(uid: str) -> str: return (db.get_doc(_path(uid)) or {}).get("status", "not_started") def submit(uid: str, values: dict) -> dict: account_type = accounts.account_type_of(uid) if not account_type: raise accounts.AccountError("Choose an account type first") clean: dict[str, str] = {} for key, label, required in FIELDS[account_type]: value = str(values.get(key) or "").strip()[:300] if required and not value: raise accounts.AccountError(f"{label} is needed") if key in PHONE_KEYS and value and not re.fullmatch(r"\+\d{1,4} \d{6,14}", value): raise accounts.AccountError(f"{label} should be a calling code and digits only") if value: clean[key] = value if clean.get("country") == "Nigeria": rc = clean.get("registration_number") if rc and not re.fullmatch(r"(?i)(RC|BN|IT|LP|LLP)\s?-?\s?\d{4,8}", rc): raise accounts.AccountError("Registration number should look like RC1234567") code = str(values.get("postal_code") or "").strip() if code and not re.fullmatch(r"\d{6}", code): raise accounts.AccountError("Postal code should be 6 digits") for key in PLACE_EXTRAS: value = str(values.get(key) or "").strip()[:300] if value: clean[key] = value db.set_doc(_path(uid), {"status": "submitted", "values": clean, "submitted_at": datetime.now(timezone.utc).isoformat()}) return describe(uid)