Staff Response & Conclusion
- Response
- {{ active.checklist_response or active.checklist_text_response or active.checklist_number_response or active.checklist_date_response or '-' }}
- Checklist remarks
- {{ active.checklist_remarks or '-' }}
- Work remarks
- {{ active.work_remarks or '-' }}
@@ -80,7 +80,7 @@
-
+
{% else %}
diff --git a/app/modules/partner_dashboard/ui.py b/app/modules/partner_dashboard/ui.py
index 2653043..caf25ad 100644
--- a/app/modules/partner_dashboard/ui.py
+++ b/app/modules/partner_dashboard/ui.py
@@ -15,7 +15,7 @@ from app.modules.partner_dashboard.service import (
get_next_partner_review_task_id,
get_partner_review_workspace,
)
-from app.modules.services.execution import apply_task_review
+from app.modules.services.execution import apply_normal_task_review, apply_task_review
from app.modules.alerts.workflow_escalations import update_workflow_escalation
router = APIRouter(prefix="/partner", tags=["partner-dashboard-v2-ui"])
@@ -137,7 +137,7 @@ def partner_review_task_submit(
return RedirectResponse(url=f"/partner/reviews/engagements/{subscription_id}?review_error=task", status_code=303)
if active.get("is_locked") or workspace.get("is_locked"):
return RedirectResponse(url=f"/partner/reviews/engagements/{subscription_id}?task_id={task_id}&review_error=locked", status_code=303)
- if not active.get("can_review") or active.get("review_level") not in {"partner", "review_partner"}:
+ if not active.get("can_review") or active.get("review_level") not in {"normal_partner", "partner", "review_partner"}:
return RedirectResponse(url=f"/partner/reviews/engagements/{subscription_id}?task_id={task_id}&review_error=not_ready", status_code=303)
from sqlalchemy import select
@@ -149,14 +149,23 @@ def partner_review_task_submit(
if not task:
return RedirectResponse(url="/partner/dashboard?tab=review", status_code=303)
try:
- apply_task_review(
- db,
- task=task,
- review_level=active["review_level"],
- decision=decision,
- note=review_note,
- user_id=current_user.id,
- )
+ if active.get("review_level") == "normal_partner":
+ apply_normal_task_review(
+ db,
+ task=task,
+ decision=decision,
+ note=review_note,
+ user_id=current_user.id,
+ )
+ else:
+ apply_task_review(
+ db,
+ task=task,
+ review_level=active["review_level"],
+ decision=decision,
+ note=review_note,
+ user_id=current_user.id,
+ )
db.commit()
except ValueError:
db.rollback()
diff --git a/app/modules/partners/templates/partners/review_board.html b/app/modules/partners/templates/partners/review_board.html
index a73d832..6e60669 100644
--- a/app/modules/partners/templates/partners/review_board.html
+++ b/app/modules/partners/templates/partners/review_board.html
@@ -111,7 +111,7 @@
|
- {{ task.client_display }}
+ {{ task.client_display }}
{{ task.engagement_label }}
Engagement #{{ task.subscription_id }}
|
@@ -157,7 +157,7 @@
{% if task.internal_target_date %}Target {{ task.internal_target_date }}{% else %}No task target{% endif %}
- Open Review
+ Open Review
|
{% endif %}
diff --git a/app/modules/partners/ui.py b/app/modules/partners/ui.py
index 63fc973..1404e34 100644
--- a/app/modules/partners/ui.py
+++ b/app/modules/partners/ui.py
@@ -152,23 +152,40 @@ def _decorate_task(task: ClientServiceTaskInstance, today: date) -> ClientServic
return task
-def _task_bucket(task: ClientServiceTaskInstance) -> str:
+def _task_bucket(task: ClientServiceTaskInstance, current_user) -> str:
status = (task.status or "pending").strip().lower()
- if status == "blocked":
+ subscription = getattr(task, "subscription", None)
+ uid = int(getattr(current_user, "id", 0) or 0)
+ is_engagement_partner = uid and uid == int(getattr(subscription, "assigned_partner_user_id", 0) or 0)
+ is_review_partner = uid and uid == int(getattr(subscription, "review_partner_user_id", 0) or 0)
+
+ normal_role = (getattr(task, "normal_review_role", None) or "").strip().lower()
+ normal_status = (getattr(task, "normal_review_status", None) or "not_required").strip().lower()
+ normal_partner_review = (
+ is_engagement_partner
+ and getattr(task, "normal_review_required", False)
+ and normal_role in {"partner", "manager_or_partner"}
+ )
+ aqmm_partner_review = is_engagement_partner and getattr(task, "aqmm_partner_review_required", False)
+ aqmm_review_partner_review = is_review_partner and getattr(task, "aqmm_review_partner_required", False)
+
+ if status == "blocked" and getattr(task, "rework_status", "none") != "open":
return "clarification_required"
- if status == "completed":
+ if (
+ (normal_partner_review and normal_status == "rework_required")
+ or (aqmm_partner_review and getattr(task, "partner_review_status", "not_required") == "rework_required")
+ or (aqmm_review_partner_review and getattr(task, "review_partner_review_status", "not_required") == "rework_required")
+ or getattr(task, "rework_status", "none") == "open"
+ ):
+ return "rework_sent"
+ if (
+ (normal_partner_review and normal_status == "pending")
+ or (aqmm_partner_review and getattr(task, "partner_review_status", "not_required") == "pending")
+ or (aqmm_review_partner_review and getattr(task, "review_partner_review_status", "not_required") == "pending")
+ ):
return "pending_review"
if status in CLOSED_TASK_STATUSES:
return "completed"
- if status in {"rework", "rework_required"}:
- return "rework_sent"
- if status == "pending":
- has_partner_rework = any(
- (getattr(comment, "comment_type", "") or "").strip().lower() == "partner_review_note"
- and not getattr(comment, "is_deleted", False)
- for comment in getattr(task, "comments", [])
- )
- return "rework_sent" if has_partner_rework else "approved"
return "approved"
@@ -186,6 +203,7 @@ def build_partner_payload(db: Session, request: Request, current_user, *, q: str
selectinload(ClientServiceTaskInstance.subscription).selectinload(ClientServiceSubscription.catalogue),
selectinload(ClientServiceTaskInstance.subscription).selectinload(ClientServiceSubscription.assigned_manager),
selectinload(ClientServiceTaskInstance.subscription).selectinload(ClientServiceSubscription.assigned_staff),
+ selectinload(ClientServiceTaskInstance.subscription).selectinload(ClientServiceSubscription.review_partner),
selectinload(ClientServiceTaskInstance.assigned_to),
selectinload(ClientServiceTaskInstance.comments).selectinload(ServiceTaskComment.created_by),
)
@@ -227,7 +245,8 @@ def build_partner_payload(db: Session, request: Request, current_user, *, q: str
summary["clients"].add(task.client_id)
if getattr(task, "subscription_id", None):
summary["engagements"].add(task.subscription_id)
- if status == "completed":
+ bucket = _task_bucket(task, current_user)
+ if bucket == "pending_review":
summary["pending_review"] += 1
if status == "blocked":
summary["blocked"] += 1
@@ -237,7 +256,7 @@ def build_partner_payload(db: Session, request: Request, current_user, *, q: str
summary["due_today"] += 1
if status in CLOSED_TASK_STATUSES:
summary["completed"] += 1
- lookup[_task_bucket(task)]["tasks"].append(task)
+ lookup[bucket]["tasks"].append(task)
summary["clients"] = len(summary["clients"])
summary["engagements"] = len(summary["engagements"])
diff --git a/app/modules/services/execution.py b/app/modules/services/execution.py
index 08df63f..ddaf843 100644
--- a/app/modules/services/execution.py
+++ b/app/modules/services/execution.py
@@ -31,6 +31,29 @@ TASK_STATUSES = [
OPEN_TASK_STATUSES = {"pending", "in_progress", "blocked"}
CLOSED_TASK_STATUSES = {"completed", "not_applicable", "cancelled"}
+NORMAL_REVIEW_ROLES = {"manager", "partner", "manager_or_partner"}
+
+
+def normal_review_role_for_template(template) -> str | None:
+ if not getattr(template, "requires_review", False):
+ return None
+ explicit = (getattr(template, "normal_review_role", None) or "").strip().lower()
+ if explicit in NORMAL_REVIEW_ROLES:
+ return explicit
+ default_role = (getattr(template, "default_role_name", None) or "").strip().lower()
+ eligible = {
+ part.strip().lower()
+ for part in (getattr(template, "eligible_role_names", None) or "").split(",")
+ if part.strip()
+ }
+ if default_role in {"manager", "branch manager"} and "partner" in eligible:
+ return "partner"
+ if default_role not in {"manager", "branch manager", "partner"} and ({"manager", "branch manager"} & eligible):
+ return "manager"
+ if "partner" in eligible and not ({"manager", "branch manager"} & eligible):
+ return "partner"
+ return "manager"
+
TASK_COMMENT_TYPES = [
("internal_note", "Internal Note"),
@@ -307,6 +330,9 @@ def generate_tasks_for_subscription(db: Session, *, subscription: ClientServiceS
response_type=(getattr(template, "response_type", "NONE") or "NONE").upper(),
evidence_required=getattr(template, "evidence_required", False),
remarks_required_if_no=getattr(template, "remarks_required_if_no", False),
+ normal_review_required=bool(getattr(template, "requires_review", False)),
+ normal_review_role=normal_review_role_for_template(template),
+ normal_review_status="not_ready" if getattr(template, "requires_review", False) else "not_required",
is_aqmm_task=getattr(template, "is_aqmm_task", False),
aqmm_mandatory=getattr(template, "aqmm_mandatory", False),
aqmm_evidence_required=getattr(template, "aqmm_evidence_required", False),
@@ -372,6 +398,12 @@ def _copy_template_snapshot_to_task(
task.response_type = (getattr(template, "response_type", "NONE") or "NONE").upper()
task.evidence_required = getattr(template, "evidence_required", False)
task.remarks_required_if_no = getattr(template, "remarks_required_if_no", False)
+ task.normal_review_required = bool(getattr(template, "requires_review", False))
+ task.normal_review_role = normal_review_role_for_template(template)
+ if not task.normal_review_required:
+ task.normal_review_status = "not_required"
+ elif (getattr(task, "normal_review_status", None) or "not_required") == "not_required":
+ task.normal_review_status = "not_ready"
task.is_aqmm_task = getattr(template, "is_aqmm_task", False)
task.aqmm_mandatory = getattr(template, "aqmm_mandatory", False)
task.aqmm_evidence_required = getattr(template, "aqmm_evidence_required", False)
@@ -465,6 +497,9 @@ def sync_open_engagement_tasks_for_service(
response_type=(getattr(template, "response_type", "NONE") or "NONE").upper(),
evidence_required=getattr(template, "evidence_required", False),
remarks_required_if_no=getattr(template, "remarks_required_if_no", False),
+ normal_review_required=bool(getattr(template, "requires_review", False)),
+ normal_review_role=normal_review_role_for_template(template),
+ normal_review_status="not_ready" if getattr(template, "requires_review", False) else "not_required",
is_aqmm_task=getattr(template, "is_aqmm_task", False),
aqmm_mandatory=getattr(template, "aqmm_mandatory", False),
aqmm_evidence_required=getattr(template, "aqmm_evidence_required", False),
@@ -1323,6 +1358,11 @@ def submit_task_for_review(db: Session, *, task: ClientServiceTaskInstance, note
now = datetime.now(timezone.utc)
task.submitted_for_review_by_user_id = user_id
task.submitted_for_review_at_utc = now
+ if getattr(task, "normal_review_required", False):
+ task.normal_review_status = "pending"
+ task.normal_review_note = None
+ task.normal_reviewed_by_user_id = None
+ task.normal_reviewed_at_utc = None
if getattr(task, "aqmm_manager_review_required", False) and task.manager_review_status != "reviewed":
task.manager_review_status = "pending"
if getattr(task, "aqmm_partner_review_required", False) and task.partner_review_status != "reviewed":
@@ -1339,6 +1379,53 @@ def submit_task_for_review(db: Session, *, task: ClientServiceTaskInstance, note
recalculate_task_aqmm_status(db, task)
+
+def apply_normal_task_review(
+ db: Session,
+ *,
+ task: ClientServiceTaskInstance,
+ decision: str,
+ note: str,
+ user_id: int,
+) -> None:
+ if getattr(task, "is_locked", False) or getattr(getattr(task, "subscription", None), "is_locked", False):
+ return
+ if not getattr(task, "normal_review_required", False):
+ raise ValueError("Normal review is not required for this task.")
+ clean_decision = (decision or "reviewed").strip().lower()
+ if clean_decision not in {"reviewed", "rework_required"}:
+ clean_decision = "reviewed"
+ clean_note = (note or "").strip()
+ if clean_decision == "rework_required" and not clean_note:
+ raise ValueError("Rework reason is required.")
+ now = datetime.now(timezone.utc)
+ task.normal_review_status = clean_decision
+ task.normal_review_note = clean_note or task.normal_review_note
+ task.normal_reviewed_by_user_id = user_id
+ task.normal_reviewed_at_utc = now
+ if clean_decision == "rework_required":
+ task.rework_status = "open"
+ task.rework_reason = clean_note
+ task.rework_requested_by_user_id = user_id
+ task.rework_requested_at_utc = now
+ task.rework_resolved_at_utc = None
+ task.status = "blocked"
+ comment_type = "rework_note"
+ else:
+ if getattr(task, "rework_status", "none") == "open":
+ task.rework_status = "resolved"
+ task.rework_resolved_at_utc = now
+ comment_type = "manager_review_note" if (getattr(task, "normal_review_role", "") or "").startswith("manager") else "partner_review_note"
+ task.updated_by_user_id = user_id
+ _append_system_task_comment(
+ db,
+ task=task,
+ comment_type=comment_type,
+ message=clean_note or ("Normal review approved." if clean_decision == "reviewed" else clean_note),
+ user_id=user_id,
+ )
+
+
def apply_task_review(
db: Session,
*,
diff --git a/app/modules/services/models.py b/app/modules/services/models.py
index 212a7a6..b93b0cc 100644
--- a/app/modules/services/models.py
+++ b/app/modules/services/models.py
@@ -114,6 +114,7 @@ class ServiceDefaultTaskTemplate(CommonBase):
eligible_role_names: Mapped[str | None] = mapped_column(String(200), nullable=True)
is_mandatory: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
requires_review: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
+ normal_review_role: Mapped[str | None] = mapped_column(String(30), nullable=True)
# AQMM task tags. These flags allow the existing service checklist to become
# the engagement quality checklist for assurance engagements, without creating
@@ -183,6 +184,7 @@ class FirmServiceTaskTemplate(CommonBase):
eligible_role_names: Mapped[str | None] = mapped_column(String(200), nullable=True)
is_mandatory: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
requires_review: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
+ normal_review_role: Mapped[str | None] = mapped_column(String(30), nullable=True)
# AQMM task tags copied into generated ClientServiceTaskInstance rows.
is_aqmm_task: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False, index=True)
@@ -783,6 +785,14 @@ class ClientServiceTaskInstance(CommonBase):
submitted_for_review_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id"), nullable=True, index=True)
submitted_for_review_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
+ # Normal operational review is intentionally separate from AQMM review.
+ normal_review_required: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, index=True)
+ normal_review_role: Mapped[str | None] = mapped_column(String(30), nullable=True, index=True)
+ normal_review_status: Mapped[str] = mapped_column(String(30), nullable=False, default="not_required", index=True)
+ normal_review_note: Mapped[str | None] = mapped_column(Text, nullable=True)
+ normal_reviewed_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
+ normal_reviewed_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
+
manager_review_status: Mapped[str] = mapped_column(String(30), nullable=False, default="not_required", index=True)
manager_review_note: Mapped[str | None] = mapped_column(Text, nullable=True)
manager_reviewed_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id"), nullable=True, index=True)
diff --git a/app/modules/services/templates/services/default_task_form.html b/app/modules/services/templates/services/default_task_form.html
index 25b80e6..e4848a3 100644
--- a/app/modules/services/templates/services/default_task_form.html
+++ b/app/modules/services/templates/services/default_task_form.html
@@ -56,6 +56,14 @@
Review
+
@@ -44,7 +44,7 @@
-
+
@@ -165,7 +165,7 @@
{% if task.is_mandatory %}Mandatory{% endif %}
- {% if task.requires_review %}Review{% endif %}
+ {% if task.requires_review %}Review: {{ (task.normal_review_role or "manager").replace("_"," ").title() }}{% endif %}
{% if task.is_aqmm_task %}AQMM{% endif %}
{% if task.aqmm_mandatory %}AQMM Mandatory{% endif %}
{% if task.aqmm_evidence_required %}Evidence{% endif %}
diff --git a/app/modules/services/ui.py b/app/modules/services/ui.py
index 48a9eab..390e235 100644
--- a/app/modules/services/ui.py
+++ b/app/modules/services/ui.py
@@ -138,6 +138,15 @@ def _validated_registration_type_code(db, value: str, *, existing_value: str | N
raise ValueError("registration_type")
+def _normal_review_role_value(value: str, *, requires_review: bool) -> str | None:
+ if not requires_review:
+ return None
+ clean = (value or "").strip().lower()
+ if clean in {"manager", "partner", "manager_or_partner"}:
+ return clean
+ return "manager"
+
+
def _redirect_denied():
from app.core.http_responses import ui_access_denied
return ui_access_denied()
@@ -948,6 +957,7 @@ def _copy_system_defaults_if_firm_tasks_empty(
eligible_role_names=getattr(default, "eligible_role_names", None) or default.default_role_name,
is_mandatory=default.is_mandatory,
requires_review=default.requires_review,
+ normal_review_role=getattr(default, "normal_review_role", None),
is_aqmm_task=getattr(default, "is_aqmm_task", False),
aqmm_mandatory=getattr(default, "aqmm_mandatory", False),
aqmm_evidence_required=getattr(default, "aqmm_evidence_required", False),
@@ -1241,7 +1251,7 @@ def task_templates_detail(request: Request, catalogue_id: int):
@router.post('/templates/{catalogue_id}/tasks/new')
-def task_template_create_submit(request: Request, catalogue_id: int, task_name: str = Form(...), description: str = Form(''), default_role_name: str = Form(''), eligible_roles: list[str] = Form([]), sequence_no: int | None = Form(None), is_mandatory: str | None = Form(None), requires_review: str | None = Form(None), task_category: str = Form(''), response_required: str | None = Form(None), response_type: str = Form('NONE'), evidence_required: str | None = Form(None), remarks_required_if_no: str | None = Form(None), is_aqmm_task: str | None = Form(None), aqmm_mandatory: str | None = Form(None), aqmm_evidence_required: str | None = Form(None), aqmm_manager_review_required: str | None = Form(None), aqmm_partner_review_required: str | None = Form(None), aqmm_review_partner_required: str | None = Form(None), aqmm_blocks_final_release: str | None = Form(None), aqmm_reference: str = Form(''), is_active: str | None = Form(None), csrf_token: str = Form(...)):
+def task_template_create_submit(request: Request, catalogue_id: int, task_name: str = Form(...), description: str = Form(''), default_role_name: str = Form(''), eligible_roles: list[str] = Form([]), sequence_no: int | None = Form(None), is_mandatory: str | None = Form(None), requires_review: str | None = Form(None), normal_review_role: str = Form('manager'), task_category: str = Form(''), response_required: str | None = Form(None), response_type: str = Form('NONE'), evidence_required: str | None = Form(None), remarks_required_if_no: str | None = Form(None), is_aqmm_task: str | None = Form(None), aqmm_mandatory: str | None = Form(None), aqmm_evidence_required: str | None = Form(None), aqmm_manager_review_required: str | None = Form(None), aqmm_partner_review_required: str | None = Form(None), aqmm_review_partner_required: str | None = Form(None), aqmm_blocks_final_release: str | None = Form(None), aqmm_reference: str = Form(''), is_active: str | None = Form(None), csrf_token: str = Form(...)):
validate_csrf(request, csrf_token)
db = CommonSessionLocal()
try:
@@ -1267,6 +1277,7 @@ def task_template_create_submit(request: Request, catalogue_id: int, task_name:
sequence_no=sequence_no or next_task_sequence(db, tenant_id=tenant_id, catalogue_id=catalogue_id),
is_mandatory=is_mandatory is not None,
requires_review=requires_review is not None,
+ normal_review_role=_normal_review_role_value(normal_review_role, requires_review=requires_review is not None),
task_category=task_category.strip() or None,
response_required=response_required is not None,
response_type=(response_type.strip().upper() or "NONE"),
@@ -1351,7 +1362,7 @@ def default_templates_detail(request: Request, catalogue_id: int):
@router.post('/catalogue/{catalogue_id}/defaults/new')
-def default_template_create_submit(request: Request, catalogue_id: int, task_name: str = Form(...), description: str = Form(''), default_role_name: str = Form(''), sequence_no: int | None = Form(None), is_mandatory: str | None = Form(None), requires_review: str | None = Form(None), task_category: str = Form(''), response_required: str | None = Form(None), response_type: str = Form('NONE'), evidence_required: str | None = Form(None), remarks_required_if_no: str | None = Form(None), is_aqmm_task: str | None = Form(None), aqmm_mandatory: str | None = Form(None), aqmm_evidence_required: str | None = Form(None), aqmm_manager_review_required: str | None = Form(None), aqmm_partner_review_required: str | None = Form(None), aqmm_review_partner_required: str | None = Form(None), aqmm_blocks_final_release: str | None = Form(None), aqmm_reference: str = Form(''), is_active: str | None = Form(None), csrf_token: str = Form(...)):
+def default_template_create_submit(request: Request, catalogue_id: int, task_name: str = Form(...), description: str = Form(''), default_role_name: str = Form(''), sequence_no: int | None = Form(None), is_mandatory: str | None = Form(None), requires_review: str | None = Form(None), normal_review_role: str = Form('manager'), task_category: str = Form(''), response_required: str | None = Form(None), response_type: str = Form('NONE'), evidence_required: str | None = Form(None), remarks_required_if_no: str | None = Form(None), is_aqmm_task: str | None = Form(None), aqmm_mandatory: str | None = Form(None), aqmm_evidence_required: str | None = Form(None), aqmm_manager_review_required: str | None = Form(None), aqmm_partner_review_required: str | None = Form(None), aqmm_review_partner_required: str | None = Form(None), aqmm_blocks_final_release: str | None = Form(None), aqmm_reference: str = Form(''), is_active: str | None = Form(None), csrf_token: str = Form(...)):
validate_csrf(request, csrf_token)
db = CommonSessionLocal()
try:
@@ -1364,7 +1375,7 @@ def default_template_create_submit(request: Request, catalogue_id: int, task_nam
catalogue = get_catalogue(db, catalogue_id)
if not catalogue:
return RedirectResponse(url='/services/defaults', status_code=303)
- row = ServiceDefaultTaskTemplate(service_catalogue_id=catalogue_id, task_name=task_name.strip(), description=description.strip() or None, default_role_name=default_role_name.strip() or None, sequence_no=sequence_no or next_default_task_sequence(db, catalogue_id=catalogue_id), is_mandatory=is_mandatory is not None, requires_review=requires_review is not None, task_category=task_category.strip() or None, response_required=response_required is not None, response_type=(response_type.strip().upper() or "NONE"), evidence_required=evidence_required is not None, remarks_required_if_no=remarks_required_if_no is not None, is_aqmm_task=is_aqmm_task is not None, aqmm_mandatory=aqmm_mandatory is not None, aqmm_evidence_required=aqmm_evidence_required is not None, aqmm_manager_review_required=aqmm_manager_review_required is not None, aqmm_partner_review_required=aqmm_partner_review_required is not None, aqmm_review_partner_required=aqmm_review_partner_required is not None, aqmm_blocks_final_release=aqmm_blocks_final_release is not None, aqmm_reference=aqmm_reference.strip() or None, is_active=is_active is not None)
+ row = ServiceDefaultTaskTemplate(service_catalogue_id=catalogue_id, task_name=task_name.strip(), description=description.strip() or None, default_role_name=default_role_name.strip() or None, sequence_no=sequence_no or next_default_task_sequence(db, catalogue_id=catalogue_id), is_mandatory=is_mandatory is not None, requires_review=requires_review is not None, normal_review_role=_normal_review_role_value(normal_review_role, requires_review=requires_review is not None), task_category=task_category.strip() or None, response_required=response_required is not None, response_type=(response_type.strip().upper() or "NONE"), evidence_required=evidence_required is not None, remarks_required_if_no=remarks_required_if_no is not None, is_aqmm_task=is_aqmm_task is not None, aqmm_mandatory=aqmm_mandatory is not None, aqmm_evidence_required=aqmm_evidence_required is not None, aqmm_manager_review_required=aqmm_manager_review_required is not None, aqmm_partner_review_required=aqmm_partner_review_required is not None, aqmm_review_partner_required=aqmm_review_partner_required is not None, aqmm_blocks_final_release=aqmm_blocks_final_release is not None, aqmm_reference=aqmm_reference.strip() or None, is_active=is_active is not None)
db.add(row); db.commit()
return RedirectResponse(url=f'/services/catalogue/{catalogue_id}/defaults', status_code=303)
finally:
@@ -1403,6 +1414,7 @@ def copy_defaults_to_firm(request: Request, catalogue_id: int, csrf_token: str =
default_role_name=d.default_role_name,
is_mandatory=d.is_mandatory,
requires_review=d.requires_review,
+ normal_review_role=getattr(d, "normal_review_role", None),
task_category=getattr(d, "task_category", None),
response_required=getattr(d, "response_required", False),
response_type=getattr(d, "response_type", "NONE") or "NONE",
@@ -1707,6 +1719,7 @@ def firm_task_template_edit_submit(
sequence_no: int = Form(1),
is_mandatory: str | None = Form(None),
requires_review: str | None = Form(None),
+ normal_review_role: str = Form('manager'),
task_category: str = Form(''),
response_required: str | None = Form(None),
response_type: str = Form('NONE'),
@@ -1753,6 +1766,7 @@ def firm_task_template_edit_submit(
task.sequence_no = sequence_no
task.is_mandatory = is_mandatory is not None
task.requires_review = requires_review is not None
+ task.normal_review_role = _normal_review_role_value(normal_review_role, requires_review=task.requires_review)
task.task_category = task_category.strip() or None
task.response_required = response_required is not None
task.response_type = response_type.strip().upper() or "NONE"
@@ -1849,6 +1863,7 @@ def default_task_template_edit_submit(
sequence_no: int = Form(1),
is_mandatory: str | None = Form(None),
requires_review: str | None = Form(None),
+ normal_review_role: str = Form('manager'),
task_category: str = Form(''),
response_required: str | None = Form(None),
response_type: str = Form('NONE'),
@@ -1895,6 +1910,7 @@ def default_task_template_edit_submit(
task.sequence_no = sequence_no
task.is_mandatory = is_mandatory is not None
task.requires_review = requires_review is not None
+ task.normal_review_role = _normal_review_role_value(normal_review_role, requires_review=task.requires_review)
task.task_category = task_category.strip() or None
task.response_required = response_required is not None
task.response_type = response_type.strip().upper() or "NONE"
|