|
|
@@ -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
|