225 lines
12 KiB
HTML
225 lines
12 KiB
HTML
{% extends "ui/templates/base/layout.html" %}
|
|
{% block content %}
|
|
<div class="space-y-6">
|
|
{% set _uiux_partner_role_text = (current_user_roles or [])|join('|')|lower %}
|
|
{% if 'partner' in _uiux_partner_role_text %}
|
|
{% include "ui/templates/components/partner_navigation_v2.html" %}
|
|
{% endif %}
|
|
|
|
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
<div>
|
|
<h2 class="text-xl font-semibold text-slate-900">
|
|
{{ scope_display.primary if scope_display else plan.client.client_name }} — {{ plan.catalogue.service_name }}
|
|
</h2>
|
|
<p class="text-sm text-slate-500">
|
|
Client service subscription master and its period-wise engagements.
|
|
{% if scope_display and scope_display.context %}
|
|
<span class="block">{{ scope_display.context }}</span>
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
<div class="flex flex-wrap gap-2">
|
|
<a href="/services/subscriptions"
|
|
class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">
|
|
Back
|
|
</a>
|
|
{% if can_edit_subscription %}
|
|
<a href="/services/subscriptions/{{ plan.id }}/edit"
|
|
class="rounded-xl border border-brand-300 px-4 py-2 text-sm font-medium text-brand-700 hover:bg-brand-50">
|
|
Edit Subscription
|
|
</a>
|
|
<a href="/services/subscriptions/{{ plan.id }}/scope"
|
|
class="rounded-xl border border-emerald-300 px-4 py-2 text-sm font-medium text-emerald-700 hover:bg-emerald-50">
|
|
Map Scope
|
|
</a>
|
|
{% endif %}
|
|
{% if can_edit_subscription and plan.is_active and plan.status == 'active' %}
|
|
<form method="post" action="/services/subscriptions/{{ plan.id }}/generate-current"
|
|
onsubmit="return confirm('Generate the current engagement for FY {{ financial_year }}? Existing matching engagements will be reused.');">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<input type="hidden" name="financial_year" value="{{ financial_year }}">
|
|
<button type="submit"
|
|
class="rounded-xl border border-emerald-300 px-4 py-2 text-sm font-medium text-emerald-700 hover:bg-emerald-50">
|
|
Generate Current Engagement
|
|
</button>
|
|
</form>
|
|
{% endif %}
|
|
<a href="/services/engagements/new?client_id={{ plan.client_id }}"
|
|
class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white hover:bg-brand-700">
|
|
Create Engagement
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
{% if generated %}
|
|
<div class="rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800">
|
|
Current FY engagement generated successfully using the subscription defaults. Due dates, quality workflow and task generation were processed through the existing engagement engine.
|
|
</div>
|
|
{% endif %}
|
|
{% if existing %}
|
|
<div class="rounded-xl border border-sky-200 bg-sky-50 px-4 py-3 text-sm text-sky-800">
|
|
A matching engagement already exists for the current FY/period, so no duplicate was created.
|
|
</div>
|
|
{% endif %}
|
|
{% if generation_error %}
|
|
<div class="rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-800">
|
|
{% if generation_error == 'financial_year' %}
|
|
Engagement generation is not allowed because FY {{ financial_year }} is locked.
|
|
{% elif generation_error == 'review_partner_required' %}
|
|
This assurance service requires a Review Partner before an engagement can be generated.
|
|
{% elif generation_error == 'review_partner_independence' %}
|
|
The Review Partner must differ from the Engagement Partner and Performing Partner.
|
|
{% elif generation_error == 'inactive' %}
|
|
This subscription is inactive and cannot generate an engagement.
|
|
{% elif generation_error == 'service' %}
|
|
The underlying firm service is not enabled, so the engagement was not generated.
|
|
{% else %}
|
|
The current engagement could not be generated. Please verify the subscription scope and defaults.
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<section class="rounded-2xl bg-white p-5 shadow-soft">
|
|
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
<div>
|
|
<h3 class="text-base font-semibold text-slate-900">Subscription Scope</h3>
|
|
<p class="text-sm text-slate-500">
|
|
The legal client remains unchanged. Business Unit, Client Branch and Registration identify the exact compliance scope.
|
|
</p>
|
|
</div>
|
|
{% if can_edit_subscription %}
|
|
<a href="/services/subscriptions/{{ plan.id }}/scope"
|
|
class="rounded-xl border border-emerald-300 px-4 py-2 text-sm font-medium text-emerald-700 hover:bg-emerald-50">
|
|
Change Scope
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
<div class="mt-4 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Scope Type</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">
|
|
{{ (plan.scope_type or 'client')|replace('_', ' ')|title }}
|
|
</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Client</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.client.client_name }}</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Business Unit</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">
|
|
{{ scope_business.business_name if scope_business else '-' }}
|
|
</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Client Branch</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">
|
|
{{ scope_branch.branch_name if scope_branch else '-' }}
|
|
</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Registration Type</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">
|
|
{{ scope_registration_type.name if scope_registration_type else '-' }}
|
|
</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Registration Number</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">
|
|
{{ scope_registration.registration_number if scope_registration else '-' }}
|
|
</div>
|
|
{% if scope_registration and scope_registration.trade_name %}
|
|
<div class="mt-1 text-xs text-slate-500">{{ scope_registration.trade_name }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="rounded-2xl bg-white p-5 shadow-soft">
|
|
<h3 class="text-base font-semibold text-slate-900">Subscription Defaults</h3>
|
|
<div class="mt-4 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Recurrence</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.recurrence_type|replace('_', ' ')|title }}</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Status</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.status|replace('_', ' ')|title }}</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Engagement Partner</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_partner.full_name if plan.default_partner else '-' }}</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Performing Partner</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_performing_partner.full_name if plan.default_performing_partner else '-' }}</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Manager</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_manager.full_name if plan.default_manager else '-' }}</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Staff</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_staff.full_name if plan.default_staff else '-' }}</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Review Partner</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_review_partner.full_name if plan.default_review_partner else '-' }}</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 p-4">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Auto-generate Periods</div>
|
|
<div class="mt-1 text-sm font-medium text-slate-900">{{ 'Yes' if plan.auto_generate_periods else 'No' }}</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="overflow-hidden rounded-2xl bg-white shadow-soft">
|
|
<div class="border-b border-slate-200 px-5 py-4">
|
|
<h3 class="text-base font-semibold text-slate-900">Engagement Instances</h3>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-slate-200">
|
|
<thead class="bg-slate-50">
|
|
<tr>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">FY</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Period</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Due Date</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Status</th>
|
|
<th class="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wide text-slate-500">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-100">
|
|
{% for row in engagements %}
|
|
<tr>
|
|
<td class="px-4 py-3 text-sm text-slate-700">{{ row.financial_year or '-' }}</td>
|
|
<td class="px-4 py-3 text-sm text-slate-700">{{ row.period_label or '-' }}</td>
|
|
<td class="px-4 py-3 text-sm text-slate-700">{{ row.current_due_date or '-' }}</td>
|
|
<td class="px-4 py-3 text-sm">
|
|
<span class="rounded-full px-2 py-1 text-xs font-medium
|
|
{% if row.status == 'active' %}bg-emerald-100 text-emerald-700
|
|
{% else %}bg-slate-200 text-slate-700{% endif %}">
|
|
{{ row.status|replace('_', ' ')|title }}
|
|
</span>
|
|
</td>
|
|
<td class="px-4 py-3 text-right text-sm">
|
|
<a href="/services/engagements/{{ row.id }}"
|
|
class="font-medium text-brand-700 hover:underline">
|
|
View
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="5" class="px-4 py-10 text-center text-sm text-slate-500">
|
|
No engagement instances generated.
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
{% endblock %}
|