125 lines
11 KiB
HTML
125 lines
11 KiB
HTML
{% extends "ui/templates/base/layout.html" %}
|
|
{% block content %}
|
|
<div class="mx-auto max-w-4xl rounded-2xl bg-white p-6 shadow-soft">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h2 class="text-xl font-semibold text-slate-900">{% if mode == 'edit' %}Edit Engagement{% else %}Assign Service to Client{% endif %}</h2>
|
|
<p class="text-sm text-slate-500">Engagement Partner owns the assignment, Performing Partner executes or supervises it, and Review Partner independently reviews applicable assurance engagements.</p>
|
|
</div>
|
|
<a href="/services/engagements" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Back</a>
|
|
</div>
|
|
|
|
<form method="post" class="mt-6 grid gap-5 md:grid-cols-2">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
|
|
<div>
|
|
<label class="mb-2 block text-sm font-medium text-slate-700">Financial Year</label>
|
|
{% if mode == 'edit' %}
|
|
<div class="rounded-xl border border-slate-200 bg-slate-50 px-4 py-2 text-sm text-slate-700">{{ subscription.financial_year }}</div>
|
|
{% else %}
|
|
<input type="text" id="engagement-financial-year" name="financial_year" value="{{ financial_year or '2025-26' }}" required placeholder="2025-26" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div>
|
|
<label class="mb-2 block text-sm font-medium text-slate-700">Client</label>
|
|
{% if mode == 'edit' %}
|
|
<div class="rounded-xl border border-slate-200 bg-slate-50 px-4 py-2 text-sm text-slate-700">{{ subscription.client.client_name if subscription and subscription.client else '-' }}</div>
|
|
{% else %}
|
|
<select name="client_id" required class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
|
<option value="">Select client</option>
|
|
{% for client in clients %}<option value="{{ client.id }}" {% if selected_client_id and client.id == selected_client_id %}selected{% endif %}>{{ client.client_name }} ({{ client.client_code }})</option>{% endfor %}
|
|
</select>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div>
|
|
<label class="mb-2 block text-sm font-medium text-slate-700">Enabled Service</label>
|
|
{% if mode == 'edit' %}
|
|
<div class="rounded-xl border border-slate-200 bg-slate-50 px-4 py-2 text-sm text-slate-700">
|
|
{{ subscription.catalogue.service_name if subscription and subscription.catalogue else '-' }} · {{ 'Assurance' if subscription and subscription.engagement_type == 'assurance' else 'Non-Assurance' }}
|
|
</div>
|
|
{% else %}
|
|
<select name="service_catalogue_id" id="engagement-service" required class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
|
<option value="">Select service</option>
|
|
{% for selection in enabled_services %}
|
|
<option value="{{ selection.catalogue.id }}" data-recurrence="{{ selection.catalogue.recurrence_type or '' }}">{{ selection.catalogue.service_name }} ({{ selection.catalogue.service_code }}) - {{ 'Assurance' if selection.catalogue.engagement_type == 'assurance' else 'Non-Assurance' }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div id="engagement-period-field">
|
|
<label class="mb-2 block text-sm font-medium text-slate-700">Return / Engagement Period</label>
|
|
{% if mode == 'edit' %}
|
|
<select name="period_label" {% if period_required %}required{% endif %} class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
|
{% for value, label in period_choices %}<option value="{{ value }}" {% if subscription and subscription.period_label == value %}selected{% endif %}>{{ label }}</option>{% endfor %}
|
|
</select>
|
|
{% else %}
|
|
<select name="period_label" id="engagement-period" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
|
<option value="">Not applicable</option>
|
|
</select>
|
|
<label id="generate-all-periods-wrap" class="mt-2 hidden items-center gap-2 text-sm text-slate-700">
|
|
<input type="checkbox" name="generate_all_periods" id="generate-all-periods" value="1" class="rounded border-slate-300">
|
|
Generate all periods for this financial year
|
|
</label>
|
|
{% endif %}
|
|
<p class="mt-1 text-xs text-slate-500">Monthly and quarterly services require a period so the statutory due date can be calculated.</p>
|
|
</div>
|
|
|
|
<div><label class="mb-2 block text-sm font-medium text-slate-700">Assigned Partner</label><select name="assigned_partner_user_id" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm"><option value="">Not assigned</option>{% for u in assignable_users %}<option value="{{ u.id }}" {% if subscription and subscription.assigned_partner_user_id == u.id %}selected{% endif %}>{{ u.full_name or u.email }}</option>{% endfor %}</select></div>
|
|
<div><label class="mb-2 block text-sm font-medium text-slate-700">Performing Partner</label><select name="performing_partner_user_id" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm"><option value="">Use client default / Engagement Partner</option>{% for u in performing_partners or [] %}<option value="{{ u.id }}" {% if subscription and subscription.performing_partner_user_id == u.id %}selected{% endif %}>{{ u.full_name or u.email }}</option>{% endfor %}</select><p class="mt-1 text-xs text-slate-500">The Partner who directly performs or supervises this engagement.</p></div>
|
|
<div><label class="mb-2 block text-sm font-medium text-slate-700">Assigned Manager</label><select name="assigned_manager_user_id" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm"><option value="">Not assigned</option>{% for u in assignable_users %}<option value="{{ u.id }}" {% if subscription and subscription.assigned_manager_user_id == u.id %}selected{% endif %}>{{ u.full_name or u.email }}</option>{% endfor %}</select></div>
|
|
<div><label class="mb-2 block text-sm font-medium text-slate-700">Assigned Staff</label><select name="assigned_staff_user_id" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm"><option value="">Not assigned</option>{% for u in assignable_users %}<option value="{{ u.id }}" {% if subscription and subscription.assigned_staff_user_id == u.id %}selected{% endif %}>{{ u.full_name or u.email }}</option>{% endfor %}</select></div>
|
|
<div><label class="mb-2 block text-sm font-medium text-slate-700">Review Partner</label><select name="review_partner_user_id" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm"><option value="">Use client default / Not required</option>{% for u in review_partners or [] %}<option value="{{ u.id }}" {% if subscription and subscription.review_partner_user_id == u.id %}selected{% endif %}>{{ u.full_name or u.email }}</option>{% endfor %}</select><p class="mt-1 text-xs text-slate-500">Saved only for assurance engagements of partnership audit firms.</p></div>
|
|
|
|
<div><label class="mb-2 block text-sm font-medium text-slate-700">Status</label><select name="status" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">{% for value, label in subscription_statuses %}<option value="{{ value }}" {% if subscription and subscription.status == value %}selected{% elif not subscription and value == 'active' %}selected{% endif %}>{{ label }}</option>{% endfor %}</select></div>
|
|
<div><label class="mb-2 block text-sm font-medium text-slate-700">Start Date</label><input type="date" name="start_date" value="{{ subscription.start_date if subscription and subscription.start_date else '' }}" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm"></div>
|
|
<div><label class="mb-2 block text-sm font-medium text-slate-700">End Date</label><input type="date" name="end_date" value="{{ subscription.end_date if subscription and subscription.end_date else '' }}" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm"></div>
|
|
<div><label class="mb-2 block text-sm font-medium text-slate-700">Expiry Date</label><input type="date" name="expiry_date" value="{{ subscription.expiry_date if subscription and subscription.expiry_date else '' }}" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm"><p class="mt-1 text-xs text-slate-500">Use for renewal-before-expiry services like DSC/FSSAI. Current due date is calculated from the service due-date rule.</p></div>
|
|
<div class="flex items-center gap-6 pt-7 text-sm text-slate-700"><label class="inline-flex items-center gap-2"><input type="checkbox" name="is_active" {% if not subscription or subscription.is_active %}checked{% endif %}> Active</label></div>
|
|
<div class="md:col-span-2"><label class="mb-2 block text-sm font-medium text-slate-700">Remarks</label><textarea name="remarks" rows="4" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">{{ subscription.remarks if subscription and subscription.remarks else '' }}</textarea></div>
|
|
<div class="md:col-span-2 flex justify-end gap-3"><a href="/services/engagements" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</a><button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white hover:bg-brand-700">Save</button></div>
|
|
</form>
|
|
</div>
|
|
|
|
{% if mode != 'edit' %}
|
|
<script>
|
|
(function () {
|
|
const service = document.getElementById('engagement-service');
|
|
const fy = document.getElementById('engagement-financial-year');
|
|
const period = document.getElementById('engagement-period');
|
|
const generateWrap = document.getElementById('generate-all-periods-wrap');
|
|
const generateAll = document.getElementById('generate-all-periods');
|
|
if (!service || !fy || !period) return;
|
|
|
|
function fyStart() {
|
|
const match = (fy.value || '').trim().match(/^(\d{4})-(\d{2}|\d{4})$/);
|
|
return match ? Number(match[1]) : null;
|
|
}
|
|
function add(value, label) {
|
|
const option = document.createElement('option'); option.value = value; option.textContent = label; period.appendChild(option);
|
|
}
|
|
function rebuild() {
|
|
const selected = service.options[service.selectedIndex];
|
|
const recurrence = ((selected && selected.dataset.recurrence) || '').toLowerCase().replaceAll('-', '_').replaceAll(' ', '_');
|
|
const start = fyStart();
|
|
period.innerHTML = '';
|
|
generateAll.checked = false;
|
|
if (recurrence === 'monthly' && start) {
|
|
[['04','Apr',start],['05','May',start],['06','Jun',start],['07','Jul',start],['08','Aug',start],['09','Sep',start],['10','Oct',start],['11','Nov',start],['12','Dec',start],['01','Jan',start+1],['02','Feb',start+1],['03','Mar',start+1]].forEach(row => add(`${row[2]}-${row[0]}`, `${row[1]} ${row[2]}`));
|
|
period.required = true; generateWrap.classList.remove('hidden'); generateWrap.classList.add('flex');
|
|
} else if (recurrence === 'quarterly' && start) {
|
|
['Q1','Q2','Q3','Q4'].forEach(q => add(q, `${q} ${fy.value}`));
|
|
period.required = true; generateWrap.classList.remove('hidden'); generateWrap.classList.add('flex');
|
|
} else {
|
|
add('', 'Not applicable'); period.required = false; generateWrap.classList.add('hidden'); generateWrap.classList.remove('flex');
|
|
}
|
|
}
|
|
generateAll.addEventListener('change', () => { period.disabled = generateAll.checked; });
|
|
service.addEventListener('change', rebuild); fy.addEventListener('input', rebuild); rebuild();
|
|
})();
|
|
</script>
|
|
{% endif %}
|
|
{% endblock %}
|