248 lines
7.1 KiB
Python
248 lines
7.1 KiB
Python
"""RPA发票数据服务:处理RPA提取的发票数据存储和查询。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import sqlite3
|
||
from typing import Any, Dict, List, Optional
|
||
|
||
from db.connection import get_conn
|
||
from db.display_metadata import upsert_table_metadata, seed_column_metadata_batch
|
||
from db.rpa_invoice_schema import RPA_INVOICES_DDL, RPA_INVOICES_INDEX, RPA_INVOICES_COLUMNS
|
||
from util.constants import LOG_LOGGER_NAME
|
||
from util.logging_config import get_skill_logger
|
||
|
||
|
||
def init_rpa_invoice_table() -> None:
|
||
"""初始化RPA发票数据表。"""
|
||
conn = get_conn()
|
||
try:
|
||
cursor = conn.cursor()
|
||
|
||
# 创建表
|
||
cursor.execute(RPA_INVOICES_DDL)
|
||
cursor.execute(RPA_INVOICES_INDEX)
|
||
|
||
# 添加表元数据
|
||
upsert_table_metadata(
|
||
cursor,
|
||
table_name="rpa_invoices",
|
||
display_name="RPA发票提取",
|
||
description="通过RPA从网站提取的发票数据",
|
||
grid_help="查看RPA提取的发票数据,可按批次ID筛选",
|
||
visible=1,
|
||
readonly=1,
|
||
default_sort_json='[{"column":"id","direction":"desc"}]',
|
||
default_visible_columns_json='["id","batch_id","extraction_time","username","status","created_at"]',
|
||
)
|
||
|
||
# 添加列元数据
|
||
seed_column_metadata_batch(
|
||
cursor,
|
||
table_name="rpa_invoices",
|
||
columns=RPA_INVOICES_COLUMNS,
|
||
valid_column_names=[str(c["column_name"]) for c in RPA_INVOICES_COLUMNS],
|
||
)
|
||
|
||
conn.commit()
|
||
|
||
except Exception as e:
|
||
logger = get_skill_logger()
|
||
logger.error("init_rpa_invoice_table_failed error=%s", str(e))
|
||
raise
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def save_rpa_invoice_data(
|
||
batch_id: str,
|
||
source_url: str,
|
||
invoice_data: Dict[str, Any],
|
||
username: str = "",
|
||
status: str = "extracted",
|
||
error_message: str = "",
|
||
) -> int:
|
||
"""保存RPA提取的发票数据。
|
||
|
||
Args:
|
||
batch_id: 批次ID
|
||
source_url: 来源网址
|
||
invoice_data: 发票数据
|
||
username: 操作用户
|
||
status: 状态
|
||
error_message: 错误信息
|
||
|
||
Returns:
|
||
保存的记录ID
|
||
"""
|
||
conn = get_conn()
|
||
try:
|
||
cursor = conn.cursor()
|
||
|
||
# 将发票数据转换为JSON字符串
|
||
invoice_data_json = json.dumps(invoice_data, ensure_ascii=False)
|
||
|
||
# 插入数据
|
||
cursor.execute("""
|
||
INSERT INTO rpa_invoices (
|
||
batch_id, source_url, username, invoice_data_json, status, error_message
|
||
) VALUES (?, ?, ?, ?, ?, ?)
|
||
""", (batch_id, source_url, username, invoice_data_json, status, error_message))
|
||
|
||
record_id = cursor.lastrowid
|
||
conn.commit()
|
||
|
||
logger = get_skill_logger()
|
||
logger.info(
|
||
"rpa_invoice_saved record_id=%s batch_id=%s invoice_count=%s",
|
||
record_id,
|
||
batch_id,
|
||
invoice_data.get("total_count", 0),
|
||
)
|
||
|
||
return record_id
|
||
|
||
except Exception as e:
|
||
logger = get_skill_logger()
|
||
logger.error("save_rpa_invoice_data_failed error=%s", str(e))
|
||
raise
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def get_rpa_invoice_data(record_id: int) -> Optional[Dict[str, Any]]:
|
||
"""获取RPA提取的发票数据。"""
|
||
conn = get_conn()
|
||
try:
|
||
cursor = conn.cursor()
|
||
cursor.execute("SELECT * FROM rpa_invoices WHERE id = ?", (record_id,))
|
||
row = cursor.fetchone()
|
||
|
||
if not row:
|
||
return None
|
||
|
||
# 转换为字典
|
||
columns = [desc[0] for desc in cursor.description]
|
||
data = dict(zip(columns, row))
|
||
|
||
# 解析JSON数据
|
||
if "invoice_data_json" in data and data["invoice_data_json"]:
|
||
try:
|
||
data["invoice_data"] = json.loads(data["invoice_data_json"])
|
||
except json.JSONDecodeError:
|
||
data["invoice_data"] = {}
|
||
|
||
return data
|
||
|
||
except Exception as e:
|
||
logger = get_skill_logger()
|
||
logger.error("get_rpa_invoice_data_failed error=%s", str(e))
|
||
return None
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def list_rpa_invoices(
|
||
limit: int = 20,
|
||
batch_id: Optional[str] = None,
|
||
username: Optional[str] = None,
|
||
status: Optional[str] = None,
|
||
) -> List[Dict[str, Any]]:
|
||
"""查询RPA提取的发票数据列表。"""
|
||
conn = get_conn()
|
||
try:
|
||
cursor = conn.cursor()
|
||
|
||
# 构建查询条件
|
||
conditions = []
|
||
params = []
|
||
|
||
if batch_id:
|
||
conditions.append("batch_id = ?")
|
||
params.append(batch_id)
|
||
|
||
if username:
|
||
conditions.append("username = ?")
|
||
params.append(username)
|
||
|
||
if status:
|
||
conditions.append("status = ?")
|
||
params.append(status)
|
||
|
||
where_clause = " AND ".join(conditions) if conditions else "1=1"
|
||
|
||
# 执行查询
|
||
query = f"""
|
||
SELECT id, batch_id, source_url, extraction_time, username, status, error_message, created_at
|
||
FROM rpa_invoices
|
||
WHERE {where_clause}
|
||
ORDER BY id DESC
|
||
LIMIT ?
|
||
"""
|
||
params.append(limit)
|
||
|
||
cursor.execute(query, params)
|
||
rows = cursor.fetchall()
|
||
|
||
# 转换为字典列表
|
||
columns = [desc[0] for desc in cursor.description]
|
||
result = [dict(zip(columns, row)) for row in rows]
|
||
|
||
return result
|
||
|
||
except Exception as e:
|
||
logger = get_skill_logger()
|
||
logger.error("list_rpa_invoices_failed error=%s", str(e))
|
||
return []
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def get_rpa_invoice_stats() -> Dict[str, Any]:
|
||
"""获取RPA提取统计信息。"""
|
||
conn = get_conn()
|
||
try:
|
||
cursor = conn.cursor()
|
||
|
||
# 总记录数
|
||
cursor.execute("SELECT COUNT(*) FROM rpa_invoices")
|
||
total_count = cursor.fetchone()[0]
|
||
|
||
# 按状态统计
|
||
cursor.execute("""
|
||
SELECT status, COUNT(*) as count
|
||
FROM rpa_invoices
|
||
GROUP BY status
|
||
""")
|
||
status_stats = {row[0]: row[1] for row in cursor.fetchall()}
|
||
|
||
# 最近提取记录
|
||
cursor.execute("""
|
||
SELECT id, batch_id, extraction_time, username, status
|
||
FROM rpa_invoices
|
||
ORDER BY id DESC
|
||
LIMIT 5
|
||
""")
|
||
recent_extractions = [
|
||
{
|
||
"id": row[0],
|
||
"batch_id": row[1],
|
||
"extraction_time": row[2],
|
||
"username": row[3],
|
||
"status": row[4],
|
||
}
|
||
for row in cursor.fetchall()
|
||
]
|
||
|
||
return {
|
||
"total_count": total_count,
|
||
"status_stats": status_stats,
|
||
"recent_extractions": recent_extractions,
|
||
}
|
||
|
||
except Exception as e:
|
||
logger = get_skill_logger()
|
||
logger.error("get_rpa_invoice_stats_failed error=%s", str(e))
|
||
return {"error": str(e)}
|
||
finally:
|
||
conn.close() |