重构学员证书签发与批量导入流程
This commit is contained in:
@@ -8,12 +8,11 @@ from app.core.security import generate_public_token, hash_token
|
||||
from app.db.session import get_db
|
||||
from app.models import AdminUser, Certificate, CertificateAccessToken, Learner, ProjectCourse
|
||||
from app.schemas.certificate import CertificateCreate, CertificateOut, PdfPregenerationJobCreate, PdfPregenerationJobOut
|
||||
from app.services.certificate_number import build_certificate_no
|
||||
from app.services.certificate_issuance import CertificateIssueData, DuplicateCertificate, issue_certificate
|
||||
from app.services.logs import log_action
|
||||
from app.services.pdf import PdfGenerationBusy, render_certificate_pdf
|
||||
from app.services.pdf_pregeneration import pdf_pregeneration_manager
|
||||
from app.services.system_settings import get_pdf_generation_concurrency_limit
|
||||
from app.services.certificate_templates import get_certificate_template
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -51,6 +50,7 @@ def list_certificates(
|
||||
Certificate.course_name.like(like),
|
||||
Certificate.stage_name.like(like),
|
||||
Learner.current_name.like(like),
|
||||
Learner.phone.like(like),
|
||||
)
|
||||
)
|
||||
if status_value:
|
||||
@@ -68,38 +68,34 @@ def create_certificate(
|
||||
db: Session = Depends(get_db),
|
||||
admin: AdminUser = Depends(require_roles("system_admin", "certificate_admin")),
|
||||
) -> Certificate:
|
||||
learner = db.get(Learner, payload.learner_id)
|
||||
if not learner:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Learner not found")
|
||||
project = db.query(ProjectCourse).filter(ProjectCourse.code == payload.project_code, ProjectCourse.status == "active").first()
|
||||
if not project:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Project code is inactive or missing")
|
||||
template_code = payload.template_code or project.default_template_code
|
||||
try:
|
||||
template_code = get_certificate_template(template_code).code
|
||||
project = db.query(ProjectCourse).filter(ProjectCourse.code == payload.project_code, ProjectCourse.status == "active").first()
|
||||
if not project:
|
||||
raise ValueError("项目代码不存在或已停用")
|
||||
certificate, learner, learner_created = issue_certificate(
|
||||
db,
|
||||
CertificateIssueData(
|
||||
learner_name=payload.learner_name,
|
||||
learner_phone=payload.learner_phone,
|
||||
project_code=payload.project_code,
|
||||
class_name=payload.class_name,
|
||||
course_name=payload.course_name,
|
||||
stage_name=payload.stage_name,
|
||||
course_start_date=payload.course_start_date,
|
||||
course_end_date=payload.course_end_date,
|
||||
issue_date=payload.issue_date,
|
||||
template_code=payload.template_code or project.default_template_code,
|
||||
remark=payload.remark,
|
||||
),
|
||||
source="manual_certificate",
|
||||
)
|
||||
except DuplicateCertificate as exc:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(exc)) from exc
|
||||
except (ValueError, FileNotFoundError) as exc:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
|
||||
certificate = Certificate(
|
||||
learner_id=payload.learner_id,
|
||||
project_code=payload.project_code,
|
||||
certificate_no="PENDING",
|
||||
certificate_name=project.name,
|
||||
class_name=payload.class_name,
|
||||
course_name=payload.course_name or project.default_course_name or project.name,
|
||||
stage_name=payload.stage_name or project.default_stage_name,
|
||||
course_start_date=payload.course_start_date,
|
||||
course_end_date=payload.course_end_date,
|
||||
issue_date=payload.issue_date,
|
||||
template_code=template_code,
|
||||
remark=payload.remark,
|
||||
)
|
||||
db.add(certificate)
|
||||
db.flush()
|
||||
certificate.certificate_no = build_certificate_no(certificate.id, certificate.project_code, certificate.issue_date)
|
||||
certificate.public_token_id = _create_token(db, certificate.id, "public_link")
|
||||
certificate.qr_token_id = _create_token(db, certificate.id, "qr_verify")
|
||||
log_action(db, admin, "create_certificate", "certificate", certificate.id, {"certificate_no": certificate.certificate_no, "learner_name": learner.current_name, "project_code": certificate.project_code, "issue_date": certificate.issue_date})
|
||||
log_action(db, admin, "create_certificate", "certificate", certificate.id, {"certificate_no": certificate.certificate_no, "learner_name": learner.current_name, "learner_created": learner_created, "project_code": certificate.project_code, "issue_date": certificate.issue_date})
|
||||
db.commit()
|
||||
db.refresh(certificate)
|
||||
return certificate
|
||||
@@ -167,6 +163,7 @@ def _certificate_payload(certificate: Certificate, learner: Learner | None = Non
|
||||
"id": certificate.id,
|
||||
"learner_id": certificate.learner_id,
|
||||
"learner_name": learner.current_name if learner else None,
|
||||
"learner_phone": learner.phone if learner else None,
|
||||
"import_batch_id": certificate.import_batch_id,
|
||||
"project_code": certificate.project_code,
|
||||
"certificate_no": certificate.certificate_no,
|
||||
@@ -240,6 +237,7 @@ def preview_certificate(
|
||||
return {
|
||||
"certificate_no": certificate.certificate_no,
|
||||
"learner_name": learner.current_name if learner else "",
|
||||
"learner_phone": learner.phone if learner else "",
|
||||
"certificate_name": certificate.certificate_name,
|
||||
"project_code": certificate.project_code,
|
||||
"course_name": certificate.course_name,
|
||||
|
||||
Reference in New Issue
Block a user