Let customer-service quick register write storage, certificate, and insurance separately without extra menu or data-scope checks. List freight by document data scope like the web admin, allow protocol staff outside the collection region, and pad OA datetimes to seconds so PC date pickers can show historical minute values. Co-authored-by: Cursor <cursoragent@cursor.com>
311 lines
9.7 KiB
Python
311 lines
9.7 KiB
Python
"""样本信息列表快捷登记写入。"""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.utils import generate_uuid
|
|
from app.crud import sample_customer_service as sample_customer_service_crud
|
|
from app.crud import sample_insurance as sample_insurance_crud
|
|
from app.crud import sample_storage_cert as sample_storage_cert_crud
|
|
from app.crud.storage_release_review import _get_user_name
|
|
from app.services.sample_customer_service_register import has_any_customer_service_payload
|
|
from app.models.models import (
|
|
BizCollectionProtocol,
|
|
BizProtocolSample,
|
|
BizStorageReleaseReview,
|
|
)
|
|
from app.models.research_donation import BizResearchDonation, BizResearchDonationSample
|
|
from app.services.sample_info_quick_register import (
|
|
apply_quick_storage_payload,
|
|
unique_sample_items,
|
|
)
|
|
|
|
|
|
def _protocol_accessible(db: Session, protocol_id: str, tenant_no: str) -> bool:
|
|
"""登记写入只校验本租户协议存在,不再按数据权限拦截。"""
|
|
row = (
|
|
db.query(BizCollectionProtocol.id)
|
|
.filter(
|
|
BizCollectionProtocol.id == protocol_id,
|
|
BizCollectionProtocol.del_flag == 0,
|
|
BizCollectionProtocol.tenant_no == tenant_no,
|
|
)
|
|
.first()
|
|
)
|
|
return row is not None
|
|
|
|
|
|
def _donation_accessible(db: Session, donation_id: str, tenant_no: str) -> bool:
|
|
"""登记写入只校验本租户捐赠单存在,不再按数据权限拦截。"""
|
|
row = (
|
|
db.query(BizResearchDonation.id)
|
|
.filter(
|
|
BizResearchDonation.id == donation_id,
|
|
BizResearchDonation.del_flag == 0,
|
|
BizResearchDonation.tenant_no == tenant_no,
|
|
)
|
|
.first()
|
|
)
|
|
return row is not None
|
|
|
|
|
|
def _pick_latest_review(
|
|
rows: List[BizStorageReleaseReview],
|
|
) -> Optional[BizStorageReleaseReview]:
|
|
best = None
|
|
best_t = None
|
|
for rev in rows:
|
|
cur_t = rev.storage_time or rev.update_time or rev.create_time
|
|
if best is None:
|
|
best, best_t = rev, cur_t
|
|
continue
|
|
if cur_t is None:
|
|
continue
|
|
if best_t is None or cur_t > best_t:
|
|
best, best_t = rev, cur_t
|
|
return best
|
|
|
|
|
|
def batch_handle_storage_certs(
|
|
db: Session,
|
|
*,
|
|
items: List[Dict[str, str]],
|
|
tenant_no: str,
|
|
user_id: str,
|
|
handle_time: Optional[datetime],
|
|
handler_user_id: Optional[str],
|
|
attachments: str,
|
|
remark: str,
|
|
mail_cert_time: Optional[datetime] = None,
|
|
update_mail_cert_time: bool = False,
|
|
do_commit: bool = True,
|
|
) -> Dict[str, int]:
|
|
pairs = unique_sample_items(items)
|
|
if not pairs:
|
|
raise ValueError("请选择样本")
|
|
success = 0
|
|
fail = 0
|
|
for sample_code, protocol_id in pairs:
|
|
if not protocol_id or not _protocol_accessible(db, protocol_id, tenant_no):
|
|
fail += 1
|
|
continue
|
|
try:
|
|
sample_storage_cert_crud.upsert_handle(
|
|
db,
|
|
tenant_no=tenant_no,
|
|
sample_code=sample_code,
|
|
collection_protocol_id=protocol_id,
|
|
user_id=user_id,
|
|
handle_time=handle_time,
|
|
handler_user_id=handler_user_id,
|
|
cert_image_urls=attachments,
|
|
remark=remark,
|
|
mail_cert_time=mail_cert_time,
|
|
update_mail_cert_time=update_mail_cert_time,
|
|
)
|
|
success += 1
|
|
except ValueError:
|
|
fail += 1
|
|
if do_commit:
|
|
db.commit()
|
|
return {"success": success, "fail": fail}
|
|
|
|
|
|
def batch_handle_insurance(
|
|
db: Session,
|
|
*,
|
|
items: List[Dict[str, str]],
|
|
tenant_no: str,
|
|
user_id: str,
|
|
handle_time: Optional[datetime],
|
|
handler_user_id: Optional[str],
|
|
attachments: str,
|
|
remark: str,
|
|
policy_send_time: Optional[datetime] = None,
|
|
update_policy_send_time: bool = False,
|
|
do_commit: bool = True,
|
|
) -> Dict[str, int]:
|
|
pairs = unique_sample_items(items)
|
|
if not pairs:
|
|
raise ValueError("请选择样本")
|
|
success = 0
|
|
fail = 0
|
|
for sample_code, protocol_id in pairs:
|
|
if not protocol_id or not _protocol_accessible(db, protocol_id, tenant_no):
|
|
fail += 1
|
|
continue
|
|
try:
|
|
sample_insurance_crud.upsert_handle(
|
|
db,
|
|
tenant_no=tenant_no,
|
|
sample_code=sample_code,
|
|
collection_protocol_id=protocol_id,
|
|
user_id=user_id,
|
|
handle_time=handle_time,
|
|
handler_user_id=handler_user_id,
|
|
insurance_attachments=attachments,
|
|
handle_remark=remark,
|
|
policy_send_time=policy_send_time,
|
|
update_policy_send_time=update_policy_send_time,
|
|
)
|
|
success += 1
|
|
except ValueError:
|
|
fail += 1
|
|
if do_commit:
|
|
db.commit()
|
|
return {"success": success, "fail": fail}
|
|
|
|
|
|
def batch_register_customer_service(
|
|
db: Session,
|
|
*,
|
|
items: List[Dict[str, str]],
|
|
tenant_no: str,
|
|
user_id: str,
|
|
incoming: Dict[str, Any],
|
|
do_commit: bool = True,
|
|
) -> Dict[str, int]:
|
|
if not has_any_customer_service_payload(incoming):
|
|
raise ValueError("请至少填写一项客户服务信息")
|
|
pairs = unique_sample_items(items)
|
|
if not pairs:
|
|
raise ValueError("请选择样本")
|
|
success = 0
|
|
fail = 0
|
|
for sample_code, protocol_id in pairs:
|
|
if not protocol_id or not _protocol_accessible(db, protocol_id, tenant_no):
|
|
fail += 1
|
|
continue
|
|
try:
|
|
sample_customer_service_crud.upsert_by_sample_code(
|
|
db,
|
|
tenant_no=tenant_no,
|
|
sample_code=sample_code,
|
|
collection_protocol_id=protocol_id,
|
|
user_id=user_id,
|
|
incoming=incoming,
|
|
)
|
|
success += 1
|
|
except ValueError:
|
|
fail += 1
|
|
if do_commit:
|
|
db.commit()
|
|
return {"success": success, "fail": fail}
|
|
|
|
|
|
def batch_quick_register_storage(
|
|
db: Session,
|
|
*,
|
|
items: List[Dict[str, str]],
|
|
reception_source: str,
|
|
tenant_no: str,
|
|
user_id: str,
|
|
handle_time: Optional[datetime],
|
|
handler_user_id: Optional[str],
|
|
attachments: str,
|
|
remark: str,
|
|
do_commit: bool = True,
|
|
) -> Dict[str, int]:
|
|
source = (reception_source or "").strip()
|
|
if source not in ("cell_storage", "research_donation"):
|
|
raise ValueError("来源无效")
|
|
fields = apply_quick_storage_payload(
|
|
handle_time=handle_time,
|
|
handler_user_id=handler_user_id,
|
|
attachments=attachments,
|
|
remark=remark,
|
|
)
|
|
pairs = unique_sample_items(items)
|
|
if not pairs:
|
|
raise ValueError("请选择样本")
|
|
|
|
handler_name = _get_user_name(db, fields["storage_by"] or user_id)
|
|
success = 0
|
|
fail = 0
|
|
now = datetime.now()
|
|
for sample_code, protocol_id in pairs:
|
|
if source == "cell_storage":
|
|
if not protocol_id or not _protocol_accessible(db, protocol_id, tenant_no):
|
|
fail += 1
|
|
continue
|
|
else:
|
|
if not protocol_id or not _donation_accessible(db, protocol_id, tenant_no):
|
|
fail += 1
|
|
continue
|
|
rows = (
|
|
db.query(BizStorageReleaseReview)
|
|
.filter(
|
|
BizStorageReleaseReview.tenant_no == tenant_no,
|
|
BizStorageReleaseReview.del_flag == 0,
|
|
BizStorageReleaseReview.reception_source == source,
|
|
BizStorageReleaseReview.sample_code == sample_code,
|
|
)
|
|
.all()
|
|
)
|
|
rev = _pick_latest_review(rows)
|
|
if rev is None:
|
|
rev = BizStorageReleaseReview(
|
|
id=generate_uuid(),
|
|
sample_code=sample_code,
|
|
reception_source=source,
|
|
protocol_id=protocol_id,
|
|
storage_status="yrk",
|
|
tenant_no=tenant_no,
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
update_by=user_id,
|
|
create_time=now,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(rev)
|
|
rev.storage_status = fields["storage_status"]
|
|
rev.storage_time = fields["storage_time"]
|
|
rev.storage_by = fields["storage_by"]
|
|
rev.storage_by_name = handler_name
|
|
rev.remark = fields["remark"] or None
|
|
if fields["attachments"]:
|
|
rev.review_attachments = fields["attachments"]
|
|
rev.update_by = user_id
|
|
rev.update_time = now
|
|
db.add(rev)
|
|
|
|
ymd = fields["storage_in_date"]
|
|
if source == "cell_storage":
|
|
ps = (
|
|
db.query(BizProtocolSample)
|
|
.filter(
|
|
BizProtocolSample.sample_code == sample_code,
|
|
BizProtocolSample.tenant_no == tenant_no,
|
|
BizProtocolSample.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if ps:
|
|
ps.sample_status = "yrk"
|
|
ps.storage_in_date = ymd
|
|
ps.update_time = now
|
|
db.add(ps)
|
|
else:
|
|
ds = (
|
|
db.query(BizResearchDonationSample)
|
|
.filter(
|
|
BizResearchDonationSample.sample_code == sample_code,
|
|
BizResearchDonationSample.tenant_no == tenant_no,
|
|
BizResearchDonationSample.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if ds:
|
|
ds.sample_status = "yrk"
|
|
ds.storage_in_date = ymd
|
|
ds.update_time = now
|
|
db.add(ds)
|
|
success += 1
|
|
if do_commit:
|
|
db.commit()
|
|
return {"success": success, "fail": fail}
|