Require review partner for bulk assurance engagements
This commit is contained in:
@@ -388,6 +388,7 @@ def subscription_bulk_create_page(request: Request, error: str = ""):
|
|||||||
"manager": "The selected Manager is not available for this firm.",
|
"manager": "The selected Manager is not available for this firm.",
|
||||||
"staff": "The selected Staff member is not available for this firm.",
|
"staff": "The selected Staff member is not available for this firm.",
|
||||||
"review_partner": "The selected Review Partner is not available for this firm.",
|
"review_partner": "The selected Review Partner is not available for this firm.",
|
||||||
|
"review_partner_required": "Review Partner is mandatory for an assurance engagement.",
|
||||||
"clients": "Select at least one permitted client.",
|
"clients": "Select at least one permitted client.",
|
||||||
}.get(error),
|
}.get(error),
|
||||||
)
|
)
|
||||||
@@ -492,11 +493,19 @@ def subscription_bulk_create_submit(
|
|||||||
return RedirectResponse(url="/services/engagements/bulk-new?error=clients", status_code=303)
|
return RedirectResponse(url="/services/engagements/bulk-new?error=clients", status_code=303)
|
||||||
|
|
||||||
engagement_type = getattr(firm_selection.catalogue, "engagement_type", "non_assurance") or "non_assurance"
|
engagement_type = getattr(firm_selection.catalogue, "engagement_type", "non_assurance") or "non_assurance"
|
||||||
requires_review_partner = review_partner_required_for_engagement(
|
normalized_engagement_type = str(engagement_type).strip().lower().replace("-", "_").replace(" ", "_")
|
||||||
|
assurance_review_partner_required = normalized_engagement_type == "assurance"
|
||||||
|
workflow_review_partner_required = review_partner_required_for_engagement(
|
||||||
db,
|
db,
|
||||||
tenant_id=tenant_id,
|
tenant_id=tenant_id,
|
||||||
engagement_type=engagement_type,
|
engagement_type=engagement_type,
|
||||||
)
|
)
|
||||||
|
requires_review_partner = assurance_review_partner_required or workflow_review_partner_required
|
||||||
|
if assurance_review_partner_required and review_partner_id is None:
|
||||||
|
return RedirectResponse(
|
||||||
|
url="/services/engagements/bulk-new?error=review_partner_required",
|
||||||
|
status_code=303,
|
||||||
|
)
|
||||||
|
|
||||||
for client_id in selected_client_ids:
|
for client_id in selected_client_ids:
|
||||||
existing = get_existing_subscription(
|
existing = get_existing_subscription(
|
||||||
@@ -525,9 +534,13 @@ def subscription_bulk_create_submit(
|
|||||||
assigned_manager_user_id=manager_id,
|
assigned_manager_user_id=manager_id,
|
||||||
assigned_staff_user_id=staff_id,
|
assigned_staff_user_id=staff_id,
|
||||||
review_partner_user_id=(
|
review_partner_user_id=(
|
||||||
review_partner_id or getattr(client, "default_review_partner_user_id", None)
|
review_partner_id
|
||||||
|
if review_partner_id is not None
|
||||||
|
else (
|
||||||
|
getattr(client, "default_review_partner_user_id", None)
|
||||||
if requires_review_partner
|
if requires_review_partner
|
||||||
else None
|
else None
|
||||||
|
)
|
||||||
),
|
),
|
||||||
financial_year=selected_financial_year,
|
financial_year=selected_financial_year,
|
||||||
assessment_year=assessment_year_from_financial_year(selected_financial_year),
|
assessment_year=assessment_year_from_financial_year(selected_financial_year),
|
||||||
|
|||||||
@@ -60,13 +60,16 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="review-partner-field" class="hidden">
|
<div id="review-partner-field">
|
||||||
<label class="mb-2 block text-sm font-medium text-slate-700">Review Partner</label>
|
<label class="mb-2 flex items-center gap-2 text-sm font-medium text-slate-700">
|
||||||
|
<span>Review Partner</span>
|
||||||
|
<span id="review-partner-requirement" class="rounded-full bg-slate-100 px-2 py-0.5 text-xs font-semibold text-slate-600">Optional</span>
|
||||||
|
</label>
|
||||||
<select name="review_partner_user_id" id="bulk-review-partner" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
<select name="review_partner_user_id" id="bulk-review-partner" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
||||||
<option value="">Use client default / Not assigned</option>
|
<option value="">Not assigned</option>
|
||||||
{% for u in review_partners %}<option value="{{ u.id }}" data-branch="{{ u.branch_id }}">{{ u.full_name or u.email }}</option>{% endfor %}
|
{% for u in review_partners %}<option value="{{ u.id }}" data-branch="{{ u.branch_id }}">{{ u.full_name or u.email }}</option>{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<p class="mt-1 text-xs text-slate-500">Used only when the selected service is an assurance engagement and the firm setup requires a review partner.</p>
|
<p id="review-partner-help" class="mt-1 text-xs text-slate-500">Optional for non-assurance engagements. A selected Review Partner is saved for every engagement created in this batch.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="md:col-span-2 xl:col-span-3">
|
<div class="md:col-span-2 xl:col-span-3">
|
||||||
@@ -133,7 +136,9 @@
|
|||||||
const form = document.getElementById('bulk-engagement-form');
|
const form = document.getElementById('bulk-engagement-form');
|
||||||
const service = document.getElementById('bulk-service');
|
const service = document.getElementById('bulk-service');
|
||||||
const info = document.getElementById('service-derived-info');
|
const info = document.getElementById('service-derived-info');
|
||||||
const reviewField = document.getElementById('review-partner-field');
|
const reviewPartner = document.getElementById('bulk-review-partner');
|
||||||
|
const reviewRequirement = document.getElementById('review-partner-requirement');
|
||||||
|
const reviewHelp = document.getElementById('review-partner-help');
|
||||||
const search = document.getElementById('client-search');
|
const search = document.getElementById('client-search');
|
||||||
const clear = document.getElementById('clear-client-search');
|
const clear = document.getElementById('clear-client-search');
|
||||||
const selectAll = document.getElementById('select-all-visible');
|
const selectAll = document.getElementById('select-all-visible');
|
||||||
@@ -145,8 +150,16 @@
|
|||||||
const option = service.options[service.selectedIndex];
|
const option = service.options[service.selectedIndex];
|
||||||
const type = option ? (option.dataset.type || '') : '';
|
const type = option ? (option.dataset.type || '') : '';
|
||||||
const recurrence = option ? (option.dataset.recurrence || '') : '';
|
const recurrence = option ? (option.dataset.recurrence || '') : '';
|
||||||
const assurance = type.toLowerCase() === 'assurance';
|
const normalizedType = type.trim().toLowerCase().replaceAll('-', '_').replaceAll(' ', '_');
|
||||||
reviewField.classList.toggle('hidden', !assurance);
|
const assurance = normalizedType === 'assurance';
|
||||||
|
reviewPartner.required = assurance;
|
||||||
|
reviewRequirement.textContent = assurance ? 'Mandatory' : 'Optional';
|
||||||
|
reviewRequirement.className = assurance
|
||||||
|
? 'rounded-full bg-rose-100 px-2 py-0.5 text-xs font-semibold text-rose-700'
|
||||||
|
: 'rounded-full bg-slate-100 px-2 py-0.5 text-xs font-semibold text-slate-600';
|
||||||
|
reviewHelp.textContent = assurance
|
||||||
|
? 'Mandatory because the selected enabled firm service is an assurance engagement.'
|
||||||
|
: 'Optional for non-assurance engagements. A selected Review Partner is saved for every engagement created in this batch.';
|
||||||
info.textContent = option && option.value
|
info.textContent = option && option.value
|
||||||
? `Type: ${assurance ? 'Assurance' : 'Non-Assurance'}${recurrence ? ' · Recurrence: ' + recurrence.replaceAll('_', ' ') : ''} · Due-date rule and workflow are taken from the service setup.`
|
? `Type: ${assurance ? 'Assurance' : 'Non-Assurance'}${recurrence ? ' · Recurrence: ' + recurrence.replaceAll('_', ' ') : ''} · Due-date rule and workflow are taken from the service setup.`
|
||||||
: 'Due-date rules, recurrence, assurance type, and task workflow are taken from the selected service setup.';
|
: 'Due-date rules, recurrence, assurance type, and task workflow are taken from the selected service setup.';
|
||||||
|
|||||||
Reference in New Issue
Block a user