Hide inactive merged services from service catalogue
This commit is contained in:
@@ -44,6 +44,8 @@ def build_merge_preview(db: Session, *, source_id: int, target_id: int) -> Merge
|
||||
target = db.get(ServiceCatalogue, target_id)
|
||||
if not source or not target:
|
||||
raise ValueError("The selected source or target service no longer exists.")
|
||||
if not source.is_active or not target.is_active:
|
||||
raise ValueError("Only active services can be selected for a merge.")
|
||||
|
||||
counts = {
|
||||
"firm_selections": _count(db, FirmServiceSelection, FirmServiceSelection.service_catalogue_id == source_id),
|
||||
|
||||
@@ -65,7 +65,9 @@ def get_category(db: Session, category_id: int) -> ServiceCategory | None:
|
||||
|
||||
|
||||
def list_catalogue_payload(db: Session, *, q: str = "", category_id: int | None = None, recurrence_type: str = "", engagement_type: str = "", page: int = 1, per_page: int = 20):
|
||||
query = select(ServiceCatalogue).options(
|
||||
query = select(ServiceCatalogue).where(
|
||||
ServiceCatalogue.is_active.is_(True)
|
||||
).options(
|
||||
selectinload(ServiceCatalogue.service_category),
|
||||
selectinload(ServiceCatalogue.default_task_templates),
|
||||
selectinload(ServiceCatalogue.due_date_rules),
|
||||
@@ -115,6 +117,7 @@ def list_firm_services_payload(db: Session, *, tenant_id: int, q: str = ""):
|
||||
.where(
|
||||
FirmServiceSelection.tenant_id == tenant_id,
|
||||
FirmServiceSelection.is_enabled.is_(True),
|
||||
ServiceCatalogue.is_active.is_(True),
|
||||
)
|
||||
)
|
||||
if q.strip():
|
||||
@@ -143,7 +146,10 @@ def list_disabled_catalogues(db: Session, *, tenant_id: int, q: str = ""):
|
||||
)
|
||||
)
|
||||
|
||||
query = select(ServiceCatalogue).where(~ServiceCatalogue.id.in_(enabled_subq)).options(
|
||||
query = select(ServiceCatalogue).where(
|
||||
ServiceCatalogue.is_active.is_(True),
|
||||
~ServiceCatalogue.id.in_(enabled_subq),
|
||||
).options(
|
||||
selectinload(ServiceCatalogue.service_category),
|
||||
selectinload(ServiceCatalogue.default_task_templates),
|
||||
selectinload(ServiceCatalogue.due_date_rules),
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<a href="/services/templates" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Firm Task Templates</a>
|
||||
{% if can_create %}
|
||||
<a href="/services/defaults" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">System Default Tasks</a>
|
||||
<a href="/services/catalogue/export" class="rounded-xl border border-emerald-300 bg-emerald-50 px-4 py-2 text-sm font-medium text-emerald-800 hover:bg-emerald-100">Export Excel</a>
|
||||
<a href="/services/catalogue/merge" class="rounded-xl border border-amber-300 px-4 py-2 text-sm font-medium text-amber-800 hover:bg-amber-50">Merge Services</a>
|
||||
<a href="/services/catalogue/new" class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white hover:bg-brand-700">Add Catalogue Service</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -21,6 +21,7 @@ from app.modules.services.bulk_imports import (
|
||||
import_system_default_tasks,
|
||||
import_due_date_extensions,
|
||||
)
|
||||
from app.modules.services.catalogue_export import build_service_catalogue_export
|
||||
from app.modules.services.due_dates import (
|
||||
DUE_PERIOD_TYPES,
|
||||
DUE_YEAR_BASIS_CHOICES,
|
||||
@@ -333,6 +334,28 @@ def catalogue_list(request: Request, q: str = '', category_id: int | None = None
|
||||
db.close()
|
||||
|
||||
|
||||
@router.get('/catalogue/export')
|
||||
def catalogue_export(request: Request):
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user = get_current_user(request, db=db)
|
||||
if not user:
|
||||
return RedirectResponse(url='/login', status_code=303)
|
||||
if not _is_system_admin(db, user):
|
||||
return _redirect_denied()
|
||||
require_permission(db, user, 'services.view')
|
||||
|
||||
workbook_bytes = build_service_catalogue_export(db)
|
||||
filename = f"service_catalogue_export_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}.xlsx"
|
||||
return StreamingResponse(
|
||||
iter([workbook_bytes]),
|
||||
media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
headers={'Content-Disposition': f'attachment; filename="{filename}"'},
|
||||
)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.get('/catalogue/merge')
|
||||
def catalogue_merge_page(request: Request, source_id: int | None = None, target_id: int | None = None):
|
||||
db = CommonSessionLocal()
|
||||
@@ -345,7 +368,9 @@ def catalogue_merge_page(request: Request, source_id: int | None = None, target_
|
||||
require_permission(db, user, 'services.edit')
|
||||
|
||||
services = db.execute(
|
||||
select(ServiceCatalogue).order_by(ServiceCatalogue.is_active.desc(), ServiceCatalogue.service_code.asc())
|
||||
select(ServiceCatalogue)
|
||||
.where(ServiceCatalogue.is_active.is_(True))
|
||||
.order_by(ServiceCatalogue.service_code.asc())
|
||||
).scalars().all()
|
||||
preview = None
|
||||
error = None
|
||||
@@ -495,7 +520,7 @@ def catalogue_detail(request: Request, catalogue_id: int):
|
||||
if not _can_view_services(db, user):
|
||||
return _redirect_denied()
|
||||
row = get_catalogue(db, catalogue_id)
|
||||
if not row:
|
||||
if not row or not row.is_active:
|
||||
return RedirectResponse(url='/services/catalogue', status_code=303)
|
||||
tenant_id = _active_tenant_id(request, user)
|
||||
can_edit = _is_system_admin(db, user) and _has_perm(db, user, 'services.edit')
|
||||
@@ -764,7 +789,7 @@ def catalogue_edit_page(request: Request, catalogue_id: int):
|
||||
return _redirect_denied()
|
||||
require_permission(db, user, 'services.edit')
|
||||
row = get_catalogue(db, catalogue_id)
|
||||
if not row:
|
||||
if not row or not row.is_active:
|
||||
return RedirectResponse(url='/services/catalogue', status_code=303)
|
||||
return _render(request, 'modules/services/templates/services/catalogue_form.html', db, user, title='Edit Service Catalogue', mode='edit', catalogue=row, categories=list_categories(db))
|
||||
except Exception:
|
||||
@@ -785,7 +810,7 @@ def catalogue_edit_submit(request: Request, catalogue_id: int, service_name: str
|
||||
return _redirect_denied()
|
||||
require_permission(db, user, 'services.edit')
|
||||
row = get_catalogue(db, catalogue_id)
|
||||
if not row:
|
||||
if not row or not row.is_active:
|
||||
return RedirectResponse(url='/services/catalogue', status_code=303)
|
||||
selected_category = get_category(db, int(category_id)) if str(category_id).strip() else None
|
||||
row.service_name = service_name.strip()
|
||||
@@ -823,8 +848,8 @@ def toggle_firm_service(request: Request, catalogue_id: int, default_branch_id:
|
||||
return _redirect_denied()
|
||||
tenant_id = _active_tenant_id(request, user)
|
||||
row = get_catalogue(db, catalogue_id)
|
||||
if not row:
|
||||
return RedirectResponse(url='/services', status_code=303)
|
||||
if not row or not row.is_active:
|
||||
return RedirectResponse(url='/services/catalogue', status_code=303)
|
||||
selection = get_firm_selection(db, tenant_id=tenant_id, catalogue_id=catalogue_id)
|
||||
if not selection:
|
||||
selection = FirmServiceSelection(
|
||||
|
||||
Reference in New Issue
Block a user