2026-11-01 20:42:53 -05:00
|
|
|
|
"""保留成功读取实际观察到的当前版本,不把历史最大ID当成当前值。"""
|
|
|
|
|
|
|
|
|
|
|
|
from sqlalchemy import inspect, select, tuple_
|
|
|
|
|
|
|
|
|
|
|
|
from app.models import TPlusSourceHead, TPlusSyncRecord
|
|
|
|
|
|
from app.services.tplus.staging import prepare_row
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def observe_rows(session, batch, mapping, rows):
|
|
|
|
|
|
"""每页提交前记录所有读到的源版本,包括去重跳过的 A→B→A。"""
|
|
|
|
|
|
# V15 运行中的升级窗口继续允许原读取功能;工作区本身要求 V16。
|
|
|
|
|
|
if not inspect(session.connection()).has_table(TPlusSourceHead.__tablename__):
|
|
|
|
|
|
return
|
|
|
|
|
|
prepared = [
|
|
|
|
|
|
prepare_row(batch.batch_no, mapping.entity_type, mapping.source_table, r)
|
|
|
|
|
|
for r in rows
|
|
|
|
|
|
if r.get("id") is not None
|
|
|
|
|
|
]
|
|
|
|
|
|
wanted = [(r["source_id"], r["row_hash"]) for r in prepared]
|
|
|
|
|
|
if not wanted:
|
|
|
|
|
|
return
|
|
|
|
|
|
records = {
|
|
|
|
|
|
(r.source_id, r.row_hash): r.id
|
|
|
|
|
|
for r in session.scalars(
|
|
|
|
|
|
select(TPlusSyncRecord).where(
|
|
|
|
|
|
TPlusSyncRecord.entity_type == mapping.entity_type,
|
|
|
|
|
|
tuple_(TPlusSyncRecord.source_id, TPlusSyncRecord.row_hash).in_(wanted),
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
source = batch.source_database
|
|
|
|
|
|
if not source:
|
|
|
|
|
|
raise ValueError("源账套身份缺失,不能发布当前快照")
|
|
|
|
|
|
current = {
|
|
|
|
|
|
h.source_id: h
|
|
|
|
|
|
for h in session.scalars(
|
|
|
|
|
|
select(TPlusSourceHead).where(
|
|
|
|
|
|
TPlusSourceHead.source_database == source,
|
|
|
|
|
|
TPlusSourceHead.entity_type == mapping.entity_type,
|
|
|
|
|
|
TPlusSourceHead.source_id.in_([v[0] for v in wanted]),
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
for row in prepared:
|
|
|
|
|
|
record_id = records.get((row["source_id"], row["row_hash"]))
|
|
|
|
|
|
if record_id is None:
|
|
|
|
|
|
continue
|
|
|
|
|
|
head = current.get(row["source_id"])
|
|
|
|
|
|
if head is None:
|
|
|
|
|
|
head = TPlusSourceHead(
|
|
|
|
|
|
source_database=source,
|
|
|
|
|
|
entity_type=mapping.entity_type,
|
|
|
|
|
|
source_id=row["source_id"],
|
|
|
|
|
|
record_id=record_id,
|
|
|
|
|
|
batch_no=batch.batch_no,
|
|
|
|
|
|
)
|
|
|
|
|
|
session.add(head)
|
|
|
|
|
|
current[row["source_id"]] = head
|
|
|
|
|
|
head.record_id, head.batch_no = record_id, batch.batch_no
|
2026-11-05 05:47:13 -05:00
|
|
|
|
raw = row["payload_json"]
|
|
|
|
|
|
head.source_parent_id = str(raw["source_parent_id"]) if raw.get("source_parent_id") is not None else None
|
|
|
|
|
|
customer = raw.get("idcustomer", raw.get("idpartner"))
|
|
|
|
|
|
head.source_customer_id = str(customer) if customer is not None else None
|
|
|
|
|
|
day = raw.get("voucherdate", raw.get("voucherDate"))
|
|
|
|
|
|
head.source_date = str(day)[:10] if day is not None else None
|