Add Phase 4 standard accounting classification taxonomy

This commit is contained in:
A R R R Associates
2026-08-22 12:37:20 +05:30
parent 397c887703
commit 45fedd0d96
9 changed files with 466 additions and 0 deletions
+121
View File
@@ -0,0 +1,121 @@
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.accounting.taxonomy_service import ensure_standard_taxonomy, grouped_taxonomy, list_taxonomy, set_nature_active
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.documents.services import build_document_scope
router = APIRouter(prefix="/tools/accounting/taxonomy", tags=["accounting-taxonomy-ui"])
def _denied():
from app.core.http_responses import ui_access_denied
return ui_access_denied()
def _require_partner_permission(request: Request, db, permission: str):
user = get_current_user(request, db)
if not user:
return None, RedirectResponse(url="/login", status_code=303)
roles = set(get_user_roles(db, user.id))
if "Partner" not in roles:
return None, _denied()
try:
require_permission(db, user, permission)
except Exception:
return None, _denied()
return user, None
def _context(request: Request, db, user, **extra):
data = {
"request": request,
"current_user": user,
"current_user_roles": get_user_roles(db, user.id),
"current_user_permissions": get_user_permissions(db, user.id),
"csrf_token": get_or_create_csrf_token(request),
}
data.update(extra)
return data
@router.get("")
def accounting_taxonomy(request: Request, status: str = "all", group: str = "", updated: int = 0):
db = CommonSessionLocal()
try:
user, response = _require_partner_permission(request, db, "accounting.taxonomy.view")
if response:
return response
scope = build_document_scope(request, db, user)
ensure_standard_taxonomy(db, scope.tenant_id, user.id)
status = status if status in {"all", "active", "inactive"} else "all"
allowed_groups = {"purchase", "expense", "repairs", "capital", "statutory", "finance", "review"}
group = group if group in allowed_groups else ""
rows = list_taxonomy(db, scope.tenant_id, status=status, group=group)
all_rows = list_taxonomy(db, scope.tenant_id)
counts = {
"total": sum(1 for r in all_rows if r.is_posting_nature),
"active": sum(1 for r in all_rows if r.is_posting_nature and r.is_active),
"inactive": sum(1 for r in all_rows if r.is_posting_nature and not r.is_active),
"capital": sum(1 for r in all_rows if r.is_posting_nature and r.capital_revenue == "capital"),
}
return templates.TemplateResponse(
"modules/accounting/templates/accounting/taxonomy.html",
_context(
request,
db,
user,
taxonomy_groups=grouped_taxonomy(rows),
rows=rows,
counts=counts,
selected_status=status,
selected_group=group,
updated=updated,
),
)
finally:
db.close()
@router.post("/{nature_id}/active")
def update_accounting_nature_active(
nature_id: int,
request: Request,
csrf_token: str = Form(...),
is_active: str = Form(...),
status: str = Form("all"),
group: str = Form(""),
):
db = CommonSessionLocal()
try:
user, response = _require_partner_permission(request, db, "accounting.taxonomy.manage")
if response:
return response
validate_csrf(request, csrf_token)
scope = build_document_scope(request, db, user)
try:
row = set_nature_active(
db,
tenant_id=scope.tenant_id,
nature_id=nature_id,
is_active=is_active.strip().lower() in {"1", "true", "yes", "on"},
actor_user_id=user.id,
)
except ValueError:
return _denied()
if row is None:
return _denied()
query = f"?updated=1&status={status if status in {'all','active','inactive'} else 'all'}"
if group:
query += f"&group={group}"
return RedirectResponse(url=f"/tools/accounting/taxonomy{query}", status_code=303)
finally:
db.close()