certflow.services.db_source_adapter 源代码

"""DB→DB 导入源适配层(蓝图 §4.3.2:跨库复用导入框架)。

把「查询视图勾选的 SalePlan 列表」包装成与 xlsx 解析结果同构的源记录,
喂给统一「打印合格证」入口 ``QueryController.generate_print_certificates`` 适配层,
实现「销售计划 DB → 合格证清单」的复用,无需经过 Excel 文件。

设计要点(与总原则一致):
- 纯 SQLAlchemy,不依赖任何 Qt 组件,可单测;
- 视图层只把勾选的 SalePlan id 交给本适配层,适配层负责取回实体并暴露
  ``plan_ids`` / ``records`` / ``to_source_records``;
- 真正的「编号 + 写 Certificate」由统一入口 ``QueryController.generate_print_certificates``
  经 ``CertificatePrintService`` 编排(去重安全),框架零改动,仅新增此适配层 + 一个 view_key。
"""

from __future__ import annotations

from typing import Any

from sqlalchemy.orm import Session

from certflow.models import SalePlan


[文档] class DbSourceAdapter: """把选中的 SalePlan 包装为 DB→DB 导入源。 查询视图「打印合格证」动作把勾选的 SalePlan id 交给本适配层, 适配层从会话取回实体并暴露 ``plan_ids`` / ``records``,供控制器经统一入口 ``generate_print_certificates`` 生成 Certificate 记录。 Attributes: session: SQLAlchemy 会话 plan_ids: 选中的销售计划主键列表 """ def __init__(self, session: Session, plan_ids: list[int]) -> None: self.session = session self._plan_ids = list(plan_ids)
[文档] def plan_ids(self) -> list[int]: """返回选中的销售计划主键列表(去重保序)。""" seen: set[int] = set() out: list[int] = [] for pid in self._plan_ids: if pid not in seen: seen.add(pid) out.append(pid) return out
[文档] def get_records(self) -> list[SalePlan]: """从会话取回选中的 SalePlan 实体列表(保持传入顺序)。""" ids = self.plan_ids() if not ids: return [] rows = self.session.query(SalePlan).filter(SalePlan.id.in_(ids)).all() order = {pid: i for i, pid in enumerate(ids)} rows.sort(key=lambda r: order.get(r.id, 0)) return rows
[文档] def to_source_records(self) -> list[dict[str, Any]]: """导出与 xlsx 解析结果同构的源记录字典列表(供审计/预览)。 仅包含合格证生成所需的源字段,等价于 ``create_certificates`` 读取的列。 """ return [ { "id": sp.id, "unique_key": sp.unique_key, "production_order_no": sp.production_order_no, "sales_order_no": sp.sales_order_no, "product_code": sp.product_code, "cert_product_name": sp.cert_product_name, "cert_product_model": sp.cert_product_model, "cert_product_spec": sp.cert_product_spec, "product_name": sp.product_name, "product_model": sp.product_model, "product_spec": sp.product_spec, "quantity": sp.quantity, "customer": sp.customer, "project_name": sp.project_name, "test_standard": sp.test_standard, } for sp in self.get_records() ]