feat: add material deletion confirmation with checkbox UI
- Add MaterialsToBeDeletedDAO for managing material deletion records by MaterialCode - Add MaterialValidationResult dataclass for enhanced validation results - Add CheckboxTreeview component with selectable checkbox functionality - Refactor material validation UI with new columns: select, material name, code, spec, model, manager - Add double-click to edit manager name functionality - Add select all/deselect all buttons - Add confirm deletion button to write selected records to database - Prioritize MaterialsToBeDeleted.ManagerName over type-based matching when displaying - Export results to Excel with selection state Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,12 +9,28 @@
|
||||
|
||||
import os
|
||||
import pandas as pd
|
||||
from typing import List, Dict, Any
|
||||
from typing import List, Dict, Any, Optional, Set
|
||||
from dataclasses import dataclass
|
||||
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 MaterialsTypeToBeDeletedDAO
|
||||
from db.materials_to_be_deleted_records_dao import MaterialsToBeDeletedDAO
|
||||
|
||||
|
||||
# ==================== DATA STRUCTURES ====================
|
||||
|
||||
@dataclass
|
||||
class MaterialValidationResult:
|
||||
"""Enhanced material validation result with complete record information"""
|
||||
material_name: str
|
||||
material_code: str
|
||||
specification: Optional[str] = None
|
||||
model: Optional[str] = None
|
||||
manager_name: Optional[str] = None
|
||||
is_marked_for_deletion: bool = False
|
||||
matched_type_keyword: Optional[str] = None # Matched keyword from MaterialsTypeToBeDeleted
|
||||
|
||||
|
||||
class MaterialStatusValidator:
|
||||
@@ -346,3 +362,162 @@ class MaterialStatusValidator:
|
||||
self._print(f" 未匹配: {len(results) - matched_count}")
|
||||
|
||||
return output_file
|
||||
|
||||
# ==================== ENHANCED VALIDATION METHODS ====================
|
||||
|
||||
def match_materials_detailed(
|
||||
self,
|
||||
material_records: List[Dict[str, Any]],
|
||||
type_keywords: List[Dict[str, Any]],
|
||||
marked_codes_dict: Dict[str, str] # Changed: MaterialCode -> ManagerName mapping
|
||||
) -> List[MaterialValidationResult]:
|
||||
"""
|
||||
Match materials with detailed information.
|
||||
|
||||
Args:
|
||||
material_records: Complete records from DiscreteMaterialPlanData
|
||||
type_keywords: Records from MaterialsTypeToBeDeleted (MaterialName matching)
|
||||
marked_codes_dict: MaterialCode -> ManagerName mapping from MaterialsToBeDeleted
|
||||
|
||||
Returns:
|
||||
List of MaterialValidationResult objects
|
||||
"""
|
||||
results = []
|
||||
|
||||
for record in material_records:
|
||||
material_name = record.get('MaterialName', '') or ''
|
||||
material_code = record.get('MaterialCode', '') or ''
|
||||
specification = record.get('Specification', '') or None
|
||||
model = record.get('Model', '') or None
|
||||
|
||||
# Priority 1: Check MaterialsToBeDeleted (MaterialCode exact match)
|
||||
# This has highest priority - if MaterialCode exists, use its ManagerName
|
||||
manager_name = marked_codes_dict.get(material_code) if material_code else None
|
||||
is_marked = manager_name is not None
|
||||
matched_keyword = None
|
||||
|
||||
# Priority 2: If not in MaterialsToBeDeleted, match with MaterialsTypeToBeDeleted
|
||||
# (MaterialName contains match)
|
||||
if not manager_name:
|
||||
for type_record in type_keywords:
|
||||
type_material_name = type_record.get('MaterialName', '')
|
||||
if type_material_name and type_material_name in material_name:
|
||||
matched_keyword = type_material_name
|
||||
manager_name = type_record.get('ManagerName')
|
||||
break
|
||||
|
||||
result = MaterialValidationResult(
|
||||
material_name=material_name,
|
||||
material_code=material_code,
|
||||
specification=specification,
|
||||
model=model,
|
||||
manager_name=manager_name,
|
||||
is_marked_for_deletion=is_marked,
|
||||
matched_type_keyword=matched_keyword
|
||||
)
|
||||
results.append(result)
|
||||
|
||||
return results
|
||||
|
||||
def validate_from_database_enhanced(
|
||||
self,
|
||||
production_id_file: str = None,
|
||||
full_table: bool = False,
|
||||
output_file: str = None
|
||||
) -> tuple:
|
||||
"""
|
||||
Enhanced database validation with complete record information.
|
||||
|
||||
Args:
|
||||
production_id_file: ProductionID.txt path (for filtered mode)
|
||||
full_table: Whether to query full table (for full table mode)
|
||||
output_file: Output Excel file path
|
||||
|
||||
Returns:
|
||||
Tuple of (output_file_path, List[MaterialValidationResult])
|
||||
"""
|
||||
# Set default output path
|
||||
if output_file is None:
|
||||
output_file = "D:/python/playwrite/data/物料状态校验结果.xlsx"
|
||||
|
||||
self._print("=" * 60)
|
||||
self._print("使用增强数据库校验(完整记录模式)...")
|
||||
|
||||
# Get material records (complete records, not just MaterialName)
|
||||
if full_table:
|
||||
self._print("\n模式: 全表校验")
|
||||
self._print("[INFO] 查询 DiscreteMaterialPlanData 表中的所有完整记录...")
|
||||
dao = DiscreteMaterialPlanDAO()
|
||||
material_records = dao.query_all()
|
||||
self._print(f"[INFO] 获取到 {len(material_records)} 条记录")
|
||||
elif production_id_file:
|
||||
self._print("\n模式: ProductionID 过滤校验")
|
||||
self._print(f"[INFO] 读取 ProductionID 文件: {production_id_file}")
|
||||
|
||||
# 1. Read ProductionID.txt
|
||||
production_ids = self._read_production_ids(production_id_file)
|
||||
self._print(f"[INFO] 读取到 {len(production_ids)} 个总排号")
|
||||
|
||||
# 2. Query SourceNumbers
|
||||
source_numbers = self._get_source_numbers_from_production_ids(production_ids)
|
||||
|
||||
# 3. Get complete material records
|
||||
self._print(f"[INFO] 查询 {len(source_numbers)} 个生产订单对应的完整物料记录...")
|
||||
dao = DiscreteMaterialPlanDAO()
|
||||
material_records = dao.query_by_source_numbers(source_numbers)
|
||||
self._print(f"[INFO] 获取到 {len(material_records)} 条记录")
|
||||
else:
|
||||
raise ValueError("必须指定 full_table=True 或提供 production_id_file 参数")
|
||||
|
||||
# Get type keywords from MaterialsTypeToBeDeleted
|
||||
self._print("\n从数据库获取待删除物料类型...")
|
||||
type_dao = MaterialsTypeToBeDeletedDAO()
|
||||
type_keywords = type_dao.get_all_materials()
|
||||
self._print(f"获取到 {len(type_keywords)} 条物料类型记录")
|
||||
|
||||
# Get marked material codes and manager names from MaterialsToBeDeleted
|
||||
self._print("从数据库获取已标记删除的物料记录...")
|
||||
record_dao = MaterialsToBeDeletedDAO()
|
||||
marked_records = record_dao.get_all_records()
|
||||
|
||||
# Build dictionary: MaterialCode -> ManagerName
|
||||
marked_codes_dict = {
|
||||
r['MaterialCode']: r['ManagerName']
|
||||
for r in marked_records
|
||||
if r.get('MaterialCode') and r.get('ManagerName')
|
||||
}
|
||||
self._print(f"获取到 {len(marked_codes_dict)} 个已标记的物料代码")
|
||||
|
||||
# Match materials
|
||||
self._print("\n匹配物料...")
|
||||
results = self.match_materials_detailed(material_records, type_keywords, marked_codes_dict)
|
||||
|
||||
# Output to Excel
|
||||
self._print("\n输出结果...")
|
||||
|
||||
# Convert to DataFrame for Excel export
|
||||
df_data = []
|
||||
for r in results:
|
||||
df_data.append({
|
||||
"材料名称": r.material_name,
|
||||
"材料代码": r.material_code,
|
||||
"规格": r.specification or '',
|
||||
"型号": r.model or '',
|
||||
"负责人": r.manager_name or '',
|
||||
"已标记删除": "是" if r.is_marked_for_deletion else "否",
|
||||
"匹配的关键词": r.matched_type_keyword or ''
|
||||
})
|
||||
|
||||
result_df = pd.DataFrame(df_data)
|
||||
result_df.to_excel(output_file, index=False)
|
||||
self._print(f"结果已保存: {output_file}")
|
||||
|
||||
# Print statistics
|
||||
marked_count = sum(1 for r in results if r.is_marked_for_deletion)
|
||||
matched_count = sum(1 for r in results if r.manager_name)
|
||||
self._print(f"\n统计信息:")
|
||||
self._print(f" 总记录数: {len(results)}")
|
||||
self._print(f" 匹配到负责人: {matched_count}")
|
||||
self._print(f" 已标记删除: {marked_count}")
|
||||
|
||||
return output_file, results
|
||||
|
||||
Reference in New Issue
Block a user