Preserve PUT item sequence when create_time ties on replace. Co-authored-by: Cursor <cursoragent@cursor.com>
180 lines
5.7 KiB
Python
180 lines
5.7 KiB
Python
"""OA 实例银行回执单(biz_attachment 关联)。"""
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.models.models import BizAttachment, OaInstance
|
|
|
|
BUSINESS_TYPE = "oa_bank_receipt"
|
|
|
|
|
|
class OaBankReceiptError(Exception):
|
|
pass
|
|
|
|
|
|
def _require_instance(db: Session, instance_id: str, tenant_no: str) -> OaInstance:
|
|
iid = (instance_id or "").strip()
|
|
if not iid:
|
|
raise OaBankReceiptError("实例ID无效")
|
|
row = (
|
|
db.query(OaInstance)
|
|
.filter(
|
|
OaInstance.id == iid,
|
|
OaInstance.tenant_no == tenant_no,
|
|
OaInstance.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
raise OaBankReceiptError("审批实例不存在")
|
|
return row
|
|
|
|
|
|
def _row_to_item(row: BizAttachment) -> Dict[str, Any]:
|
|
return {
|
|
"id": row.id,
|
|
"fileName": row.original_name or "",
|
|
"fileUrl": row.file_url or "",
|
|
"fileType": row.file_type or "",
|
|
"fileSize": row.file_size,
|
|
"createTime": row.create_time.strftime("%Y-%m-%d %H:%M:%S") if row.create_time else "",
|
|
}
|
|
|
|
|
|
def list_bank_receipts(db: Session, *, instance_id: str, tenant_no: str) -> List[Dict[str, Any]]:
|
|
_require_instance(db, instance_id, tenant_no)
|
|
rows = (
|
|
db.query(BizAttachment)
|
|
.filter(
|
|
BizAttachment.tenant_no == tenant_no,
|
|
BizAttachment.business_type == BUSINESS_TYPE,
|
|
BizAttachment.business_id == instance_id,
|
|
BizAttachment.del_flag == 0,
|
|
)
|
|
.order_by(
|
|
BizAttachment.order_num.asc(),
|
|
BizAttachment.create_time.asc(),
|
|
BizAttachment.id.asc(),
|
|
)
|
|
.all()
|
|
)
|
|
return [_row_to_item(r) for r in rows]
|
|
|
|
|
|
def replace_bank_receipts(
|
|
db: Session,
|
|
*,
|
|
instance_id: str,
|
|
tenant_no: str,
|
|
items: List[Dict[str, Any]],
|
|
user_id: str,
|
|
dept_id: str = "",
|
|
) -> List[Dict[str, Any]]:
|
|
_require_instance(db, instance_id, tenant_no)
|
|
now = datetime.now()
|
|
desired: List[Dict[str, Any]] = []
|
|
seen_urls = set()
|
|
for raw in items or []:
|
|
url = str((raw or {}).get("fileUrl") or (raw or {}).get("file_url") or "").strip()
|
|
if not url or url in seen_urls:
|
|
continue
|
|
seen_urls.add(url)
|
|
desired.append(
|
|
{
|
|
"fileUrl": url,
|
|
"fileName": str((raw or {}).get("fileName") or (raw or {}).get("file_name") or "").strip()
|
|
or url.rsplit("/", 1)[-1],
|
|
"fileType": str((raw or {}).get("fileType") or (raw or {}).get("file_type") or "").strip(),
|
|
"fileSize": (raw or {}).get("fileSize")
|
|
if (raw or {}).get("fileSize") is not None
|
|
else (raw or {}).get("file_size"),
|
|
"orderNum": len(desired),
|
|
}
|
|
)
|
|
|
|
existing = (
|
|
db.query(BizAttachment)
|
|
.filter(
|
|
BizAttachment.tenant_no == tenant_no,
|
|
BizAttachment.business_type == BUSINESS_TYPE,
|
|
BizAttachment.business_id == instance_id,
|
|
BizAttachment.del_flag == 0,
|
|
)
|
|
.all()
|
|
)
|
|
existing_by_url = {r.file_url: r for r in existing if r.file_url}
|
|
desired_urls = {d["fileUrl"] for d in desired}
|
|
|
|
for row in existing:
|
|
if row.file_url not in desired_urls:
|
|
row.del_flag = 1
|
|
row.update_by = user_id or None
|
|
row.update_time = now
|
|
|
|
for d in desired:
|
|
url = d["fileUrl"]
|
|
order_num = int(d["orderNum"])
|
|
row: Optional[BizAttachment] = existing_by_url.get(url)
|
|
if row is None:
|
|
row = (
|
|
db.query(BizAttachment)
|
|
.filter(
|
|
BizAttachment.tenant_no == tenant_no,
|
|
BizAttachment.file_url == url,
|
|
BizAttachment.del_flag == 0,
|
|
)
|
|
.order_by(BizAttachment.create_time.desc())
|
|
.first()
|
|
)
|
|
if row is None:
|
|
ext = ""
|
|
if "." in d["fileName"]:
|
|
ext = d["fileName"].rsplit(".", 1)[-1][:20]
|
|
size = d["fileSize"]
|
|
try:
|
|
size_int = int(size) if size is not None else None
|
|
except (TypeError, ValueError):
|
|
size_int = None
|
|
row = BizAttachment(
|
|
id=uuid.uuid4().hex,
|
|
business_type=BUSINESS_TYPE,
|
|
business_id=instance_id,
|
|
original_name=d["fileName"][:200],
|
|
file_ext=ext or None,
|
|
file_url=url,
|
|
file_size=size_int,
|
|
file_type=(d["fileType"] or None),
|
|
tenant_no=tenant_no,
|
|
order_num=order_num,
|
|
create_by=user_id or None,
|
|
create_dept_id=dept_id or "",
|
|
create_time=now,
|
|
update_by=user_id or None,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(row)
|
|
else:
|
|
row.business_type = BUSINESS_TYPE
|
|
row.business_id = instance_id
|
|
row.del_flag = 0
|
|
row.order_num = order_num
|
|
if d["fileName"]:
|
|
row.original_name = d["fileName"][:200]
|
|
if d["fileType"]:
|
|
row.file_type = d["fileType"]
|
|
if d["fileSize"] is not None:
|
|
try:
|
|
row.file_size = int(d["fileSize"])
|
|
except (TypeError, ValueError):
|
|
pass
|
|
row.update_by = user_id or None
|
|
row.update_time = now
|
|
|
|
db.flush()
|
|
return list_bank_receipts(db, instance_id=instance_id, tenant_no=tenant_no)
|