feat: apply dual-gate storage release submit, auto store, and unstore.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-19 11:39:00 +08:00
1 parent 217549884d
commit 6143a99133
1 file changed
+130 -18
+130 -18
View File
@@ -419,6 +419,9 @@ def list_reviews(
storage_status: Optional[str] = None,
keyword: Optional[str] = None,
review_phase: Optional[str] = None,
review_side: Optional[str] = None,
prod_review_conclusion: Optional[str] = None,
qc_review_conclusion: Optional[str] = None,
qc_work_order_completed=None,
ready_for_review_only=None,
user_info=None,
@@ -431,18 +434,29 @@ def list_reviews(
if rs:
q0 = q0.filter(BizStorageReleaseReview.reception_source == rs)
phase = normalize_review_phase(review_phase)
if phase == "pending":
q0 = q0.filter(
or_(
BizStorageReleaseReview.review_conclusion.is_(None),
BizStorageReleaseReview.review_conclusion == "",
)
side = normalize_review_side(review_side) or "overview"
if phase:
prod_blank = or_(
BizStorageReleaseReview.prod_review_conclusion.is_(None),
BizStorageReleaseReview.prod_review_conclusion == "",
)
elif phase == "reviewed":
q0 = q0.filter(
BizStorageReleaseReview.review_conclusion.isnot(None),
BizStorageReleaseReview.review_conclusion != "",
qc_blank = or_(
BizStorageReleaseReview.qc_review_conclusion.is_(None),
BizStorageReleaseReview.qc_review_conclusion == "",
)
if side == "production":
q0 = q0.filter(prod_blank if phase == "pending" else ~prod_blank)
elif side == "qc":
q0 = q0.filter(qc_blank if phase == "pending" else ~qc_blank)
else:
both_filled = and_(~prod_blank, ~qc_blank)
q0 = q0.filter(~both_filled if phase == "pending" else both_filled)
prc = (prod_review_conclusion or "").strip()
if prc:
q0 = q0.filter(BizStorageReleaseReview.prod_review_conclusion == prc)
qrc = (qc_review_conclusion or "").strip()
if qrc:
q0 = q0.filter(BizStorageReleaseReview.qc_review_conclusion == qrc)
rc = (review_conclusion or "").strip()
if rc:
q0 = q0.filter(BizStorageReleaseReview.review_conclusion == rc)
@@ -944,6 +958,7 @@ def submit_review(
db: Session,
review_id: str,
*,
review_side: str,
review_conclusion: str,
review_remark: Optional[str] = None,
review_attachments: Optional[str] = None,
@@ -961,17 +976,50 @@ def submit_review(
)
if not rev:
raise ValueError("审核记录不存在")
side = normalize_review_side(review_side)
if side not in ("production", "qc"):
raise ValueError("审核侧无效")
conclusion = (review_conclusion or "").strip()
if conclusion not in ("tg", "btg"):
raise ValueError("审核结论无效")
user_name = _get_user_name(db, user_id)
rev.review_conclusion = review_conclusion
rev.review_remark = (review_remark or "").strip() or None
rev.review_attachments = (review_attachments or "").strip() or None
now = datetime.now()
remark = (review_remark or "").strip() or None
attachments = (review_attachments or "").strip() or None
if side == "production":
rev.prod_review_conclusion = conclusion
rev.prod_review_remark = remark
rev.prod_review_attachments = attachments
rev.prod_review_by = user_id
rev.prod_review_by_name = user_name
rev.prod_review_time = now
else:
rev.qc_review_conclusion = conclusion
rev.qc_review_remark = remark
rev.qc_review_attachments = attachments
rev.qc_review_by = user_id
rev.qc_review_by_name = user_name
rev.qc_review_time = now
agg = aggregate_review_conclusion(rev.prod_review_conclusion, rev.qc_review_conclusion)
rev.review_conclusion = agg
rev.review_remark = remark
rev.review_attachments = attachments
rev.review_by = user_id
rev.review_by_name = user_name
rev.review_time = datetime.now()
rev.review_time = now
rev.update_by = user_id
rev.update_time = datetime.now()
rev.update_time = now
db.add(rev)
db.flush()
action = storage_transition(
rev.prod_review_conclusion, rev.qc_review_conclusion, rev.storage_status
)
if action == "store":
store_sample(db, review_id, tenant_no=tenant_no, user_id=user_id)
db.refresh(rev)
elif action == "unstore":
unstore_sample(db, review_id, tenant_no=tenant_no, user_id=user_id)
db.refresh(rev)
return rev
@@ -979,6 +1027,7 @@ def batch_submit_review(
db: Session,
ids: List[str],
*,
review_side: str,
review_conclusion: str,
review_remark: Optional[str] = None,
review_attachments: Optional[str] = None,
@@ -992,6 +1041,7 @@ def batch_submit_review(
submit_review(
db,
rid,
review_side=review_side,
review_conclusion=review_conclusion,
review_remark=review_remark,
review_attachments=review_attachments,
@@ -1022,8 +1072,8 @@ def store_sample(
)
if not rev:
raise ValueError("审核记录不存在")
if rev.review_conclusion != "tg":
raise ValueError("只有审核通过的记录才能执行入库操作")
if aggregate_review_conclusion(rev.prod_review_conclusion, rev.qc_review_conclusion) != "tg":
raise ValueError("生产与质检均通过后才能入库")
if rev.storage_status != "drk":
raise ValueError("当前状态不允许入库操作")
user_name = _get_user_name(db, user_id)
@@ -1058,6 +1108,54 @@ def store_sample(
return rev
def unstore_sample(
db: Session,
review_id: str,
*,
tenant_no: str,
user_id: str,
) -> BizStorageReleaseReview:
rev = (
db.query(BizStorageReleaseReview)
.filter(
BizStorageReleaseReview.id == review_id,
BizStorageReleaseReview.tenant_no == tenant_no,
BizStorageReleaseReview.del_flag == 0,
)
.first()
)
if not rev:
raise ValueError("审核记录不存在")
if (rev.storage_status or "") != "yrk":
return rev
rev.storage_status = "drk"
rev.storage_by = None
rev.storage_by_name = None
rev.storage_time = None
rev.update_by = user_id
rev.update_time = datetime.now()
db.add(rev)
if (rev.reception_source or "cell_storage") == "cell_storage":
sample_code = (rev.sample_code or "").strip()
if sample_code:
ps = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.sample_code == sample_code,
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
)
.first()
)
if ps and (ps.sample_status or "") == "yrk":
ps.sample_status = "jcz"
ps.storage_in_date = None
ps.update_time = datetime.now()
db.add(ps)
db.flush()
return rev
def batch_store_samples(
db: Session,
ids: List[str],
@@ -1116,7 +1214,7 @@ def get_storage_release_map_for_samples(
if not code:
continue
rev = code_to_review.get(code)
if not rev or not (rev.review_conclusion or "").strip():
if not rev:
continue
rc = rev.review_conclusion or ""
out[sid] = {
@@ -1126,5 +1224,19 @@ def get_storage_release_map_for_samples(
"reviewTime": _fmt_dt(rev.review_time),
"reviewRemark": rev.review_remark or "",
"reviewAttachments": rev.review_attachments or "",
"qcReviewConclusion": rev.qc_review_conclusion or "",
"qcReviewConclusionLabel": _REVIEW_CONCLUSION_LABELS.get(rev.qc_review_conclusion or "", rev.qc_review_conclusion or ""),
"qcReviewByName": rev.qc_review_by_name or "",
"qcReviewTime": _fmt_dt(rev.qc_review_time),
"qcReviewRemark": rev.qc_review_remark or "",
"qcReviewAttachments": rev.qc_review_attachments or "",
"prodReviewConclusion": rev.prod_review_conclusion or "",
"prodReviewConclusionLabel": _REVIEW_CONCLUSION_LABELS.get(rev.prod_review_conclusion or "", rev.prod_review_conclusion or ""),
"prodReviewByName": rev.prod_review_by_name or "",
"prodReviewTime": _fmt_dt(rev.prod_review_time),
"prodReviewRemark": rev.prod_review_remark or "",
"prodReviewAttachments": rev.prod_review_attachments or "",
"storageStatus": rev.storage_status or "drk",
"storageStatusLabel": _STORAGE_STATUS_LABELS.get(rev.storage_status or "drk", rev.storage_status or "drk"),
}
return out