Files
shanxia2.0/backend/app/crud/collection_protocol_no.py
T
2026-05-17 08:36:37 +08:00

340 lines
9.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""采集协议号池 CRUD(biz_collection_protocol_no)"""
from __future__ import annotations
import math
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy import and_, func, or_
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.models.models import BizCollectionProtocolNo
def _row_to_dict(r: BizCollectionProtocolNo) -> Dict[str, Any]:
return {
"id": r.id,
"protocolNo": r.protocol_no,
"issued": int(r.issued or 0),
"issuedUserId": r.issued_user_id or "",
"issuedUserName": r.issued_user_name or "",
"issuedTime": r.issued_time.strftime("%Y-%m-%d %H:%M:%S") if r.issued_time else "",
"tenantNo": r.tenant_no,
"orderNum": r.order_num if r.order_num is not None else 0,
"remark": r.remark or "",
"createTime": r.create_time.strftime("%Y-%m-%d %H:%M:%S") if r.create_time else "",
"updateTime": r.update_time.strftime("%Y-%m-%d %H:%M:%S") if r.update_time else "",
}
def protocol_no_exists(db: Session, no: str, tenant_no: str, exclude_id: Optional[str] = None) -> bool:
v = (no or "").strip()
if not v:
return False
q = db.query(BizCollectionProtocolNo).filter(
and_(
BizCollectionProtocolNo.protocol_no == v,
BizCollectionProtocolNo.tenant_no == tenant_no,
BizCollectionProtocolNo.del_flag == 0,
)
)
if exclude_id:
q = q.filter(BizCollectionProtocolNo.id != exclude_id)
return q.first() is not None
def list_protocol_nos(
db: Session,
*,
page: int = 1,
page_size: int = 10,
keyword: Optional[str] = None,
tenant_no: Optional[str] = None,
) -> Tuple[List[Dict[str, Any]], int]:
def _filtered():
q0 = db.query(BizCollectionProtocolNo).filter(BizCollectionProtocolNo.del_flag == 0)
if tenant_no:
q0 = q0.filter(BizCollectionProtocolNo.tenant_no == tenant_no)
kw = (keyword or "").strip()
if kw:
like = f"%{kw}%"
q0 = q0.filter(or_(BizCollectionProtocolNo.protocol_no.like(like), BizCollectionProtocolNo.remark.like(like)))
return q0
total = _filtered().order_by(None).with_entities(func.count(BizCollectionProtocolNo.id)).scalar() or 0
page = max(1, page)
page_size = min(max(1, page_size), 100)
rows = (
_filtered()
.order_by(BizCollectionProtocolNo.create_time.desc())
.offset((page - 1) * page_size)
.limit(page_size)
.all()
)
return [_row_to_dict(x) for x in rows], int(total)
def get_protocol_no(db: Session, row_id: str, tenant_no: Optional[str] = None) -> Optional[BizCollectionProtocolNo]:
q = db.query(BizCollectionProtocolNo).filter(and_(BizCollectionProtocolNo.id == row_id, BizCollectionProtocolNo.del_flag == 0))
if tenant_no:
q = q.filter(BizCollectionProtocolNo.tenant_no == tenant_no)
return q.first()
def create_protocol_no(
db: Session,
*,
protocol_no: str,
issued: int = 0,
tenant_no: str = "zkxw",
order_num: Optional[int] = None,
remark: Optional[str] = None,
user_id: Optional[str] = None,
) -> BizCollectionProtocolNo:
pn = (protocol_no or "").strip()
if not pn:
raise ValueError("采集协议号不能为空")
if protocol_no_exists(db, pn, tenant_no):
raise ValueError("采集协议号已存在")
obj = BizCollectionProtocolNo(
id=generate_uuid(),
protocol_no=pn,
issued=1 if issued else 0,
tenant_no=tenant_no,
order_num=order_num if order_num is not None else 0,
remark=(remark or "").strip() or None,
create_by=user_id,
create_dept_id="",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(obj)
db.commit()
db.refresh(obj)
return obj
def update_protocol_no(
db: Session,
row_id: str,
*,
protocol_no: Optional[str] = None,
issued: Optional[int] = None,
order_num: Optional[int] = None,
remark: Optional[str] = None,
user_id: Optional[str] = None,
tenant_no: Optional[str] = None,
issued_user_id: Optional[str] = None,
issued_user_name: Optional[str] = None,
issued_time: Optional[str] = None,
) -> BizCollectionProtocolNo:
obj = get_protocol_no(db, row_id, tenant_no=tenant_no)
if not obj:
raise ValueError("记录不存在")
if protocol_no is not None:
pn = protocol_no.strip()
if not pn:
raise ValueError("采集协议号不能为空")
if pn != obj.protocol_no and protocol_no_exists(db, pn, obj.tenant_no, exclude_id=row_id):
raise ValueError("采集协议号已存在")
obj.protocol_no = pn
if issued is not None:
obj.issued = 1 if issued else 0
if order_num is not None:
obj.order_num = order_num
if remark is not None:
obj.remark = remark.strip() or None
if issued_user_id is not None:
obj.issued_user_id = issued_user_id or None
if issued_user_name is not None:
obj.issued_user_name = issued_user_name or None
if issued_time is not None:
obj.issued_time = issued_time or None
obj.update_by = user_id
obj.update_time = datetime.now()
db.add(obj)
db.commit()
db.refresh(obj)
return obj
def soft_delete_protocol_no(db: Session, row_id: str, tenant_no: Optional[str] = None) -> None:
obj = get_protocol_no(db, row_id, tenant_no=tenant_no)
if not obj:
raise ValueError("记录不存在")
obj.del_flag = 1
obj.update_time = datetime.now()
db.add(obj)
db.commit()
def batch_generate_protocol_nos(
db: Session,
*,
prefix: str,
middle: str,
seq_start: int,
seq_end: int,
digit_count: int = 6,
tenant_no: str = "zkxw",
user_id: Optional[str] = None,
) -> Dict[str, Any]:
"""批量生成协议号: 前缀 + 中间段 + 补零序号"""
p = (prefix or "").strip()
m = (middle or "").strip()
if not p:
raise ValueError("固定前缀不能为空")
if seq_start < 0 or seq_end < 0:
raise ValueError("序号不能为负数")
if seq_start > seq_end:
raise ValueError("开始序号不能大于结束序号")
if digit_count < 1:
raise ValueError("序号位数不能小于1")
count = seq_end - seq_start + 1
if count > 10000:
raise ValueError("单次批量生成不能超过10000条")
generated_nos = []
for i in range(seq_start, seq_end + 1):
seq_str = str(i).zfill(digit_count)
full_no = f"{p}{m}{seq_str}"
generated_nos.append(full_no)
# Batch check existing
existing = set(
row.protocol_no
for row in db.query(BizCollectionProtocolNo.protocol_no)
.filter(
BizCollectionProtocolNo.tenant_no == tenant_no,
BizCollectionProtocolNo.del_flag == 0,
BizCollectionProtocolNo.protocol_no.in_(generated_nos),
)
.all()
)
now = datetime.now()
created = []
skipped = []
for no in generated_nos:
if no in existing:
skipped.append(no)
continue
obj = BizCollectionProtocolNo(
id=generate_uuid(),
protocol_no=no,
issued=0,
tenant_no=tenant_no,
order_num=0,
remark=None,
create_by=user_id,
create_dept_id="",
create_time=now,
update_by=user_id,
update_time=now,
del_flag=0,
)
created.append(obj)
if created:
db.bulk_save_objects(created)
db.commit()
return {
"created": len(created),
"skipped": len(skipped),
"skippedNos": skipped,
}
def batch_issue_protocol_nos(
db: Session,
*,
ids: List[str],
issued_user_id: str,
issued_user_name: Optional[str] = None,
tenant_no: Optional[str] = None,
user_id: Optional[str] = None,
) -> Dict[str, Any]:
"""批量下发协议号"""
if not ids:
raise ValueError("请选择要下发的协议号")
uid = (issued_user_id or "").strip()
if not uid:
raise ValueError("请选择下发用户")
now = datetime.now()
issued_count = 0
already_issued = []
for row_id in ids:
obj = get_protocol_no(db, row_id, tenant_no=tenant_no)
if not obj:
continue
if obj.issued == 1:
already_issued.append(obj.protocol_no)
continue
obj.issued = 1
obj.issued_user_id = uid
obj.issued_user_name = (issued_user_name or "").strip() or None
obj.issued_time = now
obj.update_by = user_id
obj.update_time = now
db.add(obj)
issued_count += 1
if issued_count > 0:
db.commit()
return {
"issuedCount": issued_count,
"alreadyIssued": already_issued,
}
def batch_revoke_protocol_nos(
db: Session,
*,
ids: List[str],
tenant_no: Optional[str] = None,
user_id: Optional[str] = None,
) -> Dict[str, Any]:
if not ids:
raise ValueError("请选择要收回的协议号")
now = datetime.now()
revoked_count = 0
not_issued = []
for row_id in ids:
obj = get_protocol_no(db, row_id, tenant_no=tenant_no)
if not obj:
continue
if obj.issued != 1:
not_issued.append(obj.protocol_no)
continue
obj.issued = 0
obj.issued_user_id = None
obj.issued_user_name = None
obj.issued_time = None
obj.update_by = user_id
obj.update_time = now
db.add(obj)
revoked_count += 1
if revoked_count > 0:
db.commit()
return {
"revokedCount": revoked_count,
"notIssued": not_issued,
}
def total_pages(total: int, page_size: int) -> int:
if total <= 0:
return 0
return int(math.ceil(total / float(page_size)))