v1.1.0: 版本更新 - 增强规格解析能力、修复条码映射功能、改进特殊条码处理
This commit is contained in:
parent
c0fceea9dc
commit
b3c175836a
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Python缓存文件
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# 虚拟环境
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# 日志文件
|
||||||
|
logs/*.log
|
||||||
|
logs/*.active
|
||||||
|
*.log.*
|
||||||
|
|
||||||
|
# 临时文件和缓存
|
||||||
|
data/temp/
|
||||||
|
data/*.bak
|
||||||
|
*.bak
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# 输出文件(可选是否忽略)
|
||||||
|
# data/output/
|
||||||
|
|
||||||
|
# IDE文件
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
28
CHANGELOG.md
Normal file
28
CHANGELOG.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# 更新日志
|
||||||
|
|
||||||
|
## v1.1.0 (2025-05-30)
|
||||||
|
|
||||||
|
### 新特性
|
||||||
|
- 添加对特殊条码6958620703716的处理,支持同时设置规格和条码映射
|
||||||
|
- 增强不规范规格格式的解析能力(如"IL*12"、"6oo*12"等)
|
||||||
|
- 支持带重量单位的规格解析(如"5kg*6")
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- 修复条码映射功能在特殊处理后不生效的问题
|
||||||
|
- 修复OrderService中缺少merge_all_purchase_orders方法导致合并采购单报错的问题
|
||||||
|
- 修复了条码映射对话框无法同时添加特殊处理和映射的问题
|
||||||
|
|
||||||
|
### 改进
|
||||||
|
- 改进了BarcodeMapper类,使其支持同时进行特殊处理和条码映射
|
||||||
|
- 改进了规格解析逻辑,增加了对各种单位和格式的支持
|
||||||
|
- 添加条码映射对话框中可视化标记映射关系
|
||||||
|
- 更新了条码映射配置文件,增加了更多特殊条码处理
|
||||||
|
|
||||||
|
## v1.0.0 (2025-05-01)
|
||||||
|
|
||||||
|
### 初始版本
|
||||||
|
- 基础OCR识别功能
|
||||||
|
- Excel处理功能
|
||||||
|
- 采购单合并功能
|
||||||
|
- 烟草订单处理功能
|
||||||
|
- 图形用户界面
|
||||||
95
README.md
95
README.md
@ -1,80 +1,43 @@
|
|||||||
# 益选-OCR订单处理系统
|
# 益选-OCR订单处理系统
|
||||||
|
|
||||||
## 项目简介
|
一个集OCR识别、Excel处理和订单合并功能于一体的采购单处理系统。
|
||||||
益选-OCR订单处理系统是一款基于Python的图形化本地订单自动化处理工具,支持采购单图片OCR识别、Excel数据处理、采购单合并、烟草订单专用处理等功能,适用于中小型企业、商超、烟草公司等场景。
|
|
||||||
|
|
||||||
## 主要功能
|
## 主要功能
|
||||||
- 图片采购单OCR识别,自动生成标准Excel采购单
|
|
||||||
- Excel采购单智能处理与格式转换
|
|
||||||
- 多采购单合并为总单,支持批量处理
|
|
||||||
- 烟草公司订单明细专用处理与格式转换
|
|
||||||
- 条码映射与单位转换规则自定义
|
|
||||||
- 图形化界面,支持批量、单文件、完整流程一键处理
|
|
||||||
- 系统设置界面,支持API、路径、性能等参数自定义
|
|
||||||
- 日志管理与处理结果预览
|
|
||||||
- 键盘快捷键支持
|
|
||||||
|
|
||||||
## 安装与运行
|
- **OCR识别**:识别图片中的商品信息,包括条码、名称、数量、单价等
|
||||||
### 1. 环境准备
|
- **Excel处理**:将OCR识别结果处理成规范的Excel采购单
|
||||||
- 推荐Python 3.8及以上版本
|
- **采购单合并**:合并多个采购单,汇总相同商品
|
||||||
- Windows 10/11(推荐),支持部分Linux发行版
|
- **条码映射**:支持将特定条码映射为其他条码,适应不同系统要求
|
||||||
|
- **规格处理**:智能解析商品规格,实现单位自动转换
|
||||||
|
- **烟草订单处理**:专门处理烟草公司订单
|
||||||
|
|
||||||
### 2. 安装依赖
|
## 技术特点
|
||||||
```bash
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 启动程序
|
- 基于Python开发,使用Tkinter构建图形界面
|
||||||
- 图形界面启动:
|
- 采用模块化设计,易于扩展和维护
|
||||||
```bash
|
- 自动处理各种不规范数据格式
|
||||||
python 启动器.py
|
- 配置文件支持,可自定义各种处理参数
|
||||||
```
|
- 日志记录,便于问题排查
|
||||||
- 命令行模式:
|
|
||||||
```bash
|
## 使用方法
|
||||||
python run.py --help
|
|
||||||
```
|
1. 运行`启动器.py`打开主界面
|
||||||
|
2. 根据需要选择相应功能按钮
|
||||||
|
3. 按照提示操作,完成数据处理
|
||||||
|
|
||||||
|
## 系统要求
|
||||||
|
|
||||||
## 依赖环境
|
|
||||||
- Python 3.8+
|
- Python 3.8+
|
||||||
- 主要依赖库:tkinter、pandas、numpy、xlrd、xlwt、xlutils、requests、openpyxl 等
|
- 所需第三方库:详见`requirements.txt`
|
||||||
- 详见 requirements.txt
|
|
||||||
|
|
||||||
## 目录结构
|
## 最近更新
|
||||||
```
|
|
||||||
├── app/ # 主程序模块
|
|
||||||
│ ├── config/ # 配置管理
|
|
||||||
│ ├── core/ # 核心功能(OCR、Excel、工具等)
|
|
||||||
│ ├── services/ # 服务层(业务逻辑)
|
|
||||||
│ └── ...
|
|
||||||
├── data/ # 输入输出与缓存目录
|
|
||||||
├── templates/ # Excel模板文件
|
|
||||||
├── logs/ # 日志文件
|
|
||||||
├── run.py # 命令行主入口
|
|
||||||
├── 启动器.py # 图形界面主入口
|
|
||||||
├── requirements.txt # 依赖包列表
|
|
||||||
├── README.md # 使用说明
|
|
||||||
├── 更新日志.md # 更新日志
|
|
||||||
└── ...
|
|
||||||
```
|
|
||||||
|
|
||||||
## 常见问题
|
请查看[更新日志](CHANGELOG.md)了解最新版本变更。
|
||||||
- **Q: 启动时报错缺少依赖?**
|
|
||||||
A: 请先运行 `pip install -r requirements.txt` 安装所有依赖。
|
|
||||||
- **Q: OCR识别失败或API报错?**
|
|
||||||
A: 请在系统设置中正确填写API Key和Secret Key,并确保网络畅通。
|
|
||||||
- **Q: 处理结果找不到?**
|
|
||||||
A: 默认输出在 `data/output/` 目录,可在系统设置中自定义。
|
|
||||||
- **Q: 如何自定义条码映射和单位规则?**
|
|
||||||
A: 通过"编辑条码映射"按钮进入图形化编辑界面。
|
|
||||||
- **Q: 其他问题?**
|
|
||||||
A: 请查看日志窗口或logs目录下日志文件,或联系作者。
|
|
||||||
|
|
||||||
## 联系方式
|
## 贡献者
|
||||||
- 作者:欢欢欢
|
|
||||||
- 邮箱:huanhuanhuan@example.com
|
|
||||||
- QQ:123456789
|
|
||||||
- Issues反馈:请在项目仓库提交Issue
|
|
||||||
|
|
||||||
---
|
- 欢欢欢
|
||||||
|
|
||||||
© 2025 益选-OCR订单处理系统 by 欢欢欢
|
## 版权
|
||||||
|
|
||||||
|
© 2025 益选-OCR订单处理系统
|
||||||
@ -297,6 +297,17 @@ class UnitConverter:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
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等
|
# 处理带容量单位的规格,如500ml*15, 1L*12等
|
||||||
ml_match = re.match(r'(\d+)(?:ml|毫升)[*](\d+)', spec, re.IGNORECASE)
|
ml_match = re.match(r'(\d+)(?:ml|毫升)[*](\d+)', spec, re.IGNORECASE)
|
||||||
if ml_match:
|
if ml_match:
|
||||||
@ -340,6 +351,17 @@ class UnitConverter:
|
|||||||
return 1, quantity, None
|
return 1, quantity, None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
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")
|
logger.warning(f"无法解析规格: {spec},使用默认值1*1")
|
||||||
@ -440,6 +462,12 @@ class UnitConverter:
|
|||||||
'6923644268923': {
|
'6923644268923': {
|
||||||
'map_to': '6923644268480',
|
'map_to': '6923644268480',
|
||||||
'description': '条码映射:6923644268923 -> 6923644268480'
|
'description': '条码映射:6923644268923 -> 6923644268480'
|
||||||
|
},
|
||||||
|
# 添加特殊条码6958620703716,既需要特殊处理又需要映射
|
||||||
|
'6958620703716': {
|
||||||
|
'specification': '1*14',
|
||||||
|
'map_to': '6958620703907',
|
||||||
|
'description': '特殊处理: 规格1*14,同时映射到6958620703907'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,12 +45,6 @@ class BarcodeMapper:
|
|||||||
|
|
||||||
special_config = self.special_barcodes[barcode]
|
special_config = self.special_barcodes[barcode]
|
||||||
|
|
||||||
# 处理条码映射
|
|
||||||
if 'map_to' in special_config:
|
|
||||||
new_barcode = special_config['map_to']
|
|
||||||
logger.info(f"条码映射: {barcode} -> {new_barcode}")
|
|
||||||
result['barcode'] = new_barcode
|
|
||||||
|
|
||||||
# 处理特殊倍数
|
# 处理特殊倍数
|
||||||
if 'multiplier' in special_config:
|
if 'multiplier' in special_config:
|
||||||
multiplier = special_config.get('multiplier', 1)
|
multiplier = special_config.get('multiplier', 1)
|
||||||
@ -79,5 +73,11 @@ class BarcodeMapper:
|
|||||||
result['quantity'] = new_quantity
|
result['quantity'] = new_quantity
|
||||||
result['price'] = new_price
|
result['price'] = new_price
|
||||||
result['unit'] = target_unit
|
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
|
return result
|
||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import messagebox, ttk
|
from tkinter import messagebox, ttk, simpledialog
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
def create_custom_dialog(title="提示", message="", result_file=None, time_info=None,
|
def create_custom_dialog(title="提示", message="", result_file=None, time_info=None,
|
||||||
@ -363,6 +363,45 @@ def create_barcode_mapping_dialog(parent=None, on_save=None, current_mappings=No
|
|||||||
remove_special_btn = tk.Button(special_btn_frame, text="删除特殊处理", command=remove_special)
|
remove_special_btn = tk.Button(special_btn_frame, text="删除特殊处理", command=remove_special)
|
||||||
remove_special_btn.pack(side=tk.LEFT, padx=5)
|
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 = tk.Frame(dialog)
|
||||||
bottom_frame.pack(fill=tk.X, padx=10, pady=10)
|
bottom_frame.pack(fill=tk.X, padx=10, pady=10)
|
||||||
@ -380,7 +419,9 @@ def create_barcode_mapping_dialog(parent=None, on_save=None, current_mappings=No
|
|||||||
|
|
||||||
# 添加特殊处理
|
# 添加特殊处理
|
||||||
for barcode, multiplier, unit, price, spec, desc in special_list:
|
for barcode, multiplier, unit, price, spec, desc in special_list:
|
||||||
mappings[barcode] = {}
|
# 检查该条码是否已存在
|
||||||
|
if barcode not in mappings:
|
||||||
|
mappings[barcode] = {}
|
||||||
|
|
||||||
if multiplier:
|
if multiplier:
|
||||||
try:
|
try:
|
||||||
@ -411,7 +452,19 @@ def create_barcode_mapping_dialog(parent=None, on_save=None, current_mappings=No
|
|||||||
if spec:
|
if spec:
|
||||||
mappings[barcode]['specification'] = spec
|
mappings[barcode]['specification'] = spec
|
||||||
|
|
||||||
if desc:
|
# 检查描述中是否包含映射信息
|
||||||
|
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
|
mappings[barcode]['description'] = desc
|
||||||
|
|
||||||
# 调用保存回调
|
# 调用保存回调
|
||||||
|
|||||||
@ -69,6 +69,29 @@ class OrderService:
|
|||||||
"""
|
"""
|
||||||
return self.order_merger.get_purchase_orders()
|
return self.order_merger.get_purchase_orders()
|
||||||
|
|
||||||
|
def merge_purchase_orders(self, file_paths: List[str]) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
合并指定的采购单文件
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_paths: 采购单文件路径列表
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
合并后的采购单文件路径,如果合并失败则返回None
|
||||||
|
"""
|
||||||
|
logger.info(f"OrderService开始合并指定采购单: {file_paths}")
|
||||||
|
return self.merge_orders(file_paths)
|
||||||
|
|
||||||
|
def merge_all_purchase_orders(self) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
合并所有可用的采购单文件
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
合并后的采购单文件路径,如果合并失败则返回None
|
||||||
|
"""
|
||||||
|
logger.info("OrderService开始合并所有采购单")
|
||||||
|
return self.merge_orders(None)
|
||||||
|
|
||||||
def merge_orders(self, file_paths: Optional[List[str]] = None) -> Optional[str]:
|
def merge_orders(self, file_paths: Optional[List[str]] = None) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
合并采购单
|
合并采购单
|
||||||
|
|||||||
88
clean.py
Normal file
88
clean.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
清理脚本 - 用于删除无关的文件和日志
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import glob
|
||||||
|
|
||||||
|
def clean_logs():
|
||||||
|
"""清理日志文件"""
|
||||||
|
print("清理日志文件...")
|
||||||
|
|
||||||
|
# 删除.active文件
|
||||||
|
active_files = glob.glob("logs/*.active")
|
||||||
|
for file in active_files:
|
||||||
|
try:
|
||||||
|
os.remove(file)
|
||||||
|
print(f"已删除: {file}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"删除文件时出错 {file}: {e}")
|
||||||
|
|
||||||
|
# 保留最新的日志,删除旧的备份
|
||||||
|
log_files = glob.glob("logs/*.log.*")
|
||||||
|
for file in log_files:
|
||||||
|
try:
|
||||||
|
os.remove(file)
|
||||||
|
print(f"已删除: {file}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"删除文件时出错 {file}: {e}")
|
||||||
|
|
||||||
|
def clean_temp_files():
|
||||||
|
"""清理临时文件"""
|
||||||
|
print("清理临时文件...")
|
||||||
|
|
||||||
|
# 清空临时目录
|
||||||
|
temp_dir = "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)
|
||||||
|
print(f"已删除: {file_path}")
|
||||||
|
elif os.path.isdir(file_path):
|
||||||
|
shutil.rmtree(file_path)
|
||||||
|
print(f"已删除目录: {file_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"删除文件时出错 {file_path}: {e}")
|
||||||
|
|
||||||
|
# 删除备份文件
|
||||||
|
backup_files = glob.glob("data/*.bak") + glob.glob("config/*.bak")
|
||||||
|
for file in backup_files:
|
||||||
|
try:
|
||||||
|
os.remove(file)
|
||||||
|
print(f"已删除: {file}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"删除文件时出错 {file}: {e}")
|
||||||
|
|
||||||
|
def clean_pycache():
|
||||||
|
"""清理Python缓存文件"""
|
||||||
|
print("清理Python缓存文件...")
|
||||||
|
|
||||||
|
# 查找并删除所有__pycache__目录
|
||||||
|
for root, dirs, files in os.walk("."):
|
||||||
|
for dir in dirs:
|
||||||
|
if dir == "__pycache__":
|
||||||
|
cache_dir = os.path.join(root, dir)
|
||||||
|
try:
|
||||||
|
shutil.rmtree(cache_dir)
|
||||||
|
print(f"已删除目录: {cache_dir}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"删除目录时出错 {cache_dir}: {e}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
print("开始清理无关文件...")
|
||||||
|
|
||||||
|
clean_logs()
|
||||||
|
clean_temp_files()
|
||||||
|
clean_pycache()
|
||||||
|
|
||||||
|
print("清理完成!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -99,6 +99,61 @@
|
|||||||
"map_to": "6935205372772",
|
"map_to": "6935205372772",
|
||||||
"description": "条码映射:6921734908735 -> 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": {
|
||||||
|
"multiplier": 14,
|
||||||
|
"target_unit": "个",
|
||||||
|
"specification": "1*14",
|
||||||
|
"map_to": "6958620703907",
|
||||||
|
"description": "友臣肉松棒:规格1*14,映射到6958620703907"
|
||||||
|
},
|
||||||
"6925019900087": {
|
"6925019900087": {
|
||||||
"multiplier": 10,
|
"multiplier": 10,
|
||||||
"target_unit": "瓶",
|
"target_unit": "瓶",
|
||||||
@ -115,5 +170,11 @@
|
|||||||
"fixed_price": 3.7333333333333334,
|
"fixed_price": 3.7333333333333334,
|
||||||
"specification": "1*30",
|
"specification": "1*30",
|
||||||
"description": "特殊处理: 规格1*30,数量*30,单价=112/30"
|
"description": "特殊处理: 规格1*30,数量*30,单价=112/30"
|
||||||
|
},
|
||||||
|
"6958620703907": {
|
||||||
|
"multiplier": 14,
|
||||||
|
"target_unit": "个",
|
||||||
|
"specification": "1*14",
|
||||||
|
"description": "友臣肉松,1盒14个"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4
启动器.py
4
启动器.py
@ -711,7 +711,7 @@ def main():
|
|||||||
|
|
||||||
# 创建窗口
|
# 创建窗口
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.title("益选-OCR订单处理系统 v1.0")
|
root.title("益选-OCR订单处理系统 v1.1.0")
|
||||||
root.geometry("1200x650") # 增加窗口高度以容纳更多元素
|
root.geometry("1200x650") # 增加窗口高度以容纳更多元素
|
||||||
|
|
||||||
# 创建主区域分割
|
# 创建主区域分割
|
||||||
@ -930,7 +930,7 @@ def main():
|
|||||||
).pack(side=tk.LEFT, padx=button_padx)
|
).pack(side=tk.LEFT, padx=button_padx)
|
||||||
|
|
||||||
# 底部说明
|
# 底部说明
|
||||||
tk.Label(left_frame, text="© 2025 益选-OCR订单处理系统 v1.0 by 欢欢欢", font=("Arial", 9)).pack(side=tk.BOTTOM, pady=10)
|
tk.Label(left_frame, text="© 2025 益选-OCR订单处理系统 v1.1.0 by 欢欢欢", font=("Arial", 9)).pack(side=tk.BOTTOM, pady=10)
|
||||||
|
|
||||||
# 绑定键盘快捷键
|
# 绑定键盘快捷键
|
||||||
bind_keyboard_shortcuts(root, log_text, status_bar)
|
bind_keyboard_shortcuts(root, log_text, status_bar)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user