Parcourir la source

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 <cursoragent@cursor.com>
zlwu il y a 3 mois
Parent
commit
8b18d21c88
1 fichiers modifiés avec 109 ajouts et 0 suppressions
  1. 109 0
      backend/app/crud/storage_release_review.py

+ 109 - 0
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)