hesabixArc/hesabixAPI/adapters/api/v1/report_templates.py
2025-11-09 05:16:37 +00:00

242 lines
8.5 KiB
Python

from typing import Any, Dict, List, Optional
from fastapi import APIRouter, Body, Depends, Request
from sqlalchemy.orm import Session
from adapters.db.session import get_db
from app.core.auth_dependency import get_current_user, AuthContext
from app.core.permissions import require_business_access
from app.core.responses import ApiError, success_response
from app.services.report_template_service import ReportTemplateService
router = APIRouter(prefix="/report-templates", tags=["report-templates"])
@router.get(
"/business/{business_id}",
summary="لیست قالب‌های گزارش",
description="لیست قالب‌ها با امکان فیلتر بر اساس ماژول و زیرنوع. کاربران عادی فقط Published را می‌بینند.",
)
@require_business_access("business_id")
async def list_report_templates(
request: Request,
business_id: int,
module_key: Optional[str] = None,
subtype: Optional[str] = None,
status: Optional[str] = None,
ctx: AuthContext = Depends(get_current_user),
db: Session = Depends(get_db),
):
only_published = True
# فقط کسانی که write در report_templates دارند، می‌توانند پیش‌نویس‌ها را ببینند
if ctx.can_write_section("report_templates"):
only_published = False
templates = ReportTemplateService.list_templates(
db=db,
business_id=business_id,
module_key=module_key,
subtype=subtype,
status=status,
only_published=only_published,
)
data: List[Dict[str, Any]] = []
for t in templates:
data.append({
"id": t.id,
"business_id": t.business_id,
"module_key": t.module_key,
"subtype": t.subtype,
"name": t.name,
"description": t.description,
"status": t.status,
"is_default": t.is_default,
"version": t.version,
"paper_size": t.paper_size,
"orientation": t.orientation,
"margins": t.margins,
"updated_at": t.updated_at.isoformat() if t.updated_at else None,
})
return {"items": data}
@router.get(
"/{template_id}/business/{business_id}",
summary="جزئیات یک قالب گزارش (فقط سازندگان)",
description="اطلاعات کامل قالب شامل محتوا برای ویرایشگر",
)
@require_business_access("business_id")
async def get_report_template(
request: Request,
template_id: int,
business_id: int,
ctx: AuthContext = Depends(get_current_user),
db: Session = Depends(get_db),
):
if not ctx.can_write_section("report_templates"):
raise ApiError("FORBIDDEN", "Missing permission: report_templates.write", http_status=403)
entity = ReportTemplateService.get_template(db=db, template_id=template_id, business_id=business_id)
if not entity:
raise ApiError("NOT_FOUND", "Template not found", http_status=404)
return {
"id": entity.id,
"business_id": entity.business_id,
"module_key": entity.module_key,
"subtype": entity.subtype,
"name": entity.name,
"description": entity.description,
"engine": entity.engine,
"status": entity.status,
"is_default": entity.is_default,
"version": entity.version,
"content_html": entity.content_html,
"content_css": entity.content_css,
"header_html": entity.header_html,
"footer_html": entity.footer_html,
"paper_size": entity.paper_size,
"orientation": entity.orientation,
"margins": entity.margins,
"assets": entity.assets,
"created_by": entity.created_by,
"created_at": entity.created_at.isoformat() if entity.created_at else None,
"updated_at": entity.updated_at.isoformat() if entity.updated_at else None,
}
@router.post(
"/business/{business_id}",
summary="ایجاد قالب جدید (فقط سازندگان)",
)
@require_business_access("business_id")
async def create_report_template(
request: Request,
business_id: int,
body: Dict[str, Any] = Body(...),
ctx: AuthContext = Depends(get_current_user),
db: Session = Depends(get_db),
):
if not ctx.can_write_section("report_templates"):
raise ApiError("FORBIDDEN", "Missing permission: report_templates.write", http_status=403)
body = dict(body or {})
body["business_id"] = business_id
entity = ReportTemplateService.create_template(db=db, data=body, user_id=ctx.get_user_id())
return {"id": entity.id}
@router.put(
"/{template_id}/business/{business_id}",
summary="ویرایش قالب (فقط سازندگان)",
)
@require_business_access("business_id")
async def update_report_template(
request: Request,
template_id: int,
business_id: int,
body: Dict[str, Any] = Body(...),
ctx: AuthContext = Depends(get_current_user),
db: Session = Depends(get_db),
):
if not ctx.can_write_section("report_templates"):
raise ApiError("FORBIDDEN", "Missing permission: report_templates.write", http_status=403)
entity = ReportTemplateService.update_template(db=db, template_id=template_id, data=body or {}, business_id=business_id)
return {"id": entity.id, "version": entity.version}
@router.delete(
"/{template_id}/business/{business_id}",
summary="حذف قالب (فقط سازندگان)",
)
@require_business_access("business_id")
async def delete_report_template(
request: Request,
template_id: int,
business_id: int,
ctx: AuthContext = Depends(get_current_user),
db: Session = Depends(get_db),
):
if not ctx.can_write_section("report_templates"):
raise ApiError("FORBIDDEN", "Missing permission: report_templates.write", http_status=403)
ReportTemplateService.delete_template(db=db, template_id=template_id, business_id=business_id)
return success_response(data={"deleted": True}, request=request, message="Deleted")
@router.post(
"/{template_id}/business/{business_id}/publish",
summary="انتشار/بازگشت به پیش‌نویس (فقط سازندگان)",
)
@require_business_access("business_id")
async def publish_report_template(
request: Request,
template_id: int,
business_id: int,
body: Dict[str, Any] = Body(...),
ctx: AuthContext = Depends(get_current_user),
db: Session = Depends(get_db),
):
if not ctx.can_write_section("report_templates"):
raise ApiError("FORBIDDEN", "Missing permission: report_templates.write", http_status=403)
is_published = bool((body or {}).get("published", True))
entity = ReportTemplateService.publish_template(db=db, template_id=template_id, business_id=business_id, is_published=is_published)
return {"id": entity.id, "status": entity.status}
@router.post(
"/business/{business_id}/set-default",
summary="تنظیم قالب پیش‌فرض یک ماژول/زیرنوع (فقط سازندگان)",
)
@require_business_access("business_id")
async def set_default_template(
request: Request,
business_id: int,
body: Dict[str, Any] = Body(...),
ctx: AuthContext = Depends(get_current_user),
db: Session = Depends(get_db),
):
if not ctx.can_write_section("report_templates"):
raise ApiError("FORBIDDEN", "Missing permission: report_templates.write", http_status=403)
module_key = str((body or {}).get("module_key") or "")
if not module_key:
raise ApiError("VALIDATION_ERROR", "module_key is required", http_status=400)
subtype = (body or {}).get("subtype")
template_id = int((body or {}).get("template_id") or 0)
if template_id <= 0:
raise ApiError("VALIDATION_ERROR", "template_id is required", http_status=400)
entity = ReportTemplateService.set_default(
db=db,
business_id=business_id,
module_key=module_key,
subtype=(str(subtype) if subtype is not None else None),
template_id=template_id,
)
return {"id": entity.id, "is_default": entity.is_default}
@router.post(
"/business/{business_id}/preview",
summary="پیش‌نمایش قالب (فقط سازندگان)",
description="بدون ذخیره‌سازی؛ HTML/CSS ارسالی با داده نمونه رندر و به PDF تبدیل می‌شود.",
)
@require_business_access("business_id")
async def preview_report_template(
request: Request,
business_id: int,
body: Dict[str, Any] = Body(...),
ctx: AuthContext = Depends(get_current_user),
db: Session = Depends(get_db),
):
from weasyprint import HTML
from weasyprint.text.fonts import FontConfiguration
if not ctx.can_write_section("report_templates"):
raise ApiError("FORBIDDEN", "Missing permission: report_templates.write", http_status=403)
content_html = (body or {}).get("content_html") or ""
content_css = (body or {}).get("content_css") or ""
context = (body or {}).get("context") or {}
temp = type("T", (), {"content_html": content_html, "content_css": content_css})() # شیء موقت شبیه ReportTemplate
html = ReportTemplateService.render_with_template(temp, context)
pdf_bytes = HTML(string=html).write_pdf(font_config=FontConfiguration())
return {
"content_length": len(pdf_bytes),
"ok": True,
}