Add digital client acceptance workflow
This commit is contained in:
@@ -97,3 +97,100 @@ class ClientAuditLog(CommonBase):
|
||||
summary: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
payload_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
created_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False)
|
||||
|
||||
class ClientAcceptanceDeclaration(CommonBase):
|
||||
"""Digital independence/conflict declaration requested from partner, manager or staff.
|
||||
|
||||
Each row is an auditable declaration. The client level checkbox is derived
|
||||
only when all applicable declaration rows are answered without issue.
|
||||
"""
|
||||
|
||||
__tablename__ = "client_acceptance_declarations"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("client_id", "declaration_type", "assigned_user_id", name="uq_client_acceptance_declaration_user"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
client_id: Mapped[int] = mapped_column(ForeignKey("clients.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
tenant_id: Mapped[int] = mapped_column(ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
branch_id: Mapped[int | None] = mapped_column(ForeignKey("branches.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
declaration_type: Mapped[str] = mapped_column(String(30), nullable=False, index=True)
|
||||
assigned_user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
assigned_role_snapshot: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
||||
declaration_text: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
status: Mapped[str] = mapped_column(String(30), nullable=False, default="pending", index=True)
|
||||
response_notes: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
issue_details: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
responded_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
response_ip: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
response_user_agent: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
||||
requested_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
|
||||
requested_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False)
|
||||
updated_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), nullable=False)
|
||||
|
||||
|
||||
class ClientKycVerification(CommonBase):
|
||||
"""KYC verification layer on top of existing permanent client documents.
|
||||
|
||||
This does not duplicate client uploads. It stores whether the existing
|
||||
permanent documents are enough and who verified them.
|
||||
"""
|
||||
|
||||
__tablename__ = "client_kyc_verifications"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("client_id", name="uq_client_kyc_verification_client"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
client_id: Mapped[int] = mapped_column(ForeignKey("clients.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
tenant_id: Mapped[int] = mapped_column(ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
branch_id: Mapped[int | None] = mapped_column(ForeignKey("branches.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
status: Mapped[str] = mapped_column(String(30), nullable=False, default="pending_documents", index=True)
|
||||
required_document_summary: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
available_document_summary: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
verification_notes: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
verified_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
verified_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
rejected_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
rejected_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
created_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False)
|
||||
updated_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), nullable=False)
|
||||
|
||||
|
||||
class ClientEngagementLetter(CommonBase):
|
||||
"""Client acceptance engagement letter with digital OTP or manual signed upload."""
|
||||
|
||||
__tablename__ = "client_engagement_letters"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("client_id", "letter_code", "version_no", name="uq_client_engagement_letter_code_version"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
client_id: Mapped[int] = mapped_column(ForeignKey("clients.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
tenant_id: Mapped[int] = mapped_column(ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
branch_id: Mapped[int | None] = mapped_column(ForeignKey("branches.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
letter_code: Mapped[str] = mapped_column(String(80), nullable=False, default="STANDARD", index=True)
|
||||
title: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
body_text: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
version_no: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="draft", index=True)
|
||||
sent_to_client_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
approved_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
approved_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
accepted_mode: Mapped[str | None] = mapped_column(String(40), nullable=True, index=True)
|
||||
accepted_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
accepted_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
accepted_ip: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
accepted_user_agent: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
||||
acceptance_declaration_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
otp_verified: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
pdf_hash_sha256: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
manual_signed_file_path: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
||||
manual_signed_file_hash_sha256: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
manual_verified_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
manual_verified_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
rejection_reason: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
created_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
|
||||
created_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False)
|
||||
updated_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), nullable=False)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user