Add edit actions for business branch and registration

This commit is contained in:
A R R R Associates
2026-09-03 15:57:05 +05:30
parent 40047c0a7f
commit 5f51b4e02a
2 changed files with 343 additions and 9 deletions
+250 -3
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
from fastapi import APIRouter, Form, Request from fastapi import APIRouter, Form, Request
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from sqlalchemy import select from sqlalchemy import select
from urllib.parse import urlencode
from app.core.db.common import CommonSessionLocal from app.core.db.common import CommonSessionLocal
from app.core.security.csrf import get_or_create_csrf_token, validate_csrf from app.core.security.csrf import get_or_create_csrf_token, validate_csrf
@@ -43,6 +44,51 @@ def _load_client(db, tenant_id: int, client_id: int):
return db.execute(select(Client).where(Client.id == client_id, Client.tenant_id == tenant_id)).scalar_one_or_none() return db.execute(select(Client).where(Client.id == client_id, Client.tenant_id == tenant_id)).scalar_one_or_none()
def _structure_redirect(client_id: int, *, message: str | None = None, error: str | None = None, anchor: str | None = None):
params = {}
if message:
params["message"] = message
if error:
params["error"] = error
url = f"/clients/{client_id}/business-structure"
if params:
url += "?" + urlencode(params)
if anchor:
url += f"#{anchor}"
return RedirectResponse(url, 303)
def _owned_business(db, tenant_id: int, client_id: int, business_unit_id: int):
return db.execute(
select(ClientBusinessUnit).where(
ClientBusinessUnit.id == business_unit_id,
ClientBusinessUnit.tenant_id == tenant_id,
ClientBusinessUnit.client_id == client_id,
)
).scalar_one_or_none()
def _owned_branch(db, tenant_id: int, client_id: int, branch_id: int):
return db.execute(
select(ClientBranch).where(
ClientBranch.id == branch_id,
ClientBranch.tenant_id == tenant_id,
ClientBranch.client_id == client_id,
)
).scalar_one_or_none()
def _owned_registration(db, tenant_id: int, client_id: int, registration_id: int):
return db.execute(
select(ClientRegistration).where(
ClientRegistration.id == registration_id,
ClientRegistration.tenant_id == tenant_id,
ClientRegistration.client_id == client_id,
)
).scalar_one_or_none()
def _context(request, db, user, **extra): def _context(request, db, user, **extra):
data = { data = {
"request": request, "current_user": user, "request": request, "current_user": user,
@@ -81,9 +127,7 @@ def business_structure_page(request: Request, client_id: int):
registrations = [row[0] for row in registration_rows] registrations = [row[0] for row in registration_rows]
registration_type_codes = {row[0].id: row[1].code for row in registration_rows} registration_type_codes = {row[0].id: row[1].code for row in registration_rows}
registration_types = db.execute( registration_types = db.execute(
select(RegistrationType).where(RegistrationType.is_active.is_(True)).order_by( select(RegistrationType).order_by(RegistrationType.sort_order, RegistrationType.name)
RegistrationType.sort_order, RegistrationType.name
)
).scalars().all() ).scalars().all()
# Credential Vault stays the single source of truth. This page only surfaces # Credential Vault stays the single source of truth. This page only surfaces
@@ -233,6 +277,209 @@ def add_registration(request: Request, client_id: int, business_unit_id: str = F
db.close() db.close()
@router.post("/{client_id}/business-units/{business_unit_id}/edit")
def edit_business_unit(
request: Request,
client_id: int,
business_unit_id: int,
business_code: str = Form(...),
business_name: str = Form(...),
trade_name: str = Form(""),
nature_of_business: str = Form(""),
is_primary: str | None = Form(None),
csrf_token: str = Form(...),
):
validate_csrf(request, csrf_token)
db = CommonSessionLocal()
try:
user = get_current_user(request, db=db)
require_permission(db, user, "clients.edit")
tenant_id = _tenant_id(request, user)
client = _load_client(db, tenant_id, client_id)
row = _owned_business(db, tenant_id, client_id, business_unit_id) if client else None
if not client or not row:
return RedirectResponse("/clients", 303)
code = business_code.strip().upper()
name = business_name.strip()
if not code or not name:
return _structure_redirect(client_id, error="Business code and business unit name are required.", anchor="business-units")
duplicate = db.execute(
select(ClientBusinessUnit.id).where(
ClientBusinessUnit.tenant_id == tenant_id,
ClientBusinessUnit.client_id == client_id,
ClientBusinessUnit.business_code == code,
ClientBusinessUnit.id != row.id,
)
).scalar_one_or_none()
if duplicate:
return _structure_redirect(client_id, error=f"Business code {code} is already used for this client.", anchor="business-units")
if is_primary:
db.query(ClientBusinessUnit).filter(
ClientBusinessUnit.tenant_id == tenant_id,
ClientBusinessUnit.client_id == client_id,
).update({"is_primary": False}, synchronize_session=False)
row.business_code = code
row.business_name = name
row.trade_name = trade_name.strip() or None
row.nature_of_business = nature_of_business.strip() or None
row.is_primary = bool(is_primary)
row.updated_by_user_id = user.id
db.commit()
return _structure_redirect(client_id, message="Business Unit updated successfully.", anchor="business-units")
finally:
db.close()
@router.post("/{client_id}/branches/{client_branch_id}/edit")
def edit_client_branch(
request: Request,
client_id: int,
client_branch_id: int,
business_unit_id: int = Form(...),
branch_code: str = Form(...),
branch_name: str = Form(...),
branch_type: str = Form("branch"),
city: str = Form(""),
state: str = Form(""),
pincode: str = Form(""),
is_primary: str | None = Form(None),
csrf_token: str = Form(...),
):
validate_csrf(request, csrf_token)
db = CommonSessionLocal()
try:
user = get_current_user(request, db=db)
require_permission(db, user, "clients.edit")
tenant_id = _tenant_id(request, user)
client = _load_client(db, tenant_id, client_id)
row = _owned_branch(db, tenant_id, client_id, client_branch_id) if client else None
business = _owned_business(db, tenant_id, client_id, business_unit_id) if client else None
if not client or not row or not business:
return RedirectResponse("/clients", 303)
code = branch_code.strip().upper()
name = branch_name.strip()
if not code or not name:
return _structure_redirect(client_id, error="Branch code and branch name are required.", anchor="client-branches")
duplicate = db.execute(
select(ClientBranch.id).where(
ClientBranch.tenant_id == tenant_id,
ClientBranch.business_unit_id == business.id,
ClientBranch.branch_code == code,
ClientBranch.id != row.id,
)
).scalar_one_or_none()
if duplicate:
return _structure_redirect(client_id, error=f"Branch code {code} is already used under the selected Business Unit.", anchor="client-branches")
if is_primary:
db.query(ClientBranch).filter(
ClientBranch.tenant_id == tenant_id,
ClientBranch.business_unit_id == business.id,
).update({"is_primary": False}, synchronize_session=False)
row.business_unit_id = business.id
row.branch_code = code
row.branch_name = name
row.branch_type = branch_type.strip() or "branch"
row.city = city.strip() or None
row.state = state.strip() or None
row.pincode = pincode.strip() or None
row.is_primary = bool(is_primary)
row.updated_by_user_id = user.id
db.commit()
return _structure_redirect(client_id, message="Client Branch updated successfully.", anchor="client-branches")
finally:
db.close()
@router.post("/{client_id}/registrations/{registration_id}/edit")
def edit_registration(
request: Request,
client_id: int,
registration_id: int,
business_unit_id: str = Form(""),
client_branch_id: str = Form(""),
registration_type_id: int = Form(...),
registration_number: str = Form(...),
legal_name: str = Form(""),
trade_name: str = Form(""),
state: str = Form(""),
csrf_token: str = Form(...),
):
validate_csrf(request, csrf_token)
db = CommonSessionLocal()
try:
user = get_current_user(request, db=db)
require_permission(db, user, "clients.edit")
tenant_id = _tenant_id(request, user)
client = _load_client(db, tenant_id, client_id)
row = _owned_registration(db, tenant_id, client_id, registration_id) if client else None
if not client or not row:
return RedirectResponse("/clients", 303)
try:
bu_id = int(business_unit_id) if business_unit_id else None
br_id = int(client_branch_id) if client_branch_id else None
except (TypeError, ValueError):
return _structure_redirect(client_id, error="Invalid Business Unit or Client Branch selection.", anchor="registrations")
business = _owned_business(db, tenant_id, client_id, bu_id) if bu_id else None
if bu_id and not business:
return _structure_redirect(client_id, error="Selected Business Unit does not belong to this client.", anchor="registrations")
branch = _owned_branch(db, tenant_id, client_id, br_id) if br_id else None
if br_id and not branch:
return _structure_redirect(client_id, error="Selected Client Branch does not belong to this client.", anchor="registrations")
if branch:
bu_id = branch.business_unit_id
registration_type = db.get(RegistrationType, registration_type_id)
if not registration_type:
return _structure_redirect(client_id, error="Registration Type was not found.", anchor="registrations")
if not registration_type.is_active and registration_type.id != row.registration_type_id:
return _structure_redirect(client_id, error="An inactive Registration Type cannot be newly selected.", anchor="registrations")
number = registration_number.strip().upper()
if not number:
return _structure_redirect(client_id, error="Registration number is required.", anchor="registrations")
duplicate = db.execute(
select(ClientRegistration.id).where(
ClientRegistration.tenant_id == tenant_id,
ClientRegistration.registration_type_id == registration_type.id,
ClientRegistration.registration_number == number,
ClientRegistration.id != row.id,
)
).scalar_one_or_none()
if duplicate:
return _structure_redirect(
client_id,
error=f"{registration_type.code} registration number {number} already exists.",
anchor="registrations",
)
old_state = row.state
row.business_unit_id = bu_id
row.client_branch_id = br_id
row.registration_type_id = registration_type.id
row.registration_number = number
row.legal_name = legal_name.strip() or client.client_name
row.trade_name = trade_name.strip() or None
row.state = state.strip() or None
if not row.jurisdiction or row.jurisdiction == old_state:
row.jurisdiction = row.state
db.commit()
return _structure_redirect(client_id, message="Registration updated successfully.", anchor="registrations")
finally:
db.close()
@router.post("/{client_id}/business-structure/{entity}/{entity_id}/toggle") @router.post("/{client_id}/business-structure/{entity}/{entity_id}/toggle")
def toggle_scope_record(request: Request, client_id: int, entity: str, entity_id: int, csrf_token: str = Form(...)): def toggle_scope_record(request: Request, client_id: int, entity: str, entity_id: int, csrf_token: str = Form(...)):
validate_csrf(request, csrf_token) validate_csrf(request, csrf_token)
@@ -7,6 +7,13 @@
<a href="/clients/{{ client.id }}" class="rounded-xl border border-slate-300 px-4 py-2 text-sm">Back to Client</a> <a href="/clients/{{ client.id }}" class="rounded-xl border border-slate-300 px-4 py-2 text-sm">Back to Client</a>
</div> </div>
{% if request.query_params.get('message') %}
<div class="rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800">{{ request.query_params.get('message') }}</div>
{% endif %}
{% if request.query_params.get('error') %}
<div class="rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-800">{{ request.query_params.get('error') }}</div>
{% endif %}
{% if can_edit %} {% if can_edit %}
<div class="grid gap-5 xl:grid-cols-3"> <div class="grid gap-5 xl:grid-cols-3">
<form id="add-business" data-quick-action="business" method="post" action="/clients/{{ client.id }}/business-units" class="rounded-2xl bg-white p-5 shadow-soft space-y-3"> <form id="add-business" data-quick-action="business" method="post" action="/clients/{{ client.id }}/business-units" class="rounded-2xl bg-white p-5 shadow-soft space-y-3">
@@ -45,7 +52,7 @@
<select name="client_branch_id" class="w-full rounded-xl border px-3 py-2 text-sm"><option value="">No Client Branch</option>{% for row in branches if row.is_active %}<option value="{{ row.id }}" {% if request.query_params.get('client_branch_id') == row.id|string %}selected{% endif %}>{{ row.branch_name }}</option>{% endfor %}</select> <select name="client_branch_id" class="w-full rounded-xl border px-3 py-2 text-sm"><option value="">No Client Branch</option>{% for row in branches if row.is_active %}<option value="{{ row.id }}" {% if request.query_params.get('client_branch_id') == row.id|string %}selected{% endif %}>{{ row.branch_name }}</option>{% endfor %}</select>
<select name="registration_type_id" required class="w-full rounded-xl border px-3 py-2 text-sm"> <select name="registration_type_id" required class="w-full rounded-xl border px-3 py-2 text-sm">
<option value="">Select Registration Type</option> <option value="">Select Registration Type</option>
{% for row in registration_types %}<option value="{{ row.id }}">{{ row.name }} ({{ row.code }})</option>{% endfor %} {% for row in registration_types if row.is_active %}<option value="{{ row.id }}">{{ row.name }} ({{ row.code }})</option>{% endfor %}
</select> </select>
<input name="registration_number" required placeholder="Registration number" class="w-full rounded-xl border px-3 py-2 text-sm"> <input name="registration_number" required placeholder="Registration number" class="w-full rounded-xl border px-3 py-2 text-sm">
<input name="legal_name" placeholder="Legal name" class="w-full rounded-xl border px-3 py-2 text-sm"> <input name="legal_name" placeholder="Legal name" class="w-full rounded-xl border px-3 py-2 text-sm">
@@ -56,19 +63,96 @@
</div> </div>
{% endif %} {% endif %}
<section class="rounded-2xl bg-white shadow-soft overflow-hidden"> {% if can_edit and request.query_params.get('edit_business') %}
{% for edit_row in businesses if edit_row.id|string == request.query_params.get('edit_business') %}
<section id="edit-business" class="rounded-2xl border border-brand-200 bg-white p-5 shadow-soft">
<div class="mb-4 flex items-center justify-between gap-3">
<div><h3 class="font-semibold text-slate-900">Edit Business Unit</h3><p class="text-xs text-slate-500">Updates this existing Business Unit; linked records remain attached.</p></div>
<a href="/clients/{{ client.id }}/business-structure#business-units" class="rounded-lg border px-3 py-1.5 text-xs">Cancel</a>
</div>
<form method="post" action="/clients/{{ client.id }}/business-units/{{ edit_row.id }}/edit" class="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input name="business_code" value="{{ edit_row.business_code }}" required placeholder="Business code" class="rounded-xl border px-3 py-2 text-sm">
<input name="business_name" value="{{ edit_row.business_name }}" required placeholder="Business unit name" class="rounded-xl border px-3 py-2 text-sm">
<input name="trade_name" value="{{ edit_row.trade_name or '' }}" placeholder="Trade name" class="rounded-xl border px-3 py-2 text-sm">
<input name="nature_of_business" value="{{ edit_row.nature_of_business or '' }}" placeholder="Nature of business" class="rounded-xl border px-3 py-2 text-sm">
<label class="flex items-center gap-2 text-sm"><input type="checkbox" name="is_primary" {% if edit_row.is_primary %}checked{% endif %}> Primary Business Unit</label>
<div class="md:col-span-2 xl:col-span-3"><button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white">Save Business Changes</button></div>
</form>
</section>
{% endfor %}
{% endif %}
{% if can_edit and request.query_params.get('edit_branch') %}
{% for edit_row in branches if edit_row.id|string == request.query_params.get('edit_branch') %}
<section id="edit-branch" class="rounded-2xl border border-brand-200 bg-white p-5 shadow-soft">
<div class="mb-4 flex items-center justify-between gap-3">
<div><h3 class="font-semibold text-slate-900">Edit Client Branch</h3><p class="text-xs text-slate-500">Updates this existing branch without changing its record ID.</p></div>
<a href="/clients/{{ client.id }}/business-structure#client-branches" class="rounded-lg border px-3 py-1.5 text-xs">Cancel</a>
</div>
<form method="post" action="/clients/{{ client.id }}/branches/{{ edit_row.id }}/edit" class="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<select name="business_unit_id" required class="rounded-xl border px-3 py-2 text-sm">
{% for business in businesses %}<option value="{{ business.id }}" {% if business.id == edit_row.business_unit_id %}selected{% endif %}>{{ business.business_name }}{% if not business.is_active %} (Inactive){% endif %}</option>{% endfor %}
</select>
<input name="branch_code" value="{{ edit_row.branch_code }}" required placeholder="Branch code" class="rounded-xl border px-3 py-2 text-sm">
<input name="branch_name" value="{{ edit_row.branch_name }}" required placeholder="Client Branch name" class="rounded-xl border px-3 py-2 text-sm">
<select name="branch_type" class="rounded-xl border px-3 py-2 text-sm">
{% for code, label in [('head_office','Head Office'),('branch','Branch'),('warehouse','Warehouse'),('unit','Unit')] %}<option value="{{ code }}" {% if edit_row.branch_type == code %}selected{% endif %}>{{ label }}</option>{% endfor %}
</select>
<input name="city" value="{{ edit_row.city or '' }}" placeholder="City" class="rounded-xl border px-3 py-2 text-sm">
<input name="state" value="{{ edit_row.state or '' }}" placeholder="State" class="rounded-xl border px-3 py-2 text-sm">
<input name="pincode" value="{{ edit_row.pincode or '' }}" placeholder="Pincode" class="rounded-xl border px-3 py-2 text-sm">
<label class="flex items-center gap-2 text-sm"><input type="checkbox" name="is_primary" {% if edit_row.is_primary %}checked{% endif %}> Primary Branch</label>
<div class="md:col-span-2 xl:col-span-4"><button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white">Save Branch Changes</button></div>
</form>
</section>
{% endfor %}
{% endif %}
{% if can_edit and request.query_params.get('edit_registration') %}
{% for edit_row in registrations if edit_row.id|string == request.query_params.get('edit_registration') %}
<section id="edit-registration" class="rounded-2xl border border-brand-200 bg-white p-5 shadow-soft">
<div class="mb-4 flex items-center justify-between gap-3">
<div><h3 class="font-semibold text-slate-900">Edit Registration</h3><p class="text-xs text-slate-500">The existing registration ID and linked credentials remain unchanged.</p></div>
<a href="/clients/{{ client.id }}/business-structure#registrations" class="rounded-lg border px-3 py-1.5 text-xs">Cancel</a>
</div>
<form method="post" action="/clients/{{ client.id }}/registrations/{{ edit_row.id }}/edit" class="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<select name="business_unit_id" class="rounded-xl border px-3 py-2 text-sm">
<option value="">Client level / derive from Branch</option>
{% for business in businesses %}<option value="{{ business.id }}" {% if business.id == edit_row.business_unit_id %}selected{% endif %}>{{ business.business_name }}{% if not business.is_active %} (Inactive){% endif %}</option>{% endfor %}
</select>
<select name="client_branch_id" class="rounded-xl border px-3 py-2 text-sm">
<option value="">No Client Branch</option>
{% for branch in branches %}<option value="{{ branch.id }}" {% if branch.id == edit_row.client_branch_id %}selected{% endif %}>{{ branch.branch_name }}{% if not branch.is_active %} (Inactive){% endif %}</option>{% endfor %}
</select>
<select name="registration_type_id" required class="rounded-xl border px-3 py-2 text-sm">
{% for reg_type in registration_types if reg_type.is_active or reg_type.id == edit_row.registration_type_id %}<option value="{{ reg_type.id }}" {% if reg_type.id == edit_row.registration_type_id %}selected{% endif %}>{{ reg_type.name }} ({{ reg_type.code }}){% if not reg_type.is_active %} — Inactive{% endif %}</option>{% endfor %}
</select>
<input name="registration_number" value="{{ edit_row.registration_number }}" required placeholder="Registration number" class="rounded-xl border px-3 py-2 text-sm">
<input name="legal_name" value="{{ edit_row.legal_name or '' }}" placeholder="Legal name" class="rounded-xl border px-3 py-2 text-sm">
<input name="trade_name" value="{{ edit_row.trade_name or '' }}" placeholder="Trade / deductor unit name" class="rounded-xl border px-3 py-2 text-sm">
<input name="state" value="{{ edit_row.state or '' }}" placeholder="State" class="rounded-xl border px-3 py-2 text-sm">
<div><button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white">Save Registration Changes</button></div>
</form>
</section>
{% endfor %}
{% endif %}
<section id="business-units" class="rounded-2xl bg-white shadow-soft overflow-hidden">
<div class="border-b p-4 font-semibold">Business Units</div> <div class="border-b p-4 font-semibold">Business Units</div>
<table class="min-w-full text-sm"><thead class="bg-slate-50"><tr><th class="p-3 text-left">Code</th><th class="p-3 text-left">Business Unit</th><th class="p-3 text-left">Trade Name</th><th class="p-3 text-left">Nature</th><th class="p-3">Status</th><th></th></tr></thead> <table class="min-w-full text-sm"><thead class="bg-slate-50"><tr><th class="p-3 text-left">Code</th><th class="p-3 text-left">Business Unit</th><th class="p-3 text-left">Trade Name</th><th class="p-3 text-left">Nature</th><th class="p-3">Status</th><th></th></tr></thead>
<tbody>{% for row in businesses %}<tr class="border-t"><td class="p-3">{{ row.business_code }}</td><td class="p-3 font-medium">{{ row.business_name }}{% if row.is_primary %} <span class="text-xs text-brand-700">Primary</span>{% endif %}</td><td class="p-3">{{ row.trade_name or '-' }}</td><td class="p-3">{{ row.nature_of_business or '-' }}</td><td class="p-3 text-center">{{ 'Active' if row.is_active else 'Inactive' }}</td><td class="p-3">{% if can_edit %}<form method="post" action="/clients/{{ client.id }}/business-structure/business/{{ row.id }}/toggle"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="text-xs text-brand-700">{{ 'Deactivate' if row.is_active else 'Activate' }}</button></form>{% endif %}</td></tr>{% else %}<tr><td colspan="6" class="p-6 text-center text-slate-500">No Business Units added.</td></tr>{% endfor %}</tbody></table> <tbody>{% for row in businesses %}<tr class="border-t"><td class="p-3">{{ row.business_code }}</td><td class="p-3 font-medium">{{ row.business_name }}{% if row.is_primary %} <span class="text-xs text-brand-700">Primary</span>{% endif %}</td><td class="p-3">{{ row.trade_name or '-' }}</td><td class="p-3">{{ row.nature_of_business or '-' }}</td><td class="p-3 text-center">{{ 'Active' if row.is_active else 'Inactive' }}</td><td class="p-3">{% if can_edit %}<div class="flex items-center gap-3"><a href="/clients/{{ client.id }}/business-structure?edit_business={{ row.id }}#edit-business" class="text-xs font-semibold text-brand-700">Edit</a><form method="post" action="/clients/{{ client.id }}/business-structure/business/{{ row.id }}/toggle"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="text-xs text-brand-700">{{ 'Deactivate' if row.is_active else 'Activate' }}</button></form></div>{% endif %}</td></tr>{% else %}<tr><td colspan="6" class="p-6 text-center text-slate-500">No Business Units added.</td></tr>{% endfor %}</tbody></table>
</section> </section>
<section class="rounded-2xl bg-white shadow-soft overflow-hidden"> <section id="client-branches" class="rounded-2xl bg-white shadow-soft overflow-hidden">
<div class="border-b p-4 font-semibold">Client Branches</div> <div class="border-b p-4 font-semibold">Client Branches</div>
<table class="min-w-full text-sm"><thead class="bg-slate-50"><tr><th class="p-3 text-left">Code</th><th class="p-3 text-left">Client Branch</th><th class="p-3 text-left">Type</th><th class="p-3 text-left">Location</th><th class="p-3">Status</th><th></th></tr></thead> <table class="min-w-full text-sm"><thead class="bg-slate-50"><tr><th class="p-3 text-left">Code</th><th class="p-3 text-left">Client Branch</th><th class="p-3 text-left">Type</th><th class="p-3 text-left">Location</th><th class="p-3">Status</th><th></th></tr></thead>
<tbody>{% for row in branches %}<tr class="border-t"><td class="p-3">{{ row.branch_code }}</td><td class="p-3 font-medium">{{ row.branch_name }}{% if row.is_primary %} <span class="text-xs text-brand-700">Primary</span>{% endif %}</td><td class="p-3">{{ row.branch_type|replace('_',' ')|title }}</td><td class="p-3">{{ row.city or '' }}{% if row.city and row.state %}, {% endif %}{{ row.state or '-' }}</td><td class="p-3 text-center">{{ 'Active' if row.is_active else 'Inactive' }}</td><td class="p-3">{% if can_edit %}<form method="post" action="/clients/{{ client.id }}/business-structure/branch/{{ row.id }}/toggle"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="text-xs text-brand-700">{{ 'Deactivate' if row.is_active else 'Activate' }}</button></form>{% endif %}</td></tr>{% else %}<tr><td colspan="6" class="p-6 text-center text-slate-500">No Client Branches added.</td></tr>{% endfor %}</tbody></table> <tbody>{% for row in branches %}<tr class="border-t"><td class="p-3">{{ row.branch_code }}</td><td class="p-3 font-medium">{{ row.branch_name }}{% if row.is_primary %} <span class="text-xs text-brand-700">Primary</span>{% endif %}</td><td class="p-3">{{ row.branch_type|replace('_',' ')|title }}</td><td class="p-3">{{ row.city or '' }}{% if row.city and row.state %}, {% endif %}{{ row.state or '-' }}</td><td class="p-3 text-center">{{ 'Active' if row.is_active else 'Inactive' }}</td><td class="p-3">{% if can_edit %}<div class="flex items-center gap-3"><a href="/clients/{{ client.id }}/business-structure?edit_branch={{ row.id }}#edit-branch" class="text-xs font-semibold text-brand-700">Edit</a><form method="post" action="/clients/{{ client.id }}/business-structure/branch/{{ row.id }}/toggle"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="text-xs text-brand-700">{{ 'Deactivate' if row.is_active else 'Activate' }}</button></form></div>{% endif %}</td></tr>{% else %}<tr><td colspan="6" class="p-6 text-center text-slate-500">No Client Branches added.</td></tr>{% endfor %}</tbody></table>
</section> </section>
<section class="rounded-2xl bg-white shadow-soft overflow-hidden"> <section id="registrations" class="rounded-2xl bg-white shadow-soft overflow-hidden">
<div class="flex flex-wrap items-center justify-between gap-2 border-b p-4"> <div class="flex flex-wrap items-center justify-between gap-2 border-b p-4">
<div> <div>
<div class="font-semibold">Registrations</div> <div class="font-semibold">Registrations</div>
@@ -129,6 +213,9 @@
</td> </td>
<td class="p-3 min-w-[170px]"> <td class="p-3 min-w-[170px]">
<div class="flex flex-wrap items-center gap-x-3 gap-y-2"> <div class="flex flex-wrap items-center gap-x-3 gap-y-2">
{% if can_edit %}
<a href="/clients/{{ client.id }}/business-structure?edit_registration={{ row.id }}#edit-registration" class="text-xs font-semibold text-brand-700">Edit</a>
{% endif %}
{% if can_manage_credentials %} {% if can_manage_credentials %}
<a href="/credential-vault/new?client_id={{ client.id }}&registration_id={{ row.id }}" class="text-xs font-semibold text-violet-700">{{ '+ Add Another Credential' if linked_credentials else '+ Add Credential' }}</a> <a href="/credential-vault/new?client_id={{ client.id }}&registration_id={{ row.id }}" class="text-xs font-semibold text-violet-700">{{ '+ Add Another Credential' if linked_credentials else '+ Add Credential' }}</a>
{% endif %} {% endif %}