feat: 添加线索引擎、NLQ、场景检测、前端界面等核心功能模块
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
"""R8 适配器:政企收入全链路穿透 / 拆单规避。
|
||||
|
||||
源明细:SrcContract / SrcContractApproval / SrcPayment
|
||||
映射到:Entity(CONTRACT, CUSTOMER, ACCOUNT, ADDRESS, LEGAL_PERSON) + 关系 + MetricEvent
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.datahub.graph_repo import add_relationship, upsert_entity
|
||||
from app.datahub.models import MetricEvent
|
||||
from app.datahub.ontology import EntityType, RelationshipType
|
||||
from app.datahub.staging import SrcContract, SrcContractApproval, SrcPayment
|
||||
from app.ingest.base import BaseAdapter, IngestResult
|
||||
from app.ingest.registry import register_adapter
|
||||
|
||||
|
||||
@register_adapter
|
||||
class ContractAdapter(BaseAdapter):
|
||||
"""SrcContract → Entity(CONTRACT, CUSTOMER, ACCOUNT, ADDRESS, LEGAL_PERSON) + 关系。"""
|
||||
|
||||
source_system = "CONTRACT"
|
||||
staging_table = "src_contract"
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
session: Session,
|
||||
data_version_id: uuid.UUID | None = None,
|
||||
batch_size: int = 1000,
|
||||
) -> IngestResult:
|
||||
result = IngestResult()
|
||||
query = session.query(SrcContract)
|
||||
if data_version_id:
|
||||
query = query.filter(SrcContract.data_version_id == data_version_id)
|
||||
rows = query.limit(batch_size).all()
|
||||
|
||||
for row in rows:
|
||||
try:
|
||||
# 合同实体
|
||||
contract_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.CONTRACT,
|
||||
business_key=row.contract_no,
|
||||
display_name=f"合同-{row.contract_no}",
|
||||
attributes={
|
||||
"amount": row.amount,
|
||||
"sign_date": str(row.sign_date) if row.sign_date else None,
|
||||
"approval_threshold": row.approval_threshold,
|
||||
"approval_level": row.approval_level,
|
||||
},
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(contract_entity)
|
||||
|
||||
# 客户实体 + 签约关系
|
||||
cust_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.CUSTOMER,
|
||||
business_key=row.customer_key,
|
||||
display_name=row.customer_name,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(cust_entity)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.SIGNED, cust_entity, contract_entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
# 回款账户 → Entity(ACCOUNT) + 关系 PAID_BY
|
||||
if row.pay_account:
|
||||
acct_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.ACCOUNT,
|
||||
business_key=row.pay_account,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(acct_entity)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.PAID_BY, contract_entity, acct_entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
# 注册地址
|
||||
if row.register_address:
|
||||
addr_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.ADDRESS,
|
||||
business_key=row.register_address,
|
||||
display_name=row.register_address,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.REGISTERED_AT, cust_entity, addr_entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
# 法人
|
||||
if row.legal_person:
|
||||
lp_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.LEGAL_PERSON,
|
||||
business_key=row.legal_person,
|
||||
display_name=row.legal_person,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.LEGAL_REP_OF, lp_entity, cust_entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
result.row_count += 1
|
||||
except Exception:
|
||||
result.error_count += 1
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@register_adapter
|
||||
class ContractApprovalAdapter(BaseAdapter):
|
||||
"""SrcContractApproval → MetricEvent(审批时序事件)。"""
|
||||
|
||||
source_system = "CONTRACT"
|
||||
staging_table = "src_contract_approval"
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
session: Session,
|
||||
data_version_id: uuid.UUID | None = None,
|
||||
batch_size: int = 1000,
|
||||
) -> IngestResult:
|
||||
result = IngestResult()
|
||||
query = session.query(SrcContractApproval)
|
||||
if data_version_id:
|
||||
query = query.filter(SrcContractApproval.data_version_id == data_version_id)
|
||||
rows = query.limit(batch_size).all()
|
||||
|
||||
for row in rows:
|
||||
try:
|
||||
if row.approval_time:
|
||||
event = MetricEvent(
|
||||
event_time=row.approval_time,
|
||||
subject_type="contract",
|
||||
subject_key=row.contract_no,
|
||||
metric_name="approval_step",
|
||||
metric_value=float(row.approval_step),
|
||||
attributes={
|
||||
"approver": row.approver,
|
||||
"result": row.approval_result,
|
||||
"remark": row.remark,
|
||||
},
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
session.add(event)
|
||||
result.metric_events.append(event)
|
||||
result.row_count += 1
|
||||
except Exception:
|
||||
result.error_count += 1
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@register_adapter
|
||||
class PaymentAdapter(BaseAdapter):
|
||||
"""SrcPayment → MetricEvent(回款时序事件) + 关系补强。"""
|
||||
|
||||
source_system = "FIN"
|
||||
staging_table = "src_payment"
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
session: Session,
|
||||
data_version_id: uuid.UUID | None = None,
|
||||
batch_size: int = 1000,
|
||||
) -> IngestResult:
|
||||
result = IngestResult()
|
||||
query = session.query(SrcPayment)
|
||||
if data_version_id:
|
||||
query = query.filter(SrcPayment.data_version_id == data_version_id)
|
||||
rows = query.limit(batch_size).all()
|
||||
|
||||
for row in rows:
|
||||
try:
|
||||
if row.pay_date:
|
||||
import datetime as dt
|
||||
|
||||
event_time = dt.datetime.combine(
|
||||
row.pay_date, dt.time.min, tzinfo=dt.timezone.utc
|
||||
)
|
||||
event = MetricEvent(
|
||||
event_time=event_time,
|
||||
subject_type="contract",
|
||||
subject_key=row.contract_no,
|
||||
metric_name="payment",
|
||||
metric_value=row.pay_amount,
|
||||
attributes={
|
||||
"pay_account": row.pay_account,
|
||||
"pay_type": row.pay_type,
|
||||
"overdue_flag": row.overdue_flag,
|
||||
},
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
session.add(event)
|
||||
result.metric_events.append(event)
|
||||
|
||||
# 强化合同→账户关系
|
||||
if row.pay_account:
|
||||
contract_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.CONTRACT,
|
||||
business_key=row.contract_no,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
acct_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.ACCOUNT,
|
||||
business_key=row.pay_account,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.PAID_BY, contract_entity, acct_entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
result.row_count += 1
|
||||
except Exception:
|
||||
result.error_count += 1
|
||||
|
||||
return result
|
||||
Reference in New Issue
Block a user