"""R14 适配器:云业务 / IDC 与新兴业务。 源明细:SrcCloudUsage / SrcIdcCabinet 映射到:Entity(CONTRACT, CUSTOMER) + MetricEvent """ from __future__ import annotations import datetime as dt import uuid from sqlalchemy.orm import Session from app.datahub.graph_repo import upsert_entity from app.datahub.models import MetricEvent from app.datahub.ontology import EntityType from app.datahub.staging import SrcCloudUsage, SrcIdcCabinet from app.ingest.base import BaseAdapter, IngestResult from app.ingest.registry import register_adapter @register_adapter class CloudUsageAdapter(BaseAdapter): """SrcCloudUsage → Entity(CONTRACT) + MetricEvent(云资源用量时序)。""" source_system = "BSS" staging_table = "src_cloud_usage" def ingest( self, session: Session, data_version_id: uuid.UUID | None = None, batch_size: int = 1000, ) -> IngestResult: result = IngestResult() query = session.query(SrcCloudUsage) if data_version_id: query = query.filter(SrcCloudUsage.data_version_id == data_version_id) rows = query.limit(batch_size).all() for row in rows: try: # 合同实体 upsert_entity( session, entity_type=EntityType.CONTRACT, business_key=row.contract_no, data_version_id=data_version_id, ) # 客户实体(如有) if row.customer_key: upsert_entity( session, entity_type=EntityType.CUSTOMER, business_key=row.customer_key, data_version_id=data_version_id, ) # 云资源用量事件 if row.usage_date: event_time = dt.datetime.combine( row.usage_date, dt.time.min, tzinfo=dt.timezone.utc ) event = MetricEvent( event_time=event_time, subject_type="contract", subject_key=row.contract_no, metric_name="cloud_usage", metric_value=row.actual_usage, attributes={ "resource_type": row.resource_type, "contracted_quota": row.contracted_quota, "billed_usage": row.billed_usage, "unit": row.unit, "customer_key": row.customer_key, }, 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 IdcCabinetAdapter(BaseAdapter): """SrcIdcCabinet → MetricEvent(IDC 机柜出租率/电力时序)。""" source_system = "OSS" staging_table = "src_idc_cabinet" def ingest( self, session: Session, data_version_id: uuid.UUID | None = None, batch_size: int = 1000, ) -> IngestResult: result = IngestResult() query = session.query(SrcIdcCabinet) if data_version_id: query = query.filter(SrcIdcCabinet.data_version_id == data_version_id) rows = query.limit(batch_size).all() for row in rows: try: # 合同实体(如有) if row.contract_no: upsert_entity( session, entity_type=EntityType.CONTRACT, business_key=row.contract_no, data_version_id=data_version_id, ) # IDC 出租/电力事件 try: event_time = dt.datetime.strptime( row.report_month, "%Y-%m" ).replace(tzinfo=dt.timezone.utc) if row.report_month else dt.datetime.now(dt.timezone.utc) except ValueError: event_time = dt.datetime.now(dt.timezone.utc) event = MetricEvent( event_time=event_time, subject_type="contract", subject_key=row.contract_no or row.cabinet_id, metric_name="idc_cabinet", metric_value=row.occupancy_rate or 0.0, attributes={ "cabinet_id": row.cabinet_id, "customer_key": row.customer_key, "power_kwh": row.power_kwh, "revenue_amount": row.revenue_amount, "acceptance_date": str(row.acceptance_date) if row.acceptance_date else None, }, 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