Move AQMM controls to assurance engagement workflow
This commit is contained in:
@@ -386,6 +386,21 @@ class ClientServiceSubscription(CommonBase):
|
||||
end_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
status: Mapped[str] = mapped_column(String(30), nullable=False, default="active", index=True)
|
||||
remarks: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
|
||||
# AQMM / engagement-level quality workflow. This is intentionally attached
|
||||
# to the engagement/subscription, not to the client master, because one
|
||||
# client can have both assurance and non-assurance services in the same FY.
|
||||
quality_workflow_required: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, index=True)
|
||||
quality_workflow_status: Mapped[str] = mapped_column(String(40), nullable=False, default="not_required", index=True)
|
||||
quality_acceptance_status: Mapped[str] = mapped_column(String(40), nullable=False, default="not_required", index=True)
|
||||
quality_independence_status: Mapped[str] = mapped_column(String(40), nullable=False, default="not_required", index=True)
|
||||
quality_conflict_status: Mapped[str] = mapped_column(String(40), nullable=False, default="not_required", index=True)
|
||||
quality_kyc_status: Mapped[str] = mapped_column(String(40), nullable=False, default="not_required", index=True)
|
||||
quality_engagement_letter_status: Mapped[str] = mapped_column(String(40), nullable=False, default="not_required", index=True)
|
||||
quality_approved_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id"), nullable=True, index=True)
|
||||
quality_approved_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
quality_block_reason: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, index=True)
|
||||
is_locked: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, index=True)
|
||||
locked_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
@@ -405,6 +420,123 @@ class ClientServiceSubscription(CommonBase):
|
||||
assigned_staff = relationship("User", foreign_keys=[assigned_staff_user_id])
|
||||
review_partner = relationship("User", foreign_keys=[review_partner_user_id])
|
||||
locked_by = relationship("User", foreign_keys=[locked_by_user_id])
|
||||
quality_approved_by = relationship("User", foreign_keys=[quality_approved_by_user_id])
|
||||
|
||||
|
||||
class EngagementQualityDeclaration(CommonBase):
|
||||
"""Digital AQMM declaration attached to an assurance engagement.
|
||||
|
||||
Used for independence and conflict confirmations from the assigned partner,
|
||||
review partner, manager, staff and any other engagement team member.
|
||||
"""
|
||||
|
||||
__tablename__ = "engagement_quality_declarations"
|
||||
__table_args__ = (
|
||||
UniqueConstraint(
|
||||
"subscription_id",
|
||||
"declaration_type",
|
||||
"requested_user_id",
|
||||
name="uq_engagement_quality_declaration_user_type",
|
||||
),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=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)
|
||||
client_id: Mapped[int] = mapped_column(ForeignKey("clients.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
subscription_id: Mapped[int] = mapped_column(ForeignKey("client_service_subscriptions.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
|
||||
declaration_type: Mapped[str] = mapped_column(String(40), nullable=False, index=True) # independence / conflict
|
||||
requested_user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
requested_role: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True)
|
||||
declaration_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
response_notes: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
responded_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
ip_address: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
user_agent: Mapped[str | None] = mapped_column(String(500), 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)
|
||||
|
||||
subscription = relationship("ClientServiceSubscription")
|
||||
client = relationship("Client")
|
||||
requested_user = relationship("User", foreign_keys=[requested_user_id])
|
||||
created_by = relationship("User", foreign_keys=[created_by_user_id])
|
||||
|
||||
|
||||
class EngagementKycVerification(CommonBase):
|
||||
"""KYC verification for an assurance engagement using existing permanent documents."""
|
||||
|
||||
__tablename__ = "engagement_kyc_verifications"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=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)
|
||||
client_id: Mapped[int] = mapped_column(ForeignKey("clients.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
subscription_id: Mapped[int] = mapped_column(ForeignKey("client_service_subscriptions.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending_verification", index=True)
|
||||
source: Mapped[str] = mapped_column(String(80), nullable=False, default="permanent_documents")
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
subscription = relationship("ClientServiceSubscription")
|
||||
client = relationship("Client")
|
||||
verified_by = relationship("User", foreign_keys=[verified_by_user_id])
|
||||
created_by = relationship("User", foreign_keys=[created_by_user_id])
|
||||
|
||||
|
||||
class EngagementLetter(CommonBase):
|
||||
"""Engagement-specific letter acceptance evidence.
|
||||
|
||||
Supports both client OTP acceptance and manual signed PDF upload/verification.
|
||||
File upload storage can be extended without changing the AQMM gate fields.
|
||||
"""
|
||||
|
||||
__tablename__ = "engagement_letters"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=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)
|
||||
client_id: Mapped[int] = mapped_column(ForeignKey("clients.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
subscription_id: Mapped[int] = mapped_column(ForeignKey("client_service_subscriptions.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
|
||||
title: Mapped[str] = mapped_column(String(255), nullable=False, default="Engagement Letter")
|
||||
version_no: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||||
status: Mapped[str] = mapped_column(String(50), nullable=False, default="draft_pending", index=True)
|
||||
acceptance_mode: Mapped[str | None] = mapped_column(String(40), nullable=True) # digital_otp / manual_signed_upload
|
||||
body_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
pdf_sha256: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
||||
manual_upload_filename: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||
manual_upload_path: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
||||
client_acceptance_declaration: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
|
||||
partner_approved_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
partner_approved_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
client_accepted_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
|
||||
client_accepted_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=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)
|
||||
ip_address: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
user_agent: Mapped[str | None] = mapped_column(String(500), 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)
|
||||
|
||||
subscription = relationship("ClientServiceSubscription")
|
||||
client = relationship("Client")
|
||||
partner_approved_by = relationship("User", foreign_keys=[partner_approved_by_user_id])
|
||||
client_accepted_by = relationship("User", foreign_keys=[client_accepted_by_user_id])
|
||||
manual_verified_by = relationship("User", foreign_keys=[manual_verified_by_user_id])
|
||||
created_by = relationship("User", foreign_keys=[created_by_user_id])
|
||||
|
||||
|
||||
class ClientServiceTaskInstance(CommonBase):
|
||||
|
||||
Reference in New Issue
Block a user