Add engagement closure checklist workflow
This commit is contained in:
@@ -10,7 +10,13 @@ from app.core.security.session_auth import get_current_user
|
||||
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 aqmm_task_summary_for_subscription
|
||||
from app.modules.services.execution import (
|
||||
aqmm_task_summary_for_subscription,
|
||||
update_engagement_closure_from_sources,
|
||||
save_engagement_closure_confirmations,
|
||||
approve_engagement_closure,
|
||||
reopen_engagement_closure,
|
||||
)
|
||||
from app.modules.clients.models import Client
|
||||
from app.modules.services.client_services import (
|
||||
SUBSCRIPTION_STATUSES,
|
||||
@@ -400,6 +406,7 @@ def subscription_detail(request: Request, subscription_id: int):
|
||||
kyc_verification = get_latest_engagement_kyc_verification(db, subscription_id=row.id)
|
||||
engagement_letter = get_current_engagement_letter(db, subscription_id=row.id)
|
||||
aqmm_task_summary = aqmm_task_summary_for_subscription(db, subscription_id=row.id)
|
||||
closure_checklist, closure_summary = update_engagement_closure_from_sources(db, subscription=row, actor_user_id=user.id)
|
||||
|
||||
tasks = db.execute(
|
||||
select(ClientServiceTaskInstance)
|
||||
@@ -420,6 +427,8 @@ def subscription_detail(request: Request, subscription_id: int):
|
||||
kyc_verification=kyc_verification,
|
||||
engagement_letter=engagement_letter,
|
||||
aqmm_task_summary=aqmm_task_summary,
|
||||
closure_checklist=closure_checklist,
|
||||
closure_summary=closure_summary,
|
||||
can_manage=_can_manage_client_services(db, user),
|
||||
)
|
||||
finally:
|
||||
@@ -578,6 +587,122 @@ def subscription_aqmm_approve(request: Request, subscription_id: int, csrf_token
|
||||
db.close()
|
||||
|
||||
|
||||
@router.post("/{subscription_id}/closure/sync")
|
||||
def subscription_closure_sync(request: Request, subscription_id: int, csrf_token: str = Form(...)):
|
||||
validate_csrf(request, csrf_token)
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user = get_current_user(request, db=db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=303)
|
||||
try:
|
||||
require_permission(db, user, "clients.view")
|
||||
except Exception:
|
||||
return _redirect_denied()
|
||||
tenant_id = _active_tenant_id(request, user)
|
||||
row = get_subscription(db, subscription_id=subscription_id, tenant_id=tenant_id)
|
||||
if row:
|
||||
update_engagement_closure_from_sources(db, subscription=row, actor_user_id=user.id)
|
||||
db.commit()
|
||||
return RedirectResponse(url=f"/services/engagements/{subscription_id}", status_code=303)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.post("/{subscription_id}/closure/update")
|
||||
def subscription_closure_update(
|
||||
request: Request,
|
||||
subscription_id: int,
|
||||
deliverables_sent_to_client: str | None = Form(None),
|
||||
billing_reviewed: str | None = Form(None),
|
||||
open_points_closed: str | None = Form(None),
|
||||
client_communication_completed: str | None = Form(None),
|
||||
closure_note: str = Form(""),
|
||||
csrf_token: str = Form(...),
|
||||
):
|
||||
validate_csrf(request, csrf_token)
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user = get_current_user(request, db=db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=303)
|
||||
try:
|
||||
require_permission(db, user, "clients.edit")
|
||||
except Exception:
|
||||
return _redirect_denied()
|
||||
tenant_id = _active_tenant_id(request, user)
|
||||
row = get_subscription(db, subscription_id=subscription_id, tenant_id=tenant_id)
|
||||
if row:
|
||||
try:
|
||||
save_engagement_closure_confirmations(
|
||||
db,
|
||||
subscription=row,
|
||||
deliverables_sent_to_client=deliverables_sent_to_client is not None,
|
||||
billing_reviewed=billing_reviewed is not None,
|
||||
open_points_closed=open_points_closed is not None,
|
||||
client_communication_completed=client_communication_completed is not None,
|
||||
closure_note=closure_note,
|
||||
actor_user_id=user.id,
|
||||
)
|
||||
db.commit()
|
||||
except ValueError:
|
||||
db.rollback()
|
||||
return RedirectResponse(url=f"/services/engagements/{subscription_id}", status_code=303)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.post("/{subscription_id}/closure/approve")
|
||||
def subscription_closure_approve(request: Request, subscription_id: int, csrf_token: str = Form(...)):
|
||||
validate_csrf(request, csrf_token)
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user = get_current_user(request, db=db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=303)
|
||||
if not _can_lock_engagements(db, user):
|
||||
return _redirect_denied()
|
||||
tenant_id = _active_tenant_id(request, user)
|
||||
row = get_subscription(db, subscription_id=subscription_id, tenant_id=tenant_id)
|
||||
if row:
|
||||
try:
|
||||
approve_engagement_closure(db, subscription=row, actor_user_id=user.id)
|
||||
db.commit()
|
||||
except ValueError:
|
||||
db.rollback()
|
||||
return RedirectResponse(url=f"/services/engagements/{subscription_id}", status_code=303)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.post("/{subscription_id}/closure/reopen")
|
||||
def subscription_closure_reopen(
|
||||
request: Request,
|
||||
subscription_id: int,
|
||||
reason: str = Form(""),
|
||||
csrf_token: str = Form(...),
|
||||
):
|
||||
validate_csrf(request, csrf_token)
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user = get_current_user(request, db=db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=303)
|
||||
if not _can_lock_engagements(db, user):
|
||||
return _redirect_denied()
|
||||
tenant_id = _active_tenant_id(request, user)
|
||||
row = get_subscription(db, subscription_id=subscription_id, tenant_id=tenant_id)
|
||||
if row:
|
||||
try:
|
||||
reopen_engagement_closure(db, subscription=row, reason=reason, actor_user_id=user.id)
|
||||
db.commit()
|
||||
except ValueError:
|
||||
db.rollback()
|
||||
return RedirectResponse(url=f"/services/engagements/{subscription_id}", status_code=303)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.get("/{subscription_id}/edit")
|
||||
def subscription_edit_page(request: Request, subscription_id: int):
|
||||
db = CommonSessionLocal()
|
||||
|
||||
Reference in New Issue
Block a user