From 8b18d21c8814fdb315b9d201563bfb6e2bddbd62 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Wed, 29 Jul 2026 13:17:13 +0800 Subject: [PATCH] feat(storage-release): hide list rows when related docs are void Exclude reviews whose protocol is inactive or whose inbound QC/production work orders are all voided. Co-authored-by: Cursor --- backend/app/crud/storage_release_review.py | 109 +++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/backend/app/crud/storage_release_review.py b/backend/app/crud/storage_release_review.py index f93391f0..11a29313 100644 --- a/backend/app/crud/storage_release_review.py +++ b/backend/app/crud/storage_release_review.py @@ -219,6 +219,107 @@ def _production_work_order_unfinished_exists_for_review_sample(tenant_no: str): ) +def _inactive_protocol_exists_for_review(): + """True when linked collection/donation protocol is yzf or sdfq.""" + inactive_cell = and_( + or_( + BizStorageReleaseReview.reception_source == "cell_storage", + BizStorageReleaseReview.reception_source.is_(None), + BizStorageReleaseReview.reception_source == "", + ), + BizStorageReleaseReview.protocol_id.isnot(None), + BizStorageReleaseReview.protocol_id != "", + exists() + .where( + and_( + eq_unicode( + BizCollectionProtocol.id, BizStorageReleaseReview.protocol_id + ), + BizCollectionProtocol.del_flag == 0, + BizCollectionProtocol.protocol_status.in_(INACTIVE_PROTOCOL_STATUSES), + ) + ) + .correlate(BizStorageReleaseReview), + ) + inactive_donation = and_( + BizStorageReleaseReview.reception_source == "research_donation", + BizStorageReleaseReview.protocol_id.isnot(None), + BizStorageReleaseReview.protocol_id != "", + exists() + .where( + and_( + eq_unicode( + BizResearchDonation.id, BizStorageReleaseReview.protocol_id + ), + BizResearchDonation.del_flag == 0, + BizResearchDonation.donation_status.in_(INACTIVE_PROTOCOL_STATUSES), + ) + ) + .correlate(BizStorageReleaseReview), + ) + return or_(inactive_cell, inactive_donation) + + +def _inbound_qc_all_void_for_review_sample(tenant_no: str): + """True when sample has ≥1 inbound QC WO and every such WO is yzf.""" + base = [ + BizQcWorkOrder.tenant_no == tenant_no, + BizQcWorkOrder.del_flag == 0, + BizQcWorkOrder.qc_biz_type == "inbound", + BizQcWorkOrder.sample_code.isnot(None), + BizQcWorkOrder.sample_code != "", + eq_unicode(BizQcWorkOrder.sample_code, BizStorageReleaseReview.sample_code), + BizStorageReleaseReview.sample_code.isnot(None), + BizStorageReleaseReview.sample_code != "", + ] + any_inbound = exists().where(and_(*base)).correlate(BizStorageReleaseReview) + any_non_void = ( + exists() + .where( + and_( + *base, + or_( + BizQcWorkOrder.work_order_status.is_(None), + BizQcWorkOrder.work_order_status != "yzf", + ), + ) + ) + .correlate(BizStorageReleaseReview) + ) + return and_(any_inbound, ~any_non_void) + + +def _inbound_production_all_void_for_review_sample(tenant_no: str): + """True when sample has ≥1 inbound production WO and every such WO is yzf.""" + base = [ + BizProductionWorkOrder.tenant_no == tenant_no, + BizProductionWorkOrder.del_flag == 0, + BizProductionWorkOrder.work_order_type == "inbound", + BizProductionWorkOrder.sample_code.isnot(None), + BizProductionWorkOrder.sample_code != "", + eq_unicode( + BizProductionWorkOrder.sample_code, BizStorageReleaseReview.sample_code + ), + BizStorageReleaseReview.sample_code.isnot(None), + BizStorageReleaseReview.sample_code != "", + ] + any_inbound = exists().where(and_(*base)).correlate(BizStorageReleaseReview) + any_non_void = ( + exists() + .where( + and_( + *base, + or_( + BizProductionWorkOrder.work_order_status.is_(None), + BizProductionWorkOrder.work_order_status != "yzf", + ), + ) + ) + .correlate(BizStorageReleaseReview) + ) + return and_(any_inbound, ~any_non_void) + + def list_reviews( db: Session, *, @@ -303,6 +404,14 @@ def list_reviews( ), ~_production_work_order_unfinished_exists_for_review_sample(tenant_no), ) + # 协议无效 或 入库质检/生产「有工单且全部 yzf」→ 列表隐藏(两 Tab 常驻) + q0 = q0.filter( + ~or_( + _inactive_protocol_exists_for_review(), + _inbound_qc_all_void_for_review_sample(tenant_no), + _inbound_production_all_void_for_review_sample(tenant_no), + ) + ) if user_info: from app.core.data_scope import apply_data_scope q0 = apply_data_scope(q0, BizStorageReleaseReview, user_info, db, tenant_no)