certflow.services.sale_plan_service module¶
销售计划业务服务模块
提供销售计划的Excel导入、查询和分组等业务服务, 支持带格式读取单元格边框字体背景色等信息 封装完整的读取、清洗、校验、分组排序和持久化流程。
- class certflow.services.sale_plan_service.SalePlanService(db_session)[源代码]¶
基类:
object销售计划服务
提供销售计划数据的完整业务流程管理,包括: - Excel文件导入(支持带格式和不带格式两种模式) - 数据清洗和校验 - 分组排序(先按业务分组,组内按产品排序) - 数据库持久化 - 查询和统计
- 参数:
db_session (Session)
- session¶
SQLAlchemy数据库会话对象
- excel_handler¶
Excel文件处理器实例
- cleaner¶
数据清洗器实例
- sorter¶
排序器实例
- save_handler¶
保存处理器实例
示例
>>> from sqlalchemy import create_engine >>> from sqlalchemy.orm import sessionmaker >>> >>> engine = create_engine("sqlite:///certflow.db") >>> Session = sessionmaker(bind=engine) >>> session = Session() >>> >>> service = SalePlanService(session) >>> >>> # 导入Excel文件 >>> result = service.import_from_excel_with_config({ ... "file_path": "sales_plan.xlsx", ... "sheet_name": "Sheet1", ... "preserve_formatting": True ... }) >>> print(f"导入成功: {result['new_count']}条")
- static detect_header_row(df_raw, keywords, max_rows=20)[源代码]¶
自动检测表头行(委托
ExcelHandler.detect_header_row)。
- static extract_year_from_filename(file_path)[源代码]¶
从工作簿文件名提取年份后两位(委托
Sorter._extract_year_from_filename)。
- static apply_range_filter(records, range_filter, selected_rows)[源代码]¶
B0-8 导入范围筛选。
selected_rows:勾选行模式,传入 0-based 数据行序号集合,仅保留这些行。
range_filter:按订单筛选模式,dict 含 plan_date/customer/project_name/plan_no 中若干非空字段,仅保留这些字段**全部精确匹配**的行(空值字段视为通配)。
两者均未指定:返回原 records(整表导入)。
临时字段 _src_row 用后即清,不污染落库数据。
- record_shipment(sale_plan_id, quantity, ship_date=None, operator='', note='')[源代码]¶
记录一次分批发货(B0-3 分批发货数量追踪)。
将本次发货追加到
shipment_batchesJSON 列表,累加shipped_quantity; 当累计已发货量达到订单总量quantity时,标记shipping_status='已发货'(仅更新发货状态,不动生产状态),并记录发货日期。
- excel_handler: ExcelHandler¶
- cleaner: DataCleaner¶
- save_handler: SaveHandler¶
- shipped_handler: ShippedExportHandler¶
- import_from_excel_with_config(config_params)[源代码]¶
使用自定义配置从Excel导入销售计划
根据配置参数选择带格式或不带格式的导入方式。
- 参数:
config_params (dict[str, Any]) -- 导入配置参数字典,包含以下字段: - file_path: Excel文件路径(必填) - sheet_name: 工作表名称或索引,默认为0 - header_row: 表头行号(可选) - skip_rows: 跳过的行数,默认为0 - column_mapping: 自定义列映射字典(可选) - preserve_formatting: 是否保留单元格格式,默认为False
- 返回:
导入结果字典
- 返回类型:
Dict[str, Any]
- 抛出:
Exception -- 导入失败时抛出异常
示例
>>> service = SalePlanService(session) >>> result = service.import_from_excel_with_config({ ... "file_path": "sales.xlsx", ... "sheet_name": "1月", ... "header_row": 1, ... "skip_rows": 0, ... "preserve_formatting": True, ... }) >>> print(result["new_count"])
- get_all_sale_plans()[源代码]¶
获取所有销售计划
- 返回:
按分组键排序的所有销售计划列表
- 返回类型:
List[SalePlan]
示例
>>> service = SalePlanService(session) >>> plans = service.get_all_sale_plans() >>> print(len(plans))
- get_by_sort_group(sort_group)[源代码]¶
根据分组键获取销售计划
- 参数:
sort_group (str) -- 分组键值
- 返回:
指定分组的销售计划列表
- 返回类型:
List[SalePlan]
- get_by_product_model(product_model)[源代码]¶
根据产品型号获取销售计划
- 参数:
product_model (str) -- 产品型号
- 返回:
指定产品型号的销售计划列表
- 返回类型:
List[SalePlan]
- get_statistics()[源代码]¶
获取销售计划统计信息
- 返回:
- 统计信息字典,包含:
total_records: 总记录数
group_count: 分组数
status_stats: 按生产状态分组统计
- 返回类型:
Dict[str, Any]
- get_by_status(status)[源代码]¶
根据格式状态获取销售计划
- 参数:
status (str) -- 格式状态值(如"已开票"、"已发货"等)
- 返回:
指定格式状态的销售计划列表
- 返回类型:
List[SalePlan]
- get_exportable_plans()[源代码]¶
获取可导出的销售计划(排除已发货、外购未回、隐藏行)
对应 VBA 中导出合格证时的过滤逻辑: - 排除字体蓝色(已发货)的记录 - 排除背景橙棕色(外购未回)的记录 - 排除行高=0(隐藏/取消)的记录
- 返回:
可导出的销售计划列表
- 返回类型:
List[SalePlan]
- find_by_unique_key(unique_key)[源代码]¶
根据唯一键查找已存在的销售计划
- 参数:
unique_key (str) -- 唯一键
- 返回:
已存在的 SalePlan 或 None
- 返回类型:
SalePlan | None
- find_by_id(plan_id)[源代码]¶
按主键查询销售计划。
- 参数:
plan_id (int) -- 销售计划主键
- 返回:
命中的 SalePlan 或 None
- 返回类型:
SalePlan | None
- find_by_production_order_no(production_order_no)[源代码]¶
根据生产令号查找已存在的销售计划
用于老数据模式降级去重:当唯一键匹配失败但生产令号有值时, 按生产令号查找已有记录,避免同一记录从不同来源重复导入。
- 参数:
production_order_no (str) -- 生产令号
- 返回:
已存在的 SalePlan 或 None
- 返回类型:
SalePlan | None
- find_by_contract_and_model(contract_no, product_model)[源代码]¶
根据合同号 + 产品型号查找已存在的销售计划
用于跨来源补充场景的兜底匹配:当唯一键和生产令号都匹配失败时, 通过合同号 + 产品型号定位已有记录,实现缺失字段补充。
- CERT_EDITABLE_FIELDS: tuple[str, ...] = ('cert_product_name', 'cert_product_model', 'cert_product_spec', 'certificate_remarks')¶
- update_cert_fields(plan_id, fields)[源代码]¶
仅更新合格证打印字段(蓝图 §4.2.3:查询视图 cert-only 订正)
只写入
cert_product_name/model/spec与certificate_remarks, 绝不触碰合同字段(product_*等)。这是合格证清单/打印的数据源, 订正即时生效于后续create_certificates。
- archive_to_shipped(sale_plan_ids)[源代码]¶
将选中的 SalePlan 归档到 sale_plans_shipped 表并从主表移除
三层模型的 Layer 1 → Layer 2: - 将记录完整拷贝到 sale_plans_shipped(设置 shipped_at / shipped_by="archive") - 从 sale_plans 表删除对应记录 - 同时将 production_status 设为"已发货"(如果还不是)
- export_and_delete(sale_plan_ids, output_dir)[源代码]¶
导出选中 SalePlan 的完整字段 Excel,归档到 shipped 表,并从主表删除
三层模型的 Layer 1 → Layer 3: - 生成完整字段 Excel 文件 - 将记录拷贝到 sale_plans_shipped(shipped_by="export_delete") - 从 sale_plans 表删除