feat: add database-driven material validation with multi-mode support
This commit enhances the material validation functionality to support database-driven workflows alongside the existing Excel-based approach. ## New Features ### DAO Layer - Add ProductionContractDataDAO for querying production contract data - Add MaterialsToBeDeletedDAO with full CRUD operations - Enhance DiscreteMaterialPlanDAO with query_all(), query_by_source_numbers(), and get_unique_material_names() methods ### Validation Modes Support for 4 validation modes in MaterialValidationTab: 1. Database Full - Query all materials from DiscreteMaterialPlanData 2. Database Filtered - Query by ProductionID.txt file 3. Excel Existing - Validate from existing Excel file 4. Excel Full - Complete workflow with ERP extraction ### Configuration - Add ValidationConfig dataclass with data_source, batch_size, match_mode, enable_crud_operations, and default_manager fields - Update ConfigLoader to support validation configuration - Add validation settings section in SettingsTab GUI ### Query Chain Implementation of full query chain: ProductionID.txt (总排号) → productionContractData (生产订单号) → DiscreteMaterialPlanData (SourceNumber) → MaterialName → MaterialsToBeDeleted comparison ## Backward Compatibility All existing Excel-based validation methods remain unchanged, ensuring no breaking changes for existing workflows. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
"""
|
||||
物料状态校验工具
|
||||
校验订单中的物料状态,匹配待删除物料
|
||||
|
||||
支持两种数据源:
|
||||
1. Excel 文件(原有方式)
|
||||
2. 数据库驱动(新增方式)
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -8,6 +12,9 @@ import pandas as pd
|
||||
from typing import List, Dict, Any
|
||||
from utils.离散备料计划维护数据提取 import DiscreteMaterialPlanExtractor
|
||||
from db.materials_to_delete import get_all_materials_to_delete
|
||||
from db.production_contract_data_dao import ProductionContractDataDAO
|
||||
from db.discrete_material_plan_dao import DiscreteMaterialPlanDAO
|
||||
from db.materials_to_be_deleted_dao import MaterialsToBeDeletedDAO
|
||||
|
||||
|
||||
class MaterialStatusValidator:
|
||||
@@ -195,3 +202,147 @@ class MaterialStatusValidator:
|
||||
self._print(f" 未匹配: {len(results) - matched_count}")
|
||||
|
||||
return output_file
|
||||
|
||||
# ==================== DATABASE-DRIVEN VALIDATION ====================
|
||||
|
||||
def _read_production_ids(self, production_id_file: str) -> List[str]:
|
||||
"""
|
||||
读取 ProductionID.txt 文件
|
||||
|
||||
Args:
|
||||
production_id_file: ProductionID.txt 文件路径
|
||||
|
||||
Returns:
|
||||
List[str]: 总排号列表
|
||||
"""
|
||||
with open(production_id_file, 'r', encoding='utf-8') as f:
|
||||
production_ids = [line.strip() for line in f if line.strip()]
|
||||
return production_ids
|
||||
|
||||
def _get_source_numbers_from_production_ids(
|
||||
self, production_ids: List[str]
|
||||
) -> List[str]:
|
||||
"""
|
||||
通过 ProductionID 查询获取 SourceNumber 列表
|
||||
|
||||
查询链路:
|
||||
ProductionID (总排号) -> productionContractData.26年压力表合同数据.生产订单号
|
||||
|
||||
Args:
|
||||
production_ids: 总排号列表
|
||||
|
||||
Returns:
|
||||
List[str]: 生产订单号列表
|
||||
"""
|
||||
self._print(f"[INFO] 正在查询 {len(production_ids)} 个总排号对应的生产订单号...")
|
||||
|
||||
contract_dao = ProductionContractDataDAO()
|
||||
source_numbers = contract_dao.get_source_numbers_by_总排号(production_ids)
|
||||
|
||||
self._print(f"[INFO] 找到 {len(source_numbers)} 个唯一的生产订单号")
|
||||
return source_numbers
|
||||
|
||||
def _get_material_names_from_db(
|
||||
self, source_numbers: List[str] = None
|
||||
) -> List[str]:
|
||||
"""
|
||||
从数据库获取材料名称,可选按 SourceNumber 过滤
|
||||
|
||||
Args:
|
||||
source_numbers: 可选的 SourceNumber 列表进行过滤
|
||||
|
||||
Returns:
|
||||
List[str]: 唯一材料名称列表
|
||||
"""
|
||||
if source_numbers is None or not source_numbers:
|
||||
self._print("[INFO] 查询所有材料的名称...")
|
||||
else:
|
||||
self._print(f"[INFO] 查询 {len(source_numbers)} 个生产订单对应的材料名称...")
|
||||
|
||||
dao = DiscreteMaterialPlanDAO()
|
||||
material_names = dao.get_unique_material_names(source_numbers)
|
||||
|
||||
self._print(f"[INFO] 找到 {len(material_names)} 个唯一材料名称")
|
||||
return material_names
|
||||
|
||||
def validate_from_database(
|
||||
self,
|
||||
production_id_file: str = None,
|
||||
full_table: bool = False,
|
||||
output_file: str = None
|
||||
) -> str:
|
||||
"""
|
||||
使用数据库作为数据源执行校验
|
||||
|
||||
支持两种模式:
|
||||
1. 全表校验 (full_table=True): 查询整个 DiscreteMaterialPlanData 表
|
||||
2. ProductionID 过滤校验 (production_id_file 指定): 基于 ProductionID.txt 文件过滤
|
||||
|
||||
查询链路(模式2):
|
||||
ProductionID.txt (总排号)
|
||||
-> productionContractData.26年压力表合同数据.生产订单号 (SourceNumber)
|
||||
-> DiscreteMaterialPlanData.SourceNumber
|
||||
-> DiscreteMaterialPlanData.MaterialName
|
||||
-> 对比 MaterialsToBeDeleted.MaterialName
|
||||
|
||||
Args:
|
||||
production_id_file: ProductionID.txt 路径(模式2)
|
||||
full_table: 是否全表校验(模式1)
|
||||
output_file: 输出文件路径
|
||||
|
||||
Returns:
|
||||
输出文件路径
|
||||
"""
|
||||
# 设置默认输出路径
|
||||
if output_file is None:
|
||||
output_file = "D:/python/playwrite/data/物料状态校验结果.xlsx"
|
||||
|
||||
self._print("=" * 60)
|
||||
self._print("使用数据库数据源执行校验...")
|
||||
|
||||
# 根据模式获取材料名称
|
||||
if full_table:
|
||||
self._print("\n模式: 全表校验")
|
||||
self._print("[INFO] 查询 DiscreteMaterialPlanData 表中的所有材料...")
|
||||
material_names = self._get_material_names_from_db(None)
|
||||
elif production_id_file:
|
||||
self._print("\n模式: ProductionID 过滤校验")
|
||||
self._print(f"[INFO] 读取 ProductionID 文件: {production_id_file}")
|
||||
|
||||
# 1. 读取 ProductionID.txt
|
||||
production_ids = self._read_production_ids(production_id_file)
|
||||
self._print(f"[INFO] 读取到 {len(production_ids)} 个总排号")
|
||||
|
||||
# 2. 查询获取 SourceNumbers
|
||||
source_numbers = self._get_source_numbers_from_production_ids(production_ids)
|
||||
|
||||
# 3. 获取材料名称
|
||||
material_names = self._get_material_names_from_db(source_numbers)
|
||||
else:
|
||||
raise ValueError(
|
||||
"必须指定 full_table=True 或提供 production_id_file 参数"
|
||||
)
|
||||
|
||||
# 从数据库获取待删除物料
|
||||
self._print("\n从数据库获取待删除物料...")
|
||||
db_materials = get_all_materials_to_delete()
|
||||
self._print(f"获取到 {len(db_materials)} 条待删除物料记录")
|
||||
|
||||
# 匹配物料
|
||||
self._print("\n匹配物料...")
|
||||
results = self.match_materials(material_names, db_materials)
|
||||
|
||||
# 输出结果
|
||||
self._print("\n输出结果...")
|
||||
result_df = pd.DataFrame(results)
|
||||
result_df.to_excel(output_file, index=False)
|
||||
self._print(f"结果已保存: {output_file}")
|
||||
|
||||
# 打印统计信息
|
||||
matched_count = sum(1 for r in results if r["匹配状态"] == "匹配成功")
|
||||
self._print(f"\n统计信息:")
|
||||
self._print(f" 总材料数: {len(results)}")
|
||||
self._print(f" 匹配成功: {matched_count}")
|
||||
self._print(f" 未匹配: {len(results) - matched_count}")
|
||||
|
||||
return output_file
|
||||
|
||||
Reference in New Issue
Block a user