"""保留成功读取实际观察到的当前版本,不把历史最大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 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