Auto lock completed non assurance engagements
This commit is contained in:
@@ -11,6 +11,7 @@ from app.core.templating import templates
|
||||
from app.modules.services.models import ClientServiceSubscription, ClientServiceTaskInstance
|
||||
from app.modules.services.due_dates import apply_due_date_rule_to_subscription
|
||||
from app.modules.services.execution import (
|
||||
CLOSED_TASK_STATUSES,
|
||||
aqmm_task_summary_for_subscription,
|
||||
generate_tasks_for_subscription_if_ready,
|
||||
update_engagement_closure_from_sources,
|
||||
@@ -151,6 +152,60 @@ def _lock_subscription_row(row: ClientServiceSubscription, user) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def _auto_lock_completed_non_assurance_subscription(
|
||||
db,
|
||||
row: ClientServiceSubscription,
|
||||
user,
|
||||
) -> bool:
|
||||
"""Lock a completed non-assurance engagement without touching its plan.
|
||||
|
||||
Completion here means every active task is closed, every required normal
|
||||
review is reviewed, every required AQMM task-review flag (if any) is
|
||||
reviewed, and no task has open rework. Assurance engagements deliberately
|
||||
remain on the existing AQMM/final-release closure workflow.
|
||||
"""
|
||||
if getattr(row, "is_locked", False):
|
||||
return False
|
||||
if (getattr(row, "engagement_type", None) or "non_assurance").strip().lower() == "assurance":
|
||||
return False
|
||||
|
||||
tasks = list(
|
||||
db.execute(
|
||||
select(ClientServiceTaskInstance).where(
|
||||
ClientServiceTaskInstance.subscription_id == row.id,
|
||||
ClientServiceTaskInstance.is_active.is_(True),
|
||||
)
|
||||
).scalars().all()
|
||||
)
|
||||
if not tasks:
|
||||
return False
|
||||
|
||||
for task in tasks:
|
||||
status = (getattr(task, "status", None) or "pending").strip().lower()
|
||||
if status not in CLOSED_TASK_STATUSES:
|
||||
return False
|
||||
|
||||
if getattr(task, "normal_review_required", False):
|
||||
if (getattr(task, "normal_review_status", None) or "not_required").strip().lower() != "reviewed":
|
||||
return False
|
||||
|
||||
if getattr(task, "aqmm_manager_review_required", False):
|
||||
if (getattr(task, "manager_review_status", None) or "not_required").strip().lower() != "reviewed":
|
||||
return False
|
||||
if getattr(task, "aqmm_partner_review_required", False):
|
||||
if (getattr(task, "partner_review_status", None) or "not_required").strip().lower() != "reviewed":
|
||||
return False
|
||||
if getattr(task, "aqmm_review_partner_required", False):
|
||||
if (getattr(task, "review_partner_review_status", None) or "not_required").strip().lower() != "reviewed":
|
||||
return False
|
||||
|
||||
if (getattr(task, "rework_status", None) or "none").strip().lower() == "open":
|
||||
return False
|
||||
|
||||
return _lock_subscription_row(row, user)
|
||||
|
||||
|
||||
@router.get("")
|
||||
def subscription_list(
|
||||
request: Request,
|
||||
@@ -184,6 +239,13 @@ def subscription_list(
|
||||
q=q,
|
||||
include_inactive=include_inactive,
|
||||
)
|
||||
auto_locked = 0
|
||||
for row in rows:
|
||||
if _auto_lock_completed_non_assurance_subscription(db, row, user):
|
||||
auto_locked += 1
|
||||
if auto_locked:
|
||||
db.commit()
|
||||
|
||||
return _render(
|
||||
request,
|
||||
"modules/services/templates/services/engagements/list.html",
|
||||
@@ -731,6 +793,10 @@ def subscription_detail(request: Request, subscription_id: int):
|
||||
if row.financial_year != active_fy:
|
||||
return RedirectResponse(url=f"/services/engagements?financial_year={active_fy}", status_code=303)
|
||||
|
||||
if _auto_lock_completed_non_assurance_subscription(db, row, user):
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
|
||||
ensure_engagement_quality_workflow(db, subscription=row, actor_user_id=user.id, create_declarations=False)
|
||||
db.flush()
|
||||
declarations = list_engagement_quality_declarations(db, subscription_id=row.id)
|
||||
@@ -1055,6 +1121,9 @@ def subscription_edit_page(request: Request, subscription_id: int):
|
||||
active_fy = _active_financial_year(request)
|
||||
if row.financial_year != active_fy:
|
||||
return RedirectResponse(url=f"/services/engagements?financial_year={active_fy}", status_code=303)
|
||||
if _auto_lock_completed_non_assurance_subscription(db, row, user):
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
if getattr(row, "is_locked", False) or is_row_financial_year_locked(db, row):
|
||||
return RedirectResponse(url=f"/services/engagements/{row.id}?year_locked=1", status_code=303)
|
||||
|
||||
@@ -1125,6 +1194,9 @@ def subscription_edit_submit(
|
||||
active_fy = _active_financial_year(request)
|
||||
if row.financial_year != active_fy:
|
||||
return RedirectResponse(url=f"/services/engagements?financial_year={active_fy}", status_code=303)
|
||||
if _auto_lock_completed_non_assurance_subscription(db, row, user):
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
if getattr(row, "is_locked", False) or is_row_financial_year_locked(db, row):
|
||||
return RedirectResponse(url=f"/services/engagements/{row.id}?year_locked=1", status_code=303)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user