Add subscription registration scope mapping
This commit is contained in:
@@ -25,6 +25,10 @@
|
||||
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 %}
|
||||
<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">
|
||||
@@ -33,6 +37,63 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<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">
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
{% 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-start justify-between gap-3">
|
||||
<div>
|
||||
<h2 class="text-xl font-semibold text-slate-900">Map Subscription Scope</h2>
|
||||
<p class="text-sm text-slate-500">
|
||||
{{ plan.client.client_name }} — {{ plan.catalogue.service_name }}
|
||||
</p>
|
||||
</div>
|
||||
<a href="/services/subscriptions/{{ plan.id }}"
|
||||
class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700">
|
||||
Back to Subscription
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if error_message %}
|
||||
<div class="rounded-2xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-700">
|
||||
{{ error_message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if saved %}
|
||||
<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-700">
|
||||
Subscription scope updated. Open engagements updated: {{ updated_engagements }}.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<section class="rounded-2xl bg-white p-5 shadow-soft">
|
||||
<h3 class="text-base font-semibold text-slate-900">Current Scope</h3>
|
||||
<div class="mt-4 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<div class="rounded-xl border p-4">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">Scope Type</div>
|
||||
<div class="mt-1 text-sm font-medium">{{ (plan.scope_type or 'client')|replace('_',' ')|title }}</div>
|
||||
</div>
|
||||
<div class="rounded-xl border p-4">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">Business Unit</div>
|
||||
<div class="mt-1 text-sm font-medium">{{ scope_business.business_name if scope_business else '-' }}</div>
|
||||
</div>
|
||||
<div class="rounded-xl border p-4">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">Client Branch</div>
|
||||
<div class="mt-1 text-sm font-medium">{{ scope_branch.branch_name if scope_branch else '-' }}</div>
|
||||
</div>
|
||||
<div class="rounded-xl border p-4">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">Registration</div>
|
||||
<div class="mt-1 text-sm font-medium">
|
||||
{% if scope_registration_type and scope_registration %}
|
||||
{{ scope_registration_type.code }} — {{ scope_registration.registration_number }}
|
||||
{% else %}-{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<form method="post" action="/services/subscriptions/{{ plan.id }}/scope"
|
||||
class="space-y-5 rounded-2xl bg-white p-5 shadow-soft">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
|
||||
<div class="grid gap-4 md:grid-cols-2">
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">New Scope Type *</label>
|
||||
<select name="scope_type" id="scope-type" required
|
||||
class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
||||
{% for value,label in [
|
||||
('client','Client / PAN level'),
|
||||
('business_unit','Business Unit level'),
|
||||
('client_branch','Client Branch level'),
|
||||
('registration','Registration level')
|
||||
] %}
|
||||
<option value="{{ value }}" {% if (plan.scope_type or 'client') == value %}selected{% endif %}>
|
||||
{{ label }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="business-wrap">
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">Business Unit</label>
|
||||
<select name="business_unit_id" id="business-unit"
|
||||
class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
||||
<option value="">Select Business Unit</option>
|
||||
{% for row in businesses %}
|
||||
<option value="{{ row.id }}" {% if plan.business_unit_id == row.id %}selected{% endif %}>
|
||||
{{ row.business_name }}{% if row.trade_name %} — {{ row.trade_name }}{% endif %}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="branch-wrap">
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">Client Branch</label>
|
||||
<select name="client_branch_id" id="client-branch"
|
||||
class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
||||
<option value="">Select Client Branch</option>
|
||||
{% for row in branches %}
|
||||
<option value="{{ row.id }}"
|
||||
data-business="{{ row.business_unit_id }}"
|
||||
{% if plan.client_branch_id == row.id %}selected{% endif %}>
|
||||
{{ row.branch_name }}{% if row.state %} — {{ row.state }}{% endif %}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="registration-wrap">
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">Registration</label>
|
||||
<select name="registration_id" id="registration"
|
||||
class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
||||
<option value="">Select Registration</option>
|
||||
{% for row in registrations %}
|
||||
{% set registration_type = registration_type_by_id.get(row.id) %}
|
||||
<option value="{{ row.id }}"
|
||||
data-business="{{ row.business_unit_id or '' }}"
|
||||
data-branch="{{ row.client_branch_id or '' }}"
|
||||
data-type="{{ registration_type.code if registration_type else '' }}"
|
||||
{% if plan.registration_id == row.id %}selected{% endif %}>
|
||||
{{ registration_type.code if registration_type else 'Registration' }}
|
||||
— {{ row.registration_number }}
|
||||
{% if row.trade_name %} — {{ row.trade_name }}{% endif %}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if plan.catalogue.required_registration_type %}
|
||||
<p class="mt-1 text-xs text-slate-500">
|
||||
Required by Service Catalogue: {{ plan.catalogue.required_registration_type }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">Apply Scope Change To</label>
|
||||
<div class="grid gap-3 md:grid-cols-2">
|
||||
<label class="flex items-start gap-3 rounded-xl border p-4">
|
||||
<input type="radio" name="propagation_mode" value="subscription_only" class="mt-1">
|
||||
<span>
|
||||
<span class="block text-sm font-medium">Subscription master only</span>
|
||||
<span class="text-xs text-slate-500">
|
||||
Future engagements use the new scope; existing engagements remain unchanged.
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<label class="flex items-start gap-3 rounded-xl border p-4">
|
||||
<input type="radio" name="propagation_mode" value="open_engagements" checked class="mt-1">
|
||||
<span>
|
||||
<span class="block text-sm font-medium">Subscription and open engagements</span>
|
||||
<span class="text-xs text-slate-500">
|
||||
Updates active/unlocked engagements only. Completed, cancelled and locked history is preserved.
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">Reason for Scope Change</label>
|
||||
<textarea name="scope_change_reason" rows="3" required
|
||||
placeholder="Example: Existing GSTR-3B subscription mapped to IZI GST registration."
|
||||
class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800">
|
||||
This action does not change the Client, subscription ID, engagement IDs, due dates,
|
||||
assignment team, tasks, evidence or review history.
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-3">
|
||||
<a href="/services/subscriptions/{{ plan.id }}"
|
||||
class="rounded-xl border border-slate-300 px-4 py-2 text-sm text-slate-700">
|
||||
Cancel
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white">
|
||||
Save Scope Mapping
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
const type = document.getElementById('scope-type');
|
||||
const businessWrap = document.getElementById('business-wrap');
|
||||
const branchWrap = document.getElementById('branch-wrap');
|
||||
const registrationWrap = document.getElementById('registration-wrap');
|
||||
const business = document.getElementById('business-unit');
|
||||
const branch = document.getElementById('client-branch');
|
||||
const registration = document.getElementById('registration');
|
||||
|
||||
function refresh(){
|
||||
const value = type.value;
|
||||
businessWrap.classList.toggle('hidden', value === 'client');
|
||||
branchWrap.classList.toggle('hidden', !['client_branch','registration'].includes(value));
|
||||
registrationWrap.classList.toggle('hidden', value !== 'registration');
|
||||
business.required = value === 'business_unit';
|
||||
branch.required = value === 'client_branch';
|
||||
registration.required = value === 'registration';
|
||||
}
|
||||
|
||||
branch.addEventListener('change', function(){
|
||||
const option = branch.options[branch.selectedIndex];
|
||||
if (option && option.dataset.business) {
|
||||
business.value = option.dataset.business;
|
||||
}
|
||||
});
|
||||
|
||||
registration.addEventListener('change', function(){
|
||||
const option = registration.options[registration.selectedIndex];
|
||||
if (!option) return;
|
||||
if (option.dataset.business) business.value = option.dataset.business;
|
||||
if (option.dataset.branch) branch.value = option.dataset.branch;
|
||||
});
|
||||
|
||||
type.addEventListener('change', refresh);
|
||||
refresh();
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user