1 parent
96468f3c48
commit
bd669ea77e
2 files changed
+170
-5
No files matched your search
@@ -949,11 +949,13 @@ def link_samples(
|
||||
items: List[Dict[str, Any]],
|
||||
commit: bool = True,
|
||||
user_info: Optional[dict] = None,
|
||||
allow_settled_relink: bool = False,
|
||||
) -> Dict[str, Any]:
|
||||
header = get_freight(db, freight_id, tenant_no, user_info)
|
||||
if not header:
|
||||
raise ValueError("运费批次不存在")
|
||||
assert_freight_mutable(header.settle_status, "items")
|
||||
if not allow_settled_relink:
|
||||
assert_freight_mutable(header.settle_status, "items")
|
||||
if not items:
|
||||
raise ValueError("请选择要关联的样本")
|
||||
if user_info is not None:
|
||||
@@ -1156,6 +1158,16 @@ def freight_map_for_samples(
|
||||
return out
|
||||
|
||||
|
||||
def _input_freight_id(raw: Any) -> str:
|
||||
if not isinstance(raw, dict):
|
||||
return ""
|
||||
nested = raw.get("freight") if isinstance(raw.get("freight"), dict) else {}
|
||||
return (
|
||||
str(raw.get("freightId") or raw.get("freight_id") or "").strip()
|
||||
or str(nested.get("id") or "").strip()
|
||||
)
|
||||
|
||||
|
||||
def apply_freight_on_protocol_save(
|
||||
db: Session,
|
||||
*,
|
||||
@@ -1190,6 +1202,34 @@ def apply_freight_on_protocol_save(
|
||||
)
|
||||
now = _now()
|
||||
affected_freight_ids = {item.freight_id for item in stale_items}
|
||||
stale_by_freight: Dict[str, List[BizSampleFreightItem]] = {}
|
||||
for item in stale_items:
|
||||
stale_by_freight.setdefault(item.freight_id, []).append(item)
|
||||
settled_relink_ids = set()
|
||||
if stale_by_freight:
|
||||
headers = (
|
||||
db.query(BizSampleFreight)
|
||||
.filter(
|
||||
BizSampleFreight.id.in_(list(stale_by_freight.keys())),
|
||||
BizSampleFreight.tenant_no == tenant_no,
|
||||
BizSampleFreight.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
header_by_id = {row.id: row for row in headers}
|
||||
for freight_id, grouped in stale_by_freight.items():
|
||||
header = header_by_id.get(freight_id)
|
||||
if header is None or (header.settle_status or "") != "yjs":
|
||||
continue
|
||||
stale_count = len(grouped)
|
||||
keep_count = sum(
|
||||
1
|
||||
for raw in (input_samples or [])
|
||||
if _input_freight_id(raw) == freight_id
|
||||
)
|
||||
if keep_count != stale_count:
|
||||
raise ValueError("已结算的运费不能调整样本")
|
||||
settled_relink_ids.add(freight_id)
|
||||
for stale in stale_items:
|
||||
stale.del_flag = 1
|
||||
stale.update_by = user_id
|
||||
@@ -1218,10 +1258,7 @@ def apply_freight_on_protocol_save(
|
||||
"protocolId": protocol_id,
|
||||
"sampleCode": sample_code,
|
||||
}
|
||||
freight_id = (
|
||||
str(raw.get("freightId") or raw.get("freight_id") or "").strip()
|
||||
or str((raw.get("freight") or {}).get("id") or "").strip()
|
||||
)
|
||||
freight_id = _input_freight_id(raw)
|
||||
draft = raw.get("freightDraft")
|
||||
if draft is None:
|
||||
draft = raw.get("freight_draft")
|
||||
@@ -1233,6 +1270,7 @@ def apply_freight_on_protocol_save(
|
||||
user_id=user_id,
|
||||
items=[item],
|
||||
commit=False,
|
||||
allow_settled_relink=freight_id in settled_relink_ids,
|
||||
)
|
||||
continue
|
||||
if isinstance(draft, dict):
|
||||
@@ -1281,6 +1319,7 @@ def apply_freight_on_protocol_save(
|
||||
.first()
|
||||
)
|
||||
if freight is not None:
|
||||
assert_freight_mutable(freight.settle_status, "delete")
|
||||
freight.del_flag = 1
|
||||
freight.update_by = user_id
|
||||
freight.update_time = now
|
||||
|
||||
@@ -259,3 +259,129 @@ def test_admin_and_market_bodies_accept_sf_without_amount():
|
||||
})
|
||||
assert draft.waybill_no == "SF100"
|
||||
MarketFreightUpdateBody.model_validate({"waybillNo": "SF100"})
|
||||
|
||||
|
||||
def _protocol_freight_db():
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from app.models.base import Base
|
||||
from app.models.models import (
|
||||
BizCellSampleType,
|
||||
BizCollectionProtocol,
|
||||
BizProtocolPartyCustomer,
|
||||
BizProtocolSample,
|
||||
BizSampleFreight,
|
||||
BizSampleFreightItem,
|
||||
SysDictData,
|
||||
)
|
||||
|
||||
engine = create_engine("sqlite:///:memory:")
|
||||
Base.metadata.create_all(
|
||||
engine,
|
||||
tables=[
|
||||
BizSampleFreight.__table__,
|
||||
BizSampleFreightItem.__table__,
|
||||
BizProtocolSample.__table__,
|
||||
BizCollectionProtocol.__table__,
|
||||
BizCellSampleType.__table__,
|
||||
BizProtocolPartyCustomer.__table__,
|
||||
SysDictData.__table__,
|
||||
],
|
||||
)
|
||||
return sessionmaker(bind=engine)()
|
||||
|
||||
|
||||
def _seed_settled_protocol_freight(db, sample_id="s-old"):
|
||||
from app.models.models import BizSampleFreight, BizSampleFreightItem
|
||||
|
||||
now = datetime(2026, 10, 21, 9, 0, 0)
|
||||
freight = BizSampleFreight(
|
||||
id="f-yjs",
|
||||
freight_no="YF1",
|
||||
transport_mode="sfkd",
|
||||
freight_amount=None,
|
||||
waybill_no="SF001",
|
||||
settle_status="yjs",
|
||||
tenant_no="tenant-a",
|
||||
create_dept_id="",
|
||||
create_time=now,
|
||||
update_time=now,
|
||||
del_flag=0,
|
||||
)
|
||||
item = BizSampleFreightItem(
|
||||
id="fi-1",
|
||||
freight_id=freight.id,
|
||||
sample_source="cell_storage",
|
||||
sample_id=sample_id,
|
||||
sample_code="C1",
|
||||
protocol_id="p1",
|
||||
tenant_no="tenant-a",
|
||||
create_dept_id="",
|
||||
create_time=now,
|
||||
update_time=now,
|
||||
del_flag=0,
|
||||
)
|
||||
db.add_all([freight, item])
|
||||
db.commit()
|
||||
return freight, item
|
||||
|
||||
|
||||
def test_settled_protocol_save_without_freight_id_keeps_links():
|
||||
from types import SimpleNamespace
|
||||
|
||||
from app.crud.sample_freight import apply_freight_on_protocol_save
|
||||
from app.models.models import BizSampleFreight, BizSampleFreightItem
|
||||
|
||||
db = _protocol_freight_db()
|
||||
freight, item = _seed_settled_protocol_freight(db)
|
||||
try:
|
||||
with pytest.raises(ValueError, match="已结算的运费不能调整样本"):
|
||||
apply_freight_on_protocol_save(
|
||||
db,
|
||||
tenant_no="tenant-a",
|
||||
user_id="u1",
|
||||
sample_source="cell_storage",
|
||||
protocol_id="p1",
|
||||
saved_samples=[SimpleNamespace(id="s-new", sample_code="C2")],
|
||||
input_samples=[{}],
|
||||
)
|
||||
db.expire_all()
|
||||
item = db.query(BizSampleFreightItem).filter_by(id=item.id).one()
|
||||
freight = db.query(BizSampleFreight).filter_by(id=freight.id).one()
|
||||
assert item.del_flag == 0
|
||||
assert freight.del_flag == 0
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_settled_protocol_save_relinks_same_count_to_new_sample():
|
||||
from types import SimpleNamespace
|
||||
|
||||
from app.crud.sample_freight import apply_freight_on_protocol_save
|
||||
from app.models.models import BizSampleFreight, BizSampleFreightItem
|
||||
|
||||
db = _protocol_freight_db()
|
||||
freight, _item = _seed_settled_protocol_freight(db)
|
||||
try:
|
||||
apply_freight_on_protocol_save(
|
||||
db,
|
||||
tenant_no="tenant-a",
|
||||
user_id="u1",
|
||||
sample_source="cell_storage",
|
||||
protocol_id="p1",
|
||||
saved_samples=[SimpleNamespace(id="s-new", sample_code="C2")],
|
||||
input_samples=[{"freightId": freight.id}],
|
||||
)
|
||||
db.expire_all()
|
||||
freight = db.query(BizSampleFreight).filter_by(id=freight.id).one()
|
||||
assert freight.del_flag == 0
|
||||
assert freight.settle_status == "yjs"
|
||||
live = (
|
||||
db.query(BizSampleFreightItem)
|
||||
.filter_by(freight_id=freight.id, sample_id="s-new", del_flag=0)
|
||||
.one()
|
||||
)
|
||||
assert live.protocol_id == "p1"
|
||||
finally:
|
||||
db.close()
|
||||
Reference in new issue
Block a user