|
|
@@ -455,10 +455,177 @@ def get_freight_detail(db: Session, freight_id: str, tenant_no: str) -> Dict[str
|
|
|
linked_sample_count=len(items),
|
|
|
transport_mode_label=labels.get(obj.transport_mode or "", obj.transport_mode or ""),
|
|
|
)
|
|
|
- data["items"] = [_item_to_dict(i) for i in items]
|
|
|
+ protocol_no_map, type_name_map = _enrich_items_maps(db, items, tenant_no)
|
|
|
+ enriched = []
|
|
|
+ for i in items:
|
|
|
+ key = f"{i.sample_source}|{i.sample_id}"
|
|
|
+ enriched.append(
|
|
|
+ _item_to_dict_enriched(
|
|
|
+ i,
|
|
|
+ protocol_no=protocol_no_map.get(key, ""),
|
|
|
+ sample_type_name=type_name_map.get(key, ""),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ data["items"] = enriched
|
|
|
return data
|
|
|
|
|
|
|
|
|
+def list_sample_options(
|
|
|
+ db: Session,
|
|
|
+ *,
|
|
|
+ tenant_no: str,
|
|
|
+ page: int = 1,
|
|
|
+ page_size: int = 20,
|
|
|
+ keyword: Optional[str] = None,
|
|
|
+ sample_source: Optional[str] = None,
|
|
|
+) -> Tuple[List[Dict[str, Any]], int]:
|
|
|
+ """可选样本列表(配置运费弹窗),支持细胞存储 / 科研捐赠。"""
|
|
|
+ page = max(1, int(page or 1))
|
|
|
+ page_size = max(1, min(100, int(page_size or 20)))
|
|
|
+ src = (sample_source or "").strip() or None
|
|
|
+ if src and src not in (SAMPLE_SOURCE_CELL, SAMPLE_SOURCE_DONATION):
|
|
|
+ raise ValueError("sampleSource 无效")
|
|
|
+ kw = (keyword or "").strip()
|
|
|
+ like = f"%{kw}%" if kw else None
|
|
|
+
|
|
|
+ rows: List[Dict[str, Any]] = []
|
|
|
+
|
|
|
+ if src in (None, SAMPLE_SOURCE_CELL):
|
|
|
+ cq = (
|
|
|
+ db.query(
|
|
|
+ BizProtocolSample.id,
|
|
|
+ BizProtocolSample.sample_code,
|
|
|
+ BizProtocolSample.collection_protocol_id,
|
|
|
+ BizProtocolSample.create_time,
|
|
|
+ BizCollectionProtocol.protocol_no,
|
|
|
+ BizCellSampleType.type_name,
|
|
|
+ )
|
|
|
+ .outerjoin(
|
|
|
+ BizCollectionProtocol,
|
|
|
+ and_(
|
|
|
+ BizCollectionProtocol.id
|
|
|
+ == BizProtocolSample.collection_protocol_id,
|
|
|
+ BizCollectionProtocol.del_flag == 0,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .outerjoin(
|
|
|
+ BizCellSampleType,
|
|
|
+ and_(
|
|
|
+ BizCellSampleType.id == BizProtocolSample.sample_type_id,
|
|
|
+ BizCellSampleType.del_flag == 0,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .filter(
|
|
|
+ BizProtocolSample.tenant_no == tenant_no,
|
|
|
+ BizProtocolSample.del_flag == 0,
|
|
|
+ )
|
|
|
+ )
|
|
|
+ if like:
|
|
|
+ cq = cq.filter(
|
|
|
+ or_(
|
|
|
+ BizProtocolSample.sample_code.like(like),
|
|
|
+ BizCollectionProtocol.protocol_no.like(like),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ for sid, scode, pid, ctime, pno, tname in cq.all():
|
|
|
+ rows.append(
|
|
|
+ {
|
|
|
+ "sampleSource": SAMPLE_SOURCE_CELL,
|
|
|
+ "sampleId": sid,
|
|
|
+ "sampleCode": scode or "",
|
|
|
+ "protocolId": pid or "",
|
|
|
+ "protocolNo": pno or "",
|
|
|
+ "sampleTypeName": tname or "",
|
|
|
+ "createTime": ctime,
|
|
|
+ "freightId": "",
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ if src in (None, SAMPLE_SOURCE_DONATION):
|
|
|
+ dq = (
|
|
|
+ db.query(
|
|
|
+ BizResearchDonationSample.id,
|
|
|
+ BizResearchDonationSample.sample_code,
|
|
|
+ BizResearchDonationSample.research_donation_id,
|
|
|
+ BizResearchDonationSample.create_time,
|
|
|
+ BizResearchDonation.donation_no,
|
|
|
+ BizCellSampleType.type_name,
|
|
|
+ )
|
|
|
+ .outerjoin(
|
|
|
+ BizResearchDonation,
|
|
|
+ and_(
|
|
|
+ BizResearchDonation.id
|
|
|
+ == BizResearchDonationSample.research_donation_id,
|
|
|
+ BizResearchDonation.del_flag == 0,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .outerjoin(
|
|
|
+ BizCellSampleType,
|
|
|
+ and_(
|
|
|
+ BizCellSampleType.id == BizResearchDonationSample.sample_type_id,
|
|
|
+ BizCellSampleType.del_flag == 0,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .filter(
|
|
|
+ BizResearchDonationSample.tenant_no == tenant_no,
|
|
|
+ BizResearchDonationSample.del_flag == 0,
|
|
|
+ )
|
|
|
+ )
|
|
|
+ if like:
|
|
|
+ dq = dq.filter(
|
|
|
+ or_(
|
|
|
+ BizResearchDonationSample.sample_code.like(like),
|
|
|
+ BizResearchDonation.donation_no.like(like),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ for sid, scode, pid, ctime, dno, tname in dq.all():
|
|
|
+ rows.append(
|
|
|
+ {
|
|
|
+ "sampleSource": SAMPLE_SOURCE_DONATION,
|
|
|
+ "sampleId": sid,
|
|
|
+ "sampleCode": scode or "",
|
|
|
+ "protocolId": pid or "",
|
|
|
+ "protocolNo": dno or "",
|
|
|
+ "sampleTypeName": tname or "",
|
|
|
+ "createTime": ctime,
|
|
|
+ "freightId": "",
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ # 左连当前运费关联
|
|
|
+ if rows:
|
|
|
+ sample_ids = [r["sampleId"] for r in rows]
|
|
|
+ link_rows = (
|
|
|
+ db.query(
|
|
|
+ BizSampleFreightItem.sample_source,
|
|
|
+ BizSampleFreightItem.sample_id,
|
|
|
+ BizSampleFreightItem.freight_id,
|
|
|
+ )
|
|
|
+ .filter(
|
|
|
+ BizSampleFreightItem.tenant_no == tenant_no,
|
|
|
+ BizSampleFreightItem.del_flag == 0,
|
|
|
+ BizSampleFreightItem.sample_id.in_(sample_ids),
|
|
|
+ )
|
|
|
+ .all()
|
|
|
+ )
|
|
|
+ freight_map = {
|
|
|
+ f"{src_}|{sid}": fid for src_, sid, fid in link_rows if src_ and sid and fid
|
|
|
+ }
|
|
|
+ for r in rows:
|
|
|
+ r["freightId"] = freight_map.get(f"{r['sampleSource']}|{r['sampleId']}", "") or ""
|
|
|
+
|
|
|
+ rows.sort(
|
|
|
+ key=lambda r: (r["createTime"] or datetime.min, r["sampleId"]),
|
|
|
+ reverse=True,
|
|
|
+ )
|
|
|
+ total = len(rows)
|
|
|
+ start = (page - 1) * page_size
|
|
|
+ page_rows = rows[start : start + page_size]
|
|
|
+ for r in page_rows:
|
|
|
+ r["createTime"] = _fmt_dt(r.get("createTime"))
|
|
|
+ return page_rows, total
|
|
|
+
|
|
|
+
|
|
|
def _upsert_item(
|
|
|
db: Session,
|
|
|
*,
|