feat(订单处理): 添加杨碧月订单预处理功能
在特殊供应商服务中添加 process_yang_biyue 方法,用于处理经手人为"杨碧月"的订单。该方法能够自动识别相关列并进行数据清洗,生成标准格式的预处理文件。 同时优化订单服务的处理流程,在 process_excel 方法中集成特殊供应商预处理检查,通过 _check_special_preprocess 方法识别杨碧月订单并执行列映射转换,确保数据能够被后续标准流程正确处理。
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
提供订单处理服务,协调Excel处理和订单合并流程。
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Dict, List, Optional, Tuple, Union, Any, Callable
|
||||
|
||||
from ..config.settings import ConfigManager
|
||||
@@ -45,7 +46,7 @@ class OrderService:
|
||||
|
||||
def process_excel(self, file_path: Optional[str] = None, progress_cb: Optional[Callable[[int], None]] = None) -> Optional[str]:
|
||||
"""
|
||||
处理Excel文件,生成采购单
|
||||
处理Excel订单文件,生成标准采购单
|
||||
|
||||
Args:
|
||||
file_path: Excel文件路径,如果为None则处理最新的文件
|
||||
@@ -53,12 +54,93 @@ class OrderService:
|
||||
Returns:
|
||||
输出采购单文件路径,如果处理失败则返回None
|
||||
"""
|
||||
if file_path:
|
||||
logger.info(f"OrderService开始处理指定Excel文件: {file_path}")
|
||||
return self.excel_processor.process_specific_file(file_path, progress_cb=progress_cb)
|
||||
else:
|
||||
if not file_path:
|
||||
file_path = self.excel_processor.get_latest_excel()
|
||||
if not file_path:
|
||||
logger.warning("未找到可处理的Excel文件")
|
||||
return None
|
||||
logger.info("OrderService开始处理最新Excel文件")
|
||||
return self.excel_processor.process_latest_file(progress_cb=progress_cb)
|
||||
else:
|
||||
logger.info(f"OrderService开始处理指定Excel文件: {file_path}")
|
||||
|
||||
# 检查是否需要特殊的供应商预处理(如杨碧月)
|
||||
try:
|
||||
from .special_suppliers_service import SpecialSuppliersService
|
||||
special_service = SpecialSuppliersService(self.config)
|
||||
|
||||
# 尝试识别并预处理(注意:这里不再传入 progress_cb 避免无限递归或重复进度条,
|
||||
# 或者我们在 special_service 内部逻辑中处理完后直接返回结果)
|
||||
# 为了避免循环调用,我们在 SpecialSuppliersService 内部不再调用 process_excel,
|
||||
# 而是让 process_excel 识别后自己决定是否处理预处理后的文件。
|
||||
|
||||
# 我们新增一个 check_and_preprocess 方法
|
||||
preprocessed_path = self._check_special_preprocess(file_path)
|
||||
if preprocessed_path:
|
||||
logger.info(f"检测到特殊供应商,已生成预处理文件: {preprocessed_path}")
|
||||
file_path = preprocessed_path
|
||||
except Exception as e:
|
||||
logger.error(f"检查特殊预处理时出错: {e}")
|
||||
|
||||
return self.excel_processor.process_specific_file(file_path, progress_cb=progress_cb)
|
||||
|
||||
def _check_special_preprocess(self, file_path: str) -> Optional[str]:
|
||||
"""检查并执行特殊的预处理"""
|
||||
try:
|
||||
from app.core.utils.file_utils import smart_read_excel
|
||||
import pandas as pd
|
||||
|
||||
# 仅读取前几行进行识别
|
||||
df_head = smart_read_excel(file_path, nrows=50)
|
||||
|
||||
# 1. 检查“杨碧月”
|
||||
handler_col = None
|
||||
for col in df_head.columns:
|
||||
if '经手人' in str(col):
|
||||
handler_col = col
|
||||
break
|
||||
|
||||
if handler_col is not None and df_head[handler_col].astype(str).str.contains('杨碧月').any():
|
||||
logger.info("识别到杨碧月订单,执行预处理...")
|
||||
# 重新读取完整数据
|
||||
df = smart_read_excel(file_path)
|
||||
column_map = {
|
||||
'商品条码': '商品条码', '商品名称': '商品名称', '规格': '规格',
|
||||
'单位': '单位', '数量': '数量', '单价': '单价', '金额': '金额'
|
||||
}
|
||||
found_cols = {}
|
||||
# 优先级排序,确保更精确的匹配
|
||||
for target_zh, std_name in column_map.items():
|
||||
for col in df.columns:
|
||||
col_str = str(col)
|
||||
if target_zh == col_str: # 精确匹配优先
|
||||
found_cols[col] = std_name
|
||||
break
|
||||
if std_name not in found_cols.values():
|
||||
for col in df.columns:
|
||||
col_str = str(col)
|
||||
if target_zh in col_str: # 模糊匹配
|
||||
found_cols[col] = std_name
|
||||
break
|
||||
|
||||
if len(found_cols) >= 4:
|
||||
df_clean = df[list(found_cols.keys())].copy()
|
||||
df_clean = df_clean.rename(columns=found_cols)
|
||||
|
||||
# 确保数量和价格是数值
|
||||
# 这里的列名已经改回中文了
|
||||
for c in ['数量', '单价', '金额']:
|
||||
if c in df_clean.columns:
|
||||
df_clean[c] = pd.to_numeric(df_clean[c], errors='coerce').fillna(0)
|
||||
|
||||
df_clean = df_clean.dropna(subset=['商品条码'])
|
||||
out_dir = os.path.dirname(file_path)
|
||||
final_path = os.path.join(out_dir, "预处理之后.xlsx")
|
||||
df_clean.to_excel(final_path, index=False)
|
||||
return final_path
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"预处理识别失败: {e}")
|
||||
return None
|
||||
|
||||
def get_purchase_orders(self) -> List[str]:
|
||||
"""
|
||||
|
||||
@@ -20,6 +20,74 @@ class SpecialSuppliersService:
|
||||
self.config_manager = config_manager
|
||||
self.order_service = OrderService(config_manager)
|
||||
|
||||
def process_yang_biyue(self, src_path: str, progress_cb: Optional[Callable[[int, str], None]] = None) -> Optional[str]:
|
||||
"""
|
||||
处理杨碧月经手的订单(预处理)
|
||||
"""
|
||||
try:
|
||||
if progress_cb: progress_cb(10, "正在进行杨碧月订单预处理...")
|
||||
from app.core.utils.file_utils import smart_read_excel
|
||||
|
||||
# 读取原始数据
|
||||
df = smart_read_excel(src_path)
|
||||
|
||||
# 检查是否包含“杨碧月”
|
||||
handler_col = None
|
||||
for col in df.columns:
|
||||
if '经手人' in str(col):
|
||||
handler_col = col
|
||||
break
|
||||
|
||||
if handler_col is None or not df[handler_col].astype(str).str.contains('杨碧月').any():
|
||||
logger.info("未在订单中找到经手人'杨碧月',跳过特殊预处理")
|
||||
return None
|
||||
|
||||
if progress_cb: progress_cb(30, "识别到杨碧月订单,正在清洗列数据...")
|
||||
|
||||
# 定义列映射关系
|
||||
column_map = {
|
||||
'商品条码': 'barcode',
|
||||
'商品名称': 'name',
|
||||
'商品规格': 'specification',
|
||||
'单位': 'unit',
|
||||
'数量': 'quantity',
|
||||
'含税单价': 'unit_price',
|
||||
'含税金额': 'total_price'
|
||||
}
|
||||
|
||||
# 提取并重命名列
|
||||
found_cols = {}
|
||||
for target_zh, std_name in column_map.items():
|
||||
for col in df.columns:
|
||||
if target_zh in str(col):
|
||||
found_cols[col] = std_name
|
||||
break
|
||||
|
||||
if len(found_cols) < 4:
|
||||
logger.error(f"杨碧月订单列匹配不足: 找到 {list(found_cols.values())}")
|
||||
return None
|
||||
|
||||
df_clean = df[list(found_cols.keys())].copy()
|
||||
df_clean = df_clean.rename(columns=found_cols)
|
||||
|
||||
# 过滤掉空的条码行
|
||||
df_clean = df_clean.dropna(subset=['barcode'])
|
||||
|
||||
# 保存预处理文件
|
||||
out_dir = os.path.dirname(src_path)
|
||||
final_path = os.path.join(out_dir, "预处理之后.xlsx")
|
||||
df_clean.to_excel(final_path, index=False)
|
||||
|
||||
if progress_cb: progress_cb(60, "预处理文件已保存,开始标准转换流程...")
|
||||
|
||||
# 调用标准处理流程
|
||||
result = self.order_service.process_excel(final_path, progress_cb=lambda p: progress_cb(60 + int(p*0.4), "生成采购单中...") if progress_cb else None)
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理杨碧月订单出错: {e}")
|
||||
return None
|
||||
|
||||
def process_rongcheng_yigou(self, src_path: str, progress_cb: Optional[Callable[[int, str], None]] = None) -> Optional[str]:
|
||||
"""
|
||||
处理蓉城易购订单
|
||||
|
||||
Reference in New Issue
Block a user