|
|
@@ -687,12 +687,13 @@ def sync_plan_legacy_from_stops(
|
|
|
plan.destination_notes = first.notes
|
|
|
|
|
|
|
|
|
-def _soft_delete_plan_stops(
|
|
|
+def _soft_delete_load_products_and_stop_contracts(
|
|
|
db: Session,
|
|
|
tenant_no: str,
|
|
|
plan_id: str,
|
|
|
user_id: Optional[str],
|
|
|
) -> None:
|
|
|
+ """软删装货产品与装/送货段合同;送货段本体由 upsert 保留主键,不在此全量软删。"""
|
|
|
now = datetime.now()
|
|
|
load_ids = [
|
|
|
row.id
|
|
|
@@ -710,28 +711,6 @@ def _soft_delete_plan_stops(
|
|
|
PlPlanLoadProduct.del_flag == 0,
|
|
|
).update({"del_flag": 1, "update_by": user_id, "update_time": now}, synchronize_session=False)
|
|
|
|
|
|
- delivery_ids = [
|
|
|
- row.id
|
|
|
- for row in db.query(PlPlanDelivery)
|
|
|
- .filter(
|
|
|
- PlPlanDelivery.plan_id == plan_id,
|
|
|
- PlPlanDelivery.tenant_no == tenant_no,
|
|
|
- PlPlanDelivery.del_flag == 0,
|
|
|
- )
|
|
|
- .all()
|
|
|
- ]
|
|
|
- if delivery_ids:
|
|
|
- db.query(PlPlanDeliveryProduct).filter(
|
|
|
- PlPlanDeliveryProduct.delivery_id.in_(delivery_ids),
|
|
|
- PlPlanDeliveryProduct.del_flag == 0,
|
|
|
- ).update({"del_flag": 1, "update_by": user_id, "update_time": now}, synchronize_session=False)
|
|
|
-
|
|
|
- db.query(PlPlanDelivery).filter(
|
|
|
- PlPlanDelivery.plan_id == plan_id,
|
|
|
- PlPlanDelivery.tenant_no == tenant_no,
|
|
|
- PlPlanDelivery.del_flag == 0,
|
|
|
- ).update({"del_flag": 1, "update_by": user_id, "update_time": now}, synchronize_session=False)
|
|
|
-
|
|
|
db.query(PlPlanContract).filter(
|
|
|
PlPlanContract.plan_id == plan_id,
|
|
|
PlPlanContract.tenant_no == tenant_no,
|
|
|
@@ -742,6 +721,35 @@ def _soft_delete_plan_stops(
|
|
|
).update({"del_flag": 1, "update_by": user_id, "update_time": now}, synchronize_session=False)
|
|
|
|
|
|
|
|
|
+def _soft_delete_delivery_products(
|
|
|
+ db: Session,
|
|
|
+ delivery_ids: list[str],
|
|
|
+ user_id: Optional[str],
|
|
|
+ now: datetime,
|
|
|
+) -> None:
|
|
|
+ if not delivery_ids:
|
|
|
+ return
|
|
|
+ db.query(PlPlanDeliveryProduct).filter(
|
|
|
+ PlPlanDeliveryProduct.delivery_id.in_(delivery_ids),
|
|
|
+ PlPlanDeliveryProduct.del_flag == 0,
|
|
|
+ ).update({"del_flag": 1, "update_by": user_id, "update_time": now}, synchronize_session=False)
|
|
|
+
|
|
|
+
|
|
|
+def resolve_delivery_id_for_upsert(
|
|
|
+ *,
|
|
|
+ plan_id: str,
|
|
|
+ payload_id: Optional[str],
|
|
|
+ existing_by_id: dict,
|
|
|
+) -> tuple[str, Optional[object]]:
|
|
|
+ pid = (payload_id or "").strip()
|
|
|
+ if not pid:
|
|
|
+ return generate_uuid(), None
|
|
|
+ row = existing_by_id.get(pid)
|
|
|
+ if row is None or getattr(row, "plan_id", None) != plan_id:
|
|
|
+ raise HTTPException(status_code=422, detail=f"送货段 id 无效或不属于本计划:{pid}")
|
|
|
+ return pid, row
|
|
|
+
|
|
|
+
|
|
|
def _write_stop_contracts(
|
|
|
db: Session,
|
|
|
tenant_no: str,
|
|
|
@@ -884,7 +892,7 @@ def replace_plan_stops(
|
|
|
dept_id: Optional[str],
|
|
|
plan_products: Optional[list] = None,
|
|
|
) -> None:
|
|
|
- _soft_delete_plan_stops(db, tenant_no, plan_id, user_id)
|
|
|
+ _soft_delete_load_products_and_stop_contracts(db, tenant_no, plan_id, user_id)
|
|
|
now = datetime.now()
|
|
|
|
|
|
load_id = _resolve_or_create_plan_load(
|
|
|
@@ -940,6 +948,17 @@ def replace_plan_stops(
|
|
|
contract_order,
|
|
|
)
|
|
|
|
|
|
+ existing_deliveries = (
|
|
|
+ db.query(PlPlanDelivery)
|
|
|
+ .filter(
|
|
|
+ PlPlanDelivery.plan_id == plan_id,
|
|
|
+ PlPlanDelivery.tenant_no == tenant_no,
|
|
|
+ )
|
|
|
+ .all()
|
|
|
+ )
|
|
|
+ existing_by_id = {row.id: row for row in existing_deliveries}
|
|
|
+ kept_ids: set[str] = set()
|
|
|
+
|
|
|
for delivery in deliveries:
|
|
|
generate_dibang, dibang_direction = normalize_stop_dibang_fields(
|
|
|
delivery.customer_name,
|
|
|
@@ -948,32 +967,57 @@ def replace_plan_stops(
|
|
|
delivery.dibang_direction,
|
|
|
)
|
|
|
|
|
|
- delivery_id = generate_uuid()
|
|
|
- db.add(
|
|
|
- PlPlanDelivery(
|
|
|
- id=delivery_id,
|
|
|
- plan_id=plan_id,
|
|
|
- seq=delivery.seq or 1,
|
|
|
- customer_id=delivery.customer_id,
|
|
|
- customer_name=delivery.customer_name,
|
|
|
- address=delivery.address,
|
|
|
- lng=delivery.lng,
|
|
|
- lat=delivery.lat,
|
|
|
- delivery_time=delivery.delivery_time,
|
|
|
- contact=delivery.contact,
|
|
|
- notes=delivery.notes,
|
|
|
- generate_dibang=generate_dibang,
|
|
|
- dibang_direction=dibang_direction,
|
|
|
- tenant_no=tenant_no,
|
|
|
- remark=delivery.remark,
|
|
|
- create_by=user_id,
|
|
|
- create_dept_id=dept_id or "",
|
|
|
- create_time=now,
|
|
|
- update_by=user_id,
|
|
|
- update_time=now,
|
|
|
- del_flag=0,
|
|
|
- )
|
|
|
+ delivery_id, existing = resolve_delivery_id_for_upsert(
|
|
|
+ plan_id=plan_id,
|
|
|
+ payload_id=delivery.id,
|
|
|
+ existing_by_id=existing_by_id,
|
|
|
)
|
|
|
+ kept_ids.add(delivery_id)
|
|
|
+
|
|
|
+ if existing is not None:
|
|
|
+ existing.seq = delivery.seq or 1
|
|
|
+ existing.customer_id = delivery.customer_id
|
|
|
+ existing.customer_name = delivery.customer_name
|
|
|
+ existing.address = delivery.address
|
|
|
+ existing.lng = delivery.lng
|
|
|
+ existing.lat = delivery.lat
|
|
|
+ existing.delivery_time = delivery.delivery_time
|
|
|
+ existing.contact = delivery.contact
|
|
|
+ existing.notes = delivery.notes
|
|
|
+ existing.generate_dibang = generate_dibang
|
|
|
+ existing.dibang_direction = dibang_direction
|
|
|
+ existing.remark = delivery.remark
|
|
|
+ existing.del_flag = 0
|
|
|
+ existing.update_by = user_id
|
|
|
+ existing.update_time = now
|
|
|
+ else:
|
|
|
+ db.add(
|
|
|
+ PlPlanDelivery(
|
|
|
+ id=delivery_id,
|
|
|
+ plan_id=plan_id,
|
|
|
+ seq=delivery.seq or 1,
|
|
|
+ customer_id=delivery.customer_id,
|
|
|
+ customer_name=delivery.customer_name,
|
|
|
+ address=delivery.address,
|
|
|
+ lng=delivery.lng,
|
|
|
+ lat=delivery.lat,
|
|
|
+ delivery_time=delivery.delivery_time,
|
|
|
+ contact=delivery.contact,
|
|
|
+ notes=delivery.notes,
|
|
|
+ generate_dibang=generate_dibang,
|
|
|
+ dibang_direction=dibang_direction,
|
|
|
+ tenant_no=tenant_no,
|
|
|
+ remark=delivery.remark,
|
|
|
+ create_by=user_id,
|
|
|
+ create_dept_id=dept_id or "",
|
|
|
+ create_time=now,
|
|
|
+ update_by=user_id,
|
|
|
+ update_time=now,
|
|
|
+ del_flag=0,
|
|
|
+ )
|
|
|
+ )
|
|
|
+
|
|
|
+ _soft_delete_delivery_products(db, [delivery_id], user_id, now)
|
|
|
|
|
|
for idx, prod in enumerate(delivery.products or []):
|
|
|
plan_product_id = _resolve_plan_product_id(prod, plan_product_rows)
|
|
|
@@ -1014,3 +1058,12 @@ def replace_plan_stops(
|
|
|
dept_id,
|
|
|
contract_order,
|
|
|
)
|
|
|
+
|
|
|
+ removed_ids = [row.id for row in existing_deliveries if row.id not in kept_ids and row.del_flag == 0]
|
|
|
+ if removed_ids:
|
|
|
+ _soft_delete_delivery_products(db, removed_ids, user_id, now)
|
|
|
+ db.query(PlPlanDelivery).filter(
|
|
|
+ PlPlanDelivery.id.in_(removed_ids),
|
|
|
+ PlPlanDelivery.tenant_no == tenant_no,
|
|
|
+ PlPlanDelivery.del_flag == 0,
|
|
|
+ ).update({"del_flag": 1, "update_by": user_id, "update_time": now}, synchronize_session=False)
|