Add controlled client subscription team reassignment

This commit is contained in:
A R R R Associates
2026-08-05 15:09:32 +05:30
parent 956560850d
commit 6a6ca2a4a7
3 changed files with 577 additions and 35 deletions
@@ -20,6 +20,12 @@
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>
{% 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
@@ -0,0 +1,138 @@
{% 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">Edit Client Service Subscription</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 hover:bg-slate-50">
Back
</a>
</div>
{% if saved %}
<div class="rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800">
Subscription defaults saved. {{ updated_engagements }} open engagement(s) and {{ updated_tasks }} unfinished Staff task(s) were updated.
</div>
{% endif %}
{% if error %}
<div class="rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-800">
The subscription could not be saved. Please verify the selected team, dates, status and propagation option.
</div>
{% endif %}
<form method="post" action="/services/subscriptions/{{ plan.id }}/edit" class="space-y-6">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<section class="rounded-2xl bg-white p-5 shadow-soft">
<h3 class="text-base font-semibold text-slate-900">Default Assignment Team</h3>
<p class="mt-1 text-sm text-slate-500">These defaults will be used for newly generated engagements.</p>
<div class="mt-5 grid gap-5 md:grid-cols-2">
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Engagement Partner</label>
<select name="default_partner_user_id" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
<option value="">No default Partner</option>
{% for row in partners %}<option value="{{ row.id }}" {% if plan.default_partner_user_id == row.id %}selected{% endif %}>{{ row.full_name or row.email }}</option>{% endfor %}
</select>
</div>
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Performing Partner</label>
<select name="default_performing_partner_user_id" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
<option value="">Same as Engagement Partner</option>
{% for row in partners %}<option value="{{ row.id }}" {% if plan.default_performing_partner_user_id == row.id %}selected{% endif %}>{{ row.full_name or row.email }}</option>{% endfor %}
</select>
</div>
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Manager</label>
<select name="default_manager_user_id" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
<option value="">No default Manager</option>
{% for row in managers %}<option value="{{ row.id }}" {% if plan.default_manager_user_id == row.id %}selected{% endif %}>{{ row.full_name or row.email }}</option>{% endfor %}
</select>
</div>
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Staff</label>
<select name="default_staff_user_id" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
<option value="">No default Staff</option>
{% for row in staff_users %}<option value="{{ row.id }}" {% if plan.default_staff_user_id == row.id %}selected{% endif %}>{{ row.full_name or row.email }}</option>{% endfor %}
</select>
</div>
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Review Partner</label>
<select name="default_review_partner_user_id" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
<option value="">Not required / no default</option>
{% for row in review_partners %}<option value="{{ row.id }}" {% if plan.default_review_partner_user_id == row.id %}selected{% endif %}>{{ row.full_name or row.email }}</option>{% endfor %}
</select>
</div>
</div>
</section>
<section class="rounded-2xl bg-white p-5 shadow-soft">
<h3 class="text-base font-semibold text-slate-900">Subscription Settings</h3>
<div class="mt-5 grid gap-5 md:grid-cols-2">
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Effective From</label>
<input type="date" name="effective_from" value="{{ plan.effective_from or '' }}" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
</div>
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Effective To</label>
<input type="date" name="effective_to" value="{{ plan.effective_to or '' }}" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
</div>
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Status</label>
<select name="status" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
{% for value, label in subscription_statuses %}<option value="{{ value }}" {% if plan.status == value %}selected{% endif %}>{{ label }}</option>{% endfor %}
</select>
</div>
<label class="mt-7 inline-flex items-center gap-2 text-sm text-slate-700">
<input type="checkbox" name="auto_generate_periods" value="1" {% if plan.auto_generate_periods %}checked{% endif %} class="rounded border-slate-300">
Automatically generate recurring periods when the scheduler is enabled
</label>
<div class="md:col-span-2">
<label class="mb-1 block text-sm font-medium text-slate-700">Remarks</label>
<textarea name="remarks" rows="3" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">{{ plan.remarks or '' }}</textarea>
</div>
</div>
</section>
<section class="rounded-2xl border border-amber-200 bg-amber-50 p-5">
<h3 class="text-base font-semibold text-slate-900">Apply Team Change</h3>
<p class="mt-1 text-sm text-slate-600">Completed and locked engagements, completed tasks, evidence and review history are never changed.</p>
<div class="mt-4 space-y-3">
<label class="flex items-start gap-3 rounded-xl border border-amber-200 bg-white p-4">
<input type="radio" name="propagation_mode" value="future_only" checked class="mt-1">
<span><strong class="block text-sm text-slate-900">Future engagements only</strong><span class="text-sm text-slate-500">Save new defaults without changing any existing engagement.</span></span>
</label>
<label class="flex items-start gap-3 rounded-xl border border-amber-200 bg-white p-4">
<input type="radio" name="propagation_mode" value="open_engagements" class="mt-1">
<span><strong class="block text-sm text-slate-900">Future engagements and currently open engagements</strong><span class="text-sm text-slate-500">Update unlocked, non-completed engagement assignments and unfinished Staff tasks.</span></span>
</label>
<div class="grid gap-4 md:grid-cols-2">
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Open engagements effective from</label>
<input type="date" name="reassignment_effective_from" class="w-full rounded-xl border border-amber-300 bg-white px-3 py-2 text-sm">
<p class="mt-1 text-xs text-slate-500">Leave blank to update all open engagements under this subscription.</p>
</div>
<div>
<label class="mb-1 block text-sm font-medium text-slate-700">Reason for reassignment</label>
<input type="text" name="reassignment_reason" maxlength="500" placeholder="Optional operational reason" class="w-full rounded-xl border border-amber-300 bg-white px-3 py-2 text-sm">
</div>
</div>
</div>
</section>
<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 font-medium text-slate-700 hover:bg-slate-50">Cancel</a>
<button type="submit" class="rounded-xl bg-brand-600 px-5 py-2 text-sm font-medium text-white hover:bg-brand-700">Save Subscription</button>
</div>
</form>
</div>
{% endblock %}