344 lines
14 KiB
Python
344 lines
14 KiB
Python
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Form, Request
|
|
from fastapi.responses import RedirectResponse
|
|
|
|
from app.core.db.common import CommonSessionLocal
|
|
from app.core.security.csrf import get_or_create_csrf_token, validate_csrf
|
|
from app.core.security.session_auth import get_current_user
|
|
from app.core.templating import templates
|
|
from app.modules.core.rbac.deps import get_user_permissions, get_user_roles
|
|
from app.modules.core.rbac.permission_guard import require_permission
|
|
from app.modules.marketplace.services import (
|
|
LEAD_PRIORITIES,
|
|
LEAD_SOURCES,
|
|
LEAD_STATUSES,
|
|
SERVICE_CATEGORIES,
|
|
assign_marketplace_lead,
|
|
convert_lead_to_client,
|
|
create_marketplace_lead,
|
|
get_marketplace_lead,
|
|
get_marketplace_overview_counts,
|
|
is_marketplace_domain_request,
|
|
list_marketplace_leads,
|
|
list_public_marketplace_audit_firms,
|
|
list_public_marketplace_consultants,
|
|
list_reference_audit_firms,
|
|
list_reference_branches,
|
|
list_reference_partners,
|
|
update_lead_status,
|
|
)
|
|
|
|
router = APIRouter(prefix="/marketplace", tags=["marketplace-ui"])
|
|
public_router = APIRouter(tags=["marketplace-public-ui"])
|
|
|
|
|
|
|
|
|
|
def _public_marketplace_ctx(request: Request, db, **ctx):
|
|
base = {
|
|
"request": request,
|
|
"current_user": None,
|
|
"current_user_roles": [],
|
|
"current_user_permissions": [],
|
|
"csrf_token": get_or_create_csrf_token(request),
|
|
"service_categories": SERVICE_CATEGORIES,
|
|
"lead_priorities": LEAD_PRIORITIES,
|
|
"lead_sources": LEAD_SOURCES,
|
|
"marketplace_counts": get_marketplace_overview_counts(db),
|
|
"public_audit_firms": list_public_marketplace_audit_firms(db, limit=8),
|
|
"public_consultants": list_public_marketplace_consultants(db, limit=8),
|
|
}
|
|
base.update(ctx)
|
|
return base
|
|
|
|
|
|
def _render_public_marketplace(request: Request, template: str, db, **ctx):
|
|
return templates.TemplateResponse(template, _public_marketplace_ctx(request, db, **ctx))
|
|
|
|
|
|
@public_router.get("/")
|
|
def marketplace_domain_home(request: Request):
|
|
"""Marketplace domain landing page.
|
|
|
|
Only marketplace-mapped domains use this as the public home page. Normal localhost,
|
|
tenant domains and consultant domains continue to the normal login flow.
|
|
"""
|
|
if not is_marketplace_domain_request(request):
|
|
return RedirectResponse(url="/login", status_code=303)
|
|
db = CommonSessionLocal()
|
|
try:
|
|
return _render_public_marketplace(
|
|
request,
|
|
"modules/marketplace/templates/marketplace/public_marketplace_home.html",
|
|
db,
|
|
title="FilingABC Marketplace",
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@public_router.get("/audit-firms")
|
|
def marketplace_public_audit_firms(request: Request):
|
|
if not is_marketplace_domain_request(request):
|
|
return RedirectResponse(url="/login", status_code=303)
|
|
db = CommonSessionLocal()
|
|
try:
|
|
return _render_public_marketplace(
|
|
request,
|
|
"modules/marketplace/templates/marketplace/public_audit_firms.html",
|
|
db,
|
|
title="Audit Firms",
|
|
public_audit_firms=list_public_marketplace_audit_firms(db, limit=50),
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@public_router.get("/consultants")
|
|
def marketplace_public_consultants(request: Request):
|
|
if not is_marketplace_domain_request(request):
|
|
return RedirectResponse(url="/login", status_code=303)
|
|
db = CommonSessionLocal()
|
|
try:
|
|
return _render_public_marketplace(
|
|
request,
|
|
"modules/marketplace/templates/marketplace/public_consultants.html",
|
|
db,
|
|
title="Consultants",
|
|
public_consultants=list_public_marketplace_consultants(db, limit=50),
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@public_router.get("/request-service")
|
|
def marketplace_public_request_service(request: Request):
|
|
if not is_marketplace_domain_request(request):
|
|
return RedirectResponse(url="/marketplace/public-lead", status_code=303)
|
|
db = CommonSessionLocal()
|
|
try:
|
|
return _render_public_marketplace(
|
|
request,
|
|
"modules/marketplace/templates/marketplace/public_marketplace_lead_form.html",
|
|
db,
|
|
title="Request a Service",
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@public_router.post("/request-service")
|
|
def marketplace_public_request_service_submit(request: Request, csrf_token: str = Form(...), lead_name: str = Form(...), business_name: str = Form(""), email: str = Form(""), mobile: str = Form(""), city: str = Form(""), state: str = Form(""), service_category: str = Form(""), service_requested: str = Form(...), message: str = Form("")):
|
|
if not is_marketplace_domain_request(request):
|
|
return RedirectResponse(url="/marketplace/public-lead", status_code=303)
|
|
db = CommonSessionLocal()
|
|
try:
|
|
validate_csrf(request, csrf_token)
|
|
lead = create_marketplace_lead(
|
|
db,
|
|
lead_name=lead_name,
|
|
business_name=business_name,
|
|
email=email,
|
|
mobile=mobile,
|
|
city=city,
|
|
state=state,
|
|
service_category=service_category,
|
|
service_requested=service_requested,
|
|
message=message,
|
|
source="public_website",
|
|
priority="NORMAL",
|
|
)
|
|
return _render_public_marketplace(
|
|
request,
|
|
"modules/marketplace/templates/marketplace/public_marketplace_thank_you.html",
|
|
db,
|
|
title="Thank You",
|
|
lead=lead,
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def _redirect_denied():
|
|
return RedirectResponse(url="/system-settings", status_code=303)
|
|
|
|
|
|
def _has_perm(db, user, code: str) -> bool:
|
|
try:
|
|
require_permission(db, user, code)
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def _require_user(request: Request, db, permission_code: str):
|
|
user = get_current_user(request, db=db)
|
|
if not user:
|
|
return None, RedirectResponse(url="/login", status_code=303)
|
|
try:
|
|
require_permission(db, user, permission_code)
|
|
except Exception:
|
|
# Assigned lead users are allowed if they have assigned-lead permission.
|
|
if permission_code == "marketplace_leads.view" and _has_perm(db, user, "marketplace_leads.view_assigned"):
|
|
return user, None
|
|
return user, _redirect_denied()
|
|
return user, None
|
|
|
|
|
|
def _base_ctx(request: Request, db, user=None, **ctx):
|
|
base = {
|
|
"request": request,
|
|
"current_user": user,
|
|
"current_user_roles": get_user_roles(db, user.id) if user else [],
|
|
"current_user_permissions": get_user_permissions(db, user.id) if user else [],
|
|
"csrf_token": get_or_create_csrf_token(request),
|
|
"lead_statuses": LEAD_STATUSES,
|
|
"lead_priorities": LEAD_PRIORITIES,
|
|
"lead_sources": LEAD_SOURCES,
|
|
"service_categories": SERVICE_CATEGORIES,
|
|
}
|
|
base.update(ctx)
|
|
return base
|
|
|
|
|
|
def _render(request: Request, template: str, db, user=None, **ctx):
|
|
return templates.TemplateResponse(template, _base_ctx(request, db, user, **ctx))
|
|
|
|
|
|
@router.get("")
|
|
def dashboard(request: Request):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
user, response = _require_user(request, db, "marketplace_leads.view")
|
|
if response:
|
|
return response
|
|
roles = get_user_roles(db, user.id)
|
|
leads = list_marketplace_leads(db, user=user, role_names=roles)
|
|
return _render(request, "modules/marketplace/templates/marketplace/dashboard.html", db, user, title="Marketplace Leads", leads=leads[:8], total=len(leads), can_create=_has_perm(db, user, "marketplace_leads.create"), can_assign=_has_perm(db, user, "marketplace_leads.assign"))
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.get("/leads")
|
|
def leads_list(request: Request, q: str = "", status: str = ""):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
user, response = _require_user(request, db, "marketplace_leads.view")
|
|
if response:
|
|
return response
|
|
roles = get_user_roles(db, user.id)
|
|
return _render(request, "modules/marketplace/templates/marketplace/leads_list.html", db, user, title="Marketplace Leads", rows=list_marketplace_leads(db, q=q, status=status, user=user, role_names=roles), q=q, selected_status=status, can_create=_has_perm(db, user, "marketplace_leads.create"), can_assign=_has_perm(db, user, "marketplace_leads.assign"))
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.get("/leads/new")
|
|
def lead_new(request: Request):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
user, response = _require_user(request, db, "marketplace_leads.create")
|
|
if response:
|
|
return response
|
|
return _render(request, "modules/marketplace/templates/marketplace/lead_form.html", db, user, title="New Marketplace Lead", public_mode=False)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.post("/leads/new")
|
|
def lead_create(request: Request, csrf_token: str = Form(...), lead_name: str = Form(...), business_name: str = Form(""), email: str = Form(""), mobile: str = Form(""), city: str = Form(""), state: str = Form(""), service_category: str = Form(""), service_requested: str = Form(...), message: str = Form(""), source: str = Form("manual"), priority: str = Form("NORMAL"), estimated_value: str = Form("0")):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
user, response = _require_user(request, db, "marketplace_leads.create")
|
|
if response:
|
|
return response
|
|
validate_csrf(request, csrf_token)
|
|
lead = create_marketplace_lead(db, lead_name=lead_name, business_name=business_name, email=email, mobile=mobile, city=city, state=state, service_category=service_category, service_requested=service_requested, message=message, source=source, priority=priority, estimated_value=estimated_value, created_by_user_id=user.id)
|
|
return RedirectResponse(url=f"/marketplace/leads/{lead.id}", status_code=303)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.get("/public-lead")
|
|
def public_lead_form(request: Request):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
return _render(request, "modules/marketplace/templates/marketplace/public_lead_form.html", db, None, title="Request a Service")
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.post("/public-lead")
|
|
def public_lead_submit(request: Request, csrf_token: str = Form(...), lead_name: str = Form(...), business_name: str = Form(""), email: str = Form(""), mobile: str = Form(""), city: str = Form(""), state: str = Form(""), service_category: str = Form(""), service_requested: str = Form(...), message: str = Form("")):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
validate_csrf(request, csrf_token)
|
|
lead = create_marketplace_lead(db, lead_name=lead_name, business_name=business_name, email=email, mobile=mobile, city=city, state=state, service_category=service_category, service_requested=service_requested, message=message, source="public_website", priority="NORMAL")
|
|
return _render(request, "modules/marketplace/templates/marketplace/public_thank_you.html", db, None, title="Thank You", lead=lead)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.get("/leads/{lead_id}")
|
|
def lead_detail(request: Request, lead_id: int):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
user, response = _require_user(request, db, "marketplace_leads.view")
|
|
if response:
|
|
return response
|
|
lead = get_marketplace_lead(db, lead_id)
|
|
if not lead:
|
|
return RedirectResponse(url="/marketplace/leads", status_code=303)
|
|
return _render(request, "modules/marketplace/templates/marketplace/lead_detail.html", db, user, title=f"Lead {lead.lead_no}", lead=lead, audit_firms=list_reference_audit_firms(db), branches=list_reference_branches(db, lead.assigned_tenant_id), partners=list_reference_partners(db, lead.assigned_tenant_id), can_assign=_has_perm(db, user, "marketplace_leads.assign"), can_update=_has_perm(db, user, "marketplace_leads.update"), can_convert=_has_perm(db, user, "marketplace_leads.convert"))
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.post("/leads/{lead_id}/assign")
|
|
def lead_assign(request: Request, lead_id: int, csrf_token: str = Form(...), tenant_id: int = Form(...), branch_id: int = Form(0), partner_user_id: int = Form(0), notes: str = Form("")):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
user, response = _require_user(request, db, "marketplace_leads.assign")
|
|
if response:
|
|
return response
|
|
validate_csrf(request, csrf_token)
|
|
lead = get_marketplace_lead(db, lead_id)
|
|
if lead:
|
|
assign_marketplace_lead(db, lead=lead, tenant_id=tenant_id, branch_id=branch_id or None, partner_user_id=partner_user_id or None, notes=notes, assigned_by_user_id=user.id)
|
|
return RedirectResponse(url=f"/marketplace/leads/{lead_id}", status_code=303)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.post("/leads/{lead_id}/status")
|
|
def lead_status_update(request: Request, lead_id: int, csrf_token: str = Form(...), status: str = Form(...)):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
user, response = _require_user(request, db, "marketplace_leads.update")
|
|
if response:
|
|
return response
|
|
validate_csrf(request, csrf_token)
|
|
lead = get_marketplace_lead(db, lead_id)
|
|
if lead:
|
|
update_lead_status(db, lead=lead, status=status, user_id=user.id)
|
|
return RedirectResponse(url=f"/marketplace/leads/{lead_id}", status_code=303)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.post("/leads/{lead_id}/convert-client")
|
|
def lead_convert_client(request: Request, lead_id: int, csrf_token: str = Form(...), tenant_id: int = Form(...), branch_id: int = Form(...), partner_user_id: int = Form(0), client_code: str = Form("")):
|
|
db = CommonSessionLocal()
|
|
try:
|
|
user, response = _require_user(request, db, "marketplace_leads.convert")
|
|
if response:
|
|
return response
|
|
validate_csrf(request, csrf_token)
|
|
lead = get_marketplace_lead(db, lead_id)
|
|
if lead:
|
|
client = convert_lead_to_client(db, lead=lead, tenant_id=tenant_id, branch_id=branch_id, partner_user_id=partner_user_id or None, client_code=client_code, user_id=user.id)
|
|
return RedirectResponse(url=f"/clients/{client.id}", status_code=303)
|
|
return RedirectResponse(url="/marketplace/leads", status_code=303)
|
|
finally:
|
|
db.close()
|