From e4d62df7e3419101763674691933193112738929 Mon Sep 17 00:00:00 2001 From: houhuan Date: Mon, 4 May 2026 19:51:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=9B=8A=E9=80=89=20OCR=20=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E5=A4=84=E7=90=86=E7=B3=BB=E7=BB=9F=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 智能供应商识别(蓉城易购/烟草/杨碧月/通用) - 百度 OCR 表格识别集成 - 规则引擎(列映射/数据清洗/单位转换/规格推断) - 条码映射管理与云端同步(Gitea REST API) - 云端同步支持:条码映射、供应商配置、商品资料、采购模板 - 拖拽一键处理(图片→OCR→Excel→合并) - 191 个单元测试 - 移除无用的模板管理功能 - 清理 IDE 产物目录 Co-Authored-By: Claude Opus 4.7 --- .env.example | 3 + .gitignore | 42 + CHANGELOG.md | 39 + CLAUDE.md | 146 +++ README.md | 110 ++ app/__init__.py | 8 + app/config/__init__.py | 5 + app/config/defaults.py | 49 + app/config/settings.py | 176 +++ app/core/db/__init__.py | 0 app/core/db/product_db.py | 214 +++ app/core/excel/__init__.py | 5 + app/core/excel/converter.py | 535 ++++++++ app/core/excel/handlers/__init__.py | 11 + app/core/excel/handlers/barcode_mapper.py | 83 ++ .../excel/handlers/unit_converter_handlers.py | 286 +++++ app/core/excel/merger.py | 423 ++++++ app/core/excel/processor.py | 860 +++++++++++++ app/core/excel/validators.py | 259 ++++ app/core/handlers/__init__.py | 9 + app/core/handlers/calculator.py | 378 ++++++ app/core/handlers/column_mapper.py | 382 ++++++ app/core/handlers/data_cleaner.py | 401 ++++++ app/core/handlers/rule_engine.py | 150 +++ app/core/ocr/__init__.py | 5 + app/core/ocr/baidu_ocr.py | 368 ++++++ app/core/ocr/table_ocr.py | 389 ++++++ app/core/processors/__init__.py | 9 + app/core/processors/base.py | 167 +++ app/core/processors/ocr_processor.py | 192 +++ .../supplier_processors/__init__.py | 7 + .../generic_supplier_processor.py | 340 +++++ app/core/processors/tobacco_processor.py | 347 +++++ app/core/utils/__init__.py | 5 + app/core/utils/cloud_sync.py | 184 +++ app/core/utils/dialog_utils.py | 1142 +++++++++++++++++ app/core/utils/file_utils.py | 286 +++++ app/core/utils/log_utils.py | 180 +++ app/core/utils/string_utils.py | 279 ++++ app/services/__init__.py | 5 + app/services/ocr_service.py | 193 +++ app/services/order_service.py | 245 ++++ app/services/processor_service.py | 297 +++++ app/services/special_suppliers_service.py | 227 ++++ app/services/tobacco_service.py | 336 +++++ app/ui/__init__.py | 2 + app/ui/action_handlers.py | 565 ++++++++ app/ui/barcode_editor.py | 33 + app/ui/command_runner.py | 158 +++ app/ui/config_dialog.py | 207 +++ app/ui/error_utils.py | 41 + app/ui/file_operations.py | 207 +++ app/ui/logging_ui.py | 126 ++ app/ui/main_window.py | 485 +++++++ app/ui/result_previews.py | 371 ++++++ app/ui/shortcuts.py | 60 + app/ui/theme.py | 193 +++ app/ui/ui_widgets.py | 121 ++ app/ui/user_settings.py | 128 ++ build_exe.py | 350 +++++ config.ini | 43 + config/barcode_mappings.json | 273 ++++ config/config.ini | 40 + config/suppliers_config.json | 237 ++++ docs/SYSTEM_ARCHITECTURE.md | 208 +++ headless_api.py | 212 +++ requirements.txt | 10 + templates/商品资料.xlsx | Bin 0 -> 845650 bytes templates/银豹-采购单模板.xls | Bin 0 -> 34304 bytes tests/__init__.py | 0 tests/test_calculator.py | 222 ++++ tests/test_column_mapper.py | 154 +++ tests/test_data_cleaner.py | 236 ++++ tests/test_product_db.py | 187 +++ tests/test_rule_engine.py | 223 ++++ tests/test_string_utils.py | 124 ++ tests/test_validators.py | 251 ++++ 启动器.py | 13 + 78 files changed, 15257 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 CLAUDE.md create mode 100644 README.md create mode 100644 app/__init__.py create mode 100644 app/config/__init__.py create mode 100644 app/config/defaults.py create mode 100644 app/config/settings.py create mode 100644 app/core/db/__init__.py create mode 100644 app/core/db/product_db.py create mode 100644 app/core/excel/__init__.py create mode 100644 app/core/excel/converter.py create mode 100644 app/core/excel/handlers/__init__.py create mode 100644 app/core/excel/handlers/barcode_mapper.py create mode 100644 app/core/excel/handlers/unit_converter_handlers.py create mode 100644 app/core/excel/merger.py create mode 100644 app/core/excel/processor.py create mode 100644 app/core/excel/validators.py create mode 100644 app/core/handlers/__init__.py create mode 100644 app/core/handlers/calculator.py create mode 100644 app/core/handlers/column_mapper.py create mode 100644 app/core/handlers/data_cleaner.py create mode 100644 app/core/handlers/rule_engine.py create mode 100644 app/core/ocr/__init__.py create mode 100644 app/core/ocr/baidu_ocr.py create mode 100644 app/core/ocr/table_ocr.py create mode 100644 app/core/processors/__init__.py create mode 100644 app/core/processors/base.py create mode 100644 app/core/processors/ocr_processor.py create mode 100644 app/core/processors/supplier_processors/__init__.py create mode 100644 app/core/processors/supplier_processors/generic_supplier_processor.py create mode 100644 app/core/processors/tobacco_processor.py create mode 100644 app/core/utils/__init__.py create mode 100644 app/core/utils/cloud_sync.py create mode 100644 app/core/utils/dialog_utils.py create mode 100644 app/core/utils/file_utils.py create mode 100644 app/core/utils/log_utils.py create mode 100644 app/core/utils/string_utils.py create mode 100644 app/services/__init__.py create mode 100644 app/services/ocr_service.py create mode 100644 app/services/order_service.py create mode 100644 app/services/processor_service.py create mode 100644 app/services/special_suppliers_service.py create mode 100644 app/services/tobacco_service.py create mode 100644 app/ui/__init__.py create mode 100644 app/ui/action_handlers.py create mode 100644 app/ui/barcode_editor.py create mode 100644 app/ui/command_runner.py create mode 100644 app/ui/config_dialog.py create mode 100644 app/ui/error_utils.py create mode 100644 app/ui/file_operations.py create mode 100644 app/ui/logging_ui.py create mode 100644 app/ui/main_window.py create mode 100644 app/ui/result_previews.py create mode 100644 app/ui/shortcuts.py create mode 100644 app/ui/theme.py create mode 100644 app/ui/ui_widgets.py create mode 100644 app/ui/user_settings.py create mode 100644 build_exe.py create mode 100644 config.ini create mode 100644 config/barcode_mappings.json create mode 100644 config/config.ini create mode 100644 config/suppliers_config.json create mode 100644 docs/SYSTEM_ARCHITECTURE.md create mode 100644 headless_api.py create mode 100644 requirements.txt create mode 100644 templates/商品资料.xlsx create mode 100644 templates/银豹-采购单模板.xls create mode 100644 tests/__init__.py create mode 100644 tests/test_calculator.py create mode 100644 tests/test_column_mapper.py create mode 100644 tests/test_data_cleaner.py create mode 100644 tests/test_product_db.py create mode 100644 tests/test_rule_engine.py create mode 100644 tests/test_string_utils.py create mode 100644 tests/test_validators.py create mode 100644 启动器.py diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2eff444 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +# 百度 OCR API 配置 +BAIDU_API_KEY=your_api_key_here +BAIDU_SECRET_KEY=your_secret_key_here diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c861b2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# Environment +.env + +# Python +__pycache__/ +*.pyc +*.pyo +.pytest_cache/ +.venv/ + +# Build & dist +build/ +dist/ +release/ +*.spec + +# Logs & temp +logs/ +data/temp/ + +# Runtime outputs +data/output/ +data/result/ +data/input/ +data/product_cache.db +data/user_settings.json +*.db + +# Claude Code / IDE +.claude/ +.playwright-mcp/ +.trae/ + +# Old project +wework_xiaoai_bot/ + +# OS/IDE +.DS_Store +Thumbs.db +.idea/ +.vscode/ + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5cb1679 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,39 @@ +# Changelog + +## [v2.2.0] - 2026-03-31 +### Added +- **UI Simplification**: Removed dedicated buttons for Rongcheng and Tobacco; all Excel orders now use the intelligent auto-routing. +- **Enhanced Yang Biyue Support**: Fixed column mapping for Yang Biyue orders, ensuring standard fields (Barcode, Quantity, Price) are correctly extracted. +- **Headless API Auto-Detect**: `headless_api.py` now automatically distinguishes between Image (OCR) and Excel (Direct) inputs based on file extension. + +### Fixed +- **Yang Biyue Preprocessing**: Resolved issue where data was empty due to incorrect column renaming. +- **Interference Filtering**: Added logic to exclude distractor columns like "Settlement Unit" or "Base Quantity" during preprocessing. + +### Removed +- **Redundant Files**: Cleaned up `run.py`, `clean.py`, and unused CLI modules. +- **Legacy UI Elements**: Removed tobacco-specific keyboard shortcuts and help entries. + +## [v2.1.0] - 2026-03-30 +### Added +- **Intelligent Recognition**: Automated fingerprinting for Rongcheng Yigou, Tobacco, and Yang Biyue orders. +- **Auto-Routing**: `OrderService.process_excel` now automatically handles preprocessing without explicit flags. +- **Headless API Enhancements**: `headless_api.py` updated to support the new intelligent recognition mode. +- **Comprehensive Documentation**: Added `OPENCLAW_GUIDE.md` and `FINAL_UPDATE_REPORT.md`. + +### Fixed +- **Rongcheng Yigou**: Fixed barcode splitting issue where quantities were incorrectly distributed (30 to 5). +- **Tobacco Orders**: Corrected unit price calculation (divided by 10) and quantity calculation (multiplied by 10). +- **Identification Failure**: Fixed issue where `header=0` caused identification keywords at the very first row to be missed. + +## [v2.0.0] - 2026-03-25 +### Added +- **Headless API**: First release of `headless_api.py` for OpenClaw integration. +- **Price Validation**: Integration with PosPal item data for unit price auditing. +- **Asynchronous Logging**: GUI now uses a queue for log output to prevent UI freezing. + +## [v1.1.0] - 2026-03-10 +### Added +- **Rongcheng Yigou Support**: Initial support for Rongcheng Excel templates. +- **Tobacco Support**: Initial support for Tobacco Excel templates. +- **Excel Processor**: Refactored core processing logic into `ExcelProcessor`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a10215b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,146 @@ +# CLAUDE.md - 益选 OCR 订单处理系统 + +## 项目概述 + +益选 OCR 订单处理系统 (orc-order-v2) 是一个面向零售与分销场景的采购单处理工具。 + +**核心流程**: 图片 OCR → Excel 规范化 → 模板填充 → 合并导出 + +**目标系统**: 银豹 (PosPal) POS 系统 + +**技术栈**: Python 3.9+, Tkinter, Pandas, Baidu OCR API, xlrd/xlwt/openpyxl + +## 项目结构 + +``` +orc-order-v2/ +├── 启动器.py # 入口桩 (~13行, 仅导入 main) +├── headless_api.py # CLI 自动化接口 (OpenClaw 对接) +├── build_exe.py # PyInstaller 打包脚本 +├── config.ini # 全局配置 (API密钥、路径) +├── config/ +│ ├── config.ini # 配置副本 +│ ├── barcode_mappings.json # 条码映射规则 +│ └── suppliers_config.json # 供应商配置 (列映射/清洗规则/计算规则) +├── app/ +│ ├── config/ +│ │ ├── settings.py # ConfigManager 单例 +│ │ └── defaults.py # 默认配置 +│ ├── core/ +│ │ ├── excel/ +│ │ │ ├── processor.py # ExcelProcessor - 标准化转换核心 +│ │ │ ├── converter.py # UnitConverter - 单位转换与规格推断 +│ │ │ ├── merger.py # PurchaseOrderMerger - 采购单合并 +│ │ │ ├── validators.py # ProductValidator +│ │ │ └── handlers/ # 条码映射、单位转换处理器 +│ │ ├── handlers/ +│ │ │ ├── rule_engine.py # 通用规则引擎 (split/extract/normalize/mark) +│ │ │ ├── column_mapper.py # 列映射器 +│ │ │ ├── data_cleaner.py # 数据清洗器 +│ │ │ └── calculator.py # 计算器 +│ │ ├── ocr/ +│ │ │ ├── table_ocr.py # OCRProcessor +│ │ │ └── baidu_ocr.py # BaiduOCRClient +│ │ ├── processors/ +│ │ │ ├── base.py # BaseProcessor 抽象基类 +│ │ │ ├── tobacco_processor.py +│ │ │ ├── ocr_processor.py +│ │ │ └── supplier_processors/ +│ │ │ └── generic_supplier_processor.py +│ │ └── utils/ +│ │ ├── file_utils.py # 文件操作工具 +│ │ ├── log_utils.py # 日志工具 +│ │ ├── string_utils.py # 字符串工具 +│ │ └── dialog_utils.py # Tkinter 对话框工具 +│ ├── services/ +│ │ ├── order_service.py # 订单服务 (智能路由分发) +│ │ ├── ocr_service.py # OCR 服务 +│ │ ├── processor_service.py # 处理器调度服务 +│ │ ├── tobacco_service.py # 烟草公司专用服务 +│ │ └── special_suppliers_service.py # 特殊供应商服务 (蓉城/杨碧月) +│ └── ui/ # GUI 模块 (从启动器.py拆分) +│ ├── error_utils.py # L0 错误对话框 +│ ├── theme.py # L0 主题管理 (THEMES, create_modern_button) +│ ├── logging_ui.py # L0 日志队列与GUI日志处理器 +│ ├── ui_widgets.py # L0 StatusBar, ProgressReporter, center_window +│ ├── user_settings.py # L1 用户设置与最近文件管理 +│ ├── result_previews.py # L1 处理结果预览对话框 +│ ├── command_runner.py # L1 命令执行器 (subprocess + 日志重定向) +│ ├── file_operations.py # L2 文件选择/清理/目录操作 +│ ├── action_handlers.py # L2 业务操作 (OCR/Excel/合并/拖拽) +│ ├── barcode_editor.py # L2 条码映射编辑 +│ ├── config_dialog.py # L3 系统设置对话框 +│ ├── shortcuts.py # L3 键盘快捷键绑定 +│ └── main_window.py # L4 main() 主窗口构建 +├── templates/ +│ ├── 银豹-采购单模板.xls # 输出模板 +│ └── 商品资料.xlsx # 单价校验参考数据 +├── data/ +│ ├── input/ # 输入文件 +│ ├── output/ # OCR 输出 +│ ├── result/ # 最终采购单 +│ └── user_settings.json # 用户设置 +└── docs/ + └── SYSTEM_ARCHITECTURE.md # 系统架构文档 +``` + +## 命令与运行 + +```bash +# GUI 模式 +python 启动器.py + +# CLI 模式 (OpenClaw 对接) +python headless_api.py [input] [--excel|--tobacco|--rongcheng] [--barcode X --target Y] + +# 打包 EXE +python build_exe.py + +# 条码映射更新 +python headless_api.py --update-mapping --barcode 6920584471055 --target 6920584471017 +``` + +## 供应商智能识别逻辑 + +系统通过扫描 Excel 前 50 行内容特征自动路由: + +| 供应商 | 识别特征 | 预处理逻辑 | +|--------|----------|-----------| +| 烟草公司 | "专卖证号" 或 "510109104938" | B/E/G/H 列映射, 数量*10, 单价/10 | +| 蓉城易购 | "RCDH" | E/N/Q/S 列映射, 多条码分裂均分数量 | +| 杨碧月 | "经手人" + "杨碧月" | 列对齐, 单位转换 (件→瓶) | +| 通用供应商 | suppliers_config.json 配置 | 列映射 + 规则引擎 | + +## 配置系统 + +- **ConfigManager** (`app/config/settings.py`): 单例模式, 基于 configparser 读取 `config.ini` +- **供应商配置** (`config/suppliers_config.json`): JSON 格式, 定义列映射/清洗规则/计算规则 +- **条码映射** (`config/barcode_mappings.json`): 运行时可更新的条码转换规则 + +## 关键约定 + +### 输出格式 +- 银豹采购单模板: 4 列 — 条码(B), 采购量(C), 赠送量(D), 采购单价(E) +- 单价保留 4 位小数, 使用 xlwt.XFStyle +- 采购单文件名: `采购单_{原文件名}.xls` + +### 单位转换规则 +- "件"/"箱"/"提"/"盒" → 数量*包装数量, 单价/包装数量, 单位→"瓶" +- 赠品: 价格为 0 或金额为 0 的行标记为赠品 +- 条码映射优先于单位转换 + +### 规格推断 +- 从商品名称推断: "24入纸箱" → 1*24, "450g*15" → 1*15 +- 支持三级规格: 1*5*12 +- OCR 修正: "IL" → "1L", "6oo" → "600" + +## 已知技术债务 + +1. ~~**启动器.py 过大**~~ (已拆分为 13 个 `app/ui/` 模块, 入口桩仅 13 行) +2. **代码重复**: 表头识别、列映射、金额解析在多处重复实现 +3. **配置不统一**: config.ini + suppliers_config.json + 硬编码路径混用 +4. **无测试**: 测试目录为空, 无自动化测试 +5. **旧格式依赖**: xlrd/xlwt 仅支持 .xls, 不支持 .xlsx 写入 +6. **API 密钥明文**: config.ini 中百度 OCR API 密钥未加密 +7. **路径硬编码**: config.ini 中 `template_folder = E:\2025Code\python\orc-order-v2\templates` +8. **日志不统一**: 混用 `get_logger()` 和 `logging.getLogger()` diff --git a/README.md b/README.md new file mode 100644 index 0000000..0790012 --- /dev/null +++ b/README.md @@ -0,0 +1,110 @@ +# 益选 OCR 订单处理系统 + +面向零售与分销场景的采购单处理工具,支持图片 OCR → Excel 规范化 → 模板填充 → 合并导出全流程,输出适配银豹 (PosPal) POS 系统。 + +## 核心功能 + +- **智能供应商识别**:自动扫描 Excel 前 50 行内容特征,路由到对应的预处理逻辑(蓉城易购、烟草公司、杨碧月等) +- **图片 OCR**:调用百度 OCR 表格识别 API,将采购单图片转为结构化 Excel +- **规则引擎**:支持列映射、数据清洗、单位转换、规格推断、赠品标记等自动化规则 +- **条码映射**:可配置的条码转换规则,支持运行时编辑和云端同步 +- **单价校验**:自动比对 `商品资料.xlsx`,价差超过 1.0 元触发预警 +- **云端同步**:通过 Gitea REST API 在多台设备间同步配置文件(条码映射、供应商配置、商品资料、采购模板) +- **拖拽一键处理**:拖入图片或 Excel 自动走完 OCR → 规范化 → 合并全流程 +- **CLI 接口**:`headless_api.py` 支持无界面自动化调用 + +## 快速开始 + +```bash +# 安装依赖 +pip install -r requirements.txt + +# GUI 模式 +python 启动器.py + +# CLI 模式 +python headless_api.py data/input/xxx.xlsx +python headless_api.py data/input/xxx.jpg --barcode 6920584471055 --target 6920584471017 + +# 打包 EXE +python build_exe.py +``` + +## 项目结构 + +``` +├── 启动器.py # GUI 入口 +├── headless_api.py # CLI 自动化接口 +├── config.ini # 全局配置(API密钥、路径、Gitea) +├── config/ +│ ├── config.ini # 配置副本 +│ ├── barcode_mappings.json # 条码映射规则 +│ └── suppliers_config.json # 供应商配置(列映射/规则引擎) +├── app/ +│ ├── config/ # 配置管理(ConfigManager 单例) +│ ├── core/ +│ │ ├── excel/ # Excel 处理(标准化、转换、合并、校验) +│ │ ├── handlers/ # 规则引擎、列映射、数据清洗、计算器 +│ │ ├── ocr/ # 百度 OCR 客户端 +│ │ ├── processors/ # 处理器(通用/烟草/OCR) +│ │ └── utils/ # 工具(日志、文件、字符串、云端同步、对话框) +│ ├── services/ # 业务服务(订单、OCR、处理器调度) +│ └── ui/ # GUI 模块(主题、日志、快捷键、主窗口) +├── templates/ +│ ├── 银豹-采购单模板.xls # 输出模板(条码/采购量/赠送量/单价) +│ └── 商品资料.xlsx # 单价校验参考数据 +├── data/ +│ ├── input/ # 输入文件 +│ ├── output/ # OCR 输出 +│ └── result/ # 最终采购单 +└── tests/ # 单元测试(191 个) +``` + +## 供应商智能路由 + +| 供应商 | 识别特征 | 处理逻辑 | +|--------|----------|----------| +| 烟草公司 | "专卖证号" 或 "510109104938" | B/E/G/H 列映射,数量×10,单价÷10 | +| 蓉城易购 | "RCDH" | E/N/Q/S 列映射,多条码分裂均分数量 | +| 杨碧月 | "经手人" + "杨碧月" | 列对齐,单位转换(件→瓶) | +| 通用供应商 | `suppliers_config.json` 配置 | 列映射 + 规则引擎 | + +## 云端同步 + +通过 Gitea REST API 在多台设备间同步配置,无需 git 客户端。 + +**支持同步的文件:** +- 条码映射 (`barcode_mappings.json`) +- 供应商配置 (`suppliers_config.json`) +- 商品资料 (`templates/商品资料.xlsx`) +- 采购单模板 (`templates/银豹-采购单模板.xls`) + +**配置方式:** +1. 系统设置 → 填入 Gitea 地址、仓库信息、Access Token +2. 主窗口 → "云端同步" 按钮 → 选择文件推拉 + +**Gitea 仓库:** `https://gitea.94kan.cn/houhuan/yixuan-sync-data` + +## 配置说明 + +| 配置项 | 文件 | 说明 | +|--------|------|------| +| API 密钥 | `.env` 或 `config.ini` | 百度 OCR API,优先从环境变量读取 | +| Gitea Token | `.env` 或 `config.ini` | 云端同步 Token,优先从环境变量读取 | +| 供应商规则 | `config/suppliers_config.json` | 列映射、清洗规则、计算规则 | +| 条码映射 | `config/barcode_mappings.json` | 条码转换规则,运行时可更新 | + +## 构建打包 + +```bash +pip install pyinstaller +python build_exe.py +# 输出: dist/OCR订单处理系统.exe +# 便携包: release/OCR订单处理系统.exe(含模板和商品资料) +``` + +## 测试 + +```bash +python -m pytest tests/ -v +``` diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..1c563d5 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,8 @@ +""" +OCR订单处理系统 +--------------- +用于自动识别和处理Excel格式的订单文件的系统。 +支持多种格式的订单处理,包括普通订单和赠品订单的处理。 +""" + +__version__ = '2.0.0' \ No newline at end of file diff --git a/app/config/__init__.py b/app/config/__init__.py new file mode 100644 index 0000000..9331d71 --- /dev/null +++ b/app/config/__init__.py @@ -0,0 +1,5 @@ +""" +OCR订单处理系统 - 配置模块 +------------------------ +负责管理系统配置,包括API密钥、路径和处理选项。 +""" \ No newline at end of file diff --git a/app/config/defaults.py b/app/config/defaults.py new file mode 100644 index 0000000..9904a87 --- /dev/null +++ b/app/config/defaults.py @@ -0,0 +1,49 @@ +""" +默认配置 +------- +包含系统的默认配置值。 +""" + +# 默认配置 +DEFAULT_CONFIG = { + 'API': { + 'api_key': '', # 将从配置文件中读取 + 'secret_key': '', # 将从配置文件中读取 + 'timeout': '30', + 'max_retries': '3', + 'retry_delay': '2', + 'api_url': 'https://aip.baidubce.com/rest/2.0/ocr/v1/table', + 'token_url': 'https://aip.baidubce.com/oauth/2.0/token', + 'form_ocr_url': 'https://aip.baidubce.com/rest/2.0/solution/v1/form_ocr/get_request_result' + }, + 'Paths': { + 'input_folder': 'data/input', + 'output_folder': 'data/output', + 'temp_folder': 'data/temp', + 'template_folder': 'templates', + 'template_file': '银豹-采购单模板.xls', + 'processed_record': 'data/processed_files.json', + 'data_dir': 'data', + 'product_db': 'data/product_cache.db' + }, + 'Performance': { + 'max_workers': '4', + 'batch_size': '5', + 'skip_existing': 'true' + }, + 'File': { + 'allowed_extensions': '.jpg,.jpeg,.png,.bmp', + 'excel_extension': '.xlsx', + 'max_file_size_mb': '4' + }, + 'Templates': { + 'purchase_order': '银豹-采购单模板.xls', + 'item_data': '商品资料.xlsx' + }, + 'Gitea': { + 'base_url': 'https://gitea.94kan.cn', + 'owner': 'houhuan', + 'repo': 'yixuan-sync-data', + 'token': '' + } +} \ No newline at end of file diff --git a/app/config/settings.py b/app/config/settings.py new file mode 100644 index 0000000..9717513 --- /dev/null +++ b/app/config/settings.py @@ -0,0 +1,176 @@ +""" +配置管理模块 +----------- +提供统一的配置加载、访问和保存功能。 +""" + +import os +import configparser +from typing import Dict, List, Optional, Any + +from dotenv import load_dotenv +from ..core.utils.log_utils import get_logger +from .defaults import DEFAULT_CONFIG + +# 加载 .env 文件 +load_dotenv() + +logger = get_logger(__name__) + +class ConfigManager: + """ + 配置管理类,负责加载和保存配置 + 单例模式确保全局只有一个配置实例 + """ + _instance = None + + def __new__(cls, config_file=None): + """单例模式实现""" + if cls._instance is None: + cls._instance = super(ConfigManager, cls).__new__(cls) + cls._instance._init(config_file) + return cls._instance + + def _init(self, config_file): + """初始化配置管理器""" + self.config_file = config_file or 'config.ini' + self.config = configparser.ConfigParser() + self.load_config() + + def load_config(self) -> None: + """ + 加载配置文件,如果不存在则创建默认配置 + API 密钥优先从环境变量 (.env) 读取 + """ + if not os.path.exists(self.config_file): + self.create_default_config() + else: + try: + # 先读取现有配置 + self.config.read(self.config_file, encoding='utf-8') + + # 检查是否有缺失的配置项,只添加缺失的项 + for section, options in DEFAULT_CONFIG.items(): + if not self.config.has_section(section): + self.config.add_section(section) + + for option, value in options.items(): + if not self.config.has_option(section, option): + self.config.set(section, option, value) + + # API 密钥优先从环境变量读取 + self._override_from_env() + + # 保存更新后的配置 + self.save_config() + logger.info(f"已加载并更新配置文件: {self.config_file}") + except Exception as e: + logger.error(f"加载配置文件时出错: {e}") + logger.info("使用默认配置") + self.create_default_config(save=False) + + def _override_from_env(self) -> None: + """从环境变量覆盖敏感配置""" + env_mapping = { + ('API', 'api_key'): 'BAIDU_API_KEY', + ('API', 'secret_key'): 'BAIDU_SECRET_KEY', + ('Gitea', 'token'): 'GITEA_TOKEN', + } + for (section, option), env_key in env_mapping.items(): + env_val = os.getenv(env_key, '').strip() + if env_val: + self.config.set(section, option, env_val) + + def create_default_config(self, save: bool = True) -> None: + """创建默认配置""" + for section, options in DEFAULT_CONFIG.items(): + if not self.config.has_section(section): + self.config.add_section(section) + + for option, value in options.items(): + self.config.set(section, option, value) + + if save: + self.save_config() + logger.info(f"已创建默认配置文件: {self.config_file}") + + def save_config(self) -> None: + """保存配置到文件(API 密钥不写入文件)""" + try: + # 保存前临时清空 API 密钥,避免写入文件 + saved_keys = {} + for option in ('api_key', 'secret_key'): + saved_keys[option] = self.config.get('API', option, fallback='') + self.config.set('API', option, '') + + with open(self.config_file, 'w', encoding='utf-8') as f: + self.config.write(f) + + # 恢复内存中的值 + for option, val in saved_keys.items(): + self.config.set('API', option, val) + + logger.info(f"配置已保存到: {self.config_file}") + except Exception as e: + logger.error(f"保存配置文件时出错: {e}") + + def get(self, section: str, option: str, fallback: Any = None) -> Any: + """获取配置值""" + return self.config.get(section, option, fallback=fallback) + + def getint(self, section: str, option: str, fallback: int = 0) -> int: + """获取整数配置值""" + return self.config.getint(section, option, fallback=fallback) + + def getfloat(self, section: str, option: str, fallback: float = 0.0) -> float: + """获取浮点数配置值""" + return self.config.getfloat(section, option, fallback=fallback) + + def getboolean(self, section: str, option: str, fallback: bool = False) -> bool: + """获取布尔配置值""" + return self.config.getboolean(section, option, fallback=fallback) + + def get_list(self, section: str, option: str, fallback: str = "", delimiter: str = ",") -> List[str]: + """获取列表配置值(逗号分隔的字符串转为列表)""" + value = self.get(section, option, fallback) + return [item.strip() for item in value.split(delimiter) if item.strip()] + + def update(self, section: str, option: str, value: Any) -> None: + """更新配置选项""" + if not self.config.has_section(section): + self.config.add_section(section) + + self.config.set(section, option, str(value)) + logger.debug(f"更新配置: [{section}] {option} = {value}") + + def get_path(self, section: str, option: str, fallback: str = "", create: bool = False) -> str: + """ + 获取路径配置并确保它是一个有效的绝对路径 + 如果create为True,则自动创建该目录 + """ + from pathlib import Path + path_str = self.get(section, option, fallback) + path = Path(path_str) + + if not path.is_absolute(): + # 相对路径,转为绝对路径(相对于项目根目录) + path = Path(os.getcwd()) / path + + if create: + try: + # 智能判断是文件还是目录 + # 如果有后缀名则认为是文件,创建其父目录 + if path.suffix: + directory = path.parent + if not directory.exists(): + directory.mkdir(parents=True, exist_ok=True) + logger.info(f"已创建父目录: {directory}") + else: + # 否则认为是目录路径 + if not path.exists(): + path.mkdir(parents=True, exist_ok=True) + logger.info(f"已创建目录: {path}") + except Exception as e: + logger.error(f"创建目录失败: {path}, 错误: {e}") + + return str(path.absolute()) \ No newline at end of file diff --git a/app/core/db/__init__.py b/app/core/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/core/db/product_db.py b/app/core/db/product_db.py new file mode 100644 index 0000000..478a165 --- /dev/null +++ b/app/core/db/product_db.py @@ -0,0 +1,214 @@ +""" +商品资料 SQLite 数据库 + +将商品资料 (条码/名称/进货价/单位) 存储在 SQLite 中, +支持从 Excel 自动导入和按条码快速查询。 +""" + +import os +import sqlite3 +from datetime import datetime +from typing import Dict, List, Optional + +import pandas as pd + +from ..utils.log_utils import get_logger +from ..utils.file_utils import smart_read_excel +from ...core.handlers.column_mapper import ColumnMapper + +logger = get_logger(__name__) + + +class ProductDatabase: + """商品资料 SQLite 数据库""" + + SCHEMA = """ + CREATE TABLE IF NOT EXISTS products ( + barcode TEXT PRIMARY KEY, + name TEXT DEFAULT '', + price REAL DEFAULT 0.0, + unit TEXT DEFAULT '', + updated_at TEXT + ); + """ + + def __init__(self, db_path: str, excel_source: str): + """初始化数据库,如果 SQLite 不存在则自动从 Excel 导入 + + Args: + db_path: SQLite 数据库文件路径 + excel_source: 商品资料 Excel 文件路径 + """ + self.db_path = db_path + self.excel_source = excel_source + self._ensure_db() + + def _connect(self) -> sqlite3.Connection: + return sqlite3.connect(self.db_path) + + def _ensure_db(self): + """确保数据库存在,不存在则从 Excel 导入""" + if os.path.exists(self.db_path): + return + + if not os.path.exists(self.excel_source): + logger.warning(f"商品资料 Excel 不存在,跳过导入: {self.excel_source}") + self._create_empty_db() + return + + logger.info(f"首次运行,从 Excel 导入商品资料: {self.excel_source}") + os.makedirs(os.path.dirname(self.db_path), exist_ok=True) + self._create_empty_db() + count = self.import_from_excel(self.excel_source) + logger.info(f"商品资料导入完成: {count} 条记录") + + def _create_empty_db(self): + """创建空数据库""" + conn = self._connect() + try: + conn.executescript(self.SCHEMA) + conn.commit() + finally: + conn.close() + + def import_from_excel(self, excel_path: str) -> int: + """从 Excel 导入商品资料 + + Args: + excel_path: Excel 文件路径 + + Returns: + 导入的记录数 + """ + df = smart_read_excel(excel_path) + if df is None or df.empty: + logger.warning(f"Excel 文件为空或读取失败: {excel_path}") + return 0 + + # 查找条码列 + barcode_col = ColumnMapper.find_column(list(df.columns), 'barcode') + if not barcode_col: + logger.error(f"Excel 中未找到条码列: {list(df.columns)}") + return 0 + + # 查找进货价列 + price_col = ColumnMapper.find_column(list(df.columns), 'unit_price') + # 进货价可能没有标准别名,补充查找 + if not price_col: + for col in df.columns: + col_str = str(col).strip() + if '进货价' in col_str: + price_col = col + break + + # 查找名称列和单位列 (可选) + name_col = ColumnMapper.find_column(list(df.columns), 'name') + unit_col = ColumnMapper.find_column(list(df.columns), 'unit') + + now = datetime.now().isoformat() + rows = [] + for _, row in df.iterrows(): + barcode = str(row.get(barcode_col, '')).strip() + if not barcode or barcode == 'nan': + continue + + price = 0.0 + if price_col: + try: + p = row.get(price_col) + if p is not None and str(p).strip() not in ('', 'nan', 'None'): + price = float(p) + except (ValueError, TypeError): + pass + + name = str(row.get(name_col, '')).strip() if name_col else '' + if name == 'nan': + name = '' + unit = str(row.get(unit_col, '')).strip() if unit_col else '' + if unit == 'nan': + unit = '' + + rows.append((barcode, name, price, unit, now)) + + if not rows: + logger.warning(f"Excel 中未解析出有效记录: {excel_path}") + return 0 + + conn = self._connect() + try: + conn.executemany( + "INSERT OR REPLACE INTO products (barcode, name, price, unit, updated_at) " + "VALUES (?, ?, ?, ?, ?)", + rows + ) + conn.commit() + finally: + conn.close() + + return len(rows) + + def reimport(self) -> int: + """重新从 Excel 导入(清空现有数据后重新导入) + + Returns: + 导入的记录数 + """ + conn = self._connect() + try: + conn.execute("DELETE FROM products") + conn.commit() + finally: + conn.close() + return self.import_from_excel(self.excel_source) + + def get_price(self, barcode: str) -> Optional[float]: + """按条码查询进货价 + + Args: + barcode: 商品条码 + + Returns: + 进货价,未找到返回 None + """ + conn = self._connect() + try: + cursor = conn.execute( + "SELECT price FROM products WHERE barcode = ?", + (str(barcode).strip(),) + ) + row = cursor.fetchone() + return row[0] if row else None + finally: + conn.close() + + def get_prices(self, barcodes: List[str]) -> Dict[str, float]: + """批量查询进货价 + + Args: + barcodes: 条码列表 + + Returns: + {条码: 进货价} 字典,未找到的不包含 + """ + if not barcodes: + return {} + + conn = self._connect() + try: + placeholders = ','.join('?' * len(barcodes)) + cursor = conn.execute( + f"SELECT barcode, price FROM products WHERE barcode IN ({placeholders})", + [str(b).strip() for b in barcodes] + ) + return {row[0]: row[1] for row in cursor.fetchall()} + finally: + conn.close() + + def count(self) -> int: + """返回商品总数""" + conn = self._connect() + try: + cursor = conn.execute("SELECT COUNT(*) FROM products") + return cursor.fetchone()[0] + finally: + conn.close() diff --git a/app/core/excel/__init__.py b/app/core/excel/__init__.py new file mode 100644 index 0000000..3d49a8b --- /dev/null +++ b/app/core/excel/__init__.py @@ -0,0 +1,5 @@ +""" +OCR订单处理系统 - Excel处理模块 +---------------------------- +提供Excel文件处理、数据提取和转换功能。 +""" \ No newline at end of file diff --git a/app/core/excel/converter.py b/app/core/excel/converter.py new file mode 100644 index 0000000..3de8b8f --- /dev/null +++ b/app/core/excel/converter.py @@ -0,0 +1,535 @@ +""" +单位转换模块 +---------- +提供单位转换功能,支持规格推断和单位自动提取。 +""" + +import re +import logging +import os +import json +from typing import Dict, Tuple, Optional, Any, List, Union + +from ..utils.log_utils import get_logger +from .handlers.barcode_mapper import BarcodeMapper +from .handlers.unit_converter_handlers import ( + JianUnitHandler, BoxUnitHandler, TiHeUnitHandler, + GiftUnitHandler, UnitHandler +) +from .validators import ProductValidator + +logger = get_logger(__name__) + +# 条码映射配置文件路径 +BARCODE_MAPPING_CONFIG = "config/barcode_mappings.json" + +class UnitConverter: + """ + 单位转换器:处理不同单位之间的转换,支持从商品名称推断规格 + """ + + def __init__(self): + """ + 初始化单位转换器 + """ + # 加载特殊条码配置 + self.special_barcodes = self.load_barcode_mappings() + + # 规格推断的正则表达式模式 + self.spec_patterns = [ + # 1*6、1x12、1X20等格式 + (r'(\d+)[*xX×](\d+)', r'\1*\2'), + # 1*5*12和1x5x12等三级格式 + (r'(\d+)[*xX×](\d+)[*xX×](\d+)', r'\1*\2*\3'), + # "xx入"格式,如"12入"、"24入" + (r'(\d+)入', r'1*\1'), + # "xxL*1"或"xx升*1"格式 + (r'([\d\.]+)[L升][*xX×]?(\d+)?', r'\1L*\2' if r'\2' else r'\1L*1'), + # "xxkg*1"或"xx公斤*1"格式 + (r'([\d\.]+)(?:kg|公斤)[*xX×]?(\d+)?', r'\1kg*\2' if r'\2' else r'\1kg*1'), + # "xxg*1"或"xx克*1"格式 + (r'([\d\.]+)(?:g|克)[*xX×]?(\d+)?', r'\1g*\2' if r'\2' else r'\1g*1'), + # "xxmL*1"或"xx毫升*1"格式 + (r'([\d\.]+)(?:mL|毫升)[*xX×]?(\d+)?', r'\1mL*\2' if r'\2' else r'\1mL*1'), + ] + + # 初始化处理程序 + self._init_handlers() + + # 初始化验证器 + self.validator = ProductValidator() + + def _init_handlers(self): + """ + 初始化各种处理程序 + """ + # 创建条码处理程序 + self.barcode_mapper = BarcodeMapper(self.special_barcodes) + + # 创建单位处理程序列表,优先级从高到低 + self.unit_handlers: List[UnitHandler] = [ + GiftUnitHandler(), # 首先处理赠品,优先级最高 + JianUnitHandler(), # 处理"件"单位 + BoxUnitHandler(), # 处理"箱"单位 + TiHeUnitHandler() # 处理"提"和"盒"单位 + ] + + def extract_unit_from_quantity(self, quantity_str: str) -> Tuple[Optional[float], Optional[str]]: + """ + 从数量字符串中提取单位 + + 支持的格式: + 1. "2箱" -> (2, "箱") + 2. "3件" -> (3, "件") + 3. "1.5提" -> (1.5, "提") + 4. "数量: 5盒" -> (5, "盒") + 5. "× 2瓶" -> (2, "瓶") + + Args: + quantity_str: 数量字符串,如"2箱"、"5件" + + Returns: + (数量, 单位)的元组,如果无法提取则返回(None, None) + """ + if not quantity_str or not isinstance(quantity_str, str): + return None, None + + # 清理字符串,移除前后空白和一些常见前缀 + cleaned_str = quantity_str.strip() + for prefix in ['数量:', '数量:', '×', 'x', 'X', '*']: + cleaned_str = cleaned_str.replace(prefix, '').strip() + + # 匹配数字+单位格式 (基本格式) + basic_match = re.match(r'^([\d\.]+)\s*([^\d\s\.]+)$', cleaned_str) + if basic_match: + try: + num = float(basic_match.group(1)) + unit = basic_match.group(2) + logger.info(f"从数量提取单位(基本格式): {quantity_str} -> 数量={num}, 单位={unit}") + return num, unit + except ValueError: + pass + + # 匹配更复杂的格式,如包含其他文本的情况 + complex_match = re.search(r'([\d\.]+)\s*([箱|件|瓶|提|盒|袋|桶|包|kg|g|升|毫升|L|ml|个])', cleaned_str) + if complex_match: + try: + num = float(complex_match.group(1)) + unit = complex_match.group(2) + logger.info(f"从数量提取单位(复杂格式): {quantity_str} -> 数量={num}, 单位={unit}") + return num, unit + except ValueError: + pass + + return None, None + + def extract_specification(self, text: str) -> Optional[str]: + """ + 从文本中提取规格信息 + + Args: + text: 文本字符串 + + Returns: + 提取的规格字符串,如果无法提取则返回None + """ + if not text or not isinstance(text, str): + return None + + # 处理XX入白膜格式,如"550纯净水24入白膜" + match = re.search(r'.*?(\d+)入白膜', text) + if match: + result = f"1*{match.group(1)}" + logger.info(f"提取规格(入白膜): {text} -> {result}") + return result + + # 尝试所有模式 + for pattern, replacement in self.spec_patterns: + match = re.search(pattern, text) + if match: + # 特殊处理三级格式,确保正确显示为1*5*12 + if '*' in replacement and replacement.count('*') == 1 and len(match.groups()) >= 2: + result = f"{match.group(1)}*{match.group(2)}" + logger.info(f"提取规格: {text} -> {result}") + return result + # 特殊处理三级规格格式 + elif '*' in replacement and replacement.count('*') == 2 and len(match.groups()) >= 3: + result = f"{match.group(1)}*{match.group(2)}*{match.group(3)}" + logger.info(f"提取三级规格: {text} -> {result}") + return result + # 一般情况 + else: + result = re.sub(pattern, replacement, text) + logger.info(f"提取规格: {text} -> {result}") + return result + + # 没有匹配任何模式 + return None + + def infer_specification_from_name(self, name: str) -> Optional[str]: + """ + 从商品名称中推断规格 + + 规则: + 1. "xx入纸箱" -> 1*xx (如"15入纸箱" -> 1*15) + 2. 直接包含规格 "1*15" -> 1*15 + 3. "xx纸箱" -> 1*xx (如"15纸箱" -> 1*15) + 4. "xx白膜" -> 1*xx (如"12白膜" -> 1*12) + 5. "xxL" 容量单位特殊处理 + 6. "xx(g|ml|毫升|克)*数字" -> 1*数字 (如"450g*15" -> 1*15) + + Args: + name: 商品名称 + + Returns: + 推断的规格,如果无法推断则返回None + """ + if not name or not isinstance(name, str): + return None + + # 记录原始商品名称,用于日志 + original_name = name + + # 新增模式: 处理重量/容量*数字格式,如"450g*15", "450ml*15" + # 忽略重量/容量值,只提取后面的数量作为规格 + weight_volume_pattern = r'.*?\d+(?:g|ml|毫升|克)[*xX×](\d+)' + match = re.search(weight_volume_pattern, name) + if match: + inferred_spec = f"1*{match.group(1)}" + logger.info(f"从名称推断规格(重量/容量*数量): {original_name} -> {inferred_spec}") + return inferred_spec + + # 特殊模式1.1: "xx入白膜" 格式,如"550纯净水24入白膜" -> "1*24" + pattern1_1 = r'.*?(\d+)入白膜' + match = re.search(pattern1_1, name) + if match: + inferred_spec = f"1*{match.group(1)}" + logger.info(f"从名称推断规格(入白膜): {original_name} -> {inferred_spec}") + return inferred_spec + + # 特殊模式1: "xx入纸箱" 格式,如"445水溶C血橙15入纸箱" -> "1*15" + pattern1 = r'.*?(\d+)入纸箱' + match = re.search(pattern1, name) + if match: + inferred_spec = f"1*{match.group(1)}" + logger.info(f"从名称推断规格(入纸箱): {original_name} -> {inferred_spec}") + return inferred_spec + + # 特殊模式2: 直接包含规格,如"500-东方树叶-乌龙茶1*15-纸箱装" -> "1*15" + pattern2 = r'.*?(\d+)[*xX×](\d+).*' + match = re.search(pattern2, name) + if match: + inferred_spec = f"{match.group(1)}*{match.group(2)}" + logger.info(f"从名称推断规格(直接格式): {original_name} -> {inferred_spec}") + return inferred_spec + + # 特殊模式3: "xx纸箱" 格式,如"500茶π蜜桃乌龙15纸箱" -> "1*15" + pattern3 = r'.*?(\d+)纸箱' + match = re.search(pattern3, name) + if match: + inferred_spec = f"1*{match.group(1)}" + logger.info(f"从名称推断规格(纸箱): {original_name} -> {inferred_spec}") + return inferred_spec + + # 特殊模式4: "xx白膜" 格式,如"1.5L水12白膜" 或 "550水24白膜" -> "1*12" 或 "1*24" + pattern4 = r'.*?(\d+)白膜' + match = re.search(pattern4, name) + if match: + inferred_spec = f"1*{match.group(1)}" + logger.info(f"从名称推断规格(白膜): {original_name} -> {inferred_spec}") + return inferred_spec + + # 特殊模式5: 容量单位带数量格式 "1.8L*8瓶" -> "1.8L*8" + volume_count_pattern = r'.*?([\d\.]+)[Ll升][*×xX](\d+).*' + match = re.search(volume_count_pattern, name) + if match: + volume = match.group(1) + count = match.group(2) + inferred_spec = f"{volume}L*{count}" + logger.info(f"从名称推断规格(容量*数量): {original_name} -> {inferred_spec}") + return inferred_spec + + # 特殊模式6: 简单容量单位如"12.9L桶装水" -> "12.9L*1" + simple_volume_pattern = r'.*?([\d\.]+)[Ll升].*' + match = re.search(simple_volume_pattern, name) + if match: + inferred_spec = f"{match.group(1)}L*1" + logger.info(f"从名称推断规格(简单容量): {original_name} -> {inferred_spec}") + return inferred_spec + + # 尝试通用模式匹配 + spec = self.extract_specification(name) + if spec: + logger.info(f"从名称推断规格(通用模式): {original_name} -> {spec}") + return spec + + return None + + def parse_specification(self, spec: str) -> Tuple[int, int, Optional[int]]: + """ + 解析规格字符串,支持1*12和1*5*12等格式 + + Args: + spec: 规格字符串 + + Returns: + (一级包装, 二级包装, 三级包装)元组,如果是二级包装,第三个值为None + """ + if not spec or not isinstance(spec, str): + return 1, 1, None + + try: + # 清理规格字符串,确保格式统一 + spec = re.sub(r'\s+', '', spec) # 移除所有空白 + spec = re.sub(r'[xX×]', '*', spec) # 统一分隔符为* + + logger.debug(f"解析规格: {spec}") + + # 新增:处理“1件=12桶/袋/盒...”等等式规格,统一为1*12 + eq_match = re.match(r'(\d+(?:\.\d+)?)\s*(?:件|箱|提|盒)\s*[==]\s*(\d+)\s*(?:瓶|桶|盒|支|个|袋|罐|包|卷)', spec) + if eq_match: + try: + level2 = int(eq_match.group(2)) + logger.info(f"解析等式规格: {spec} -> 1*{level2}") + return 1, level2, None + except ValueError: + pass + + # 处理三级包装,如1*5*12 + three_level_match = re.match(r'(\d+)[*](\d+)[*](\d+)', spec) + if three_level_match: + try: + level1 = int(three_level_match.group(1)) + level2 = int(three_level_match.group(2)) + level3 = int(three_level_match.group(3)) + logger.info(f"解析三级规格: {spec} -> {level1}*{level2}*{level3}") + return level1, level2, level3 + except ValueError: + pass + + # 处理带重量单位的规格,如5kg*6、500g*12等 + weight_match = re.match(r'([\d\.]+)(?:kg|g|克|千克|公斤)[*](\d+)', spec, re.IGNORECASE) + if weight_match: + try: + # 对于重量单位,使用1作为一级包装,后面的数字作为二级包装 + level2 = int(weight_match.group(2)) + logger.info(f"解析重量规格: {spec} -> 1*{level2}") + return 1, level2, None + except ValueError: + pass + + # 处理带容量单位的规格,如500ml*15, 1L*12等 + ml_match = re.match(r'(\d+)(?:ml|毫升)[*](\d+)', spec, re.IGNORECASE) + if ml_match: + try: + # 对于ml单位,使用1作为一级包装,后面的数字作为二级包装 + level2 = int(ml_match.group(2)) + logger.info(f"解析容量(ml)规格: {spec} -> 1*{level2}") + return 1, level2, None + except ValueError: + pass + + # 处理带L单位的规格,如1L*12等 + l_match = re.match(r'(\d+(?:\.\d+)?)[Ll升][*](\d+)', spec) + if l_match: + try: + # 对于L单位,正确提取第二部分作为包装数量 + level2 = int(l_match.group(2)) + logger.info(f"解析容量(L)规格: {spec} -> 1*{level2}") + return 1, level2, None + except ValueError: + pass + + # 处理二级包装,如1*12 + two_level_match = re.match(r'(\d+)[*](\d+)', spec) + if two_level_match: + try: + level1 = int(two_level_match.group(1)) + level2 = int(two_level_match.group(2)) + logger.info(f"解析二级规格: {spec} -> {level1}*{level2}") + return level1, level2, None + except ValueError: + pass + + # 特殊处理L/升为单位的规格,如12.5L*1 + volume_match = re.match(r'([\d\.]+)[L升][*xX×](\d+)', spec) + if volume_match: + try: + volume = float(volume_match.group(1)) + quantity = int(volume_match.group(2)) + logger.info(f"解析容量规格: {spec} -> {volume}L*{quantity}") + return 1, quantity, None + except ValueError: + pass + + # 处理不规范格式,如IL*12, 6oo*12等,从中提取数字部分作为包装数量 + # 只要规格中包含*和数字,就尝试提取*后面的数字作为件数 + irregular_match = re.search(r'[^0-9]*\*(\d+)', spec) + if irregular_match: + try: + level2 = int(irregular_match.group(1)) + logger.info(f"解析不规范规格: {spec} -> 1*{level2}") + return 1, level2, None + except ValueError: + pass + + # 默认值 + logger.warning(f"无法解析规格: {spec},使用默认值1*1") + return 1, 1, None + except Exception as e: + logger.error(f"解析规格时出错: {e}") + return 1, 1, None + + def process_unit_conversion(self, product: Dict) -> Dict: + """ + 处理单位转换,按照以下规则: + 1. 特殊条码: 优先处理特殊条码 + 2. 赠品处理: 对于赠品,维持数量转换但单价为0 + 3. "件"单位: 数量×包装数量, 单价÷包装数量, 单位转为"瓶" + 4. "箱"单位: 数量×包装数量, 单价÷包装数量, 单位转为"瓶" + 5. "提"和"盒"单位: 如果是三级规格, 按件处理; 如果是二级规格, 保持不变 + 6. 其他单位: 保持不变 + + Args: + product: 商品信息字典 + + Returns: + 处理后的商品信息字典 + """ + # 首先验证商品数据 + product = self.validator.validate_product(product) + + # 复制原始数据,避免修改原始字典 + result = product.copy() + + barcode = result.get('barcode', '') + specification = result.get('specification', '') + + # 跳过无效数据 + if not barcode: + return result + + # 先处理条码映射 + result = self.barcode_mapper.map_barcode(result) + + # 如果没有规格信息,无法进行单位转换 + if not specification: + # 尝试从商品名称推断规格 + inferred_spec = self.infer_specification_from_name(result.get('name', '')) + if inferred_spec: + result['specification'] = inferred_spec + logger.info(f"从商品名称推断规格: {result.get('name', '')} -> {inferred_spec}") + else: + return result + + # 解析规格信息 + level1, level2, level3 = self.parse_specification(result.get('specification', '')) + + # 使用单位处理程序处理单位转换 + for handler in self.unit_handlers: + if handler.can_handle(result): + return handler.handle(result, level1, level2, level3) + + # 没有找到适用的处理程序,保持不变 + logger.info(f"其他单位处理: 保持原样 数量: {result.get('quantity', 0)}, 单价: {result.get('price', 0)}, 单位: {result.get('unit', '')}") + return result + + def load_barcode_mappings(self) -> Dict[str, Dict[str, Any]]: + """ + 从配置文件加载条码映射 + + Returns: + 条码映射字典 + """ + # 默认映射 + default_mappings = { + '6925019900087': { + 'multiplier': 10, + 'target_unit': '瓶', + 'description': '特殊处理:数量*10,单位转换为瓶' + }, + '6921168593804': { + 'multiplier': 30, + 'target_unit': '瓶', + 'description': 'NFC产品特殊处理:每箱30瓶' + }, + '6901826888138': { + 'multiplier': 30, + 'target_unit': '瓶', + 'fixed_price': 112/30, + 'specification': '1*30', + 'description': '特殊处理: 规格1*30,数量*30,单价=112/30' + }, + # 条码映射配置 + '6920584471055': { + 'map_to': '6920584471017', + 'description': '条码映射:6920584471055 -> 6920584471017' + }, + '6925861571159': { + 'map_to': '69021824', + 'description': '条码映射:6925861571159 -> 69021824' + }, + '6923644268923': { + 'map_to': '6923644268480', + 'description': '条码映射:6923644268923 -> 6923644268480' + }, + # 添加特殊条码6958620703716,既需要特殊处理又需要映射 + '6958620703716': { + 'specification': '1*14', + 'map_to': '6958620703907', + 'description': '特殊处理: 规格1*14,同时映射到6958620703907' + } + } + + try: + # 检查配置文件是否存在 + if os.path.exists(BARCODE_MAPPING_CONFIG): + with open(BARCODE_MAPPING_CONFIG, 'r', encoding='utf-8') as file: + mappings = json.load(file) + logger.info(f"成功加载条码映射配置,共{len(mappings)}项") + return mappings + else: + # 创建默认配置文件 + self.save_barcode_mappings(default_mappings) + logger.info(f"创建默认条码映射配置,共{len(default_mappings)}项") + return default_mappings + except Exception as e: + logger.error(f"加载条码映射配置失败: {e}") + return default_mappings + + def save_barcode_mappings(self, mappings: Dict[str, Dict[str, Any]]) -> bool: + """ + 保存条码映射到配置文件 + + Args: + mappings: 条码映射字典 + + Returns: + 保存是否成功 + """ + try: + # 确保配置目录存在 + os.makedirs(os.path.dirname(BARCODE_MAPPING_CONFIG), exist_ok=True) + + # 写入配置文件 + with open(BARCODE_MAPPING_CONFIG, 'w', encoding='utf-8') as file: + json.dump(mappings, file, ensure_ascii=False, indent=2) + + logger.info(f"条码映射配置保存成功,共{len(mappings)}项") + return True + except Exception as e: + logger.error(f"保存条码映射配置失败: {e}") + return False + + def update_barcode_mappings(self, new_mappings: Dict[str, Dict[str, Any]]) -> bool: + """ + 更新条码映射配置 + + Args: + new_mappings: 新的条码映射字典 + + Returns: + 更新是否成功 + """ + self.special_barcodes = new_mappings + return self.save_barcode_mappings(new_mappings) diff --git a/app/core/excel/handlers/__init__.py b/app/core/excel/handlers/__init__.py new file mode 100644 index 0000000..fe768ae --- /dev/null +++ b/app/core/excel/handlers/__init__.py @@ -0,0 +1,11 @@ +""" +单位转换处理程序包 +----------------- +提供单位转换和条码处理的各种处理程序 +""" + +from typing import Dict, Any + +# 导出所有处理程序类 +from .barcode_mapper import BarcodeMapper +from .unit_converter_handlers import JianUnitHandler, BoxUnitHandler, TiHeUnitHandler, GiftUnitHandler, UnitHandler \ No newline at end of file diff --git a/app/core/excel/handlers/barcode_mapper.py b/app/core/excel/handlers/barcode_mapper.py new file mode 100644 index 0000000..979cded --- /dev/null +++ b/app/core/excel/handlers/barcode_mapper.py @@ -0,0 +1,83 @@ +""" +条码映射处理程序 +------------- +处理特殊条码的映射和转换 +""" + +import logging +from typing import Dict, Optional, Any + +from ...utils.log_utils import get_logger + +logger = get_logger(__name__) + + +class BarcodeMapper: + """ + 条码映射器:负责特殊条码的映射和处理 + """ + + def __init__(self, special_barcodes: Dict[str, Dict[str, Any]]): + """ + 初始化条码映射器 + + Args: + special_barcodes: 特殊条码配置字典 + """ + self.special_barcodes = special_barcodes or {} + + def map_barcode(self, product: Dict[str, Any]) -> Dict[str, Any]: + """ + 映射商品条码,处理特殊情况 + + Args: + product: 包含条码的商品信息字典 + + Returns: + 处理后的商品信息字典 + """ + result = product.copy() + barcode = result.get('barcode', '') + + # 如果条码不在特殊条码列表中,直接返回 + if not barcode or barcode not in self.special_barcodes: + return result + + special_config = self.special_barcodes[barcode] + + # 处理特殊倍数 + if 'multiplier' in special_config: + multiplier = special_config.get('multiplier', 1) + target_unit = special_config.get('target_unit', '瓶') + + # 数量乘以倍数 + quantity = result.get('quantity', 0) + new_quantity = quantity * multiplier + + # 单价除以倍数 + price = result.get('price', 0) + new_price = price / multiplier if price else 0 + + # 如果有固定单价,优先使用 + if 'fixed_price' in special_config: + new_price = special_config['fixed_price'] + logger.info(f"特殊条码({barcode})使用固定单价: {new_price}") + + # 如果有固定规格,设置规格 + if 'specification' in special_config: + result['specification'] = special_config['specification'] + logger.info(f"特殊条码({barcode})使用固定规格: {special_config['specification']}") + + logger.info(f"特殊条码处理: {barcode}, 数量: {quantity} -> {new_quantity}, 单价: {price} -> {new_price}, 单位: {result.get('unit', '')} -> {target_unit}") + + result['quantity'] = new_quantity + result['price'] = new_price + result['unit'] = target_unit + + # 处理条码映射 - 放在后面以便可以同时进行特殊处理和条码映射 + if 'map_to' in special_config: + new_barcode = special_config['map_to'] + logger.info(f"条码映射: {barcode} -> {new_barcode}") + result['barcode'] = new_barcode + + return result \ No newline at end of file diff --git a/app/core/excel/handlers/unit_converter_handlers.py b/app/core/excel/handlers/unit_converter_handlers.py new file mode 100644 index 0000000..9cce4e9 --- /dev/null +++ b/app/core/excel/handlers/unit_converter_handlers.py @@ -0,0 +1,286 @@ +""" +单位转换处理程序 +------------- +处理不同单位的转换逻辑 +""" + +import logging +from typing import Dict, Optional, Any, Tuple, Protocol +from abc import ABC, abstractmethod + +from ...utils.log_utils import get_logger + +logger = get_logger(__name__) + + +class UnitHandler(ABC): + """ + 单位处理器基类:定义单位处理接口 + """ + + @abstractmethod + def can_handle(self, product: Dict[str, Any]) -> bool: + """ + 检查是否可以处理该商品 + + Args: + product: 商品信息字典 + + Returns: + 是否可以处理 + """ + pass + + @abstractmethod + def handle(self, product: Dict[str, Any], level1: int, level2: int, level3: Optional[int]) -> Dict[str, Any]: + """ + 处理单位转换 + + Args: + product: 商品信息字典 + level1: 一级包装数量 + level2: 二级包装数量 + level3: 三级包装数量,可能为None + + Returns: + 处理后的商品信息字典 + """ + pass + + +class JianUnitHandler(UnitHandler): + """ + 处理"件"单位的转换 + """ + + def can_handle(self, product: Dict[str, Any]) -> bool: + """ + 检查是否可以处理该商品(单位为"件") + + Args: + product: 商品信息字典 + + Returns: + 是否可以处理 + """ + unit = str(product.get('unit', '')).strip() + # 匹配"件"、"件、"、"件装"等 + return unit == '件' or unit.startswith('件') + + def handle(self, product: Dict[str, Any], level1: int, level2: int, level3: Optional[int]) -> Dict[str, Any]: + """ + 处理"件"单位转换:数量×包装数量,单价÷包装数量,单位转为"瓶" + + Args: + product: 商品信息字典 + level1: 一级包装数量 + level2: 二级包装数量 + level3: 三级包装数量,可能为None + + Returns: + 处理后的商品信息字典 + """ + result = product.copy() + + quantity = result.get('quantity', 0) + price = result.get('price', 0) + + # 计算包装数量(二级*三级,如果无三级则仅二级) + packaging_count = level2 * (level3 or 1) + + # 数量×包装数量 + new_quantity = quantity * packaging_count + + # 单价÷包装数量 + new_price = price / packaging_count if price else 0 + + logger.info(f"件单位处理: 数量: {quantity} -> {new_quantity}, 单价: {price} -> {new_price}, 单位: 件 -> 瓶") + + result['quantity'] = new_quantity + result['price'] = new_price + result['unit'] = '瓶' + + return result + + +class BoxUnitHandler(UnitHandler): + """ + 处理"箱"单位的转换 + """ + + def can_handle(self, product: Dict[str, Any]) -> bool: + """ + 检查是否可以处理该商品(单位为"箱") + + Args: + product: 商品信息字典 + + Returns: + 是否可以处理 + """ + unit = str(product.get('unit', '')).strip() + # 匹配"箱"、"箱、"、"箱装"等 + return unit == '箱' or unit.startswith('箱') + + def handle(self, product: Dict[str, Any], level1: int, level2: int, level3: Optional[int]) -> Dict[str, Any]: + """ + 处理"箱"单位转换:数量×包装数量,单价÷包装数量,单位转为"瓶" + + Args: + product: 商品信息字典 + level1: 一级包装数量 + level2: 二级包装数量 + level3: 三级包装数量,可能为None + + Returns: + 处理后的商品信息字典 + """ + result = product.copy() + + quantity = result.get('quantity', 0) + price = result.get('price', 0) + + # 计算包装数量(二级*三级,如果无三级则仅二级) + packaging_count = level2 * (level3 or 1) + + # 数量×包装数量 + new_quantity = quantity * packaging_count + + # 单价÷包装数量 + new_price = price / packaging_count if price else 0 + + logger.info(f"箱单位处理: 数量: {quantity} -> {new_quantity}, 单价: {price} -> {new_price}, 单位: 箱 -> 瓶") + + result['quantity'] = new_quantity + result['price'] = new_price + result['unit'] = '瓶' + + return result + + +class TiHeUnitHandler(UnitHandler): + """ + 处理"提"和"盒"单位的转换 + """ + + def can_handle(self, product: Dict[str, Any]) -> bool: + """ + 检查是否可以处理该商品(单位为"提"或"盒") + + Args: + product: 商品信息字典 + + Returns: + 是否可以处理 + """ + unit = str(product.get('unit', '')).strip() + return unit in ['提', '盒'] or unit.startswith('提') or unit.startswith('盒') + + def handle(self, product: Dict[str, Any], level1: int, level2: int, level3: Optional[int]) -> Dict[str, Any]: + """ + 处理"提"和"盒"单位转换: + - 如果是三级规格,按件处理(数量×包装数量,单价÷包装数量,单位转为"瓶") + - 如果是二级规格,保持不变 + + Args: + product: 商品信息字典 + level1: 一级包装数量 + level2: 二级包装数量 + level3: 三级包装数量,可能为None + + Returns: + 处理后的商品信息字典 + """ + result = product.copy() + + quantity = result.get('quantity', 0) + price = result.get('price', 0) + unit = result.get('unit', '') + + # 如果是三级规格,按件处理 + if level3 is not None: + # 计算包装数量 - 只乘以最后一级数量 + packaging_count = level3 + + # 数量×包装数量 + new_quantity = quantity * packaging_count + + # 单价÷包装数量 + new_price = price / packaging_count if price else 0 + + logger.info(f"提/盒单位(三级规格)处理: 数量: {quantity} -> {new_quantity}, 单价: {price} -> {new_price}, 单位: {unit} -> 瓶") + + result['quantity'] = new_quantity + result['price'] = new_price + result['unit'] = '瓶' + else: + # 如果是二级规格,保持不变 + logger.info(f"提/盒单位(二级规格)处理: 保持原样 数量: {quantity}, 单价: {price}, 单位: {unit}") + + return result + + +class GiftUnitHandler(UnitHandler): + """ + 处理赠品的特殊情况 + """ + + def can_handle(self, product: Dict[str, Any]) -> bool: + """ + 检查是否可以处理该商品(是否为赠品) + + Args: + product: 商品信息字典 + + Returns: + 是否可以处理 + """ + return product.get('is_gift', False) is True + + def handle(self, product: Dict[str, Any], level1: int, level2: int, level3: Optional[int]) -> Dict[str, Any]: + """ + 处理赠品的单位转换: + - 对于件/箱单位,数量仍然需要转换,但赠品的单价保持为0 + + Args: + product: 商品信息字典 + level1: 一级包装数量 + level2: 二级包装数量 + level3: 三级包装数量,可能为None + + Returns: + 处理后的商品信息字典 + """ + result = product.copy() + + unit = result.get('unit', '') + quantity = result.get('quantity', 0) + + # 根据单位类型选择适当的包装数计算 + if unit in ['件', '箱']: + # 计算包装数量(二级*三级,如果无三级则仅二级) + packaging_count = level2 * (level3 or 1) + + # 数量×包装数量 + new_quantity = quantity * packaging_count + + logger.info(f"赠品{unit}单位处理: 数量: {quantity} -> {new_quantity}, 单价: 0, 单位: {unit} -> 瓶") + + result['quantity'] = new_quantity + result['unit'] = '瓶' + elif unit in ['提', '盒'] and level3 is not None: + # 对于三级规格的提/盒,类似件处理 + new_quantity = quantity * level3 + + logger.info(f"赠品{unit}单位(三级规格)处理: 数量: {quantity} -> {new_quantity}, 单价: 0, 单位: {unit} -> 瓶") + + result['quantity'] = new_quantity + result['unit'] = '瓶' + else: + # 其他情况保持不变 + logger.info(f"赠品{unit}单位处理: 保持原样 数量: {quantity}, 单价: 0, 单位: {unit}") + + # 确保单价为0 + result['price'] = 0 + + return result \ No newline at end of file diff --git a/app/core/excel/merger.py b/app/core/excel/merger.py new file mode 100644 index 0000000..f325a09 --- /dev/null +++ b/app/core/excel/merger.py @@ -0,0 +1,423 @@ +""" +订单合并模块 +---------- +提供采购单合并功能,将多个采购单合并为一个。 +""" + +import os +import re +import pandas as pd +import numpy as np +import xlrd +import xlwt +from xlutils.copy import copy as xlcopy +from typing import Dict, List, Optional, Tuple, Union, Any, Callable +from datetime import datetime + +from ...config.settings import ConfigManager +from ..utils.log_utils import get_logger +from ..handlers.column_mapper import ColumnMapper +from ..utils.file_utils import ( + ensure_dir, + get_file_extension, + get_files_by_extensions, + load_json, + save_json +) +from ..utils.string_utils import ( + clean_string, + clean_barcode, + format_barcode +) + +logger = get_logger(__name__) + +class PurchaseOrderMerger: + """ + 采购单合并器:将多个采购单Excel文件合并成一个文件 + """ + + def __init__(self, config): + """ + 初始化采购单合并器 + + Args: + config: 配置信息 + """ + self.config = config + + # 修复ConfigParser对象没有get_path方法的问题 + try: + # 获取输出目录 + self.output_dir = config.get('Paths', 'output_folder', fallback='data/output') + + # 确保目录存在 + os.makedirs(self.output_dir, exist_ok=True) + + # 记录实际路径 + logger.info(f"使用输出目录: {os.path.abspath(self.output_dir)}") + + # 获取模板文件路径 + template_folder = config.get('Paths', 'template_folder', fallback='templates') + template_name = config.get('Templates', 'purchase_order', fallback='银豹-采购单模板.xls') + + self.template_path = os.path.join(template_folder, template_name) + + # 检查模板文件是否存在 + if not os.path.exists(self.template_path): + logger.warning(f"模板文件不存在: {self.template_path}") + + # 用于记录已合并的文件 + self.merged_files_json = os.path.join(self.output_dir, "merged_files.json") + self.merged_files = self._load_merged_files() + + logger.info(f"初始化PurchaseOrderMerger完成,模板文件: {self.template_path}") + except Exception as e: + logger.error(f"初始化PurchaseOrderMerger失败: {e}") + raise + + def _load_merged_files(self) -> Dict[str, str]: + """ + 加载已合并文件的缓存 + + Returns: + 合并记录字典 + """ + return load_json(self.merged_files_json, {}) + + def _save_merged_files(self) -> None: + """保存已合并文件的缓存""" + save_json(self.merged_files, self.merged_files_json) + + def get_purchase_orders(self) -> List[str]: + """ + 获取result目录下的采购单Excel文件 + + Returns: + 采购单文件路径列表 + """ + # 采购单文件保存在data/result目录 + result_dir = "data/result" + logger.info(f"搜索目录 {result_dir} 中的采购单Excel文件") + + # 确保目录存在 + os.makedirs(result_dir, exist_ok=True) + + # 获取所有Excel文件 + all_files = get_files_by_extensions(result_dir, ['.xls', '.xlsx']) + + # 筛选采购单文件 + purchase_orders = [ + file for file in all_files + if os.path.basename(file).startswith('采购单_') + ] + + if not purchase_orders: + logger.warning(f"未在 {result_dir} 目录下找到采购单Excel文件") + return [] + + # 按修改时间排序,最新的在前 + purchase_orders.sort(key=lambda x: os.path.getmtime(x), reverse=True) + + logger.info(f"找到 {len(purchase_orders)} 个采购单Excel文件") + return purchase_orders + + def read_purchase_order(self, file_path: str) -> Optional[pd.DataFrame]: + """ + 读取采购单Excel文件 + + Args: + file_path: 采购单文件路径 + + Returns: + 数据帧,如果读取失败则返回None + """ + try: + # 读取Excel文件 + df = pd.read_excel(file_path) + logger.info(f"成功读取采购单文件: {file_path}") + + # 打印列名,用于调试 + logger.debug(f"Excel文件的列名: {df.columns.tolist()}") + + # 处理特殊情况:检查是否需要读取指定行作为标题行 + header_row_idx = ColumnMapper.detect_header_row(df, max_rows=5, min_matches=3) + if header_row_idx >= 0: + logger.info(f"检测到表头在第 {header_row_idx+1} 行") + + # 使用此行作为列名,数据从下一行开始 + header_row = df.iloc[header_row_idx].astype(str) + data_rows = df.iloc[header_row_idx+1:].reset_index(drop=True) + + # 为每一列分配名称(避免重复的列名) + new_columns = [] + for i, col in enumerate(header_row): + col_str = str(col) + if col_str == 'nan' or col_str == 'None' or pd.isna(col): + new_columns.append(f"Col_{i}") + else: + new_columns.append(col_str) + + # 使用新列名创建新的DataFrame + data_rows.columns = new_columns + df = data_rows + logger.debug(f"重新构建的数据帧列名: {df.columns.tolist()}") + + # 使用 ColumnMapper 统一查找列名(保留中文键名以兼容下游代码) + all_columns = df.columns.tolist() + logger.info(f"列名: {all_columns}") + + standard_to_chinese = { + 'barcode': '条码', + 'quantity': '采购量', + 'unit_price': '采购单价', + 'gift_quantity': '赠送量', + } + + mapped_columns = {} + for std_name, chinese_name in standard_to_chinese.items(): + matched = ColumnMapper.find_column(all_columns, std_name) + if matched: + mapped_columns[chinese_name] = matched + logger.info(f"列名映射: {matched} -> {chinese_name}") + + # 如果找到了必要的列,重命名列 + if mapped_columns: + rename_dict = {mapped_columns[key]: key for key in mapped_columns} + logger.info(f"列名重命名映射: {rename_dict}") + df = df.rename(columns=rename_dict) + logger.info(f"重命名后的列名: {df.columns.tolist()}") + else: + logger.warning(f"未找到可映射的列名: {file_path}") + + return df + + except Exception as e: + logger.error(f"读取采购单文件失败: {file_path}, 错误: {str(e)}") + return None + + def merge_purchase_orders(self, file_paths: List[str]) -> Optional[pd.DataFrame]: + """ + 合并多个采购单文件 + + Args: + file_paths: 采购单文件路径列表 + + Returns: + 合并后的数据帧,如果合并失败则返回None + """ + if not file_paths: + logger.warning("没有需要合并的采购单文件") + return None + + # 读取所有采购单文件 + dfs = [] + for file_path in file_paths: + df = self.read_purchase_order(file_path) + if df is not None: + dfs.append(df) + + if not dfs: + logger.warning("没有成功读取的采购单文件") + return None + + # 合并数据 + logger.info(f"开始合并 {len(dfs)} 个采购单文件") + + # 首先,整理每个数据帧以确保它们有相同的结构 + processed_dfs = [] + for i, df in enumerate(dfs): + # 确保必要的列存在 + required_columns = ['条码', '采购量', '采购单价'] + missing_columns = [col for col in required_columns if col not in df.columns] + + if missing_columns: + logger.warning(f"数据帧 {i} 缺少必要的列: {missing_columns}") + continue + + # 处理赠送量列不存在的情况 + if '赠送量' not in df.columns: + df['赠送量'] = 0 + + # 选择并清理需要的列 + cleaned_df = pd.DataFrame() + + # 清理条码 - 确保是字符串且无小数点 + cleaned_df['条码'] = df['条码'].apply(lambda x: format_barcode(x) if pd.notna(x) else '') + + # 清理采购量 - 确保是数字 + cleaned_df['采购量'] = pd.to_numeric(df['采购量'], errors='coerce').fillna(0) + + # 清理单价 - 确保是数字并保留4位小数 + cleaned_df['采购单价'] = pd.to_numeric(df['采购单价'], errors='coerce').fillna(0).round(4) + + # 清理赠送量 - 确保是数字 + cleaned_df['赠送量'] = pd.to_numeric(df['赠送量'], errors='coerce').fillna(0) + + # 过滤无效行 - 条码为空或采购量为0的行跳过 + valid_df = cleaned_df[(cleaned_df['条码'] != '') & (cleaned_df['采购量'] > 0)] + + if len(valid_df) > 0: + processed_dfs.append(valid_df) + logger.info(f"处理文件 {i+1}: 有效记录 {len(valid_df)} 行") + else: + logger.warning(f"处理文件 {i+1}: 没有有效记录") + + if not processed_dfs: + logger.warning("没有有效的数据帧用于合并") + return None + + # 将所有数据帧合并 + merged_df = pd.concat(processed_dfs, ignore_index=True) + + # 按条码和单价分组,合并相同商品 + # 四舍五入到4位小数,避免浮点误差导致相同价格被当作不同价格 + merged_df['采购单价'] = merged_df['采购单价'].round(4) + + # 对于同一条码和单价的商品,合并数量和赠送量 + result = merged_df.groupby(['条码', '采购单价'], as_index=False).agg({ + '采购量': 'sum', + '赠送量': 'sum' + }) + + # 排序,按条码升序 + result = result.sort_values('条码').reset_index(drop=True) + + # 设置为0的赠送量设为空 + result.loc[result['赠送量'] == 0, '赠送量'] = pd.NA + + logger.info(f"合并完成,共 {len(result)} 条商品记录") + return result + + def create_merged_purchase_order(self, df: pd.DataFrame) -> Optional[str]: + """ + 创建合并的采购单文件,完全按照银豹格式要求 + + Args: + df: 合并后的数据帧 + + Returns: + 输出文件路径,如果创建失败则返回None + """ + try: + # 打开模板文件 + template_workbook = xlrd.open_workbook(self.template_path, formatting_info=True) + template_sheet = template_workbook.sheet_by_index(0) + + # 首先分析模板结构,确定关键列的位置 + logger.info(f"分析模板结构") + for i in range(min(5, template_sheet.nrows)): + row_values = [str(cell.value).strip() for cell in template_sheet.row(i)] + logger.debug(f"模板第{i+1}行: {row_values}") + + # 银豹模板的标准列位置: + # 条码列(商品条码): B列(索引1) + barcode_col = 1 + # 采购量列: C列(索引2) + quantity_col = 2 + # 赠送量列: D列(索引3) + gift_col = 3 + # 采购单价列: E列(索引4) + price_col = 4 + + # 找到数据开始行 - 通常是第二行(索引1) + data_start_row = 1 + + # 创建可写的副本 + output_workbook = xlcopy(template_workbook) + output_sheet = output_workbook.get_sheet(0) + + # 设置单价的格式样式(保留4位小数) + price_style = xlwt.XFStyle() + price_style.num_format_str = '0.0000' + + # 数量格式 + quantity_style = xlwt.XFStyle() + quantity_style.num_format_str = '0' + + # 遍历数据并填充到Excel + for i, (_, row) in enumerate(df.iterrows()): + r = data_start_row + i + + # 只填充银豹采购单格式要求的4个列:条码、采购量、赠送量、采购单价 + + # 条码(必填)- B列(1) + output_sheet.write(r, barcode_col, row['条码']) + + # 采购量(必填)- C列(2) + output_sheet.write(r, quantity_col, float(row['采购量']), quantity_style) + + # 赠送量 - D列(3) + if pd.notna(row['赠送量']) and float(row['赠送量']) > 0: + output_sheet.write(r, gift_col, float(row['赠送量']), quantity_style) + + # 采购单价(必填)- E列(4) + output_sheet.write(r, price_col, float(row['采购单价']), price_style) + + # 生成输出文件名,保存到data/result目录 + timestamp = datetime.now().strftime("%Y%m%d%H%M%S") + result_dir = "data/result" + os.makedirs(result_dir, exist_ok=True) + output_file = os.path.join(result_dir, f"合并采购单_{timestamp}.xls") + + # 保存文件 + output_workbook.save(output_file) + logger.info(f"合并采购单已保存到: {output_file},共{len(df)}条记录") + return output_file + + except Exception as e: + logger.error(f"创建合并采购单时出错: {e}") + return None + + def process(self, file_paths: Optional[List[str]] = None, progress_cb: Optional[Callable[[int], None]] = None) -> Optional[str]: + """ + 处理采购单合并 + + Args: + file_paths: 指定要合并的文件路径列表,如果为None则自动获取 + + Returns: + 合并后的文件路径,如果合并失败则返回None + """ + # 如果未指定文件路径,则获取所有采购单文件 + if file_paths is None: + file_paths = self.get_purchase_orders() + try: + if progress_cb: + progress_cb(97) + except Exception: + pass + + # 检查是否有文件需要合并 + if not file_paths: + logger.warning("没有找到可合并的采购单文件") + return None + + # 合并采购单 + merged_df = self.merge_purchase_orders(file_paths) + if merged_df is None: + logger.error("合并采购单失败") + return None + try: + if progress_cb: + progress_cb(98) + except Exception: + pass + + # 创建合并的采购单文件 + output_file = self.create_merged_purchase_order(merged_df) + if output_file is None: + logger.error("创建合并采购单文件失败") + return None + try: + if progress_cb: + progress_cb(100) + except Exception: + pass + + # 记录已合并文件 + for file_path in file_paths: + self.merged_files[file_path] = output_file + self._save_merged_files() + + return output_file diff --git a/app/core/excel/processor.py b/app/core/excel/processor.py new file mode 100644 index 0000000..b2a9a58 --- /dev/null +++ b/app/core/excel/processor.py @@ -0,0 +1,860 @@ +""" +Excel处理核心模块 +-------------- +提供Excel文件处理功能,包括表格解析、数据提取和处理。 +""" + +import os +import re +import pandas as pd +import numpy as np +import xlrd +import xlwt +from xlutils.copy import copy as xlcopy +from typing import Dict, List, Optional, Tuple, Union, Any, Callable +from datetime import datetime + +from ...config.settings import ConfigManager +from ..utils.log_utils import get_logger +from ..utils.file_utils import ( + ensure_dir, + get_file_extension, + get_latest_file, + load_json, + save_json +) +from ..utils.string_utils import ( + clean_string, + extract_number, + format_barcode, + parse_monetary_string +) +from .converter import UnitConverter +from ..handlers.column_mapper import ColumnMapper + +logger = get_logger(__name__) + +class ExcelProcessor: + """ + Excel处理器:处理OCR识别后的Excel文件, + 提取条码、单价和数量,并按照采购单模板的格式填充 + """ + + def __init__(self, config): + """ + 初始化Excel处理器 + + Args: + config: 配置信息 + """ + self.config = config + + # 修复ConfigParser对象没有get_path方法的问题 + try: + # 获取输入和输出目录 + self.output_dir = config.get('Paths', 'output_folder', fallback='data/output') + self.temp_dir = config.get('Paths', 'temp_folder', fallback='data/temp') + + # 获取模板文件路径 + self.template_path = config.get('Paths', 'template_file', fallback='templates/银豹-采购单模板.xls') + if not os.path.exists(self.template_path): + logger.warning(f"模板文件不存在: {self.template_path}") + + # 设置缓存文件路径 + self.cache_file = os.path.join(self.output_dir, "processed_files.json") + self.processed_files = self._load_processed_files() + + # 确保目录存在 + os.makedirs(self.output_dir, exist_ok=True) + os.makedirs(self.temp_dir, exist_ok=True) + + # 记录实际路径 + logger.info(f"使用输出目录: {os.path.abspath(self.output_dir)}") + logger.info(f"使用临时目录: {os.path.abspath(self.temp_dir)}") + + # 加载单位转换器和配置 + self.unit_converter = UnitConverter() + logger.info(f"初始化ExcelProcessor完成,模板文件: {self.template_path}") + except Exception as e: + logger.error(f"初始化ExcelProcessor失败: {e}") + raise + + def _load_processed_files(self) -> Dict[str, str]: + """ + 加载已处理文件的缓存 + + Returns: + 处理记录字典 + """ + return load_json(self.cache_file, {}) + + def _save_processed_files(self) -> None: + """保存已处理文件的缓存""" + save_json(self.processed_files, self.cache_file) + + def get_latest_excel(self) -> Optional[str]: + """ + 获取output目录下最新的Excel文件(排除采购单文件) + + Returns: + 最新Excel文件的路径,如果未找到则返回None + """ + logger.info(f"搜索目录 {self.output_dir} 中的Excel文件") + + # 使用文件工具获取最新文件 + latest_file = get_latest_file( + self.output_dir, + pattern="", # 不限制文件名 + extensions=['.xlsx', '.xls'] # 限制为Excel文件 + ) + + # 如果没有找到文件 + if not latest_file: + logger.warning(f"未在 {self.output_dir} 目录下找到未处理的Excel文件") + return None + + # 检查是否是采购单(以"采购单_"开头的文件) + file_name = os.path.basename(latest_file) + if file_name.startswith('采购单_'): + logger.warning(f"找到的最新文件是采购单,不作处理: {latest_file}") + return None + + logger.info(f"找到最新的Excel文件: {latest_file}") + return latest_file + + def extract_barcode(self, df: pd.DataFrame) -> List[str]: + """ + 从数据帧中提取条码列名 + + Args: + df: 数据帧 + + Returns: + 可能的条码列名列表 + """ + possible_barcode_columns = ColumnMapper.STANDARD_COLUMNS['barcode'] + + found_columns = [] + + # 检查精确匹配 + for col in df.columns: + col_str = str(col).strip() + if col_str in possible_barcode_columns: + found_columns.append(col) + logger.info(f"找到精确匹配的条码列: {col_str}") + + # 如果找不到精确匹配,尝试部分匹配 + if not found_columns: + for col in df.columns: + col_str = str(col).strip().lower() + for keyword in ['条码', '条形码', 'barcode', '编码']: + if keyword.lower() in col_str: + found_columns.append(col) + logger.info(f"找到部分匹配的条码列: {col} (包含关键词: {keyword})") + break + + # 如果仍然找不到,尝试使用数据特征识别 + if not found_columns and len(df) > 0: + for col in df.columns: + # 检查此列数据是否符合条码特征 + sample_values = df[col].dropna().astype(str).tolist()[:10] # 取前10个非空值 + + if sample_values and all(len(val) >= 8 and len(val) <= 14 for val in sample_values): + # 大多数条码长度在8-14之间 + if all(val.isdigit() for val in sample_values): + found_columns.append(col) + logger.info(f"基于数据特征识别的可能条码列: {col}") + + return found_columns + + def extract_product_info(self, df: pd.DataFrame) -> List[Dict]: + """ + 从数据帧中提取商品信息 + + Args: + df: 数据帧 + + Returns: + 商品信息列表 + """ + products = [] + + # 检测列映射 + column_mapping = self._detect_column_mapping(df) + logger.info(f"检测到列映射: {column_mapping}") + + # 处理每一行 + for idx, row in df.iterrows(): + try: + # 初始化商品信息 + product = { + 'barcode': '', # 条码 + 'name': '', # 商品名称 + 'specification': '', # 规格 + 'quantity': 0, # 数量 + 'unit': '', # 单位 + 'price': 0, # 单价 + 'amount': 0, # 金额 + 'is_gift': False # 是否为赠品 + } + + # 提取条码 + if '条码' in df.columns and not pd.isna(row['条码']): + product['barcode'] = str(row['条码']).strip() + elif column_mapping.get('barcode') and not pd.isna(row[column_mapping['barcode']]): + product['barcode'] = str(row[column_mapping['barcode']]).strip() + + # 跳过空条码行 + if not product['barcode']: + continue + + # 检查备注列,过滤换货、退货、作废等非采购行 + skip_row = False + for col in df.columns: + col_str = str(col) + if any(k in col_str for k in ['备注', '说明', '类型', '备注1']): + val = str(row[col]).strip() + # 过滤常见的非采购关键字 + if any(k in val for k in ['换货', '退货', '作废', '减钱', '冲减', '赠品单', '补货']): + logger.info(f"过滤非采购行: {product['barcode']} - {product.get('name', '')}, 原因: {col_str}包含 '{val}'") + skip_row = True + break + if skip_row: + continue + + # 提取商品名称 + if '商品名称' in df.columns and not pd.isna(row['商品名称']): + product['name'] = str(row['商品名称']).strip() + elif '名称' in df.columns and not pd.isna(row['名称']): + product['name'] = str(row['名称']).strip() + elif column_mapping.get('name') and not pd.isna(row[column_mapping['name']]): + product['name'] = str(row[column_mapping['name']]).strip() + + # 提取单位 + if '单位' in df.columns and not pd.isna(row['单位']): + product['unit'] = str(row['单位']).strip() + elif column_mapping.get('unit') and not pd.isna(row[column_mapping['unit']]): + product['unit'] = str(row[column_mapping['unit']]).strip() + + # 提取单价 + if '单价' in df.columns and not pd.isna(row['单价']): + product['price'] = row['单价'] + elif column_mapping.get('price') and not pd.isna(row[column_mapping['price']]): + product['price'] = row[column_mapping['price']] + + # 提取金额 + if '金额' in df.columns and not pd.isna(row['金额']): + product['amount'] = row['金额'] + elif '小计' in df.columns and not pd.isna(row['小计']): + product['amount'] = row['小计'] + elif column_mapping.get('amount') and not pd.isna(row[column_mapping['amount']]): + product['amount'] = row[column_mapping['amount']] + # 根据金额判断赠品:金额为0、为空、或为o/O + amt = product.get('amount', None) + try: + is_amt_gift = False + if amt is None: + is_amt_gift = True + elif isinstance(amt, str): + parsed = parse_monetary_string(amt) + is_amt_gift = (parsed is None or parsed == 0.0) + else: + parsed = parse_monetary_string(amt) + is_amt_gift = (parsed is not None and parsed == 0.0) + if is_amt_gift: + product['is_gift'] = True + except Exception: + pass + + # 提取数量 + if '数量' in df.columns and not pd.isna(row['数量']): + product['quantity'] = row['数量'] + elif column_mapping.get('quantity') and not pd.isna(row[column_mapping['quantity']]): + product['quantity'] = row[column_mapping['quantity']] + + # 处理可能的复合数量字段,例如"2箱"、"3件" + if isinstance(product['quantity'], str) and product['quantity']: + num, unit = self.unit_converter.extract_unit_from_quantity(product['quantity']) + if unit: + product['unit'] = unit + if num is not None: + product['quantity'] = num + + # 提取规格并解析包装数量 + if '规格' in df.columns and not pd.isna(row['规格']): + product['specification'] = str(row['规格']) + # 修正OCR误识别的4.51*4为4.5L*4 + product['specification'] = re.sub(r'(\d+\.\d+)1\*(\d+)', r'\1L*\2', product['specification']) + package_quantity = self.parse_specification(product['specification']) + if package_quantity: + product['package_quantity'] = package_quantity + logger.info(f"解析规格: {product['specification']} -> 包装数量={package_quantity}") + elif column_mapping.get('specification') and not pd.isna(row[column_mapping['specification']]): + product['specification'] = str(row[column_mapping['specification']]) + # 修正OCR误识别的4.51*4为4.5L*4 + product['specification'] = re.sub(r'(\d+\.\d+)1\*(\d+)', r'\1L*\2', product['specification']) + package_quantity = self.parse_specification(product['specification']) + if package_quantity: + product['package_quantity'] = package_quantity + logger.info(f"从映射列解析规格: {product['specification']} -> 包装数量={package_quantity}") + else: + # 只有在无法从Excel获取规格时,才尝试从商品名称推断规格 + if product['name']: + # 特殊处理:优先检查名称中是否包含"容量*数量"格式 + container_pattern = r'.*?(\d+(?:\.\d+)?)\s*(?:ml|[mM][lL]|[lL]|升|毫升)[*×xX](\d+).*' + match = re.search(container_pattern, product['name']) + if match: + # 容量单位*数量格式,如"1.8L*8瓶",取数量部分作为包装数量 + volume = match.group(1) + count = match.group(2) + inferred_spec = f"{volume}L*{count}" + inferred_qty = int(count) + product['specification'] = inferred_spec + product['package_quantity'] = inferred_qty + logger.info(f"从商品名称提取容量*数量格式: {product['name']} -> {inferred_spec}, 包装数量={inferred_qty}") + # 原来的重量/容量*数字格式处理逻辑 + else: + weight_volume_pattern = r'.*?\d+(?:g|ml|毫升|克)[*xX×](\d+)' + match = re.search(weight_volume_pattern, product['name']) + if match: + inferred_spec = f"1*{match.group(1)}" + inferred_qty = int(match.group(1)) + product['specification'] = inferred_spec + product['package_quantity'] = inferred_qty + logger.info(f"从商品名称提取重量/容量规格: {product['name']} -> {inferred_spec}, 包装数量={inferred_qty}") + else: + # 一般情况的规格推断 + inferred_spec = self.unit_converter.infer_specification_from_name(product['name']) + if inferred_spec: + product['specification'] = inferred_spec + package_quantity = self.parse_specification(inferred_spec) + if package_quantity: + product['package_quantity'] = package_quantity + logger.info(f"从商品名称推断规格: {product['name']} -> {inferred_spec}, 包装数量={package_quantity}") + + # 检查已设置的规格但未设置包装数量的情况 + if product.get('specification') and not product.get('package_quantity'): + package_quantity = self.parse_specification(product['specification']) + if package_quantity: + product['package_quantity'] = package_quantity + logger.info(f"解析已设置的规格: {product['specification']} -> 包装数量={package_quantity}") + + # 新增逻辑:根据规格推断单位为"件" + if not product['unit'] and product.get('barcode') and product.get('specification') and product.get('quantity') and product.get('price') is not None: + # 检查规格是否符合容量*数量格式 + volume_pattern = r'(\d+(?:\.\d+)?)\s*(?:ml|[mL]L|l|L|升|毫升)[*×xX](\d+)' + match = re.search(volume_pattern, product['specification']) + + # 判断是否需要推断单位为"件" + if match: + product['unit'] = '件' + logger.info(f"根据规格推断单位: {product['specification']} -> 单位=件") + else: + # 检查简单的数量*数量格式 + simple_pattern = r'(\d+)[*×xX](\d+)' + match = re.search(simple_pattern, product['specification']) + if match: + product['unit'] = '件' + logger.info(f"根据规格推断单位: {product['specification']} -> 单位=件") + + # 应用单位转换规则 + product = self.unit_converter.process_unit_conversion(product) + + # 如果数量为0但单价和金额都存在,计算数量 = 金额/单价 + if (product['quantity'] == 0 or product['quantity'] is None) and product['price'] > 0 and product['amount']: + try: + amount = parse_monetary_string(product['amount']) + if amount is not None and amount > 0: + quantity = amount / product['price'] + logger.info(f"数量为空或为0,通过金额({amount})和单价({product['price']})计算得出数量: {quantity}") + product['quantity'] = quantity + except Exception as e: + logger.warning(f"通过金额和单价计算数量失败: {e}") + + products.append(product) + except Exception as e: + logger.error(f"提取第{idx+1}行商品信息时出错: {e}", exc_info=True) + continue + + logger.info(f"提取到 {len(products)} 个商品信息") + return products + + def fill_template(self, products: List[Dict], output_file_path: str) -> bool: + """ + 填充采购单模板 + + Args: + products: 商品信息列表 + output_file_path: 输出文件路径 + + Returns: + 是否成功填充 + """ + try: + # 打开模板文件 + template_workbook = xlrd.open_workbook(self.template_path, formatting_info=True) + template_sheet = template_workbook.sheet_by_index(0) + + # 创建可写的副本 + output_workbook = xlcopy(template_workbook) + output_sheet = output_workbook.get_sheet(0) + + # 先对产品按条码分组,区分正常商品和赠品 + barcode_groups = {} + + # 遍历所有产品,按条码分组 + logger.info(f"开始处理{len(products)} 个产品信息") + for product in products: + barcode = product.get('barcode', '') + # 确保条码是整数字符串 + barcode = format_barcode(barcode) + + if not barcode: + logger.warning(f"跳过无条码商品") + continue + + # 获取数量和单价 + quantity = product.get('quantity', 0) + price = product.get('price', 0) + amount = product.get('amount', 0) + + # 如果数量为0但单价和金额都存在,计算数量 = 金额/单价 + if (quantity == 0 or quantity is None) and price > 0 and amount: + try: + amount = parse_monetary_string(amount) + if amount is not None and amount > 0: + quantity = amount / price + logger.info(f"数量为空或为0,通过金额({amount})和单价({price})计算得出数量: {quantity}") + product['quantity'] = quantity + except Exception as e: + logger.warning(f"通过金额和单价计算数量失败: {e}") + + # 判断是否为赠品(价格为0) + is_gift = bool(product.get('is_gift', False)) or (price == 0) + + logger.info(f"处理商品: 条码={barcode}, 数量={quantity}, 单价={price}, 是否赠品={is_gift}") + + if barcode not in barcode_groups: + barcode_groups[barcode] = { + 'normal': None, # 正常商品信息 + 'gift_quantity': 0 # 赠品数量 + } + + if is_gift: + # 是赠品,累加赠品数量 + barcode_groups[barcode]['gift_quantity'] += quantity + logger.info(f"发现赠品:条码{barcode}, 数量={quantity}") + else: + # 是正常商品 + if barcode_groups[barcode]['normal'] is None: + barcode_groups[barcode]['normal'] = { + 'product': product, + 'quantity': quantity, + 'price': price + } + logger.info(f"发现正常商品:条码{barcode}, 数量={quantity}, 单价={price}") + else: + # 如果有多个正常商品记录,累加数量 + barcode_groups[barcode]['normal']['quantity'] += quantity + logger.info(f"累加正常商品数量:条码{barcode}, 新增={quantity}, 累计={barcode_groups[barcode]['normal']['quantity']}") + + # 如果单价不同,取平均值 + if price != barcode_groups[barcode]['normal']['price']: + avg_price = (barcode_groups[barcode]['normal']['price'] + price) / 2 + barcode_groups[barcode]['normal']['price'] = avg_price + logger.info(f"调整单价(取平均值):条码{barcode}, 原价={barcode_groups[barcode]['normal']['price']}, 新价={price}, 平均={avg_price}") + + # 输出调试信息 + logger.info(f"分组后共{len(barcode_groups)} 个不同条码的商品") + for barcode, group in barcode_groups.items(): + if group['normal'] is not None: + logger.info(f"条码 {barcode} 处理结果:正常商品数量{group['normal']['quantity']},单价{group['normal']['price']},赠品数量{group['gift_quantity']}") + else: + logger.info(f"条码 {barcode} 处理结果:只有赠品,数量={group['gift_quantity']}") + + # 准备填充数据 + row_index = 1 # 从第2行开始填充(索引从0开始) + + for barcode, group in barcode_groups.items(): + # 1. 列B(1): 条码(必填) + output_sheet.write(row_index, 1, barcode) + + if group['normal'] is not None: + # 有正常商品 + product = group['normal']['product'] + + # 2. 列C(2): 采购量(必填) 使用正常商品的采购量 + normal_quantity = group['normal']['quantity'] + output_sheet.write(row_index, 2, normal_quantity) + + # 3. 列D(3): 赠送量 - 添加赠品数量 + if group['gift_quantity'] > 0: + output_sheet.write(row_index, 3, group['gift_quantity']) + logger.info(f"条码 {barcode} 填充:采购量={normal_quantity},赠品数量{group['gift_quantity']}") + + # 4. 列E(4): 采购单价(必填) + purchase_price = group['normal']['price'] + style = xlwt.XFStyle() + style.num_format_str = '0.0000' + output_sheet.write(row_index, 4, round(purchase_price, 4), style) + else: + # 只有赠品,没有正常商品 + # 采购量填0,赠送量填赠品数量 + output_sheet.write(row_index, 2, 0) # 采购量为0 + output_sheet.write(row_index, 3, group['gift_quantity']) # 赠送量 + output_sheet.write(row_index, 4, 0) # 单价为0 + + logger.info(f"条码 {barcode} 填充:仅有赠品,采购量=0,赠品数量={group['gift_quantity']}") + + # 移到下一行 + row_index += 1 + + # 保存文件 + output_workbook.save(output_file_path) + logger.info(f"采购单已保存到: {output_file_path}") + return True + + except Exception as e: + logger.error(f"填充模板时出错: {e}") + return False + + def _find_header_row(self, df: pd.DataFrame) -> Optional[int]: + """自动识别表头行,委托给 ColumnMapper.detect_header_row""" + result = ColumnMapper.detect_header_row(df, max_rows=30) + if result >= 0: + logger.info(f"找到表头行: 第{result+1}行") + return result + # 回退:找第一个非空行 + for row in range(len(df)): + if df.iloc[row].notna().sum() > 3: + logger.info(f"未找到明确表头,使用第一个有效行: 第{row+1}行") + return row + logger.warning("无法识别表头行") + return None + + def process_specific_file(self, file_path: str, progress_cb: Optional[Callable[[int], None]] = None) -> Optional[str]: + """ + 处理指定的Excel文件 + + Args: + file_path: Excel文件路径 + + Returns: + 输出文件路径,如果处理失败则返回None + """ + logger.info(f"开始处理Excel文件: {file_path}") + + if not os.path.exists(file_path): + logger.error(f"文件不存在: {file_path}") + return None + + try: + # 读取Excel文件时不立即指定表头 + if progress_cb: + try: + progress_cb(92) + except Exception: + pass + df = pd.read_excel(file_path, header=None) + logger.info(f"成功读取Excel文件: {file_path}, 共 {len(df)} 行") + + # 自动识别表头行 + header_row = self._find_header_row(df) + if header_row is None: + logger.error("无法识别表头行") + return None + + logger.info(f"识别到表头在第 {header_row+1} 行") + + # 重新设置表头,避免二次读取 + if progress_cb: + try: + progress_cb(94) + except Exception: + pass + + # 使用识别到的表头行设置列名,并过滤掉表头之前的行 + df.columns = df.iloc[header_row] + df = df.iloc[header_row + 1:].reset_index(drop=True) + + logger.info(f"重新整理数据结构,共 {len(df)} 行有效数据") + + # 提取商品信息 + if progress_cb: + try: + progress_cb(96) + except Exception: + pass + products = self.extract_product_info(df) + + if not products: + logger.warning("未提取到有效商品信息") + return None + + # 生成输出文件名,保存到data/result目录 + file_name = os.path.splitext(os.path.basename(file_path))[0] + result_dir = "data/result" + os.makedirs(result_dir, exist_ok=True) + output_file = os.path.join(result_dir, f"采购单_{file_name}.xls") + + # 填充模板并保存 + if self.fill_template(products, output_file): + # 记录已处理文件 + self.processed_files[file_path] = output_file + self._save_processed_files() + + # 不再自动打开输出目录 + logger.info(f"采购单已保存到: {output_file}") + if progress_cb: + try: + progress_cb(100) + except Exception: + pass + + return output_file + + return None + + except Exception as e: + logger.error(f"处理Excel文件时出错: {file_path}, 错误: {e}") + return None + + def process_latest_file(self, progress_cb: Optional[Callable[[int], None]] = None) -> Optional[str]: + """ + 处理最新的Excel文件 + + Returns: + 输出文件路径,如果处理失败则返回None + """ + # 获取最新的Excel文件 + latest_file = self.get_latest_excel() + if not latest_file: + logger.warning("未找到可处理的Excel文件") + return None + + # 处理文件 + return self.process_specific_file(latest_file, progress_cb=progress_cb) + + def _detect_column_mapping(self, df: pd.DataFrame) -> Dict[str, str]: + """ + 自动检测列名映射 + + Args: + df: 数据框 + + Returns: + 列名映射字典,键为标准列名,值为实际列名 + """ + # 提取有用的列 + barcode_cols = self.extract_barcode(df) + + # 如果没有找到条码列,无法继续处理 + if not barcode_cols: + logger.error("未找到条码列,无法处理") + return {} + + # 使用 ColumnMapper 统一查找列名 + mapped_columns = {'barcode': barcode_cols[0]} + logger.info(f"使用条码列: {mapped_columns['barcode']}") + + # 内部键名 -> 标准列名映射 (processor.py 使用 price/amount 作为内部键名) + field_map = [ + ('name', 'name'), + ('specification', 'specification'), + ('quantity', 'quantity'), + ('unit', 'unit'), + ('price', 'unit_price'), + ('amount', 'total_price'), + ] + + for internal_key, standard_name in field_map: + matched = ColumnMapper.find_column(list(df.columns), standard_name) + if matched: + mapped_columns[internal_key] = matched + logger.info(f"找到{internal_key}列: {matched}") + + return mapped_columns + + def infer_specification_from_name(self, product_name: str) -> Tuple[Optional[str], Optional[int]]: + """ + 从商品名称推断规格 + 根据特定的命名规则匹配规格信息 + + Args: + product_name: 商品名称 + + Returns: + 规格字符串和包装数量的元组 + """ + if not product_name or not isinstance(product_name, str): + logger.warning(f"无效的商品名: {product_name}") + return None, None + + product_name = product_name.strip() + + # 特殊处理:重量/容量*数字格式 + weight_volume_pattern = r'.*?\d+(?:g|ml|毫升|克)[*xX×](\d+)' + match = re.search(weight_volume_pattern, product_name) + if match: + inferred_spec = f"1*{match.group(1)}" + inferred_qty = int(match.group(1)) + logger.info(f"从商品名称提取重量/容量规格: {product_name} -> {inferred_spec}, 包装数量={inferred_qty}") + return inferred_spec, inferred_qty + + # 使用单位转换器推断规格 + inferred_spec = self.unit_converter.infer_specification_from_name(product_name) + if inferred_spec: + # 解析规格中的包装数量 + package_quantity = self.parse_specification(inferred_spec) + if package_quantity: + logger.info(f"从商品名称推断规格: {product_name} -> {inferred_spec}, 包装数量={package_quantity}") + return inferred_spec, package_quantity + + # 特定商品规则匹配 + spec_rules = [ + # XX入白膜格式,如"550纯净水24入白膜" + (r'.*?(\d+)入白膜', lambda m: (f"1*{m.group(1)}", int(m.group(1)))), + + # 白膜格式,如"550水24白膜" + (r'.*?(\d+)白膜', lambda m: (f"1*{m.group(1)}", int(m.group(1)))), + + # 445水溶C系列 + (r'445水溶C.*?(\d+)[入个]纸箱', lambda m: (f"1*{m.group(1)}", int(m.group(1)))), + + # 东方树叶系列 + (r'东方树叶.*?(\d+\*\d+).*纸箱', lambda m: (m.group(1), int(m.group(1).split('*')[1]))), + + # 桶装 + (r'(\d+\.?\d*L)桶装', lambda m: (f"{m.group(1)}*1", 1)), + + # 树叶茶系 + (r'树叶.*?(\d+)[入个]纸箱', lambda m: (f"1*{m.group(1)}", int(m.group(1)))), + + # 茶π系列 + (r'茶[πΠπ].*?(\d+)纸箱', lambda m: (f"1*{m.group(1)}", int(m.group(1)))), + + # 通用入数匹配 + (r'.*?(\d+)[入个](?:纸箱|箱装|白膜)', lambda m: (f"1*{m.group(1)}", int(m.group(1)))), + + # 通用数字+纸箱格式 + (r'.*?(\d+)纸箱', lambda m: (f"1*{m.group(1)}", int(m.group(1)))) + ] + + # 尝试所有规则 + for pattern, formatter in spec_rules: + match = re.search(pattern, product_name) + if match: + spec, qty = formatter(match) + logger.info(f"根据特定规则推断规格: {product_name} -> {spec}, 包装数量={qty}") + return spec, qty + + # 尝试直接从名称中提取数字*数字格式 + match = re.search(r'(\d+\*\d+)', product_name) + if match: + spec = match.group(1) + package_quantity = self.parse_specification(spec) + if package_quantity: + logger.info(f"从名称中直接提取规格: {spec}, 包装数量={package_quantity}") + return spec, package_quantity + + # 最后尝试提取任何位置的数字,默认典型件装数 + numbers = re.findall(r'\d+', product_name) + if numbers: + for num in numbers: + # 检查是否为典型的件装数(12/15/24/30) + if num in ['12', '15', '24', '30']: + spec = f"1*{num}" + logger.info(f"从名称中提取可能的件装数: {spec}, 包装数量={int(num)}") + return spec, int(num) + + logger.warning(f"无法从商品名'{product_name}' 推断规格") + return None, None + + def parse_specification(self, spec_str: str) -> Optional[int]: + """ + 解析规格字符串,提取包装数量 + 支持格式:1*15, 1x15, 1*5*10, 5kg*6, IL*12等 + + Args: + spec_str: 规格字符串 + + Returns: + 包装数量,如果无法解析则返回None + """ + if not spec_str or not isinstance(spec_str, str): + return None + + try: + # 清理规格字符串 + spec_str = clean_string(spec_str) + + # 处理可能的OCR误识别,如"IL"应为"1L","6oo"应为"600" + spec_str = re.sub(r'(\b|^)[iIlL](\d+)', r'1\2', spec_str) # 将"IL"替换为"1L" + spec_str = re.sub(r'(\d+)[oO0]{2,}', lambda m: m.group(1) + '00', spec_str) # 将"6oo"替换为"600" + spec_str = spec_str.replace('×', '*').replace('x', '*').replace('X', '*') # 统一乘号 + + logger.debug(f"清理后的规格字符串: {spec_str}") + + # 新增:匹配“1件=12桶/袋/盒…”等等式规格,取右侧数量作为包装数量 + eq_match = re.search(r'(\d+(?:\.\d+)?)\s*(?:件|箱|提|盒)\s*[==]\s*(\d+)\s*(?:瓶|桶|盒|支|个|袋|罐|包|卷)', spec_str) + if eq_match: + return int(eq_match.group(2)) + + # 匹配带单位的格式,如"5kg*6"、"450g*15"、"450ml*15" + weight_pattern = r'(\d+(?:\.\d+)?)\s*(?:kg|KG|千克|公斤)[*×](\d+)' + match = re.search(weight_pattern, spec_str) + if match: + return int(match.group(2)) + + # 匹配克、毫升等单位格式 + match = re.search(r'\d+(?:\.\d+)?(?:g|G|ml|ML|mL|毫升|克)[*×](\d+)', spec_str) + if match: + return int(match.group(1)) + + # 匹配1*5*10 格式的三级规格 + match = re.search(r'(\d+(?:\.\d+)?)[*×](\d+(?:\.\d+)?)[*×](\d+(?:\.\d+)?)', spec_str) + if match: + # 取最后一个数字作为袋数量 + return int(float(match.group(3))) + + # 匹配1*15, 1x15 格式 + match = re.search(r'(\d+(?:\.\d+)?)[*×](\d+(?:\.\d+)?)', spec_str) + if match: + # 取第二个数字作为包装数量 + return int(float(match.group(2))) + + # 匹配24瓶/件等格式 + match = re.search(r'(\d+(?:\.\d+)?)[瓶个支袋][//](件|箱)', spec_str) + if match: + return int(float(match.group(1))) + + # 匹配4L格式 + match = re.search(r'(\d+(?:\.\d+)?)\s*[Ll升][*×]?(\d+(?:\.\d+)?)?', spec_str) + if match: + # 如果有第二个数字,返回它;否则返回1 + return int(float(match.group(2))) if match.group(2) else 1 + + # 匹配单独的数字+单位格式,如"12瓶装" + match = re.search(r'(\d+(?:\.\d+)?)[瓶个支袋包盒罐箱](?:装|\/箱)?', spec_str) + if match: + return int(float(match.group(1))) + + # 尝试直接匹配任何数字 + numbers = re.findall(r'\d+(?:\.\d+)?', spec_str) + if numbers and len(numbers) > 0: + # 如果只有一个数字,通常是包装数量 + if len(numbers) == 1: + return int(float(numbers[0])) + + # 如果有多个数字,尝试识别可能的包装数量(典型数值如6/12/24/30) + for num in numbers: + if float(num) in [6.0, 12.0, 24.0, 30.0]: + return int(float(num)) + + # 如果没有典型数值,选择最后一个数字(通常是包装数量) + return int(float(numbers[-1])) + + except Exception as e: + logger.warning(f"解析规格'{spec_str}'时出错: {e}") + + return None diff --git a/app/core/excel/validators.py b/app/core/excel/validators.py new file mode 100644 index 0000000..4bb1900 --- /dev/null +++ b/app/core/excel/validators.py @@ -0,0 +1,259 @@ +""" +数据验证器模块 +---------- +提供对商品数据的验证和修复功能 +""" + +import re +import logging +from typing import Dict, Any, Optional, List, Tuple, Union + +from ..utils.log_utils import get_logger +from ..utils.string_utils import parse_monetary_string + +logger = get_logger(__name__) + + +class ProductValidator: + """ + 商品数据验证器:验证和修复商品数据 + """ + + def __init__(self): + """ + 初始化商品数据验证器 + """ + # 仓库标识列表 + self.warehouse_identifiers = ["仓库", "仓库全名", "warehouse"] + + def validate_barcode(self, barcode: Any) -> Tuple[bool, str, Optional[str]]: + """ + 验证并修复条码 + + Args: + barcode: 原始条码值 + + Returns: + (是否有效, 修复后的条码, 错误信息)元组 + """ + error_message = None + + # 处理空值 + if barcode is None: + return False, "", "条码为空" + + # 转为字符串 + barcode_str = str(barcode).strip() + + # 处理"仓库"特殊情况 + if barcode_str in self.warehouse_identifiers: + return False, barcode_str, "条码为仓库标识" + + # 清理条码格式(移除非数字字符) + barcode_clean = re.sub(r'\D', '', barcode_str) + + # 如果清理后为空,无效 + if not barcode_clean: + return False, barcode_str, "条码不包含数字" + + # 对特定的错误条码进行修正(5开头改为6开头) + if len(barcode_clean) > 8 and barcode_clean.startswith('5') and not barcode_clean.startswith('53'): + original_barcode = barcode_clean + barcode_clean = '6' + barcode_clean[1:] + logger.info(f"修正条码前缀 5->6: {original_barcode} -> {barcode_clean}") + + # 新增:处理14位条码,如果多余长度都是0,截断为13位 + if len(barcode_clean) > 13: + original_length = len(barcode_clean) + # 检查多余部分是否都是0 + if barcode_clean.endswith('0'): + # 从末尾开始移除0,直到条码长度为13位或不再以0结尾 + while len(barcode_clean) > 13 and barcode_clean.endswith('0'): + barcode_clean = barcode_clean[:-1] + logger.info(f"修正条码长度: 从{original_length}位截断到{len(barcode_clean)}位") + else: + error_message = f"条码长度异常: {barcode_clean}, 长度={len(barcode_clean)}" + logger.warning(error_message) + return False, barcode_clean, error_message + + # 验证条码长度 + if len(barcode_clean) < 8 or len(barcode_clean) > 13: + error_message = f"条码长度异常: {barcode_clean}, 长度={len(barcode_clean)}" + logger.warning(error_message) + return False, barcode_clean, error_message + + # 验证条码是否全为数字 + if not barcode_clean.isdigit(): + error_message = f"条码包含非数字字符: {barcode_clean}" + logger.warning(error_message) + return False, barcode_clean, error_message + + # 对于序号9的特殊情况,允许其条码格式 + if barcode_clean == "5321545613": + logger.info(f"特殊条码验证通过: {barcode_clean}") + return True, barcode_clean, None + + logger.debug(f"条码验证通过: {barcode_clean}") + return True, barcode_clean, None + + def validate_quantity(self, quantity: Any) -> Tuple[bool, float, Optional[str]]: + """ + 验证并修复数量 + + Args: + quantity: 原始数量值 + + Returns: + (是否有效, 修复后的数量, 错误信息)元组 + """ + # 处理空值 + if quantity is None: + return False, 0.0, "数量为空" + + # 如果是字符串,尝试解析 + if isinstance(quantity, str): + # 去除空白和非数字字符(保留小数点) + quantity_clean = re.sub(r'[^\d\.]', '', quantity.strip()) + if not quantity_clean: + return False, 0.0, "数量不包含数字" + + try: + quantity_value = float(quantity_clean) + except ValueError: + return False, 0.0, f"无法将数量 '{quantity}' 转换为数字" + else: + # 尝试直接转换 + try: + quantity_value = float(quantity) + except (ValueError, TypeError): + return False, 0.0, f"无法将数量 '{quantity}' 转换为数字" + + # 数量必须大于0 + if quantity_value <= 0: + return False, 0.0, f"数量必须大于0,当前值: {quantity_value}" + + return True, quantity_value, None + + def validate_price(self, price: Any) -> Tuple[bool, float, bool, Optional[str]]: + """ + 验证并修复单价 + + Args: + price: 原始单价值 + + Returns: + (是否有效, 修复后的单价, 是否为赠品, 错误信息)元组 + """ + # 初始化不是赠品 + is_gift = False + + # 处理空值 + if price is None: + return False, 0.0, True, "单价为空,视为赠品" + + # 如果是字符串,检查赠品标识 + if isinstance(price, str): + price_str = price.strip().lower() + if price_str in ["赠品", "gift", "赠送", "0", ""]: + return True, 0.0, True, None + + price_value = parse_monetary_string(price_str) + if price_value is None: + return False, 0.0, True, f"无法将单价 '{price}' 转换为数字,视为赠品" + else: + # 尝试直接转换 + try: + price_value = float(price) + except (ValueError, TypeError): + return False, 0.0, True, f"无法将单价 '{price}' 转换为数字,视为赠品" + + # 单价为0视为赠品 + if price_value == 0: + return True, 0.0, True, None + + # 单价必须大于0 + if price_value < 0: + return False, 0.0, True, f"单价不能为负数: {price_value},视为赠品" + + return True, price_value, False, None + + def validate_product(self, product: Dict[str, Any]) -> Dict[str, Any]: + """ + 验证并修复商品数据 + + Args: + product: 商品数据字典 + + Returns: + 修复后的商品数据字典 + """ + # 创建新字典,避免修改原始数据 + validated_product = product.copy() + + # 验证条码 + barcode = product.get('barcode', '') + is_valid, fixed_barcode, error_msg = self.validate_barcode(barcode) + if is_valid: + validated_product['barcode'] = fixed_barcode + else: + logger.warning(f"条码验证失败: {error_msg}") + if fixed_barcode: + # 即使验证失败,但如果有修复后的条码仍然使用它 + validated_product['barcode'] = fixed_barcode + + # 验证单价 + price = product.get('price', 0) + is_valid, fixed_price, is_gift, error_msg = self.validate_price(price) + validated_product['price'] = fixed_price + + # 如果单价验证结果表示为赠品,更新赠品标识 + if is_gift: + validated_product['is_gift'] = True + if error_msg: + logger.info(error_msg) + + amount = product.get('amount', None) + try: + is_amount_gift = False + parsed_amount = parse_monetary_string(amount) + if parsed_amount is None or parsed_amount == 0.0: + is_amount_gift = True + if is_amount_gift: + validated_product['is_gift'] = True + except Exception: + pass + + # 验证数量 + quantity = product.get('quantity', None) + is_valid, fixed_quantity, error_msg = self.validate_quantity(quantity) + + # 检查数量是否为空,但单价和金额存在的情况 + if not is_valid and error_msg == "数量为空": + # 获取金额 + amount = product.get('amount', None) + + # 如果单价有效且金额存在,则可以计算数量 + if fixed_price > 0 and amount is not None: + try: + # 确保金额是数字 + amount = parse_monetary_string(amount) + if amount is None: + raise ValueError("无法解析金额") + + # 计算数量 = 金额 / 单价 + if amount > 0: + calculated_quantity = amount / fixed_price + logger.info(f"数量为空,通过金额({amount})和单价({fixed_price})计算得出数量: {calculated_quantity}") + validated_product['quantity'] = calculated_quantity + is_valid = True + except (ValueError, TypeError, ZeroDivisionError) as e: + logger.warning(f"通过金额和单价计算数量失败: {e}") + + # 如果数量验证有效或通过金额计算成功 + if is_valid: + validated_product['quantity'] = fixed_quantity if is_valid and fixed_quantity > 0 else validated_product.get('quantity', 0) + else: + logger.warning(f"数量验证失败: {error_msg}") + validated_product['quantity'] = 0.0 + + return validated_product \ No newline at end of file diff --git a/app/core/handlers/__init__.py b/app/core/handlers/__init__.py new file mode 100644 index 0000000..3dccd02 --- /dev/null +++ b/app/core/handlers/__init__.py @@ -0,0 +1,9 @@ +""" +数据处理handlers模块初始化文件 +""" + +from .data_cleaner import DataCleaner +from .column_mapper import ColumnMapper +from .calculator import DataCalculator + +__all__ = ['DataCleaner', 'ColumnMapper', 'DataCalculator'] \ No newline at end of file diff --git a/app/core/handlers/calculator.py b/app/core/handlers/calculator.py new file mode 100644 index 0000000..b274681 --- /dev/null +++ b/app/core/handlers/calculator.py @@ -0,0 +1,378 @@ +""" +数据计算处理器 + +提供各种数据计算功能,如数量计算、价格计算、汇总统计等 +""" + +import pandas as pd +import numpy as np +from typing import Dict, Any, Optional, List, Union +from ...core.utils.log_utils import get_logger + +logger = get_logger(__name__) + + +class DataCalculator: + """数据计算处理器 + + 提供标准化的数据计算功能,支持各种业务计算规则 + """ + + def __init__(self, config: Optional[Dict[str, Any]] = None): + """初始化数据计算器 + + Args: + config: 计算配置 + """ + self.config = config or {} + self.calculation_rules = [] + + def add_rule(self, rule_type: str, **kwargs): + """添加计算规则 + + Args: + rule_type: 规则类型 + **kwargs: 规则参数 + """ + rule = {'type': rule_type, **kwargs} + self.calculation_rules.append(rule) + logger.debug(f"添加计算规则: {rule_type}") + + def calculate(self, df: pd.DataFrame) -> pd.DataFrame: + """执行数据计算 + + Args: + df: 输入数据 + + Returns: + 计算后的数据 + """ + logger.info(f"开始数据计算,原始数据形状: {df.shape}") + + result_df = df.copy() + + for i, rule in enumerate(self.calculation_rules): + try: + logger.debug(f"执行计算规则 {i+1}/{len(self.calculation_rules)}: {rule['type']}") + result_df = self._apply_rule(result_df, rule) + logger.debug(f"规则执行完成,数据形状: {result_df.shape}") + except Exception as e: + logger.error(f"计算规则执行失败: {rule}, 错误: {e}") + # 继续执行下一个规则,而不是中断整个流程 + continue + + logger.info(f"数据计算完成,最终数据形状: {result_df.shape}") + return result_df + + def _apply_rule(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """应用单个计算规则 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + rule_type = rule.get('type') + + if rule_type == 'multiply': + return self._multiply(df, rule) + elif rule_type == 'divide': + return self._divide(df, rule) + elif rule_type == 'add': + return self._add(df, rule) + elif rule_type == 'subtract': + return self._subtract(df, rule) + elif rule_type == 'formula': + return self._formula(df, rule) + elif rule_type == 'round': + return self._round(df, rule) + elif rule_type == 'sum': + return self._sum(df, rule) + elif rule_type == 'aggregate': + return self._aggregate(df, rule) + else: + logger.warning(f"未知的计算规则类型: {rule_type}") + return df + + def _multiply(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """乘法计算 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + source_column = rule.get('source_column') + target_column = rule.get('target_column') + factor = rule.get('factor', 1) + + if source_column and target_column: + if source_column in df.columns: + df[target_column] = df[source_column] * factor + logger.debug(f"乘法计算: {source_column} * {factor} -> {target_column}") + else: + logger.warning(f"源列不存在: {source_column}") + + return df + + def _divide(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """除法计算 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + source_column = rule.get('source_column') + target_column = rule.get('target_column') + divisor = rule.get('divisor', 1) + + if source_column and target_column and divisor != 0: + if source_column in df.columns: + df[target_column] = df[source_column] / divisor + logger.debug(f"除法计算: {source_column} / {divisor} -> {target_column}") + else: + logger.warning(f"源列不存在: {source_column}") + elif divisor == 0: + logger.error("除数不能为0") + + return df + + def _add(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """加法计算 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + columns = rule.get('columns', []) + target_column = rule.get('target_column') + constant = rule.get('constant', 0) + + if target_column: + if isinstance(columns, str): + columns = [columns] + + if columns: + # 列相加 + valid_columns = [col for col in columns if col in df.columns] + if valid_columns: + df[target_column] = df[valid_columns].sum(axis=1) + constant + logger.debug(f"加法计算: {valid_columns} + {constant} -> {target_column}") + else: + logger.warning(f"没有有效的列用于加法计算: {columns}") + else: + # 只加常数 + if target_column in df.columns: + df[target_column] = df[target_column] + constant + logger.debug(f"加法计算: {target_column} + {constant}") + else: + logger.warning(f"目标列不存在: {target_column}") + + return df + + def _subtract(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """减法计算 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + minuend = rule.get('minuend') # 被减数列 + subtrahend = rule.get('subtrahend') # 减数列 + target_column = rule.get('target_column') + constant = rule.get('constant', 0) + + if target_column and minuend and minuend in df.columns: + if subtrahend and subtrahend in df.columns: + df[target_column] = df[minuend] - df[subtrahend] - constant + logger.debug(f"减法计算: {minuend} - {subtrahend} - {constant} -> {target_column}") + else: + df[target_column] = df[minuend] - constant + logger.debug(f"减法计算: {minuend} - {constant} -> {target_column}") + else: + logger.warning(f"减法计算参数不完整或列不存在") + + return df + + def _formula(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """公式计算 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + formula = rule.get('formula') + target_column = rule.get('target_column') + + if formula and target_column: + try: + df[target_column] = df.eval(formula) + logger.debug(f"公式计算: {formula} -> {target_column}") + except Exception as e: + logger.error(f"公式计算失败: {formula}, 错误: {e}") + else: + logger.warning("公式计算缺少公式或目标列") + + return df + + def _round(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """四舍五入 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + columns = rule.get('columns', []) + decimals = rule.get('decimals', 0) + + if isinstance(columns, str): + columns = [columns] + + target_columns = columns or df.select_dtypes(include=[np.number]).columns + + for col in target_columns: + if col in df.columns and pd.api.types.is_numeric_dtype(df[col]): + df[col] = df[col].round(decimals) + logger.debug(f"四舍五入: {col} 保留 {decimals} 位小数") + + return df + + def _sum(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """求和计算 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + columns = rule.get('columns', []) + target_column = rule.get('target_column') + group_by = rule.get('group_by') + + if isinstance(columns, str): + columns = [columns] + + if group_by and group_by in df.columns: + # 分组求和 + if columns: + for col in columns: + if col in df.columns: + sum_result = df.groupby(group_by)[col].sum() + logger.debug(f"分组求和: {col} 按 {group_by} 分组") + else: + # 所有数值列分组求和 + numeric_columns = df.select_dtypes(include=[np.number]).columns + sum_result = df.groupby(group_by)[numeric_columns].sum() + logger.debug(f"分组求和: 所有数值列 按 {group_by} 分组") + else: + # 总体求和 + if columns: + valid_columns = [col for col in columns if col in df.columns] + if valid_columns and target_column: + df[target_column] = df[valid_columns].sum(axis=1) + logger.debug(f"求和计算: {valid_columns} -> {target_column}") + else: + # 所有数值列求和 + numeric_columns = df.select_dtypes(include=[np.number]).columns + if target_column and len(numeric_columns) > 0: + df[target_column] = df[numeric_columns].sum(axis=1) + logger.debug(f"求和计算: {list(numeric_columns)} -> {target_column}") + + return df + + def _aggregate(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """聚合计算 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + group_by = rule.get('group_by') + aggregations = rule.get('aggregations', {}) + + if group_by and group_by in df.columns: + # 构建聚合函数字典 + agg_dict = {} + for column, func in aggregations.items(): + if column in df.columns: + if isinstance(func, str): + agg_dict[column] = func + elif isinstance(func, list): + agg_dict[column] = func + + if agg_dict: + result = df.groupby(group_by).agg(agg_dict) + logger.debug(f"聚合计算: 按 {group_by} 分组, 聚合: {agg_dict}") + return result.reset_index() + + return df + + # 便捷方法 + def multiply(self, source_column: str, target_column: str, factor: float): + """乘法计算""" + self.add_rule('multiply', source_column=source_column, + target_column=target_column, factor=factor) + return self + + def divide(self, source_column: str, target_column: str, divisor: float): + """除法计算""" + self.add_rule('divide', source_column=source_column, + target_column=target_column, divisor=divisor) + return self + + def add(self, columns: Union[str, List[str]], target_column: str, constant: float = 0): + """加法计算""" + self.add_rule('add', columns=columns, target_column=target_column, constant=constant) + return self + + def subtract(self, minuend: str, target_column: str, + subtrahend: Optional[str] = None, constant: float = 0): + """减法计算""" + self.add_rule('subtract', minuend=minuend, target_column=target_column, + subtrahend=subtrahend, constant=constant) + return self + + def formula(self, formula: str, target_column: str): + """公式计算""" + self.add_rule('formula', formula=formula, target_column=target_column) + return self + + def round_columns(self, columns: Optional[Union[str, List[str]]] = None, decimals: int = 0): + """四舍五入""" + self.add_rule('round', columns=columns, decimals=decimals) + return self + + def sum_columns(self, columns: Optional[Union[str, List[str]]] = None, + target_column: Optional[str] = None, group_by: Optional[str] = None): + """求和计算""" + self.add_rule('sum', columns=columns, target_column=target_column, group_by=group_by) + return self + + def aggregate(self, group_by: str, aggregations: Dict[str, Union[str, List[str]]]): + """聚合计算""" + self.add_rule('aggregate', group_by=group_by, aggregations=aggregations) + return self \ No newline at end of file diff --git a/app/core/handlers/column_mapper.py b/app/core/handlers/column_mapper.py new file mode 100644 index 0000000..dc58806 --- /dev/null +++ b/app/core/handlers/column_mapper.py @@ -0,0 +1,382 @@ +""" +列映射处理器 + +提供列名映射和转换功能,支持不同供应商的列名标准化 +""" + +import re +import pandas as pd +from typing import Dict, Any, Optional, List, Union +from ...core.utils.log_utils import get_logger + +logger = get_logger(__name__) + + +class ColumnMapper: + """列映射处理器 + + 提供列名标准化功能,将不同供应商的列名映射到标准列名 + """ + + # 标准列名定义(所有列名别名的唯一来源) + STANDARD_COLUMNS = { + 'barcode': [ + '条码', '条形码', '商品条码', '商品条形码', '产品条码', '商品编码', + '商品编号', '条码(必填)', '电脑条码', '条码ID', + 'barcode', 'Barcode', 'BarCode', 'code', '编码', + ], + 'name': [ + '商品名称', '产品名称', '名称', '商品', '产品', '商品名', '品名', + '品项名', '商品或服务名称', '品项', '名 称', + 'name', 'product_name', + ], + 'specification': [ + '规格', '规格型号', '型号', '商品规格', '产品规格', '包装规格', '规 格', + 'specification', 'spec', 'model', + ], + 'quantity': [ + '数量', '采购量', '订货数量', '订单量', '需求量', '采购数量', '购买数量', + '订单数量', '数量(必填)', '采购量(必填)', '入库数', '入库数量', '数 量', + 'quantity', 'qty', + ], + 'unit': [ + '单位', '计量单位', '采购单位', '单位(必填)', '单位名称', '计价单位', '单 位', + 'unit', 'units', + ], + 'unit_price': [ + '单价', '价格', '采购单价', '进货价', '销售价', '采购价', '参考价', + '入库单价', '单价(必填)', '采购单价(必填)', '价格(必填)', '单 价', + 'unit_price', 'price', + ], + 'total_price': [ + '总价', '金额', '小计', '合计金额', '小计金额', '金额(元)', + '金额合计', '合计', '总额', + 'total_price', 'total', 'amount', + ], + 'gift_quantity': [ + '赠送量', '赠品数量', '赠送数量', '赠品', + ], + 'category': ['类别', '分类', '商品类别', 'category', 'type'], + 'brand': ['品牌', '商标', 'brand'], + 'supplier': ['供应商', '供货商', 'supplier', 'vendor'], + } + + def __init__(self, mapping_config: Optional[Dict[str, Any]] = None): + """初始化列映射器 + + Args: + mapping_config: 映射配置 + """ + self.mapping_config = mapping_config or {} + self.custom_mappings = {} + self._build_reverse_mapping() + + def _build_reverse_mapping(self): + """构建反向映射表""" + self.reverse_mapping = {} + + # 添加标准列的反向映射 + for standard_name, variations in self.STANDARD_COLUMNS.items(): + for variation in variations: + self.reverse_mapping[variation.lower()] = standard_name + + # 添加自定义映射 + for standard_name, custom_names in self.mapping_config.items(): + if isinstance(custom_names, str): + custom_names = [custom_names] + + for custom_name in custom_names: + self.reverse_mapping[custom_name.lower()] = standard_name + self.custom_mappings[custom_name.lower()] = standard_name + + def map_columns(self, df: pd.DataFrame, target_columns: Optional[List[str]] = None) -> pd.DataFrame: + """映射列名 + + Args: + df: 输入数据 + target_columns: 目标列名列表,如果为None则使用所有标准列 + + Returns: + 列名映射后的数据 + """ + if target_columns is None: + target_columns = list(self.STANDARD_COLUMNS.keys()) + + logger.info(f"开始列名映射,目标列: {target_columns}") + logger.info(f"原始列名: {list(df.columns)}") + + # 创建列名映射 + column_mapping = {} + used_columns = set() + + for target_col in target_columns: + # 查找匹配的原始列名 + matched_column = self._find_matching_column(df.columns, target_col) + if matched_column: + column_mapping[matched_column] = target_col + used_columns.add(matched_column) + logger.debug(f"列名映射: {matched_column} -> {target_col}") + + # 重命名列 + if column_mapping: + df_mapped = df.rename(columns=column_mapping) + + # 添加缺失的目标列 + for target_col in target_columns: + if target_col not in df_mapped.columns: + df_mapped[target_col] = self._get_default_value(target_col) + logger.debug(f"添加缺失列: {target_col}") + + # 只保留目标列 + existing_target_columns = [col for col in target_columns if col in df_mapped.columns] + df_result = df_mapped[existing_target_columns] + + logger.info(f"列名映射完成,结果列名: {list(df_result.columns)}") + return df_result + else: + logger.warning("没有找到可映射的列名") + return df + + def _find_matching_column(self, columns: List[str], target_column: str) -> Optional[str]: + """查找匹配的列名 + + Args: + columns: 原始列名列表 + target_column: 目标标准列名 + + Returns: + 匹配的原始列名或None + """ + # 获取目标列的所有可能变体 + possible_names = [] + + # 标准列名变体 + if target_column in self.STANDARD_COLUMNS: + possible_names.extend(self.STANDARD_COLUMNS[target_column]) + + # 自定义映射 + for standard_name, custom_names in self.mapping_config.items(): + if standard_name == target_column: + if isinstance(custom_names, str): + possible_names.append(custom_names) + else: + possible_names.extend(custom_names) + + # 查找匹配 + for possible_name in possible_names: + # 精确匹配(忽略大小写) + for column in columns: + if column.lower() == possible_name.lower(): + return column + + # 模糊匹配 + for column in columns: + if possible_name.lower() in column.lower() or column.lower() in possible_name.lower(): + return column + + return None + + def _get_default_value(self, column_name: str) -> Any: + """获取列的默认值 + + Args: + column_name: 列名 + + Returns: + 默认值 + """ + # 根据列名类型返回合适的默认值 + if column_name in ['quantity', 'unit_price', 'total_price']: + return 0 + elif column_name in ['barcode', 'name', 'specification', 'unit', 'category', 'brand', 'supplier']: + return '' + else: + return None + + def add_custom_mapping(self, standard_name: str, custom_names: Union[str, List[str]]): + """添加自定义列名映射 + + Args: + standard_name: 标准列名 + custom_names: 自定义列名或列名列表 + """ + if isinstance(custom_names, str): + custom_names = [custom_names] + + # 更新配置 + self.mapping_config[standard_name] = custom_names + + # 更新反向映射 + for custom_name in custom_names: + self.reverse_mapping[custom_name.lower()] = standard_name + self.custom_mappings[custom_name.lower()] = standard_name + + logger.info(f"添加自定义映射: {standard_name} <- {custom_names}") + + def detect_column_types(self, df: pd.DataFrame) -> Dict[str, str]: + """检测列的数据类型 + + Args: + df: 数据 + + Returns: + 列类型字典 + """ + column_types = {} + + for column in df.columns: + if pd.api.types.is_numeric_dtype(df[column]): + column_types[column] = 'numeric' + elif pd.api.types.is_datetime64_any_dtype(df[column]): + column_types[column] = 'datetime' + elif pd.api.types.is_bool_dtype(df[column]): + column_types[column] = 'boolean' + else: + column_types[column] = 'text' + + return column_types + + def suggest_column_mapping(self, df: pd.DataFrame) -> Dict[str, List[str]]: + """建议列名映射 + + Args: + df: 数据 + + Returns: + 建议的映射关系 + """ + suggestions = {} + + for column in df.columns: + column_lower = column.lower() + suggestions[column] = [] + + # 检查标准列名 + for standard_name, variations in self.STANDARD_COLUMNS.items(): + for variation in variations: + if column_lower in variation.lower() or variation.lower() in column_lower: + suggestions[column].append(standard_name) + + # 检查自定义映射 + for custom_name, standard_name in self.custom_mappings.items(): + if column_lower in custom_name or custom_name in column_lower: + suggestions[column].append(standard_name) + + # 去重 + suggestions[column] = list(set(suggestions[column])) + + # 只返回有建议的列 + return {k: v for k, v in suggestions.items() if v} + + def validate_mapping(self, df: pd.DataFrame, required_columns: List[str]) -> Dict[str, Any]: + """验证列映射结果 + + Args: + df: 映射后的数据 + required_columns: 必需的列名列表 + + Returns: + 验证结果 + """ + result = { + 'valid': True, + 'missing_columns': [], + 'empty_columns': [], + 'warnings': [] + } + + # 检查缺失列 + for col in required_columns: + if col not in df.columns: + result['missing_columns'].append(col) + result['valid'] = False + + # 检查空列 + for col in df.columns: + if df[col].isnull().all(): + result['empty_columns'].append(col) + result['warnings'].append(f"列 '{col}' 全部为空值") + + # 检查数值列 + numeric_columns = ['quantity', 'unit_price', 'total_price'] + for col in numeric_columns: + if col in df.columns and not pd.api.types.is_numeric_dtype(df[col]): + result['warnings'].append(f"列 '{col}' 不是数值类型") + + return result + + @classmethod + def find_column(cls, columns: List[str], standard_name: str) -> Optional[str]: + """在列名列表中查找匹配标准列名的列 + + 匹配策略: 精确匹配 → 忽略空白匹配 → 子串匹配 + + Args: + columns: 实际列名列表 + standard_name: 标准列名 (STANDARD_COLUMNS 的键) + + Returns: + 匹配到的实际列名,未找到返回 None + """ + candidates = cls.STANDARD_COLUMNS.get(standard_name, []) + if not candidates: + return None + + columns_str = [str(c) for c in columns] + + # 精确匹配 + for col in columns_str: + col_clean = col.strip() + for candidate in candidates: + if col_clean == candidate: + return col + + # 忽略空白匹配 + for col in columns_str: + col_clean = re.sub(r'\s+', '', col.strip()) + for candidate in candidates: + if col_clean == re.sub(r'\s+', '', candidate): + return col + + # 子串匹配 (候选名包含在列名中) + for col in columns_str: + col_lower = col.strip().lower() + for candidate in candidates: + if candidate.lower() in col_lower: + return col + + return None + + @staticmethod + def detect_header_row(df: pd.DataFrame, max_rows: int = 10, min_matches: int = 3) -> int: + """检测表头所在行 + + 扫描前 max_rows 行,返回包含最多关键词匹配的行索引。 + + Args: + df: 数据框 + max_rows: 最大扫描行数 + min_matches: 最少关键词匹配数 + + Returns: + 表头行索引,未找到返回 -1 + """ + header_keywords = [ + '条码', '条形码', '商品条码', '商品名称', '名称', '规格', + '单价', '数量', '金额', '单位', '必填', '编码', + ] + + best_row = -1 + best_matches = 0 + + for row_idx in range(min(max_rows, len(df))): + row_values = df.iloc[row_idx].astype(str) + matches = sum( + 1 for kw in header_keywords + if any(kw in str(val) for val in row_values.values) + ) + if matches >= min_matches and matches > best_matches: + best_matches = matches + best_row = row_idx + + return best_row \ No newline at end of file diff --git a/app/core/handlers/data_cleaner.py b/app/core/handlers/data_cleaner.py new file mode 100644 index 0000000..156255a --- /dev/null +++ b/app/core/handlers/data_cleaner.py @@ -0,0 +1,401 @@ +""" +数据清洗处理器 + +提供各种数据清洗功能,如空值处理、重复项处理、数据类型转换等 +""" + +import pandas as pd +from typing import Dict, Any, Optional, List, Union +from ...core.utils.log_utils import get_logger + +logger = get_logger(__name__) + + +class DataCleaner: + """数据清洗处理器 + + 提供标准化的数据清洗功能,支持链式调用和规则配置 + """ + + def __init__(self, config: Optional[Dict[str, Any]] = None): + """初始化数据清洗器 + + Args: + config: 清洗配置 + """ + self.config = config or {} + self.cleaning_rules = [] + + def add_rule(self, rule_type: str, **kwargs): + """添加清洗规则 + + Args: + rule_type: 规则类型 + **kwargs: 规则参数 + """ + rule = {'type': rule_type, **kwargs} + self.cleaning_rules.append(rule) + logger.debug(f"添加清洗规则: {rule_type}") + + def clean(self, df: pd.DataFrame) -> pd.DataFrame: + """执行数据清洗 + + Args: + df: 输入数据 + + Returns: + 清洗后的数据 + """ + logger.info(f"开始数据清洗,原始数据形状: {df.shape}") + + result_df = df.copy() + + for i, rule in enumerate(self.cleaning_rules): + try: + logger.debug(f"执行清洗规则 {i+1}/{len(self.cleaning_rules)}: {rule['type']}") + result_df = self._apply_rule(result_df, rule) + logger.debug(f"规则执行完成,数据形状: {result_df.shape}") + except Exception as e: + logger.error(f"清洗规则执行失败: {rule}, 错误: {e}") + # 继续执行下一个规则,而不是中断整个流程 + continue + + logger.info(f"数据清洗完成,最终数据形状: {result_df.shape}") + return result_df + + def _apply_rule(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """应用单个清洗规则 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + rule_type = rule.get('type') + + if rule_type == 'remove_duplicates': + return self._remove_duplicates(df, rule) + elif rule_type == 'fill_na': + return self._fill_na(df, rule) + elif rule_type == 'remove_rows': + return self._remove_rows(df, rule) + elif rule_type == 'convert_type': + return self._convert_type(df, rule) + elif rule_type == 'strip_whitespace': + return self._strip_whitespace(df, rule) + elif rule_type == 'normalize_text': + return self._normalize_text(df, rule) + elif rule_type == 'validate_data': + return self._validate_data(df, rule) + else: + logger.warning(f"未知的清洗规则类型: {rule_type}") + return df + + def _remove_duplicates(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """移除重复项 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + subset = rule.get('subset') # 用于判断重复的列 + keep = rule.get('keep', 'first') # 保留哪个重复项 + + before_count = len(df) + df_cleaned = df.drop_duplicates(subset=subset, keep=keep) + after_count = len(df_cleaned) + + logger.info(f"移除重复项: {before_count - after_count} 行被移除") + return df_cleaned + + def _fill_na(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """填充空值 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + columns = rule.get('columns') # 要处理的列 + value = rule.get('value', 0) # 填充值 + method = rule.get('method') # 填充方法('ffill', 'bfill', 'mean', 'median') + + if columns: + # 处理指定列 + if isinstance(columns, str): + columns = [columns] + + for col in columns: + if col in df.columns: + if method == 'ffill': + df[col] = df[col].fillna(method='ffill') + elif method == 'bfill': + df[col] = df[col].fillna(method='bfill') + elif method == 'mean': + df[col] = df[col].fillna(df[col].mean()) + elif method == 'median': + df[col] = df[col].fillna(df[col].median()) + else: + df[col] = df[col].fillna(value) + + logger.debug(f"填充列 {col} 的空值: {method or value}") + else: + # 处理所有列 + if method == 'ffill': + df = df.fillna(method='ffill') + elif method == 'bfill': + df = df.fillna(method='bfill') + else: + df = df.fillna(value) + + logger.debug(f"填充所有列的空值: {method or value}") + + return df + + def _remove_rows(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """移除行 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + condition = rule.get('condition') # 条件表达式 + columns = rule.get('columns') # 要检查的列 + values = rule.get('values') # 要移除的值 + + if condition: + # 使用条件表达式 + try: + before_count = len(df) + df_filtered = df.query(condition) + after_count = len(df_filtered) + logger.info(f"条件过滤: {condition}, 移除了 {before_count - after_count} 行") + return df_filtered + except Exception as e: + logger.error(f"条件表达式执行失败: {condition}, 错误: {e}") + return df + + if columns and values: + # 基于列值过滤 + if isinstance(columns, str): + columns = [columns] + if not isinstance(values, list): + values = [values] + + df_filtered = df.copy() + for col in columns: + if col in df_filtered.columns: + mask = ~df_filtered[col].isin(values) + df_filtered = df_filtered[mask] + logger.debug(f"列 {col} 过滤值 {values}") + + return df_filtered + + logger.warning("移除行规则缺少条件或列配置") + return df + + def _convert_type(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """类型转换 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + columns = rule.get('columns') + target_type = rule.get('target_type', 'float') + errors = rule.get('errors', 'coerce') # 错误处理方式 + + if isinstance(columns, str): + columns = [columns] + + for col in columns: + if col in df.columns: + try: + if target_type == 'int': + df[col] = pd.to_numeric(df[col], errors=errors).astype('Int64') + elif target_type == 'float': + df[col] = pd.to_numeric(df[col], errors=errors) + elif target_type == 'datetime': + df[col] = pd.to_datetime(df[col], errors=errors) + elif target_type == 'string': + df[col] = df[col].astype(str) + else: + df[col] = df[col].astype(target_type) + + logger.debug(f"列 {col} 类型转换: {target_type}") + except Exception as e: + logger.error(f"列 {col} 类型转换失败: {e}") + + return df + + def _strip_whitespace(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """去除空白字符 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + columns = rule.get('columns') + + if columns: + if isinstance(columns, str): + columns = [columns] + + for col in columns: + if col in df.columns and df[col].dtype == 'object': + df[col] = df[col].str.strip() + logger.debug(f"列 {col} 去除空白字符") + else: + # 处理所有文本列 + text_columns = df.select_dtypes(include=['object']).columns + for col in text_columns: + df[col] = df[col].str.strip() + + logger.debug(f"所有文本列去除空白字符: {list(text_columns)}") + + return df + + def _normalize_text(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """文本标准化 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + columns = rule.get('columns') + lowercase = rule.get('lowercase', False) + uppercase = rule.get('uppercase', False) + replace_map = rule.get('replace_map', {}) # 替换映射 + + if isinstance(columns, str): + columns = [columns] + + target_columns = columns or df.select_dtypes(include=['object']).columns + + for col in target_columns: + if col in df.columns and df[col].dtype == 'object': + if lowercase: + df[col] = df[col].str.lower() + elif uppercase: + df[col] = df[col].str.upper() + + # 应用替换映射 + for old, new in replace_map.items(): + df[col] = df[col].str.replace(old, new) + + logger.debug(f"列 {col} 文本标准化完成") + + return df + + def _validate_data(self, df: pd.DataFrame, rule: Dict[str, Any]) -> pd.DataFrame: + """数据验证 + + Args: + df: 数据 + rule: 规则配置 + + Returns: + 处理后的数据 + """ + columns = rule.get('columns') + min_value = rule.get('min_value') + max_value = rule.get('max_value') + required = rule.get('required', False) + + if isinstance(columns, str): + columns = [columns] + + validation_results = [] + + for col in columns: + if col in df.columns: + # 检查必需值 + if required: + null_count = df[col].isnull().sum() + if null_count > 0: + validation_results.append(f"{col}: {null_count} 个空值") + + # 检查数值范围 + if min_value is not None or max_value is not None: + if pd.api.types.is_numeric_dtype(df[col]): + invalid_mask = pd.Series(False, index=df.index) + if min_value is not None: + invalid_mask |= df[col] < min_value + if max_value is not None: + invalid_mask |= df[col] > max_value + + invalid_count = invalid_mask.sum() + if invalid_count > 0: + validation_results.append(f"{col}: {invalid_count} 个值超出范围") + + if validation_results: + logger.warning(f"数据验证发现问题: {', '.join(validation_results)}") + else: + logger.debug("数据验证通过") + + return df + + # 便捷方法 + def remove_duplicates(self, subset: Optional[List[str]] = None, keep: str = 'first'): + """移除重复项""" + self.add_rule('remove_duplicates', subset=subset, keep=keep) + return self + + def fill_na(self, columns: Optional[Union[str, List[str]]] = None, + value: Any = 0, method: Optional[str] = None): + """填充空值""" + self.add_rule('fill_na', columns=columns, value=value, method=method) + return self + + def remove_rows(self, condition: Optional[str] = None, + columns: Optional[Union[str, List[str]]] = None, + values: Optional[Any] = None): + """移除行""" + self.add_rule('remove_rows', condition=condition, columns=columns, values=values) + return self + + def convert_type(self, columns: Union[str, List[str]], target_type: str, errors: str = 'coerce'): + """类型转换""" + self.add_rule('convert_type', columns=columns, target_type=target_type, errors=errors) + return self + + def strip_whitespace(self, columns: Optional[Union[str, List[str]]] = None): + """去除空白字符""" + self.add_rule('strip_whitespace', columns=columns) + return self + + def normalize_text(self, columns: Optional[Union[str, List[str]]] = None, + lowercase: bool = False, uppercase: bool = False, + replace_map: Optional[Dict[str, str]] = None): + """文本标准化""" + self.add_rule('normalize_text', columns=columns, lowercase=lowercase, + uppercase=uppercase, replace_map=replace_map or {}) + return self + + def validate_data(self, columns: Union[str, List[str]], + min_value: Optional[float] = None, + max_value: Optional[float] = None, + required: bool = False): + """数据验证""" + self.add_rule('validate_data', columns=columns, min_value=min_value, + max_value=max_value, required=required) + return self \ No newline at end of file diff --git a/app/core/handlers/rule_engine.py b/app/core/handlers/rule_engine.py new file mode 100644 index 0000000..bf143d5 --- /dev/null +++ b/app/core/handlers/rule_engine.py @@ -0,0 +1,150 @@ +import re +import pandas as pd +from typing import List, Dict, Any, Optional + +def _split_quantity_unit(df: pd.DataFrame, source: str, dictionary: Optional[Dict[str, Any]] = None) -> pd.DataFrame: + if source in df.columns: + vals = df[source].astype(str).fillna("") + nums = [] + units = [] + default_unit = (dictionary or {}).get("default_unit", "") + unit_synonyms = (dictionary or {}).get("unit_synonyms", {}) + for v in vals: + m = re.search(r"(\d+(?:\.\d+)?)(箱|件|提|盒|瓶)", v) + if m: + nums.append(float(m.group(1))) + u = unit_synonyms.get(m.group(2), m.group(2)) + units.append(u) + else: + try: + nums.append(float(v)) + units.append(unit_synonyms.get(default_unit, default_unit)) + except Exception: + nums.append(0.0) + units.append(unit_synonyms.get(default_unit, default_unit)) + df["quantity"] = nums + df["unit"] = units + return df + +def _extract_spec_from_name(df: pd.DataFrame, source: str, dictionary: Optional[Dict[str, Any]] = None) -> pd.DataFrame: + if source in df.columns: + names = df[source].astype(str).fillna("") + specs = [] + packs = [] + ignore_words = (dictionary or {}).get("ignore_words", []) + name_patterns = (dictionary or {}).get("name_patterns", []) + for s in names: + if ignore_words: + for w in ignore_words: + s = s.replace(w, "") + matched = False + for pat in name_patterns: + try: + m = re.search(pat, s) + if m and len(m.groups()) >= 2: + try: + qty = int(m.group(len(m.groups()))) + except Exception: + qty = None + specs.append(s) + packs.append(qty) + matched = True + break + except Exception: + pass + if matched: + continue + m = re.search(r"(\d+(?:\.\d+)?)(ml|l|升|毫升)[*×xX](\d+)", s, re.IGNORECASE) + if m: + specs.append(f"{m.group(1)}{m.group(2)}*{m.group(3)}") + packs.append(int(m.group(3))) + continue + m2 = re.search(r"(\d+)[*×xX](\d+)", s) + if m2: + specs.append(f"1*{m2.group(2)}") + packs.append(int(m2.group(2))) + continue + m3 = re.search(r"(\d{2,3})\D*(\d{1,3})\D*", s) + if m3: + specs.append(f"1*{m3.group(2)}") + packs.append(int(m3.group(2))) + continue + specs.append("") + packs.append(None) + df["specification"] = df.get("specification", pd.Series(specs)) + df["package_quantity"] = packs + return df + +def _normalize_unit(df: pd.DataFrame, target: str, unit_map: Dict[str, str], dictionary: Optional[Dict[str, Any]] = None) -> pd.DataFrame: + if target in df.columns: + df[target] = df[target].astype(str) + df[target] = df[target].apply(lambda u: unit_map.get(u, u)) + pack_multipliers = (dictionary or {}).get("pack_multipliers", {}) + default_pq = (dictionary or {}).get("default_package_quantity", 1) + try: + if "quantity" in df.columns: + def convert_qty(row): + u = row.get(target) + q = row.get("quantity") + pq = row.get("package_quantity") + if u in ("件", "箱", "提", "盒"): + mult = pq or pack_multipliers.get(u, default_pq) + if pd.notna(q) and pd.notna(mult) and float(mult) > 0: + return float(q) * float(mult) + return q + df["quantity"] = df.apply(convert_qty, axis=1) + df[target] = df[target].apply(lambda u: "瓶" if u in ("件","箱","提","盒") else u) + except Exception: + pass + return df + +def _compute_quantity_from_total(df: pd.DataFrame) -> pd.DataFrame: + if "quantity" in df.columns and "unit_price" in df.columns: + qty = df["quantity"].fillna(0) + up = pd.to_numeric(df.get("unit_price", 0), errors="coerce").fillna(0) + tp = pd.to_numeric(df.get("total_price", 0), errors="coerce").fillna(0) + need = (qty <= 0) & (up > 0) & (tp > 0) + df.loc[need, "quantity"] = (tp[need] / up[need]).round(6) + return df + +def _fill_missing(df: pd.DataFrame, fills: Dict[str, Any]) -> pd.DataFrame: + for k, v in fills.items(): + if k in df.columns: + df[k] = df[k].fillna(v) + else: + df[k] = v + return df + +def _mark_gift(df: pd.DataFrame) -> pd.DataFrame: + df["is_gift"] = False + tp = df.get("total_price") + up = df.get("unit_price") + flags = pd.Series([False]*len(df)) + if tp is not None: + tpn = pd.to_numeric(tp, errors="coerce").fillna(0) + flags = flags | (tpn == 0) + if up is not None: + upn = pd.to_numeric(up, errors="coerce").fillna(0) + flags = flags | (upn == 0) + if "name" in df.columns: + flags = flags | df["name"].astype(str).str.contains(r"赠品|^o$|^O$", regex=True) + df.loc[flags, "is_gift"] = True + return df + +def apply_rules(df: pd.DataFrame, rules: List[Dict[str, Any]], dictionary: Optional[Dict[str, Any]] = None) -> pd.DataFrame: + out = df.copy() + for r in rules or []: + t = r.get("type") + if t == "split_quantity_unit": + out = _split_quantity_unit(out, r.get("source", "quantity"), dictionary) + elif t == "extract_spec_from_name": + out = _extract_spec_from_name(out, r.get("source", "name"), dictionary) + elif t == "normalize_unit": + out = _normalize_unit(out, r.get("target", "unit"), r.get("map", {}), dictionary) + elif t == "compute_quantity_from_total": + out = _compute_quantity_from_total(out) + elif t == "fill_missing": + out = _fill_missing(out, r.get("fills", {})) + elif t == "mark_gift": + out = _mark_gift(out) + return out \ No newline at end of file diff --git a/app/core/ocr/__init__.py b/app/core/ocr/__init__.py new file mode 100644 index 0000000..e3d34ad --- /dev/null +++ b/app/core/ocr/__init__.py @@ -0,0 +1,5 @@ +""" +OCR订单处理系统 - OCR核心模块 +--------------------------- +提供OCR识别相关功能,包括图片预处理、文字识别和表格识别。 +""" \ No newline at end of file diff --git a/app/core/ocr/baidu_ocr.py b/app/core/ocr/baidu_ocr.py new file mode 100644 index 0000000..ad4a694 --- /dev/null +++ b/app/core/ocr/baidu_ocr.py @@ -0,0 +1,368 @@ +""" +百度OCR客户端模块 +--------------- +提供百度OCR API的访问和调用功能。 +""" + +import time +import base64 +import requests +from typing import Dict, Optional, Union + +from ..utils.log_utils import get_logger + +logger = get_logger(__name__) + +# Token 过期相关常量 +_DEFAULT_TOKEN_LIFETIME = 30 * 24 * 3600 # 30天(秒) +_TOKEN_EARLY_EXPIRY = 3600 # 提前1小时刷新(秒) + +class TokenManager: + """ + 令牌管理类,负责获取和刷新百度API访问令牌 + """ + + def __init__(self, api_key: str, secret_key: str, max_retries: int = 3, retry_delay: int = 2, token_url: str = None): + """ + 初始化令牌管理器 + + Args: + api_key: 百度API Key + secret_key: 百度Secret Key + max_retries: 最大重试次数 + retry_delay: 重试延迟(秒) + token_url: 令牌获取地址 + """ + self.api_key = api_key + self.secret_key = secret_key + self.max_retries = max_retries + self.retry_delay = retry_delay + self.token_url = token_url or 'https://aip.baidubce.com/oauth/2.0/token' + self.access_token = None + self.token_expiry = 0 + + def get_token(self) -> Optional[str]: + """ + 获取访问令牌,如果令牌已过期则刷新 + + Returns: + 访问令牌,如果获取失败则返回None + """ + if self.is_token_valid(): + return self.access_token + + return self.refresh_token() + + def is_token_valid(self) -> bool: + """ + 检查令牌是否有效 + + Returns: + 令牌是否有效 + """ + return ( + self.access_token is not None and + self.token_expiry > time.time() + 60 # 提前1分钟刷新 + ) + + def refresh_token(self) -> Optional[str]: + """ + 刷新访问令牌 + + Returns: + 新的访问令牌,如果获取失败则返回None + """ + url = self.token_url + params = { + "grant_type": "client_credentials", + "client_id": self.api_key, + "client_secret": self.secret_key + } + + for attempt in range(self.max_retries): + try: + response = requests.post(url, params=params, timeout=10) + if response.status_code == 200: + result = response.json() + if "access_token" in result: + self.access_token = result["access_token"] + # 设置令牌过期时间(默认30天,提前1小时过期以确保安全) + self.token_expiry = time.time() + result.get("expires_in", _DEFAULT_TOKEN_LIFETIME) - _TOKEN_EARLY_EXPIRY + logger.info("成功获取访问令牌") + return self.access_token + + logger.warning(f"获取访问令牌失败 (尝试 {attempt+1}/{self.max_retries}): {response.text}") + + except Exception as e: + logger.warning(f"获取访问令牌时发生错误 (尝试 {attempt+1}/{self.max_retries}): {e}") + + # 如果不是最后一次尝试,则等待后重试 + if attempt < self.max_retries - 1: + time.sleep(self.retry_delay * (attempt + 1)) # 指数退避 + + logger.error("无法获取访问令牌") + return None + +class BaiduOCRClient: + """ + 百度OCR API客户端 + """ + + def __init__(self, config): + """ + 初始化百度OCR客户端 + + Args: + config: 配置信息 + """ + self.config = config + + # 从配置中读取API信息 + try: + # 修复getint调用方式 + self.timeout = config.get('API', 'timeout', fallback=30) + if isinstance(self.timeout, str): + self.timeout = int(self.timeout) + + self.api_key = config.get('API', 'api_key', fallback='') + self.secret_key = config.get('API', 'secret_key', fallback='') + + # 使用fallback而不是位置参数 + try: + self.max_retries = config.getint('API', 'max_retries', fallback=3) + except (TypeError, AttributeError): + # 如果getint不支持fallback,则使用get再转换 + self.max_retries = int(config.get('API', 'max_retries', fallback='3')) + + try: + self.retry_delay = config.getint('API', 'retry_delay', fallback=2) + except (TypeError, AttributeError): + # 如果getint不支持fallback,则使用get再转换 + self.retry_delay = int(config.get('API', 'retry_delay', fallback='2')) + + self.api_url = config.get('API', 'api_url', fallback='https://aip.baidubce.com/rest/2.0/ocr/v1/table') + + # 创建令牌管理器 + self.token_manager = TokenManager( + self.api_key, + self.secret_key, + self.max_retries, + self.retry_delay, + token_url=config.get('API', 'token_url', fallback='https://aip.baidubce.com/oauth/2.0/token') + ) + + # 验证API配置 + if not self.api_key or not self.secret_key: + logger.warning("API密钥未设置,请在配置文件中设置API密钥") + except Exception as e: + logger.error(f"初始化失败: {e}") + + def read_image(self, image_path: str) -> Optional[bytes]: + """ + 读取图片文件为二进制数据 + + Args: + image_path: 图片文件路径 + + Returns: + 图片二进制数据,如果读取失败则返回None + """ + try: + with open(image_path, 'rb') as f: + return f.read() + except Exception as e: + logger.error(f"读取图片文件失败: {image_path}, 错误: {e}") + return None + + def recognize_table(self, image_data: Union[str, bytes]) -> Optional[Dict]: + """ + 识别表格 + + Args: + image_data: 图片数据,可以是文件路径或二进制数据 + + Returns: + 识别结果字典,如果识别失败则返回None + """ + # 获取访问令牌 + access_token = self.token_manager.get_token() + if not access_token: + logger.error("无法获取访问令牌,无法进行表格识别") + return None + + # 如果是文件路径,读取图片数据 + if isinstance(image_data, str): + image_data = self.read_image(image_data) + if image_data is None: + return None + + # 准备请求参数 + url = f"{self.api_url}?access_token={access_token}" + image_base64 = base64.b64encode(image_data).decode('utf-8') + + # 请求参数 - 添加return_excel参数,与v1版本保持一致 + payload = { + 'image': image_base64, + 'is_sync': 'true', # 同步请求 + 'request_type': 'excel', # 输出为Excel + 'return_excel': 'true' # 直接返回Excel数据 + } + + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json' + } + + # 发送请求 + for attempt in range(self.max_retries): + try: + response = requests.post( + url, + data=payload, + headers=headers, + timeout=self.timeout + ) + + if response.status_code == 200: + result = response.json() + # 打印返回结果以便调试 + logger.debug(f"百度OCR API返回结果: {result}") + + if 'error_code' in result: + error_msg = result.get('error_msg', '未知错误') + logger.error(f"百度OCR API错误: {error_msg}") + # 如果是授权错误,尝试刷新令牌 + if result.get('error_code') in [110, 111]: # 授权相关错误码 + logger.info("尝试刷新访问令牌...") + self.token_manager.refresh_token() + return None + + # 兼容不同的返回结构 + # 这是最关键的修改部分: 直接返回整个结果,不强制要求特定结构 + return result + else: + logger.warning(f"表格识别请求失败 (尝试 {attempt+1}/{self.max_retries}): {response.text}") + + except Exception as e: + logger.warning(f"表格识别时发生错误 (尝试 {attempt+1}/{self.max_retries}): {e}") + + # 如果不是最后一次尝试,则等待后重试 + if attempt < self.max_retries - 1: + wait_time = self.retry_delay * (2 ** attempt) # 指数退避 + logger.info(f"将在 {wait_time} 秒后重试...") + time.sleep(wait_time) + + logger.error("表格识别失败") + return None + + def get_excel_result(self, request_id_or_result: Union[str, Dict]) -> Optional[bytes]: + """ + 获取Excel结果 + + Args: + request_id_or_result: 请求ID或完整的识别结果 + + Returns: + Excel二进制数据,如果获取失败则返回None + """ + # 获取访问令牌 + access_token = self.token_manager.get_token() + if not access_token: + logger.error("无法获取访问令牌,无法获取Excel结果") + return None + + # 处理直接传入结果对象的情况 + request_id = request_id_or_result + if isinstance(request_id_or_result, dict): + # v1版本兼容处理:如果结果中直接包含Excel数据 + if 'result' in request_id_or_result: + # 如果是同步返回的Excel结果(某些API版本会直接返回) + if 'result_data' in request_id_or_result['result']: + excel_content = request_id_or_result['result']['result_data'] + if excel_content: + try: + return base64.b64decode(excel_content) + except Exception as e: + logger.error(f"解析Excel数据失败: {e}") + + # 提取request_id + if 'request_id' in request_id_or_result['result']: + request_id = request_id_or_result['result']['request_id'] + logger.debug(f"从result子对象中提取request_id: {request_id}") + elif 'tables_result' in request_id_or_result['result'] and len(request_id_or_result['result']['tables_result']) > 0: + # 某些版本API可能直接返回表格内容,此时可能没有request_id + logger.info("检测到API直接返回了表格内容,但没有request_id") + return None + # 有些版本可能request_id在顶层 + elif 'request_id' in request_id_or_result: + request_id = request_id_or_result['request_id'] + logger.debug(f"从顶层对象中提取request_id: {request_id}") + + # 如果没有有效的request_id,无法获取结果 + if not isinstance(request_id, str): + logger.error(f"无法从结果中提取有效的request_id: {request_id_or_result}") + return None + + base_url = self.config.get('API', 'form_ocr_url', fallback='https://aip.baidubce.com/rest/2.0/solution/v1/form_ocr/get_request_result') + url = f"{base_url}?access_token={access_token}" + + payload = { + 'request_id': request_id, + 'result_type': 'excel' + } + + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json' + } + + for attempt in range(self.max_retries): + try: + response = requests.post( + url, + data=payload, + headers=headers, + timeout=self.timeout + ) + + if response.status_code == 200: + try: + result = response.json() + logger.debug(f"获取Excel结果返回: {result}") + + # 检查是否还在处理中 + if result.get('result', {}).get('ret_code') == 3: + logger.info(f"Excel结果正在处理中,等待后重试 (尝试 {attempt+1}/{self.max_retries})") + time.sleep(2) + continue + + # 检查是否有错误 + if 'error_code' in result or result.get('result', {}).get('ret_code') != 0: + error_msg = result.get('error_msg') or result.get('result', {}).get('ret_msg', '未知错误') + logger.error(f"获取Excel结果失败: {error_msg}") + return None + + # 获取Excel内容 + excel_content = result.get('result', {}).get('result_data') + if excel_content: + return base64.b64decode(excel_content) + else: + logger.error("Excel结果为空") + return None + + except Exception as e: + logger.error(f"解析Excel结果时出错: {e}") + return None + + else: + logger.warning(f"获取Excel结果请求失败 (尝试 {attempt+1}/{self.max_retries}): {response.text}") + + except Exception as e: + logger.warning(f"获取Excel结果时发生错误 (尝试 {attempt+1}/{self.max_retries}): {e}") + + # 如果不是最后一次尝试,则等待后重试 + if attempt < self.max_retries - 1: + time.sleep(self.retry_delay * (attempt + 1)) + + logger.error("获取Excel结果失败") + return None \ No newline at end of file diff --git a/app/core/ocr/table_ocr.py b/app/core/ocr/table_ocr.py new file mode 100644 index 0000000..c61f6c8 --- /dev/null +++ b/app/core/ocr/table_ocr.py @@ -0,0 +1,389 @@ +""" +表格OCR处理模块 +------------- +处理图片并提取表格内容,保存为Excel文件。 +""" + +import os +import time +import base64 +from concurrent.futures import ThreadPoolExecutor +from typing import Dict, List, Optional, Tuple, Callable + +from ..utils.log_utils import get_logger +from ..utils.file_utils import ( + ensure_dir, + get_file_extension, + get_files_by_extensions, + generate_timestamp_filename, + is_file_size_valid, + load_json, + save_json +) +from .baidu_ocr import BaiduOCRClient + +logger = get_logger(__name__) + +class ProcessedRecordManager: + """处理记录管理器,用于跟踪已处理的文件""" + + def __init__(self, record_file: str): + """ + 初始化处理记录管理器 + + Args: + record_file: 记录文件路径 + """ + self.record_file = record_file + self.processed_files = self._load_record() + + def _load_record(self) -> Dict[str, str]: + """ + 加载处理记录 + + Returns: + 处理记录字典,键为输入文件路径,值为输出文件路径 + """ + return load_json(self.record_file, {}) + + def save_record(self) -> None: + """保存处理记录""" + save_json(self.processed_files, self.record_file) + + def is_processed(self, image_file: str) -> bool: + """ + 检查图片是否已处理 + + Args: + image_file: 图片文件路径 + + Returns: + 是否已处理 + """ + return image_file in self.processed_files + + def mark_as_processed(self, image_file: str, output_file: str) -> None: + """ + 标记图片为已处理 + + Args: + image_file: 图片文件路径 + output_file: 输出文件路径 + """ + self.processed_files[image_file] = output_file + self.save_record() + + def get_output_file(self, image_file: str) -> Optional[str]: + """ + 获取图片的输出文件路径 + + Args: + image_file: 图片文件路径 + + Returns: + 输出文件路径,如果不存在则返回None + """ + return self.processed_files.get(image_file) + + def get_unprocessed_files(self, files: List[str]) -> List[str]: + """ + 获取未处理的文件列表 + + Args: + files: 文件列表 + + Returns: + 未处理的文件列表 + """ + return [file for file in files if not self.is_processed(file)] + +class OCRProcessor: + """ + OCR处理器,负责协调OCR识别和结果处理 + """ + + def __init__(self, config): + """ + 初始化OCR处理器 + + Args: + config: 配置信息 + """ + self.config = config + + # 修复ConfigParser对象没有get_path方法的问题 + try: + # 获取输入和输出目录 + self.input_folder = config.get('Paths', 'input_folder', fallback='data/input') + self.output_folder = config.get('Paths', 'output_folder', fallback='data/output') + self.temp_folder = config.get('Paths', 'temp_folder', fallback='data/temp') + + # 确保目录存在 + os.makedirs(self.input_folder, exist_ok=True) + os.makedirs(self.output_folder, exist_ok=True) + os.makedirs(self.temp_folder, exist_ok=True) + + # 获取文件类型列表 + allowed_extensions_str = config.get('File', 'allowed_extensions', fallback='.jpg,.jpeg,.png,.bmp') + self.file_types = [ext.strip() for ext in allowed_extensions_str.split(',') if ext.strip()] + if not self.file_types: + self.file_types = ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tif', '.tiff'] + + # 初始化OCR客户端 + self.ocr_client = BaiduOCRClient(self.config) + + # 记录实际路径 + logger.info(f"使用输入目录: {os.path.abspath(self.input_folder)}") + logger.info(f"使用输出目录: {os.path.abspath(self.output_folder)}") + logger.info(f"使用临时目录: {os.path.abspath(self.temp_folder)}") + logger.info(f"允许的文件类型: {self.file_types}") + + # 初始化processed_files_json和record_manager + self.processed_files_json = os.path.join(self.output_folder, 'processed_files.json') + self.record_manager = ProcessedRecordManager(self.processed_files_json) + + # 加载已处理文件记录 + self.processed_files = self._load_processed_files() + + logger.info(f"初始化OCRProcessor完成:输入目录={self.input_folder}, 输出目录={self.output_folder}") + except Exception as e: + logger.error(f"初始化OCRProcessor失败: {e}") + raise + + def _load_processed_files(self) -> Dict[str, str]: + """ + 加载已处理的文件记录 + + Returns: + 已处理的文件记录字典,键为输入文件路径,值为输出文件路径 + """ + return load_json(self.processed_files_json, {}) + + def get_unprocessed_images(self) -> List[str]: + """ + 获取未处理的图片列表 + + Returns: + 未处理的图片文件路径列表 + """ + # 获取所有图片文件 + image_files = get_files_by_extensions(self.input_folder, self.file_types) + + # 如果需要跳过已存在的文件 + skip_existing = True + try: + skip_existing = self.config.getboolean('Performance', 'skip_existing', fallback=True) + except Exception: + pass + + if skip_existing: + # 过滤已处理的文件 + unprocessed_files = self.record_manager.get_unprocessed_files(image_files) + logger.info(f"找到 {len(image_files)} 个图片文件,其中 {len(unprocessed_files)} 个未处理") + return unprocessed_files + + logger.info(f"找到 {len(image_files)} 个图片文件(不跳过已处理的文件)") + return image_files + + def validate_image(self, image_path: str) -> bool: + """ + 验证图片是否有效 + + Args: + image_path: 图片文件路径 + + Returns: + 图片是否有效 + """ + # 检查文件是否存在 + if not os.path.exists(image_path): + logger.warning(f"图片文件不存在: {image_path}") + return False + + # 检查文件扩展名 + ext = get_file_extension(image_path) + if ext not in self.file_types: + logger.warning(f"不支持的文件类型: {ext}, 文件: {image_path}") + return False + + # 检查文件大小 + max_size_mb = 4.0 + try: + max_size_mb = float(self.config.get('File', 'max_file_size_mb', fallback='4.0')) + except Exception: + pass + + if not is_file_size_valid(image_path, max_size_mb): + logger.warning(f"文件大小超过限制 ({max_size_mb}MB): {image_path}") + return False + + return True + + def process_image(self, image_path: str) -> Optional[str]: + """ + 处理单个图片 + + Args: + image_path: 图片文件路径 + + Returns: + 输出Excel文件路径,如果处理失败则返回None + """ + # 验证图片 + if not self.validate_image(image_path): + return None + + # 获取是否跳过已处理文件的配置 + skip_existing = True + try: + skip_existing = self.config.getboolean('Performance', 'skip_existing', fallback=True) + except Exception: + pass + + # 如果需要跳过已处理的文件 + if skip_existing and self.record_manager.is_processed(image_path): + output_file = self.record_manager.get_output_file(image_path) + logger.info(f"图片已处理,跳过: {image_path}, 输出文件: {output_file}") + return output_file + + logger.info(f"开始处理图片: {image_path}") + + try: + # 获取Excel扩展名 + excel_extension = '.xlsx' + try: + excel_extension = self.config.get('File', 'excel_extension', fallback='.xlsx') + except Exception: + pass + + # 生成输出文件路径 + file_name = os.path.splitext(os.path.basename(image_path))[0] + output_file = os.path.join(self.output_folder, f"{file_name}{excel_extension}") + + # 检查是否已存在对应的Excel文件 + if os.path.exists(output_file) and skip_existing: + logger.info(f"已存在对应的Excel文件,跳过处理: {os.path.basename(image_path)} -> {os.path.basename(output_file)}") + # 记录处理结果 + self.record_manager.mark_as_processed(image_path, output_file) + return output_file + + # 进行OCR识别 + ocr_result = self.ocr_client.recognize_table(image_path) + if not ocr_result: + logger.error(f"OCR识别失败: {image_path}") + return None + + # 保存Excel文件 - 按照v1版本逻辑提取Excel数据 + excel_base64 = None + + # 从不同可能的字段中尝试获取Excel数据 + if 'excel_file' in ocr_result: + excel_base64 = ocr_result['excel_file'] + logger.debug("从excel_file字段获取Excel数据") + elif 'result' in ocr_result: + if 'result_data' in ocr_result['result']: + excel_base64 = ocr_result['result']['result_data'] + logger.debug("从result.result_data字段获取Excel数据") + elif 'excel_file' in ocr_result['result']: + excel_base64 = ocr_result['result']['excel_file'] + logger.debug("从result.excel_file字段获取Excel数据") + elif 'tables_result' in ocr_result['result'] and ocr_result['result']['tables_result']: + for table in ocr_result['result']['tables_result']: + if 'excel_file' in table: + excel_base64 = table['excel_file'] + logger.debug("从tables_result中获取Excel数据") + break + + # 如果还是没有找到Excel数据,尝试通过get_excel_result获取 + if not excel_base64: + logger.info("无法从直接返回中获取Excel数据,尝试通过API获取...") + excel_data = self.ocr_client.get_excel_result(ocr_result) + if not excel_data: + logger.error(f"获取Excel结果失败: {image_path}") + return None + + # 保存Excel文件 + os.makedirs(os.path.dirname(output_file), exist_ok=True) + with open(output_file, 'wb') as f: + f.write(excel_data) + else: + # 解码并保存Excel文件 + try: + excel_data = base64.b64decode(excel_base64) + os.makedirs(os.path.dirname(output_file), exist_ok=True) + with open(output_file, 'wb') as f: + f.write(excel_data) + except Exception as e: + logger.error(f"解码或保存Excel数据时出错: {e}") + return None + + logger.info(f"图片处理成功: {image_path}, 输出文件: {output_file}") + + # 标记为已处理 + self.record_manager.mark_as_processed(image_path, output_file) + + return output_file + + except Exception as e: + logger.error(f"处理图片时出错: {image_path}, 错误: {e}") + return None + + def process_images_batch(self, batch_size: int = None, max_workers: int = None, progress_cb: Optional[Callable[[int], None]] = None) -> Tuple[int, int]: + """ + 批量处理图片 + + Args: + batch_size: 批处理大小,如果为None则使用配置值 + max_workers: 最大线程数,如果为None则使用配置值 + + Returns: + (总处理数, 成功处理数)元组 + """ + # 使用配置值或参数值 + if batch_size is None: + try: + batch_size = self.config.getint('Performance', 'batch_size', fallback=5) + except Exception: + batch_size = 5 + + if max_workers is None: + try: + max_workers = self.config.getint('Performance', 'max_workers', fallback=4) + except Exception: + max_workers = 4 + + # 获取未处理的图片 + unprocessed_images = self.get_unprocessed_images() + if not unprocessed_images: + logger.warning("没有需要处理的图片") + return 0, 0 + + total = len(unprocessed_images) + success_count = 0 + + # 按批次处理 + for i in range(0, total, batch_size): + batch = unprocessed_images[i:i+batch_size] + logger.info(f"处理批次 {i//batch_size+1}/{(total+batch_size-1)//batch_size}: {len(batch)} 个文件") + try: + if progress_cb: + # 以批次为单位估算进度(0-90%),保留10%给后续阶段 + percent = int(10 + (i / max(total, 1)) * 80) + progress_cb(min(percent, 90)) + except Exception: + pass + + # 使用多线程处理批次 + with ThreadPoolExecutor(max_workers=max_workers) as executor: + results = list(executor.map(self.process_image, batch)) + + # 统计成功数 + success_count += sum(1 for result in results if result is not None) + + logger.info(f"所有图片处理完成, 总计: {total}, 成功: {success_count}") + try: + if progress_cb: + progress_cb(90) + except Exception: + pass + return total, success_count diff --git a/app/core/processors/__init__.py b/app/core/processors/__init__.py new file mode 100644 index 0000000..0653b6d --- /dev/null +++ b/app/core/processors/__init__.py @@ -0,0 +1,9 @@ +""" +处理器模块初始化文件 +""" + +from .base import BaseProcessor +from .ocr_processor import OCRProcessor +from .tobacco_processor import TobaccoProcessor + +__all__ = ['BaseProcessor', 'OCRProcessor', 'TobaccoProcessor'] \ No newline at end of file diff --git a/app/core/processors/base.py b/app/core/processors/base.py new file mode 100644 index 0000000..e988851 --- /dev/null +++ b/app/core/processors/base.py @@ -0,0 +1,167 @@ +""" +基础处理器接口模块 + +定义所有处理器的基类,提供统一的处理接口 +""" + +from abc import ABC, abstractmethod +from typing import Dict, Any, Optional, List +from pathlib import Path +import logging +import pandas as pd + +from ...core.utils.log_utils import get_logger + +logger = get_logger(__name__) + + +class BaseProcessor(ABC): + """基础处理器接口 - 所有处理器的基类 + + 采用策略模式设计,每个处理器负责特定类型的文件处理 + """ + + def __init__(self, config: Dict[str, Any]): + """初始化处理器 + + Args: + config: 处理器配置字典 + """ + self.config = config + self.name = self.__class__.__name__ + self.description = "" + self._setup_logging() + + def _setup_logging(self): + """设置处理器日志""" + self.logger = logging.getLogger(f"{__name__}.{self.name}") + + @abstractmethod + def can_process(self, file_path: Path) -> bool: + """判断是否能处理该文件 + + Args: + file_path: 文件路径 + + Returns: + 是否能处理该文件 + """ + pass + + @abstractmethod + def process(self, input_file: Path, output_dir: Path) -> Optional[Path]: + """处理文件,返回输出文件路径 + + Args: + input_file: 输入文件路径 + output_dir: 输出目录路径 + + Returns: + 输出文件路径,处理失败返回None + """ + pass + + @abstractmethod + def get_required_columns(self) -> List[str]: + """返回需要的列名列表 + + Returns: + 列名列表 + """ + pass + + def validate_input(self, file_path: Path) -> bool: + """验证输入文件有效性 + + Args: + file_path: 文件路径 + + Returns: + 文件是否有效 + """ + try: + if not file_path.exists(): + self.logger.warning(f"文件不存在: {file_path}") + return False + + if not file_path.is_file(): + self.logger.warning(f"不是文件: {file_path}") + return False + + supported_extensions = self.get_supported_extensions() + if supported_extensions and file_path.suffix.lower() not in supported_extensions: + self.logger.warning(f"不支持的文件类型: {file_path.suffix}, 支持的类型: {supported_extensions}") + return False + + return True + + except Exception as e: + self.logger.error(f"验证文件时出错: {e}") + return False + + def get_supported_extensions(self) -> List[str]: + """获取支持的文件扩展名 + + Returns: + 支持的扩展名列表,空列表表示支持所有类型 + """ + return [] + + def get_output_filename(self, input_file: Path, suffix: str = "_processed") -> str: + """生成输出文件名 + + Args: + input_file: 输入文件路径 + suffix: 文件名后缀 + + Returns: + 输出文件名 + """ + return f"{input_file.stem}{suffix}{input_file.suffix}" + + def _read_excel_safely(self, file_path: Path, **kwargs) -> pd.DataFrame: + """根据扩展名选择合适的读取引擎 + + Args: + file_path: 文件路径 + **kwargs: 传递给 pd.read_excel 的参数 + + Returns: + DataFrame + + Raises: + Exception: 读取失败时抛出 + """ + suffix = file_path.suffix.lower() + if suffix == '.xlsx': + return pd.read_excel(file_path, engine='openpyxl', **kwargs) + elif suffix == '.xls': + try: + return pd.read_excel(file_path, engine='xlrd', **kwargs) + except Exception as e: + self.logger.warning(f"读取xls失败,可能缺少xlrd: {e}") + raise + else: + return pd.read_excel(file_path, **kwargs) + + def log_processing_start(self, input_file: Path): + """记录处理开始日志""" + self.logger.info(f"开始处理文件: {input_file}") + self.logger.info(f"处理器: {self.name} - {self.description}") + + def log_processing_end(self, input_file: Path, output_file: Optional[Path] = None, success: bool = True): + """记录处理结束日志""" + if success: + self.logger.info(f"处理完成: {input_file}") + if output_file: + self.logger.info(f"输出文件: {output_file}") + else: + self.logger.error(f"处理失败: {input_file}") + + def __str__(self) -> str: + """字符串表示""" + return f"{self.name}({self.description})" + + def __repr__(self) -> str: + """详细字符串表示""" + return f"{self.__class__.__module__}.{self.__class__.__name__}(name='{self.name}', description='{self.description}')" \ No newline at end of file diff --git a/app/core/processors/ocr_processor.py b/app/core/processors/ocr_processor.py new file mode 100644 index 0000000..1ff94bf --- /dev/null +++ b/app/core/processors/ocr_processor.py @@ -0,0 +1,192 @@ +""" +OCR处理器 + +处理图片文件的OCR识别完整流程:图片识别 → Excel处理 → 标准采购单生成 +""" + +import os +from pathlib import Path +from typing import Optional, Dict, Any, List + +from .base import BaseProcessor +from ...services.ocr_service import OCRService +from ...services.order_service import OrderService +from ...core.utils.log_utils import get_logger + +logger = get_logger(__name__) + + +class OCRProcessor(BaseProcessor): + """OCR处理器 + + 处理图片文件的完整OCR识别流程: + 1. OCR识别图片中的表格信息 + 2. 处理识别结果生成Excel文件 + 3. 转换为标准采购单格式 + """ + + def __init__(self, config: Dict[str, Any]): + """初始化OCR处理器 + + Args: + config: 配置信息 + """ + super().__init__(config) + self.description = "OCR识别完整流程(图片→识别→Excel→采购单)" + + # 初始化服务 + self.ocr_service = OCRService(config) + self.order_service = OrderService(config) + + def can_process(self, file_path: Path) -> bool: + """判断是否为支持的图片文件 + + Args: + file_path: 文件路径 + + Returns: + 是否能处理该文件 + """ + if not self.validate_input(file_path): + return False + + # 支持的图片格式 + supported_extensions = ['.jpg', '.jpeg', '.png', '.bmp'] + + if file_path.suffix.lower() in supported_extensions: + self.logger.info(f"识别为图片文件: {file_path.name}") + return True + + return False + + def process(self, input_file: Path, output_dir: Path) -> Optional[Path]: + """处理图片文件的完整OCR流程 + + Args: + input_file: 输入图片文件路径 + output_dir: 输出目录路径 + + Returns: + 输出文件路径,处理失败返回None + """ + self.log_processing_start(input_file) + + try: + self.logger.info("开始OCR识别流程...") + + # 步骤1: OCR识别 + self.logger.info("步骤1/3: OCR识别图片...") + ocr_result = self._perform_ocr(input_file, output_dir) + if not ocr_result: + self.logger.error("OCR识别失败") + self.log_processing_end(input_file, success=False) + return None + + # 步骤2: Excel处理 + self.logger.info("步骤2/3: 处理Excel文件...") + excel_result = self._process_excel(ocr_result, output_dir) + if not excel_result: + self.logger.error("Excel处理失败") + self.log_processing_end(input_file, success=False) + return None + + # 步骤3: 生成标准采购单 + self.logger.info("步骤3/3: 生成标准采购单...") + final_result = self._generate_purchase_order(excel_result, output_dir) + + if final_result: + self.logger.info(f"OCR处理流程完成,输出文件: {final_result}") + self.log_processing_end(input_file, final_result, success=True) + return final_result + else: + self.logger.error("生成采购单失败") + self.log_processing_end(input_file, success=False) + return None + + except Exception as e: + self.logger.error(f"OCR处理流程出错: {e}", exc_info=True) + self.log_processing_end(input_file, success=False) + return None + + def get_required_columns(self) -> List[str]: + """返回需要的列名列表""" + # OCR处理不直接依赖列名,由后续处理步骤决定 + return [] + + def get_supported_extensions(self) -> List[str]: + """支持的文件扩展名""" + return ['.jpg', '.jpeg', '.png', '.bmp'] + + def _perform_ocr(self, input_file: Path, output_dir: Path) -> Optional[Path]: + """执行OCR识别 + + Args: + input_file: 输入图片文件 + output_dir: 输出目录 + + Returns: + OCR生成的Excel文件路径,失败返回None + """ + try: + self.logger.info(f"开始OCR识别: {input_file}") + + # 使用OCR服务处理图片 + result_path = self.ocr_service.process_image(str(input_file)) + + if result_path: + # 确保结果文件在输出目录中 + result_path = Path(result_path) + if result_path.exists(): + self.logger.info(f"OCR识别成功,输出文件: {result_path}") + return result_path + else: + self.logger.error(f"OCR结果文件不存在: {result_path}") + return None + else: + self.logger.error("OCR服务返回None") + return None + + except Exception as e: + self.logger.error(f"OCR识别失败: {e}", exc_info=True) + return None + + def _process_excel(self, excel_file: Path, output_dir: Path) -> Optional[Path]: + """处理Excel文件 + + Args: + excel_file: Excel文件路径 + output_dir: 输出目录 + + Returns: + 处理后的Excel文件路径,失败返回None + """ + try: + self.logger.info(f"开始处理Excel文件: {excel_file}") + + # 使用订单服务处理Excel文件(生成采购单) + result_path = self.order_service.process_excel(str(excel_file)) + + if result_path: + result_path = Path(result_path) + if result_path.exists(): + self.logger.info(f"Excel处理成功,输出文件: {result_path}") + return result_path + else: + self.logger.error(f"Excel处理结果文件不存在: {result_path}") + return None + else: + self.logger.error("Excel处理服务返回None") + return None + + except Exception as e: + self.logger.error(f"Excel处理失败: {e}", exc_info=True) + return None + + def _generate_purchase_order(self, processed_file: Path, output_dir: Path) -> Optional[Path]: + """采购单生成由OrderService完成,此处直接返回处理结果""" + try: + if processed_file and processed_file.exists(): + return processed_file + return None + except Exception: + return None diff --git a/app/core/processors/supplier_processors/__init__.py b/app/core/processors/supplier_processors/__init__.py new file mode 100644 index 0000000..d9e1616 --- /dev/null +++ b/app/core/processors/supplier_processors/__init__.py @@ -0,0 +1,7 @@ +""" +供应商处理器模块初始化文件 +""" + +from .generic_supplier_processor import GenericSupplierProcessor + +__all__ = ['GenericSupplierProcessor'] \ No newline at end of file diff --git a/app/core/processors/supplier_processors/generic_supplier_processor.py b/app/core/processors/supplier_processors/generic_supplier_processor.py new file mode 100644 index 0000000..38525ca --- /dev/null +++ b/app/core/processors/supplier_processors/generic_supplier_processor.py @@ -0,0 +1,340 @@ +""" +通用供应商处理器 + +可配置化的供应商处理器,支持通过配置文件定义处理规则 +""" + +import fnmatch +import pandas as pd +from typing import Optional, Dict, Any, List +from pathlib import Path + +from ..base import BaseProcessor +from ...utils.log_utils import get_logger +from ...handlers.rule_engine import apply_rules +from ...handlers.column_mapper import ColumnMapper +from ...handlers.data_cleaner import DataCleaner +from ...handlers.calculator import DataCalculator + +logger = get_logger(__name__) + + +class GenericSupplierProcessor(BaseProcessor): + """通用供应商处理器 + + 基于配置文件处理不同供应商的Excel文件,支持: + - 文件名模式匹配 + - 内容特征识别 + - 列映射配置 + - 数据清洗规则 + - 计算处理规则 + """ + + def __init__(self, config: Dict[str, Any], supplier_config: Dict[str, Any]): + """初始化通用供应商处理器 + + Args: + config: 系统配置 + supplier_config: 供应商特定配置 + """ + super().__init__(config) + self.supplier_config = supplier_config + + # 从配置中提取基本信息 + self.name = supplier_config.get('name', 'GenericSupplier') + self.description = supplier_config.get('description', '通用供应商处理器') + + # 处理规则配置 + self.filename_patterns = supplier_config.get('filename_patterns', []) + self.content_indicators = supplier_config.get('content_indicators', []) + self.column_mapping = supplier_config.get('column_mapping', {}) + self.cleaning_rules = supplier_config.get('cleaning_rules', []) + self.calculations = supplier_config.get('calculations', []) + + # 输出配置 + self.output_template = supplier_config.get('output_template', 'templates/银豹-采购单模板.xls') + self.output_suffix = supplier_config.get('output_suffix', '_银豹采购单') + + def can_process(self, file_path: Path) -> bool: + """判断是否能处理该文件 + + Args: + file_path: 文件路径 + + Returns: + 是否能处理 + """ + if not self.validate_input(file_path): + return False + + # 检查文件名模式 + if self.filename_patterns: + filename_match = self._check_filename_patterns(file_path) + if filename_match: + return True + + # 检查文件内容特征 + if self.content_indicators: + content_match = self._check_content_indicators(file_path) + if content_match: + return True + + # 如果都没有配置,则无法判断 + if not self.filename_patterns and not self.content_indicators: + self.logger.warning(f"处理器 {self.name} 没有配置识别规则") + return False + + return False + + def process(self, input_file: Path, output_dir: Path) -> Optional[Path]: + """处理文件 + + Args: + input_file: 输入文件路径 + output_dir: 输出目录路径 + + Returns: + 输出文件路径,处理失败返回None + """ + self.log_processing_start(input_file) + + try: + # 步骤1: 读取数据 + self.logger.info("步骤1/4: 读取数据...") + df = self._read_supplier_data(input_file) + if df is None or df.empty: + self.logger.error("读取数据失败或数据为空") + self.log_processing_end(input_file, success=False) + return None + + # 步骤2: 应用列映射 + self.logger.info("步骤2/4: 应用列映射...") + mapped_df = self._apply_column_mapping(df) + if mapped_df is None: + self.logger.error("列映射失败") + self.log_processing_end(input_file, success=False) + return None + + # 步骤3: 数据清洗 + self.logger.info("步骤3/4: 数据清洗...") + cleaned_df = self._apply_data_cleaning(mapped_df) + if cleaned_df is None: + self.logger.error("数据清洗失败") + self.log_processing_end(input_file, success=False) + return None + try: + rules = self.supplier_config.get('rules', []) + dictionary = self.supplier_config.get('dictionary') + standardized_df = apply_rules(cleaned_df, rules, dictionary) + except Exception as e: + self.logger.warning(f"规则执行失败: {e}") + standardized_df = cleaned_df + + # 步骤4: 计算处理 + self.logger.info("步骤4/4: 计算处理...") + calculated_df = self._apply_calculations(standardized_df) + if calculated_df is None: + self.logger.error("计算处理失败") + self.log_processing_end(input_file, success=False) + return None + + # 生成输出文件 + output_file = self._generate_output(calculated_df, input_file, output_dir) + + if output_file and output_file.exists(): + self.logger.info(f"处理完成,输出文件: {output_file}") + self.log_processing_end(input_file, output_file, success=True) + return output_file + else: + self.logger.error("输出文件生成失败") + self.log_processing_end(input_file, success=False) + return None + + except Exception as e: + self.logger.error(f"处理文件时出错: {e}", exc_info=True) + self.log_processing_end(input_file, success=False) + return None + + def get_required_columns(self) -> List[str]: + """返回需要的列名列表""" + # 从列映射配置中提取目标列名 + return list(self.column_mapping.values()) if self.column_mapping else [] + + def _check_filename_patterns(self, file_path: Path) -> bool: + """检查文件名模式 + + Args: + file_path: 文件路径 + + Returns: + 是否匹配 + """ + try: + filename = file_path.name + for pattern in self.filename_patterns: + if fnmatch.fnmatch(filename.lower(), pattern.lower()): + self.logger.info(f"文件名匹配成功: {filename} -> {pattern}") + return True + return False + except Exception as e: + self.logger.error(f"检查文件名模式时出错: {e}") + return False + + def _check_content_indicators(self, file_path: Path) -> bool: + """检查文件内容特征 + + Args: + file_path: 文件路径 + + Returns: + 是否匹配 + """ + try: + df = self._read_excel_safely(file_path, nrows=5) + + # 检查列名中是否包含指定关键词 + columns_str = str(list(df.columns)).lower() + + for indicator in self.content_indicators: + if indicator.lower() in columns_str: + self.logger.info(f"内容特征匹配成功: {indicator}") + return True + + return False + + except Exception as e: + self.logger.error(f"检查内容特征时出错: {e}") + return False + + def _read_supplier_data(self, file_path: Path) -> Optional[pd.DataFrame]: + """读取供应商数据 + + Args: + file_path: 文件路径 + + Returns: + 数据DataFrame或None + """ + try: + specified = self.supplier_config.get('header_row') + if specified is not None: + try: + df = self._read_excel_safely(file_path, header=int(specified)) + except Exception: + df = self._read_excel_safely(file_path) + else: + df0 = self._read_excel_safely(file_path, header=None) + if df0 is None: + return None + header_row = self._find_header_row(df0) + if header_row is not None: + df = self._read_excel_safely(file_path, header=header_row) + else: + df = self._read_excel_safely(file_path) + if df is None or df.empty: + self.logger.warning("数据文件为空") + return None + self.logger.info(f"成功读取数据,形状: {df.shape}") + return df + except Exception as e: + self.logger.error(f"读取数据失败: {e}") + return None + + def _find_header_row(self, df: pd.DataFrame) -> Optional[int]: + result = ColumnMapper.detect_header_row(df, max_rows=30) + return result if result >= 0 else None + + def _apply_column_mapping(self, df: pd.DataFrame) -> Optional[pd.DataFrame]: + """应用列映射 + + Args: + df: 原始数据 + + Returns: + 映射后的数据或None + """ + if not self.column_mapping: + self.logger.info("没有列映射配置") + return df + + try: + # 应用列重命名 + df_renamed = df.rename(columns=self.column_mapping) + + # 检查必需的列是否存在 + required_columns = self.get_required_columns() + missing_columns = [col for col in required_columns if col not in df_renamed.columns] + + if missing_columns: + self.logger.warning(f"缺少必需的列: {missing_columns}") + # 创建缺失的列并填充默认值 + for col in missing_columns: + df_renamed[col] = 0 if '量' in col or '价' in col else '' + self.logger.info(f"创建缺失列: {col},默认值: {df_renamed[col].iloc[0] if len(df_renamed) > 0 else 'N/A'}") + + self.logger.info(f"列映射完成,列名: {list(df_renamed.columns)}") + return df_renamed + + except Exception as e: + self.logger.error(f"列映射失败: {e}") + return None + + def _apply_data_cleaning(self, df: pd.DataFrame) -> Optional[pd.DataFrame]: + """应用数据清洗规则,委托给 DataCleaner""" + if not self.cleaning_rules: + self.logger.info("没有数据清洗规则") + return df + try: + cleaner = DataCleaner() + for rule in self.cleaning_rules: + cleaner.add_rule(rule.get('type'), **{k: v for k, v in rule.items() if k != 'type'}) + result = cleaner.clean(df) + self.logger.info(f"数据清洗完成,数据形状: {result.shape}") + return result + except Exception as e: + self.logger.error(f"数据清洗失败: {e}") + return None + + def _apply_calculations(self, df: pd.DataFrame) -> Optional[pd.DataFrame]: + """应用计算处理,委托给 DataCalculator""" + if not self.calculations: + self.logger.info("没有计算规则") + return df + try: + calculator = DataCalculator() + for calc in self.calculations: + calculator.add_rule(calc.get('type'), **{k: v for k, v in calc.items() if k != 'type'}) + result = calculator.calculate(df) + self.logger.info(f"计算处理完成,数据形状: {result.shape}") + return result + except Exception as e: + self.logger.error(f"计算处理失败: {e}") + return None + + def _generate_output(self, df: pd.DataFrame, input_file: Path, output_dir: Path) -> Optional[Path]: + """生成输出文件 + + Args: + df: 最终数据 + input_file: 输入文件路径 + output_dir: 输出目录 + + Returns: + 输出文件路径或None + """ + try: + # 生成输出文件名 + timestamp = pd.Timestamp.now().strftime("%Y%m%d_%H%M%S") + output_filename = f"{input_file.stem}{self.output_suffix}_{timestamp}.xls" + output_file = output_dir / output_filename + + # 这里应该使用实际的模板生成逻辑 + # 暂时直接保存为Excel文件 + df.to_excel(output_file, index=False) + + self.logger.info(f"输出文件生成成功: {output_file}") + return output_file + + except Exception as e: + self.logger.error(f"生成输出文件失败: {e}") + return None diff --git a/app/core/processors/tobacco_processor.py b/app/core/processors/tobacco_processor.py new file mode 100644 index 0000000..3641ad5 --- /dev/null +++ b/app/core/processors/tobacco_processor.py @@ -0,0 +1,347 @@ +""" +烟草订单处理器 + +处理烟草公司特定格式的订单明细文件,生成银豹采购单 +""" + +import os +import datetime +import pandas as pd +import xlrd +import xlwt +from xlutils.copy import copy +from openpyxl import load_workbook +from typing import Optional, Dict, Any, List, Tuple +from pathlib import Path + +from .base import BaseProcessor +from ...core.utils.log_utils import get_logger +from ...core.utils.string_utils import parse_monetary_string +from ...core.utils.dialog_utils import show_custom_dialog + +logger = get_logger(__name__) + + +class TobaccoProcessor(BaseProcessor): + """烟草订单处理器 + + 处理烟草公司订单明细文件,提取商品信息并生成标准银豹采购单格式 + """ + + def __init__(self, config: Dict[str, Any]): + """初始化烟草订单处理器 + + Args: + config: 配置信息 + """ + super().__init__(config) + self.description = "处理烟草公司订单明细文件" + self.template_file = config.get('Paths', 'template_file', fallback='templates/银豹-采购单模板.xls') + + # 输出目录配置 + self.result_dir = Path("data/result") + self.result_dir.mkdir(exist_ok=True) + + # 默认输出文件名 + self.default_output_name = "银豹采购单_烟草公司.xls" + + def can_process(self, file_path: Path) -> bool: + """判断是否为烟草订单文件 + + Args: + file_path: 文件路径 + + Returns: + 是否能处理该文件 + """ + if not self.validate_input(file_path): + return False + + # 检查文件名特征 + filename = file_path.name + tobacco_keywords = ['烟草', '卷烟', '订单明细', 'tobacco', '烟'] + + # 检查文件内容特征 + try: + df = self._read_excel_safely(file_path, nrows=5) + required_columns = ['商品', '盒码', '订单量'] + + # 检查文件名或内容特征 + filename_match = any(keyword in filename for keyword in tobacco_keywords) + content_match = all(col in df.columns for col in required_columns) + + if filename_match or content_match: + self.logger.info(f"识别为烟草订单文件: {filename}") + return True + + return False + + except Exception as e: + self.logger.warning(f"检查文件内容时出错: {e}") + # 如果无法读取内容,仅基于文件名判断 + return any(keyword in filename for keyword in tobacco_keywords) + + def process(self, input_file: Path, output_dir: Path) -> Optional[Path]: + """处理烟草订单 + + Args: + input_file: 输入文件路径 + output_dir: 输出目录路径 + + Returns: + 输出文件路径,处理失败返回None + """ + self.log_processing_start(input_file) + + try: + # 读取订单信息(时间和总金额) + order_info = self._read_order_info(input_file) + if not order_info: + self.logger.error(f"读取订单信息失败: {input_file}") + self.log_processing_end(input_file, success=False) + return None + + order_time, total_amount = order_info + self.logger.info(f"订单信息 - 时间: {order_time}, 总金额: {total_amount}") + + # 读取订单数据 + order_data = self._read_order_data(input_file) + if order_data is None or order_data.empty: + self.logger.error(f"读取订单数据失败或数据为空: {input_file}") + self.log_processing_end(input_file, success=False) + return None + + self.logger.info(f"成功读取订单数据,共{len(order_data)}条记录") + + # 生成输出文件路径 + timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + output_filename = f"银豹采购单_烟草公司_{timestamp}.xls" + output_file = output_dir / output_filename + + # 确保输出目录存在 + output_file.parent.mkdir(parents=True, exist_ok=True) + + # 生成银豹采购单 + result = self._generate_pospal_order(order_data, order_time, output_file) + + if result: + self.logger.info(f"采购单生成成功: {output_file}") + self.log_processing_end(input_file, output_file, success=True) + + # 显示处理结果 + self._show_processing_result(output_file, order_time, len(order_data), total_amount) + + return output_file + else: + self.logger.error("生成银豹采购单失败") + self.log_processing_end(input_file, success=False) + return None + + except Exception as e: + self.logger.error(f"处理烟草订单时发生错误: {e}", exc_info=True) + self.log_processing_end(input_file, success=False) + return None + + def get_required_columns(self) -> List[str]: + """返回需要的列名列表""" + return ['商品', '盒码', '条码', '建议零售价', '批发价', '需求量', '订单量', '金额'] + + def get_supported_extensions(self) -> List[str]: + """支持的文件扩展名""" + return ['.xlsx', '.xls'] + + def _read_order_info(self, file_path: Path) -> Optional[Tuple[str, float]]: + """读取订单信息(时间和总金额) + + Args: + file_path: 文件路径 + + Returns: + 包含订单时间和总金额的元组或None + """ + try: + wb_info = load_workbook(file_path, data_only=True) + ws_info = wb_info.active + + # 从指定单元格读取订单信息 + order_time = ws_info["H1"].value or "(空)" + total_amount = ws_info["H3"].value or 0.0 + + self.logger.info(f"成功读取订单信息: 时间={order_time}, 总金额={total_amount}") + return (order_time, total_amount) + + except Exception as e: + self.logger.error(f"读取订单信息出错: {e}") + return None + + def _read_order_data(self, file_path: Path) -> Optional[pd.DataFrame]: + """读取订单数据 + + Args: + file_path: 文件路径 + + Returns: + 订单数据DataFrame或None + """ + columns = ['商品', '盒码', '条码', '建议零售价', '批发价', '需求量', '订单量', '金额'] + + try: + df_old = self._read_excel_safely(file_path, header=None, skiprows=3, names=columns) + + # 过滤订单量不为0的数据,并计算采购量和单价 + df_filtered = df_old[df_old['订单量'] != 0].copy() + + if df_filtered.empty: + self.logger.warning("没有订单量不为0的记录") + return None + + # 计算采购量和单价 + df_filtered['采购量'] = df_filtered['订单量'] * 10 # 烟草订单通常需要乘以10 + df_filtered['采购单价'] = df_filtered['金额'] / df_filtered['采购量'] + df_filtered = df_filtered.reset_index(drop=True) + + self.logger.info(f"成功处理订单数据,有效记录数: {len(df_filtered)}") + return df_filtered + + except Exception as e: + self.logger.error(f"读取订单数据失败: {e}") + return None + + def _generate_pospal_order(self, order_data: pd.DataFrame, order_time: str, output_file: Path) -> bool: + """生成银豹采购单 + + Args: + order_data: 订单数据 + order_time: 订单时间 + output_file: 输出文件路径 + + Returns: + 是否生成成功 + """ + try: + # 检查模板文件是否存在 + template_path = Path(self.template_file) + if not template_path.exists(): + self.logger.error(f"采购单模板文件不存在: {template_path}") + return False + + self.logger.info(f"使用模板文件: {template_path}") + + # 打开模板,准备写入 + template_rd = xlrd.open_workbook(str(template_path), formatting_info=True) + template_wb = copy(template_rd) + template_ws = template_wb.get_sheet(0) + + # 获取模板中的表头列索引 + header_row = template_rd.sheet_by_index(0).row_values(0) + + # 查找需要的列索引 + try: + barcode_col = header_row.index("条码(必填)") + amount_col = header_row.index("采购量(必填)") + gift_col = header_row.index("赠送量") + price_col = header_row.index("采购单价(必填)") + except ValueError as e: + self.logger.error(f"模板列查找失败: {e}") + return False + + self.logger.info(f"模板列索引 - 条码:{barcode_col}, 采购量:{amount_col}, 赠送量:{gift_col}, 单价:{price_col}") + + # 写入数据到模板 + for i, row in order_data.iterrows(): + template_ws.write(i + 1, barcode_col, row['盒码']) # 商品条码 + template_ws.write(i + 1, amount_col, int(row['采购量'])) # 采购量 + template_ws.write(i + 1, gift_col, "") # 赠送量为空 + template_ws.write(i + 1, price_col, round(row['采购单价'], 2)) # 采购单价保留两位小数 + + # 确保输出目录存在 + output_file.parent.mkdir(parents=True, exist_ok=True) + + # 保存输出文件 + template_wb.save(str(output_file)) + + self.logger.info(f"采购单生成成功: {output_file}") + return True + + except Exception as e: + self.logger.error(f"生成银豹采购单失败: {e}", exc_info=True) + return False + + def _show_processing_result(self, output_file: Path, order_time: str, total_count: int, total_amount: float): + """显示处理结果 + + Args: + output_file: 输出文件路径 + order_time: 订单时间 + total_count: 处理条目数 + total_amount: 总金额 + """ + try: + # 创建附加信息 + additional_info = { + "订单来源": "烟草公司", + "处理时间": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + } + + # 格式化金额显示 + parsed = parse_monetary_string(total_amount) + total_amount = parsed if parsed is not None else 0.0 + amount_display = f"¥{total_amount:.2f}" + + # 显示自定义对话框 + show_custom_dialog( + title="烟草订单处理结果", + message="烟草订单处理完成", + result_file=str(output_file), + time_info=order_time, + count_info=f"{total_count}个商品", + amount_info=amount_display, + additional_info=additional_info + ) + + self.logger.info(f"显示处理结果 - 文件:{output_file}, 时间:{order_time}, 数量:{total_count}, 金额:{total_amount}") + + except Exception as e: + self.logger.error(f"显示处理结果时出错: {e}") + + def get_latest_tobacco_order(self) -> Optional[Path]: + """获取最新的烟草订单明细文件(兼容旧接口) + + Returns: + 文件路径或None + """ + try: + # 获取今日开始时间戳 + today = datetime.date.today() + today_start = datetime.datetime.combine(today, datetime.time.min).timestamp() + + # 查找订单明细文件 + result_dir = Path("data/output") + if not result_dir.exists(): + return None + + # 查找符合条件的文件 + candidates = [] + for file_path in result_dir.glob("订单明细*.xlsx"): + if file_path.stat().st_ctime >= today_start: + candidates.append(file_path) + + if not candidates: + self.logger.warning("未找到今天创建的烟草订单明细文件") + # 返回最新的文件 + all_files = list(result_dir.glob("订单明细*.xlsx")) + if all_files: + all_files.sort(key=lambda x: x.stat().st_ctime, reverse=True) + return all_files[0] + return None + + # 返回最新的文件 + candidates.sort(key=lambda x: x.stat().st_ctime, reverse=True) + latest_file = candidates[0] + + self.logger.info(f"找到最新烟草订单明细文件: {latest_file}") + return latest_file + + except Exception as e: + self.logger.error(f"获取最新烟草订单文件时出错: {e}") + return None diff --git a/app/core/utils/__init__.py b/app/core/utils/__init__.py new file mode 100644 index 0000000..7931e8d --- /dev/null +++ b/app/core/utils/__init__.py @@ -0,0 +1,5 @@ +""" +OCR订单处理系统 - 工具模块 +------------------------ +提供系统通用工具和辅助函数。 +""" \ No newline at end of file diff --git a/app/core/utils/cloud_sync.py b/app/core/utils/cloud_sync.py new file mode 100644 index 0000000..ff929a4 --- /dev/null +++ b/app/core/utils/cloud_sync.py @@ -0,0 +1,184 @@ +"""云端同步模块 — 基于 Gitea REST API 的文件同步""" + +import base64 +import json +from typing import Optional, Tuple + +import requests + +from .log_utils import get_logger + +logger = get_logger(__name__) + + +class GiteaSync: + """通过 Gitea REST API 读写仓库文件""" + + def __init__(self, base_url: str, owner: str, repo: str, token: str, timeout: int = 15): + self.base_url = base_url.rstrip("/") + self.owner = owner + self.repo = repo + self.token = token + self.timeout = timeout + + @property + def _headers(self) -> dict: + return {"Authorization": f"token {self.token}"} + + def _api_url(self, path: str) -> str: + return f"{self.base_url}/api/v1/repos/{self.owner}/{self.repo}/contents/{path}" + + def pull_file(self, remote_path: str) -> Optional[Tuple[bytes, str]]: + """从仓库下载文件 + + Returns: + (content_bytes, sha) 或 None(文件不存在或失败) + """ + try: + resp = requests.get( + self._api_url(remote_path), + headers=self._headers, + timeout=self.timeout, + ) + if resp.status_code == 404: + logger.info(f"云端文件不存在: {remote_path}") + return None + if resp.status_code != 200: + logger.warning(f"拉取文件失败: {resp.status_code} {resp.text[:200]}") + return None + + data = resp.json() + sha = data.get("sha", "") + content_b64 = data.get("content", "") + # Gitea 返回的 base64 可能含换行 + content_bytes = base64.b64decode(content_b64.replace("\n", "")) + logger.info(f"拉取文件成功: {remote_path} ({len(content_bytes)} bytes)") + return content_bytes, sha + + except requests.RequestException as e: + logger.error(f"拉取文件网络错误: {e}") + return None + + def push_file( + self, + remote_path: str, + content: bytes, + message: str, + sha: Optional[str] = None, + ) -> Optional[str]: + """上传或更新文件到仓库 + + Args: + remote_path: 仓库中的文件路径 + content: 文件内容(bytes) + message: commit message + sha: 文件当前 sha(更新时必传,新建时省略) + + Returns: + 新的 sha,失败返回 None + """ + payload = { + "message": message, + "content": base64.b64encode(content).decode("ascii"), + } + if sha: + payload["sha"] = sha + + try: + resp = requests.put( + self._api_url(remote_path), + headers={**self._headers, "Content-Type": "application/json"}, + json=payload, + timeout=self.timeout, + ) + if resp.status_code not in (200, 201): + logger.warning(f"推送文件失败: {resp.status_code} {resp.text[:200]}") + return None + + new_sha = resp.json().get("content", {}).get("sha", "") + logger.info(f"推送文件成功: {remote_path} (sha={new_sha[:12]})") + return new_sha + + except requests.RequestException as e: + logger.error(f"推送文件网络错误: {e}") + return None + + def file_exists(self, remote_path: str) -> Optional[str]: + """检查文件是否存在 + + Returns: + 文件 sha(存在)或 None(不存在) + """ + try: + resp = requests.head( + self._api_url(remote_path), + headers=self._headers, + timeout=self.timeout, + ) + if resp.status_code == 200: + # HEAD 不返回 body,需要 GET 获取 sha + result = self.pull_file(remote_path) + return result[1] if result else None + return None + except requests.RequestException: + return None + + def pull_json(self, remote_path: str) -> Optional[Tuple[dict, str]]: + """拉取并解析 JSON 文件 + + Returns: + (parsed_dict, sha) 或 None + """ + result = self.pull_file(remote_path) + if result is None: + return None + content_bytes, sha = result + try: + data = json.loads(content_bytes) + return data, sha + except json.JSONDecodeError as e: + logger.error(f"解析 JSON 失败: {e}") + return None + + def push_json(self, remote_path: str, data: dict, message: str, sha: Optional[str] = None) -> Optional[str]: + """将 dict 序列化为 JSON 并推送 + + Returns: + 新的 sha,失败返回 None + """ + content = json.dumps(data, ensure_ascii=False, indent=2).encode("utf-8") + return self.push_file(remote_path, content, message, sha) + + def push_binary(self, remote_path: str, local_path: str, message: str) -> Optional[str]: + """读取本地二进制文件并推送到云端 + + Returns: + 新的 sha,失败返回 None + """ + try: + with open(local_path, "rb") as f: + content = f.read() + except OSError as e: + logger.error(f"读取本地文件失败: {local_path} — {e}") + return None + + existing_sha = self.file_exists(remote_path) + return self.push_file(remote_path, content, message, sha=existing_sha) + + @classmethod + def from_config(cls, config) -> Optional["GiteaSync"]: + """从 ConfigManager 创建实例 + + Returns: + GiteaSync 实例,配置不完整时返回 None + """ + base_url = config.get("Gitea", "base_url", fallback="").strip() + owner = config.get("Gitea", "owner", fallback="").strip() + repo = config.get("Gitea", "repo", fallback="").strip() + token = config.get("Gitea", "token", fallback="").strip() + + if not all([base_url, owner, repo, token]): + logger.debug("Gitea 配置不完整,跳过云端同步") + return None + + return cls(base_url=base_url, owner=owner, repo=repo, token=token) diff --git a/app/core/utils/dialog_utils.py b/app/core/utils/dialog_utils.py new file mode 100644 index 0000000..78d8746 --- /dev/null +++ b/app/core/utils/dialog_utils.py @@ -0,0 +1,1142 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +对话框工具模块 +------------- +提供各种弹窗和对话框显示功能 +""" + +import os +import json +import tkinter as tk +from tkinter import messagebox, ttk, simpledialog +from datetime import datetime + +from .cloud_sync import GiteaSync +from app.config.settings import ConfigManager + +def create_custom_dialog(title="提示", message="", result_file=None, time_info=None, + count_info=None, amount_info=None, additional_info=None): + """ + 创建自定义结果对话框 + + Args: + title: 对话框标题 + message: 主要消息 + result_file: 结果文件路径(如果有) + time_info: 时间信息(如:订单时间) + count_info: 数量信息(如:处理条目数) + amount_info: 金额信息(如:总金额) + additional_info: 其他附加信息(字典格式) + + Returns: + dialog: 对话框对象 + """ + # 创建对话框 + dialog = tk.Toplevel() + dialog.title(title) + dialog.geometry("450x320") + dialog.resizable(False, False) + + # 使弹窗居中显示 + center_window(dialog) + + # 添加标题 + tk.Label(dialog, text=message, font=("Arial", 16, "bold")).pack(pady=10) + + # 创建内容框架 + result_frame = tk.Frame(dialog) + result_frame.pack(pady=10, fill=tk.BOTH, expand=True) + + # 添加时间、数量、金额等信息 + if time_info: + tk.Label(result_frame, text=f"时间信息: {time_info}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + + if count_info: + tk.Label(result_frame, text=f"处理数量: {count_info}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + + if amount_info: + tk.Label(result_frame, text=f"金额信息: {amount_info}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + + # 添加其他附加信息 + if additional_info and isinstance(additional_info, dict): + for key, value in additional_info.items(): + tk.Label(result_frame, text=f"{key}: {value}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + + # 如果有结果文件,显示文件信息 + if result_file and os.path.exists(result_file): + tk.Label(result_frame, text=f"输出文件: {os.path.basename(result_file)}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + + # 成功提示 + tk.Label(result_frame, text="处理已成功完成!", font=("Arial", 12, "bold"), fg="#28a745").pack(pady=10) + + # 文件信息框 + file_frame = tk.Frame(result_frame, relief=tk.GROOVE, borderwidth=1) + file_frame.pack(fill=tk.X, padx=15, pady=5) + + tk.Label(file_frame, text="文件信息", font=("Arial", 10, "bold")).pack(anchor=tk.W, padx=10, pady=5) + + # 获取文件大小和时间 + try: + file_size = os.path.getsize(result_file) + file_time = datetime.fromtimestamp(os.path.getmtime(result_file)) + + from .file_utils import format_file_size + size_text = format_file_size(file_size) + + tk.Label(file_frame, text=f"文件大小: {size_text}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2) + tk.Label(file_frame, text=f"创建时间: {file_time.strftime('%Y-%m-%d %H:%M:%S')}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2) + except Exception: + tk.Label(file_frame, text="无法获取文件信息", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2) + + # 添加按钮 + button_frame = tk.Frame(dialog) + button_frame.pack(pady=10) + + tk.Button(button_frame, text="打开文件", command=lambda: os.startfile(result_file)).pack(side=tk.LEFT, padx=5) + tk.Button(button_frame, text="打开所在文件夹", command=lambda: os.startfile(os.path.dirname(result_file))).pack(side=tk.LEFT, padx=5) + tk.Button(button_frame, text="关闭", command=dialog.destroy).pack(side=tk.LEFT, padx=5) + else: + # 如果没有结果文件或文件不存在 + if result_file: + tk.Label(result_frame, text="未找到输出文件", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text="请检查输出目录", font=("Arial", 12, "bold"), fg="#dc3545").pack(pady=10) + + # 添加按钮 + button_frame = tk.Frame(dialog) + button_frame.pack(pady=10) + + tk.Button(button_frame, text="打开输出目录", command=lambda: os.startfile(os.path.abspath("data/output"))).pack(side=tk.LEFT, padx=5) + tk.Button(button_frame, text="关闭", command=dialog.destroy).pack(side=tk.LEFT, padx=5) + + # 确保窗口显示在最前 + dialog.lift() + dialog.attributes('-topmost', True) + dialog.after_idle(lambda: dialog.attributes('-topmost', False)) + + return dialog + +def show_custom_dialog(*args, **kwargs): + """ + 显示自定义对话框 + + 参数与create_custom_dialog相同 + + Returns: + dialog: 对话框对象 + """ + return create_custom_dialog(*args, **kwargs) + +def center_window(window): + """使窗口居中显示""" + window.update_idletasks() + width = window.winfo_width() + height = window.winfo_height() + x = (window.winfo_screenwidth() // 2) - (width // 2) + y = (window.winfo_screenheight() // 2) - (height // 2) + window.geometry('{}x{}+{}+{}'.format(width, height, x, y)) + +def create_barcode_mapping_dialog(parent=None, on_save=None, current_mappings=None): + """ + 创建条码映射编辑弹窗 + + Args: + parent: 父窗口 + on_save: 保存回调函数,接收修改后的映射数据 + current_mappings: 当前的映射数据 + + Returns: + dialog: 对话框对象 + """ + dialog = tk.Toplevel(parent) + dialog.title("条码映射编辑") + dialog.geometry("600x500") + dialog.resizable(True, True) + + # 使弹窗居中显示 + center_window(dialog) + + # 创建主框架 + main_frame = tk.Frame(dialog) + main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) + + # 创建选项卡控件 + tab_control = ttk.Notebook(main_frame) + + # 创建两个选项卡页面 + tab1 = tk.Frame(tab_control) + tab2 = tk.Frame(tab_control) + + tab_control.add(tab1, text="条码映射") + tab_control.add(tab2, text="特殊处理") + tab_control.pack(expand=True, fill=tk.BOTH) + + # ========= 条码映射选项卡 ========= + # 顶部输入区域 + input_frame = tk.Frame(tab1) + input_frame.pack(fill=tk.X, padx=5, pady=5) + + tk.Label(input_frame, text="源条码:").grid(row=0, column=0, padx=5, pady=5) + source_entry = tk.Entry(input_frame, width=20) + source_entry.grid(row=0, column=1, padx=5, pady=5) + + tk.Label(input_frame, text="目标条码:").grid(row=0, column=2, padx=5, pady=5) + target_entry = tk.Entry(input_frame, width=20) + target_entry.grid(row=0, column=3, padx=5, pady=5) + + # 存储映射列表的变量 + mapping_list = [] + + # 映射列表显示区域 + list_frame = tk.Frame(tab1) + list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) + + columns = ("源条码", "目标条码") + mapping_tree = ttk.Treeview(list_frame, columns=columns, show="headings", selectmode="browse") + + for col in columns: + mapping_tree.heading(col, text=col) + mapping_tree.column(col, width=100) + + mapping_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + + # 添加滚动条 + scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=mapping_tree.yview) + scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + mapping_tree.configure(yscrollcommand=scrollbar.set) + + # ========= 特殊处理选项卡 ========= + # 顶部输入区域 + special_input_frame = tk.Frame(tab2) + special_input_frame.pack(fill=tk.X, padx=5, pady=5) + + tk.Label(special_input_frame, text="条码:").grid(row=0, column=0, padx=5, pady=5) + special_barcode_entry = tk.Entry(special_input_frame, width=20) + special_barcode_entry.grid(row=0, column=1, padx=5, pady=5) + + tk.Label(special_input_frame, text="乘数:").grid(row=1, column=0, padx=5, pady=5) + multiplier_entry = tk.Entry(special_input_frame, width=10) + multiplier_entry.grid(row=1, column=1, padx=5, pady=5) + + tk.Label(special_input_frame, text="目标单位:").grid(row=1, column=2, padx=5, pady=5) + unit_entry = tk.Entry(special_input_frame, width=10) + unit_entry.grid(row=1, column=3, padx=5, pady=5) + + tk.Label(special_input_frame, text="固定单价:").grid(row=2, column=0, padx=5, pady=5) + price_entry = tk.Entry(special_input_frame, width=10) + price_entry.grid(row=2, column=1, padx=5, pady=5) + + tk.Label(special_input_frame, text="规格:").grid(row=2, column=2, padx=5, pady=5) + spec_entry = tk.Entry(special_input_frame, width=10) + spec_entry.grid(row=2, column=3, padx=5, pady=5) + + tk.Label(special_input_frame, text="描述:").grid(row=3, column=0, padx=5, pady=5) + desc_entry = tk.Entry(special_input_frame, width=40) + desc_entry.grid(row=3, column=1, columnspan=3, padx=5, pady=5) + + # 特殊处理列表显示区域 + special_list_frame = tk.Frame(tab2) + special_list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) + + special_columns = ("条码", "乘数", "目标单位", "固定单价", "规格", "描述") + special_tree = ttk.Treeview(special_list_frame, columns=special_columns, show="headings", selectmode="browse") + + for col in special_columns: + special_tree.heading(col, text=col) + special_tree.column(col, width=80) + + special_tree.column("描述", width=200) + special_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + + # 添加滚动条 + special_scrollbar = ttk.Scrollbar(special_list_frame, orient=tk.VERTICAL, command=special_tree.yview) + special_scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + special_tree.configure(yscrollcommand=special_scrollbar.set) + + # 存储特殊处理列表的变量 + special_list = [] + + # 按钮区域 + def add_mapping(): + source = source_entry.get().strip() + target = target_entry.get().strip() + + if not source or not target: + messagebox.showwarning("输入错误", "源条码和目标条码不能为空") + return + + # 检查是否已存在 + for item in mapping_list: + if item[0] == source: + messagebox.showwarning("重复条码", f"条码 {source} 已存在映射") + return + + # 添加到列表 + mapping_list.append((source, target)) + mapping_tree.insert("", tk.END, values=(source, target)) + + # 清空输入框 + source_entry.delete(0, tk.END) + target_entry.delete(0, tk.END) + + def remove_mapping(): + selected = mapping_tree.selection() + if not selected: + messagebox.showwarning("未选择", "请先选择要删除的条目") + return + + # 获取选中项的索引 + item = mapping_tree.item(selected[0]) + source = item['values'][0] + + # 从列表中移除 + for i, (s, _) in enumerate(mapping_list): + if s == source: + mapping_list.pop(i) + break + + # 从树中移除 + mapping_tree.delete(selected[0]) + + def add_special(): + barcode = special_barcode_entry.get().strip() + multiplier = multiplier_entry.get().strip() + unit = unit_entry.get().strip() + price = price_entry.get().strip() + spec = spec_entry.get().strip() + desc = desc_entry.get().strip() + + if not barcode: + messagebox.showwarning("输入错误", "条码不能为空") + return + + # 检查是否已存在 + for item in special_list: + if item[0] == barcode: + messagebox.showwarning("重复条码", f"条码 {barcode} 已存在特殊处理") + return + + # 添加到列表 + special_list.append((barcode, multiplier, unit, price, spec, desc)) + special_tree.insert("", tk.END, values=(barcode, multiplier, unit, price, spec, desc)) + + # 清空输入框 + special_barcode_entry.delete(0, tk.END) + multiplier_entry.delete(0, tk.END) + unit_entry.delete(0, tk.END) + price_entry.delete(0, tk.END) + spec_entry.delete(0, tk.END) + desc_entry.delete(0, tk.END) + + def remove_special(): + selected = special_tree.selection() + if not selected: + messagebox.showwarning("未选择", "请先选择要删除的条目") + return + + # 获取选中项的索引 + item = special_tree.item(selected[0]) + barcode = item['values'][0] + + # 从列表中移除 + for i, (b, _, _, _, _, _) in enumerate(special_list): + if b == barcode: + special_list.pop(i) + break + + # 从树中移除 + special_tree.delete(selected[0]) + + # 条码映射按钮 + btn_frame = tk.Frame(tab1) + btn_frame.pack(fill=tk.X, padx=5, pady=5) + + add_btn = tk.Button(btn_frame, text="添加映射", command=add_mapping) + add_btn.pack(side=tk.LEFT, padx=5) + + remove_btn = tk.Button(btn_frame, text="删除映射", command=remove_mapping) + remove_btn.pack(side=tk.LEFT, padx=5) + + # 特殊处理按钮 + special_btn_frame = tk.Frame(tab2) + special_btn_frame.pack(fill=tk.X, padx=5, pady=5) + + add_special_btn = tk.Button(special_btn_frame, text="添加特殊处理", command=add_special) + add_special_btn.pack(side=tk.LEFT, padx=5) + + remove_special_btn = tk.Button(special_btn_frame, text="删除特殊处理", command=remove_special) + remove_special_btn.pack(side=tk.LEFT, padx=5) + + # 添加映射到特殊处理的功能 + def add_mapping_to_special(): + selected = special_tree.selection() + if not selected: + messagebox.showwarning("未选择", "请先选择要添加映射的特殊处理条目") + return + + # 获取选中项 + item = special_tree.item(selected[0]) + barcode = item['values'][0] + + # 弹出对话框输入映射目标 + target_barcode = tk.simpledialog.askstring("添加映射", f"为条码 {barcode} 添加映射目标条码:") + if not target_barcode: + return + + # 更新特殊处理列表中的项 + for i, (b, mult, unit, price, spec, desc) in enumerate(special_list): + if b == barcode: + # 如果描述中已有映射信息,更新它 + if "映射到:" in desc: + desc = desc.split("映射到:")[0].strip() + + # 添加映射信息到描述 + new_desc = f"{desc} 映射到: {target_barcode}" + special_list[i] = (b, mult, unit, price, spec, new_desc) + + # 更新显示 + special_tree.item(selected[0], values=(b, mult, unit, price, spec, new_desc)) + + # 标记该条码有映射 + special_tree.item(selected[0], tags=("mapped",)) + special_tree.tag_configure("mapped", foreground="blue") + + break + + map_special_btn = tk.Button(special_btn_frame, text="添加条码映射", command=add_mapping_to_special) + map_special_btn.pack(side=tk.LEFT, padx=5) + + # 底部按钮区域 + bottom_frame = tk.Frame(dialog) + bottom_frame.pack(fill=tk.X, padx=10, pady=10) + + def save_mappings(): + # 构建保存数据 + mappings = {} + + # 添加条码映射 + for source, target in mapping_list: + mappings[source] = { + 'map_to': target, + 'description': f'条码映射:{source} -> {target}' + } + + # 添加特殊处理 + for barcode, multiplier, unit, price, spec, desc in special_list: + # 检查该条码是否已存在 + if barcode not in mappings: + mappings[barcode] = {} + + if multiplier: + try: + # 安全地转换multiplier为数字 + if isinstance(multiplier, str): + if '.' in multiplier: + mappings[barcode]['multiplier'] = float(multiplier) + else: + mappings[barcode]['multiplier'] = int(multiplier) + else: + # 已经是数字类型 + mappings[barcode]['multiplier'] = multiplier + except ValueError: + # 如果转换失败,保持原始字符串 + mappings[barcode]['multiplier'] = multiplier + + if unit: + mappings[barcode]['target_unit'] = unit + + if price: + try: + # 安全地转换price为浮点数 + mappings[barcode]['fixed_price'] = float(price) + except ValueError: + # 如果转换失败,保持原始字符串 + mappings[barcode]['fixed_price'] = price + + if spec: + mappings[barcode]['specification'] = spec + + # 检查描述中是否包含映射信息 + if desc and "映射到:" in desc: + parts = desc.split("映射到:") + base_desc = parts[0].strip() + target_barcode = parts[1].strip() + + # 设置基本描述 + if base_desc: + mappings[barcode]['description'] = base_desc + + # 设置映射目标 + mappings[barcode]['map_to'] = target_barcode + elif desc: + mappings[barcode]['description'] = desc + + # 调用保存回调 + if on_save: + on_save(mappings) + + messagebox.showinfo("保存成功", f"已保存{len(mapping_list)}个条码映射和{len(special_list)}个特殊处理规则") + dialog.destroy() + + def cancel(): + dialog.destroy() + + save_btn = tk.Button(bottom_frame, text="保存", command=save_mappings) + save_btn.pack(side=tk.RIGHT, padx=5) + + cancel_btn = tk.Button(bottom_frame, text="取消", command=cancel) + cancel_btn.pack(side=tk.RIGHT, padx=5) + + # ---- 云端同步按钮 ---- + def _build_current_mappings(): + """从弹窗当前数据构建 mappings dict(与 save_mappings 逻辑相同)""" + mappings = {} + for source, target in mapping_list: + mappings[source] = { + 'map_to': target, + 'description': f'条码映射:{source} -> {target}' + } + for barcode, multiplier, unit, price, spec, desc in special_list: + if barcode not in mappings: + mappings[barcode] = {} + if multiplier: + try: + if isinstance(multiplier, str): + mappings[barcode]['multiplier'] = float(multiplier) if '.' in multiplier else int(multiplier) + else: + mappings[barcode]['multiplier'] = multiplier + except ValueError: + mappings[barcode]['multiplier'] = multiplier + if unit: + mappings[barcode]['target_unit'] = unit + if price: + try: + mappings[barcode]['fixed_price'] = float(price) + except ValueError: + mappings[barcode]['fixed_price'] = price + if spec: + mappings[barcode]['specification'] = spec + if desc and "映射到:" in desc: + parts = desc.split("映射到:") + base_desc = parts[0].strip() + target_barcode = parts[1].strip() + if base_desc: + mappings[barcode]['description'] = base_desc + mappings[barcode]['map_to'] = target_barcode + elif desc: + mappings[barcode]['description'] = desc + return mappings + + def _get_sync(): + """获取 GiteaSync 实例,配置不完整时提示用户""" + sync = GiteaSync.from_config(ConfigManager()) + if sync is None: + messagebox.showwarning("云端同步", "请先在「系统设置」中配置 Gitea 云端同步参数(token)") + return sync + + def _refresh_trees(new_mappings): + """用新数据刷新两个 Treeview""" + # 清空 + for item in mapping_tree.get_children(): + mapping_tree.delete(item) + mapping_list.clear() + for item in special_tree.get_children(): + special_tree.delete(item) + special_list.clear() + # 重新填充 + if new_mappings: + for barcode, data in new_mappings.items(): + if 'map_to' in data and 'multiplier' not in data: + mapping_list.append((barcode, data['map_to'])) + mapping_tree.insert('', 'end', values=(barcode, data['map_to'])) + else: + mult = data.get('multiplier', '') + unit = data.get('target_unit', '') + price = data.get('fixed_price', '') + spec = data.get('specification', '') + desc = data.get('description', '') + if 'map_to' in data: + desc = f"{desc} 映射到: {data['map_to']}" if desc else f"映射到: {data['map_to']}" + special_list.append((barcode, mult, unit, price, spec, desc)) + tags = ("mapped",) if 'map_to' in data else () + special_tree.insert('', 'end', values=(barcode, mult, unit, price, spec, desc), tags=tags) + if any('map_to' in d for d in new_mappings.values()): + special_tree.tag_configure("mapped", foreground="blue") + + def push_to_cloud(): + sync = _get_sync() + if not sync: + return + mappings = _build_current_mappings() + if not mappings: + messagebox.showwarning("同步到云端", "当前没有映射数据可同步") + return + # 先获取当前 sha(如果文件已存在) + sha = None + existing = sync.pull_file("barcode_mappings.json") + if existing: + sha = existing[1] + new_sha = sync.push_json( + "barcode_mappings.json", + mappings, + f"同步条码映射 ({len(mappings)} 条)", + sha=sha, + ) + if new_sha: + messagebox.showinfo("同步成功", f"已推送 {len(mappings)} 条映射到云端") + else: + messagebox.showerror("同步失败", "推送到云端失败,请检查网络和 Gitea 配置") + + def pull_from_cloud(): + sync = _get_sync() + if not sync: + return + result = sync.pull_json("barcode_mappings.json") + if result is None: + messagebox.showwarning("拉取失败", "云端没有找到条码映射文件,或网络错误") + return + data, sha = result + if not isinstance(data, dict) or len(data) == 0: + messagebox.showwarning("拉取失败", "云端数据格式异常") + return + # 同时保存到本地 + from app.core.excel.converter import UnitConverter + uc = UnitConverter() + uc.update_barcode_mappings(data) + # 刷新弹窗 + _refresh_trees(data) + messagebox.showinfo("拉取成功", f"已从云端拉取 {len(data)} 条映射,本地已同步更新") + + sync_frame = tk.Frame(bottom_frame) + sync_frame.pack(side=tk.LEFT, padx=5) + + push_btn = tk.Button(sync_frame, text="同步到云端", command=push_to_cloud, fg="white", bg="#4a90d9") + push_btn.pack(side=tk.LEFT, padx=3) + + pull_btn = tk.Button(sync_frame, text="从云端拉取", command=pull_from_cloud, fg="white", bg="#5cb85c") + pull_btn.pack(side=tk.LEFT, padx=3) + + # 导入当前映射数据 + if current_mappings: + for barcode, data in current_mappings.items(): + if 'map_to' in data: + # 这是条码映射 + mapping_list.append((barcode, data['map_to'])) + mapping_tree.insert("", tk.END, values=(barcode, data['map_to'])) + else: + # 这是特殊处理 + multiplier = data.get('multiplier', '') + unit = data.get('target_unit', '') + price = data.get('fixed_price', '') + spec = data.get('specification', '') + desc = data.get('description', '') + + special_list.append((barcode, multiplier, unit, price, spec, desc)) + special_tree.insert("", tk.END, values=(barcode, multiplier, unit, price, spec, desc)) + + # 确保窗口显示在最前 + dialog.transient(parent) + dialog.grab_set() + + return dialog + +def show_barcode_mapping_dialog(*args, **kwargs): + """ + 显示条码映射编辑弹窗 + + 参数与create_barcode_mapping_dialog相同 + + Returns: + dialog: 对话框对象 + """ + # 确保已导入ttk + import tkinter.ttk as ttk + return create_barcode_mapping_dialog(*args, **kwargs) + +def show_config_dialog(parent, config_manager, on_save=None): + """显示配置设置对话框""" + dialog = tk.Toplevel(parent) + dialog.title("系统配置") + dialog.geometry("600x500") + dialog.resizable(False, False) + + # 使窗口居中 + dialog.update_idletasks() + width = dialog.winfo_width() + height = dialog.winfo_height() + x = (dialog.winfo_screenwidth() // 2) - (width // 2) + y = (dialog.winfo_screenheight() // 2) - (height // 2) + dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y)) + + # 创建主框架 + main_frame = ttk.Frame(dialog, padding="10") + main_frame.pack(fill=tk.BOTH, expand=True) + + # 创建选项卡 + notebook = ttk.Notebook(main_frame) + notebook.pack(fill=tk.BOTH, expand=True, pady=5) + + # 创建各个配置页面的框架 + api_frame = ttk.Frame(notebook, padding="10") + paths_frame = ttk.Frame(notebook, padding="10") + performance_frame = ttk.Frame(notebook, padding="10") + file_frame = ttk.Frame(notebook, padding="10") + + # 添加选项卡 + notebook.add(api_frame, text="API设置") + notebook.add(paths_frame, text="路径设置") + notebook.add(performance_frame, text="性能设置") + notebook.add(file_frame, text="文件设置") + + # 存储所有输入框的引用 + entries = {} + + # API设置 + ttk.Label(api_frame, text="百度OCR API设置", font=("Arial", 12, "bold")).pack(anchor=tk.W, pady=5) + + # API Key + ttk.Label(api_frame, text="API Key:").pack(anchor=tk.W, pady=2) + api_key_entry = ttk.Entry(api_frame, width=50) + api_key_entry.pack(fill=tk.X, pady=2) + api_key_entry.insert(0, config_manager.get('API', 'api_key', '')) + entries[('API', 'api_key')] = api_key_entry + + # Secret Key + ttk.Label(api_frame, text="Secret Key:").pack(anchor=tk.W, pady=2) + secret_key_entry = ttk.Entry(api_frame, width=50) + secret_key_entry.pack(fill=tk.X, pady=2) + secret_key_entry.insert(0, config_manager.get('API', 'secret_key', '')) + entries[('API', 'secret_key')] = secret_key_entry + + # 超时设置 + ttk.Label(api_frame, text="超时时间(秒):").pack(anchor=tk.W, pady=2) + timeout_entry = ttk.Entry(api_frame, width=10) + timeout_entry.pack(anchor=tk.W, pady=2) + timeout_entry.insert(0, config_manager.get('API', 'timeout', '30')) + entries[('API', 'timeout')] = timeout_entry + + # 路径设置 + ttk.Label(paths_frame, text="系统路径设置", font=("Arial", 12, "bold")).pack(anchor=tk.W, pady=5) + + # 输入目录 + ttk.Label(paths_frame, text="输入目录:").pack(anchor=tk.W, pady=2) + input_dir_entry = ttk.Entry(paths_frame, width=50) + input_dir_entry.pack(fill=tk.X, pady=2) + input_dir_entry.insert(0, config_manager.get('Paths', 'input_folder', 'data/input')) + entries[('Paths', 'input_folder')] = input_dir_entry + + # 输出目录 + ttk.Label(paths_frame, text="输出目录:").pack(anchor=tk.W, pady=2) + output_dir_entry = ttk.Entry(paths_frame, width=50) + output_dir_entry.pack(fill=tk.X, pady=2) + output_dir_entry.insert(0, config_manager.get('Paths', 'output_folder', 'data/output')) + entries[('Paths', 'output_folder')] = output_dir_entry + + # 性能设置 + ttk.Label(performance_frame, text="性能设置", font=("Arial", 12, "bold")).pack(anchor=tk.W, pady=5) + + # 最大工作线程数 + ttk.Label(performance_frame, text="最大工作线程数:").pack(anchor=tk.W, pady=2) + max_workers_entry = ttk.Entry(performance_frame, width=10) + max_workers_entry.pack(anchor=tk.W, pady=2) + max_workers_entry.insert(0, config_manager.get('Performance', 'max_workers', '4')) + entries[('Performance', 'max_workers')] = max_workers_entry + + # 批处理大小 + ttk.Label(performance_frame, text="批处理大小:").pack(anchor=tk.W, pady=2) + batch_size_entry = ttk.Entry(performance_frame, width=10) + batch_size_entry.pack(anchor=tk.W, pady=2) + batch_size_entry.insert(0, config_manager.get('Performance', 'batch_size', '5')) + entries[('Performance', 'batch_size')] = batch_size_entry + + # 文件设置 + ttk.Label(file_frame, text="文件设置", font=("Arial", 12, "bold")).pack(anchor=tk.W, pady=5) + + # 允许的文件扩展名 + ttk.Label(file_frame, text="允许的文件扩展名:").pack(anchor=tk.W, pady=2) + extensions_entry = ttk.Entry(file_frame, width=50) + extensions_entry.pack(fill=tk.X, pady=2) + extensions_entry.insert(0, config_manager.get('File', 'allowed_extensions', '.jpg,.jpeg,.png,.bmp')) + entries[('File', 'allowed_extensions')] = extensions_entry + + # 最大文件大小 + ttk.Label(file_frame, text="最大文件大小(MB):").pack(anchor=tk.W, pady=2) + max_size_entry = ttk.Entry(file_frame, width=10) + max_size_entry.pack(anchor=tk.W, pady=2) + max_size_entry.insert(0, config_manager.get('File', 'max_file_size_mb', '4')) + entries[('File', 'max_file_size_mb')] = max_size_entry + + def save_config(): + """保存配置""" + try: + # 收集所有输入框的值 + for (section, option), entry in entries.items(): + value = entry.get().strip() + config_manager.update(section, option, value) + + # 保存配置 + config_manager.save_config() + + if on_save: + on_save() + + messagebox.showinfo("成功", "配置已保存") + dialog.destroy() + except Exception as e: + messagebox.showerror("错误", f"保存配置时出错: {str(e)}") + + # 按钮框架 + button_frame = ttk.Frame(main_frame) + button_frame.pack(fill=tk.X, pady=10) + + # 保存按钮 + ttk.Button(button_frame, text="保存", command=save_config).pack(side=tk.RIGHT, padx=5) + + # 取消按钮 + ttk.Button(button_frame, text="取消", command=dialog.destroy).pack(side=tk.RIGHT, padx=5) + + # 设置模态 + dialog.transient(parent) + dialog.grab_set() + + +# ────────────────────────────────────────────────────────────── +# 云端同步管理对话框 +# ────────────────────────────────────────────────────────────── + +SYNC_FILES = [ + { + "name": "条码映射", + "remote": "barcode_mappings.json", + "local": "config/barcode_mappings.json", + "type": "json", + }, + { + "name": "供应商配置", + "remote": "suppliers_config.json", + "local": "config/suppliers_config.json", + "type": "json", + }, + { + "name": "商品资料", + "remote": "templates/商品资料.xlsx", + "local": "templates/商品资料.xlsx", + "type": "binary", + }, + { + "name": "采购单模板", + "remote": "templates/银豹-采购单模板.xls", + "local": "templates/银豹-采购单模板.xls", + "type": "binary", + }, +] + + +def _format_size(path: str) -> str: + try: + size = os.path.getsize(path) + if size < 1024 * 1024: + return f"{size / 1024:.1f} KB" + return f"{size / (1024 * 1024):.1f} MB" + except OSError: + return "—" + + +def show_cloud_sync_dialog(parent=None): + """统一云端同步管理对话框""" + + sync = GiteaSync.from_config(ConfigManager()) + if sync is None: + messagebox.showwarning( + "配置不完整", + "请先在「系统设置」中配置 Gitea 地址和 Access Token", + ) + return + + dlg = tk.Toplevel(parent) + dlg.title("云端同步管理") + dlg.geometry("620x440") + dlg.resizable(False, False) + + # 居中 + dlg.update_idletasks() + x = (dlg.winfo_screenwidth() - 620) // 2 + y = (dlg.winfo_screenheight() - 440) // 2 + dlg.geometry(f"620x440+{x}+{y}") + + # ── Treeview ── + columns = ("name", "local_status", "cloud_status") + tree = ttk.Treeview(dlg, columns=columns, show="headings", height=6) + tree.heading("name", text="文件") + tree.heading("local_status", text="本地状态") + tree.heading("cloud_status", text="云端状态") + tree.column("name", width=140) + tree.column("local_status", width=220) + tree.column("cloud_status", width=220) + tree.pack(fill=tk.BOTH, expand=True, padx=16, pady=(16, 8)) + + # tag 颜色 + tree.tag_configure("synced", foreground="#2e7d32") + tree.tag_configure("cloud_only", foreground="#e65100") + tree.tag_configure("local_only", foreground="#1565c0") + tree.tag_configure("missing", foreground="#999999") + + # 用 iid = remote_path 标识每行 + cloud_sha_cache: dict = {} # remote_path -> sha + + def _load_local_status(): + """仅加载本地状态,不发网络请求""" + for item in tree.get_children(): + tree.delete(item) + for entry in SYNC_FILES: + local = entry["local"] + if os.path.exists(local): + if entry["type"] == "json": + try: + with open(local, "r", encoding="utf-8") as f: + data = json.load(f) + if isinstance(data, dict): + local_text = f"{len(data)} 项" + elif isinstance(data, list): + local_text = f"{len(data)} 条记录" + else: + local_text = "已存在" + except Exception: + local_text = "已存在(解析异常)" + else: + local_text = _format_size(local) + tag = "local_only" + else: + local_text = "不存在" + tag = "missing" + tree.insert( + "", tk.END, + iid=entry["remote"], + values=(entry["name"], local_text, "点「刷新状态」检查"), + tags=(tag,), + ) + + def refresh_status(): + """刷新每行的本地/云端状态""" + cloud_sha_cache.clear() + for item in tree.get_children(): + tree.delete(item) + + for entry in SYNC_FILES: + remote = entry["remote"] + local = entry["local"] + + # 本地状态 + if os.path.exists(local): + if entry["type"] == "json": + try: + with open(local, "r", encoding="utf-8") as f: + data = json.load(f) + if isinstance(data, dict): + local_text = f"{len(data)} 项" + elif isinstance(data, list): + local_text = f"{len(data)} 条记录" + else: + local_text = "已存在" + except Exception: + local_text = "已存在(解析异常)" + else: + local_text = _format_size(local) + else: + local_text = "不存在" + + # 云端状态 — 网络请求,可能慢 + sha = sync.file_exists(remote) + if sha: + cloud_sha_cache[remote] = sha + cloud_text = "已存在" + else: + cloud_text = "未上传" + + # tag + local_ok = os.path.exists(local) + cloud_ok = sha is not None + if local_ok and cloud_ok: + tag = "synced" + elif cloud_ok and not local_ok: + tag = "cloud_only" + elif local_ok and not cloud_ok: + tag = "local_only" + else: + tag = "missing" + + tree.insert( + "", tk.END, + iid=remote, + values=(entry["name"], local_text, cloud_text), + tags=(tag,), + ) + + # ── 操作函数 ── + def _get_selected_entries(): + """获取选中的文件条目列表""" + selected = tree.selection() + if not selected: + messagebox.showinfo("提示", "请先选中要操作的文件") + return [] + return [e for e in SYNC_FILES if e["remote"] in selected] + + def push_selected(): + entries = _get_selected_entries() + if not entries: + return + ok, fail = 0, 0 + for entry in entries: + local, remote = entry["local"], entry["remote"] + if not os.path.exists(local): + messagebox.showwarning("跳过", f"本地文件不存在: {local}") + fail += 1 + continue + + if entry["type"] == "json": + try: + with open(local, "r", encoding="utf-8") as f: + data = json.load(f) + sha = cloud_sha_cache.get(remote) + result = sync.push_json(remote, data, f"同步 {entry['name']}", sha=sha) + except Exception as e: + messagebox.showerror("推送失败", f"{entry['name']}: {e}") + fail += 1 + continue + else: + result = sync.push_binary(remote, local, f"同步 {entry['name']}") + + if result: + ok += 1 + else: + fail += 1 + + if ok: + messagebox.showinfo("推送完成", f"成功 {ok} 个" + (f",失败 {fail} 个" if fail else "")) + refresh_status() + + def pull_selected(): + entries = _get_selected_entries() + if not entries: + return + ok, fail = 0, 0 + for entry in entries: + remote, local = entry["remote"], entry["local"] + + if entry["type"] == "json": + result = sync.pull_json(remote) + if result is None: + messagebox.showwarning("拉取失败", f"云端文件不存在: {entry['name']}") + fail += 1 + continue + content, sha = result + # 写入本地 + os.makedirs(os.path.dirname(local) or ".", exist_ok=True) + with open(local, "w", encoding="utf-8") as f: + json.dump(content, f, ensure_ascii=False, indent=2) + # 特殊后处理 + _post_pull(entry, content) + else: + result = sync.pull_file(remote) + if result is None: + messagebox.showwarning("拉取失败", f"云端文件不存在: {entry['name']}") + fail += 1 + continue + content, sha = result + os.makedirs(os.path.dirname(local) or ".", exist_ok=True) + with open(local, "wb") as f: + f.write(content) + + ok += 1 + + if ok: + messagebox.showinfo("拉取完成", f"成功 {ok} 个" + (f",失败 {fail} 个" if fail else "")) + refresh_status() + + def _post_pull(entry, data): + """拉取 JSON 文件后的特殊处理""" + if entry["remote"] == "barcode_mappings.json": + try: + from app.core.excel.converter import UnitConverter + UnitConverter().update_barcode_mappings(data) + except Exception: + pass + elif entry["remote"] == "suppliers_config.json": + try: + from app.services.processor_service import ProcessorService + ProcessorService(ConfigManager()).reload_processors() + except Exception: + pass + + def push_all(): + ok, fail = 0, 0 + for entry in SYNC_FILES: + local, remote = entry["local"], entry["remote"] + if not os.path.exists(local): + fail += 1 + continue + if entry["type"] == "json": + try: + with open(local, "r", encoding="utf-8") as f: + data = json.load(f) + sha = cloud_sha_cache.get(remote) + result = sync.push_json(remote, data, f"批量同步 {entry['name']}", sha=sha) + except Exception: + fail += 1 + continue + else: + result = sync.push_binary(remote, local, f"批量同步 {entry['name']}") + if result: + ok += 1 + else: + fail += 1 + messagebox.showinfo("批量推送完成", f"成功 {ok} 个,失败 {fail} 个") + refresh_status() + + def pull_all(): + ok, fail = 0, 0 + for entry in SYNC_FILES: + remote, local = entry["remote"], entry["local"] + if entry["type"] == "json": + result = sync.pull_json(remote) + if result is None: + fail += 1 + continue + content, sha = result + os.makedirs(os.path.dirname(local) or ".", exist_ok=True) + with open(local, "w", encoding="utf-8") as f: + json.dump(content, f, ensure_ascii=False, indent=2) + _post_pull(entry, content) + else: + result = sync.pull_file(remote) + if result is None: + fail += 1 + continue + content, sha = result + os.makedirs(os.path.dirname(local) or ".", exist_ok=True) + with open(local, "wb") as f: + f.write(content) + ok += 1 + messagebox.showinfo("批量拉取完成", f"成功 {ok} 个,失败 {fail} 个") + refresh_status() + + # ── 按钮区域 ── + btn_frame = ttk.Frame(dlg) + btn_frame.pack(fill=tk.X, padx=16, pady=(4, 16)) + + # 左侧:批量操作 + ttk.Button(btn_frame, text="全部推送到云端", command=push_all).pack(side=tk.LEFT, padx=4) + ttk.Button(btn_frame, text="全部从云端拉取", command=pull_all).pack(side=tk.LEFT, padx=4) + + # 右侧:选中操作 + 刷新 + 关闭 + ttk.Button(btn_frame, text="关闭", command=dlg.destroy).pack(side=tk.RIGHT, padx=4) + ttk.Button(btn_frame, text="刷新状态", command=refresh_status).pack(side=tk.RIGHT, padx=4) + tk.Button(btn_frame, text="推送到云端", command=push_selected, fg="white", bg="#4a90d9").pack(side=tk.RIGHT, padx=4) + tk.Button(btn_frame, text="从云端拉取", command=pull_selected, fg="white", bg="#5cb85c").pack(side=tk.RIGHT, padx=4) + + # 仅显示本地状态,云端状态需手动点"刷新状态" + _load_local_status() + + dlg.transient(parent) + dlg.grab_set() \ No newline at end of file diff --git a/app/core/utils/file_utils.py b/app/core/utils/file_utils.py new file mode 100644 index 0000000..5c91be3 --- /dev/null +++ b/app/core/utils/file_utils.py @@ -0,0 +1,286 @@ +""" +文件操作工具模块 +-------------- +提供文件处理、查找和管理功能。 +""" + +import os +import sys +import shutil +import json +from datetime import datetime +from pathlib import Path +from typing import Dict, List, Optional, Union, Any + +from .log_utils import get_logger + +logger = get_logger(__name__) + +def ensure_dir(directory: str) -> bool: + """ + 确保目录存在,如果不存在则创建 + + Args: + directory: 目录路径 + + Returns: + 是否成功创建或目录已存在 + """ + try: + os.makedirs(directory, exist_ok=True) + return True + except Exception as e: + logger.error(f"创建目录失败: {directory}, 错误: {e}") + return False + +def get_file_extension(file_path: str) -> str: + """ + 获取文件扩展名(小写) + + Args: + file_path: 文件路径 + + Returns: + 文件扩展名,包含点(例如 .jpg) + """ + return os.path.splitext(file_path)[1].lower() + +def is_valid_extension(file_path: str, allowed_extensions: List[str]) -> bool: + """ + 检查文件扩展名是否在允许的列表中 + + Args: + file_path: 文件路径 + allowed_extensions: 允许的扩展名列表(例如 ['.jpg', '.png']) + + Returns: + 文件扩展名是否有效 + """ + ext = get_file_extension(file_path) + return ext in allowed_extensions + +def get_files_by_extensions(directory: str, extensions: List[str], exclude_patterns: List[str] = None) -> List[str]: + """ + 获取指定目录下所有符合扩展名的文件路径 + + Args: + directory: 目录路径 + extensions: 扩展名列表(例如 ['.jpg', '.png']) + exclude_patterns: 排除的文件名模式(例如 ['~$', '.tmp']) + + Returns: + 文件路径列表 + """ + if exclude_patterns is None: + exclude_patterns = ['~$', '.tmp'] + + files = [] + for file in os.listdir(directory): + file_path = os.path.join(directory, file) + + # 检查是否是文件 + if not os.path.isfile(file_path): + continue + + # 检查扩展名 + if not is_valid_extension(file_path, extensions): + continue + + # 检查排除模式 + exclude = False + for pattern in exclude_patterns: + if pattern in file: + exclude = True + break + + if not exclude: + files.append(file_path) + + return files + +def get_latest_file(directory: str, pattern: str = "", extensions: List[str] = None) -> Optional[str]: + """ + 获取指定目录下最新的文件 + + Args: + directory: 目录路径 + pattern: 文件名包含的字符串模式 + extensions: 限制的文件扩展名列表 + + Returns: + 最新文件的路径,如果没有找到则返回None + """ + if not os.path.exists(directory): + logger.warning(f"目录不存在: {directory}") + return None + + files = [] + for file in os.listdir(directory): + # 检查模式和扩展名 + if (pattern and pattern not in file) or \ + (extensions and not is_valid_extension(file, extensions)): + continue + + file_path = os.path.join(directory, file) + if os.path.isfile(file_path): + files.append((file_path, os.path.getmtime(file_path))) + + if not files: + logger.warning(f"未在目录 {directory} 中找到符合条件的文件") + return None + + # 按修改时间排序,返回最新的 + sorted_files = sorted(files, key=lambda x: x[1], reverse=True) + return sorted_files[0][0] + +def generate_timestamp_filename(original_path: str) -> str: + """ + 生成基于时间戳的文件名 + + Args: + original_path: 原始文件路径 + + Returns: + 带时间戳的新文件路径 + """ + dir_path = os.path.dirname(original_path) + ext = os.path.splitext(original_path)[1] + timestamp = datetime.now().strftime("%Y%m%d%H%M%S") + return os.path.join(dir_path, f"{timestamp}{ext}") + +def rename_file(source_path: str, target_path: str) -> bool: + """ + 重命名文件 + + Args: + source_path: 源文件路径 + target_path: 目标文件路径 + + Returns: + 是否成功重命名 + """ + try: + # 确保目标目录存在 + target_dir = os.path.dirname(target_path) + ensure_dir(target_dir) + + # 重命名文件 + os.rename(source_path, target_path) + logger.info(f"文件已重命名: {os.path.basename(source_path)} -> {os.path.basename(target_path)}") + return True + except Exception as e: + logger.error(f"重命名文件失败: {e}") + return False + +def load_json(file_path: str, default: Any = None) -> Any: + """ + 加载JSON文件 + + Args: + file_path: JSON文件路径 + default: 如果文件不存在或加载失败时返回的默认值 + + Returns: + JSON内容,或者默认值 + """ + if not os.path.exists(file_path): + return default + + try: + with open(file_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + logger.error(f"加载JSON文件失败: {file_path}, 错误: {e}") + return default + +def save_json(data: Any, file_path: str, ensure_ascii: bool = False, indent: int = 2) -> bool: + """ + 保存数据到JSON文件 + + Args: + data: 要保存的数据 + file_path: JSON文件路径 + ensure_ascii: 是否确保ASCII编码 + indent: 缩进空格数 + + Returns: + 是否成功保存 + """ + try: + # 确保目录存在 + directory = os.path.dirname(file_path) + ensure_dir(directory) + + with open(file_path, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=ensure_ascii, indent=indent) + logger.debug(f"JSON数据已保存到: {file_path}") + return True + except Exception as e: + logger.error(f"保存JSON文件失败: {file_path}, 错误: {e}") + return False + +def smart_read_excel(file_path: Union[str, Path], **kwargs) -> Any: + """ + 智能读取 Excel 文件,自动选择引擎并处理常见错误 + + Args: + file_path: Excel 文件路径 + **kwargs: 传递给 pd.read_excel 的额外参数 + + Returns: + pandas.DataFrame 对象 + """ + import pandas as pd + + path_str = str(file_path) + ext = os.path.splitext(path_str)[1].lower() + + # 自动选择引擎 + if ext == '.xlsx': + kwargs.setdefault('engine', 'openpyxl') + elif ext == '.xls': + kwargs.setdefault('engine', 'xlrd') + + try: + return pd.read_excel(path_str, **kwargs) + except Exception as e: + logger.error(f"读取 Excel 文件失败: {path_str}, 错误: {e}") + raise + +def get_file_size(file_path: str) -> int: + """ + 获取文件大小(字节) + + Args: + file_path: 文件路径 + + Returns: + 文件大小(字节) + """ + try: + return os.path.getsize(file_path) + except Exception as e: + logger.error(f"获取文件大小失败: {file_path}, 错误: {e}") + return 0 + +def is_file_size_valid(file_path: str, max_size_mb: float) -> bool: + """ + 检查文件大小是否在允许范围内 + + Args: + file_path: 文件路径 + max_size_mb: 最大允许大小(MB) + + Returns: + 文件大小是否有效 + """ + size_bytes = get_file_size(file_path) + max_size_bytes = max_size_mb * 1024 * 1024 + return size_bytes <= max_size_bytes + + +def format_file_size(size_bytes: int) -> str: + """将字节数格式化为可读的文件大小字符串(KB/MB)""" + if size_bytes < 1024 * 1024: + return f"{size_bytes / 1024:.1f} KB" + return f"{size_bytes / (1024 * 1024):.1f} MB" \ No newline at end of file diff --git a/app/core/utils/log_utils.py b/app/core/utils/log_utils.py new file mode 100644 index 0000000..84bb617 --- /dev/null +++ b/app/core/utils/log_utils.py @@ -0,0 +1,180 @@ +""" +日志工具模块 +---------- +提供统一的日志配置和管理功能。 +""" + +import os +import sys +import logging +from logging.handlers import RotatingFileHandler +from datetime import datetime +from pathlib import Path +from typing import Optional, Dict + +# 日志处理器字典,用于跟踪已创建的处理器 +_handlers: Dict[str, logging.Handler] = {} + +def setup_logger(name: str, + log_file: Optional[str] = None, + level=logging.INFO, + console_output: bool = True, + file_output: bool = True, + log_format: str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s') -> logging.Logger: + """ + 配置并返回日志记录器 + + Args: + name: 日志记录器的名称 + log_file: 日志文件路径,如果为None则使用默认路径 + level: 日志级别 + console_output: 是否输出到控制台 + file_output: 是否输出到文件 + log_format: 日志格式 + + Returns: + 配置好的日志记录器 + """ + # 获取或创建日志记录器 + logger = logging.getLogger(name) + + # 如果已经配置过处理器,不重复配置 + if logger.handlers: + return logger + + # 设置日志级别 + logger.setLevel(level) + + # 创建格式化器 + formatter = logging.Formatter(log_format) + + # 如果需要输出到文件 + if file_output: + # 如果没有指定日志文件,使用默认路径 + if log_file is None: + log_dir = os.path.abspath('logs') + # 确保日志目录存在 + os.makedirs(log_dir, exist_ok=True) + log_file = os.path.join(log_dir, f"{name}.log") + + # 创建文件处理器 + try: + # 使用滚动日志,限制单个日志大小与备份数量 + file_handler = RotatingFileHandler(log_file, maxBytes=5 * 1024 * 1024, backupCount=3, encoding='utf-8') + file_handler.setFormatter(formatter) + file_handler.setLevel(level) + logger.addHandler(file_handler) + _handlers[f"{name}_file"] = file_handler + + # 记录活跃标记,避免被日志清理工具删除 + active_marker = os.path.join(os.path.dirname(log_file), f"{name}.active") + with open(active_marker, 'w', encoding='utf-8') as f: + f.write(f"Active since: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + except Exception as e: + print(f"无法创建日志文件处理器: {e}") + + # 如果需要输出到控制台 + if console_output: + # 创建控制台处理器 + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setFormatter(formatter) + console_handler.setLevel(level) + logger.addHandler(console_handler) + _handlers[f"{name}_console"] = console_handler + + return logger + +def get_logger(name: str) -> logging.Logger: + """ + 获取已配置的日志记录器,如果不存在则创建一个新的 + + Args: + name: 日志记录器的名称 + + Returns: + 日志记录器 + """ + logger = logging.getLogger(name) + if not logger.handlers: + return setup_logger(name) + return logger + +def set_log_level(level: str) -> None: + """ + 设置所有日志记录器的级别 + + Args: + level: 日志级别(DEBUG, INFO, WARNING, ERROR, CRITICAL) + """ + level_map = { + 'debug': logging.DEBUG, + 'info': logging.INFO, + 'warning': logging.WARNING, + 'error': logging.ERROR, + 'critical': logging.CRITICAL + } + + # 获取对应的日志级别 + log_level = level_map.get(level.lower(), logging.INFO) + + # 获取所有记录器 + loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict] + + # 设置每个记录器的级别 + for logger in loggers: + logger.setLevel(log_level) + + # 设置根记录器的级别 + logging.getLogger().setLevel(log_level) + + print(f"所有日志记录器级别已设置为: {logging.getLevelName(log_level)}") + +def close_logger(name: str) -> None: + """ + 关闭日志记录器的所有处理器 + + Args: + name: 日志记录器的名称 + """ + logger = logging.getLogger(name) + for handler in logger.handlers[:]: + handler.close() + logger.removeHandler(handler) + + # 清除处理器缓存 + _handlers.pop(f"{name}_file", None) + _handlers.pop(f"{name}_console", None) + +def close_all_loggers() -> None: + """ + 关闭所有日志记录器的处理器 + """ + # 获取所有记录器 + loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict] + + # 关闭每个记录器的处理器 + for logger in loggers: + if hasattr(logger, 'handlers'): + for handler in logger.handlers[:]: + handler.close() + logger.removeHandler(handler) + + # 清空处理器缓存 + _handlers.clear() + + print("所有日志记录器已关闭") + +def cleanup_active_marker(name: str) -> None: + """ + 清理日志活跃标记 + + Args: + name: 日志记录器的名称 + """ + try: + log_dir = os.path.abspath('logs') + active_marker = os.path.join(log_dir, f"{name}.active") + if os.path.exists(active_marker): + os.remove(active_marker) + except Exception as e: + print(f"无法清理日志活跃标记: {e}") diff --git a/app/core/utils/string_utils.py b/app/core/utils/string_utils.py new file mode 100644 index 0000000..7dc66ed --- /dev/null +++ b/app/core/utils/string_utils.py @@ -0,0 +1,279 @@ +""" +字符串处理工具模块 +--------------- +提供字符串处理、正则表达式匹配等功能。 +""" + +import re +from typing import Dict, List, Optional, Tuple, Any + +def clean_string(text: str) -> str: + """ + 清理字符串,移除多余空白 + + Args: + text: 源字符串 + + Returns: + 清理后的字符串 + """ + if not isinstance(text, str): + return "" + + # 移除首尾空白 + text = text.strip() + # 移除多余空白 + text = re.sub(r'\s+', ' ', text) + return text + +def remove_non_digits(text: str) -> str: + """ + 移除字符串中的非数字字符 + + Args: + text: 源字符串 + + Returns: + 只包含数字的字符串 + """ + if not isinstance(text, str): + return "" + + return re.sub(r'\D', '', text) + +def extract_number(text: str) -> Optional[float]: + """ + 从字符串中提取数字 + + Args: + text: 源字符串 + + Returns: + 提取的数字,如果没有则返回None + """ + if not isinstance(text, str): + return None + + # 匹配数字(可以包含小数点和负号) + match = re.search(r'-?\d+(\.\d+)?', text) + if match: + return float(match.group()) + return None + +def extract_unit(text: str, units: List[str] = None) -> Optional[str]: + """ + 从字符串中提取单位 + + Args: + text: 源字符串 + units: 有效单位列表,如果为None则自动识别 + + Returns: + 提取的单位,如果没有则返回None + """ + if not isinstance(text, str): + return None + + # 如果提供了单位列表,检查字符串中是否包含 + if units: + for unit in units: + if unit in text: + return unit + return None + + # 否则,尝试自动识别常见单位 + # 正则表达式:匹配数字后面的非数字部分作为单位 + match = re.search(r'\d+\s*([^\d\s]+)', text) + if match: + return match.group(1) + return None + +def extract_number_and_unit(text: str) -> Tuple[Optional[float], Optional[str]]: + """ + 从字符串中同时提取数字和单位 + + Args: + text: 源字符串 + + Returns: + (数字, 单位)元组,如果没有则对应返回None + """ + if not isinstance(text, str): + return None, None + + # 匹配数字和单位的组合 + match = re.search(r'(-?\d+(?:\.\d+)?)\s*([^\d\s]+)?', text) + if match: + number = float(match.group(1)) + unit = match.group(2) if match.group(2) else None + return number, unit + return None, None + +def parse_specification(spec_str: str) -> Optional[int]: + """ + 解析规格字符串,提取包装数量 + 支持格式:1*15, 1x15, 1*5*10 + + Args: + spec_str: 规格字符串 + + Returns: + 包装数量,如果无法解析则返回None + """ + if not spec_str or not isinstance(spec_str, str): + return None + + try: + # 清理规格字符串 + spec_str = clean_string(spec_str) + + # 匹配重量/容量格式,如"450g*15"、"450ml*15" + match = re.search(r'\d+(?:g|ml|毫升|克)[*xX×](\d+)', spec_str) + if match: + # 返回后面的数量 + return int(match.group(1)) + + # 匹配1*5*10 格式的三级规格 + match = re.search(r'(\d+)[\*xX×](\d+)[\*xX×](\d+)', spec_str) + if match: + # 取最后一个数字作为袋数量 + return int(match.group(3)) + + # 匹配1*15, 1x15 格式 + match = re.search(r'(\d+)[\*xX×](\d+)', spec_str) + if match: + # 取第二个数字作为包装数量 + return int(match.group(2)) + + # 匹配24瓶/件等格式 + match = re.search(r'(\d+)[瓶个支袋][//](件|箱)', spec_str) + if match: + return int(match.group(1)) + + # 匹配4L格式 + match = re.search(r'(\d+(?:\.\d+)?)\s*[Ll升][*×]?(\d+)?', spec_str) + if match: + # 如果有第二个数字,返回它;否则返回1 + return int(match.group(2)) if match.group(2) else 1 + + except Exception: + pass + + return None + +def clean_barcode(barcode: Any) -> str: + """ + 清理条码格式 + + Args: + barcode: 条码(可以是字符串、整数或浮点数) + + Returns: + 清理后的条码字符串 + """ + if isinstance(barcode, (int, float)): + barcode = f"{barcode:.0f}" + + # 清理条码格式,移除可能的非数字字符(包括小数点) + barcode_clean = re.sub(r'\.0+$', '', str(barcode)) # 移除末尾0 + barcode_clean = re.sub(r'\D', '', barcode_clean) # 只保留数字 + + return barcode_clean + +def is_scientific_notation(value: str) -> bool: + """ + 检查字符串是否是科学计数法表示 + + Args: + value: 字符串值 + + Returns: + 是否是科学计数法 + """ + return bool(re.match(r'^-?\d+(\.\d+)?[eE][+-]?\d+$', str(value))) + +def parse_monetary_string(value: Any) -> Optional[float]: + """ + 解析金额/数量字符串为浮点数。 + 处理: 货币符号(¥/$)、逗号作小数点、逗号作千位分隔符、中文"元"后缀等。 + + Args: + value: 金额值(字符串、数字或其他类型) + + Returns: + 解析后的浮点数,无法解析则返回 None + """ + if value is None: + return None + if isinstance(value, (int, float)): + return float(value) + if not isinstance(value, str): + return None + + s = value.strip() + if not s or s.lower() in ('o', 'none', 'null', '-', '--'): + return None + + # 移除非数字字符,保留数字、小数点、逗号和负号 + cleaned = re.sub(r'[^\d\.\-,]', '', s) + if not cleaned or cleaned in ('-', '.', '-.', ','): + return None + + # 逗号处理策略: + # 多个逗号 -> 千位分隔符,全部移除 (如 "1,234,567" = 1234567) + # 一个逗号 + 无小数点 -> 逗号当小数点 (如 "1,5" = 1.5) + # 一个逗号 + 有小数点 -> 千位分隔符,移除 (如 "1,234.56" = 1234.56) + comma_count = cleaned.count(',') + if comma_count > 1: + cleaned = cleaned.replace(',', '') + elif comma_count == 1 and '.' not in cleaned: + cleaned = cleaned.replace(',', '.') + elif comma_count == 1 and '.' in cleaned: + cleaned = cleaned.replace(',', '') + + try: + return float(cleaned) + except (ValueError, TypeError): + return None + + +def format_barcode(barcode: Any) -> str: + """ + 格式化条码,处理科学计数法 + + Args: + barcode: 条码值 + + Returns: + 格式化后的条码字符串 + """ + if barcode is None: + return "" + + # 先转为字符串 + barcode_str = str(barcode).strip() + + # 判断是否为科学计数法 + if is_scientific_notation(barcode_str): + try: + # 科学计数法转为普通数字字符串 + barcode_str = f"{float(barcode_str):.0f}" + except (ValueError, TypeError): + pass + + # 移除可能的小数部分(如"123456.0"变为"123456") + if '.' in barcode_str: + barcode_str = re.sub(r'\.0+$', '', barcode_str) + + # 确保是纯数字字符串 + if not barcode_str.isdigit(): + # 只保留数字字符 + barcode_str = re.sub(r'\D', '', barcode_str) + + # 新增:处理末尾多余的0,标准条码通常为12-13位 + if len(barcode_str) > 13 and barcode_str.endswith('0'): + # 从末尾开始移除多余的0,直到条码长度为13位或者不再以0结尾 + while len(barcode_str) > 13 and barcode_str.endswith('0'): + barcode_str = barcode_str[:-1] + + return barcode_str \ No newline at end of file diff --git a/app/services/__init__.py b/app/services/__init__.py new file mode 100644 index 0000000..4ff788e --- /dev/null +++ b/app/services/__init__.py @@ -0,0 +1,5 @@ +""" +OCR订单处理系统 - 服务模块 +----------------------- +提供业务逻辑服务,协调各个核心组件完成业务功能。 +""" \ No newline at end of file diff --git a/app/services/ocr_service.py b/app/services/ocr_service.py new file mode 100644 index 0000000..1a4ce59 --- /dev/null +++ b/app/services/ocr_service.py @@ -0,0 +1,193 @@ +""" +OCR服务模块 +--------- +提供OCR识别服务,协调OCR流程。 +""" + +from typing import Dict, List, Optional, Tuple, Union, Any, Callable +import os + +from ..config.settings import ConfigManager +from ..core.utils.log_utils import get_logger +from ..core.ocr.table_ocr import OCRProcessor + +logger = get_logger(__name__) + +class OCRService: + """ + OCR识别服务:协调OCR流程 + """ + + def __init__(self, config: Optional[ConfigManager] = None): + """ + 初始化OCR服务 + + Args: + config: 配置管理器,如果为None则创建新的 + """ + logger.info("初始化OCRService") + self.config = config or ConfigManager() + + # 创建OCR处理器 + self.ocr_processor = OCRProcessor(self.config) + + logger.info("OCRService初始化完成") + + def get_unprocessed_images(self) -> List[str]: + """ + 获取待处理的图片列表 + + Returns: + 待处理图片路径列表 + """ + return self.ocr_processor.get_unprocessed_images() + + def process_image(self, image_path: str) -> Optional[str]: + """ + 处理单个图片文件 + + Args: + image_path: 图片文件路径 + + Returns: + 生成的Excel文件路径,如果处理失败则返回None + """ + try: + # 检查文件是否存在 + if not os.path.exists(image_path): + logger.error(f"文件不存在: {image_path}") + return None + + # 检查文件类型 + if not self._is_valid_image(image_path): + logger.error(f"不支持的文件类型: {image_path}") + return None + + # 检查是否已处理 + excel_file = self._get_excel_path(image_path) + if os.path.exists(excel_file): + logger.info(f"文件已处理过,跳过OCR识别: {image_path}") + return excel_file + + # 执行OCR识别 + result = self.ocr_processor.process_image(image_path) + if not result: + logger.error(f"OCR识别失败: {image_path}") + return None + + # 生成Excel文件 + excel_file = self._generate_excel(result, image_path) + if not excel_file: + logger.error(f"生成Excel文件失败: {image_path}") + return None + + logger.info(f"处理完成: {image_path} -> {excel_file}") + return excel_file + + except Exception as e: + logger.error(f"处理图片时发生错误: {e}", exc_info=True) + return None + + def process_images_batch(self, batch_size: int = None, max_workers: int = None, progress_cb: Optional[Callable[[int], None]] = None) -> Tuple[int, int]: + """ + 批量处理图片 + + Args: + batch_size: 批处理大小 + max_workers: 最大线程数 + + Returns: + (总处理数, 成功处理数)元组 + """ + logger.info(f"OCRService开始批量处理图片, batch_size={batch_size}, max_workers={max_workers}") + return self.ocr_processor.process_images_batch(batch_size, max_workers, progress_cb) + + # 添加batch_process作为process_images_batch的别名,确保兼容性 + def batch_process(self, batch_size: int = None, max_workers: int = None, progress_cb: Optional[Callable[[int], None]] = None) -> Tuple[int, int]: + """ + 批量处理图片(别名方法,与process_images_batch功能相同) + + Args: + batch_size: 批处理大小 + max_workers: 最大线程数 + + Returns: + (总处理数, 成功处理数)元组 + """ + logger.info(f"OCRService.batch_process被调用,转发到process_images_batch") + return self.process_images_batch(batch_size, max_workers, progress_cb) + + def validate_image(self, image_path: str) -> bool: + """ + 验证图片是否有效 + + Args: + image_path: 图片路径 + + Returns: + 图片是否有效 + """ + return self.ocr_processor.validate_image(image_path) + + def _is_valid_image(self, image_path: str) -> bool: + """ + 检查文件是否为有效的图片格式 + + Args: + image_path: 图片文件路径 + + Returns: + 是否为有效图片格式 + """ + return self.validate_image(image_path) + + def _get_excel_path(self, image_path: str) -> str: + """ + 根据图片路径生成对应的Excel文件路径 + + Args: + image_path: 图片文件路径 + + Returns: + Excel文件路径 + """ + # 获取文件名(不含扩展名) + base_name = os.path.splitext(os.path.basename(image_path))[0] + # 生成Excel文件路径 + output_dir = self.config.get('Paths', 'output_folder', fallback='data/output') + excel_path = os.path.join(output_dir, f"{base_name}.xlsx") + return excel_path + + def _generate_excel(self, ocr_result: dict, image_path: str) -> Optional[str]: + """ + 根据OCR结果生成Excel文件 + + Args: + ocr_result: OCR识别结果 + image_path: 原始图片路径 + + Returns: + 生成的Excel文件路径,失败返回None + """ + try: + excel_path = self._get_excel_path(image_path) + + # 确保输出目录存在 + os.makedirs(os.path.dirname(excel_path), exist_ok=True) + + # 调用OCR处理器的Excel生成功能 + if hasattr(self.ocr_processor, 'generate_excel'): + success = self.ocr_processor.generate_excel(ocr_result, excel_path) + if success: + return excel_path + else: + # 如果OCR处理器没有generate_excel方法,直接返回路径 + # 假设OCR处理器已经生成了Excel文件 + if os.path.exists(excel_path): + return excel_path + + return None + + except Exception as e: + logger.error(f"生成Excel文件时发生错误: {e}", exc_info=True) + return None diff --git a/app/services/order_service.py b/app/services/order_service.py new file mode 100644 index 0000000..fd53151 --- /dev/null +++ b/app/services/order_service.py @@ -0,0 +1,245 @@ +""" +订单服务模块 +--------- +提供订单处理服务,协调Excel处理和订单合并流程。 +""" + +import os +from typing import Dict, List, Optional, Tuple, Union, Any, Callable + +from ..config.settings import ConfigManager +from ..core.utils.log_utils import get_logger +from ..core.excel.processor import ExcelProcessor +from ..core.excel.merger import PurchaseOrderMerger +from ..core.db.product_db import ProductDatabase + +logger = get_logger(__name__) + +class OrderService: + """ + 订单服务:协调Excel处理和订单合并流程 + """ + + def __init__(self, config: Optional[ConfigManager] = None): + """ + 初始化订单服务 + + Args: + config: 配置管理器,如果为None则创建新的 + """ + logger.info("初始化OrderService") + self.config = config or ConfigManager() + + # 创建Excel处理器和采购单合并器 + self.excel_processor = ExcelProcessor(self.config) + self.order_merger = PurchaseOrderMerger(self.config) + + logger.info("OrderService初始化完成") + + def get_latest_excel(self) -> Optional[str]: + """ + 获取最新的Excel文件 + + Returns: + 最新Excel文件路径,如果未找到则返回None + """ + return self.excel_processor.get_latest_excel() + + def process_excel(self, file_path: Optional[str] = None, progress_cb: Optional[Callable[[int], None]] = None) -> Optional[str]: + """ + 处理Excel订单文件,生成标准采购单 + + Args: + file_path: Excel文件路径,如果为None则处理最新的文件 + + Returns: + 输出采购单文件路径,如果处理失败则返回None + """ + 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文件") + 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 + import re + + # 仅读取前 50 行进行智能识别 (header=None 确保能读到第一行内容) + df_head = smart_read_excel(file_path, nrows=50, header=None) + df_str = df_head.astype(str) + + # 1. 识别:烟草公司 (Tobacco) + # 特征:内容中包含“专卖证号”或特定证号“510109104938” + is_tobacco = df_str.apply(lambda x: x.str.contains('专卖证号|510109104938')).any().any() + if is_tobacco: + logger.info("识别到烟草公司订单,执行专用预处理...") + from .tobacco_service import TobaccoService + tobacco_svc = TobaccoService(self.config) + return tobacco_svc.preprocess_tobacco_order(file_path) + + # 2. 识别:蓉城易购 (Rongcheng Yigou) + # 特征:内容中包含单号标识“RCDH” + is_rongcheng = df_str.apply(lambda x: x.str.contains('RCDH')).any().any() + if is_rongcheng: + logger.info("识别到蓉城易购订单,执行专用预处理...") + from .special_suppliers_service import SpecialSuppliersService + special_svc = SpecialSuppliersService(self.config) + return special_svc.preprocess_rongcheng_yigou(file_path) + + # 3. 识别:杨碧月 (Yang Biyue) + # 特征:经手人列包含“杨碧月” + handler_col = None + for col in df_head.columns: + # 在前50行中搜索“经手人”关键字 + if df_head[col].astype(str).str.contains('经手人').any(): + handler_col = col + break + + if handler_col is not None: + # 检查该列是否有“杨碧月” + if df_head[handler_col].astype(str).str.contains('杨碧月').any(): + logger.info("识别到杨碧月订单,执行专用预处理...") + from .special_suppliers_service import SpecialSuppliersService + special_svc = SpecialSuppliersService(self.config) + return special_svc.process_yang_biyue_only(file_path) + + except Exception as e: + logger.warning(f"智能预处理识别失败: {e}") + return None + + def get_purchase_orders(self) -> List[str]: + """ + 获取采购单文件列表 + + Returns: + 采购单文件路径列表 + """ + return self.order_merger.get_purchase_orders() + + def merge_purchase_orders(self, file_paths: List[str], progress_cb: Optional[Callable[[int], None]] = None) -> Optional[str]: + """ + 合并指定的采购单文件 + + Args: + file_paths: 采购单文件路径列表 + + Returns: + 合并后的采购单文件路径,如果合并失败则返回None + """ + logger.info(f"OrderService开始合并指定采购单: {file_paths}") + return self.merge_orders(file_paths, progress_cb) + + def merge_all_purchase_orders(self, progress_cb: Optional[Callable[[int], None]] = None) -> Optional[str]: + """ + 合并所有可用的采购单文件 + + Returns: + 合并后的采购单文件路径,如果合并失败则返回None + """ + logger.info("OrderService开始合并所有采购单") + return self.merge_orders(None, progress_cb) + + def merge_orders(self, file_paths: Optional[List[str]] = None, progress_cb: Optional[Callable[[int], None]] = None) -> Optional[str]: + """ + 合并采购单 + + Args: + file_paths: 采购单文件路径列表,如果为None则处理所有采购单 + + Returns: + 合并后的采购单文件路径,如果合并失败则返回None + """ + if file_paths: + logger.info(f"OrderService开始合并指定采购单: {file_paths}") + else: + logger.info("OrderService开始合并所有采购单") + + return self.order_merger.process(file_paths, progress_cb) + + def validate_unit_price(self, result_path: str) -> List[str]: + """ + 校验采购单单价与商品资料进货价的差异 + + Args: + result_path: 待校验的采购单路径 + + Returns: + 差异信息列表,无差异返回空列表 + """ + try: + import pandas as pd + import os + from app.core.utils.file_utils import smart_read_excel + from app.core.handlers.column_mapper import ColumnMapper as CM + + config = ConfigManager() + template_folder = config.get('Paths', 'template_folder', fallback='templates') + item_data = config.get('Templates', 'item_data', fallback='商品资料.xlsx') + item_path = os.path.join(template_folder, item_data) + product_db_path = config.get('Paths', 'product_db', fallback='data/product_cache.db') + + # 使用 SQLite 查询商品进货价 + product_db = ProductDatabase(product_db_path, item_path) + + # 读取待校验的采购单 + df_res = smart_read_excel(result_path) + + res_barcode_col = CM.find_column(list(df_res.columns), 'barcode') + res_price_col = CM.find_column(list(df_res.columns), 'unit_price') + + if not res_barcode_col or not res_price_col: + logger.warning("未能在采购单中找到条码或单价列") + return [] + + # 批量查询进货价 + barcodes = df_res[res_barcode_col].astype(str).str.strip().tolist() + item_prices = product_db.get_prices(barcodes) + + results = [] + for _, row in df_res.iterrows(): + bc = str(row[res_barcode_col]).strip() + if bc not in item_prices: + continue + + try: + res_price = float(row[res_price_col]) + except (ValueError, TypeError): + continue + + item_price = item_prices[bc] + diff = abs(res_price - item_price) + if diff > 1.0: + results.append(f"条码 {bc}: 采购单价={res_price} vs 进货价={item_price} 差异={diff:.2f}") + + return results + + except Exception as e: + logger.error(f"单价校验过程中发生错误: {e}") + return [] diff --git a/app/services/processor_service.py b/app/services/processor_service.py new file mode 100644 index 0000000..6b3fe05 --- /dev/null +++ b/app/services/processor_service.py @@ -0,0 +1,297 @@ +""" +处理器调度服务 + +负责管理和调度各种文件处理器,实现智能文件类型检测和处理器选择 +""" + +import logging +from typing import Dict, Any, Optional, List +from pathlib import Path + +from ..core.processors.base import BaseProcessor +from ..core.processors.tobacco_processor import TobaccoProcessor +from ..core.processors.ocr_processor import OCRProcessor +from ..core.utils.log_utils import get_logger + +logger = get_logger(__name__) + + +class ProcessorService: + """处理器调度服务 + + 负责管理所有处理器实例,提供统一的文件处理接口 + """ + + def __init__(self, config: Dict[str, Any]): + """初始化处理器服务 + + Args: + config: 系统配置字典 + """ + self.config = config + self.processors: List[BaseProcessor] = [] + self._load_processors() + logger.info(f"处理器服务初始化完成,加载了{len(self.processors)}个处理器") + + def _load_processors(self): + """加载所有处理器""" + try: + self.processors = [ + TobaccoProcessor(self.config), + OCRProcessor(self.config), + ] + + supplier_configs = [] + try: + import json + from pathlib import Path + # 优先从`config/suppliers_config.json`加载 + config_path = Path("config/suppliers_config.json") + if not config_path.exists(): + # 兼容其它路径 + config_path = Path("./suppliers_config.json") + if config_path.exists(): + with open(config_path, 'r', encoding='utf-8') as f: + data = json.load(f) + ok, errs, supplier_configs = self._validate_suppliers_config(data) + if not ok: + logger.error("供应商配置校验失败:\n" + "\n".join([f"- {e}" for e in errs])) + else: + logger.info(f"从 {config_path} 加载供应商配置,共 {len(supplier_configs)} 项") + else: + logger.info("未找到供应商配置文件,跳过供应商处理器加载") + except Exception as e: + logger.error(f"读取供应商配置失败: {e}") + + for supplier_config in supplier_configs: + try: + from ..core.processors.supplier_processors.generic_supplier_processor import GenericSupplierProcessor + processor = GenericSupplierProcessor(self.config, supplier_config) + self.processors.append(processor) + logger.info(f"加载供应商处理器: {processor.name}") + except Exception as e: + logger.error(f"加载供应商处理器失败: {e}") + + logger.info(f"成功加载{len(self.processors)}个处理器") + + except Exception as e: + logger.error(f"加载处理器时出错: {e}", exc_info=True) + self.processors = [ + TobaccoProcessor(self.config), + OCRProcessor(self.config), + ] + + def _validate_suppliers_config(self, data): + try: + suppliers = data.get('suppliers') + errors = [] + valid = [] + if not isinstance(suppliers, list) or not suppliers: + errors.append('suppliers必须是非空数组') + return False, errors, [] + for idx, s in enumerate(suppliers): + e = self._validate_single_supplier(s, idx) + if e: + errors.extend(e) + else: + valid.append(s) + return len(errors) == 0, errors, valid + except Exception as e: + return False, [f'配置解析异常: {e}'], [] + + def _validate_single_supplier(self, s, idx): + errs = [] + prefix = f'suppliers[{idx}]' + name = s.get('name') + if not name or not isinstance(name, str): + errs.append(f'{prefix}.name 必须为字符串') + fp = s.get('filename_patterns', []) + ci = s.get('content_indicators', []) + if not fp and not ci: + errs.append(f'{prefix} 必须至少提供 filename_patterns 或 content_indicators 之一') + cm = s.get('column_mapping', {}) + if cm and not isinstance(cm, dict): + errs.append(f'{prefix}.column_mapping 必须为对象') + cr = s.get('cleaning_rules', []) + if cr and not isinstance(cr, list): + errs.append(f'{prefix}.cleaning_rules 必须为数组') + else: + for i, rule in enumerate(cr): + rtype = rule.get('type') + if rtype not in ('remove_rows','fill_na','convert_type'): + errs.append(f'{prefix}.cleaning_rules[{i}].type 非法: {rtype}') + if rtype == 'remove_rows' and not rule.get('condition'): + errs.append(f'{prefix}.cleaning_rules[{i}].condition 必填') + if rtype in ('fill_na','convert_type'): + if not rule.get('columns') and not rule.get('column'): + errs.append(f'{prefix}.cleaning_rules[{i}] 需提供 columns 或 column') + calc = s.get('calculations', []) + if calc and not isinstance(calc, list): + errs.append(f'{prefix}.calculations 必须为数组') + else: + for i, c in enumerate(calc): + ctype = c.get('type') + if ctype not in ('multiply','divide','formula'): + errs.append(f'{prefix}.calculations[{i}].type 非法: {ctype}') + if ctype in ('multiply','divide'): + if not c.get('source_column') or not c.get('target_column'): + errs.append(f'{prefix}.calculations[{i}] 需提供 source_column 与 target_column') + if ctype == 'formula' and (not c.get('formula') or not c.get('target_column')): + errs.append(f'{prefix}.calculations[{i}] 需提供 formula 与 target_column') + return errs + + def process_file(self, input_file: Path, output_dir: Path, + preferred_processor: Optional[str] = None) -> Optional[Path]: + """处理文件 - 自动选择合适的处理器 + + Args: + input_file: 输入文件路径 + output_dir: 输出目录路径 + preferred_processor: 优先使用的处理器名称(可选) + + Returns: + 输出文件路径,处理失败返回None + """ + if not input_file.exists(): + logger.error(f"输入文件不存在: {input_file}") + return None + + if not output_dir.exists(): + output_dir.mkdir(parents=True, exist_ok=True) + + try: + # 如果指定了优先处理器,先尝试使用它 + if preferred_processor: + processor = self._get_processor_by_name(preferred_processor) + if processor and processor.can_process(input_file): + logger.info(f"使用指定的处理器: {processor.name}") + return processor.process(input_file, output_dir) + else: + logger.warning(f"指定的处理器不可用或无法处理该文件: {preferred_processor}") + + # 自动选择合适的处理器 + suitable_processors = [p for p in self.processors if p.can_process(input_file)] + + if not suitable_processors: + logger.warning(f"未找到适合处理文件的处理器: {input_file}") + logger.info(f"支持的文件类型: {self.get_supported_types()}") + return None + + # 使用第一个合适的处理器 + processor = suitable_processors[0] + logger.info(f"使用处理器 {processor.name} 处理文件: {input_file}") + + return processor.process(input_file, output_dir) + + except Exception as e: + logger.error(f"处理文件时出错: {e}", exc_info=True) + return None + + def _get_processor_by_name(self, name: str) -> Optional[BaseProcessor]: + """根据名称获取处理器 + + Args: + name: 处理器名称 + + Returns: + 处理器实例或None + """ + for processor in self.processors: + if processor.name == name or processor.__class__.__name__ == name: + return processor + return None + + def get_supported_types(self) -> List[Dict[str, Any]]: + """获取支持的文件类型信息 + + Returns: + 处理器类型信息列表 + """ + return [ + { + 'name': processor.name, + 'description': processor.description, + 'extensions': processor.get_supported_extensions(), + 'class_name': processor.__class__.__name__ + } + for processor in self.processors + ] + + def get_processor_info(self) -> List[Dict[str, Any]]: + """获取处理器详细信息 + + Returns: + 处理器详细信息列表 + """ + return [ + { + 'name': processor.name, + 'description': processor.description, + 'extensions': processor.get_supported_extensions(), + 'required_columns': processor.get_required_columns(), + 'class_name': processor.__class__.__name__, + 'module': processor.__class__.__module__ + } + for processor in self.processors + ] + + def can_process_file(self, file_path: Path) -> bool: + """检查是否有处理器能处理该文件 + + Args: + file_path: 文件路径 + + Returns: + 是否有处理器能处理 + """ + if not file_path.exists(): + return False + + return any(processor.can_process(file_path) for processor in self.processors) + + def get_suitable_processors(self, file_path: Path) -> List[BaseProcessor]: + """获取能处理该文件的所有处理器 + + Args: + file_path: 文件路径 + + Returns: + 合适的处理器列表 + """ + if not file_path.exists(): + return [] + + return [p for p in self.processors if p.can_process(file_path)] + + def reload_processors(self): + """重新加载处理器""" + logger.info("重新加载处理器...") + self.processors.clear() + self._load_processors() + logger.info(f"重新加载完成,共{len(self.processors)}个处理器") + + def add_processor(self, processor: BaseProcessor): + """添加处理器 + + Args: + processor: 处理器实例 + """ + self.processors.append(processor) + logger.info(f"添加处理器: {processor.name}") + + def remove_processor(self, processor_name: str) -> bool: + """移除处理器 + + Args: + processor_name: 处理器名称 + + Returns: + 是否成功移除 + """ + for i, processor in enumerate(self.processors): + if processor.name == processor_name or processor.__class__.__name__ == processor_name: + del self.processors[i] + logger.info(f"移除处理器: {processor_name}") + return True + logger.warning(f"未找到要移除的处理器: {processor_name}") + return False diff --git a/app/services/special_suppliers_service.py b/app/services/special_suppliers_service.py new file mode 100644 index 0000000..5cb7444 --- /dev/null +++ b/app/services/special_suppliers_service.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import re +import time +import pandas as pd +from typing import Optional, Callable + +from ..core.utils.log_utils import get_logger + +logger = get_logger(__name__) + +class SpecialSuppliersService: + """ + 处理特殊供应商逻辑的服务类,如蓉城易购等 + """ + + def __init__(self, config_manager=None): + self.config_manager = config_manager + + def process_yang_biyue_only(self, src_path: str) -> Optional[str]: + """ + 仅执行杨碧月订单的预处理,返回预处理后的文件路径 + """ + try: + 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(): + return None + + # 识别到杨碧月订单,执行专用清洗 + logger.info("识别到杨碧月订单,正在执行专用清洗...") + + # 定义列映射关系 (映射到 ExcelProcessor 期望的中文列名) + # 使用精确匹配优先,防止“结算单位”匹配到“单位” + column_map = { + '商品条码': '商品条码', + '商品名称': '商品名称', + '商品规格': '规格', + '单位': '单位', + '数量': '数量', + '含税单价': '单价', + '含税金额': '金额' + } + + found_cols = {} + # 1. 第一遍:尝试精确匹配 + for target_zh, std_name in column_map.items(): + for col in df.columns: + if str(col).strip() == target_zh: + found_cols[col] = std_name + break + + # 2. 第二遍:对未匹配成功的列尝试模糊匹配(但要排除特定干扰词) + for target_zh, std_name in column_map.items(): + if std_name in found_cols.values(): + continue + for col in df.columns: + col_str = str(col) + if target_zh in col_str: + # 排除干扰列 + if target_zh == '单位' and '结算单位' in col_str: + continue + if target_zh == '数量' and '基本单位数量' in col_str: + continue + 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=['商品条码']) + + # 保存预处理文件 + out_dir = os.path.dirname(src_path) + base = os.path.basename(src_path) + final_path = os.path.join(out_dir, f"预处理之后_{base}") + df_clean.to_excel(final_path, index=False) + + return final_path + except Exception as e: + logger.error(f"预处理杨碧月订单出错: {e}") + return None + + 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, "正在进行杨碧月订单预处理...") + preprocessed_path = self.process_yang_biyue_only(src_path) + + if not preprocessed_path: + return None + + if progress_cb: progress_cb(60, "预处理文件已保存,开始标准转换流程...") + + # 延迟导入以避免循环依赖 + from app.services.order_service import OrderService + order_service = OrderService(self.config_manager) + result = order_service.process_excel(preprocessed_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 preprocess_rongcheng_yigou(self, src_path: str, progress_cb: Optional[Callable[[int, str], None]] = None) -> Optional[str]: + """ + 蓉城易购订单预处理:按用户提供的 E, N, Q, S 列索引进行强制清洗 + """ + try: + if progress_cb: progress_cb(10, "正在处理蓉城易购预处理...") + + from app.core.utils.file_utils import smart_read_excel + # 蓉城易购格式:Row 0是单号,Row 1是联系人,Row 2是表头,Row 3开始是数据 + df_raw = smart_read_excel(src_path, header=None) + + # 检查数据行数 + if len(df_raw) <= 3: + logger.error("蓉城易购文件数据行数不足") + return None + + # 提取数据部分 (Row 3开始) + df_data = df_raw.iloc[3:].reset_index(drop=True) + + # 用户指定列映射: + # E列 (Index 4) -> 商品条码 + # N列 (Index 13) -> 数量 + # Q列 (Index 16) -> 单价 + # S列 (Index 18) -> 金额 + # C列 (Index 2) -> 商品名称 (通用需求) + + idx_map = { + 2: '商品名称', + 4: '商品条码', + 13: '数量', + 16: '单价', + 18: '金额' + } + + # 确保列索引不越界 + available_indices = [i for i in idx_map.keys() if i < df_data.shape[1]] + df2 = df_data.iloc[:, available_indices].copy() + df2.columns = [idx_map[i] for i in available_indices] + + # 强制转换类型 + for c in ['数量', '单价', '金额']: + if c in df2.columns: + df2[c] = pd.to_numeric(df2[c], errors='coerce').fillna(0) + + # 过滤掉空的条码行 + df2 = df2.dropna(subset=['商品条码']) + df2['商品条码'] = df2['商品条码'].astype(str).str.strip() + df2 = df2[df2['商品条码'] != ''] + + # 核心逻辑:分裂多条码行并均分数量 + if '商品条码' in df2.columns and '数量' in df2.columns: + rows = [] + for _, row in df2.iterrows(): + bc_val = str(row.get('商品条码', '')).strip() + # 识别分隔符:/ , , 、 + if any(sep in bc_val for sep in ['/', ',', ',', '、']): + parts = re.split(r'[/,,、]+', bc_val) + parts = [p.strip() for p in parts if p.strip()] + + if len(parts) >= 2: + q_total = float(row.get('数量', 0) or 0) + if q_total > 0: + n = len(parts) + base_qty = int(q_total // n) + remainder = int(q_total % n) + + for i, p_bc in enumerate(parts): + new_row = row.copy() + new_row['商品条码'] = p_bc + current_qty = base_qty + (1 if i < remainder else 0) + new_row['数量'] = current_qty + if '单价' in new_row: + try: + up = float(new_row['单价'] or 0) + new_row['金额'] = up * current_qty + except Exception: + pass + rows.append(new_row) + continue + rows.append(row) + df2 = pd.DataFrame(rows) + + # 保存预处理文件 + out_dir = os.path.dirname(src_path) + base = os.path.basename(src_path) + final_path = os.path.join(out_dir, f"预处理之后_{base}") + df2.to_excel(final_path, index=False) + + if progress_cb: progress_cb(100, "蓉城易购预处理完成") + return final_path + + 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]: + """ + 兼容性方法:处理蓉城易购订单并执行后续转换 + """ + cleaned_path = self.preprocess_rongcheng_yigou(src_path, progress_cb) + if cleaned_path: + from app.services.order_service import OrderService + order_service = OrderService(self.config_manager) + return order_service.process_excel(cleaned_path, progress_cb=lambda p: progress_cb(60 + int(p*0.4), "生成采购单中...") if progress_cb else None) + return None diff --git a/app/services/tobacco_service.py b/app/services/tobacco_service.py new file mode 100644 index 0000000..8564079 --- /dev/null +++ b/app/services/tobacco_service.py @@ -0,0 +1,336 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +烟草公司订单处理服务 +---------------- +处理烟草公司特定格式的订单明细文件,生成银豹采购单 +""" + +import os +import glob +import datetime +import pandas as pd +import xlrd +import xlwt +import re +from xlutils.copy import copy +from openpyxl import load_workbook +from typing import Optional, Dict, Any, List, Tuple +from app.core.utils.log_utils import get_logger +from app.core.utils.string_utils import parse_monetary_string +from app.core.utils.dialog_utils import show_custom_dialog # 导入自定义弹窗工具 +from ..config.settings import ConfigManager + +logger = get_logger(__name__) + +class TobaccoService: + """烟草公司订单处理服务""" + + def __init__(self, config: Dict[str, Any]): + """ + 初始化服务 + + Args: + config: 配置信息 + """ + self.config = config + # 修复配置获取方式,使用fallback机制 + self.output_dir = config.get('Paths', 'output_folder', fallback='data/output') + self.template_file = config.get('Paths', 'template_file', fallback='templates/银豹-采购单模板.xls') + # 将烟草订单保存到result目录 + result_dir = "data/result" + os.makedirs(result_dir, exist_ok=True) + self.output_file = os.path.join(result_dir, '银豹采购单_烟草公司.xls') + + def get_latest_tobacco_order(self) -> Optional[str]: + """ + 获取最新的烟草订单明细文件 + + Returns: + 文件路径或None + """ + # 获取今日开始时间戳 + today = datetime.date.today() + today_start = datetime.datetime.combine(today, datetime.time.min).timestamp() + + # 查找订单明细文件 + file_pattern = os.path.join(self.output_dir, "订单明细*.xlsx") + candidates = glob.glob(file_pattern) + + if not candidates: + logger.warning("未找到烟草公司订单明细文件") + return None + + # 按创建时间排序 + candidates.sort(key=os.path.getctime, reverse=True) + latest_file = candidates[0] + + # 检查是否是今天的文件 + if os.path.getctime(latest_file) >= today_start: + logger.info(f"找到最新烟草订单明细文件: {latest_file}") + return latest_file + else: + logger.warning(f"找到的烟草订单明细文件不是今天创建的: {latest_file}") + return latest_file # 仍然返回最新文件,但给出警告 + + def preprocess_tobacco_order(self, file_path: str) -> Optional[str]: + """ + 烟草订单预处理:按用户提供的 B, E, G, H 列索引进行强制清洗 + """ + try: + logger.info(f"执行烟草订单专用预处理: {file_path}") + from app.core.utils.file_utils import smart_read_excel + + # 烟草格式:Row 0是专卖证号,Row 1是表头,Row 2是合计,Row 3开始是数据 + df_raw = smart_read_excel(file_path, header=None) + + if len(df_raw) <= 3: + logger.error("烟草订单文件数据行数不足") + return None + + # 提取数据部分 (Row 3开始) + df_data = df_raw.iloc[3:].reset_index(drop=True) + + # 用户指定列映射: + # A列 (Index 0) -> 商品名称 + # B列 (Index 1) -> 商品条码 (盒码) + # E列 (Index 4) -> 批发价 (单价) + # G列 (Index 6) -> 订单量 (数量) + # H列 (Index 7) -> 金额 + + idx_map = { + 0: '商品名称', + 1: '商品条码', + 4: '批发价', + 6: '数量', + 7: '金额' + } + + available_indices = [i for i in idx_map.keys() if i < df_data.shape[1]] + df = df_data.iloc[:, available_indices].copy() + df.columns = [idx_map[i] for i in available_indices] + + # 1. 过滤订单量不为0的数据 + df['数量'] = pd.to_numeric(df['数量'], errors='coerce').fillna(0) + df = df[df['数量'] != 0].copy() + + if df.empty: + logger.warning("烟草订单无有效订单量记录") + return None + + # 2. 核心清洗逻辑: + # 数量 = 订单量 * 10 (G列) + # 单价 = 批发价 / 10 (E列) + df['单价'] = pd.to_numeric(df['批发价'], errors='coerce').fillna(0) / 10 + df['数量'] = df['数量'] * 10 + + # 3. 校验金额 (H列) + df['金额'] = pd.to_numeric(df['金额'], errors='coerce').fillna(0) + + # 4. 只保留需要的列 + final_cols = ['商品条码', '商品名称', '数量', '单价', '金额'] + df_final = df[final_cols].copy() + + # 保存预处理文件 + out_dir = os.path.dirname(file_path) + base = os.path.basename(file_path) + final_path = os.path.join(out_dir, f"预处理之后_{base}") + df_final.to_excel(final_path, index=False) + + logger.info(f"烟草订单预处理完成: {final_path}") + return final_path + + except Exception as e: + logger.error(f"烟草订单预处理失败: {e}") + return None + + def process_tobacco_order(self, input_file=None): + """ + 处理烟草订单 + + Args: + input_file: 输入文件路径,如果为None则自动查找最新文件 + + Returns: + 输出文件路径或None(如果处理失败) + """ + try: + # 如果没有指定输入文件,查找最新的文件 + if input_file is None: + input_file = self.get_latest_tobacco_order() + + if input_file is None: + logger.warning("未找到烟草公司订单明细文件") + logger.error("未找到可处理的烟草订单明细文件") + return None + + logger.info(f"开始处理烟草公司订单: {input_file}") + + # 读取订单时间和总金额 + order_info = self._read_order_info(input_file) + if not order_info: + logger.error(f"读取订单信息失败: {input_file}") + return None + + order_time, total_amount = order_info + + # 读取订单数据 + order_data = self._read_order_data(input_file) + if order_data is None or order_data.empty: + logger.error(f"读取订单数据失败: {input_file}") + return None + + # 生成银豹采购单 + output_file = self._generate_pospal_order(order_data, order_time) + if not output_file: + logger.error("生成银豹采购单失败") + return None + + # 获取处理条目数 + total_count = len(order_data) + + # 输出处理结果 + logger.info(f"烟草公司订单处理成功,订单时间: {order_time}, 总金额: {total_amount}, 处理条目: {total_count}") + logger.info(f"采购单已生成: {output_file}") + + # 显示处理结果对话框 + self.show_result_dialog(output_file, order_time, total_count, total_amount) + + return output_file + + except Exception as e: + logger.error(f"处理烟草公司订单时发生错误: {e}", exc_info=True) + return None + + def _read_order_info(self, file_path: str) -> Optional[Tuple[str, float]]: + """ + 读取订单信息(时间和总金额) + + Args: + file_path: 文件路径 + + Returns: + 包含订单时间和总金额的元组或None + """ + try: + wb_info = load_workbook(file_path, data_only=True) + ws_info = wb_info.active + order_time = ws_info["H1"].value or "(空)" + total_amount = ws_info["H3"].value or 0 + + return (order_time, total_amount) + except Exception as e: + logger.error(f"读取订单信息出错: {e}") + return None + + def _read_order_data(self, file_path: str) -> Optional[pd.DataFrame]: + """ + 读取订单数据 + + Args: + file_path: 文件路径 + + Returns: + 订单数据DataFrame或None + """ + columns = ['商品', '盒码', '条码', '建议零售价', '批发价', '需求量', '订单量', '金额'] + + try: + from app.core.utils.file_utils import smart_read_excel + # 读取Excel文件 + df_old = smart_read_excel(file_path, header=None, skiprows=3, names=columns) + + # 过滤订单量不为0的数据,并计算采购量和单价 + df_filtered = df_old[df_old['订单量'] != 0].copy() + df_filtered['采购量'] = df_filtered['订单量'] * 10 + df_filtered['采购单价'] = df_filtered['金额'] / df_filtered['采购量'] + df_filtered = df_filtered.reset_index(drop=True) + + return df_filtered + except Exception as e: + logger.error(f"读取订单数据失败: {e}") + return None + + def _generate_pospal_order(self, order_data: pd.DataFrame, order_time: str) -> Optional[str]: + """ + 生成银豹采购单 + + Args: + order_data: 订单数据 + order_time: 订单时间 + + Returns: + 输出文件路径或None + """ + try: + # 检查模板文件是否存在 + if not os.path.exists(self.template_file): + logger.error(f"采购单模板文件不存在: {self.template_file}") + return None + + # 打开模板,准备写入 + template_rd = xlrd.open_workbook(self.template_file, formatting_info=True) + template_wb = copy(template_rd) + template_ws = template_wb.get_sheet(0) + + # 获取模板中的表头列索引 + header_row = template_rd.sheet_by_index(0).row_values(0) + barcode_col = header_row.index("条码(必填)") + amount_col = header_row.index("采购量(必填)") + gift_col = header_row.index("赠送量") + price_col = header_row.index("采购单价(必填)") + + # 写入数据到模板 + for i, row in order_data.iterrows(): + template_ws.write(i + 1, barcode_col, row['盒码']) # 商品条码 + template_ws.write(i + 1, amount_col, int(row['采购量'])) # 采购量 + template_ws.write(i + 1, gift_col, "") # 赠送量为空 + template_ws.write(i + 1, price_col, round(row['采购单价'], 2)) # 采购单价保留两位小数 + + # 确保输出目录存在 + os.makedirs(os.path.dirname(self.output_file), exist_ok=True) + + # 保存输出文件 + template_wb.save(self.output_file) + logger.info(f"采购单生成成功: {self.output_file}") + + return self.output_file + except Exception as e: + logger.error(f"生成银豹采购单失败: {e}") + return None + + def show_result_dialog(self, output_file, order_time, total_count, total_amount): + """ + 显示处理结果对话框 + + Args: + output_file: 输出文件路径 + order_time: 订单时间 + total_count: 总处理条目 + total_amount: 总金额 + """ + # 创建附加信息 + additional_info = { + "订单来源": "烟草公司", + "处理时间": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + } + + # 确保 total_amount 是数字类型 + parsed = parse_monetary_string(total_amount) + total_amount = parsed if parsed is not None else 0.0 + amount_display = f"¥{total_amount:.2f}" + + # 显示自定义对话框 + show_custom_dialog( + title="烟草订单处理结果", + message="烟草订单处理完成", + result_file=output_file, + time_info=order_time, + count_info=f"{total_count}个商品", + amount_info=amount_display, + additional_info=additional_info + ) + + # 记录日志 + logger.info(f"烟草公司订单处理成功,订单时间: {order_time}, 总金额: {total_amount}, 处理条目: {total_count}") \ No newline at end of file diff --git a/app/ui/__init__.py b/app/ui/__init__.py new file mode 100644 index 0000000..658473e --- /dev/null +++ b/app/ui/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +"""益选-OCR订单处理系统 UI 模块""" diff --git a/app/ui/action_handlers.py b/app/ui/action_handlers.py new file mode 100644 index 0000000..4188f7a --- /dev/null +++ b/app/ui/action_handlers.py @@ -0,0 +1,565 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""业务操作处理模块""" + +import os +import time +import datetime +import json +import logging +import tkinter as tk +from tkinter import messagebox +from threading import Thread + +from app.config.settings import ConfigManager +from app.services.ocr_service import OCRService +from app.services.order_service import OrderService +from app.core.utils.log_utils import get_logger + +from .logging_ui import add_to_log, init_gui_logger, dispose_gui_logger, GUILogHandler +from .ui_widgets import ProgressReporter +from .error_utils import show_error_dialog, get_error_suggestion + +logger = get_logger(__name__) +from .result_previews import show_ocr_result_preview, show_excel_result_preview, show_merge_result_preview +from .user_settings import add_recent_file +from .command_runner import get_running_task, set_running_task +from .file_operations import select_file, select_excel_file, validate_unit_price_against_item_data + + +def _ask_and_merge_purchase_orders(order_service, log_widget, add_to_recent=False): + """弹窗询问是否合并采购单,返回合并结果路径或 None。 + + 用于 run_pipeline_directly 和 batch_process_orders_with_status 的共享逻辑。 + """ + try: + purchase_orders = order_service.get_purchase_orders() + + if len(purchase_orders) == 0: + add_to_log(log_widget, "没有找到采购单文件,跳过合并步骤\n", "info") + elif len(purchase_orders) == 1: + add_to_log(log_widget, f"只有1个采购单文件,无需合并: {os.path.basename(purchase_orders[0])}\n", "info") + else: + add_to_log(log_widget, f"找到{len(purchase_orders)}个采购单文件\n", "info") + + file_list = "\n".join([f"• {os.path.basename(f)}" for f in purchase_orders]) + merge_choice = messagebox.askyesnocancel( + "采购单合并选择", + f"发现{len(purchase_orders)}个采购单文件:\n\n{file_list}\n\n是否需要合并这些采购单?\n\n• 选择'是':合并所有采购单\n• 选择'否':保持文件分离\n• 选择'取消':跳过此步骤", + icon='question' + ) + + if merge_choice is True: + add_to_log(log_widget, "开始合并采购单...\n", "info") + merge_result = order_service.merge_all_purchase_orders() + if merge_result: + add_to_log(log_widget, "采购单合并完成\n", "success") + if add_to_recent: + try: + add_recent_file(merge_result) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + return merge_result + else: + add_to_log(log_widget, "合并失败\n", "warning") + elif merge_choice is False: + add_to_log(log_widget, "用户选择不合并采购单,保持文件分离\n", "info") + else: + add_to_log(log_widget, "用户取消合并操作\n", "info") + except Exception as e: + add_to_log(log_widget, f"合并过程出现问题: {str(e)}\n", "warning") + return None + + +def process_single_image_with_status(log_widget, status_bar): + status_bar.set_status("选择图片中...") + file_path = select_file(log_widget, [("图片文件", "*.jpg *.jpeg *.png *.bmp"), ("所有文件", "*.*")], "选择图片") + if not file_path: + status_bar.set_status("操作已取消") + add_to_log(log_widget, "未选择文件,操作已取消\n", "warning") + return + + def run_in_thread(): + try: + status_bar.set_running(True) + status_bar.set_status("开始处理图片...") + + gui_handler = GUILogHandler(log_widget) + gui_handler.setLevel(logging.INFO) + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + gui_handler.setFormatter(formatter) + + root_logger = logging.getLogger() + for handler in root_logger.handlers[:]: + if isinstance(handler, logging.StreamHandler): + root_logger.removeHandler(handler) + root_logger.addHandler(gui_handler) + root_logger.setLevel(logging.INFO) + + ocr_service = OCRService() + add_to_log(log_widget, f"开始处理图片: {file_path}\n", "info") + try: + add_recent_file(file_path) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + excel_path = ocr_service.process_image(file_path) + + if excel_path: + add_to_log(log_widget, "图片OCR处理完成\n", "success") + preview_output = f"采购单已保存到: {excel_path}\n" + show_excel_result_preview(preview_output) + try: + add_recent_file(excel_path) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + else: + add_to_log(log_widget, "图片OCR处理失败\n", "error") + + except Exception as e: + add_to_log(log_widget, f"处理单个图片时出错: {str(e)}\n", "error") + sugg = get_error_suggestion(str(e)) + if sugg: + show_error_dialog("OCR处理错误", str(e), sugg) + finally: + try: + root_logger = logging.getLogger() + for handler in root_logger.handlers[:]: + if isinstance(handler, GUILogHandler): + root_logger.removeHandler(handler) + handler.close() + except Exception as e: + logger.debug(f"清理日志处理器失败: {e}") + status_bar.set_running(False) + status_bar.set_status("就绪") + + thread = Thread(target=run_in_thread) + thread.daemon = True + thread.start() + + +def run_pipeline_directly(log_widget, status_bar): + """直接运行完整处理流程""" + if get_running_task() is not None: + messagebox.showinfo("任务进行中", "请等待当前任务完成后再执行新的操作。") + return + + def run_in_thread(): + set_running_task("pipeline") + + if status_bar: + status_bar.set_running(True) + status_bar.set_status("开始完整处理流程...") + + start_time = datetime.datetime.now() + start_perf = time.perf_counter() + log_widget.configure(state=tk.NORMAL) + log_widget.delete(1.0, tk.END) + log_widget.insert(tk.END, "执行命令: 完整处理流程\n", "command") + log_widget.insert(tk.END, f"开始时间: {start_time.strftime('%Y-%m-%d %H:%M:%S')}\n", "time") + log_widget.insert(tk.END, "=" * 50 + "\n\n", "separator") + log_widget.configure(state=tk.DISABLED) + + try: + config = ConfigManager() + + gui_handler = init_gui_logger(log_widget) + + ocr_service = OCRService(config) + order_service = OrderService(config) + + reporter = ProgressReporter(status_bar) + reporter.running() + reporter.set("开始OCR批量处理...", 10) + + total, success = ocr_service.batch_process(progress_cb=lambda p: reporter.set("OCR处理中...", p)) + if total == 0: + add_to_log(log_widget, "没有找到需要处理的图片\n", "warning") + if status_bar: + status_bar.set_status("未找到图片文件") + return + elif success == 0: + add_to_log(log_widget, "OCR处理没有成功处理任何新文件\n", "warning") + else: + add_to_log(log_widget, f"OCR处理完成,共处理 {success}/{total} 个文件\n", "success") + try: + processed_map = {} + config = ConfigManager() + pjson = config.get('Paths', 'processed_record', fallback='data/processed_files.json') + if os.path.exists(pjson): + with open(pjson, 'r', encoding='utf-8') as f: + processed_map = json.load(f) + outputs = list(processed_map.values()) + for p in outputs[-10:]: + if p: + add_recent_file(os.path.abspath(p)) + except Exception as e: + logger.debug(f"加载已处理文件记录失败: {e}") + reporter.set("开始Excel处理...", 92) + + add_to_log(log_widget, "开始Excel处理...\n", "info") + result = order_service.process_excel() + + if not result: + add_to_log(log_widget, "Excel处理失败\n", "error") + else: + add_to_log(log_widget, "Excel处理完成\n", "success") + try: + add_recent_file(result) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + try: + validate_unit_price_against_item_data(result, log_widget) + except Exception as e: + logger.debug(f"单价校验失败: {e}") + + reporter.set("检查是否需要合并采购单...", 80) + _ask_and_merge_purchase_orders(order_service, log_widget, add_to_recent=True) + + end_time = datetime.datetime.now() + duration_sec = max(0.0, time.perf_counter() - start_perf) + + add_to_log(log_widget, f"\n{'=' * 50}\n", "separator") + add_to_log(log_widget, "完整处理流程执行完毕!\n", "success") + add_to_log(log_widget, f"结束时间: {end_time.strftime('%Y-%m-%d %H:%M:%S')}\n", "time") + add_to_log(log_widget, f"耗时: {duration_sec:.2f} 秒\n", "time") + reporter.set("处理完成", 100) + + except Exception as e: + add_to_log(log_widget, f"执行过程中发生错误: {str(e)}\n", "error") + import traceback + add_to_log(log_widget, f"详细错误信息: {traceback.format_exc()}\n", "error") + finally: + dispose_gui_logger() + reporter.done() + + set_running_task(None) + if status_bar: + status_bar.set_running(False) + status_bar.set_status("就绪") + + thread = Thread(target=run_in_thread) + thread.daemon = True + thread.start() + + +def batch_ocr_with_status(log_widget, status_bar): + """OCR批量识别""" + def run_in_thread(): + try: + reporter = ProgressReporter(status_bar) + reporter.running() + reporter.set("正在进行OCR批量识别...", 10) + add_to_log(log_widget, "开始OCR批量识别\n", "info") + + init_gui_logger(log_widget) + + ocr_service = OCRService() + + result = ocr_service.batch_process() + + if result: + add_to_log(log_widget, "OCR批量识别完成\n", "success") + show_ocr_result_preview("OCR批量识别成功完成") + reporter.set("批量识别完成", 100) + try: + processed_map = {} + config = ConfigManager() + pjson = config.get('Paths', 'processed_record', fallback='data/processed_files.json') + if os.path.exists(pjson): + with open(pjson, 'r', encoding='utf-8') as f: + processed_map = json.load(f) + outputs = list(processed_map.values()) + for p in outputs[-10:]: + if p: + add_recent_file(p) + inputs = list(processed_map.keys()) + for p in inputs[-10:]: + if p: + add_recent_file(p) + except Exception as e: + logger.debug(f"加载已处理文件记录失败: {e}") + else: + add_to_log(log_widget, "OCR批量识别失败\n", "error") + + except Exception as e: + add_to_log(log_widget, f"OCR批量识别出错: {str(e)}\n", "error") + sugg = get_error_suggestion(str(e)) + if sugg: + show_error_dialog("OCR处理错误", str(e), sugg) + finally: + dispose_gui_logger() + reporter.done() + + thread = Thread(target=run_in_thread) + thread.daemon = True + thread.start() + + +def batch_process_orders_with_status(log_widget, status_bar): + """批量处理订单(仅Excel处理,包含合并确认)""" + def run_in_thread(): + try: + reporter = ProgressReporter(status_bar) + reporter.running() + reporter.set("正在批量处理订单...", 10) + add_to_log(log_widget, "开始批量处理订单\n", "info") + + init_gui_logger(log_widget) + + order_service = OrderService() + + add_to_log(log_widget, "开始Excel处理...\n", "info") + try: + latest_input = order_service.get_latest_excel() + if latest_input: + add_recent_file(latest_input) + except Exception as e: + logger.debug(f"获取最新Excel失败: {e}") + result = order_service.process_excel(progress_cb=lambda p: reporter.set("Excel处理中...", p)) + + if result: + add_to_log(log_widget, "Excel处理完成\n", "success") + try: + validate_unit_price_against_item_data(result, log_widget) + except Exception as e: + logger.debug(f"单价校验失败: {e}") + + reporter.set("检查是否需要合并采购单...", 70) + add_to_log(log_widget, "检查是否需要合并采购单...\n", "info") + _ask_and_merge_purchase_orders(order_service, log_widget) + + add_to_log(log_widget, "批量处理订单完成\n", "success") + reporter.set("批量处理订单完成", 100) + show_excel_result_preview(f"采购单已保存到: {result}\n") + try: + add_recent_file(result) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + else: + add_to_log(log_widget, "批量处理订单失败\n", "error") + + except Exception as e: + add_to_log(log_widget, f"批量处理订单时出错: {str(e)}\n", "error") + sugg = get_error_suggestion(str(e)) + if sugg: + show_error_dialog("Excel处理错误", str(e), sugg) + finally: + dispose_gui_logger() + reporter.done() + + thread = Thread(target=run_in_thread) + thread.daemon = True + thread.start() + + +def merge_orders_with_status(log_widget, status_bar): + """合并采购单""" + def run_in_thread(): + try: + reporter = ProgressReporter(status_bar) + reporter.running() + reporter.set("正在合并采购单...", 10) + add_to_log(log_widget, "开始合并采购单\n", "info") + + init_gui_logger(log_widget) + + order_service = OrderService() + + result = order_service.merge_all_purchase_orders(progress_cb=lambda p: reporter.set("合并处理中...", p)) + + if result: + add_to_log(log_widget, "采购单合并完成\n", "success") + show_merge_result_preview(f"已保存到: {result}\n") + try: + add_recent_file(result) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + try: + validate_unit_price_against_item_data(result, log_widget) + except Exception as e: + logger.debug(f"单价校验失败: {e}") + else: + add_to_log(log_widget, "采购单合并失败\n", "error") + + except Exception as e: + add_to_log(log_widget, f"采购单合并出错: {str(e)}\n", "error") + sugg = get_error_suggestion(str(e)) + if sugg: + show_error_dialog("合并错误", str(e), sugg) + finally: + dispose_gui_logger() + reporter.done() + + thread = Thread(target=run_in_thread) + thread.daemon = True + thread.start() + + +def process_excel_file_with_status(log_widget, status_bar): + """处理Excel文件""" + def run_in_thread(): + try: + status_bar.set_running(True) + status_bar.set_status("选择Excel文件中...") + file_path = select_excel_file(log_widget) + + if file_path: + status_bar.set_status("开始处理Excel文件...") + add_to_log(log_widget, f"开始处理Excel文件: {file_path}\n", "info") + else: + status_bar.set_status("操作已取消") + add_to_log(log_widget, "未选择文件,操作已取消\n", "warning") + return + + init_gui_logger(log_widget) + + order_service = OrderService() + + if file_path: + try: + add_recent_file(file_path) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + result = order_service.process_excel(file_path, progress_cb=lambda p: status_bar.set_status("Excel处理中...", p)) + else: + try: + latest_input = order_service.get_latest_excel() + if latest_input: + add_recent_file(latest_input) + except Exception as e: + logger.debug(f"获取最新Excel失败: {e}") + result = order_service.process_excel(progress_cb=lambda p: status_bar.set_status("Excel处理中...", p)) + + if result: + add_to_log(log_widget, "Excel文件处理完成\n", "success") + show_excel_result_preview(f"采购单已保存到: {result}\n") + try: + add_recent_file(result) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + try: + validate_unit_price_against_item_data(result, log_widget) + except Exception as e: + logger.debug(f"单价校验失败: {e}") + else: + add_to_log(log_widget, "Excel文件处理失败\n", "error") + + except Exception as e: + add_to_log(log_widget, f"Excel文件处理出错: {str(e)}\n", "error") + msg = str(e) + suggestion = None + if 'openpyxl' in msg or 'engine' in msg: + suggestion = "安装依赖:pip install openpyxl" + elif 'xlrd' in msg: + suggestion = "安装依赖:pip install xlrd" + if suggestion: + show_error_dialog("Excel处理错误", msg, suggestion) + finally: + dispose_gui_logger() + + status_bar.set_running(False) + status_bar.set_status("就绪") + + thread = Thread(target=run_in_thread) + thread.daemon = True + thread.start() + + +def process_dropped_file(log_widget, status_bar, file_path): + try: + ext = os.path.splitext(file_path)[1].lower() + if ext in ['.jpg', '.jpeg', '.png', '.bmp']: + def _run_img(): + try: + reporter = ProgressReporter(status_bar) + reporter.running() + init_gui_logger(log_widget) + add_to_log(log_widget, f"开始一键处理图片: {file_path}\n", "info") + try: + add_recent_file(file_path) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + + # 步骤1: OCR识别 + reporter.set("OCR识别中...", 10) + ocr_service = OCRService() + excel_path = ocr_service.process_image(file_path) + if not excel_path: + add_to_log(log_widget, "图片OCR处理失败\n", "error") + return + add_to_log(log_widget, f"OCR识别完成: {excel_path}\n", "success") + + # 步骤2: Excel处理 + reporter.set("Excel处理中...", 40) + order_service = OrderService() + result = order_service.process_excel(excel_path, progress_cb=lambda p: reporter.set("Excel处理中...", p)) + if not result: + add_to_log(log_widget, "Excel处理失败\n", "error") + return + add_to_log(log_widget, f"Excel处理完成: {result}\n", "success") + try: + add_recent_file(result) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + try: + validate_unit_price_against_item_data(result, log_widget) + except Exception as e: + logger.debug(f"单价校验失败: {e}") + + # 步骤3: 合并采购单 + reporter.set("检查合并采购单...", 80) + _ask_and_merge_purchase_orders(order_service, log_widget, add_to_recent=True) + + reporter.set("处理完成", 100) + add_to_log(log_widget, "一键处理完成!\n", "success") + finally: + dispose_gui_logger() + reporter.done() + t = Thread(target=_run_img) + t.daemon = True + t.start() + elif ext in ['.xlsx', '.xls']: + def _run_xls(): + try: + reporter = ProgressReporter(status_bar) + reporter.running() + init_gui_logger(log_widget) + order_service = OrderService() + add_to_log(log_widget, f"开始一键处理Excel文件: {file_path}\n", "info") + try: + add_recent_file(file_path) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + + # 步骤1: Excel处理 + reporter.set("Excel处理中...", 20) + result = order_service.process_excel(file_path, progress_cb=lambda p: reporter.set("Excel处理中...", p)) + if not result: + add_to_log(log_widget, "Excel文件处理失败\n", "error") + return + add_to_log(log_widget, f"Excel处理完成: {result}\n", "success") + try: + add_recent_file(result) + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + try: + validate_unit_price_against_item_data(result, log_widget) + except Exception as e: + logger.debug(f"单价校验失败: {e}") + + # 步骤2: 合并采购单 + reporter.set("检查合并采购单...", 80) + _ask_and_merge_purchase_orders(order_service, log_widget, add_to_recent=True) + + reporter.set("处理完成", 100) + add_to_log(log_widget, "一键处理完成!\n", "success") + finally: + dispose_gui_logger() + reporter.done() + t = Thread(target=_run_xls) + t.daemon = True + t.start() + else: + add_to_log(log_widget, f"不支持的文件类型: {file_path}\n", "warning") + except Exception as e: + add_to_log(log_widget, f"处理拖拽文件失败: {str(e)}\n", "error") diff --git a/app/ui/barcode_editor.py b/app/ui/barcode_editor.py new file mode 100644 index 0000000..19bbf3d --- /dev/null +++ b/app/ui/barcode_editor.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""条码映射编辑模块""" + +from tkinter import messagebox + +from app.core.excel.converter import UnitConverter +from app.core.utils.dialog_utils import show_barcode_mapping_dialog + +from .logging_ui import add_to_log + + +def edit_barcode_mappings(log_widget): + """编辑条码映射配置""" + try: + add_to_log(log_widget, "正在加载条码映射配置...\n", "info") + + unit_converter = UnitConverter() + + current_mappings = unit_converter.special_barcodes + + def save_mappings(new_mappings): + success = unit_converter.update_barcode_mappings(new_mappings) + if success: + add_to_log(log_widget, f"成功保存条码映射配置,共{len(new_mappings)}项\n", "success") + else: + add_to_log(log_widget, "保存条码映射配置失败\n", "error") + + show_barcode_mapping_dialog(None, save_mappings, current_mappings) + + except Exception as e: + add_to_log(log_widget, f"编辑条码映射时出错: {str(e)}\n", "error") + messagebox.showerror("错误", f"编辑条码映射时出错: {str(e)}") diff --git a/app/ui/command_runner.py b/app/ui/command_runner.py new file mode 100644 index 0000000..12e5853 --- /dev/null +++ b/app/ui/command_runner.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""命令执行器模块""" + +import os +import sys +import time +import subprocess +import datetime +import re +import tkinter as tk +from tkinter import messagebox +from threading import Thread + +from .logging_ui import LogRedirector +from .result_previews import show_result_preview + +# 任务状态跟踪 +_RUNNING_TASK = None + + +def get_running_task(): + return _RUNNING_TASK + + +def set_running_task(val): + global _RUNNING_TASK + _RUNNING_TASK = val + + +def run_command_with_logging(command, log_widget, status_bar=None, on_complete=None): + """运行命令并将输出重定向到日志窗口""" + if _RUNNING_TASK is not None: + messagebox.showinfo("任务进行中", "请等待当前任务完成后再执行新的操作。") + return + + def run_in_thread(): + global _RUNNING_TASK + _RUNNING_TASK = command + + if status_bar: + status_bar.set_running(True) + + start_time = datetime.datetime.now() + start_perf = time.perf_counter() + log_widget.configure(state=tk.NORMAL) + log_widget.delete(1.0, tk.END) + log_widget.insert(tk.END, f"执行命令: {' '.join(command)}\n", "command") + log_widget.insert(tk.END, f"开始时间: {start_time.strftime('%Y-%m-%d %H:%M:%S')}\n", "time") + log_widget.insert(tk.END, "=" * 50 + "\n\n", "separator") + log_widget.configure(state=tk.DISABLED) + + old_stdout = sys.stdout + old_stderr = sys.stderr + + log_redirector = LogRedirector(log_widget) + + env = os.environ.copy() + try: + from app.config.settings import ConfigManager + cfg = ConfigManager() + env["OCR_OUTPUT_DIR"] = cfg.get_path('Paths', 'output_folder', fallback='data/output', create=True) + env["OCR_INPUT_DIR"] = cfg.get_path('Paths', 'input_folder', fallback='data/input', create=True) + env["OCR_TEMP_DIR"] = cfg.get_path('Paths', 'temp_folder', fallback='data/temp', create=True) + except Exception: + env["OCR_OUTPUT_DIR"] = os.path.abspath("data/output") + env["OCR_INPUT_DIR"] = os.path.abspath("data/input") + env["OCR_TEMP_DIR"] = os.path.abspath("data/temp") + env["OCR_LOG_LEVEL"] = "DEBUG" + + try: + sys.stdout = log_redirector + sys.stderr = log_redirector + + print("日志重定向已启动,现在同时输出到终端和GUI") + + process = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=1, + universal_newlines=True, + env=env + ) + + output_data = [] + for line in process.stdout: + output_data.append(line) + print(line.rstrip()) + + if status_bar: + progress = extract_progress_from_log(line) + if progress is not None: + log_widget.after(0, lambda p=progress: status_bar.set_status(f"处理中: {p}%完成", p)) + + process.wait() + + end_time = datetime.datetime.now() + duration_sec = max(0.0, time.perf_counter() - start_perf) + + print(f"\n{'=' * 50}") + print(f"执行完毕!返回码: {process.returncode}") + print(f"结束时间: {end_time.strftime('%Y-%m-%d %H:%M:%S')}") + print(f"耗时: {duration_sec:.2f} 秒") + + output_text = ''.join(output_data) + + is_pipeline = "pipeline" in command + no_merge_files = "未找到采购单文件" in output_text + single_file = "只有1个采购单文件" in output_text + + if is_pipeline and (no_merge_files or single_file): + print("完整流程中没有需要合并的文件,但其他步骤执行成功,视为成功完成") + if status_bar: + log_widget.after(0, lambda: status_bar.set_status("处理完成", 100)) + log_widget.after(0, lambda: show_result_preview(command, output_text)) + else: + if on_complete: + log_widget.after(0, lambda: on_complete(process.returncode, output_text)) + elif process.returncode == 0: + if status_bar: + log_widget.after(0, lambda: status_bar.set_status("处理完成", 100)) + log_widget.after(0, lambda: show_result_preview(command, output_text)) + else: + if status_bar: + log_widget.after(0, lambda: status_bar.set_status(f"处理失败 (返回码: {process.returncode})", 0)) + log_widget.after(0, lambda: messagebox.showerror("操作失败", f"处理失败,返回码:{process.returncode}")) + + except Exception as e: + print(f"\n执行出错: {str(e)}") + if status_bar: + log_widget.after(0, lambda: status_bar.set_status(f"执行出错: {str(e)}", 0)) + log_widget.after(0, lambda: messagebox.showerror("执行错误", f"执行命令时出错: {str(e)}")) + finally: + sys.stdout = old_stdout + sys.stderr = old_stderr + + _RUNNING_TASK = None + if status_bar: + log_widget.after(0, lambda: status_bar.set_running(False)) + + Thread(target=run_in_thread).start() + + +def extract_progress_from_log(log_line): + """从日志行中提取进度信息""" + batch_match = re.search(r'处理批次 (\d+)/(\d+)', log_line) + if batch_match: + current = int(batch_match.group(1)) + total = int(batch_match.group(2)) + return int(current / total * 100) + + percent_match = re.search(r'(\d+)%', log_line) + if percent_match: + return int(percent_match.group(1)) + + return None diff --git a/app/ui/config_dialog.py b/app/ui/config_dialog.py new file mode 100644 index 0000000..b89399e --- /dev/null +++ b/app/ui/config_dialog.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""系统设置对话框模块""" + +import os +import tkinter as tk +from tkinter import messagebox, filedialog, ttk + +from app.config.settings import ConfigManager + +from .user_settings import load_user_settings, save_user_settings +from .ui_widgets import center_window +from app.core.utils.dialog_utils import show_cloud_sync_dialog + +# 模块级状态 +_PROCESSOR_SERVICE = None + + +def show_config_dialog(root, cfg: ConfigManager): + global _PROCESSOR_SERVICE + + settings = load_user_settings() + dlg = tk.Toplevel(root) + dlg.title("系统设置") + dlg.geometry("560x680") + center_window(dlg) + + content = ttk.Frame(dlg) + content.pack(fill=tk.BOTH, expand=True, padx=16, pady=16) + for i in range(2): + content.columnconfigure(i, weight=1) + + # 当前值 + log_level_val = tk.StringVar(value=settings.get('log_level', 'INFO')) + max_workers_val = tk.StringVar(value=str(settings.get('concurrency_max_workers', cfg.getint('Performance', 'max_workers', 4)))) + batch_size_val = tk.StringVar(value=str(settings.get('concurrency_batch_size', cfg.getint('Performance', 'batch_size', 5)))) + template_path_val = tk.StringVar(value=settings.get('template_path', os.path.join(cfg.get('Paths', 'template_folder', 'templates'), cfg.get('Templates', 'purchase_order', '银豹-采购单模板.xls')))) + input_dir_val = tk.StringVar(value=settings.get('input_folder', cfg.get('Paths', 'input_folder', 'data/input'))) + output_dir_val = tk.StringVar(value=settings.get('output_folder', cfg.get('Paths', 'output_folder', 'data/output'))) + result_dir_val = tk.StringVar(value=settings.get('result_folder', 'data/result')) + + def add_row(row, label_text, widget): + ttk.Label(content, text=label_text).grid(row=row, column=0, sticky='w', padx=4, pady=6) + widget.grid(row=row, column=1, sticky='ew', padx=4, pady=6) + + # 日志级别 + lvl = ttk.Combobox(content, textvariable=log_level_val, values=['DEBUG', 'INFO', 'WARNING', 'ERROR'], state='readonly') + add_row(0, "日志级别", lvl) + + # 并发参数 + maxw_entry = ttk.Entry(content, textvariable=max_workers_val) + add_row(1, "最大并发(max_workers)", maxw_entry) + batch_entry = ttk.Entry(content, textvariable=batch_size_val) + add_row(2, "批次大小(batch_size)", batch_entry) + + # 模板路径 + tpl_frame = ttk.Frame(content) + tpl_entry = ttk.Entry(tpl_frame, textvariable=template_path_val) + tpl_entry.pack(side=tk.LEFT, fill=tk.X, expand=True) + + def _select_template(): + p = filedialog.askopenfilename(title="选择模板文件", filetypes=[("Excel模板", "*.xls *.xlsx"), ("所有文件", "*.*")]) + if p: + try: + template_path_val.set(os.path.relpath(p, os.getcwd())) + except Exception: + template_path_val.set(p) + + ttk.Button(tpl_frame, text="选择", command=_select_template).pack(side=tk.LEFT, padx=6) + add_row(3, "采购单模板文件", tpl_frame) + + # 目录 + def dir_row(row_idx, label, var): + f = ttk.Frame(content) + e = ttk.Entry(f, textvariable=var) + e.pack(side=tk.LEFT, fill=tk.X, expand=True) + + def _select_dir(): + d = filedialog.askdirectory(title=f"选择{label}") + if d: + try: + var.set(os.path.relpath(d, os.getcwd())) + except Exception: + var.set(d) + + ttk.Button(f, text="选择", command=_select_dir).pack(side=tk.LEFT, padx=6) + add_row(row_idx, label, f) + + dir_row(4, "输入目录", input_dir_val) + dir_row(5, "输出目录", output_dir_val) + dir_row(6, "结果目录", result_dir_val) + + api_key_val = tk.StringVar(value=settings.get('api_key', cfg.get('API', 'api_key', ''))) + secret_key_val = tk.StringVar(value=settings.get('secret_key', cfg.get('API', 'secret_key', ''))) + timeout_val = tk.StringVar(value=str(settings.get('timeout', cfg.getint('API', 'timeout', 30)))) + max_retries_val = tk.StringVar(value=str(settings.get('max_retries', cfg.getint('API', 'max_retries', 3)))) + retry_delay_val = tk.StringVar(value=str(settings.get('retry_delay', cfg.getint('API', 'retry_delay', 2)))) + api_url_val = tk.StringVar(value=settings.get('api_url', cfg.get('API', 'api_url', ''))) + + api_key_entry = ttk.Entry(content, textvariable=api_key_val) + add_row(7, "API Key", api_key_entry) + secret_key_entry = ttk.Entry(content, textvariable=secret_key_val) + secret_key_entry.configure(show='*') + add_row(8, "Secret Key", secret_key_entry) + add_row(9, "Timeout", ttk.Entry(content, textvariable=timeout_val)) + add_row(10, "Max Retries", ttk.Entry(content, textvariable=max_retries_val)) + add_row(11, "Retry Delay", ttk.Entry(content, textvariable=retry_delay_val)) + add_row(12, "API URL", ttk.Entry(content, textvariable=api_url_val)) + + # ---- Gitea 云端同步配置 ---- + ttk.Separator(content).grid(row=13, column=0, columnspan=2, sticky='ew', pady=8) + ttk.Label(content, text="云端同步 (Gitea)", font=("Arial", 10, "bold")).grid(row=14, column=0, sticky='w', padx=4, pady=4) + + gitea_url_val = tk.StringVar(value=cfg.get('Gitea', 'base_url', fallback='https://gitea.94kan.cn')) + gitea_owner_val = tk.StringVar(value=cfg.get('Gitea', 'owner', fallback='houhuan')) + gitea_repo_val = tk.StringVar(value=cfg.get('Gitea', 'repo', fallback='yixuan-sync-data')) + gitea_token_val = tk.StringVar(value=cfg.get('Gitea', 'token', fallback='')) + + add_row(15, "Gitea 地址", ttk.Entry(content, textvariable=gitea_url_val)) + add_row(16, "仓库所有者", ttk.Entry(content, textvariable=gitea_owner_val)) + add_row(17, "仓库名称", ttk.Entry(content, textvariable=gitea_repo_val)) + gitea_token_entry = ttk.Entry(content, textvariable=gitea_token_val, show='*') + add_row(18, "Access Token", gitea_token_entry) + + # 操作按钮 + btns = ttk.Frame(content) + btns.grid(row=19, column=0, columnspan=2, sticky='ew', pady=10) + btns.columnconfigure(0, weight=1) + + def save_settings(): + try: + s = load_user_settings() + s['log_level'] = log_level_val.get() + s['concurrency_max_workers'] = int(max_workers_val.get() or '4') + s['concurrency_batch_size'] = int(batch_size_val.get() or '5') + tp = template_path_val.get() + inp = input_dir_val.get() + outp = output_dir_val.get() + resp = result_dir_val.get() + try: + if tp: + tp = os.path.relpath(tp, os.getcwd()) if os.path.isabs(tp) else tp + if inp: + inp = os.path.relpath(inp, os.getcwd()) if os.path.isabs(inp) else inp + if outp: + outp = os.path.relpath(outp, os.getcwd()) if os.path.isabs(outp) else outp + if resp: + resp = os.path.relpath(resp, os.getcwd()) if os.path.isabs(resp) else resp + except Exception: + pass + s['template_path'] = tp + s['input_folder'] = inp + s['output_folder'] = outp + s['result_folder'] = resp + save_user_settings(s) + try: + from app.core.utils.log_utils import set_log_level + set_log_level(s['log_level']) + except Exception: + pass + try: + tpl_path = s['template_path'] + tpl_dir = os.path.dirname(tpl_path) + tpl_name = os.path.basename(tpl_path) + cfg.update('Paths', 'template_folder', tpl_dir) + cfg.update('Templates', 'purchase_order', tpl_name) + try: + cfg.update('Paths', 'template_file', os.path.join(tpl_dir, tpl_name)) + except Exception: + pass + cfg.update('Paths', 'input_folder', s['input_folder']) + cfg.update('Paths', 'output_folder', s['output_folder']) + cfg.update('Performance', 'max_workers', s['concurrency_max_workers']) + cfg.update('Performance', 'batch_size', s['concurrency_batch_size']) + cfg.update('API', 'api_key', api_key_val.get()) + cfg.update('API', 'secret_key', secret_key_val.get()) + cfg.update('API', 'timeout', timeout_val.get()) + cfg.update('API', 'max_retries', max_retries_val.get()) + cfg.update('API', 'retry_delay', retry_delay_val.get()) + cfg.update('API', 'api_url', api_url_val.get()) + cfg.update('Gitea', 'base_url', gitea_url_val.get()) + cfg.update('Gitea', 'owner', gitea_owner_val.get()) + cfg.update('Gitea', 'repo', gitea_repo_val.get()) + cfg.update('Gitea', 'token', gitea_token_val.get()) + cfg.save_config() + except Exception: + pass + messagebox.showinfo("设置已保存", "系统设置已更新并保存") + dlg.destroy() + except Exception as e: + messagebox.showerror("保存失败", str(e)) + + def reload_suppliers(): + global _PROCESSOR_SERVICE + try: + from app.services.processor_service import ProcessorService + if _PROCESSOR_SERVICE is None: + _PROCESSOR_SERVICE = ProcessorService(ConfigManager()) + _PROCESSOR_SERVICE.reload_processors() + messagebox.showinfo("已重新加载", "供应商处理器已重新加载并应用最新配置") + except Exception as e: + messagebox.showerror("重新加载失败", str(e)) + + ttk.Button(btns, text="重新加载供应商配置", command=reload_suppliers).grid(row=0, column=0, sticky='w') + ttk.Button(btns, text="云端同步", command=lambda: show_cloud_sync_dialog(dlg)).grid(row=0, column=1, sticky='w', padx=6) + ttk.Button(btns, text="取消", command=dlg.destroy).grid(row=0, column=2, sticky='e') + ttk.Button(btns, text="保存", command=save_settings).grid(row=0, column=3, sticky='e', padx=6) diff --git a/app/ui/error_utils.py b/app/ui/error_utils.py new file mode 100644 index 0000000..fdd1ff3 --- /dev/null +++ b/app/ui/error_utils.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""错误处理工具模块""" + +from tkinter import messagebox +from typing import Optional + +from app.core.utils.log_utils import get_logger + +logger = get_logger(__name__) + + +def show_error_dialog(title: str, message: str, suggestion: Optional[str] = None): + try: + full_msg = message + if suggestion: + full_msg = f"{message}\n\n建议操作:\n- {suggestion}" + messagebox.showerror(title, full_msg) + except Exception as e: + logger.debug(f"显示错误对话框失败: {e}") + + +def get_error_suggestion(message: str) -> Optional[str]: + msg = (message or "").lower() + if 'openpyxl' in msg or ('engine' in msg and 'xlsx' in msg): + return '安装依赖:pip install openpyxl' + if 'xlrd' in msg or ('engine' in msg and 'xls' in msg): + return '安装依赖:pip install xlrd' + if 'timeout' in msg or 'timed out' in msg: + return '检查网络,增大API超时时间或稍后重试' + if 'invalid access_token' in msg or 'access token' in msg: + return '刷新百度OCR令牌或检查api_key/secret_key' + if '429' in msg or 'too many requests' in msg: + return '降低识别频率或稍后重试' + if '模板文件不存在' in msg or ('no such file' in msg and '模板' in msg): + return '在系统设置中选择正确的模板文件路径' + if '没有找到采购单' in msg or '未在 data/result 目录下找到采购单' in msg: + return '确认data/result目录内存在采购单文件' + if 'permission denied' in msg: + return '以管理员权限运行或更改目录写入权限' + return None diff --git a/app/ui/file_operations.py b/app/ui/file_operations.py new file mode 100644 index 0000000..3e0075b --- /dev/null +++ b/app/ui/file_operations.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""文件与目录操作模块""" + +import os +import json +import tkinter as tk +from tkinter import messagebox, filedialog, scrolledtext + +from .logging_ui import add_to_log +from .ui_widgets import center_window +from app.config.settings import ConfigManager + + +def select_file(log_widget, file_types=None, title="选择文件"): + """通用文件选择对话框""" + if file_types is None: + file_types = [("所有文件", "*.*")] + file_path = filedialog.askopenfilename(title=title, filetypes=file_types) + if file_path: + add_to_log(log_widget, f"已选择文件: {file_path}\n", "info") + return file_path + + +def select_excel_file(log_widget): + """选择Excel文件""" + return select_file( + log_widget, + [("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")], + "选择Excel文件" + ) + + +def ensure_directories(): + """确保必要的目录结构存在""" + config = ConfigManager() + directories = [ + config.get('Paths', 'input_folder', fallback='data/input'), + config.get('Paths', 'output_folder', fallback='data/output'), + 'data/result', + config.get('Paths', 'temp_folder', fallback='data/temp'), + 'logs' + ] + for directory in directories: + if not os.path.exists(directory): + os.makedirs(directory, exist_ok=True) + print(f"创建目录: {directory}") + + +def clean_cache(log_widget): + """清除处理缓存""" + from .command_runner import set_running_task + try: + config = ConfigManager() + processed_record = config.get('Paths', 'processed_record', fallback='data/processed_files.json') + output_folder = config.get('Paths', 'output_folder', fallback='data/output') + cache_files = [ + processed_record, + os.path.join(output_folder, "processed_files.json"), + os.path.join(output_folder, "merged_files.json") + ] + + for cache_file in cache_files: + if os.path.exists(cache_file): + os.remove(cache_file) + add_to_log(log_widget, f"已清除缓存文件: {cache_file}\n", "success") + + temp_dir = os.path.join("data/temp") + if os.path.exists(temp_dir): + for file in os.listdir(temp_dir): + file_path = os.path.join(temp_dir, file) + try: + if os.path.isfile(file_path): + os.remove(file_path) + add_to_log(log_widget, f"已清除临时文件: {file_path}\n", "info") + except Exception as e: + add_to_log(log_widget, f"清除文件时出错: {file_path}, 错误: {str(e)}\n", "error") + + log_dir = "logs" + if os.path.exists(log_dir): + for file in os.listdir(log_dir): + if file.endswith(".active"): + file_path = os.path.join(log_dir, file) + try: + os.remove(file_path) + add_to_log(log_widget, f"已清除活动日志标记: {file_path}\n", "info") + except Exception as e: + add_to_log(log_widget, f"清除文件时出错: {file_path}, 错误: {str(e)}\n", "error") + + set_running_task(None) + + add_to_log(log_widget, "缓存清除完成,系统将重新处理所有文件\n", "success") + messagebox.showinfo("缓存清除", "缓存已清除,系统将重新处理所有文件。") + except Exception as e: + add_to_log(log_widget, f"清除缓存时出错: {str(e)}\n", "error") + messagebox.showerror("错误", f"清除缓存时出错: {str(e)}") + + +def open_result_directory(): + try: + result_dir = os.path.abspath("data/result") + if not os.path.exists(result_dir): + os.makedirs(result_dir, exist_ok=True) + os.startfile(result_dir) + except Exception as e: + messagebox.showerror("错误", f"无法打开结果目录: {str(e)}") + + +def _open_directory_from_settings(settings_key, default_path, label): + """通用的从用户设置读取路径并打开目录""" + from .user_settings import load_user_settings + try: + s = load_user_settings() + path = os.path.abspath(s.get(settings_key, default_path)) + if not os.path.exists(path): + os.makedirs(path, exist_ok=True) + os.startfile(path) + except Exception as e: + messagebox.showerror("错误", f"无法打开{label}: {str(e)}") + + +def open_input_directory_from_settings(): + _open_directory_from_settings('input_folder', 'data/input', '输入目录') + + +def open_output_directory_from_settings(): + _open_directory_from_settings('output_folder', 'data/output', '输出目录') + + +def open_result_directory_from_settings(): + _open_directory_from_settings('result_folder', 'data/result', '结果目录') + + +def clean_data_files(log_widget): + """清理数据文件(仅清理input和output目录)""" + try: + if not messagebox.askyesno("确认清理", "确定要清理input和output目录的文件吗?这将删除所有输入和输出数据。"): + add_to_log(log_widget, "操作已取消\n", "info") + return + + files_cleaned = 0 + + input_dir = "data/input" + if os.path.exists(input_dir): + for file in os.listdir(input_dir): + file_path = os.path.join(input_dir, file) + if os.path.isfile(file_path): + os.remove(file_path) + files_cleaned += 1 + add_to_log(log_widget, "已清理input目录\n", "info") + + output_dir = "data/output" + if os.path.exists(output_dir): + for file in os.listdir(output_dir): + file_path = os.path.join(output_dir, file) + if os.path.isfile(file_path): + os.remove(file_path) + files_cleaned += 1 + add_to_log(log_widget, "已清理output目录\n", "info") + + add_to_log(log_widget, f"清理完成,共清理 {files_cleaned} 个文件\n", "success") + messagebox.showinfo("清理完成", f"已成功清理 {files_cleaned} 个文件") + except Exception as e: + add_to_log(log_widget, f"清理数据文件时出错: {str(e)}\n", "error") + messagebox.showerror("错误", f"清理数据文件时出错: {str(e)}") + + +def clean_result_files(log_widget): + try: + if not messagebox.askyesno("确认清理", "确定要清理result目录的文件吗?这将删除所有已生成的采购单文件。"): + add_to_log(log_widget, "操作已取消\n", "info") + return + count = 0 + result_dir = "data/result" + if os.path.exists(result_dir): + for file in os.listdir(result_dir): + file_path = os.path.join(result_dir, file) + if os.path.isfile(file_path): + os.remove(file_path) + count += 1 + add_to_log(log_widget, f"已清理result目录,共 {count} 个文件\n", "success") + messagebox.showinfo("清理完成", f"已清理result目录 {count} 个文件") + except Exception as e: + add_to_log(log_widget, f"清理result目录时出错: {str(e)}\n", "error") + messagebox.showerror("错误", f"清理result目录时出错: {str(e)}") + + +def validate_unit_price_against_item_data(result_path: str, log_widget=None): + try: + from app.services.order_service import OrderService + service = OrderService() + bad_results = service.validate_unit_price(result_path) + + if bad_results: + display_count = min(len(bad_results), 10) + msg = f"存在{len(bad_results)}条单价与商品资料进货价差异超过1元:\n" + "\n".join(bad_results[:display_count]) + if len(bad_results) > 10: + msg += f"\n...(其余 {len(bad_results) - 10} 条已省略)" + messagebox.showwarning("单价校验提示", msg) + if log_widget is not None: + add_to_log(log_widget, f"单价校验发现{len(bad_results)}条差异>1元\n", "warning") + else: + if log_widget is not None: + add_to_log(log_widget, "单价校验通过(差异<=1元)\n", "success") + except Exception as e: + if log_widget is not None: + add_to_log(log_widget, f"单价校验出错: {str(e)}\n", "error") diff --git a/app/ui/logging_ui.py b/app/ui/logging_ui.py new file mode 100644 index 0000000..fc6aa87 --- /dev/null +++ b/app/ui/logging_ui.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""GUI日志处理模块""" + +import logging +import queue +import sys +import tkinter as tk + +# 全局日志队列,用于异步更新UI +LOG_QUEUE = queue.Queue() + + +class LogRedirector: + """日志重定向器,用于捕获命令输出并显示到界面""" + def __init__(self, text_widget): + self.text_widget = text_widget + self.buffer = "" + self.terminal = sys.__stdout__ + + def write(self, string): + self.buffer += string + self.terminal.write(string) + self.text_widget.after(0, self.update_text_widget) + + def update_text_widget(self): + self.text_widget.configure(state=tk.NORMAL) + + if self.buffer.strip(): + if any(marker in self.buffer.lower() for marker in ["错误", "error", "失败", "异常", "exception"]): + self.text_widget.insert(tk.END, self.buffer, "error") + elif any(marker in self.buffer.lower() for marker in ["警告", "warning"]): + self.text_widget.insert(tk.END, self.buffer, "warning") + elif any(marker in self.buffer.lower() for marker in ["成功", "success", "完成", "成功处理"]): + self.text_widget.insert(tk.END, self.buffer, "success") + elif any(marker in self.buffer.lower() for marker in ["info", "信息", "开始", "处理中"]): + self.text_widget.insert(tk.END, self.buffer, "info") + else: + self.text_widget.insert(tk.END, self.buffer, "normal") + else: + self.text_widget.insert(tk.END, self.buffer) + + self.text_widget.see(tk.END) + self.text_widget.configure(state=tk.DISABLED) + self.buffer = "" + + def flush(self): + self.terminal.flush() + + +class GUILogHandler(logging.Handler): + """自定义日志处理器,将日志放入队列,由GUI主线程定时消费""" + def __init__(self, text_widget): + super().__init__() + self.text_widget = text_widget + + def emit(self, record): + try: + msg = self.format(record) + if record.levelno >= logging.ERROR: + tag = "error" + elif record.levelno >= logging.WARNING: + tag = "warning" + elif record.levelno >= logging.INFO: + tag = "info" + else: + tag = "normal" + + LOG_QUEUE.put((msg + "\n", tag)) + except Exception: + self.handleError(record) + + +def poll_log_queue(text_widget): + """定期从队列中读取日志并更新UI""" + try: + updated = False + while not LOG_QUEUE.empty(): + msg, tag = LOG_QUEUE.get_nowait() + text_widget.configure(state=tk.NORMAL) + text_widget.insert(tk.END, msg, tag) + updated = True + + if updated: + text_widget.see(tk.END) + text_widget.configure(state=tk.DISABLED) + + except Exception: + pass + finally: + text_widget.after(100, lambda: poll_log_queue(text_widget)) + + +def init_gui_logger(text_widget, level=logging.INFO): + handler = GUILogHandler(text_widget) + handler.setLevel(level) + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + handler.setFormatter(formatter) + root_logger = logging.getLogger() + for h in root_logger.handlers[:]: + if isinstance(h, logging.StreamHandler): + root_logger.removeHandler(h) + if not any(isinstance(h, GUILogHandler) for h in root_logger.handlers): + root_logger.addHandler(handler) + root_logger.setLevel(level) + return handler + + +def dispose_gui_logger(): + root_logger = logging.getLogger() + for handler in root_logger.handlers[:]: + if isinstance(handler, GUILogHandler): + root_logger.removeHandler(handler) + try: + handler.close() + except Exception: + pass + + +def add_to_log(log_widget, text, tag="normal"): + """向日志队列添加文本,由 poll_log_queue 消费并更新 UI""" + if log_widget is None: + print(f"[{tag}] {text}", end="") + return + + LOG_QUEUE.put((text, tag)) diff --git a/app/ui/main_window.py b/app/ui/main_window.py new file mode 100644 index 0000000..1be1238 --- /dev/null +++ b/app/ui/main_window.py @@ -0,0 +1,485 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""主窗口模块""" + +import os +import sys +import subprocess +import tkinter as tk +from tkinter import messagebox, filedialog, scrolledtext + +from app.config.settings import ConfigManager +from app.core.utils.log_utils import set_log_level + +from .theme import THEMES, get_theme_mode, set_theme_mode, create_modern_button, create_card_frame +from .logging_ui import add_to_log, poll_log_queue +from .ui_widgets import StatusBar +from .user_settings import ( + load_user_settings, save_user_settings, refresh_recent_list_widget, + _extract_path_from_recent_item, clear_recent_files, RECENT_LIST_WIDGET, +) +from .file_operations import ( + ensure_directories, open_result_directory, clean_cache, + clean_data_files, clean_result_files, +) +from .action_handlers import ( + process_single_image_with_status, run_pipeline_directly, + batch_ocr_with_status, batch_process_orders_with_status, + merge_orders_with_status, process_excel_file_with_status, + process_dropped_file, +) +from .config_dialog import show_config_dialog +from .barcode_editor import edit_barcode_mappings +from .shortcuts import bind_keyboard_shortcuts +from app.core.utils.dialog_utils import show_cloud_sync_dialog + + +def _init_window(): + """初始化窗口、主题和设置,返回 (root, theme, settings, dnd_supported)""" + ensure_directories() + + dnd_supported = False + try: + from tkinterdnd2 import TkinterDnD, DND_FILES + root = TkinterDnD.Tk() + dnd_supported = True + except Exception: + root = tk.Tk() + + settings = load_user_settings() + theme_mode = settings.get('theme_mode', get_theme_mode()) + set_theme_mode(theme_mode) + + try: + cfg_for_title = ConfigManager() + ver = cfg_for_title.get('App', 'version', fallback='dev') + root.title(f"益选-OCR订单处理系统 v{ver} by 欢欢欢") + except Exception: + root.title("益选-OCR订单处理系统 by 欢欢欢") + + root.geometry("900x600") + settings['window_size'] = "900x600" + theme = THEMES[get_theme_mode()] + root.configure(bg=theme["bg"]) + + try: + log_level = settings.get('log_level') + if log_level: + set_log_level(log_level) + concurrency = settings.get('concurrency_max_workers') + if concurrency: + cfg = ConfigManager() + cfg.update('Performance', 'max_workers', str(concurrency)) + cfg.save_config() + except Exception: + pass + + try: + root.iconbitmap(default="") + except Exception: + pass + + return root, theme, settings, dnd_supported + + +def _create_left_panel(content_frame, theme, log_text, status_bar): + """创建左侧面板:完整流程、OCR处理、Excel处理、最近文件""" + left_panel = create_card_frame(content_frame) + left_panel.pack(side=tk.LEFT, fill=tk.BOTH, expand=False, padx=(0, 5), pady=5) + left_panel.configure(width=160) + + panel_content = tk.Frame(left_panel, bg=theme["card_bg"]) + panel_content.pack(fill=tk.BOTH, expand=True, padx=10, pady=(5, 10)) + + # 完整流程区 + pipeline_section = tk.LabelFrame( + panel_content, text="完整流程", bg=theme["card_bg"], fg=theme["fg"], + font=("Microsoft YaHei UI", 10, "bold"), relief="flat", borderwidth=0 + ) + pipeline_section.pack(fill=tk.X, pady=(0, 8)) + pipeline_frame = tk.Frame(pipeline_section, bg=theme["card_bg"]) + pipeline_frame.pack(fill=tk.X, padx=8, pady=6) + create_modern_button(pipeline_frame, "一键处理", lambda: run_pipeline_directly(log_text, status_bar), "primary", px_width=150, px_height=32).pack(anchor='w', pady=3) + + # OCR处理区 + core_section = tk.LabelFrame( + panel_content, text="OCR处理", bg=theme["card_bg"], fg=theme["fg"], + font=("Microsoft YaHei UI", 10, "bold"), relief="flat", borderwidth=0 + ) + core_section.pack(fill=tk.X, pady=(0, 8)) + core_buttons_frame = tk.Frame(core_section, bg=theme["card_bg"]) + core_buttons_frame.pack(fill=tk.X, padx=8, pady=6) + core_row1 = tk.Frame(core_buttons_frame, bg=theme["card_bg"]) + core_row1.pack(fill=tk.X, pady=3) + create_modern_button(core_row1, "批量识别", lambda: batch_ocr_with_status(log_text, status_bar), "primary", px_width=72, px_height=32).pack(side=tk.LEFT, padx=(0, 3)) + create_modern_button(core_row1, "单个识别", lambda: process_single_image_with_status(log_text, status_bar), "primary", px_width=72, px_height=32).pack(side=tk.LEFT, padx=(3, 0)) + + # Excel处理区 + ocr_section = tk.LabelFrame( + panel_content, text="Excel处理", bg=theme["card_bg"], fg=theme["fg"], + font=("Microsoft YaHei UI", 10, "bold"), relief="flat", borderwidth=0 + ) + ocr_section.pack(fill=tk.X, pady=(0, 8)) + ocr_buttons_frame = tk.Frame(ocr_section, bg=theme["card_bg"]) + ocr_buttons_frame.pack(fill=tk.X, padx=8, pady=6) + ocr_row1 = tk.Frame(ocr_buttons_frame, bg=theme["card_bg"]) + ocr_row1.pack(fill=tk.X, pady=3) + create_modern_button(ocr_row1, "批量处理", lambda: batch_process_orders_with_status(log_text, status_bar), "primary", px_width=72, px_height=32).pack(side=tk.LEFT, padx=(0, 3)) + create_modern_button(ocr_row1, "单个处理", lambda: process_excel_file_with_status(log_text, status_bar), "primary", px_width=72, px_height=32).pack(side=tk.LEFT, padx=(3, 0)) + + # 最近文件区 + _create_recent_files_section(panel_content, theme, log_text) + + +def _create_recent_files_section(parent, theme, log_text): + """创建最近文件列表区域""" + recent_section = tk.LabelFrame( + parent, text="最近文件", bg=theme["card_bg"], fg=theme["fg"], + font=("Microsoft YaHei UI", 10, "bold"), relief="flat", borderwidth=0 + ) + recent_section.pack(fill=tk.BOTH, pady=(0, 12)) + recent_frame = tk.Frame(recent_section, bg=theme["card_bg"]) + recent_frame.pack(fill=tk.BOTH, padx=8, pady=6) + recent_top = tk.Frame(recent_frame, bg=theme["card_bg"]) + recent_top.pack(fill=tk.X) + + def _resize_recent_top(e): + try: + h = int(e.height * 0.75) + recent_top.configure(height=h) + except Exception: + pass + + try: + recent_top.pack_propagate(False) + except Exception: + pass + recent_frame.bind('', _resize_recent_top) + + recent_rect = tk.Frame(recent_top, bg=theme["card_bg"], highlightbackground=theme["border"], highlightthickness=1) + recent_rect.pack(fill=tk.BOTH, expand=True) + recent_list = tk.Listbox(recent_rect, height=12) + recent_scrollbar = tk.Scrollbar(recent_rect) + recent_list.configure(yscrollcommand=recent_scrollbar.set) + recent_scrollbar.configure(command=recent_list.yview) + recent_list.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + recent_scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + + import app.ui.user_settings as _us_mod + _us_mod.RECENT_LIST_WIDGET = recent_list + + def _open_selected_event(evt=None): + try: + idxs = recent_list.curselection() + if not idxs: + return + p = _extract_path_from_recent_item(recent_list.get(idxs[0])) + if os.path.exists(p): + os.startfile(p) + else: + messagebox.showwarning("文件不存在", p) + except Exception as e: + messagebox.showerror("打开失败", str(e)) + + recent_list.bind('', _open_selected_event) + refresh_recent_list_widget() + rf_btns = tk.Frame(recent_frame, bg=theme["card_bg"]) + rf_btns.pack(fill=tk.X, pady=6) + + def clear_list(): + clear_recent_files() + recent_list.delete(0, tk.END) + + create_modern_button(rf_btns, "清空列表", clear_list, "primary", px_width=72, px_height=32).pack(side=tk.LEFT, padx=(3, 0)) + + def purge_invalid(): + try: + kept = [] + for i in range(recent_list.size()): + item = recent_list.get(i) + p = _extract_path_from_recent_item(item) + if os.path.exists(p): + kept.append(p) + try: + kept_sorted = sorted(kept, key=lambda p: os.path.getmtime(p), reverse=True) + except Exception: + kept_sorted = kept + s = load_user_settings() + s['recent_files'] = kept_sorted + save_user_settings(s) + recent_list.delete(0, tk.END) + for i, p in enumerate(s['recent_files'][:recent_list.size() or len(s['recent_files'])], start=1): + recent_list.insert(tk.END, f"{i}. {p}") + refresh_recent_list_widget() + add_to_log(log_text, "已清理无效的最近文件条目\n", "success") + except Exception as e: + messagebox.showerror("清理失败", str(e)) + + create_modern_button(rf_btns, "清理无效", purge_invalid, "primary", px_width=72, px_height=32).pack(side=tk.LEFT, padx=(3, 0)) + + +def _create_right_panel(content_frame, theme, log_text, root): + """创建右侧面板:快捷操作、系统设置""" + right_panel = create_card_frame(content_frame) + right_panel.pack(side=tk.RIGHT, fill=tk.BOTH, expand=False, padx=(5, 0), pady=5) + right_panel.configure(width=380) + + right_panel_content = tk.Frame(right_panel, bg=theme["card_bg"]) + right_panel_content.pack(fill=tk.BOTH, expand=True, padx=10, pady=(5, 10)) + + # 工具功能区 + tools_section = tk.LabelFrame( + right_panel_content, text="快捷操作", bg=theme["card_bg"], fg=theme["fg"], + font=("Microsoft YaHei UI", 10, "bold"), relief="flat", borderwidth=0 + ) + tools_section.pack(fill=tk.X, pady=(0, 8)) + tools_buttons_frame = tk.Frame(tools_section, bg=theme["card_bg"]) + tools_buttons_frame.pack(fill=tk.X, padx=8, pady=6) + tk.Frame(tools_buttons_frame, bg=theme["card_bg"]).pack(fill=tk.X, pady=3) + + create_modern_button(tools_buttons_frame, "打开结果目录", lambda: open_result_directory(), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + create_modern_button(tools_buttons_frame, "打开输出目录", lambda: os.startfile(os.path.abspath("data/output")), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + create_modern_button(tools_buttons_frame, "打开输入目录", lambda: os.startfile(os.path.abspath("data/input")), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + create_modern_button(tools_buttons_frame, "合并订单", lambda: merge_orders_with_status(log_text, StatusBar(root)), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + create_modern_button(tools_buttons_frame, "清除缓存", lambda: clean_cache(log_text), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + create_modern_button(tools_buttons_frame, "清理input/out文件", lambda: clean_data_files(log_text), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + create_modern_button(tools_buttons_frame, "清理result文件", lambda: clean_result_files(log_text), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + + # 系统设置区 + settings_section = tk.LabelFrame( + right_panel_content, text="系统设置", bg=theme["card_bg"], fg=theme["fg"], + font=("Microsoft YaHei UI", 10, "bold"), relief="flat", borderwidth=0 + ) + settings_section.pack(fill=tk.X, pady=(0, 8)) + settings_buttons_frame = tk.Frame(settings_section, bg=theme["card_bg"]) + settings_buttons_frame.pack(fill=tk.X, padx=8, pady=6) + create_modern_button(settings_buttons_frame, "系统设置", lambda: show_config_dialog(root, ConfigManager()), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + create_modern_button(settings_buttons_frame, "条码映射", lambda: edit_barcode_mappings(log_text), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + create_modern_button(settings_buttons_frame, "云端同步", lambda: show_cloud_sync_dialog(root), "primary", px_width=132, px_height=32).pack(anchor='w', pady=3) + + +def _setup_drag_area(mid_container, theme, dnd_supported, log_text, status_bar): + """创建拖拽/点击选择文件区域""" + drag_panel = create_card_frame(mid_container) + drag_panel.pack(side=tk.TOP, fill=tk.X, padx=(5, 5), pady=(0, 5)) + drag_panel_content = tk.Frame(drag_panel, bg=theme["card_bg"]) + drag_panel_content.pack(fill=tk.X, padx=10, pady=6) + + dnd_section = tk.LabelFrame( + drag_panel_content, bg=theme["card_bg"], fg=theme["fg"], + font=("Microsoft YaHei UI", 10, "bold"), relief="flat", borderwidth=0 + ) + dnd_section.pack(fill=tk.X, pady=(0, 0)) + dnd_frame = tk.Frame(dnd_section, bg=theme["card_bg"], highlightthickness=1, highlightbackground=theme["border"]) + dnd_frame.configure(height=60) + dnd_frame.pack(fill=tk.X, padx=8, pady=6) + try: + dnd_frame.pack_propagate(False) + except Exception: + pass + + def _set_highlight(active: bool): + try: + dnd_frame.configure(highlightbackground=theme["info"] if active else theme["border"]) + except Exception: + pass + + dnd_frame.bind('', lambda e: _set_highlight(True)) + dnd_frame.bind('', lambda e: _set_highlight(False)) + + msg_row = tk.Frame(dnd_frame, bg=theme["card_bg"]) + msg_row.pack(fill=tk.X) + if dnd_supported: + tk.Label( + msg_row, text="拖拽已启用:拖拽或点击此区域选择文件", + bg=theme["card_bg"], fg="#999999", justify="center" + ).pack(fill=tk.X) + else: + tk.Label( + msg_row, text="点击此区域选择文件;可安装拖拽支持", + bg=theme["card_bg"], fg="#999999", justify="center" + ).pack(fill=tk.X) + + if not dnd_supported: + btn_row = tk.Frame(dnd_frame, bg=theme["card_bg"]) + btn_row.pack(fill=tk.X) + + def copy_install(): + try: + mid_container.winfo_toplevel().clipboard_clear() + mid_container.winfo_toplevel().clipboard_append("pip install tkinterdnd2") + messagebox.showinfo("已复制", "已复制安装命令:pip install tkinterdnd2") + except Exception as e: + messagebox.showwarning("复制失败", str(e)) + + create_modern_button(btn_row, "复制安装命令", copy_install, "primary", px_width=132, px_height=28).pack(side=tk.RIGHT) + + def install_and_restart(): + try: + add_to_log(log_text, "开始安装拖拽支持库 tkinterdnd2...\n", "info") + cmd = [sys.executable, "-m", "pip", "install", "tkinterdnd2"] + result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + add_to_log(log_text, result.stdout + "\n", "info") + add_to_log(log_text, "安装成功,准备重启程序以启用拖拽...\n", "success") + if messagebox.askyesno("安装完成", "已安装拖拽支持,是否立即重启应用?"): + os.execl(sys.executable, sys.executable, *sys.argv) + except subprocess.CalledProcessError as e: + add_to_log(log_text, f"安装失败: {e.stderr}\n", "error") + messagebox.showerror("安装失败", f"安装输出:\n{e.stderr}") + except Exception as e: + add_to_log(log_text, f"安装失败: {str(e)}\n", "error") + messagebox.showerror("安装失败", str(e)) + + create_modern_button(btn_row, "一键安装拖拽", install_and_restart, "primary", px_width=132, px_height=28).pack(side=tk.RIGHT, padx=(3, 0)) + + # 点击拖拽框选择文件 + def _click_select(evt=None): + try: + files = filedialog.askopenfilenames( + title="选择图片或Excel文件", + filetypes=[ + ("支持文件", "*.xlsx *.xls *.jpg *.jpeg *.png *.bmp"), + ("Excel", "*.xlsx *.xls"), + ("图片", "*.jpg *.jpeg *.png *.bmp"), + ("所有文件", "*.*"), + ] + ) + if not files: + return + for p in files: + process_dropped_file(log_text, status_bar, p) + except Exception as e: + messagebox.showerror("选择失败", str(e)) + + dnd_frame.bind('', _click_select) + msg_row.bind('', _click_select) + + if dnd_supported: + def _on_drop(event): + try: + data = event.data + paths = [] + buf = "" + in_brace = False + for ch in data: + if ch == '{': + in_brace = True + buf = "" + elif ch == '}': + in_brace = False + paths.append(buf) + buf = "" + elif ch == ' ' and not in_brace: + if buf: + paths.append(buf) + buf = "" + else: + buf += ch + if buf: + paths.append(buf) + for p in paths: + process_dropped_file(log_text, status_bar, p) + except Exception as e: + add_to_log(log_text, f"拖拽处理失败: {str(e)}\n", "error") + + try: + from tkinterdnd2 import DND_FILES + dnd_frame.drop_target_register(DND_FILES) + dnd_frame.dnd_bind('<>', _on_drop) + except Exception: + pass + + +def _create_log_panel(mid_container, theme): + """创建中间日志面板,返回 log_text widget""" + log_panel = create_card_frame(mid_container, "处理日志") + log_panel.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=(5, 5), pady=5) + + log_text = scrolledtext.ScrolledText( + log_panel, wrap=tk.WORD, width=68, height=26, + bg=theme["log_bg"], fg=theme["log_fg"], + font=("Consolas", 9), state=tk.DISABLED, + relief="flat", borderwidth=0 + ) + log_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=(5, 10)) + + log_text.tag_configure("command", foreground=theme["info"], font=("Consolas", 9, "bold")) + log_text.tag_configure("time", foreground=theme["secondary_bg"], font=("Consolas", 8)) + log_text.tag_configure("separator", foreground=theme["border"]) + log_text.tag_configure("success", foreground=theme["success"], font=("Consolas", 9, "bold")) + log_text.tag_configure("error", foreground=theme["error"], font=("Consolas", 9, "bold")) + log_text.tag_configure("warning", foreground=theme["warning"], font=("Consolas", 9, "bold")) + log_text.tag_configure("info", foreground=theme["info"], font=("Consolas", 9)) + + poll_log_queue(log_text) + + add_to_log(log_text, "欢迎使用 益选-OCR订单处理系统 v1.1.0\n", "success") + add_to_log(log_text, "系统已就绪,请选择相应功能进行操作。\n\n", "info") + add_to_log(log_text, "功能说明:\n", "command") + add_to_log(log_text, "• 完整处理流程:一键完成OCR识别和Excel处理\n", "info") + add_to_log(log_text, "• 批量处理订单:批量处理多个订单文件\n", "info") + add_to_log(log_text, "• 处理烟草订单:专门处理烟草类订单\n", "info") + add_to_log(log_text, "• 合并订单:将多个订单合并为一个文件\n\n", "info") + add_to_log(log_text, "请将需要处理的图片文件放入 data/input 目录中。\n", "warning") + add_to_log(log_text, "OCR识别结果保存在 data/output 目录,处理完成的订单保存在 result 目录中。\n\n", "warning") + add_to_log(log_text, "=" * 50 + "\n\n", "separator") + + return log_text + + +def main(): + """主函数""" + try: + root, theme, settings, dnd_supported = _init_window() + + # 主容器 + main_container = tk.Frame(root, bg=theme["bg"]) + main_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) + content_frame = tk.Frame(main_container, bg=theme["bg"]) + content_frame.pack(fill=tk.BOTH, expand=True) + + # 中间容器(拖拽区 + 日志区) + mid_container = tk.Frame(content_frame, bg=theme["bg"]) + mid_container.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(5, 5), pady=5) + + log_text = _create_log_panel(mid_container, theme) + + # 状态栏 + status_bar = StatusBar(root) + status_bar.pack(side=tk.BOTTOM, fill=tk.X) + + # 左侧面板 + _create_left_panel(content_frame, theme, log_text, status_bar) + + # 右侧面板 + _create_right_panel(content_frame, theme, log_text, root) + + # 拖拽区域 + _setup_drag_area(mid_container, theme, dnd_supported, log_text, status_bar) + + # 快捷键 + 关闭事件 + def on_close(): + try: + w = root.winfo_width() + h = root.winfo_height() + settings['window_size'] = f"{w}x{h}" + settings['theme_mode'] = get_theme_mode() + save_user_settings(settings) + except Exception: + pass + root.destroy() + + root.protocol("WM_DELETE_WINDOW", on_close) + bind_keyboard_shortcuts(root, log_text, status_bar) + + root.mainloop() + + except Exception as e: + import traceback + error_msg = f"程序启动失败: {str(e)}\n详细错误信息:\n{traceback.format_exc()}" + print(error_msg) + try: + import tkinter.messagebox as mb + mb.showerror("启动错误", f"程序启动失败:\n{str(e)}") + except Exception: + pass diff --git a/app/ui/result_previews.py b/app/ui/result_previews.py new file mode 100644 index 0000000..6ee53ca --- /dev/null +++ b/app/ui/result_previews.py @@ -0,0 +1,371 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""处理结果预览对话框模块""" + +import os +import re +import datetime +import tkinter as tk +from tkinter import messagebox, scrolledtext + +from .theme import THEMES, get_theme_mode, apply_theme +from .ui_widgets import center_window +from app.core.utils.file_utils import format_file_size + +TOBACCO_PREVIEW_WINDOW = None + + +def show_result_preview(command, output): + """显示处理结果预览""" + if "ocr" in command: + show_ocr_result_preview(output) + elif "excel" in command: + show_excel_result_preview(output) + elif "merge" in command: + show_merge_result_preview(output) + elif "pipeline" in command: + show_pipeline_result_preview(output) + else: + messagebox.showinfo("处理完成", "操作已成功完成!\n请在data/output目录查看结果。") + + +def show_ocr_result_preview(output): + """显示OCR处理结果预览""" + files_match = re.search(r'找到 (\d+) 个图片文件,其中 (\d+) 个未处理', output) + processed_match = re.search(r'所有图片处理完成, 总计: (\d+), 成功: (\d+)', output) + + if processed_match: + total = int(processed_match.group(1)) + success = int(processed_match.group(2)) + + preview = tk.Toplevel() + preview.title("OCR处理结果") + preview.geometry("400x300") + preview.resizable(False, False) + center_window(preview) + + tk.Label(preview, text="OCR处理完成", font=("Arial", 16, "bold")).pack(pady=10) + + result_frame = tk.Frame(preview) + result_frame.pack(pady=10, fill=tk.BOTH, expand=True) + + tk.Label(result_frame, text=f"总共处理: {total} 个文件", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text=f"成功处理: {success} 个文件", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text=f"失败数量: {total - success} 个文件", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + + if success == total: + result_text = "全部处理成功!" + result_color = "#28a745" + elif success > total * 0.8: + result_text = "大部分处理成功。" + result_color = "#ffc107" + else: + result_text = "处理失败较多,请检查日志。" + result_color = "#dc3545" + + tk.Label(result_frame, text=result_text, font=("Arial", 12, "bold"), fg=result_color).pack(pady=10) + + button_frame = tk.Frame(preview) + button_frame.pack(pady=10) + + tk.Button(button_frame, text="查看输出文件", command=lambda: os.startfile(os.path.abspath("data/output"))).pack(side=tk.LEFT, padx=10) + tk.Button(button_frame, text="关闭", command=preview.destroy).pack(side=tk.LEFT, padx=10) + else: + messagebox.showinfo("OCR处理完成", "OCR处理已完成,请在data/output目录查看结果。") + + +def show_excel_result_preview(output): + """显示Excel处理结果预览""" + extract_match = re.search(r'提取到 (\d+) 个商品信息', output) + file_match = re.search(r'采购单已保存到: (.+?)(?:\n|$)', output) + + if extract_match and file_match: + products_count = int(extract_match.group(1)) + output_file = file_match.group(1) + + preview = tk.Toplevel() + preview.title("Excel处理结果") + preview.geometry("450x320") + preview.resizable(False, False) + center_window(preview) + + tk.Label(preview, text="Excel处理完成", font=("Arial", 16, "bold")).pack(pady=10) + + result_frame = tk.Frame(preview) + result_frame.pack(pady=10, fill=tk.BOTH, expand=True) + + tk.Label(result_frame, text=f"提取商品数量: {products_count} 个", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text=f"输出文件: {os.path.basename(output_file)}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + + tk.Label(result_frame, text="采购单已成功生成!", font=("Arial", 12, "bold"), fg="#28a745").pack(pady=10) + + file_frame = tk.Frame(result_frame, relief=tk.GROOVE, borderwidth=1) + file_frame.pack(fill=tk.X, padx=15, pady=5) + + tk.Label(file_frame, text="文件信息", font=("Arial", 10, "bold")).pack(anchor=tk.W, padx=10, pady=5) + + try: + file_size = os.path.getsize(output_file) + file_time = datetime.datetime.fromtimestamp(os.path.getmtime(output_file)) + size_text = format_file_size(file_size) + tk.Label(file_frame, text=f"文件大小: {size_text}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2) + tk.Label(file_frame, text=f"创建时间: {file_time.strftime('%Y-%m-%d %H:%M:%S')}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2) + except Exception: + tk.Label(file_frame, text="无法获取文件信息", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2) + + button_frame = tk.Frame(preview) + button_frame.pack(pady=10) + + tk.Button(button_frame, text="打开文件", command=lambda: os.startfile(output_file)).pack(side=tk.LEFT, padx=5) + tk.Button(button_frame, text="打开所在文件夹", command=lambda: os.startfile(os.path.dirname(output_file))).pack(side=tk.LEFT, padx=5) + tk.Button(button_frame, text="关闭", command=preview.destroy).pack(side=tk.LEFT, padx=5) + else: + messagebox.showinfo("Excel处理完成", "Excel处理已完成,请在data/output目录查看结果。") + + +def show_merge_result_preview(output): + """显示合并结果预览""" + merged_match = re.search(r'合并了 (\d+) 个采购单', output) + product_match = re.search(r'共处理 (\d+) 个商品', output) + output_match = re.search(r'已保存到: (.+?)(?:\n|$)', output) + + if merged_match and output_match: + merged_count = int(merged_match.group(1)) + product_count = int(product_match.group(1)) if product_match else 0 + output_file = output_match.group(1) + + preview = tk.Toplevel() + preview.title("采购单合并结果") + preview.geometry("450x300") + preview.resizable(False, False) + apply_theme(preview) + + tk.Label(preview, text="采购单合并完成", font=("Arial", 16, "bold")).pack(pady=10) + + result_frame = tk.Frame(preview) + result_frame.pack(pady=10, fill=tk.BOTH, expand=True) + + tk.Label(result_frame, text=f"合并采购单数量: {merged_count} 个", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text=f"处理商品数量: {product_count} 个", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text=f"输出文件: {os.path.basename(output_file)}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + + theme = THEMES[get_theme_mode()] + tk.Label(result_frame, text="采购单已成功合并!", font=("Arial", 12, "bold"), fg=theme["success"]).pack(pady=10) + + button_frame = tk.Frame(preview) + button_frame.pack(pady=10) + + tk.Button(button_frame, text="打开文件", command=lambda: os.startfile(output_file)).pack(side=tk.LEFT, padx=10) + tk.Button(button_frame, text="打开所在文件夹", command=lambda: os.startfile(os.path.dirname(output_file))).pack(side=tk.LEFT, padx=10) + tk.Button(button_frame, text="关闭", command=preview.destroy).pack(side=tk.LEFT, padx=10) + else: + messagebox.showinfo("采购单合并完成", "采购单合并已完成,请在data/output目录查看结果。") + + +def show_pipeline_result_preview(output): + """显示完整流程结果预览""" + ocr_match = re.search(r'所有图片处理完成, 总计: (\d+), 成功: (\d+)', output) + excel_match = re.search(r'提取到 (\d+) 个商品信息', output) + output_file_match = re.search(r'采购单已保存到: (.+?)(?:\n|$)', output) + + preview = tk.Toplevel() + preview.title("完整流程处理结果") + preview.geometry("500x400") + preview.resizable(False, False) + center_window(preview) + + tk.Label(preview, text="完整处理流程已完成", font=("Arial", 16, "bold")).pack(pady=10) + + no_files_match = re.search(r'未找到可合并的文件', output) + if no_files_match: + tk.Label(preview, text="未找到可合并的文件,但其他步骤已成功执行", font=("Arial", 12)).pack(pady=0) + + result_frame = tk.Frame(preview) + result_frame.pack(pady=10, fill=tk.BOTH, expand=True) + + result_text = scrolledtext.ScrolledText(result_frame, wrap=tk.WORD, height=15, width=60) + result_text.pack(fill=tk.BOTH, expand=True, padx=15, pady=5) + result_text.configure(state=tk.NORMAL) + + result_text.insert(tk.END, "===== 流程执行结果 =====\n\n", "title") + + result_text.insert(tk.END, "步骤1: OCR识别\n", "step") + if ocr_match: + total = int(ocr_match.group(1)) + success = int(ocr_match.group(2)) + result_text.insert(tk.END, f" 处理图片: {total} 个\n", "info") + result_text.insert(tk.END, f" 成功识别: {success} 个\n", "info") + if success == total: + result_text.insert(tk.END, " 结果: 全部识别成功\n", "success") + else: + result_text.insert(tk.END, f" 结果: 部分识别成功 ({success}/{total})\n", "warning") + else: + result_text.insert(tk.END, " 结果: 无OCR处理或处理信息不完整\n", "warning") + + result_text.insert(tk.END, "\n步骤2: Excel处理\n", "step") + if excel_match: + products = int(excel_match.group(1)) + result_text.insert(tk.END, f" 提取商品: {products} 个\n", "info") + result_text.insert(tk.END, " 结果: 成功生成采购单\n", "success") + if output_file_match: + output_file = output_file_match.group(1) + result_text.insert(tk.END, f" 输出文件: {os.path.basename(output_file)}\n", "info") + else: + result_text.insert(tk.END, " 结果: 无Excel处理或处理信息不完整\n", "warning") + + result_text.insert(tk.END, "\n===== 整体评估 =====\n", "title") + + has_errors = "错误" in output or "失败" in output + + no_files_match2 = re.search(r'未找到采购单文件', output) + single_file_match = re.search(r'只有1个采购单文件', output) + + if no_files_match2: + result_text.insert(tk.END, "没有找到可合并的文件,但处理流程已成功完成。\n", "warning") + result_text.insert(tk.END, "可以选择打开Excel文件或查看输出文件夹。\n", "info") + elif single_file_match: + result_text.insert(tk.END, "只有一个采购单文件,无需合并,处理流程已成功完成。\n", "warning") + result_text.insert(tk.END, "可以选择打开生成的Excel文件。\n", "info") + elif ocr_match and excel_match and not has_errors: + result_text.insert(tk.END, "流程完整执行成功!\n", "success") + elif ocr_match or excel_match: + result_text.insert(tk.END, "流程部分执行成功,请检查日志获取详情。\n", "warning") + else: + result_text.insert(tk.END, "流程执行可能存在问题,请查看详细日志。\n", "error") + + result_text.tag_configure("title", font=("Arial", 12, "bold")) + result_text.tag_configure("step", font=("Arial", 11, "bold")) + result_text.tag_configure("info", font=("Arial", 10)) + result_text.tag_configure("success", font=("Arial", 10, "bold"), foreground="#28a745") + result_text.tag_configure("warning", font=("Arial", 10, "bold"), foreground="#ffc107") + result_text.tag_configure("error", font=("Arial", 10, "bold"), foreground="#dc3545") + + result_text.configure(state=tk.DISABLED) + + button_frame = tk.Frame(preview) + button_frame.pack(pady=10) + + if output_file_match: + output_file = output_file_match.group(1) + tk.Button(button_frame, text="打开Excel文件", command=lambda: os.startfile(output_file)).pack(side=tk.LEFT, padx=10) + else: + if excel_match or no_files_match or single_file_match: + output_dir = os.path.abspath("data/output") + excel_files = [f for f in os.listdir(output_dir) if f.startswith('采购单_') and (f.endswith('.xls') or f.endswith('.xlsx'))] + if excel_files: + excel_files.sort(key=lambda x: os.path.getmtime(os.path.join(output_dir, x)), reverse=True) + latest_file = os.path.join(output_dir, excel_files[0]) + tk.Button(button_frame, text="打开最新Excel文件", + command=lambda: os.startfile(latest_file)).pack(side=tk.LEFT, padx=10) + + tk.Button(button_frame, text="查看输出文件夹", command=lambda: os.startfile(os.path.abspath("data/output"))).pack(side=tk.LEFT, padx=10) + tk.Button(button_frame, text="关闭", command=preview.destroy).pack(side=tk.LEFT, padx=10) + + +def show_tobacco_result_preview(returncode, output): + """显示烟草订单处理结果预览""" + global TOBACCO_PREVIEW_WINDOW + if returncode != 0: + return + + try: + try: + if TOBACCO_PREVIEW_WINDOW and TOBACCO_PREVIEW_WINDOW.winfo_exists(): + TOBACCO_PREVIEW_WINDOW.lift() + return + except Exception: + TOBACCO_PREVIEW_WINDOW = None + + result_file = None + order_time = "(未知)" + total_amount = "(未知)" + items_count = 0 + + abs_path_match = re.search(r'烟草订单处理完成,绝对路径: (.+)(?:\n|$)', output) + if abs_path_match: + result_file = abs_path_match.group(1).strip() + + for line in output.split('\n'): + if "烟草公司订单处理成功" in line and "订单时间" in line: + time_match = re.search(r'订单时间: ([^,]+)', line) + amount_match = re.search(r'总金额: ([^,]+)', line) + items_match = re.search(r'处理条目: (\d+)', line) + + if time_match: + order_time = time_match.group(1).strip() + if amount_match: + total_amount = amount_match.group(1).strip() + if items_match: + items_count = int(items_match.group(1).strip()) + + if not result_file or not os.path.exists(result_file): + default_path = os.path.abspath("data/output/银豹采购单_烟草公司.xls") + if os.path.exists(default_path): + result_file = default_path + + preview = tk.Toplevel() + preview.title("烟草订单处理结果") + preview.geometry("450x320") + preview.resizable(False, False) + TOBACCO_PREVIEW_WINDOW = preview + + def _close_preview(): + global TOBACCO_PREVIEW_WINDOW + TOBACCO_PREVIEW_WINDOW = None + try: + preview.destroy() + except Exception: + pass + + preview.protocol("WM_DELETE_WINDOW", _close_preview) + center_window(preview) + + tk.Label(preview, text="烟草订单处理完成", font=("Arial", 16, "bold")).pack(pady=10) + + result_frame = tk.Frame(preview) + result_frame.pack(pady=10, fill=tk.BOTH, expand=True) + + tk.Label(result_frame, text=f"订单时间: {order_time}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text=f"订单总金额: {total_amount}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text=f"处理商品数量: {items_count} 个", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + + if result_file and os.path.exists(result_file): + tk.Label(result_frame, text=f"输出文件: {os.path.basename(result_file)}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text="银豹采购单已成功生成!", font=("Arial", 12, "bold"), fg="#28a745").pack(pady=10) + + file_frame = tk.Frame(result_frame, relief=tk.GROOVE, borderwidth=1) + file_frame.pack(fill=tk.X, padx=15, pady=5) + tk.Label(file_frame, text="文件信息", font=("Arial", 10, "bold")).pack(anchor=tk.W, padx=10, pady=5) + + try: + file_size = os.path.getsize(result_file) + file_time = datetime.datetime.fromtimestamp(os.path.getmtime(result_file)) + size_text = format_file_size(file_size) + tk.Label(file_frame, text=f"文件大小: {size_text}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2) + tk.Label(file_frame, text=f"创建时间: {file_time.strftime('%Y-%m-%d %H:%M:%S')}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2) + except Exception: + tk.Label(file_frame, text="无法获取文件信息", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2) + + button_frame = tk.Frame(preview) + button_frame.pack(pady=10) + tk.Button(button_frame, text="打开文件", command=lambda: os.startfile(result_file)).pack(side=tk.LEFT, padx=5) + tk.Button(button_frame, text="打开所在文件夹", command=lambda: os.startfile(os.path.dirname(result_file))).pack(side=tk.LEFT, padx=5) + tk.Button(button_frame, text="关闭", command=_close_preview).pack(side=tk.LEFT, padx=5) + else: + tk.Label(result_frame, text="未找到输出文件", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5) + tk.Label(result_frame, text="请检查data/output目录", font=("Arial", 12, "bold"), fg="#dc3545").pack(pady=10) + + button_frame = tk.Frame(preview) + button_frame.pack(pady=10) + tk.Button(button_frame, text="打开输出目录", command=lambda: os.startfile(os.path.abspath("data/output"))).pack(side=tk.LEFT, padx=5) + tk.Button(button_frame, text="关闭", command=_close_preview).pack(side=tk.LEFT, padx=5) + + preview.lift() + preview.attributes('-topmost', True) + preview.after_idle(lambda: preview.attributes('-topmost', False)) + + except Exception as e: + messagebox.showerror( + "处理异常", + f"显示预览时发生错误: {e}\n请检查日志了解详细信息。" + ) diff --git a/app/ui/shortcuts.py b/app/ui/shortcuts.py new file mode 100644 index 0000000..2aa3b5e --- /dev/null +++ b/app/ui/shortcuts.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""键盘快捷键模块""" + +import tkinter as tk +from tkinter import messagebox + +from .ui_widgets import center_window +from .action_handlers import ( + process_single_image_with_status, + process_excel_file_with_status, + batch_ocr_with_status, + run_pipeline_directly, + merge_orders_with_status, +) +from .file_operations import clean_cache + + +def bind_keyboard_shortcuts(root, log_widget, status_bar): + """绑定键盘快捷键""" + root.bind('', lambda e: process_single_image_with_status(log_widget, status_bar)) + root.bind('', lambda e: process_excel_file_with_status(log_widget, status_bar)) + root.bind('', lambda e: batch_ocr_with_status(log_widget, status_bar)) + root.bind('', lambda e: run_pipeline_directly(log_widget, status_bar)) + root.bind('', lambda e: merge_orders_with_status(log_widget, status_bar)) + root.bind('', lambda e: clean_cache(log_widget)) + root.bind('', lambda e: root.quit() if messagebox.askyesno("确认退出", "确定要退出程序吗?") else None) + root.bind('', lambda e: show_shortcuts_help()) + + +def show_shortcuts_help(): + """显示快捷键帮助对话框""" + help_dialog = tk.Toplevel() + help_dialog.title("快捷键帮助") + help_dialog.geometry("400x450") + center_window(help_dialog) + + tk.Label(help_dialog, text="键盘快捷键", font=("Arial", 16, "bold")).pack(pady=10) + + help_text = tk.Text(help_dialog, wrap=tk.WORD, width=50, height=20) + help_text.pack(padx=20, pady=10, fill=tk.BOTH, expand=True) + + shortcuts = """ + Ctrl+O: 处理单个图片 + Ctrl+E: 处理Excel文件 + Ctrl+B: OCR批量识别 + Ctrl+P: 完整处理流程 + Ctrl+M: 合并采购单 + F5: 清除处理缓存 + Esc: 退出程序 + """ + + help_text.insert(tk.END, shortcuts) + help_text.configure(state=tk.DISABLED) + + tk.Button(help_dialog, text="确定", command=help_dialog.destroy).pack(pady=10) + + help_dialog.lift() + help_dialog.attributes('-topmost', True) + help_dialog.after_idle(lambda: help_dialog.attributes('-topmost', False)) diff --git a/app/ui/theme.py b/app/ui/theme.py new file mode 100644 index 0000000..6a80618 --- /dev/null +++ b/app/ui/theme.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""主题管理模块""" + +import tkinter as tk +from tkinter import scrolledtext, ttk + +# 私有主题模式变量 +_theme_mode = "light" + +# 浅色和深色主题颜色 +THEMES = { + "light": { + "bg": "#f8f9fa", + "fg": "#212529", + "button_bg": "#ffffff", + "button_fg": "#495057", + "button_hover": "#e9ecef", + "primary_bg": "#007bff", + "primary_fg": "#ffffff", + "secondary_bg": "#6c757d", + "secondary_fg": "#ffffff", + "log_bg": "#ffffff", + "log_fg": "#212529", + "highlight_bg": "#007bff", + "highlight_fg": "#ffffff", + "border": "#dee2e6", + "success": "#28a745", + "error": "#dc3545", + "warning": "#ffc107", + "info": "#17a2b8", + "card_bg": "#ffffff", + "shadow": "#00000010" + }, + "dark": { + "bg": "#1a1a1a", + "fg": "#e9ecef", + "button_bg": "#343a40", + "button_fg": "#e9ecef", + "button_hover": "#495057", + "primary_bg": "#0d6efd", + "primary_fg": "#ffffff", + "secondary_bg": "#6c757d", + "secondary_fg": "#ffffff", + "log_bg": "#212529", + "log_fg": "#e9ecef", + "highlight_bg": "#0d6efd", + "highlight_fg": "#ffffff", + "border": "#495057", + "success": "#198754", + "error": "#dc3545", + "warning": "#ffc107", + "info": "#0dcaf0", + "card_bg": "#2d3748", + "shadow": "#00000030" + } +} + + +def get_theme_mode() -> str: + return _theme_mode + + +def set_theme_mode(mode: str): + global _theme_mode + _theme_mode = mode + + +def create_modern_button(parent, text, command, style="primary", width=None, height=None, px_width=None, px_height=None): + """创建现代化样式的按钮""" + theme = THEMES[_theme_mode] + + if style == "primary": + bg_color = "white" + fg_color = theme["primary_bg"] + hover_color = "#f0f8ff" + border_color = theme["primary_bg"] + elif style == "secondary": + bg_color = theme["secondary_bg"] + fg_color = theme["secondary_fg"] + hover_color = theme["button_hover"] + border_color = theme["secondary_bg"] + else: + bg_color = "white" + fg_color = theme["primary_bg"] + hover_color = "#f0f8ff" + border_color = theme["primary_bg"] + + button_frame = tk.Frame(parent, bg=border_color, highlightthickness=0) + button_frame.configure(relief="flat", bd=0) + if px_width or px_height: + try: + w = px_width if px_width else button_frame.winfo_reqwidth() + h = px_height if px_height else 32 + button_frame.configure(width=w, height=h) + button_frame.pack_propagate(False) + except Exception: + pass + + button = tk.Button( + button_frame, + text=text, + command=command, + bg=bg_color, + fg=fg_color, + font=("Microsoft YaHei UI", 8), + relief="flat", + bd=0, + padx=14, + pady=4, + anchor="center", + cursor="hand2", + activebackground=hover_color, + activeforeground=fg_color + ) + + if width: + button.configure(width=width) + else: + button.configure(width=12) + if height is not None: + button.configure(height=height) + else: + button.configure(height=1) + if height: + button.configure(height=height) + + # 悬停效果 + def on_enter(e): + button.configure(bg=hover_color) + + def on_leave(e): + button.configure(bg=bg_color) + + button.bind("", on_enter) + button.bind("", on_leave) + button_frame.bind("", on_enter) + button_frame.bind("", on_leave) + + button.pack(fill=tk.BOTH, expand=True, padx=1, pady=1) + return button_frame + + +def create_card_frame(parent, title=None): + """创建卡片样式的框架""" + theme = THEMES[_theme_mode] + + card = tk.Frame( + parent, + bg=theme["card_bg"], + relief="flat", + borderwidth=1, + highlightbackground=theme["border"], + highlightthickness=1 + ) + + if title: + title_label = tk.Label( + card, + text=title, + bg=theme["card_bg"], + fg=theme["fg"], + font=("Microsoft YaHei UI", 10, "bold") + ) + title_label.pack(pady=(6, 3)) + + return card + + +def apply_theme(widget, theme_mode=None): + """应用主题到小部件""" + if theme_mode is None: + theme_mode = _theme_mode + + theme = THEMES[theme_mode] + + try: + widget.configure(bg=theme["bg"], fg=theme["fg"]) + except Exception: + pass + + for child in widget.winfo_children(): + if isinstance(child, tk.Button) and not isinstance(child, ttk.Button): + child.configure(bg=theme["button_bg"], fg=theme["button_fg"]) + elif isinstance(child, scrolledtext.ScrolledText): + child.configure(bg=theme["log_bg"], fg=theme["log_fg"]) + else: + try: + child.configure(bg=theme["bg"], fg=theme["fg"]) + except Exception: + pass + + apply_theme(child, theme_mode) diff --git a/app/ui/ui_widgets.py b/app/ui/ui_widgets.py new file mode 100644 index 0000000..979eb7e --- /dev/null +++ b/app/ui/ui_widgets.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""UI控件模块 - StatusBar、ProgressReporter、可折叠框架等""" + +import tkinter as tk +from tkinter import ttk + +from .theme import THEMES, get_theme_mode + + +class StatusBar(tk.Frame): + """状态栏,显示当前系统状态和进度""" + + def __init__(self, master, **kwargs): + super().__init__(master, **kwargs) + self.configure(height=25, relief=tk.SUNKEN, borderwidth=1) + + self.status_label = tk.Label(self, text="就绪", anchor=tk.W, padx=5) + self.status_label.pack(side=tk.LEFT, fill=tk.X, expand=True) + + self.progress = ttk.Progressbar(self, orient=tk.HORIZONTAL, length=200, mode='determinate') + self.progress.pack(side=tk.RIGHT, padx=5, pady=2) + + self.progress.pack_forget() + + def set_status(self, text, progress=None): + """设置状态栏文本和进度""" + self.status_label.config(text=text) + + if progress is not None and 0 <= progress <= 100: + self.progress.pack(side=tk.RIGHT, padx=5, pady=2) + self.progress.config(value=progress) + else: + self.progress.pack_forget() + + def set_running(self, is_running=True): + """设置运行状态""" + theme = THEMES[get_theme_mode()] + if is_running: + self.status_label.config(text="处理中...", foreground=theme["info"]) + self.progress.pack(side=tk.RIGHT, padx=5, pady=2) + self.progress.config(mode='indeterminate') + self.progress.start() + else: + self.status_label.config(text="就绪", foreground=theme["fg"]) + self.progress.stop() + self.progress.pack_forget() + + +class ProgressReporter: + def __init__(self, status_bar: StatusBar): + self.status_bar = status_bar + + def set(self, text: str, percent: int = None): + try: + if percent is not None: + self.status_bar.set_status(text, percent) + else: + self.status_bar.set_status(text) + except Exception: + pass + + def running(self): + try: + self.status_bar.set_running(True) + except Exception: + pass + + def done(self): + try: + self.status_bar.set_running(False) + self.status_bar.set_status("就绪") + except Exception: + pass + + +def create_collapsible_frame(parent, title, initial_state=True): + """创建可折叠的面板""" + frame = tk.Frame(parent) + frame.pack(fill=tk.X, pady=5) + + title_frame = tk.Frame(frame) + title_frame.pack(fill=tk.X) + + state_var = tk.BooleanVar(value=initial_state) + indicator = "▼" if initial_state else "►" + state_label = tk.Label(title_frame, text=indicator, font=("Arial", 10, "bold")) + state_label.pack(side=tk.LEFT, padx=5) + + title_label = tk.Label(title_frame, text=title, font=("Arial", 11, "bold")) + title_label.pack(side=tk.LEFT, padx=5) + + content_frame = tk.Frame(frame) + if initial_state: + content_frame.pack(fill=tk.X, padx=20, pady=5) + + def toggle_collapse(event=None): + current_state = state_var.get() + new_state = not current_state + state_var.set(new_state) + state_label.config(text="▼" if new_state else "►") + if new_state: + content_frame.pack(fill=tk.X, padx=20, pady=5) + else: + content_frame.pack_forget() + + title_frame.bind("", toggle_collapse) + state_label.bind("", toggle_collapse) + title_label.bind("", toggle_collapse) + + return content_frame, state_var + + +def center_window(window): + """使窗口居中显示""" + window.update_idletasks() + width = window.winfo_width() + height = window.winfo_height() + x = (window.winfo_screenwidth() // 2) - (width // 2) + y = (window.winfo_screenheight() // 2) - (height // 2) + window.geometry('{}x{}+{}+{}'.format(width, height, x, y)) diff --git a/app/ui/user_settings.py b/app/ui/user_settings.py new file mode 100644 index 0000000..4a1911b --- /dev/null +++ b/app/ui/user_settings.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""用户设置与最近文件管理模块""" + +import os +import json +import re +import tkinter as tk +from typing import Dict, List, Any + +from app.core.utils.log_utils import get_logger + +logger = get_logger(__name__) + +RECENT_LIST_WIDGET = None + + +def load_user_settings(): + try: + path = os.path.abspath(os.path.join('data', 'user_settings.json')) + if os.path.exists(path): + with open(path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + logger.debug(f"加载用户设置失败: {e}") + return {} + + +def save_user_settings(settings: Dict[str, Any]): + try: + os.makedirs('data', exist_ok=True) + path = os.path.abspath(os.path.join('data', 'user_settings.json')) + with open(path, 'w', encoding='utf-8') as f: + json.dump(settings, f, ensure_ascii=False, indent=2) + except Exception as e: + logger.debug(f"保存用户设置失败: {e}") + + +def get_recent_files() -> List[str]: + s = load_user_settings() + items = s.get('recent_files', []) + if not isinstance(items, list): + return [] + + def _allowed(p: str) -> bool: + try: + if not isinstance(p, str) or not os.path.isfile(p): + return False + ext = os.path.splitext(p)[1].lower() + return ext in {'.xlsx', '.xls', '.jpg', '.jpeg', '.png', '.bmp'} + except Exception: + return False + + kept = [p for p in items if _allowed(p)] + if not kept: + candidates = [] + for d in ['data/output', 'data/result']: + try: + if os.path.exists(d): + for name in os.listdir(d): + p = os.path.join(d, name) + if _allowed(p): + candidates.append(p) + except Exception: + pass + if candidates: + kept = candidates + try: + kept_sorted = sorted(kept, key=lambda p: os.path.getmtime(p), reverse=True) + except Exception: + kept_sorted = kept + if kept_sorted != items or len(kept_sorted) != len(items): + s['recent_files'] = kept_sorted[:20] + save_user_settings(s) + return kept_sorted[:10] + + +def refresh_recent_list_widget(): + try: + global RECENT_LIST_WIDGET + if RECENT_LIST_WIDGET is None: + return + RECENT_LIST_WIDGET.delete(0, tk.END) + for i, p in enumerate(get_recent_files(), start=1): + RECENT_LIST_WIDGET.insert(tk.END, f"{i}. {p}") + except Exception as e: + logger.debug(f"刷新最近文件列表失败: {e}") + + +def _extract_path_from_recent_item(s: str) -> str: + try: + m = re.match(r'^(\d+)\.\s+(.*)$', s) + p = m.group(2) if m else s + return p.strip().strip('"') + except Exception: + return s.strip().strip('"') + + +def add_recent_file(path: str) -> None: + try: + if not path: + return + try: + if not os.path.isfile(path): + return + ext = os.path.splitext(path)[1].lower() + if ext not in {'.xlsx', '.xls', '.jpg', '.jpeg', '.png', '.bmp'}: + return + except Exception: + return + s = load_user_settings() + items = s.get('recent_files', []) + items = [p for p in items if p != path] + items.insert(0, path) + s['recent_files'] = items[:20] + save_user_settings(s) + refresh_recent_list_widget() + except Exception as e: + logger.debug(f"添加最近文件失败: {e}") + + +def clear_recent_files(): + try: + s = load_user_settings() + s['recent_files'] = [] + save_user_settings(s) + except Exception as e: + logger.debug(f"清空最近文件失败: {e}") diff --git a/build_exe.py b/build_exe.py new file mode 100644 index 0000000..6d96c45 --- /dev/null +++ b/build_exe.py @@ -0,0 +1,350 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +OCR订单处理系统 - EXE打包脚本 +============================ +自动化打包脚本,包含所有必要的资源文件和配置 +""" + +import os +import sys +import shutil +import subprocess +from pathlib import Path + +def clean_build(): + """清理之前的构建文件""" + print("清理构建目录...") + dirs_to_clean = ['build', 'dist', '__pycache__'] + for dir_name in dirs_to_clean: + if os.path.exists(dir_name): + shutil.rmtree(dir_name) + print(f"已删除: {dir_name}") + + # 删除spec文件 + spec_files = [f for f in os.listdir('.') if f.endswith('.spec')] + for spec_file in spec_files: + os.remove(spec_file) + print(f"已删除: {spec_file}") + +def create_spec_file(): + """创建PyInstaller spec文件""" + spec_content = ''' +# -*- mode: python ; coding: utf-8 -*- + +block_cipher = None + +# 需要包含的数据文件 +added_files = [ + ('config.ini', '.'), + ('config/barcode_mappings.json', 'config/'), + ('config/config.ini', 'config/'), + ('templates/银豹-采购单模板.xls', 'templates/'), + ('app', 'app'), +] + +# 需要隐式导入的模块 +hidden_imports = [ + 'tkinter', + 'tkinter.ttk', + 'tkinter.filedialog', + 'tkinter.messagebox', + 'tkinter.scrolledtext', + 'pandas', + 'numpy', + 'openpyxl', + 'xlrd', + 'xlwt', + 'xlutils', + 'requests', + 'configparser', + 'threading', + 'datetime', + 'json', + 're', + 'subprocess', + 'shutil', + 'app.config.settings', + 'app.services.ocr_service', + 'app.services.order_service', + 'app.services.tobacco_service', + 'app.core.utils.dialog_utils', + 'app.core.excel.converter', + 'app.core.db.product_db', + 'app.ui.error_utils', + 'app.ui.theme', + 'app.ui.logging_ui', + 'app.ui.ui_widgets', + 'app.ui.user_settings', + 'app.ui.result_previews', + 'app.ui.command_runner', + 'app.ui.file_operations', + 'app.ui.action_handlers', + 'app.ui.barcode_editor', + 'app.ui.config_dialog', + 'app.ui.shortcuts', + 'app.ui.main_window', +] + +a = Analysis( + ['启动器.py'], + pathex=[], + binaries=[], + datas=added_files, + hiddenimports=hidden_imports, + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) + +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='OCR订单处理系统', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) +''' + + with open('OCR订单处理系统.spec', 'w', encoding='utf-8') as f: + f.write(spec_content) + print("已创建spec文件: OCR订单处理系统.spec") + +def build_exe(): + """构建EXE文件""" + print("开始构建EXE文件...") + try: + # 注入版本信息到根config.ini + try: + root_cfg = Path('config.ini') + from datetime import datetime + version_str = datetime.now().strftime('%Y.%m.%d.%H%M') + if root_cfg.exists(): + lines = root_cfg.read_text(encoding='utf-8').splitlines() + has_app = any(l.strip().lower() == '[app]' for l in lines) + if not has_app: + lines.append('[App]') + lines.append(f'version = {version_str}') + else: + # 更新或追加version + new_lines = [] + in_app = False + app_written = False + for l in lines: + if l.strip().lower() == '[app]': + in_app = True + new_lines.append(l) + continue + if in_app and l.strip().lower().startswith('version'): + new_lines.append(f'version = {version_str}') + app_written = True + in_app = True + continue + new_lines.append(l) + if not app_written: + new_lines.append('version = ' + version_str) + lines = new_lines + root_cfg.write_text('\n'.join(lines), encoding='utf-8') + print(f"已写入版本号: {version_str}") + except Exception as e: + print(f"版本信息注入失败: {e}") + result = subprocess.run([ + 'pyinstaller', + 'OCR订单处理系统.spec' + ], check=True, capture_output=True, text=True) + print("构建成功!") + print(result.stdout) + + # 构建完成后,复制完整的配置文件到dist目录 + dist_dir = Path('dist') + + # 复制包含API密钥的配置文件 + config_file = Path('config/config.ini') + if config_file.exists(): + # 确保config目录存在 + (dist_dir / 'config').mkdir(exist_ok=True) + shutil.copy2(config_file, dist_dir / 'config') + print(f"已复制配置文件到dist: {config_file} -> {dist_dir / 'config'}") + + # 复制完整的条码映射文件 + barcode_mapping_file = Path('config/barcode_mappings.json') + if barcode_mapping_file.exists(): + shutil.copy2(barcode_mapping_file, dist_dir / 'config') + print(f"已复制条码映射文件到dist: {barcode_mapping_file} -> {dist_dir / 'config'}") + + # 复制根目录的config.ini文件(覆盖空的配置文件) + root_config_file = Path('config.ini') + if root_config_file.exists(): + shutil.copy2(root_config_file, dist_dir) + print(f"已复制根配置文件到dist: {root_config_file} -> {dist_dir}") + else: + print("警告: 根配置文件不存在,将创建缺省版本") + (dist_dir / 'config.ini').write_text('[App]\nversion = dev\n', encoding='utf-8') + + except subprocess.CalledProcessError as e: + print(f"构建失败: {e}") + print(f"错误输出: {e.stderr}") + return False + return True + +def create_portable_package(): + """创建便携版打包""" + print("创建便携版打包...") + + # 创建发布目录 + release_dir = Path('release') + if release_dir.exists(): + try: + shutil.rmtree(release_dir) + except Exception as e: + print(f"警告: 无法完全清理发布目录 (可能文件被占用): {e}") + # 如果目录还在,尝试清理能清理的部分 + for item in release_dir.iterdir(): + try: + if item.is_dir(): shutil.rmtree(item) + else: item.unlink() + except Exception: pass + + release_dir.mkdir(exist_ok=True) + + # 复制exe文件 + exe_file = Path('dist/OCR订单处理系统.exe') + if exe_file.exists(): + shutil.copy2(exe_file, release_dir) + print(f"已复制: {exe_file} -> {release_dir}") + + # 创建必要的目录结构 + dirs_to_create = ['data/input', 'data/output', 'logs', 'templates', 'config'] + for dir_path in dirs_to_create: + (release_dir / dir_path).mkdir(parents=True, exist_ok=True) + print(f"已创建目录: {dir_path}") + + # 复制配置文件(包含API密钥) + config_file = Path('config/config.ini') + if config_file.exists(): + shutil.copy2(config_file, release_dir / 'config') + print(f"已复制配置文件: {config_file} -> {release_dir / 'config'}") + else: + print(f"警告: 配置文件不存在: {config_file}") + + # 复制完整的条码映射文件 + barcode_mapping_file = Path('config/barcode_mappings.json') + if barcode_mapping_file.exists(): + shutil.copy2(barcode_mapping_file, release_dir / 'config') + print(f"已复制条码映射文件: {barcode_mapping_file} -> {release_dir / 'config'}") + else: + print(f"警告: 条码映射文件不存在: {barcode_mapping_file}") + + # 复制根目录的config.ini文件 + root_config_file = Path('config.ini') + if root_config_file.exists(): + shutil.copy2(root_config_file, release_dir) + print(f"已复制根配置文件: {root_config_file} -> {release_dir}") + else: + print(f"警告: 根配置文件不存在: {root_config_file}") + + # 复制模板文件 + template_file = Path('templates/银豹-采购单模板.xls') + if template_file.exists(): + shutil.copy2(template_file, release_dir / 'templates') + print(f"已复制模板文件: {template_file} -> {release_dir / 'templates'}") + else: + print(f"警告: 模板文件不存在: {template_file}") + item_file = Path('templates/商品资料.xlsx') + if item_file.exists(): + try: + (Path('dist') / 'templates').mkdir(exist_ok=True) + shutil.copy2(item_file, Path('dist') / 'templates') + except Exception: + pass + shutil.copy2(item_file, release_dir / 'templates') + print(f"已复制商品资料: {item_file} -> {release_dir / 'templates'}") + else: + print(f"警告: 商品资料文件不存在: {item_file}") + + # 创建README文件 + readme_content = ''' +# OCR订单处理系统 - 便携版 + +## 使用说明 +1. 双击 "OCR订单处理系统.exe" 启动程序 +2. 将需要处理的图片文件放入 data/input 目录 +3. 处理结果将保存在 data/output 目录 +4. 日志文件保存在 logs 目录 + +## 注意事项 +- 首次运行时需要配置百度OCR API密钥 +- 支持的图片格式:jpg, jpeg, png, bmp +- 单个文件大小不超过4MB + +## 目录结构 +- OCR订单处理系统.exe - 主程序 +- data/input/ - 输入图片目录 +- data/output/ - 输出结果目录 +- logs/ - 日志目录 +''' + + with open(release_dir / 'README.txt', 'w', encoding='utf-8') as f: + f.write(readme_content) + print("已创建README.txt") + + print(f"便携版打包完成,位置: {release_dir.absolute()}") + +def main(): + """主函数""" + print("=" * 50) + print("OCR订单处理系统 - EXE打包工具") + print("=" * 50) + + # 检查是否安装了PyInstaller + try: + subprocess.run(['pyinstaller', '--version'], check=True, capture_output=True) + except (subprocess.CalledProcessError, FileNotFoundError): + print("错误: 未安装PyInstaller") + print("请运行: pip install pyinstaller") + return 1 + + # 清理构建目录 + clean_build() + + # 创建spec文件 + create_spec_file() + + # 构建EXE + if not build_exe(): + return 1 + + # 创建便携版打包 + create_portable_package() + + print("\n" + "=" * 50) + print("打包完成!") + print("EXE文件位置: dist/OCR订单处理系统.exe") + print("便携版位置: release/") + print("=" * 50) + + return 0 + +if __name__ == '__main__': + sys.exit(main()) \ No newline at end of file diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..d1160e5 --- /dev/null +++ b/config.ini @@ -0,0 +1,43 @@ +[API] +api_key = +secret_key = +timeout = 30 +max_retries = 3 +retry_delay = 2 +api_url = https://aip.baidubce.com/rest/2.0/ocr/v1/table +token_url = https://aip.baidubce.com/oauth/2.0/token +form_ocr_url = https://aip.baidubce.com/rest/2.0/solution/v1/form_ocr/get_request_result + +[Paths] +input_folder = data/input +output_folder = data/output +temp_folder = data/temp +template_folder = templates +template_file = templates\银豹-采购单模板.xls +processed_record = data/processed_files.json +data_dir = data +product_db = data/product_cache.db + +[Performance] +max_workers = 4 +batch_size = 5 +skip_existing = true + +[File] +allowed_extensions = .jpg,.jpeg,.png,.bmp +excel_extension = .xlsx +max_file_size_mb = 4 + +[Templates] +purchase_order = 银豹-采购单模板.xls +item_data = 商品资料.xlsx + +[App] +version = 2026.03.30.1036 + +[Gitea] +base_url = https://gitea.94kan.cn +owner = houhuan +repo = yixuan-sync-data +token = + diff --git a/config/barcode_mappings.json b/config/barcode_mappings.json new file mode 100644 index 0000000..9d58fbb --- /dev/null +++ b/config/barcode_mappings.json @@ -0,0 +1,273 @@ +{ + "6920584471055": { + "map_to": "6920584471017", + "description": "条码映射:6920584471055 -> 6920584471017" + }, + "6925861571159": { + "map_to": "69021824", + "description": "条码映射:6925861571159 -> 69021824" + }, + "6923644268923": { + "map_to": "6923644268480", + "description": "条码映射:6923644268923 -> 6923644268480" + }, + "6925861571466": { + "map_to": "6925861571459", + "description": "条码映射:6925861571466 -> 6925861571459" + }, + "6907992508344": { + "map_to": "6907992508191", + "description": "条码映射:6907992508344 -> 6907992508191" + }, + "6903979000979": { + "map_to": "6903979000962", + "description": "条码映射:6903979000979 -> 6903979000962" + }, + "6923644283582": { + "map_to": "6923644283575", + "description": "条码映射:6923644283582 -> 6923644283575" + }, + "6923644268930": { + "map_to": "6923644268497", + "description": "条码映射:6923644268930 -> 6923644268497" + }, + "6923644268916": { + "map_to": "6923644268503", + "description": "条码映射:6923644268916 -> 6923644268503" + }, + "6923644268909": { + "map_to": "6923644268510", + "description": "条码映射:6923644268909 -> 6923644268510" + }, + "6923644299804": { + "map_to": "6923644299774", + "description": "条码映射:6923644299804 -> 6923644299774" + }, + "6923644266318": { + "map_to": "6923644266066", + "description": "条码映射:6923644266318 -> 6923644266066" + }, + "6923644210151": { + "map_to": "6923644223458", + "description": "条码映射:6923644210151 -> 6923644223458" + }, + "6907992501819": { + "map_to": "6907992500133", + "description": "条码映射:6907992501819 -> 6907992500133" + }, + "6907992502052": { + "map_to": "6907992100272", + "description": "条码映射:6907992502052 -> 6907992100272" + }, + "6907992507385": { + "map_to": "6907992507095", + "description": "条码映射:6907992507385 -> 6907992507095" + }, + "6973726149671": { + "map_to": "6973726149657", + "description": "条码映射:6973726149671 -> 6973726149657" + }, + "6977426410574": { + "map_to": "6977426410567", + "description": "条码映射:6977426410574 -> 6977426410567" + }, + "6973726149688": { + "map_to": "6973726149664", + "description": "条码映射:6973726149688 -> 6973726149664" + }, + "6935205322012": { + "map_to": "6935205320018", + "description": "条码映射:6935205322012 -> 6935205320018" + }, + "6943497411024": { + "map_to": "6943497411017", + "description": "条码映射:6943497411024 -> 6943497411017" + }, + "6921734968821": { + "map_to": "6921734968814", + "description": "条码映射:6921734968821 -> 6921734968814" + }, + "6921734968258": { + "map_to": "6921734968241", + "description": "条码映射:6921734968258 -> 6921734968241" + }, + "6921734968180": { + "map_to": "6921734968173", + "description": "条码映射:6921734968180 -> 6921734968173" + }, + "6921734908735": { + "map_to": "6935205372772", + "description": "条码映射:6921734908735 -> 6935205372772" + }, + "6923644248222": { + "map_to": "6923644248208", + "description": "条码映射:6923644248222 -> 6923644248208" + }, + "6902083881122": { + "map_to": "6902083881085", + "description": "条码映射:6902083881122 -> 6902083881085" + }, + "6907992501857": { + "map_to": "6907992500010", + "description": "条码映射:6907992501857 -> 6907992500010" + }, + "6902083891015": { + "map_to": "6902083890636", + "description": "条码映射:6902083891015 -> 6902083890636" + }, + "6923450605240": { + "map_to": "6923450605226", + "description": "条码映射:6923450605240 -> 6923450605226" + }, + "6923450605196": { + "map_to": "6923450614624", + "description": "条码映射:6923450605196 -> 6923450614624" + }, + "6923450665213": { + "map_to": "6923450665206", + "description": "条码映射:6923450665213 -> 6923450665206" + }, + "6923450666821": { + "map_to": "6923450666838", + "description": "条码映射:6923450666821 -> 6923450666838" + }, + "6923450661505": { + "map_to": "6923450661499", + "description": "条码映射:6923450661505 -> 6923450661499" + }, + "6923450676103": { + "map_to": "6923450676097", + "description": "条码映射:6923450676103 -> 6923450676097" + }, + "6923450614631": { + "map_to": "6923450614624", + "description": "条码映射:6923450614631 -> 6923450614624" + }, + "6901424334174": { + "map_to": "6973730760015", + "description": "条码映射:6901424334174 -> 6973730760015" + }, + "6958620703716": { + "map_to": "6958620703907", + "description": "条码映射:6958620703716 -> 6958620703907" + }, + "6937003706322": { + "map_to": "6937003703833", + "description": "条码映射:6937003706322 -> 6937003703833" + }, + "6950783203494": { + "map_to": "6950873203494", + "description": "条码映射:6950783203494 -> 6950873203494" + }, + "6907992501871": { + "map_to": "6907992500010", + "description": "条码映射:6907992501871 -> 6907992500010" + }, + "6907992501864": { + "map_to": "6907992100012", + "description": "条码映射:6907992501864 -> 6907992100012" + }, + "6923644264192": { + "map_to": "6923644264116", + "description": "条码映射:6923644264192 -> 6923644264116" + }, + "6923450667316": { + "map_to": "69042386", + "description": "条码映射:6923450667316 -> 69042386" + }, + "6923450653012": { + "map_to": "69021343", + "description": "条码映射:6923450653012 -> 69021343" + }, + "6923644295844": { + "map_to": "6923644285036", + "description": "条码映射:6923644295844 -> 6923644285036" + }, + "6907992513157": { + "map_to": "6907992513195", + "description": "条码映射:6907992513157 -> 6907992513195" + }, + "6902083893842": { + "map_to": "6902083907150", + "description": "条码映射:6902083893842 -> 6902083907150" + }, + "6902083904685": { + "map_to": "6902083905217", + "description": "条码映射:6902083904685 -> 6902083905217" + }, + "6917878036849": { + "map_to": "6917878036847", + "description": "条码映射:6917878036849 -> 6917878036847" + }, + "6903979000078": { + "map_to": "6903979000061", + "description": "条码映射:6903979000078 -> 6903979000061" + }, + "6937003706353": { + "map_to": "6937003706360", + "description": "条码映射:6937003706353 -> 6937003706360" + }, + "6923644242961": { + "map_to": "6907992100043", + "description": "条码映射:6923644242961 -> 6907992100043" + }, + "6923644258382": { + "map_to": "6923644252823", + "description": "条码映射:6923644258382 -> 6923644252823" + }, + "6923450657430": { + "map_to": "69029110", + "description": "条码映射:6923450657430 -> 69029110" + }, + "6923450660232": { + "map_to": "6923450690123", + "description": "条码映射:6923450660232 -> 6923450690123" + }, + "6923450657614": { + "map_to": "6923450657607", + "description": "条码映射:6923450657614 -> 6923450657607" + }, + "6972556000022": { + "map_to": "6977826050028", + "description": "条码映射:6972556000022 -> 6977826050028" + }, + "6949352266280": { + "map_to": "6949352266273", + "description": "条码映射:6949352266280 -> 6949352266273" + }, + "6925019900087": { + "multiplier": 10, + "target_unit": "瓶", + "description": "特殊处理:数量*10,单位转换为瓶" + }, + "6921168593804": { + "multiplier": 30, + "target_unit": "瓶", + "description": "NFC产品特殊处理:每箱30瓶" + }, + "6901826888138": { + "multiplier": 30, + "target_unit": "瓶", + "fixed_price": 3.7333333333333334, + "specification": "1*30", + "description": "特殊处理: 规格1*30,数量*30,单价=112/30" + }, + "6958620703907": { + "multiplier": 14, + "target_unit": "个", + "specification": "1*14", + "description": "友臣肉松,1盒14个" + }, + "6921734933485": { + "multiplier": 12, + "target_unit": "支", + "specification": "1*12", + "description": "得力铅笔" + }, + "6901826888244": { + "multiplier": 30, + "target_unit": "对", + "specification": "1*30", + "description": "南孚电池" + } +} \ No newline at end of file diff --git a/config/config.ini b/config/config.ini new file mode 100644 index 0000000..453df88 --- /dev/null +++ b/config/config.ini @@ -0,0 +1,40 @@ +[API] +api_key = +secret_key = +timeout = 30 +max_retries = 3 +retry_delay = 2 +api_url = https://aip.baidubce.com/rest/2.0/ocr/v1/table +token_url = https://aip.baidubce.com/oauth/2.0/token +form_ocr_url = https://aip.baidubce.com/rest/2.0/solution/v1/form_ocr/get_request_result + +[Paths] +input_folder = data/input +output_folder = data/output +temp_folder = data/temp +template_folder = templates +template_file = 银豹-采购单模板.xls +processed_record = data/processed_files.json +data_dir = data +product_db = data/product_cache.db + +[Performance] +max_workers = 4 +batch_size = 5 +skip_existing = true + +[File] +allowed_extensions = .jpg,.jpeg,.png,.bmp +excel_extension = .xlsx +max_file_size_mb = 4 + +[Templates] +purchase_order = 银豹-采购单模板.xls +item_data = 商品资料.xlsx + +[Gitea] +base_url = https://gitea.94kan.cn +owner = houhuan +repo = yixuan-sync-data +token = + diff --git a/config/suppliers_config.json b/config/suppliers_config.json new file mode 100644 index 0000000..6ad452b --- /dev/null +++ b/config/suppliers_config.json @@ -0,0 +1,237 @@ +{ + "suppliers": [ + { + "name": "蓉城易购", + "description": "蓉城易购供应商订单处理", + "filename_patterns": [ + "*蓉城*", + "*rongcheng*", + "*易*" + ], + "content_indicators": [ + "蓉城易购", + "商品编码", + "订货数量" + ], + "column_mapping": { + "商品条码(小条码)": "barcode", + "商品名称": "name", + "规格": "specification", + "订购数量(小单位)": "quantity", + "单位": "unit", + "单价(小单位)": "unit_price", + "优惠后金额(小单位)": "total_price", + "备注": "category", + "行号": "supplier" + }, + "cleaning_rules": [ + { + "type": "remove_rows", + "condition": "订货数量 == 0 or 订货数量.isna()" + }, + { + "type": "fill_na", + "columns": [ + "unit_price" + ], + "value": 0 + } + ], + "calculations": [ + { + "type": "multiply", + "source_column": "quantity", + "target_column": "quantity", + "factor": 1 + } + ], + "output_suffix": "_蓉城易购_银豹采购单", + "header_row": 2, + "rules": [ + { + "type": "split_quantity_unit", + "source": "订购数量(小单位)" + }, + { + "type": "extract_spec_from_name", + "source": "商品名称" + }, + { + "type": "normalize_unit", + "target": "unit", + "map": { + "箱": "件", + "提": "件", + "盒": "件" + } + }, + { + "type": "compute_quantity_from_total" + }, + { + "type": "mark_gift" + }, + { + "type": "fill_missing", + "fills": { + "unit": "瓶" + } + } + ], + "output_templates": [ + "templates/银豹-采购单模板.xls" + ], + "current_template_index": 0 + }, + { + "name": "通用食品供应商", + "description": "通用食品类供应商订单", + "filename_patterns": [ + "*食品*", + "*配送*", + "*供货*" + ], + "content_indicators": [ + "产品条码", + "订购量", + "进货价" + ], + "column_mapping": { + "产品条码": "barcode", + "产品名称": "name", + "订购量": "quantity", + "进货价": "unit_price" + }, + "cleaning_rules": [ + { + "type": "convert_type", + "columns": [ + "unit_price" + ], + "target_type": "float" + }, + { + "type": "fill_na", + "columns": [ + "barcode", + "name", + "quantity" + ], + "value": 0 + } + ], + "output_suffix": "_食品供应商_银豹采购单", + "rules": [ + { + "type": "split_quantity_unit", + "source": "订购量" + }, + { + "type": "extract_spec_from_name", + "source": "产品名称" + }, + { + "type": "normalize_unit", + "target": "unit", + "map": { + "箱": "件", + "提": "件", + "盒": "件" + } + }, + { + "type": "compute_quantity_from_total" + }, + { + "type": "mark_gift" + }, + { + "type": "fill_missing", + "fills": { + "unit": "瓶" + } + } + ], + "output_templates": [ + "templates/银豹-采购单模板.xls" + ], + "current_template_index": 0 + }, + { + "name": "农夫山泉", + "description": "", + "filename_patterns": [], + "content_indicators": [], + "column_mapping": { + "条形码": "barcode", + "商品名称": "name", + "销售价": "unit_price", + "订单金额": "total_price", + "Unnamed: 0": "supplier", + "备注": "brand" + }, + "header_row": 0, + "rules": [ + { + "type": "split_quantity_unit", + "source": "订单数量" + }, + { + "type": "extract_spec_from_name", + "source": "name" + }, + { + "type": "normalize_unit", + "target": "unit", + "map": { + "箱": "件", + "提": "件", + "盒": "件" + } + }, + { + "type": "compute_quantity_from_total" + }, + { + "type": "mark_gift" + }, + { + "type": "fill_missing", + "fills": { + "unit": "瓶" + } + } + ], + "dictionary": { + "ignore_words": [ + "白膜", + "彩膜", + "赠品" + ], + "unit_synonyms": { + "箱": "件", + "提": "件", + "盒": "件", + "瓶": "瓶" + }, + "pack_multipliers": { + "件": 24, + "箱": 24, + "提": 12, + "盒": 10 + }, + "name_patterns": [ + "(\\d+(?:\\.\\d+)?)(ml|mL|ML|l|L|升|毫升)[*×xX](\\d+)", + "(\\d+)[*×xX](\\d+)瓶", + "(\\d{2,3}).*?(\\d{1,3})" + ], + "default_unit": "瓶", + "default_package_quantity": 1 + }, + "output_templates": [ + "templates/银豹-采购单模板.xls" + ], + "current_template_index": 0 + } + ] +} diff --git a/docs/SYSTEM_ARCHITECTURE.md b/docs/SYSTEM_ARCHITECTURE.md new file mode 100644 index 0000000..c6d3521 --- /dev/null +++ b/docs/SYSTEM_ARCHITECTURE.md @@ -0,0 +1,208 @@ +# OCR 订单处理系统 - 系统架构文档 (v2.2) + +本文件详述了“OCR 订单处理系统”的技术架构、业务流向、数据模型及部署方案。 + +## 1. 系统整体架构图 (System Overall Architecture) + +```mermaid +graph TB + subgraph 用户交互层 + UI[启动器.py / Tkinter GUI] + CLI[headless_api.py / CLI] + end + + subgraph 核心业务逻辑层 + OS[OrderService / 订单调度] + OCR[OCRService / 图片识别] + SSS[SpecialSuppliersService / 特殊供应商处理] + TS[TobaccoService / 烟草处理] + EP[ExcelProcessor / 标准化转换] + end + + subgraph 基础设施与存储 + CONFIG[ConfigManager / JSON 配置] + FS[FileSystem / Excel 数据存储] + LOG[QueueLogger / 异步日志队列] + end + + subgraph 第三方集成 + OPENCLAW[OpenClaw 自动化平台] + POSPAL[银豹 POS 系统 (导出模板)] + end + + UI --> OS + CLI --> OS + OPENCLAW -- 调用 --> CLI + OS --> OCR + OS --> SSS + OS --> TS + OS --> EP + EP --> FS + EP --> CONFIG + SSS --> EP + TS --> EP + OS -- 验证 --> FS +``` + +### 图例说明 +- **用户交互层**:支持桌面 GUI 操作及专为 OpenClaw 设计的无界面 API 接入。 +- **核心业务层**:各服务高度解耦,通过 `OrderService` 进行智能路由分发。 +- **存储层**:系统采用“文件即数据库”的设计,利用 Excel 存储模板和商品资料,JSON 存储映射关系。 +- **第三方集成**:与 OpenClaw 平台通过 CLI 接口对接,最终生成符合银豹 POS 要求的采购单。 + +--- + +## 2. 核心业务逻辑流程图 (Core Business Logic) + +以“智能订单识别与预处理”为例: + +```mermaid +sequenceDiagram + participant User as 用户/OpenClaw + participant OS as OrderService + participant SSS as SpecialSuppliersService + participant TS as TobaccoService + participant EP as ExcelProcessor + + User->>OS: 提交 Excel 文件 + OS->>OS: 扫描前50行内容特征 + + alt 包含 "RCDH" + OS->>SSS: 路由至蓉城易购预处理 + SSS->>SSS: 按 E, N, Q, S 列强制清洗 + SSS-->>OS: 返回清洗后的临时文件 + else 包含 "专卖证号" + OS->>TS: 路由至烟草专用预处理 + TS->>TS: 数量*10 / 单价/10 / B,E,G,H列映射 + TS-->>OS: 返回清洗后的临时文件 + else 包含 "杨碧月" + OS->>SSS: 路由至杨碧月列对齐流程 + SSS-->>OS: 返回标准列临时文件 + else 通用格式 + OS->>OS: 直接跳过预处理 + end + + OS->>EP: 执行标准条码映射与模板填充 + EP->>EP: 校验单价 (与商品资料比对) + EP-->>User: 输出最终银豹采购单 (data/result) +``` + +### 技术注解 +- **智能指纹识别**:通过 `header=None` 读取前 50 行,避免了因标题行位置不固定导致的识别失败。 +- **原子化预处理**:每个供应商逻辑独立,预处理结果均为统一格式的中间文件,确立了系统的可扩展性。 + +--- + +## 3. 技术架构分层图 (Layered Architecture) + +| 分层 | 技术栈 / 组件 | 功能描述 | +| :--- | :--- | :--- | +| **表现层 (Presentation)** | Tkinter, headless_api.py | 桌面 GUI 交互与 OpenClaw 命令行接口 | +| **业务逻辑层 (Business)** | Python 3.x, Pandas, OCRService | 核心数据清洗、条码分裂、供应商特征识别 | +| **数据访问层 (Data)** | Pandas (Excel Engine), Json | 对 Excel 模板、映射表、用户设置的读写 | +| **基础设施层 (Infrastructure)** | Queue, Logging, PyInstaller | 异步日志分发、全局错误处理、EXE 打包工具 | + +--- + +## 4. 数据架构设计 (Data Architecture) + +系统未采用传统关系型数据库,而是基于 **JSON + Excel** 的混合存储架构。 + +### 4.1 表间关系示意 (JSON Mapping) +```mermaid +erDiagram + CONFIG_JSON ||--o{ BARCODE_MAPPING_JSON : "存储映射" + BARCODE_MAPPING_JSON { + string original_barcode "OCR识别出的原始条码" + string target_barcode "系统目标条码" + } + ITEM_DATA_EXCEL ||--o{ PURCHASE_ORDER_EXCEL : "验证单价" + ITEM_DATA_EXCEL { + string barcode "条码 (主键)" + float cost_price "进货价" + } +``` + +### 4.2 存储方案 +- **映射关系**:`barcode_mappings.json`。支持运行时动态更新,通过 `headless_api.py --update-mapping` 修改。 +- **业务数据**:`templates/商品资料.xlsx`。作为单价校验的权威数据源。 + +--- + +## 5. 微服务与模块化设计 (Microservices & Modularity) + +虽然系统目前采用单体架构(Monolithic Architecture)以适配桌面部署环境,但在逻辑上采用了**微服务式的模块化设计**: + +- **服务拆分**:每个供应商逻辑(Rongcheng, Tobacco, YangBiyue)都是独立的类,具备高度自治性。 +- **解耦机制**:通过统一的 `preprocess` 契约(输入:原始文件,输出:清洗后文件)进行交互,未来可轻松迁移至独立服务。 +- **进程隔离**:GUI 主进程与业务处理线程通过 `queue.Queue` 进行解耦,确保处理逻辑不阻塞用户界面。 + +--- + +## 6. 部署架构图 (Deployment) + +```mermaid +graph LR + subgraph 生产服务器 (Windows) + APP[orc-order-v2.exe] + DATA[data/ 目录] + LOGS[logs/ 目录] + end + + subgraph 自动化平台 + OC[OpenClaw] + end + + OC -- 命令行调用 --> APP + APP -- 读写 --> DATA + APP -- 记录 --> LOGS +``` + +### 部署要点 +- **便携化**:通过 PyInstaller 将 Python 运行环境与依赖打包,实现单文件/单目录部署。 +- **路径无关性**:系统内部通过 `os.path.abspath` 动态计算路径,支持安装在任意盘符。 + +--- + +## 6. 安全架构图 (Security) + +```mermaid +graph TD + A[外部输入] --> B{文件类型校验} + B -- 非图片/Excel --> C[拒绝处理] + B -- 图片/Excel --> D[清洗逻辑] + D --> E{单价偏差校验} + E -- 差值 > 1.0 --> F[生成警告日志/弹窗] + E -- 正常 --> G[生成采购单] + G --> H[日志埋点与审计] +``` + +### 安全策略 +- **数据隔离**:所有处理后的文件存放在 `data/output` 和 `data/result`,不修改原始输入文件。 +- **权限控制**:系统运行于用户权限下,利用 Windows 文件系统权限保护配置文件。 + +--- + +## 7. 技术债务与优化建议 (Tech Debt & Optimization) + +### 7.1 当前技术债务 +1. **并发限制**:目前为单进程串行处理,面对超大规模订单(万行级)可能存在阻塞。 +2. **持久化局限**:使用 JSON 存储映射关系在条码量达到万级时,查询性能会下降。 +3. **环境依赖**:OCR 引擎高度依赖 Tesseract/PaddleOCR 等本地二进制库,部署复杂。 + +### 7.2 单点故障风险 (SPOF Analysis) +1. **本地环境强依赖**:所有 OCR 与 Excel 处理均在单一 Windows 节点,若该节点故障,OpenClaw 对接将完全中断。 +2. **核心模板丢失**:`templates/` 下的商品资料或采购单模板缺失会导致全流程崩溃。 +3. **OCR 精度波动**:OCR 结果受图片质量影响,若 OCR 识别条码错误且无映射表,则该行数据将丢失。 + +### 7.3 架构优化建议方案 +- **容灾备份**:建议将 `templates/` 和 `barcode_mappings.json` 定期备份至远程 Git 仓库(如 Gitea)。 +- **分布式识别**:引入 PaddleOCR 服务端,支持多节点并发 OCR 识别,减少本地算力依赖。 +- **配置热更新**:支持从远程 URL 加载 `barcode_mappings.json`,实现多机条码库同步。 +- **数据回退机制**:增加中间文件持久化策略,允许在处理失败时手动干预已清洗的 Excel。 + +--- +*附注:本文档图表均采用 Mermaid 标准编写,可直接在 VS Code (需安装 Mermaid 插件) 或 [Mermaid Live Editor](https://mermaid.live/) 中实时渲染并导出为高清 PNG/SVG 格式。* + +--- +*文档版本:2.2.0 | 生成日期:2026-03-31* diff --git a/headless_api.py b/headless_api.py new file mode 100644 index 0000000..48adf1e --- /dev/null +++ b/headless_api.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +OCR订单处理系统 - 无界面自动化接口 +----------------------------- +专为与 openclaw 等自动化平台对接设计。 +处理流程:输入图片 -> OCR识别 -> 数据清洗 -> 价格校验 -> 输出结果路径。 +""" + +import os +import sys +import time +import argparse +import json +from pathlib import Path +from typing import Optional, List, Dict + +# 添加当前目录到路径 +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from app.config.settings import ConfigManager +from app.services.ocr_service import OCRService +from app.services.order_service import OrderService +from app.services.tobacco_service import TobaccoService +from app.services.special_suppliers_service import SpecialSuppliersService +from app.core.utils.log_utils import get_logger, set_log_level + +logger = get_logger("HeadlessAPI") + +def get_latest_file(directory: str, extensions: List[str]) -> Optional[str]: + """获取目录中最新的指定后缀文件""" + dir_path = Path(directory) + if not dir_path.exists(): + return None + + files = [] + for ext in extensions: + files.extend(dir_path.glob(f"*{ext}")) + files.extend(dir_path.glob(f"*{ext.upper()}")) + + if not files: + return None + + latest_file = max(files, key=lambda p: p.stat().st_mtime) + return str(latest_file) + +def update_barcode_mapping(barcode: str, target_barcode: str = None, multiplier: float = None, unit: str = None, price: float = None, spec: str = None): + """更新条码映射或特殊处理配置""" + try: + config_path = os.path.join("config", "barcode_mappings.json") + mappings = {} + if os.path.exists(config_path): + with open(config_path, 'r', encoding='utf-8') as f: + mappings = json.load(f) + + # 获取或创建该条码的配置 + config = mappings.get(barcode, {}) + + if target_barcode: + config["map_to"] = target_barcode + config["description"] = config.get("description", "") + f" 条码映射 -> {target_barcode}" + + if multiplier is not None: + config["multiplier"] = multiplier + config["description"] = config.get("description", "") + f" 数量倍数*{multiplier}" + + if unit: + config["target_unit"] = unit + + if price is not None: + config["fixed_price"] = price + + if spec: + config["specification"] = spec + + if not config.get("description"): + config["description"] = f"特殊条码配置: {barcode}" + + mappings[barcode] = config + + with open(config_path, 'w', encoding='utf-8') as f: + json.dump(mappings, f, ensure_ascii=False, indent=2) + + logger.info(f"成功更新条码配置: {barcode} -> {config}") + return True + except Exception as e: + logger.error(f"更新条码配置失败: {e}") + return False + +def run_pipeline(args): + """运行处理流水线""" + try: + config_manager = ConfigManager() + order_service = OrderService(config_manager) + start_time = time.perf_counter() + final_excel = None + + input_folder = config_manager.get('Paths', 'input_folder', fallback='data/input') + output_folder = config_manager.get('Paths', 'output_folder', fallback='data/output') + + # 1. 处理条码映射更新 + if args.update_mapping: + if not args.barcode: + print("ERROR: --barcode is required for --update-mapping", file=sys.stderr) + return None + + # 至少需要一个更新项 + if not any([args.target, args.multiplier, args.unit, args.price, args.spec]): + print("ERROR: At least one update option (--target, --multiplier, --unit, --price, --spec) is required", file=sys.stderr) + return None + + if update_barcode_mapping(args.barcode, args.target, args.multiplier, args.unit, args.price, args.spec): + print(f"SUCCESS: Barcode configuration updated for {args.barcode}") + return "MAPPING_UPDATED" + return None + + # 2. 烟草公司处理 (显式指定) + if args.tobacco: + input_path = args.input or get_latest_file(output_folder, [".xlsx", ".xls"]) + if not input_path: + print("ERROR: No tobacco order file found.", file=sys.stderr) + return None + logger.info(f"开始显式处理烟草订单: {input_path}") + # 这里的 process_tobacco_order 会调用 preprocess 并生成银豹格式 + tobacco_service = TobaccoService(config_manager) + final_excel = tobacco_service.process_tobacco_order(input_path) + + # 3. 蓉城易购处理 (显式指定) + elif args.rongcheng: + input_path = args.input or get_latest_file(output_folder, [".xlsx", ".xls"]) + if not input_path: + print("ERROR: No Rongcheng Yigou order file found.", file=sys.stderr) + return None + logger.info(f"开始显式处理蓉城易购订单: {input_path}") + special_service = SpecialSuppliersService(config_manager) + final_excel = special_service.process_rongcheng_yigou(input_path) + + # 4. 普通 Excel 处理 (支持自动识别烟草/蓉城/杨碧月) + elif args.excel: + input_path = args.input or get_latest_file(input_folder, [".xlsx", ".xls"]) + if not input_path: + print("ERROR: No Excel file found in input.", file=sys.stderr) + return None + logger.info(f"开始处理 Excel (支持智能识别): {input_path}") + # OrderService.process_excel 内部会自动调用 _check_special_preprocess + final_excel = order_service.process_excel(input_path) + + # 5. 智能处理 (默认逻辑:自动判断图片还是 Excel) + else: + input_path = args.input or get_latest_file(input_folder, [".jpg", ".jpeg", ".png", ".bmp", ".xlsx", ".xls"]) + if not input_path: + print(f"ERROR: No input file found in {input_folder}.", file=sys.stderr) + return None + + ext = os.path.splitext(input_path)[1].lower() + if ext in [".xlsx", ".xls"]: + logger.info(f"智能识别为 Excel 文件,开始处理: {input_path}") + final_excel = order_service.process_excel(input_path) + else: + logger.info(f"智能识别为图片文件,开始 OCR 处理: {input_path}") + ocr_service = OCRService(config_manager) + excel_intermediate = ocr_service.process_image(input_path) + if excel_intermediate: + final_excel = order_service.process_excel(excel_intermediate) + + # 6. 后续处理 (校验与输出) + if final_excel: + # 单价校验 + discrepancies = order_service.validate_unit_price(final_excel) + if discrepancies: + print(f"WARNING: Price validation found {len(discrepancies)} issues:", file=sys.stderr) + for d in discrepancies: + print(f" - {d}", file=sys.stderr) + + duration = time.perf_counter() - start_time + logger.info(f"处理完成,耗时: {duration:.2f}s") + + # 输出最终路径 + abs_path = os.path.abspath(final_excel) + print(abs_path) + return abs_path + else: + print("ERROR: Processing failed.", file=sys.stderr) + return None + + except Exception as e: + import traceback + print(f"CRITICAL ERROR: {str(e)}", file=sys.stderr) + traceback.print_exc(file=sys.stderr) + return None + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="OCR订单处理系统 - 无界面自动化接口") + parser.add_argument('input', nargs='?', help='输入文件路径 (图片或Excel)') + + group = parser.add_mutually_exclusive_group() + group.add_argument('--excel', action='store_true', help='处理普通 Excel 文件') + group.add_argument('--tobacco', action='store_true', help='处理烟草公司订单') + group.add_argument('--rongcheng', action='store_true', help='处理蓉城易购订单') + group.add_argument('--update-mapping', action='store_true', help='更新条码映射') + + parser.add_argument('--barcode', help='待映射的原始条码 (用于 --update-mapping)') + parser.add_argument('--target', help='目标条码 (用于 --update-mapping)') + parser.add_argument('--multiplier', type=float, help='数量倍数 (例如箱转瓶填写30)') + parser.add_argument('--unit', help='目标单位 (例如"瓶")') + parser.add_argument('--price', type=float, help='固定单价') + parser.add_argument('--spec', help='固定规格 (例如"1*30")') + + args = parser.parse_args() + result = run_pipeline(args) + sys.exit(0 if result else 1) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..609355e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +configparser>=5.0.0 +python-dotenv>=1.0.0 +numpy>=1.19.0 +openpyxl>=3.0.0 +pandas>=1.3.0 +pathlib>=1.0.1 +requests>=2.25.0 +xlrd>=2.0.0,<2.1.0 +xlutils>=2.0.0 +xlwt>=1.3.0 \ No newline at end of file diff --git a/templates/商品资料.xlsx b/templates/商品资料.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3da82e95fcc4b3b6dbbc44e0f162fe1706067a12 GIT binary patch literal 845650 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�Vj>GZF?TH)Rw!Ll2?$s{(UIv*E)GF6kjv11 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≫9#g)D!$YHP>IATT}t?MIj%y=1j4r8XZ- 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

2Qm+G4Fe{g|C1g`X59_Rnc*&;yG# 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

NXDioky)>XMZ1J%68yciU8SPLMJEUEnvpRlAIGC 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%0Ao zidg}Su2JKuCb7G1{}41hlo{yY8Z7Y)Tg7->j+WY8`WlKvlW1t`l~5k;!f9hMS9N!K zvYgBUwj}9N2%kkDSXC%NlVV3?Ir((t*68Yt#@gEwsVlk^%DIYV2erUF%JKV)If4`sUsl{Z?*RiS5)}|I zB$pA3k|6`EWL^7}(2l{0s|EEh!$H9{0(4c-R~STRfagAh+04`NM52cRAg-@% z3IQwy@v1tmG`j9ffGeP&*By{oMV85V0E)8mcXICYSrOwBDp!)(9c~~!%-_okD^|tZ z4BeH^_O^{z?#Qx`4b#8UYLXb{8`w}xdc@&=*E`$+?eVTvOx+ALIJkdOmj1JSUy}5) z(4`8%7**cp>bc^P0DnE)p@;F-ScMWflFsCNl#t;HKUnh)cdHE=6Yc>RhKB~jMoli5 zDs_V~2$oig`*Fp4x#6u(he(!fcuO+q5{>DBh27r5-O@$)t6ot2nOpk(Tz=ux>Hebg z;F}bXcTWpgoy{1=<`^0YNR$SZg{{zYPR=Z|B{wGc_R9-Tsl^U-1{%Zjh{i zSDIlIW)H!h;dIT7Y#*O%EYfF@a$aJp?f8=?{!F2YGvIR;-qfI)wlxOG@`v~N`X!2l zWSp`}&D;Oz>>lhHsOjzM>KzO{B!f5~p zATU}f0WmS$&1j0NyEKbN8<-Jg#HJe0uP@v1pCOwxEhN_dCz6?R&y@s}S6{6nfQCze zfM{b|tfByS`A(_mY!v}C4ip4n=~M1G=jaYD6xM7Z+gM~s)~T!N`e4YdLJ9O&1zk-{ zZHn*joR7Qy#A9#b*xh}G{Ce9D-EX_RXGgXbOS5E#r|()ak!Wv-vo18CN4>d4_w~#CyB8r@9pZI#janefLEak34si{f!>KU^Zc8`?Fo5b#t%Wj$2{^J$ zbE9ON_O8m>cmVj#%uw$Dr?QpP+sI53ouB*Y+ySfl*@~jT z#e;ebxNHs8h)9ghgvr)uiN>OJ9GC!ZiI~~2*nKWQB^h+asxp^v))K96YGImkW~NRL zKEk2k&0&QCoNE)0VUNl`-*#U-F07gm&o^kdrer7kjZemufBGl<**>g!J&V$>P?LK_g=!t;P=~;vM!R0R=zVEJbVtzFSIrYY^bJg zOEL{MNu;iUc2u8;H5A%!Wm-Q2Rsy3|08=KA7P|w1C`=6%Cg^8WNv+WH!Es~Li(#f8 zo(m(w(Sp7YETvRM_9nLAw!sTC&~!jAV1JU}9&h(E4#5t0n=Q6OK@X>IFo4U05#bCW zfD2XYHkQOUpc{uTU=y@Dn5T5c#p1QGcq$}L3kd|QORz{~n^D9-1Hu~iV~ftgec1Ux z>%pYB@G2Jt5GGZpy8CYoXVL@1?2{$OP*4m@HyP7zIgX;m0Hb;2Nwn-@hvNAZ{b z2<|FXAgI)Oi4Zz3h=9%rOYgz3;+GrlIibD?~7SUj{q z$C;^pm}{5yBOPxGe-51a=F?!vaNI0x@o z0Ges4@IOjjgT5~E+gK_V{rlCcy26J%p80kqrgW{auH;9F^D6+N>MDD7)zCFi-$d^C zh4PvUpYm^y!kd?<3Q)sXQW$!f=H~VgM~o2^JPMNEX-wSd!6VQXOX*G=GQ+k|?V`n! zKuKo2qS>DG?J8Bv(Z)kFE$-ZPmwwiG3%kzPcKD$SXwVW#HRk?~n&HmMhpve`7PUmG z&gjSm^gZ~`&}?pmXn2sCtf28(SY;FrREaD2UDEX$=;mHRVJVap62vi&lEv(K~nGl+V9I+fwrY4BYg?Tr% zvTG#%zx%HXs!y?H^5RuhlN8!d`0!BQ4NjBQiUr=$@6E(Y+YQ@VHC$FQ4LXObw?sqU zKwd0SAHNojM+KNvsx2Ib`}(W1x#rBQl<+ujcR!I?! zsAQAZ>Js(MiTXnGSg(cV9tV)T&(o*JPeOpH7X_wRG*Xcxp<|3)azv-LCY@mpPF{<( zmc5nAzg1}FJXU>EREw!7LwSgmVg=uzfV|4pqVyKV_^=2eN4G6XHy@JOpy1A+1k_hd z0b;}I0rl8BdXD)w$HLCWstB58DsV(lGFDaN>V{#%>1Q4#}uZ5yrL@w zR9GB)^sRq?%zed0I}}h^bXj8)>FiLZGc<1+HAg$}NYR`3(Ht@*zIhMJ+I{}kDSsSZkn(`mNaJIJcpK{L5Chn>`oB7q}piDD{*E6XaJ^od$sKtN8 z6VZlvLrXhX^!DXAnw6KP3JBm}dho2`yD}x5n(7+jiS{`2nCQfEwsyTz+Z@fW#jR*P zVl&l{EV`oWlZ_2cb&ODftnk)BQeb6dH1iCzA={Hxn#RH0oUhz8-Ns}+LT}VqXK-2!W0T_YK+%iL8+;0joj0g1e&BY=!|}FMvt70 z9|KtLqq9;;4-lrXlxKk{PZ!spe)+b;+EG2p+9mX9%ULCTFe;9<4so+}+=MI*L&qL41e1v;rqQ zdv{lDOUBQbP+Wr=T@00@h3w3vvjd!fbHznWCSTiKeGFgDhY`3%xR0MAeaO8@;lfi5 zcAHRb#ezFD&2f?8LPL$s9UX(2%#GXWex|u%43`K7#r$AO{*6k+3vXh~{Wiw)ydY^2 zsERh#z}p*YqkIOU9GGp8y#-k*iOlgw&geHRTkvKozc%H6-|^lq_~YxWaNS078VWpG z+g_hcUFAq9h1n;#`bs9VRAgxH48tp!xQA6S$eb@1f7#bD)Ri5+70$3wG;Gr~CocZ( z_ak?jV;ly#D!jNtueQyJ7$P?~N^rb=f>duyt;iUU=$7|Wz3o1#(;+P1zt^6&45 zD2=M3S&GF}I)UG1Z^6?;{h=XWHcl1=*)5ojEC2BeGVZ;9D7Yq&=oYlN|IT8N4A5*e zT8USU(9=RyIg>N;?hOyH5{kAgv7l9h;R??Gc#!|`$X}R7%A+6K*k>c}y^*!>P&+sU zF>;CywiKbSfkF5Te`se{7pml$>mfmP!UAUp%imx!p51SI&cRc6=9TyKlmFm89u1=( zQHvbi5Oo4z<7H0>#nLd*jQa2tJ7Up$bW?q-;c9bp3e-%l#S#p0DmkA&ibJX#i56lS zEFhsl(imt)gOr+(FT1(<8baZkbY?#1PhKEjdg@HSwT0uyc ziWi|d^hm@^(=fD9&>j7QjEEv-h$y%VniUh)9RP;Kk2!(s(~4FBr$XZnk>j3$$s~mh z_IIWGnC8!Qs>)^TiB4VI&)b#Z}z?V#Fzs9&j zYH5hj$j7!=ZGC$@9*ea$#hYS`n2TeSD`KQ-GqT=u9PrFk_!T81s0zx>ToCM*tBR7U zc@n2#t2$St{0wD#yuAX-09j$53i|J#M|VXR!Z)&1VQY|7hTA+s-7{EugC0+?py2<# zX^_&}A0q14S&Iid!{*Ar#RX=8O1-=irLigE?Cob7`}H8zEhd_m0<3_DDuq%+r^bCv z=Hd|qQXZm6c~n3ZWBkabLP4Tgt!$!(o%sSbQ&^W--KHWCq6U?&phFqK9aTqH2-Tr@ zq-8@6&6-MuQCBEyj}oyNOQ;>uxV0aL|AR;>#ER~!DMIkz5+(3&~1bg zl)w>Sge|NgTv$W>VY0}|qE_wGqp#k?H|O!Z^K_*Ob)p=2T_lT!hjjE^?+zhPEMsqh zGn3kl%H<0R#cJ{mdM^#+_g0l}FgwdH?|*L{sc5UnXNuuw%{|P&dr`IaNkNKCwVCGjtF7%}6-|T~5u96+QRPjTY$+|G&|M$2 z5he0g>q_ci;;yzq=a*v$Fi7>H>qS2suc($Xf`&JdHHcz7MAACMNJodld z&A)u;y}#?cWnCviHd7%DTF7({XIVo0U!^nmh<7iX+*kj}lC$=*5Y9U}UgM1C{QLLh zkZYW*DW)lDG@B%TC03tGwA4gX+@rjx{O9NS$1kdgqS|#)RAXZ`Q5ZTp`pI2=T!VJ^ zSBw7Km$1}HA&m*^HgvYsBUjG}fi=f!0a${~w5*IQ%y(BnM%T4$b4BRNKyWRxBO$om zWP?|53jpZlR#7=>u)^>p+qm{v@t1}CzgcP}`3%EZ=qP~v%gHvbL4FWK>D?)GR~weCI>=j^?AMyH*rh3XP12Ubzy)hn^z5b5siIS(g9-6N1%c^NR~%A(Y! zrbJ`gZ_RFR`*9U%G(4j;iTRXezEguqR7DikOzANqD_rT3BBbQ+y#248UU{gQz=B^o z{Wr!s==3VmsJ-*7(|=zJ`NQjDQcAlNsOPm-p`EEUaX2_OthBQ&dfJmR>^tV_DqEagBL7 z@d>8|43blH`c|Yjqw()-4Yl<-7MxnIE*t)%*MYy4A-gm7}9lLAn7I{euMJ;v(khf7}yU z)1a-pQ)?n?`t-++#$O2}8>y9TiMon)PQ{`sW;!#F=^5(n&fMlCoXel)3TgWfe!!Qr zaO^IR!_~xpxa7<%I-_&m+&6DzT|^Iaz^$Ob9+R?s`*u$UG}PZQ&~-b*Gv}Z^&o0Es zQoA*5s_u)8l5kN%D-;4Z-07PjxvRITY=#p1`DdM#CY| zsNhen`;YHAGb@)wRR|>3otedu{_pSL%fGh3JM;9G)>MNNMFpVAH3e!-*DO z)>wzMoI?Y2FprnLCju7!8XUYJv$2-$R5sPh8c1CgnWdp7K-A~>qBu^8zTq~*CVhhs z^0044iWle`{QT+B%j(`wUXqj-#f-CQJH-WO-UVGyVwvOi^sCP z^-WV1QUzelC_JGsF#j|p3GC@p&h0Pu)8*bWHF#7ki0+DqUidy~T&srN4k5=U4d+1Y>A?Lql2OF(%?X$uT&|~XLqoBa#lIPx(sJC+rhoD@4y`J#$OY36zEPctma#cBinIHf+)P_rx1hD)b?znDJpQZeKR6O^V)-{k|J{&={s9k4IFUF6!#=~8HXMen ztAgdhr6=j&?PKSV)fTr5w8yR8Fm0~Y@trY zCpX*sE$Tg5)Bbz3b2!;-Gbq7ae*BkvuuLQ}epW0!*mGz8a;HDDiDe&s zwbys;xjlDdm9?SQ>7)`4@ZsO%%0>g|SozY8NR(2b+uO6fJ?Rc#a#k$2elKAw7`9RN zp1-ToQ0*D45uV{8Jp6_nv55LeY_caW)VTfT*c&^p9=!GLPdhtrxKW(0NW^BT6jdbR zLezr$Y4FBS`NoX`WvldayCn^3ktjOBM8Rp7FMx!&-wX~kkSRwY6kah%j@|d(#-?}c zwmq{B$N0UE;30UlL#O*n7UZkQ1X}?(6Dh800~_tj`9h&s85ku*)G7riA=MVatN?(6 zD9Z7l0_Oz>D#_RZr$-2e6;+|AC(8Mu!U!ec*Dzm=BC4&fy{LZp3^QzU7MRxOU%I=m zyq|OS{r3$lNs^|Tl7hpmuMOQOj24UK0Wq&5SWf+_mPB!dH^YO4vrCL1a(|>808u5kOAu`s3yZuwjECz&gA^g)arL zVsRQ)9U7qdWhc(JC+@>3cWXzO+`v)EriCYw6^Y{GcVHyf2Vssk%3^xppxOb1ixb45 zWaoi}YwM%){$usiGj4ZlfE7h=7_R3%V%{+YdZ z&%QIx&MfcXlRLd&&#t-K8!8$5E}2j|o2exTbgp=9pqRT}Af5|XffiK4#IFqZ?N|HW zqb>G_jWp{q)w0J)mjOp0VTGog>+dg(suq>#RPS%3N_&O!Ih!=w;H!5w?4>39$BH|( ze|qo^{Bm<+?%`c~?jCUHt{*|sky_t*6YuQ@PkEKZ@C}@&`==*VDr)T&@NAMI#C=|; zY7MfNEfo98#r~20Qhx>P9c%!G2aCh33$6(m?Q2^%B$W~zLCdEHKSPcs#U3A{p(}&5Mv_E=m&cDi!}U{Ru^SxL5U%|I;a%Xyw1cSacGQw3@49!GORLomLoYC5*e zmE^wSpEruY8gyMF`JU^&IugO`nE-9{zlV#+&`%8h9b7WiTXo&V(;NRbEKFut`g{GQ z{R=A?|8M+b;=cbtQ%iIi6!xrPsgj1Ld|$D6 zLqPZ^2Srgei^$@GDo?kbJF}17AJ3f?a?dcLMwIDH*ohwRX%i7Gs=hPaFC&4~WBbQ@ z_wH(Sd9M-2AQP*ank?Zgfp~8#%_nHoXw4K~sl~QKwzD*%a^oT;!kOKIos3ch7xvao z$~>%;2S_ePKfGR1{qTCKR9toP5u^!h9YJjUt=sPVLkLSgn78-#;2hXOM?3o!WRGoc zINPW$ssDPG$|fGcUWwIdh0Mv%7s|zvfzoLIKr^yaiwM_eioLV9Vs9*ilDGTKemhp3 zm|`~@rgDOo#Sfz>qNs?lmJ_LaAy^8nn#Q+lo zEeEfe^6=Z$e}u*bUNcK*|y5?%P8k?!3R?%|1BYd*a+*cc&KZdp}P1)}8sUOq2XADO-w626E_8lO0|}ETIv> z340b*`Z0MWlgM6)XJeUEBAXS6YKoOzvpH6FOtL0qQ*hF9yo57Oi)c7QUY8;Ywq4gD zZU>LDP+)-i;H~>^!d{=O{`J$n^Mxs;_Q4l0VlOR)-ODsHard$h@ky*vu^q`P$&S{x zo_J3-<##33Y&|IVV2Aya_a+{5v(cEd4{;xo{J#LIGkGOm8(*r~UqP+2n+-7BEljgp z&bjf02INMaCF4sfAV^$!CdYNIn_%=6 zN!A-pH})}3g<+Z$`AdvFmd&IS-N|Goebw*61|pfx>Fhsqj=!h^JA-a0z`TUB)U)Xx zm9i-qwc_m>a8Y1Rb&$9Wc_^I9MwS{1Hu1fsQXcIq$WmD(TlVQrprR!%?NF2LOLac( z&|Er!Y=Y||3(@=;l1|4stEQ<^_GRbkrn7tEJ@BJAn@HBN5}58{w@ZOs|DM6*Lh(v` z2Hu-+XJ0jwC}VZFm8K1vVc-p3CzN3lvuQ<$8*l%v?b+uj=*ou{ZHQ9dwNgx36?cX zz*4EO=Ld4X4HuhKWsyw6zRwXjZeb<|vY$8}DC=v!oasrt=7lCK)5==95yY`14OqqpZxNm3NsmUnG*ub<# zUDG8A)BY+E1+O=zPiB%`L{nT|V1n4+W~?4idX(n>e8anl9$bL%DppbnQmDRHn3$nx_wZYzC1R z;N0J5eOg^wWQrmusvt2K8YqI8#UznGuZU^zVDpw&vDX2S#JmP z-u2&{IJZeBrIFd#|aAPm(6Hd$CSvWLm_)CU{e!4j>;xrBE4SvinNK{6OKl zz*!2t7}T~WNP;$Iy`OVXyI;HqCu#`38% zv2pCtC+E#8)_WHat>9Py1#9l58>Plj6v?L|!@J=6Q|H;s(}M$d{+su1&D(wNZ0@>? z$Ij}QV3n%TXjCx?`>|zETmTBiK8SbC-t^V>csAAA(@RfJ!$0A{QbQ!EfJVMKfA%Uh z_#(!U+B@Kh&aMDBRz0F%l_b;65HqwiHHnYMS=(@4EL0C4aaIt}IHqTvsVDH!&MNC> zO;B@~!&4=qY#mY6C1Mg4nsn+6%5(M1fsER98W@n3dSrC_6?7W76)z)3vLr~pjSX?PP}{9tt|Ioo!yCfI8k-=umQsm z2QEw4G73u~-IhtF1sp?l;_R7KXX(iK@a%7`VoAg9UJ!aE8E>`>gSV`0W`9#GR&JPH zie1QnrM2mnun_EJ6O;9XPGVa)$3P_Hg19!IbP^S2HNa2f6Y>z}CNFL7ZT^57HFu8e z*$3=5yc{X12dk12g^~q$*wY=!L@JYI4Pg;NT-)PHQSfKYCsa@64uRh+q<5 zOd@$PF}&NFiovC#xEMGLsYinn&NV5*mQ@R@j7pS>mP;g=I9fN9{ooJajQ_H-~{t{Cezy-jz(O{>m=db#Eek> z;ac>pZ`Fd@qBz#-qHiZ->t=%&Q9ug-m#9RrsGgI_=d@6=B4O0N7#xFRl0 zTv$BfChEy#C?939oHm4 z&9bbhiqnKj{~i#~&gg!nS>WsV7j_PNW2^SYcTQw~dN9wUXlcQ!rb$t}OUB~u9ldGc zEf9*wNj_Bp=3S|i9kL}fkd3!akeyC6myJUZoP~qa!+Gb+NA|~k{g9NZSehZL*bq5d z86Bl`VSelNt%9;l5G;j_N-{yT`|I;${n(Sm>ew;FN^Y$9X1a#e;+QC1Q6vN3nPfGB zGqDN-eSNuWgZ)Hfwd@X+XLm%2^1+ZVb2RJjd}XS=*jg^D3PYsf$6JV~mPD#EiRnco?YL9>?(Vp=wjhE74i$wUQDbm$^_f&}Pb^E};hUctkh|dH5vDdz zsbU)tH?6L`7Nj%zkk~52l|3?@z43HXxcN%aAd~|?%EpG1XkAb^z67v63vGyOcm#O- zEl2TdR)Tv6XFp8L+uI*P$4&zzcx+o_91NzA#%3*|V4dV@ru&NE9uq>g2+}O?&Xluq zV$aRlvwLE^x`pv#!`Yw35wTlNx#SZh{0oOE1i5hAAKbBb&4y6J%RAPdN#W6g1-ttR zf*US0H8gze+^7uYOGAR>2Og6wgU12eb-_Z<`m~WeBCW242$x8w(2Ln~C+@v1_Ve_3 zr^TLFX6KB1_>*;@v$YO{KWGy8LS+rI7;yMc?;pMKmd<#hy@!1EoUl!2<-PNITm{;c z24e6+^~JPilH`++Upx5#Xz{-N@TTYaj1&);qyw#hg%?I&;r|Sd{8Q87ht1@At;MwN>ZKT-Y|tmkTqkZshmW+cDfS0-fK@3+R3KomR3oaW8opD=5qw`r zcf{MNh5|vgDr7uhpKZem6`LK%R5ZML(j9-awP)hJ#B*E(+b>S{?*YH-)TDQJLZ^Zk zg7#&Lims1hMMP1l%#Vcz##y-oS+W$bH-{mE=lA@FrQFb;l}7a{ zId`2T5mAI(x;-~zKiier-ynnP<*u{v{q%5+EIS_HFr!$5Q^;CG>5gPp?ufOe+KKkg zi$B*5kUmVgqH7>b9E!#!F!n{~hAMKclLiF!2I@En@Leq!B){e;+nf8&ixqeNS#_C+Akm|S&h|Y^ z$Nrm4wu8UyFuMwc?CpZFd1~!wI%cIw?(^R`TLs7Y)_T*oz!5bJLB4O~ z0`l=p?)=YG>OVW-Ox+s~vDg!ztIu}r`!6{bOCnh@LO_I$$+{IQvT{TwN)-73{=CWF zVW73WI2M82` zbuf`m0!?qStyfeZ8Mal~Pts?*JMM#rpX|-q)5Aq}s@NYUyxC><&SSV0Oc>7}lQ}Irrz|7?qOO_00 z;k&*09By{2-&NyxRqaP?A|S=k4HdqQUN&f^SS*eR94wUKBl(IT zD#MSP#(5*g2r$r$G|j*ASWAREu{JLSlsNiH@U_& zPwtL|HLyq&N&+d8DFH(|+8f%grm{&>)ustm*GWl3y+en-S{XTP%|Z#)5Yhu5$^D2D(nMZ@u~MKHuQ)*D_07>G4p@wg$mC$%fdkJ0*`|Y8IJ0%&>9gdhiWlz9Vo_ij1@b_%7Oh7Z9DSKDmffXi zLV+ex-05a9H{3)XMWbjR{iwd0uE)pw6b-XEdr>wSQvP(3O5J;zk zWdz3paLHOk4`ny)X$TiXdtG;mwZSl?MA4Bo6iSpJth2|zuq!ari=FL#em}7f{^E0q z+?rH>9w~%F+n_Q-6J4E|SVwz;YL1JB0v3NuG*K@lN?EQFUEM;_tYdQ3TQk+$Z|r9Q z88f>$5kg_6LADG*#TBtg`iESpTp7#@ti2&SpH5kvzmK!oAKuaVUB%wtHpuQU&8QJ& z$Z+6PTQ|FPcV6vi{2Y!sVK+7KgS_1jC9`ieXhOnPMW`l&Z;EY+B!knWF``Vg6j89v zkzGbj9Ey#x>l9%?D2>X5#7RILc;lAvz7A2C{wc4}J}%QVOxcojtS%&yt?U^}!Q%Wo zewr=G>FZ6MIJZ`+2MhM&J-BZBkx|~#H1q|o`cVTRQ5+*mM8TUCl(WDC`$sB~PG3#6 zUlk;-TmGSGL5LY)4P4)JUOj>h?|4qpbSh&`htL_*vWVa|MU7}U?J|=}bdYU14<6Zb zWA^xb=jw zbI6n=18Zk&10?tka|1*9a(<-0SQ4q{oElY@iSRW`vY^z_;Ug%3`Q*0qb;@X$z^KAdF5pSC^$6cKuf`sk8%iF2QcQOHcEEHtKv@g#dpK%`l)qseC3sx-)`*|`6rVz&4>5-O! zxf(o-3Sl)oJ$S@q2c@r$KgbGHacUqNyX?zQ9*{jJsL-tVvEmx-rsdMzgFR>EtKL|$ zf%9g{g-V|;kb72QIZDvBa=G5|SGK;Ox)DXpRTC`ZUA>mdfL1xNF zItp*ve4q^tJN7e)sFbBgnv+!Dldbql2}93PB21)6^pHv9CRLXWqM?rWKv-CPMk_21`uwOuDr_q38nE(>i)NqCjlj zEcYgsp=eSmDiMU^H3*7jQuD2^G!#5b(}kbS_9#K)2kCI1Htaph0LY~p7FO^(E>mU` z&PdN=j&vd$RMAyS3tqccD1cX^6$;mhT8qvs;-vMz#}twNQbj=f6GqcUiRvWmaW%?; z*|T4(i!2PP?NqCKlhRMpWieTLH_>4bS)W>;T5=%3A5D3ej!D0HUVH|QV# zL8PIO6w>}z%Z1WlAwQt!g}nxWDW+d(NwA>o*z5RgQ`{hE3gKbuuWalA{KEyO|+(kTQ@(fn36ycb^eOP-MHm%N6Ft6 zsSUMvhD*o(+^|>ZXV3MDPVmiUQc7k z*%=BMGuy$~wBu*O{h2#?EFvWSoLo)%UG-~O(%!=w0-U4)V>1vwE%4;j%~+y5=C7x_ zsMKYEK_aM-*>TmDP6_-HVFeF^aIFXX|HgMHhx}nREbGm#($3f`o6Qv8vnxiUV|xBf zBA!XdQ$0PgbbGAvr4=&21T&&K`N-aSQGNUxICtm#Vy9fMXmFOxl7{b8wV&dp~|tAnRsroM7Iqp;7V6u?d?J_TUlxQPj31Tc>TwaP(w~qxTFO@gcjemPSkYd|g|^6}p{YS3ejHa7}n2 z(%E3iaPCi-dGsxrv4;~R_5X^GFo`9t)A(93lu%RDxc=m8faE*s+im~|E8Lkx@@kq5QZkhiQ~|8rDpZLIg57;>&rX9W z?e2uL{N8=C%(h2UrEKAb88z8?W#C9$iHH_7Oe*WUzg+4c$`uI#p~1lSZYU;UB;in@SRLQub@PBv%^)2YJ_JeC@C@!R59M#7&45 z@#ed;y)R;a(b+9T)+AHKmcin1|Im#xNtbQ}0sO#iLS`b(vsa%K(I5meb%OM}txFUt z#Z9mh^f`tKrAndD+*Fg-)Fr(CC6brLd^VC#J}emoh34u0ioNm4d3Ds7{3DPo>-eU? z1YkP2jt+_uBxKI9$KOK@sJieZu}GpOd#bmmJJ~}B2(w9}FtORDh+p`Oy@yvGzBk!? zjM;mmy^vwZB)f$JU55d8nKyM}zn!UmnfLBbd%LUN?6NN9cuC|2#rkwZQw+8%OZX-s zQTyM&%R}W{KX19zpnhLiO;{2_ zav^oF0|37i6|55ihwPbY_H#;=Nvhcpu0^EkOGFI^iSnlRCgMy`LL{a^H|mn)eErn8 zCvh}d3x(DqCWR4E@d^t&mkA#f^e%L;A6cgn_MWr%@dFB-??-eLwEqH74TPwVf$h<{ zLgiSpuFdo&+UUuv`5a#oRQ@42wQ4BcyQ}WbQ!zd%O4JmLV(XtKQ7&r+uvcIP2;oVD zM?-Rc9D4H$5MS>fE1W4nu%D|C2xAeUKhj8LmMD|gWlv}b$gi?M&V_0>Z20rJRw5{ z#srl}5v!DnxuL>fZlFLsSqnLk{A5YhA_8Fn&Bg}DQ9YUQR^F17Ni_r-)?l;gWFnCk z9FV-Gh`}!JgvW`?_8u>LPo|p7mMuIhvgy>-=CU=yiV?iGuY3WQIn!~(vNbUIVA<&l zy*J*g-IIsj%%Su2E8Dx=xiQF$d4cTy?)s6tM3CtMBGXbO!W$st9C0~n5wu^bL^|hi zUHhSd;?0|RVW}(0x6?xPR2=R9V1d16b?u=uHs0)2h|ZPqnvzZORhXiI6QyLF(A76| z?Pg)H@teS2j~)z1%XzwK@9)|_Kb`Iq^-}rENKh3VeTZgXR3cu5b$02-b)^5C>uiJI zfej(DspKt9LY>XGvqFdxk@s#1rip>IVg@r`yz%e-@0J?l{Hn7b*zf15dxx0(xVIw z6#5D|LO@95qWE@3s$@}heC7l^&3mqM08}Yq|>crvvpXc z7R6oKWmlNfpDWJZ2LNI=1VS)^Kxq}EVw)5bT7ZrT&1PDATS-wI92>o%LWqg13SC1a z6S3QJ1p5c0_`cCTF^!H^bB+YSWf|X)eKzc+do8{q~mEz6vpCbeGZY(Q7=CNN+z7ZCC<~CeVCLh{cTi)ygd--K` zZ=@U^};@SmLcI{?@Ks%D#?-_;v_sNFieToM1~C#^>DpVC_X<1Rp0qOPdVz( zWJ%bB2RwH~`7eebmg;R!Q0?(Op3{VJjjf(IjBWhh?z{REK#mxfuIJosh}I6iv;K}f zNMB6Z#a9*_4kFz{CGdoQL{1v{0Lg%@0pt6kJvQV#&vNWn#7mUZ-j{pSP#`07wIk@yRYsD29Fb6icv^dhfpI{6zM~3fQk)9NCEpFuP{p3|7tLu z?M2$MRs(}?RleND`kP95%Kg%2-u=(s$%!|;4@;HIWY$c>)HF@S2?jbah+l5+>JX+G zK+LAEXx{7TYYEew3S?c@e;7FfS#TLrAp{NFBQg<)#{t1%_vE`mIiENLRWk89j7S6{o)IxI<50S_y$iP<49edh z2)3rMBZS~KRw9HI2`;qQcAsu-K8Acmu?fFL z!!wGF7gk@HRzcK}x_VzAk>PW52@?Ew~OA4@168_r)GO3oBP;i23XQ`_a z48jOKnrO!l)i>-OPF!G1kWB+SkNp7?YykBlf@6dK!z& z*tmQ0(Am1}9L$AbJ95MlP9{l`v5()3=s0*oCAp-N*-S^GjgkfUP=75h?VGd2a3z*0~H1!IuB zHBbUeB^sn;CNp_bAt3}ppardfHbA??S`wRt+5D8-L`3FO|AlcsCo+^u_ekj5t&+)* z;`n!VKfZike)rIyc^b}5g$sWLo6mI2P`>#*VZp+Gnx|UykZx+#{!2?sTXU1%ca|(y zDa!HZKZh?iL5vPPKS_qc(C)Q5ttq(Qk_1@)oB*niH?>-I1^5S_;18HCI)BICf7JnR zzn^r)ZP$L#;mqp!NmGB}ayx`TN7ZPqE;{(A9p6z*I+IPU>89SMzEjEM(HffelXiNv zG@cG=&mX6J&nxr^L>ByO?dcF20q7?Bj91hbGDeKX&b6*&^S|7p&KJNRvgI; z42|bcOb6kFf#B5OI1uB z66h-E!exRgsXMv1y|t~ay{D)9Y;QNVm_S4+o&}iA!v*_FwD2q~KmR0eWvt@&c`EpP z~WB3L^!0CG=m+=JR9c3uCOT>ZC^pvuBx*6*>Ih1J_+xh;@L| zKwwuf={*nonsI9Nwu>3iT|#;%u_VjY>Dz%#hm9u@jXVrP3EO8-t-^(+C_mx$wpDio zbn1kUy4BU))ZSxpe16raTrR3upo;O-5l(ktZ##%SaU|#=8#k(YR9S^($B-o3T%>Qa z1P{N5JMUzfKDr%}h1*O8WQE4hzjLMV8W0c>JpGYVU114Rn($=v)PZ&Y}Yv8g)P!ia~GtZ|!K*`Qa*z6IOG$2zt}< z_g^0GFN9kkgNJLJ6wN}8K&CFMZg6fv%~CwNu5_yCn$}=GiLF`}b|#k(&&H@{IICA~ za%fc>{!>kwt*B9xSzBYm&0&k&90QrhXhX-l@8AGYK(4yy7E5+jAcqWs{W{a6TU!vO(Zd7im53U)$2Oin!B2M&i3-JGYr@kSD4{2nUUp{ht+Vg zF#XLL%yGMkfg&awbRa=njNb>-G3ZU^augAx*}>dEp+D1qi4hXVlZaY)$lXL{sv0z+?Ti{LYa zah25!ZHy)5##Ile^E17ck`^>{GjS7Yu0u_1hQ%37aM*g=x|_M?g2k=!k7UN#@2f)>U5u@zs&X*99xQMA*QelZ?>~CYA+T)QfoBah z5cV~9HYHHwRmc}DjVlZ}yMDa8d^v@1he>IWF5^wx$>nvHSce3hS#qJe_ew=1Zxxi z+Na~aZREn`*P^a#wuhPbwSRdbo9oZy#xGpTGhcq6T?=T~mqXMzm&{q=ov0MxV`@kW zmi5xrYvKDFrOj)wrL=@DVDvElk3K~ddSs&~o919F8Vpi@zqcm z$^M)h{oBAF|LtE!Fa44Gki0b>~PI$BsJbLZlyH?uSMds*7xBSWX{`@W~Ym0A7Gn-QS@xe-X>l$-?7P5un zXh!74CWbDeZ^9K0K+63q`YF6`4U*k2xo{!ns`LTmrRhtZLf~y>k z2K!6+>&cS8_#yi9i^(5gS7Hf|7cBFWZo0@nZn@OSt#kE7QA{>FRLo{aei*no!gE4J zg_wkag=)VsveKQWr8@`k2mjhZ!f_$t!T;%@WOCKd+uGW@y4suTx8^d1O27RjS0W&B zXxEPFjVsdc)6izcrSE=Ep~tSRDJtz@usKzFau`aW-i^%h>Ssn2S=Fy|6;P<ooT8@m{wmJbq&A^jlQ7`hYM1L zK`D%I0xBmE7I`tybjH+~ufS{w59a;JU8!j|z}*2qJ3f3^zC0~BNcEuxf946^Egx59 zE*7%jtUOKblS++R0JI@9SjfV~S}crkDScH57}^DGV87-L1f>heqBZFsz_GW5Uk-?7vGN4GeK~ z%fQKf?VzFF*#SofeW#mj5-eb9Zw7I{ccuQlsU3u*es5{U#_M?tvD|>o82CyXFM{Q{ z(#H)X1(;p~4H`om1r1rEl|wf?%TXPR>OrQh=u~AcWHY&b5fq-O#|nh@Q&pHDY3-Mf zyT^Ms%2(!O8d+?O))KA>&9rPRxWibHEE-gTWGgfvt1zA&A1h|^oQ%q&UvmB$9P546 z1D9iSL{ey+ce*W_TYlr}0g3}qlHIX%fSTbM$6vOQ8Fga^(_hve1k>-5B;&tka`-(X zQ_N+?xMQrk=Bdp*;v(78H-e{EOV3y8^jcF5di|%;U5#nJ4kD6#+M?pN%GDT~!3xLH z79`6eMV3Zb9qi)Ju)d1sFdpI`nLsd2(J3b&#>mkHlNrzDE)9)j^Nid$&)SX3Gf>Mo z(~$~2SG|tFf3*IrqBGaN#XV;w=t3RP@wKaQwd@3Ftkbu77>_%D9!t2o!_=?wxKkrD zUMRv~@|To+XiHP6&OJ!%p~yVA^9(CRiII#7XR+x=0-fqIQSPeZ(5+&rT)+cJ&B1UM zvKKD#g#ob)jwMQZ>OWIINHmzMugc3$;58cAr{?aIpT6-A=P@Vq%BnQa{Es?4pzUVH z2hU}57e&isObOlV{-S-13omlaV*MURbYg8%6*d>|;AqR7yFp^MZ@!Mb; zOx8dZ1iEZdAa(3$TrNySl%X}KsvwrAy9v-oP?;#W>wXOG?eP2~5}adG^+eOT0_B#X z(sv8)5s(Pein7KNC`M#e7?Dv#O$628L6McEAozQ~0+~K5f25CE(@-=DIMvsimQtD- z88ri0O;32zKw2&}E@`GhPQhrzBtK!|h)FhoL19T92NGqp_662DsF?IpwC{yU;eHLmOPIOI6!Ut`j9cK-e@+zyRf-UelB#_eZ9%Qq>3aFMni8+LrE4m#*LO z_dmxp`2PG#_~lJ_<9+z<239d<&6k>Mxt;^sF=_Bp?tF2eaDIF+n?!&id7mBRlwvfO z4@>^tKl?f~+w!k323O~UXSe9~A-zin-!= z!ZX$qv^Lt$q9|SxXqXWj1FRn0EA8wAvl9Rr*1sJWdq~F5lyI;d&TQG&A;t8xcDJ-( z<9%G290{lfiujPr)T>~inzXJs^oO>}MTd-!=7-0IhIk>d)m)@)sV1ke2+027K58ps zwy`N1W%CWMN*f85kLZAPw)M5}ZTUCfmA^hhp1g-UrOj*M^$)rZ|=Z;p|vzaUoKd(X}K6G~CZg@>Gu@DUpZ)Yw*{#L`B$+%8k>^ zAn9lhKRv@1wzym*DcUfp5|{32Yfdmm*uuZ8A^kAT=PXa|qG4>0t9BPjGiWpqobzN~ zcC{x^w8rvbtm%y;`i#EdwZyr_@KRddqo?_|6XaQZkh1C+j^;QjO@OShGDa2eIWjo^ zqo{avV?LO^i{_h3cD<265~fg;NfnqwkPbJ1* zoe$nTJcSshwkV3}O`S>%vYI@IkM= z9U3LGfJo|NFu9uYFgfA=%W(QlY5jw#SpNDhGDoki@l_v@@DqzDP)AiN-IIpzn^L`m zXU6tmR!!T3?`S+zY&`KIRyG=m>VIBF+MR==()3n*x9gTV^aH%L83(TEVU988YLXEj z$YgV)14Z%iAm?WlN0rRN#9%ZUfVA@`TtmU5o$$@R9JJuC9j0(i>Em;xPg-~l8Xi;Z z%=Bz{5n;ym&reOeoBZCJHsG%R%FN$`6mQPSTSVondbFZ$9v6ANYG) zrJYwSObctvX!HT_x6C-#UbP1di-0jhh#rB`(h?@dRgfh)5o7uEj>1+(ih!c7*HALU zQe%~W>q>d@jtq?fovl1clxP%gSn!^*nPhoeA-x*N6oxYw7$~xAiCEpb!Cbace2(Bk zmryh&Xi0)GEtO_{YVc&ChJDjhRK_bad~qamfeNUJ@zI&;uo7qa+7uj@N%#!Yq_=xv zcp#ywxzP47A;x3IrR%r<*%OV;jj8g3b$|6u@M*p4|BU`|si9YfGbO@+%}*89><*Z=DH_4kI}j#SdZ(Tu1PJiY5ABFW<8N+Ot%tbgmh_HUYwC22oyCV^5lhiZB- zA31kWG%|)wuw1xih4)U_u$XKPxs2g~wZQHnAzd{om4d5tc{-+I(}hDnhG|XMc``}I zMDrH4kX3_?2QV46PEFI6qSI?kH#ycs#25{4{c+W}EJDF7Q;oO&s)IF0gI(b?_vmPf zmJ!@&!hs&oH^&4(cf~)s5>=I21m)Inn+3FPY^1L@@jdFGDz2IgDJaDTkV-3)CrmSQ zRqJ#MW8?vs#K0Jh3d6;LvEtbHY380QCRKlo>vV*%K{CuVhQg#YBS8kWwaT7U4v7=G z;&OGdK7I=Sx)uJl74B^K>(|0hN5RvDaOV+QZqM{|*R?&5aXkHK7)&W-8boUvicS5I zsZ>{Qd;9Nw+@UL-EHVRtOGSbnfZkO;xQz^vv+qn*_Ya?yzN`l`U+mJ+6V~)m=?Ifl zm&pwGk3b{imj-N>XjE3R)a4s0@$$rVS8{(%J3vxmt9c#L?Q@;`qwxVjiDP5U#?>aPeuPgi!|FX>d$ zgu3W8!>EJg35CH+66ZKBb#y~dPn;~8*(aBOaCEPJ2W>;Awj+2r(T7f|i|sS!M4_Ii z3yV2tr1%spZ$O{xFB8LX=y9RzoNpDzgPnDm1*C}tEsrSz9FM*$OQ4fgvA>IUY4}&W zi5tr>Y+l%p6l4ExO4_Rii^C*PhF?N47RKR@uVGv#5WIMvhX z!AO-=IPJK~4jNZXjX4?5ogXU<^1IFhB}f#n=ZNHMI&r4UrH0wKC-8SPNZM4GFc5B2 zF(GPa&UW`Uvod93lq~lo3q64jCJH}_;04yZi73%%U{MohTSr$*YfIEbdmHD&lmh?y zjDu622a{@riD&2Tlx;F;^IN|t?bl_da)!btk z&sxuRas)0i%TY2sTa2**qvapYMp$k>@h4xGt~_QvO%jo9+tkS8Xk1oyVPN?D#fzf} z4k%q@AHu_xt3K{eP5YZ@s_}2{N?<2IB8Y6RNJ=($arFGflK^ogz`~dF$6vNVD~6XT zEGmET%klmzeqFkrtzzmPO_9+ZrZ5WZC>pwB+MH$|bI|HS_uR?tqCf*f!>HaHyPb!Rg%y2n6;B%R5VWfXFgTXpEKB~H^Q>Mk( zRl`SL{nvjc+5{wccoGssE>}XTu_wVEg>l0o0NvoyAH=H=SuN{;fghoRN2GKl0);0y z%>cs2v;BG2N>Sk*Mpv!LIQ0Ng=_ZDYhKH-+{%28$Vk=xd{Kwu3R-~Aj2;P6y47Oqj zKr%e6YtE#;V73*R&HjOW|GA-|EVO+gbDnKAwm8ZVVlEydMvSW8!V;`i)&JzSk zkgjP^zc0Wkj1|Un+=qm)g7QB6{qn6C%HJ>F4rlL$vpeXV+uN!K1uIlizZo3y|3;sf zAOb)_<0HdkLkTeDaH*pHwZ=RiYhlU&i2WClUlhTz_m==`yEf&j6JTld*f+34!=nf{ zIZZl(t1=PxHE?Cpb~rty>&ZiEI!vW_Td}C>gq3V)ye7zOZ0Z4NU40!OC!ylEibp(# z#_G)TwFY+Z;92l&7ky!;8D$+FwUqD(N10v&ma16voQ%glKb$?)*z4Sjv!)ZJnLF}0 zH~~Ag01E6HjS6)YlL^_^;XX+2(a6v#x&zZfM=Lt4A&4=?*iS0b!G#CbrR z548f0dc8rhW>{n5VLe|Euzx6K@(GEoF=B^FC9gq@To{$Ees6PJ0p)%2tx3L>e$v7uS2$;QAM`cHGps1BnI z*Py|2!>0gaa13EYgN^YGp9&rq?NLx2tV#T0J9zL3Nh@A#vvvAR*EMv^>ZiUlXyI=; zq|)IZ*{+CV6Nz5*B&alu(KYn!H$fxi6nhzJX$a0chj|f&?{E9}7vLAZk9VIRA1q*O zKRjL8Tusxp9NW}vhgy>g`TTHZd^{s_-;mw9u*{vQk@(wj9L1l}qB-+L{A9ZBxM~{BRsf;t_B6DW zZtqB^6I%G*wXQl`a9{;rY2%82XI4&e@>r=RwIv{XISo<)fX%IGuCZ7oC}{BKV142E z>y21^{kc+2IusbNL@?=!!=z8brI2cD16=jzDstql-oyycs&Pr0B9$GNOcs-?@?*or zgt@79)@e+|^7I?M1edx) z-5+gzjcvc3J=@yZS+_Z+Dp-t9qAATR`z!DK&#%zEIJ4-m8er6##T>$lO;!4H+3|~5 z(D{6pX)b03kk!{YQ(6tg^4cN12kIhY62NtrD_jEu*V)1sR3=KrQW)I} zZZB%lh>+Bmz*LKceM7^ku)sIH3v0R*%m;uRiDtqOjj(AMxz-V7ZyAD7HeXx$fK#a(TvvrtZuiN z2uX#>b~G$5*u16>np)>zKpQD()!}N5i%y-;7F{ASmeTBWX>MAsJf!{<&=Q-{81EYZ zXm4w8>gnWoSF2f#ErvsF*TI$T%N~&Jec>4p>Mqq7RsnEE9i(TE!-`Anvu0JK%e-J+YC){r85?NHp}(_ z=+LE$7yF^Tk>W_6Z>P$zq@lH#Vb%qZ@T;`5>~AdiH+TJ)*Mb$!LkM_O+zIsZ%x3%l zD2$IJX}&Tj4xd3>8G&H=cKO~BIx8pdnAYDXmNcF5k)nLp)kT^kS!``hO}(ja-~Jns zvh%{9*$TJUK@;Tb(VLFrfSzJ8v9Xq7(sR?WIdgYY>bG{Tef$~v*EdO0WGq>A>74;G zXu$@ZQ;Si+Fc%IY@>Nt3D2J9RhG_?pU9FFdo|$l)Q8n;;X&O^s8>OMss-859?p;S= ziu=@v)0wP>XximtV0WeN%&Qthm8vi%84C*~k_i~d6i3E60pG(!!)^jhm<4o#p0GeM ztbi_1CTPoa6pfy3O{v!2dMgyfCyVCD`*7VQ?EARSHe(?bE8*a%?n+?j@N7^HxgwQJ zFbqn_p0Fj*jYHOP_;NmceE=^F&%Zh6e|cl+|8Ii>X?cdDnjRe##tjIHF7pV-v>`f2 zj8a_s>%M<$`gnH-X@z$mf1?{dxEfqOU?M8c4I=*G0SE%^_ ze%7CSeZoL6f%hKQYs=&~JsG83cH&$%ckvY6u(=9FaW{_l7lMaR!)a6~47*-89I9dI zd^a49FZ`Bt> zcfHJ|#fpGeKZRRg{p+9ntvBJ~Eh9>&O=4{^u`)QeNFVM$(s9$cQuG#^qSch@{yo)~ zP746dEVD}$PR&sf|j3}`MU$XV?yI_ex??0e|H!8N#|z$qbsGW z*Vu|frtLYFrD_JfdYV#wy-mzVv{^3AS+=X%)G%CWm#W`uN9FyO!P0cFv>#60!*Idr zDU)~MVs#R@h}+xV**OGr8-%Awe|Y*aaF_tg7>B>NTROT`n%M*>hCy996&(0?G@{B-Y&yP{ z#&P-r-a>IW$H|D5SV6I?bCirmcIn<#9E&4P7zmKFj6vnPPt;0jpK1!EPZRJM|n=eE!#uC*o5z zh6DywTZXP%<%)bt(D~DWrjI`V^IBKTO&ja@3IdVZzZ@zSIpzdOY+*&g zZ8VNL_^^UHktpve!|{WyN8zov;oPFmUvrjg+q#7%k!t_4udk>3Y-d+zJA9c~{1FKy zOw6gHN>I44frJ*5yZ+jz^4dqx1#16={5uYm?zlp;A_F>B%v~ss@-tyYbhD$9n4xa1=%TI9Q3DC)S8SS>YJKfUR zLrVa~^i?Vb=OCvHEhlyPsQl(V<~Bc@fTe8kx{jp_ZX}JS?i(B-LQ8vNS2x!bYGdK! zkHHd`#cpBjJjkH!;b)@>$9f7CQ{F;hwAlQ(Pbx!vQLBxX`G@xmj1wJBmg1sC2sHOdr=&tu&SO z2Un!gbI4Y7`jj_pu2z%8zzC2S;$0SRy+k0cOAjO7(ShI7wQMff_jS zYuOA>ZoEN%h-d9z69V!pNa?zOL8V8U$JNDx&G`dtO;$ujABtX1&d)S_FPf<7MLAJ* zN0cESH5k_0bo#fBRQ-l%a)qH-j8j?Vstv?os|Gk(md5aP-4{K^j`V$v`j51-#ZGo?qFUo>rEEeEsF_21VP=s&5eC+ zy<9}SWD9hJieWNAL;n6}fA_jSG1*Yw!lc09&7%hR4>^jTEJ-tg&IOg4uHk_$?a^nZ zrZH6+O|}9T{?po@ozIi~3zRENjNKYQrI=g0?^d z%)6UXoP}IoKAy-la=7}2LME(jbkChES*53Usym%dlx+$!1Qla>s2Rt<{knW`yS)1W z-ygzinxK)ID*Q4unz;|R9<9{gnr=%sGA;SHZu#@OaoIvnkm2cYBzhj{WOvu^T?zc7 z7N%t&zoNx#zvJC0|KlhB;}ZV9yNl(m-o7sFT}4vT&D8{Y0Mjt>5>P46iltD`1Qs}@ z;m$p&bgHSNrMtD86B5HhX4HxMu##c?PX(f(oG;^Up;h``65;o?zP=g6(jqNV`SC8a_tu*xkUWt6} zZG_XHN;Tl5x~t`IVFSJCUprDwEeS+;@$25T(w|s( zwTfSpUZUaL#__>Q_;oIh-GR#huBe~FeU4nq5X|+OO2iJL)b(Kk%~VrG2g68{2; znQ#ow#l3sE{BYY}*@F`<-2oZ{TrcItNu)PkzpJt7lLj1kn&;UL^D0bth(%KDH0m$ zOgFZ5aG%$TG;2lH?YqJ7RVlPKNrb|bC{FCS4F`fhzltT$HS$O7DuJjfqWL^4Gt%szGf8U z0jd*i-G4akf1J`)E!cU0&bCD^uv-9Db*AJ@Dh)sFO?6Po?hr;Fzn%(rp5a(rznpM( zf|hHljz|4E*hDUq8yw^gMHy;fMX^s*oeH+D%jYq^7Z-0N6Py^Dt{bRj)3cj@rFNZ3 zHMg*&koS(tUmum$j{J{U3^>?6luD?_df0T&z{;H(RiaE}aHkq(w(z&YXm*roEv7ej z(Z8&7w?As*`v*LibOi}LnlmE_T+&h&s<8~Q2i6REe~9$}7M>>cT?6e=HEHB+s-?Bd z(-Z8u(n5+w&loRaRkKV^@AuzxaXI0mugAOh{mGqb_z7!92vS|cxJY z(3ng01cll$;MvJhp?h?}By=cwLO@xj`x|sn#y@6rCdjy(bwubcD}vgYZSGL6?nzu1 z8eNiGd*Q@xxXEQyd=t%RjD}*+cnIu7ds`3E2J~?Rv=vSZw6O@PZkjR5jy?ZKk>FG= z$yhO%KsvTiX*BeV1Qv;`Pa~_0*{uINLS<5$jKM5GP-vM%o(NP^Z@PyO;<<+9fC^KZ zo6~f)*3V6dZ z=_+jNYV7SwwWLzbZD)HLT3eGEsaQcUO3J`W+w{32(FTt`mM=dBv;Zs#38=YLFK+AV z=$Qm)a@3ekXXk0JB(Hxfai2X=1f5XfEhnahd5h6pvcft3YORnatS8Sgya2 z%M9f%Wd^h7^XC#S+c;iWWiq~kiD&-CynkyExgu|4oze2z$Kd`W8Ksfr55SUYmZsZO zQ7{zhA}ba$L-~PX_QFWrLNQTMQkAheAMZ~4^KXOYujRvM{>zEr>U`;FE_^x9LQ|2| zmN~3*{NUbxfUaAng zy8fTR!gyR<%!fHG7L5sXZ82Qct^p&N5aH=oXNHguk|<)LF@dLWew>>n!S07#lN#!X zOz>z0hX73#Devso*x_>os zBO9h_Tg+rZb7FAD$MgLOYL_Sk1bc}sAy|#2&eW(jQ*p^u493yzaDE#YuirR*M^bv4 zV)9gGi^cFxv%^)mKWKfeY%y_rW8Q)(bUd!?!?&T?Uxza$n0Zi|pM_y6KfdLEc~Kt+ zQ)xU~92hyDxlk;egas~EE^8`knt9BBPq~TC=o63Y_-FuSj~>m{^fB%( z{vIiMDY!Tx**-F!pU_j4D=H+88-MauX_ZwlMcX>_0@e|SgCCV%ykpS8y3|a=VeHHnOX@Z_KAamGDrCt#hF|CWwJ-kCM)}XXrHSd% z#52ogQ!+G|6;Dra{!>#Gn_D$9JUDo1fD`b2K8B@plpO+T>FTxc@yGJJhZ1aDY~5rh zQGnJwhVw{MOeQ|l;EI2a3=fPBT^cB4^Nf%RSGKHBZP;8{9RXaD^n_PFgf|{A?O^oH z?i=V-dFAQ<=j_YAqR6tn{}orie05hZV#OShz7=rI{L)MsNY+QfTLWEiDe$Vvx(rWF zD2Rw6;sja>lv6pP$l$Qn{ac94$fx@+e0!f086@m|BJpEdJBNh6xvcYzQ&Y}6^ zF!Jco*yQL$|Ik?fL_gbRTLgodUexMa#mN1y_ba>4V?>HjWQoLZ7y(W*Xx&P<6`4AP zz^81ctA!)sxG}40ND@#`9UZ?P9Rgk`Uom0B5yhR4#RoW5A|dT=dFdT*-K~LP`j}}J zU9o8La$L5Q#*O|vPHkNMm(~qkAbOpX=pli z6S5Jt2G_PZVz5MX4E`!IIcty^YcumfJ_97VzhJp#>BrnuOeJZ!k7(o&TL>Uxgd~=* z(`3Mvyh7ztssS;1NmxXSDV(6$bj#&4?b*(B3q#?^^@s;A0fz2TVIM>$^0w)W11q2D z>cPlj1qAd<%&)^!VI|SG>1M?#MCN6Xf*B-*v9RsVvc=sBe#iA zda8H7gd49|Sf=TCDaQAeE3_3_6pjeLCWX43-+%diuzjPv@~EkD>r?RYQLwQUUil6; zL;2n7V4f?5YIwSBo3=--_!AT3P3H#AoQ1E4l(uNYSvm}-?VmdflSzN&$s4abRj zyIigzWwF@Z*2Z(i5*Q?Y}HoX3q+?r_P0-<~QeXz3`UU?X< zts6EIa2;Ho<~@>zn*yE1Gik^!o)>zQTYo*(R_IOlv}aGVgkpF+FwQDbgFr(XfY<>k z^63#y$SGn*KUbnk5;2%gFov(uY80%0|J_8s=B|0EX zhf@;f+80NJP3k^(bdEJ9cemn?CLpBNF%?42&R#=EJC}iO#UO--iTc;^M-vbdx(bA@ zdhr~~WpY8WvafpanBk5R{<;%fe^g$Zts!7chBXAHYcW9(ERQTs9JW+EYR%;lEkn8y zTAeC-HMDxlr>ddhP}>-mnN?g*5io{IdG$qk?QQwqAK}uy%I0#gaHIU@d3AbQ-q)T& zWORJrwRNWHY)_%Px2w=mXlvs>O(q879-m=ZBS&qM2juvVj}jE&F~^-9y%+_#p6+AL z?l7_B*(e74w~ z%XamOZZq_2N*E*%5q>mxm@wNpL=ZMiu0$mW9@MrW;j|TddKJxYVmPv~%Kq+i%-XH> zok>EWV{3JS0xO4cC^FfW)}DMagop*VKVw){LoNV)db4pKSUz*!9X^$qiL%2VWhT_q zdpe_FY1|Tc`$zcWR%QL`K^VZJMc5PkRtDM4vr;(N`@uA5P45eTPJQ7A> zG4-MU7UPugqQ;{FGH*IvDL0 z8$+!PGd!UV{E^+FEvAxt0zQyE1Ow0me;@HFEHM#8s$|$cCt=6HYvWJ!k0>MK>v&7E zuakKz+pWPisa)I&7T)J1Xy50VMA^7ql zcswU(fDHuUgx;723j5m^!p~pI*FOaBZk)(DhBK(#=b%GSCpPZr3D_B>fssBKZt`5; zZ;D|^=nhk2#&2>RWzjXD?_w7i`mT%b8dY7hQYYyq$6+nk_B}U6BjKEsmZBnWEjB<_ zc+|O|sPesy%J-Y6el<)}x63!KRhB*mv#j~UvOsEsA0szlXFmG8H%o#!>W4RuF+3Bc zZn9ZvzUEQ!wT8rCkf7UHfC;~UkATc@4qgGo!NxU5|8n^J=)eBs{|x+dYFJV5-xCE1 zg;j&Ty^fV~0RvJOFt8@U^(W!wZw*!u-xU+w83X;2`Dzmkko_#sx?&$VbI#RZE0@In7pi@ z0c(Ok?|8f(D5#q$Mi101dMCouY*M}XKSu{jg99omwR#y?L`C@2nXu&=cwF?up9oGvyEK!QAfO%U>7Z|KRZu-|MvW zXdNCJA_NK+)7`_@9D3;^ND!cba#!K+xk3U(&-4#(`I&2&=Dx6!aPr_E>L9>@aGRey z+pjo!bz7XtC#rD{F?`vG_Ly%||8|T*H>oBMALY}ns!tDyJiAwU1`pSc*!U)Oq1K34 zDQ+YCT;vxF)!mv^4H%QgF0)V9g0B}Ucea8DFT}dIG#c;#fKMYvu;&of5n!lv>*@9m z)sP1e)^7oS|1OUPR>Iu765N`RJqYB^X7ddqJT_BR+u?3{+=Q)vZ)riVU8Xl-?1TGd z`5K;@*;nEx9lA>nP?+>6-~wc`s!tDyT)!VI{Bh(eOWFYj-R$sDZ)-trH11=^baeC3 zvHH5Zzq?y~bsHl@;WD`KKuHf20De4iy3U^~jq$DnBW{YTvmKCDgZVp^z17Os`{CuS zVEfM#Ai&84ljdHmR;A>C>3j4tYVOVUWLr-ZGwSbau_~BUDXNe$4vlzG#A{z&+&n-9 zy#3YEX=S?@mgCcGb6l8ghlHgXpyuAdItw;BTBy3!7#Gu{E5_weApjnf*}- zT%CE-qjzWxmG1jAgtRl?ok^!9D*p3$4Mq1R$6>T{kPnUeBN(4}H58A&k2ne*JP=13 zzG~Db`?u5X35^HQWjs9!oKL;k843k%z zVAo)nCG}NX26qAf?VqEi$&tRkvC+YCpmS!Z5skx%H#*k>;#f1n*jq6pP~pmNZj>K= zJh8w1v2yu&gNadrikkuqI(Y6xf9Y5=pl3UtfZbY|xmx~kG5q!p@bhVl0-0$s<@K;^ zFI9P5&83pTula)A+T7dO#n4co32#3QZ(YI4&%6;pz%ng*xfz;G&y%S!$>ewHZ?!pM<+$&s%2RAWfb#t>a!&)B@r=>F~%;=7y`#Z($3PhS|Kcy%V<%+jg zB+bzxxaIBXU|}t|^&0deRO!Ba0iju0wHmu!faK0NoI6fu+Tr_5MqP?phF$=_xN!0P zulF$`ehC>Db>UdP63%~t-yp1~mvOz5VVPWK9L=CfiLhyHdU_|P#?OwA^$m>yy|Jlr zr7;wnsIPO(zqloJHb8$Dqw5gx1qe=rB{GP32jn-QSQl+tuUn z9*~z#!#zOxhX~;Nz9HqsQICVxOWfbS9NgHc%zc#^UcvN>IA^Uq^Cehc#)L1B+F9d) z>0t9{m!h%_O{e8IJKA$?g^v8`Y^J-L9n(ZJ)Dc7yOK|sUaQ!J@nHYtqf-eFf;kZl< zGjy)fOUvQ>Qv$-dvm<9pzYmwj$0tTrp@ng4F0LLpwwQE|Ohl$4##w+9qt$0CFp);n z(WznG)>5?MtexV5lmrklor#Ib37F1gNgXRG>lheZn<{ouk{tc^2)W8fVfotG44*HCYwM=Pw4<$&11Xbgj#!X^ zYzsv@XC@esrdbO7z1jBcX%-BNKVn+_ER<_!IXY7X-(un`eNGvS;GM1kY_y&#fK)}Q z1IXN|DW+tItv-GS2q~eXI}Y~#`xg|U`mwO=6w?pGWaD8NN0tDX|Fs5?(m5_b);b#j zq*}M_a$cdMU}!&7?*13~(=H8JtO3wH#)9W~Tu!Y3fOjP~o|3rX&_1>?am%Jxbxel) z^5}(Fcl*#tfS3%Iss~JFBDDl@c_T5|%-0`g*FHVXkDH$fy zf62ytHEQONv`0rK2hWs7##mah&ge$r6;#o$#~xMNSVQbMyzUXj>HxiCGu{bm-N@&9 z(r`k$6ys6W)srWkD(c8nDfTca@@?Ww^@N$))boYCW|`~MrQ+@(P?SpI{Pl$SGquLC z>>QJrbO^xDaK-jh30yIm$DE5_v@Na*o-K~yh%*JH)(#YJZc~&v7a^|#fqa5DQfEl zeTWf94*{U%ZIS^fkBH|R)NYK?+(T;Y9NYPJS&$W+U+g}%?l}}b$RU7yOO@pa%Xlji8 z#j`noiU1&Q!pVu!cq8MUt}``sDSlb#s{wM|N0+(BT;`r;(oG{l_BViNo^(=78J`QePpP)nF;>T< zxJ-@Vo@;ZhvIOLjJcbriJ3WT3Q?<)BHJ#ej>JBF}AQh(~QQ8NwO|AAh zj?bin*uXnNzc<&L7XmgvB9)I003_%#0Dw-Wo)q(K(p-HfX|7b6HyE3yWpVW^4}qdo z66bFx&7aDphe*+H6X$Ow&7X!*z@x`xQy&6AM@*cnnKV}#!h47m{WfW?Uea27Oh0Ap z36?llX2hhqdP(c*(MX9yr0BOO?K{r@PQP>5qJ<#QunmWJ^$utsTfH+ebdssUoWeB3 z@o1&ymaC8Fl!$Gnc)sB>U1y>}&y>a{RH}~*6oMC@5l44E1`D@??Qbd|hR<~Tb_^~b zb?`Tm;u3cu5!J-(6ca(61qDvGyi?VsKXLE8d&C#mm0&!^TLrHcEoAOsxp!JcHlj5= zI;yBBX*KDh0Gwl=q}oda@$;u7h%VQjI7NFoS!|>B;n7J2GCQjAXX{*5VC+oMWMO+Z zy~!|xj~D;v>umi|v9Jf%+H~dh248npVAowPRw>0<6ps)r0XaM!R%vRC4}v&288&k= zs@JZ8cz|s`Vf{DXN3C+Ne+X}ERc3c8yU!WOAOO0ypEBqnHaz-l^-m6s{x&)?)IY{I zT|6lM2>hkNG52O^Z0vA^oTtc6vwwTLw z{c^fjF{s3WZGVEV7lI#`%a6Gu647NUvKqRk(=bod(^8aY<9$fy_X%}kybRItnbt?1 zJ}99!hN=71%;hof9Sk|%r$U2uWaXX11}+_j!k68M(0J4^=`cN8(E&_#d;yRd{zzj_ zu4%l)2-~#sdMg9g-$_rb6u0}XiRh}w{}Q^fA=VE!JQ&v5=-F!Lx_ zco%-+`bvY?;bKxRBTLXnK-WAPxSsO4K=H{leUtsabH}!>K^YbTr(yozZei8v4q<9hs9r~|P;AZga^F>Eu2wE>E7;+9*lC%`lMAAplG+-O|m{I6xzCG?=MQ1uc^cWd@2ZirGK-zP~#MTN{LsR1z^4XmMq7DX*Ig zr*rI3^|U0j6WQ!?1#*DRG_nA+U5{Skh$ENgxmSR-V8oWOWfhTyL?^K8g6Pk$NfXuSLn_bPXB|eR$3z% zl{XiR!UmaoFwJSKHNv!iH;^dix?0;)`e}Zhe0;s7yhB%=#gROBs;e3r)1eJJF*55T z(I#<3ZtIvMe5=437_K_ANyS!Nhb%CO8LXaM0wHQl!2ug^++#|6OM0-w5{NO8Fd$e` zJE_Ta!!2b0!3(~6lj&m4mF+TJT#m56^6g&v!z|n_iF?7J(J_M4xlEz)3Rkb)3>Q`s zm)D^pzZk!#g=_Cv8y#z_Fsy*Ztlx)W-)mC3{}-nt0$sN zhATfn>#xi{2(K=gUqM3zGH?+u+h1s0*OZ?`P|wF zruQTa!&F@)5fV;+=7N|(NTB*&;dFOPPft%8sPLB#?lt>_NW*3JnuJ`v|1o@YA$YV~ z{q`dQ&Bk)q5HmfpEUwmg;qlcQDlGjEg}R( zUw}0E#wHO;hpC65In>8iINecb&g5E}d(zy1^&A5FF>ysJgorrPq7<2tYZfb|AX5JN zAy`-|zyB1hzpPx@s(xIFh1Ud9IxS!TDmvrSwmDZ);WYfy)mao`Z6jQmy>o3gPTFaJ z%cT%ZewV;M9l7QV3!$>~Bv`x={Bf!J{Yf}?M=U#UDY4NUsq0MLXHW{Ml<8>(HAfXP zUFlr90R=|J5;fQ>H(yt7zh^(RT*I^+Dt>0V@`{XC{~#@wx@sIyCBx6lSOjF{YULxB zJEhyE<(V!6*41<>IG8rq4Fc$-b6q{B_?yKLVyEbvL4&uk4AND}jbs17^vYF$$WtyhWMa~UP3=U5X_KyyaO^!3)*6cRODjz*1RD6M_Lg-Hq%b)fz zWdHHp{ti}M#atu!&Bj~4JB@A{hVQ3bdZif#H3?%65GtWejtmS9Pn<6epP%GviisvM zx{Hg9&j%SaM&4A}`=NrUbLzFhwy_5|OV3SFle25LI|l`A0GOaUIa)R}BRAMQ4SGu_kC-O7w#zh1CR<<;-V zoriammI>}u&U!2pq+*87KOed3c+9>BG_M4zI?KS7ufAhtR(p6*8U!QD@d3w zjnxE>F}fjF^}yq@kS2!42dB;_FElE)iiMVZOGuBie06E2y7+AW$7*@|W%QE| zUWC_P1=nAcm*2n$!Pg7&=P4*Fm2yqb@pXC$jSdW)FO`OdC(oCLfKcDWVBdJDbZ%;3 zVBq)C5dZ24D>mpQ4tmOt{)q1yPB8r$eqq!?UF1ad@f@xn+eXz&d8VGiPYH+cU-tE# zIa3-Po51hYom71hOwA<{Njyiur08>B17g76k%<8a#K3$OdrN#&eJq1178p){5AJM~ zS2u!te}<2DtzmjK0CrxY_~lL~ap!5ta9z z1~0$h`}XkCFXg?t^46c_Crja_^?yTmpRAtDX7q!Gk2~IEG{}5cvG_W0mGl7lUgT#7Dn0BI{6hm#I-JziDxyfdXJhF`JdNIC%TJOR%Lt2B|!Ji#3S2 z+X%22DG!whs*-3-$w6#dLv^O{!82#anDLKnBaf+>QrSa47W@jPUx&{ZO&+8vS~D>n zM}~)n`i7a0YEE!no;a?aYDD?+^I#tPlCn*qV#;*?XETLdj_VR8h7I1VfX)oMkOhl_ zoo4TBDfWUS;87{Z)@*vmWHY^;r*O>XcCJ^NpbhJed-CHf@a0&vnU3VH=FvAdo9Ql| z!a);=SNCp*mqo9(Wz) zn`xF%h@SW7gX;7~czw0HyQik@&@F0fCe8M>O|A;mL}^M90VeKFRQ5b3{U+M2pm}~@ z6V~n-)}36#$dpL4H0E$vIu}fk&7^bL4$ki^P+$ns`XcDRtSu{sKm*P!Ek&J}z$S-V zqf9o>j9-tS@^LW{fx*^ZqB+~ZgcKG35kXFkKrBP~@k-)0Wr`+ShNjbtIh)C4(_F{C zI%2@^#JkU+h6{r^o{pm#Jb=9NmW%=T`rrv{iTq`?GP|?Sg`CyUFvUEvjU!!=6c+(B zJTx*qio{C&Y+up(C`6B|TE6@a0dDUYjvg%B2-ZJ^Z{G(CUn+ksv5?IaT4|W%J&nr6 zj?M)omc|BvR%vW_s6p|5?5;-(=G|EhW^ae{v*ne)q@mPtoY4`c$+HE#b#2g0=!L`N zdumMmv612azP=%T{J6ufY?aJ;TCu|T%*)`>oBgl%gXx+5oy}k3a!~)K2$(?77G4R| zZ68d3s&4EHYOG~~R>Eww|Kh__d6S`=F!L$`4 z;FVzE_8^~21S-0Q9mQBN>szB+U0p0co38Br2yd|Jog~d9tq+V$o*Nxe^w_nr7%dja z+h#vQ-C5xh3}Ey2Byyc zHc^_y)-MyK;e?`UvQVwXMGT8QBSFT%!s~yA^G~FXkN}D4*^GmYAf}NamD!;V4UJQ* z=axK=!Nm>WS)@I{AA;R4@5V-+m+3|VCG(YwP5el8(Y5A6SrO{wrcbrDvz67W8q?Zd$zThgA1jt z#aFg?W^o0J%fa2JKLv_j&k_C8r+%7zb@xx~I`%WgsiFg zGa#61g&^W`r!AL17KTF`SRjd$Eno#bi@o#YAxqI1@M!O}wd8Y|Zsz0g{be-#-1t=8 zxl!G@9X^_4Lu!D6rDHH6HO#fPXMSyI!Ne&S)-N>@rEm;tbT~4^Lp)@IaPdZOb~f z9AU?>4Z}654<%b{Zp-skdQq_TqW*65DFdN0{Bur9m(}S-&*9~8Nf}cM$zO8C1oPRB zd=|!HWo>CGcSXLE#rUTWSn=ecELx0>=cd_}kg#mJ62Oq2-tIKN2{C^_7VAx&qyiVR z_QD;reQ3 zVs;HxNVzXCHHaFEVCB=fQ%JJ8y{nu3Fy3K?`QPskmb>vn>s)b46I&I~C?L@G8Ea;- z8EK01!BXOx7lPdW^m0SaSxlIrVQM<_+S**jkptG{6`ZR)`U=0Q(;L7F_N}o~qOt%@ zBC#}zt-Za#jT2m5sXV`p{o;PTZ`rP8_{{1SbIsXi{%)}%->Atooxx1J7jwbFJJPn$&tf(mzz17$4xilNfxF9B5(u4~lc{rq<3j@+ks4Rz&5Er;$+c0> z6s94l@%?`O;HD*tLfD62Y@F^qm#--G-O8@2kVy5+?g1z^g5JRuNu5z zzlN1sVPFY+^J(t0BRfRKQY4S>G3h-T({fMjo0ir@svyaNU@PN>l2?FBDAbt#6&73Q z7O;Q>T;NE=Sb~jfaSW3}ypEvI#~N)1bThEUMgdAkcc#Elh>_GEq{MS%QhycG?D2hwFp?S!MWBHOo5^Z%CVVl@Q#ui7OM2yTt*+<87}o#MO^1d9Pniole`;n zglScz*)+u5OmPLF@f>y~@0D}o2)49-ofRQQm9s>v5j>wV3>%d@4 zcsPEcOLg)uZdIn=s$vB(J2YkMI+Gt`Y1BSu8=AwMvEJTHfqxlfRHGv@!`b&zqFY=+ z9vCjm}uQ<#|GsOiL*H9Wvl{!F44ZO%V zZm1*F*dAChF)D)^noq+t1u?Gq)nQtO&xTD!#F#waCT5qwVWe^m(&t7$0>D;SupbR1 zGCr+`2Zx?opaD>^xrHHcfMR-E0QrVm^@sKF5=K-Bep$!h7Y4jB{31sk8B;7|yG|i% ztcI-F-@XuBm=ET!mp7jR78QBJ^IazYg!;9AFa0*z*LPMCL1Kymt{$Hud$6U}pI6tO z06!{sUxhcWRJWg^pa$FP(kwu1$ST8R>O|QZy%m8~t%a^r9og2l&U_loT` zY&g1~qIs2)bXWFg2&0U=aIJD_85n}w#_}6)8=aF}CGldqHJgtH;Q)l+XM!s~gp%?B zPfrx@|GF~ss&bi&tH46Kj-h)@0Y!sr@7MRQiQ&HU<9$=y1LO!Vs3W56{gae|!S#>( zdrSMfe^u|j5a=F)a)L_c?jGPp0|r;y$MRfLHti)B8rFO#nGgAUn0$yBhg9a}4axf# zY6xhE5WKjADS)b&YwJ|>2CQKcR$_kRX8xo4W(nP_b$m&_B4A`1c>z}h!8SaV`H#`b z{)y2M#br=u4r0638Rj5Hlq}vwX6<0Wi%hXnHIJ*|Gw5|?nCU{HGYvyzi;4X+?I@>( zUQP8-Wb`lciM7Dia8QQ?oGez1W2$f>-tJM1j)8=#n-WHF^C9~E z>lnv}tV$RdB1ezF&;T-n`Ht*=s;)>B2T6PaO9Fj54?LFS9?A9=bKR|qT_sxCVo5Kq zHE^);ZGU$+c)KODkU1z=dKIJ1>5gQZqz;`Q9-CAO#G>sW);*(LV7F(3g;(X(@71q= z#2uI`w`POs+49Q=EHE8d;W-po3HHhG;K;}zAD?HKLf1nl+es=fRz7S7FR$XSH>>3< zPvDQ$=|xrgt_1=oYAY$KGmf4;J25yq%x2`u$TC-4TB9&W79k@7d<&F2s-~y_#DOz=|Hsvh6%P%`tWrV#9E#PKHu3 zIdBe$#ndm-3a~PnbayLYOTLXT7J>$#Ubz~~UxQzG6fV*|#~o3gVUP3gkz;>U?aK{s39Ng*>OA-Te-yDr1cEt$|Z*HcEeAr;rH*=*Y~T752SSko?w$V z`FpnMo4V`K@QX8j1A~LZ15@0Ghigz`t7@vYz$KUAu|5)WYrR^ymGZO+&FA zEgNnr3^6`AGn^# z4GeIn-0*nGg9)il7uySMoeA7{zW~4B26T8mIs!rKP{YW@7UrX9!8h-MxDvd7h&f%W zPa8~;8o;qD3d7rUYa!Q_u+1*M3%-4b8JoDE27RUA(DVSalhhOXqHU8@A zGZ?pe=VE#F2c8$XJrrg+B%}L2wccB7XIj{p*{){X3!MMDj(k*j@X|(j>5m4qxgZ9Q zn)xhjj?MxqfGp3^2$rvev%B?8B@(Mac!rTOJ&P$eRGP#t5ebDL&^Y0tJgb|Go?m%1 zQ(k+B(SIK{VJDk9e@NiQg1et7ZrRgb%;&hTunr%nf8~3BfG}Tvzf|6QT7J*eS%$Io zl&53SHgf&Y*^amLkB^-@tMCOoXofK@5zs^%15IBpzhA3-oDHwPDZjXc0gel|cs#&v zc<0C+-P3WZIoH8y4blxM3M65{FsiHz+A`h~euGY|wU6cH2VA*c2|!QzG`6^>qrI!6 zy(dRMt3^m*7%CR8U{X0HhVt6m^5c8K)%R$;7crhPBwvZc_qiwvi>lw)ppG8Oo{mDU zxuqkoGS#|GhRC=RwJyjWdho6M^s)pfA)`d}enBA)NxU9Y9ba=8ucXWMco4JYsmy$VUziWLe6_N)QhBmj{_|6?J}))haOp2}qbMyCavn_2 z0Subp%zsS3%CXYq$|!O|3K%MeqEs;{S*3Q^2dZq7zA%eAQ-XC7SfD3@k6 zo37@m<}rD84Cc{r8jjAEcf)-zw-5gB%8J}jm90Pc+);_!Gub#A#-h;E(cIDu8$72l z+L%!p9M~_+&9J^)zW-!@cenazFMPfhZgQn$B1DX99TRluYh-Zc+PjOLtyyA-sqbqb zs=Lu3m>3z}7q7Mx@KNU5AiC3SY;w;xfa_>e-K|(u5My^4lUvNe%F<`V`RN6`GvWMF z`SGgMy!XG|RM?Xu*i3w+rc*t@PI280#wX4X3{RCtKs_Je+5)(>40{U$S84DW3twJ* zpq1%>To2}-CZMP9CTt2O4pisN9ufM!v2lG&=j4Yti`@{`d75@!gI|7fyZrKgW$R6| z@|lPKx{P@VZUb6H9Cm9u+uf{iG}Zz%9C+x}kg5;9fu5WE&;ueS$<@_ty3zotC(S

a!9rZ*yDTRiyaWgLWAMi~zkPLCYgl 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

W56KdD?c!q*+X*Oe)p?Q$EMg@Zm@xjav`AXG`Ah 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 f`MaU}PaaiPuVIM$ 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%0DQ6z9T5Eb25O1DY*8#n>nve9ozy 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 literal 0 HcmV?d00001 diff --git a/templates/银豹-采购单模板.xls b/templates/银豹-采购单模板.xls new file mode 100644 index 0000000000000000000000000000000000000000..a8fb1bcc79717cd8d8f53776b0511b442447c17c GIT binary patch literal 34304 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 XgAlF5MI%Ou@M!)DMt{5iIt}~}ckBLS literal 0 HcmV?d00001 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_calculator.py b/tests/test_calculator.py new file mode 100644 index 0000000..b6e734f --- /dev/null +++ b/tests/test_calculator.py @@ -0,0 +1,222 @@ +"""app.core.handlers.calculator 单元测试""" + +import pytest +import pandas as pd +import numpy as np + +from app.core.handlers.calculator import DataCalculator + + +@pytest.fixture +def sample_df(): + return pd.DataFrame({ + 'price': [10.0, 20.0, 30.0], + 'quantity': [2, 5, 10], + 'name': ['A', 'B', 'C'], + }) + + +class TestMultiply: + def test_basic_multiply(self, sample_df): + calc = DataCalculator() + calc.add_rule('multiply', source_column='price', target_column='total', factor=2) + result = calc.calculate(sample_df) + assert list(result['total']) == [20.0, 40.0, 60.0] + + def test_multiply_missing_source(self, sample_df): + calc = DataCalculator() + calc.add_rule('multiply', source_column='nonexistent', target_column='total', factor=2) + result = calc.calculate(sample_df) + assert 'total' not in result.columns + + def test_multiply_default_factor(self, sample_df): + calc = DataCalculator() + calc.add_rule('multiply', source_column='price', target_column='copy', factor=1) + result = calc.calculate(sample_df) + assert list(result['copy']) == [10.0, 20.0, 30.0] + + def test_convenience_method(self, sample_df): + calc = DataCalculator() + calc.multiply('price', 'total', 3) + result = calc.calculate(sample_df) + assert list(result['total']) == [30.0, 60.0, 90.0] + + +class TestDivide: + def test_basic_divide(self, sample_df): + calc = DataCalculator() + calc.add_rule('divide', source_column='price', target_column='half', divisor=2) + result = calc.calculate(sample_df) + assert list(result['half']) == [5.0, 10.0, 15.0] + + def test_divide_by_zero(self, sample_df): + calc = DataCalculator() + calc.add_rule('divide', source_column='price', target_column='half', divisor=0) + result = calc.calculate(sample_df) + assert 'half' not in result.columns + + def test_divide_missing_source(self, sample_df): + calc = DataCalculator() + calc.add_rule('divide', source_column='nonexistent', target_column='x', divisor=2) + result = calc.calculate(sample_df) + assert 'x' not in result.columns + + +class TestAdd: + def test_add_columns(self): + df = pd.DataFrame({'a': [1, 2, 3], 'b': [10, 20, 30]}) + calc = DataCalculator() + calc.add_rule('add', columns=['a', 'b'], target_column='sum') + result = calc.calculate(df) + assert list(result['sum']) == [11, 22, 33] + + def test_add_constant(self): + df = pd.DataFrame({'a': [1, 2, 3]}) + calc = DataCalculator() + calc.add_rule('add', target_column='a', constant=100) + result = calc.calculate(df) + assert list(result['a']) == [101, 102, 103] + + def test_add_columns_with_constant(self): + df = pd.DataFrame({'a': [1, 2], 'b': [3, 4]}) + calc = DataCalculator() + calc.add_rule('add', columns=['a', 'b'], target_column='total', constant=10) + result = calc.calculate(df) + assert list(result['total']) == [14, 16] + + def test_add_string_column(self): + df = pd.DataFrame({'a': [1, 2]}) + calc = DataCalculator() + calc.add_rule('add', columns='a', target_column='total') + result = calc.calculate(df) + assert list(result['total']) == [1, 2] + + +class TestSubtract: + def test_subtract_two_columns(self): + df = pd.DataFrame({'income': [100, 200], 'cost': [30, 80]}) + calc = DataCalculator() + calc.add_rule('subtract', minuend='income', subtrahend='cost', target_column='profit') + result = calc.calculate(df) + assert list(result['profit']) == [70, 120] + + def test_subtract_constant(self): + df = pd.DataFrame({'price': [100, 200]}) + calc = DataCalculator() + calc.add_rule('subtract', minuend='price', target_column='discounted', constant=10) + result = calc.calculate(df) + assert list(result['discounted']) == [90, 190] + + def test_subtract_missing_minuend(self): + df = pd.DataFrame({'a': [1, 2]}) + calc = DataCalculator() + calc.add_rule('subtract', minuend='nonexistent', target_column='x', constant=1) + result = calc.calculate(df) + assert 'x' not in result.columns + + +class TestFormula: + def test_basic_formula(self, sample_df): + calc = DataCalculator() + calc.add_rule('formula', formula='price * quantity', target_column='total') + result = calc.calculate(sample_df) + assert list(result['total']) == [20.0, 100.0, 300.0] + + def test_invalid_formula(self, sample_df): + calc = DataCalculator() + calc.add_rule('formula', formula='nonexistent + 1', target_column='x') + result = calc.calculate(sample_df) + # formula fails, original df returned + assert 'x' not in result.columns + + def test_formula_missing_target(self, sample_df): + calc = DataCalculator() + calc.add_rule('formula', formula='price * 2') + result = calc.calculate(sample_df) + # no target_column, nothing happens + assert list(result['price']) == [10.0, 20.0, 30.0] + + +class TestRound: + def test_round_specific_columns(self): + df = pd.DataFrame({'a': [1.234, 2.567], 'b': [3.1, 4.9]}) + calc = DataCalculator() + calc.add_rule('round', columns=['a'], decimals=1) + result = calc.calculate(df) + assert list(result['a']) == [1.2, 2.6] + assert list(result['b']) == [3.1, 4.9] # unchanged + + def test_round_all_numeric(self): + df = pd.DataFrame({'a': [1.234, 2.567], 'b': [3.111, 4.999]}) + calc = DataCalculator() + calc.add_rule('round', decimals=0) + result = calc.calculate(df) + assert list(result['a']) == [1.0, 3.0] + assert list(result['b']) == [3.0, 5.0] + + def test_round_string_column_skipped(self): + df = pd.DataFrame({'name': ['a', 'b'], 'val': [1.5, 2.5]}) + calc = DataCalculator() + calc.add_rule('round', columns=['name', 'val'], decimals=0) + result = calc.calculate(df) + assert list(result['val']) == [2.0, 2.0] + + +class TestSum: + def test_sum_columns_to_target(self): + df = pd.DataFrame({'a': [1, 2], 'b': [3, 4], 'c': [5, 6]}) + calc = DataCalculator() + calc.add_rule('sum', columns=['a', 'b'], target_column='total') + result = calc.calculate(df) + assert list(result['total']) == [4, 6] + + def test_sum_missing_columns(self): + df = pd.DataFrame({'a': [1, 2]}) + calc = DataCalculator() + calc.add_rule('sum', columns=['a', 'missing'], target_column='total') + result = calc.calculate(df) + assert list(result['total']) == [1, 2] + + +class TestChaining: + def test_multiple_rules(self, sample_df): + calc = DataCalculator() + calc.add_rule('multiply', source_column='price', target_column='total', factor=2) + calc.add_rule('add', columns=['total', 'quantity'], target_column='grand') + result = calc.calculate(sample_df) + assert list(result['total']) == [20.0, 40.0, 60.0] + assert list(result['grand']) == [22.0, 45.0, 70.0] + + def test_chaining_convenience(self, sample_df): + calc = DataCalculator() + calc.multiply('price', 'total', 2).round_columns('total', 0) + result = calc.calculate(sample_df) + assert list(result['total']) == [20.0, 40.0, 60.0] + + +class TestEdgeCases: + def test_empty_dataframe(self): + df = pd.DataFrame({'a': pd.Series([], dtype=float)}) + calc = DataCalculator() + calc.add_rule('multiply', source_column='a', target_column='b', factor=2) + result = calc.calculate(df) + assert len(result) == 0 + + def test_no_rules(self, sample_df): + calc = DataCalculator() + result = calc.calculate(sample_df) + assert list(result['price']) == [10.0, 20.0, 30.0] + + def test_unknown_rule_type(self, sample_df): + calc = DataCalculator() + calc.add_rule('unknown_op', source_column='price', target_column='x') + result = calc.calculate(sample_df) + # unknown rule is skipped, df unchanged + assert list(result['price']) == [10.0, 20.0, 30.0] + + def test_rule_failure_continues(self, sample_df): + calc = DataCalculator() + calc.add_rule('formula', formula='nonexistent + 1', target_column='x') + calc.add_rule('multiply', source_column='price', target_column='y', factor=2) + result = calc.calculate(sample_df) + assert list(result['y']) == [20.0, 40.0, 60.0] diff --git a/tests/test_column_mapper.py b/tests/test_column_mapper.py new file mode 100644 index 0000000..e2e0019 --- /dev/null +++ b/tests/test_column_mapper.py @@ -0,0 +1,154 @@ +"""app.core.handlers.column_mapper 单元测试""" + +import pytest +import pandas as pd +from app.core.handlers.column_mapper import ColumnMapper + + +class TestStandardColumns: + """STANDARD_COLUMNS 完整性测试""" + + def test_has_all_standard_fields(self): + expected = {'barcode', 'name', 'specification', 'quantity', 'unit', + 'unit_price', 'total_price', 'gift_quantity', + 'category', 'brand', 'supplier'} + assert set(ColumnMapper.STANDARD_COLUMNS.keys()) == expected + + def test_no_empty_alias_lists(self): + for field, aliases in ColumnMapper.STANDARD_COLUMNS.items(): + assert len(aliases) > 0, f"{field} has no aliases" + + def test_barcode_includes_key_names(self): + bc = ColumnMapper.STANDARD_COLUMNS['barcode'] + assert '条码' in bc + assert '商品条码' in bc + assert 'barcode' in bc + + def test_gift_quantity_includes_common_names(self): + gq = ColumnMapper.STANDARD_COLUMNS['gift_quantity'] + assert '赠送量' in gq + assert '赠品数量' in gq + + +class TestFindColumn: + """ColumnMapper.find_column 列查找测试""" + + def test_exact_match(self): + cols = ['商品条码', '商品名称', '数量', '单价'] + assert ColumnMapper.find_column(cols, 'barcode') == '商品条码' + + def test_exact_match_standard_english(self): + cols = ['barcode', 'name', 'quantity'] + assert ColumnMapper.find_column(cols, 'barcode') == 'barcode' + + def test_whitespace_match(self): + """列名含空格时应匹配""" + cols = ['名 称', '数 量'] + assert ColumnMapper.find_column(cols, 'name') == '名 称' + assert ColumnMapper.find_column(cols, 'quantity') == '数 量' + + def test_partial_match_substring(self): + """列名包含候选名时应匹配""" + cols = ['商品条码(小条码)', '商品名称'] + assert ColumnMapper.find_column(cols, 'barcode') == '商品条码(小条码)' + + def test_not_found_returns_none(self): + cols = ['日期', '备注', '编号'] + assert ColumnMapper.find_column(cols, 'barcode') is None + + def test_unknown_standard_name_returns_none(self): + cols = ['商品条码'] + assert ColumnMapper.find_column(cols, 'nonexistent_field') is None + + def test_first_match_wins(self): + """多个列都能匹配时返回第一个""" + cols = ['条码', '商品条码', 'barcode'] + assert ColumnMapper.find_column(cols, 'barcode') == '条码' + + def test_case_insensitive(self): + cols = ['Barcode', 'Name'] + assert ColumnMapper.find_column(cols, 'barcode') == 'Barcode' + + def test_all_fields_matchable(self): + """每个标准字段都能找到至少一个匹配""" + cols = [ + '商品条码', '商品名称', '规格', '数量', '单位', + '单价', '金额', '赠送量', '类别', '品牌', '供应商', + ] + for std_name in ColumnMapper.STANDARD_COLUMNS: + result = ColumnMapper.find_column(cols, std_name) + assert result is not None, f"Could not find {std_name} in {cols}" + + +class TestDetectHeaderRow: + """ColumnMapper.detect_header_row 表头检测测试""" + + def test_header_on_first_row(self): + df = pd.DataFrame({ + 'A': ['条码', '123456', '789012'], + 'B': ['数量', '10', '20'], + 'C': ['单价', '5.5', '3.0'], + }) + assert ColumnMapper.detect_header_row(df, min_matches=2) == 0 + + def test_header_on_second_row(self): + df = pd.DataFrame({ + 'A': ['备注', '条码', '123456'], + 'B': ['日期', '数量', '10'], + 'C': ['时间', '单价', '5.5'], + }) + assert ColumnMapper.detect_header_row(df, min_matches=2) == 1 + + def test_no_header_returns_minus_one(self): + df = pd.DataFrame({ + 'A': ['aaa', 'bbb', 'ccc'], + 'B': ['ddd', 'eee', 'fff'], + }) + assert ColumnMapper.detect_header_row(df, min_matches=3) == -1 + + def test_empty_dataframe(self): + df = pd.DataFrame() + assert ColumnMapper.detect_header_row(df) == -1 + + def test_max_rows_limits_scan(self): + """表头在第 10 行但 max_rows=5 时应返回 -1""" + data = {f'col{i}': ['x'] * 15 for i in range(3)} + data['col0'][10] = '条码' + data['col1'][10] = '数量' + data['col2'][10] = '单价' + df = pd.DataFrame(data) + assert ColumnMapper.detect_header_row(df, max_rows=5, min_matches=2) == -1 + + +class TestColumnMapperInstance: + """ColumnMapper 实例方法测试""" + + def test_init_with_no_config(self): + mapper = ColumnMapper() + assert mapper.mapping_config == {} + + def test_init_with_custom_config(self): + mapper = ColumnMapper(mapping_config={'barcode': ['我的条码']}) + assert '我的条码' in mapper.custom_mappings + + def test_map_columns_renames(self): + mapper = ColumnMapper() + df = pd.DataFrame({'商品条码': ['123'], '商品名称': ['测试'], '数量': [10]}) + result = mapper.map_columns(df, target_columns=['barcode', 'name', 'quantity']) + assert 'barcode' in result.columns + assert 'name' in result.columns + assert 'quantity' in result.columns + + def test_map_columns_fills_missing(self): + mapper = ColumnMapper() + df = pd.DataFrame({'商品条码': ['123']}) + result = mapper.map_columns(df, target_columns=['barcode', 'quantity']) + assert 'barcode' in result.columns + assert 'quantity' in result.columns + assert result['quantity'].iloc[0] == 0 # default value + + def test_add_custom_mapping(self): + mapper = ColumnMapper() + mapper.add_custom_mapping('barcode', '自定义条码列') + assert '自定义条码列' in mapper.reverse_mapping + assert mapper.reverse_mapping['自定义条码列'] == 'barcode' diff --git a/tests/test_data_cleaner.py b/tests/test_data_cleaner.py new file mode 100644 index 0000000..630e220 --- /dev/null +++ b/tests/test_data_cleaner.py @@ -0,0 +1,236 @@ +"""app.core.handlers.data_cleaner 单元测试""" + +import pytest +import pandas as pd + +from app.core.handlers.data_cleaner import DataCleaner + + +@pytest.fixture +def sample_df(): + return pd.DataFrame({ + 'name': [' Alice ', 'Bob', 'Charlie', 'Dave'], + 'age': [25, 30, None, 40], + 'score': [80.5, 90.0, 70.0, 85.0], + 'city': ['Beijing', 'Shanghai', 'Beijing', 'Guangzhou'], + }) + + +class TestFillNa: + def test_fill_na_with_value(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('fill_na', columns=['age'], value=0) + result = cleaner.clean(sample_df) + assert result['age'].isna().sum() == 0 + assert result.loc[2, 'age'] == 0 + + def test_fill_na_all_columns(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('fill_na', value=-1) + result = cleaner.clean(sample_df) + assert result.isna().sum().sum() == 0 + + def test_fill_na_string_column(self): + df = pd.DataFrame({'a': ['x', None, 'z']}) + cleaner = DataCleaner() + cleaner.add_rule('fill_na', columns=['a'], value='unknown') + result = cleaner.clean(df) + assert result.loc[1, 'a'] == 'unknown' + + def test_convenience_method(self, sample_df): + cleaner = DataCleaner() + cleaner.fill_na(columns='age', value=99) + result = cleaner.clean(sample_df) + assert result.loc[2, 'age'] == 99 + + +class TestRemoveDuplicates: + def test_remove_by_subset(self): + df = pd.DataFrame({ + 'name': ['A', 'B', 'A', 'C'], + 'val': [1, 2, 3, 4], + }) + cleaner = DataCleaner() + cleaner.add_rule('remove_duplicates', subset=['name'], keep='first') + result = cleaner.clean(df) + assert len(result) == 3 + assert list(result['name']) == ['A', 'B', 'C'] + + def test_remove_all_columns(self): + df = pd.DataFrame({ + 'a': [1, 1, 2], + 'b': [10, 10, 20], + }) + cleaner = DataCleaner() + cleaner.add_rule('remove_duplicates') + result = cleaner.clean(df) + assert len(result) == 2 + + def test_no_duplicates(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('remove_duplicates', subset=['name']) + result = cleaner.clean(sample_df) + assert len(result) == 4 + + +class TestRemoveRows: + def test_remove_by_condition(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('remove_rows', condition='age > 25') + result = cleaner.clean(sample_df) + assert len(result) == 2 + + def test_remove_by_values(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('remove_rows', columns=['city'], values=['Beijing']) + result = cleaner.clean(sample_df) + assert len(result) == 2 + assert 'Beijing' not in result['city'].values + + def test_remove_no_match(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('remove_rows', condition='age > 100') + result = cleaner.clean(sample_df) + assert len(result) == 0 # condition filter: no rows match age > 100 + + def test_convenience_method(self, sample_df): + cleaner = DataCleaner() + cleaner.remove_rows(condition='score < 75') + result = cleaner.clean(sample_df) + assert len(result) == 1 # condition filter: keeps only Charlie (score=70.0) + + +class TestConvertType: + def test_to_float(self): + df = pd.DataFrame({'val': ['1.5', '2.7', 'abc']}) + cleaner = DataCleaner() + cleaner.add_rule('convert_type', columns=['val'], target_type='float') + result = cleaner.clean(df) + assert result['val'].dtype.kind == 'f' + assert result.loc[0, 'val'] == 1.5 + assert pd.isna(result.loc[2, 'val']) + + def test_to_int(self): + df = pd.DataFrame({'val': ['1', '2', '3']}) + cleaner = DataCleaner() + cleaner.add_rule('convert_type', columns=['val'], target_type='int') + result = cleaner.clean(df) + assert result.loc[0, 'val'] == 1 + + def test_to_string(self): + df = pd.DataFrame({'val': [1, 2, 3]}) + cleaner = DataCleaner() + cleaner.add_rule('convert_type', columns=['val'], target_type='string') + result = cleaner.clean(df) + assert result.loc[0, 'val'] == '1' + + def test_missing_column_skipped(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('convert_type', columns=['nonexistent'], target_type='float') + result = cleaner.clean(sample_df) + assert len(result) == 4 + + +class TestStripWhitespace: + def test_strip_specific_columns(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('strip_whitespace', columns=['name']) + result = cleaner.clean(sample_df) + assert result.loc[0, 'name'] == 'Alice' + + def test_strip_all_text(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('strip_whitespace') + result = cleaner.clean(sample_df) + assert result.loc[0, 'name'] == 'Alice' + + def test_strip_non_text_skipped(self): + df = pd.DataFrame({'val': [1, 2, 3]}) + cleaner = DataCleaner() + cleaner.add_rule('strip_whitespace', columns=['val']) + result = cleaner.clean(df) + assert list(result['val']) == [1, 2, 3] + + +class TestNormalizeText: + def test_lowercase(self): + df = pd.DataFrame({'name': ['ALICE', 'BOB']}) + cleaner = DataCleaner() + cleaner.add_rule('normalize_text', columns=['name'], lowercase=True) + result = cleaner.clean(df) + assert list(result['name']) == ['alice', 'bob'] + + def test_uppercase(self): + df = pd.DataFrame({'name': ['alice', 'bob']}) + cleaner = DataCleaner() + cleaner.add_rule('normalize_text', columns=['name'], uppercase=True) + result = cleaner.clean(df) + assert list(result['name']) == ['ALICE', 'BOB'] + + def test_replace_map(self): + df = pd.DataFrame({'city': ['BJ', 'SH']}) + cleaner = DataCleaner() + cleaner.add_rule('normalize_text', columns=['city'], replace_map={'BJ': 'Beijing', 'SH': 'Shanghai'}) + result = cleaner.clean(df) + assert list(result['city']) == ['Beijing', 'Shanghai'] + + +class TestValidateData: + def test_validate_logs_but_does_not_modify(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('validate_data', columns=['score'], min_value=0, max_value=100) + result = cleaner.clean(sample_df) + assert len(result) == 4 + + def test_validate_required(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('validate_data', columns=['age'], required=True) + result = cleaner.clean(sample_df) + assert len(result) == 4 + + +class TestChaining: + def test_multiple_rules(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('strip_whitespace', columns=['name']) + cleaner.add_rule('fill_na', columns=['age'], value=0) + cleaner.add_rule('convert_type', columns=['age'], target_type='int') + result = cleaner.clean(sample_df) + assert result.loc[0, 'name'] == 'Alice' + assert result['age'].isna().sum() == 0 + assert result.loc[2, 'age'] == 0 + + def test_convenience_chaining(self, sample_df): + cleaner = DataCleaner() + cleaner.strip_whitespace('name').fill_na('age', value=0) + result = cleaner.clean(sample_df) + assert result.loc[0, 'name'] == 'Alice' + assert result.loc[2, 'age'] == 0 + + +class TestEdgeCases: + def test_empty_dataframe(self): + df = pd.DataFrame({'a': pd.Series([], dtype=float)}) + cleaner = DataCleaner() + cleaner.add_rule('fill_na', value=0) + result = cleaner.clean(df) + assert len(result) == 0 + + def test_no_rules(self, sample_df): + cleaner = DataCleaner() + result = cleaner.clean(sample_df) + assert len(result) == 4 + + def test_unknown_rule_type(self, sample_df): + cleaner = DataCleaner() + cleaner.add_rule('unknown_op', columns=['name']) + result = cleaner.clean(sample_df) + assert len(result) == 4 + + def test_rule_failure_continues(self, sample_df): + """A failing rule should not block subsequent rules.""" + cleaner = DataCleaner() + cleaner.add_rule('convert_type', columns=['nonexistent'], target_type='float') + cleaner.add_rule('fill_na', columns=['age'], value=0) + result = cleaner.clean(sample_df) + assert result.loc[2, 'age'] == 0 diff --git a/tests/test_product_db.py b/tests/test_product_db.py new file mode 100644 index 0000000..5b94cbc --- /dev/null +++ b/tests/test_product_db.py @@ -0,0 +1,187 @@ +"""app.core.db.product_db 单元测试""" + +import os +import tempfile + +import pytest +import pandas as pd + +from app.core.db.product_db import ProductDatabase + + +@pytest.fixture +def db_dir(): + """临时目录""" + with tempfile.TemporaryDirectory() as d: + yield d + + +@pytest.fixture +def sample_excel(db_dir): + """创建测试用 Excel 文件""" + path = os.path.join(db_dir, '商品资料.xlsx') + df = pd.DataFrame({ + '商品条码': ['6920584471055', '6901028001133', '6925303800013'], + '商品名称': ['农夫山泉550ml', '蒙牛纯牛奶', '可口可乐330ml'], + '进货价': [1.2, 3.5, 1.8], + '单位': ['瓶', '盒', '罐'], + }) + df.to_excel(path, index=False) + return path + + +@pytest.fixture +def db_with_data(db_dir, sample_excel): + """已导入数据的数据库""" + db_path = os.path.join(db_dir, 'product_cache.db') + db = ProductDatabase(db_path, sample_excel) + return db + + +class TestProductDatabaseInit: + """数据库初始化测试""" + + def test_auto_import_on_first_run(self, db_dir, sample_excel): + """首次运行自动从 Excel 导入""" + db_path = os.path.join(db_dir, 'product_cache.db') + assert not os.path.exists(db_path) + + db = ProductDatabase(db_path, sample_excel) + + assert os.path.exists(db_path) + assert db.count() == 3 + + def test_no_reimport_on_existing_db(self, db_dir, sample_excel): + """数据库已存在时不重新导入""" + db_path = os.path.join(db_dir, 'product_cache.db') + + db1 = ProductDatabase(db_path, sample_excel) + assert db1.count() == 3 + + # 删除 Excel 后仍能打开已有数据库 + os.remove(sample_excel) + db2 = ProductDatabase(db_path, sample_excel) + assert db2.count() == 3 + + def test_missing_excel_creates_empty_db(self, db_dir): + """Excel 不存在时创建空数据库""" + db_path = os.path.join(db_dir, 'product_cache.db') + fake_excel = os.path.join(db_dir, '不存在.xlsx') + + db = ProductDatabase(db_path, fake_excel) + + assert os.path.exists(db_path) + assert db.count() == 0 + + def test_missing_dir_created(self, db_dir, sample_excel): + """数据库目录不存在时自动创建""" + db_path = os.path.join(db_dir, 'subdir', 'product_cache.db') + db = ProductDatabase(db_path, sample_excel) + assert os.path.exists(db_path) + assert db.count() == 3 + + +class TestGetPrice: + """单条查询测试""" + + def test_existing_barcode(self, db_with_data): + price = db_with_data.get_price('6920584471055') + assert price == pytest.approx(1.2) + + def test_nonexistent_barcode(self, db_with_data): + price = db_with_data.get_price('0000000000000') + assert price is None + + def test_empty_barcode(self, db_with_data): + price = db_with_data.get_price('') + assert price is None + + def test_barcode_with_spaces(self, db_with_data): + """条码前后空格应能匹配""" + price = db_with_data.get_price(' 6920584471055 ') + assert price == pytest.approx(1.2) + + +class TestGetPrices: + """批量查询测试""" + + def test_multiple_barcodes(self, db_with_data): + result = db_with_data.get_prices(['6920584471055', '6901028001133']) + assert len(result) == 2 + assert result['6920584471055'] == pytest.approx(1.2) + assert result['6901028001133'] == pytest.approx(3.5) + + def test_partial_match(self, db_with_data): + """部分条码存在,部分不存在""" + result = db_with_data.get_prices(['6920584471055', '0000000000000']) + assert len(result) == 1 + assert '6920584471055' in result + + def test_empty_list(self, db_with_data): + result = db_with_data.get_prices([]) + assert result == {} + + def test_all_nonexistent(self, db_with_data): + result = db_with_data.get_prices(['0000000000000', '1111111111111']) + assert result == {} + + +class TestReimport: + """重新导入测试""" + + def test_reimport_clears_and_reloads(self, db_dir, sample_excel): + db_path = os.path.join(db_dir, 'product_cache.db') + db = ProductDatabase(db_path, sample_excel) + assert db.count() == 3 + + # 修改 Excel,添加一行 + df = pd.read_excel(sample_excel) + df = pd.concat([df, pd.DataFrame({ + '商品条码': ['6954365200123'], + '商品名称': ['测试商品'], + '进货价': [5.0], + '单位': ['个'], + })]) + df.to_excel(sample_excel, index=False) + + count = db.reimport() + assert count == 4 + assert db.count() == 4 + assert db.get_price('6954365200123') == pytest.approx(5.0) + + +class TestEdgeCases: + """边界条件测试""" + + def test_excel_with_missing_price(self, db_dir): + """Excel 中价格列为空的行""" + path = os.path.join(db_dir, '商品资料.xlsx') + df = pd.DataFrame({ + '商品条码': ['6920584471055', '6901028001133'], + '商品名称': ['商品A', '商品B'], + '进货价': [1.5, None], + }) + df.to_excel(path, index=False) + + db_path = os.path.join(db_dir, 'product_cache.db') + db = ProductDatabase(db_path, path) + + assert db.count() == 2 + assert db.get_price('6920584471055') == pytest.approx(1.5) + assert db.get_price('6901028001133') == pytest.approx(0.0) + + def test_excel_with_duplicate_barcodes(self, db_dir): + """重复条码取最后一条 (INSERT OR REPLACE)""" + path = os.path.join(db_dir, '商品资料.xlsx') + df = pd.DataFrame({ + '商品条码': ['6920584471055', '6920584471055'], + '商品名称': ['商品A', '商品A-新'], + '进货价': [1.0, 2.0], + }) + df.to_excel(path, index=False) + + db_path = os.path.join(db_dir, 'product_cache.db') + db = ProductDatabase(db_path, path) + + assert db.count() == 1 + assert db.get_price('6920584471055') == pytest.approx(2.0) diff --git a/tests/test_rule_engine.py b/tests/test_rule_engine.py new file mode 100644 index 0000000..1a40ebc --- /dev/null +++ b/tests/test_rule_engine.py @@ -0,0 +1,223 @@ +"""app.core.handlers.rule_engine 单元测试""" + +import pytest +import pandas as pd + +from app.core.handlers.rule_engine import ( + apply_rules, + _split_quantity_unit, + _extract_spec_from_name, + _normalize_unit, + _compute_quantity_from_total, + _fill_missing, + _mark_gift, +) + + +@pytest.fixture +def sample_df(): + return pd.DataFrame({ + 'name': ['农夫山泉550ml*24', '蒙牛纯牛奶', '可口可乐330ml*6'], + 'quantity_raw': ['2箱', '5', '3提'], + 'unit_price': [28.8, 3.5, 10.8], + 'total_price': [57.6, 17.5, 32.4], + }) + + +class TestSplitQuantityUnit: + def test_split_with_unit(self): + df = pd.DataFrame({'quantity_raw': ['2箱', '5瓶', '3提']}) + result = _split_quantity_unit(df, 'quantity_raw') + assert list(result['quantity']) == [2.0, 5.0, 3.0] + assert list(result['unit']) == ['箱', '瓶', '提'] + + def test_split_number_only(self): + df = pd.DataFrame({'quantity_raw': ['10', '20']}) + result = _split_quantity_unit(df, 'quantity_raw') + assert list(result['quantity']) == [10.0, 20.0] + + def test_split_with_synonyms(self): + df = pd.DataFrame({'quantity_raw': ['2件']}) + dictionary = {'unit_synonyms': {'件': '箱'}, 'default_unit': '瓶'} + result = _split_quantity_unit(df, 'quantity_raw', dictionary) + assert result.loc[0, 'unit'] == '箱' + + def test_split_missing_column(self): + df = pd.DataFrame({'other': [1, 2]}) + result = _split_quantity_unit(df, 'quantity_raw') + assert 'quantity' not in result.columns + + def test_split_invalid_value(self): + df = pd.DataFrame({'quantity_raw': ['abc']}) + result = _split_quantity_unit(df, 'quantity_raw') + assert result.loc[0, 'quantity'] == 0.0 + + +class TestExtractSpecFromName: + def test_extract_550ml_24(self): + df = pd.DataFrame({'name': ['农夫山泉550ml*24']}) + result = _extract_spec_from_name(df, 'name') + assert result.loc[0, 'package_quantity'] == 24 + + def test_extract_330ml_6(self): + df = pd.DataFrame({'name': ['可口可乐330ml*6']}) + result = _extract_spec_from_name(df, 'name') + assert result.loc[0, 'package_quantity'] == 6 + + def test_extract_1_star_pattern(self): + df = pd.DataFrame({'name': ['啤酒1*12']}) + result = _extract_spec_from_name(df, 'name') + assert result.loc[0, 'package_quantity'] == 12 + + def test_no_spec(self): + df = pd.DataFrame({'name': ['蒙牛纯牛奶']}) + result = _extract_spec_from_name(df, 'name') + assert result.loc[0, 'package_quantity'] is None + + def test_missing_column(self): + df = pd.DataFrame({'other': ['test']}) + result = _extract_spec_from_name(df, 'name') + assert 'package_quantity' not in result.columns + + def test_with_ignore_words(self): + df = pd.DataFrame({'name': ['新品 农夫山泉550ml*24']}) + dictionary = {'ignore_words': ['新品'], 'name_patterns': []} + result = _extract_spec_from_name(df, 'name', dictionary) + assert result.loc[0, 'package_quantity'] == 24 + + +class TestNormalizeUnit: + def test_map_units(self): + df = pd.DataFrame({'unit': ['箱', '提', '盒', '瓶'], 'quantity': [1, 2, 3, 4]}) + unit_map = {'箱': '件', '提': '件', '盒': '件'} + result = _normalize_unit(df, 'unit', unit_map) + # _normalize_unit maps via unit_map, then converts 件→瓶 as packed unit + assert list(result['unit']) == ['瓶', '瓶', '瓶', '瓶'] + + def test_convert_quantity_for_packed_units(self): + df = pd.DataFrame({ + 'unit': ['箱', '瓶'], + 'quantity': [2, 5], + 'package_quantity': [12, None], + }) + unit_map = {'箱': '件'} + result = _normalize_unit(df, 'unit', unit_map) + assert result.loc[0, 'quantity'] == 24 # 2 * 12 + assert result.loc[1, 'quantity'] == 5 # unchanged + + def test_missing_column(self): + df = pd.DataFrame({'other': [1]}) + result = _normalize_unit(df, 'unit', {}) + assert 'unit' not in result.columns + + +class TestComputeQuantityFromTotal: + def test_compute_when_qty_zero(self): + df = pd.DataFrame({ + 'quantity': [0, 5, 0], + 'unit_price': [10.0, 20.0, 0.0], + 'total_price': [50.0, 100.0, 30.0], + }) + result = _compute_quantity_from_total(df) + assert result.loc[0, 'quantity'] == 5.0 # 50 / 10 + assert result.loc[1, 'quantity'] == 5 # unchanged + + def test_no_compute_when_qty_positive(self): + df = pd.DataFrame({ + 'quantity': [3, 5], + 'unit_price': [10.0, 20.0], + 'total_price': [50.0, 100.0], + }) + result = _compute_quantity_from_total(df) + assert list(result['quantity']) == [3, 5] + + +class TestFillMissing: + def test_fill_existing_column(self): + df = pd.DataFrame({'a': [1, None, 3], 'b': [None, 2, None]}) + result = _fill_missing(df, {'a': 0, 'b': 99}) + assert result.loc[1, 'a'] == 0 + assert result.loc[0, 'b'] == 99 + + def test_fill_new_column(self): + df = pd.DataFrame({'a': [1, 2]}) + result = _fill_missing(df, {'new_col': 'default'}) + assert list(result['new_col']) == ['default', 'default'] + + +class TestMarkGift: + def test_gift_by_zero_price(self): + df = pd.DataFrame({ + 'name': ['商品A', '商品B'], + 'unit_price': [10.0, 0.0], + 'total_price': [20.0, 0.0], + }) + result = _mark_gift(df) + assert result.loc[0, 'is_gift'] == False + assert result.loc[1, 'is_gift'] == True + + def test_gift_by_name(self): + df = pd.DataFrame({ + 'name': ['赠品-杯子', '商品A'], + 'unit_price': [0.0, 10.0], + 'total_price': [0.0, 20.0], + }) + result = _mark_gift(df) + assert result.loc[0, 'is_gift'] == True + assert result.loc[1, 'is_gift'] == False + + def test_gift_no_price_columns(self): + df = pd.DataFrame({'name': ['赠品', '正常']}) + result = _mark_gift(df) + assert result.loc[0, 'is_gift'] == True + assert result.loc[1, 'is_gift'] == False + + +class TestApplyRules: + def test_multiple_rules(self, sample_df): + rules = [ + {'type': 'split_quantity_unit', 'source': 'quantity_raw'}, + {'type': 'extract_spec_from_name', 'source': 'name'}, + {'type': 'mark_gift'}, + {'type': 'fill_missing', 'fills': {'unit': '瓶'}}, + ] + result = apply_rules(sample_df, rules) + assert 'quantity' in result.columns + assert 'unit' in result.columns + assert 'package_quantity' in result.columns + assert 'is_gift' in result.columns + + def test_empty_rules(self, sample_df): + result = apply_rules(sample_df, []) + assert len(result) == len(sample_df) + + def test_none_rules(self, sample_df): + result = apply_rules(sample_df, None) + assert len(result) == len(sample_df) + + def test_unknown_rule_type(self, sample_df): + rules = [{'type': 'unknown_operation'}] + result = apply_rules(sample_df, rules) + assert len(result) == len(sample_df) + + def test_with_dictionary(self): + df = pd.DataFrame({ + 'name': ['农夫山泉550ml*24'], + 'quantity_raw': ['2箱'], + }) + dictionary = { + 'unit_synonyms': {'箱': '件'}, + 'default_unit': '瓶', + 'ignore_words': [], + 'name_patterns': [], + 'pack_multipliers': {'件': 12}, + 'default_package_quantity': 1, + } + rules = [ + {'type': 'split_quantity_unit', 'source': 'quantity_raw'}, + {'type': 'extract_spec_from_name', 'source': 'name'}, + {'type': 'normalize_unit', 'target': 'unit', 'map': {'箱': '件'}}, + ] + result = apply_rules(df, rules, dictionary) + assert 'quantity' in result.columns + assert 'unit' in result.columns diff --git a/tests/test_string_utils.py b/tests/test_string_utils.py new file mode 100644 index 0000000..0a5a622 --- /dev/null +++ b/tests/test_string_utils.py @@ -0,0 +1,124 @@ +"""app.core.utils.string_utils 单元测试""" + +import pytest +from app.core.utils.string_utils import parse_monetary_string, format_barcode + + +class TestParseMonetaryString: + """parse_monetary_string 金额/数量字符串解析测试""" + + # --- 基本类型 --- + def test_none_returns_none(self): + assert parse_monetary_string(None) is None + + def test_int_passthrough(self): + assert parse_monetary_string(42) == 42.0 + + def test_float_passthrough(self): + assert parse_monetary_string(3.14) == 3.14 + + def test_zero_int(self): + assert parse_monetary_string(0) == 0.0 + + # --- 正常字符串 --- + def test_plain_number(self): + assert parse_monetary_string("123.45") == 123.45 + + def test_integer_string(self): + assert parse_monetary_string("100") == 100.0 + + # --- 货币符号 --- + def test_yen_prefix(self): + assert parse_monetary_string("¥1234.56") == 1234.56 + + def test_dollar_prefix(self): + assert parse_monetary_string("$99.9") == 99.9 + + def test_yuan_suffix(self): + assert parse_monetary_string("100元") == 100.0 + + # --- 逗号处理 --- + def test_comma_as_decimal_point(self): + """逗号当小数点: "1,5" = 1.5""" + assert parse_monetary_string("1,5") == 1.5 + + def test_comma_as_thousands_sep(self): + """逗号当千位分隔符: "1,234.56" = 1234.56""" + assert parse_monetary_string("1,234.56") == 1234.56 + + def test_multiple_commas_thousands(self): + """多个逗号: "1,234,567" = 1234567""" + assert parse_monetary_string("1,234,567") == 1234567.0 + + # --- 空值/无效值 --- + def test_empty_string(self): + assert parse_monetary_string("") is None + + def test_whitespace_only(self): + assert parse_monetary_string(" ") is None + + def test_o_string(self): + """OCR 常见误识别: 字母 o 当数字 0""" + assert parse_monetary_string("o") is None + + def test_none_string(self): + assert parse_monetary_string("none") is None + + def test_null_string(self): + assert parse_monetary_string("null") is None + + def test_dash(self): + assert parse_monetary_string("-") is None + + def test_double_dash(self): + assert parse_monetary_string("--") is None + + def test_no_digits(self): + assert parse_monetary_string("赠品") is None + + # --- 负数 --- + def test_negative_number(self): + assert parse_monetary_string("-5.5") == -5.5 + + # --- 非字符串非数字类型 --- + def test_list_returns_none(self): + assert parse_monetary_string([1, 2]) is None + + def test_dict_returns_none(self): + assert parse_monetary_string({"a": 1}) is None + + +class TestFormatBarcode: + """format_barcode 条码格式化测试""" + + def test_none_returns_empty(self): + assert format_barcode(None) == "" + + def test_normal_digit_string(self): + assert format_barcode("6920584471055") == "6920584471055" + + def test_integer_input(self): + assert format_barcode(6920584471055) == "6920584471055" + + def test_float_with_zero_decimal(self): + assert format_barcode(6920584471055.0) == "6920584471055" + + def test_scientific_notation(self): + assert format_barcode("6.920584e+12") == "6920584000000" + + def test_trailing_zeros_stripped(self): + assert format_barcode("123456.0") == "123456" + + def test_long_barcode_with_trailing_zeros(self): + """14位条码末尾是0时应截断到13位""" + assert format_barcode("69205844710550") == "6920584471055" + + def test_long_barcode_without_trailing_zeros(self): + """14位条码末尾不是0时不截断""" + assert format_barcode("69205844710551") == "69205844710551" + + def test_non_digit_chars_removed(self): + assert format_barcode("692-058-4471055") == "6920584471055" + + def test_empty_string(self): + assert format_barcode("") == "" diff --git a/tests/test_validators.py b/tests/test_validators.py new file mode 100644 index 0000000..e7dabe9 --- /dev/null +++ b/tests/test_validators.py @@ -0,0 +1,251 @@ +"""app.core.excel.validators 单元测试""" + +import pytest +from app.core.excel.validators import ProductValidator + + +@pytest.fixture +def validator(): + return ProductValidator() + + +class TestValidateBarcode: + """条码验证测试""" + + def test_valid_barcode_13_digits(self, validator): + ok, val, err = validator.validate_barcode("6920584471055") + assert ok is True + assert val == "6920584471055" + assert err is None + + def test_valid_barcode_8_digits(self, validator): + ok, val, err = validator.validate_barcode("12345678") + assert ok is True + assert val == "12345678" + + def test_valid_barcode_12_digits(self, validator): + ok, val, err = validator.validate_barcode("692058447105") + assert ok is True + + def test_none_returns_invalid(self, validator): + ok, val, err = validator.validate_barcode(None) + assert ok is False + assert err == "条码为空" + + def test_warehouse_identifier(self, validator): + ok, val, err = validator.validate_barcode("仓库") + assert ok is False + assert val == "仓库" + assert err == "条码为仓库标识" + + def test_warehouse_full_name(self, validator): + ok, val, err = validator.validate_barcode("仓库全名") + assert ok is False + + def test_prefix_5_to_6_correction(self, validator): + """5开头(非53)的长条码应修正为6开头""" + ok, val, err = validator.validate_barcode("5920584471055") + assert ok is True + assert val.startswith("6") + assert val == "6920584471055" + + def test_prefix_53_not_corrected(self, validator): + """53开头的条码不修正""" + ok, val, err = validator.validate_barcode("5321545613000") + assert ok is True + assert val.startswith("53") + + def test_14_digit_trailing_zero_truncated(self, validator): + """14位条码末尾是0时截断到13位""" + ok, val, err = validator.validate_barcode("69205844710550") + assert ok is True + assert len(val) == 13 + + def test_14_digit_no_trailing_zero_invalid(self, validator): + """14位条码末尾不是0时报错""" + ok, val, err = validator.validate_barcode("69205844710551") + assert ok is False + assert "长度异常" in err + + def test_too_short_invalid(self, validator): + ok, val, err = validator.validate_barcode("1234567") + assert ok is False + assert "长度异常" in err + + def test_too_long_invalid(self, validator): + ok, val, err = validator.validate_barcode("1" * 14) + # 14 digits with trailing 0s gets truncated, but "111...1" has no trailing 0 + ok2, val2, err2 = validator.validate_barcode("1" * 15) + assert ok2 is False + + def test_no_digits_invalid(self, validator): + ok, val, err = validator.validate_barcode("abc") + assert ok is False + assert err == "条码不包含数字" + + def test_float_input_cleaned(self, validator): + """浮点数输入应清理为整数字符串""" + ok, val, err = validator.validate_barcode(6920584471055.0) + assert ok is True + assert val == "6920584471055" + + def test_special_barcode_5321545613(self, validator): + """特殊条码 5321545613 应通过验证""" + ok, val, err = validator.validate_barcode("5321545613") + assert ok is True + assert val == "5321545613" + + +class TestValidatePrice: + """单价验证测试""" + + def test_valid_price(self, validator): + ok, val, is_gift, err = validator.validate_price(10.5) + assert ok is True + assert val == 10.5 + assert is_gift is False + + def test_zero_price_is_gift(self, validator): + ok, val, is_gift, err = validator.validate_price(0) + assert ok is True + assert val == 0.0 + assert is_gift is True + + def test_none_is_gift(self, validator): + ok, val, is_gift, err = validator.validate_price(None) + assert ok is False + assert is_gift is True + + def test_gift_string(self, validator): + ok, val, is_gift, err = validator.validate_price("赠品") + assert ok is True + assert is_gift is True + + def test_gift_english(self, validator): + ok, val, is_gift, err = validator.validate_price("gift") + assert ok is True + assert is_gift is True + + def test_price_string_with_yen(self, validator): + ok, val, is_gift, err = validator.validate_price("¥123.45") + assert ok is True + assert val == 123.45 + assert is_gift is False + + def test_price_string_with_comma(self, validator): + ok, val, is_gift, err = validator.validate_price("1,234.56") + assert ok is True + assert val == 1234.56 + + def test_negative_price_invalid(self, validator): + ok, val, is_gift, err = validator.validate_price(-5) + assert ok is False + assert is_gift is True + + def test_empty_string_is_gift(self, validator): + ok, val, is_gift, err = validator.validate_price("") + assert ok is True + assert is_gift is True + + +class TestValidateQuantity: + """数量验证测试""" + + def test_valid_quantity(self, validator): + ok, val, err = validator.validate_quantity(10) + assert ok is True + assert val == 10.0 + + def test_float_quantity(self, validator): + ok, val, err = validator.validate_quantity(2.5) + assert ok is True + assert val == 2.5 + + def test_string_quantity(self, validator): + ok, val, err = validator.validate_quantity("15") + assert ok is True + assert val == 15.0 + + def test_string_with_unit(self, validator): + ok, val, err = validator.validate_quantity("10瓶") + assert ok is True + assert val == 10.0 + + def test_none_invalid(self, validator): + ok, val, err = validator.validate_quantity(None) + assert ok is False + assert err == "数量为空" + + def test_zero_invalid(self, validator): + ok, val, err = validator.validate_quantity(0) + assert ok is False + assert "必须大于0" in err + + def test_negative_invalid(self, validator): + ok, val, err = validator.validate_quantity(-3) + assert ok is False + assert "必须大于0" in err + + def test_non_numeric_string_invalid(self, validator): + ok, val, err = validator.validate_quantity("abc") + assert ok is False + assert err == "数量不包含数字" + + +class TestValidateProduct: + """商品数据整体验证测试""" + + def test_valid_product(self, validator): + product = { + 'barcode': '6920584471055', + 'price': 10.5, + 'quantity': 5, + 'amount': 52.5, + } + result = validator.validate_product(product) + assert result['barcode'] == '6920584471055' + assert result['price'] == 10.5 + assert result['quantity'] == 5.0 + assert result.get('is_gift') is None or result.get('is_gift') is False + + def test_gift_product(self, validator): + product = { + 'barcode': '6920584471055', + 'price': '赠品', + 'quantity': 5, + } + result = validator.validate_product(product) + assert result['is_gift'] is True + assert result['price'] == 0.0 + + def test_quantity_from_amount_and_price(self, validator): + """数量为空时,通过金额/单价计算""" + product = { + 'barcode': '6920584471055', + 'price': 10.0, + 'amount': 50.0, + 'quantity': None, + } + result = validator.validate_product(product) + assert result['quantity'] == 5.0 # 50 / 10 + + def test_invalid_barcode_still_uses_fixed(self, validator): + """条码验证失败但有修复值时仍使用修复值""" + product = { + 'barcode': '5920584471055', # 5开头, 会被修正为6开头 + 'price': 10.0, + 'quantity': 5, + } + result = validator.validate_product(product) + assert result['barcode'] == '6920584471055' + + def test_amount_zero_marks_gift(self, validator): + """金额为0时标记为赠品""" + product = { + 'barcode': '6920584471055', + 'price': 10.0, + 'quantity': 5, + 'amount': 0, + } + result = validator.validate_product(product) + assert result.get('is_gift') is True diff --git a/启动器.py b/启动器.py new file mode 100644 index 0000000..940c84a --- /dev/null +++ b/启动器.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""益选-OCR订单处理系统启动器""" + +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +from app.ui.main_window import main + +if __name__ == "__main__": + main()