From 5c0b709528aa710a6b42b35c1ec21663bc1dbfc6 Mon Sep 17 00:00:00 2001 From: houhuan Date: Sat, 10 May 2025 11:39:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9D=A1=E7=A0=81=E6=98=A0?= =?UTF-8?q?=E5=B0=84=E7=BC=96=E8=BE=91=E5=8A=9F=E8=83=BD=E5=9B=BE=E5=BD=A2?= =?UTF-8?q?=E5=8C=96=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 117 ++++- .../__pycache__/converter.cpython-39.pyc | Bin 11124 -> 12725 bytes .../excel/__pycache__/merger.cpython-39.pyc | Bin 11921 -> 12007 bytes .../__pycache__/processor.cpython-39.pyc | Bin 21824 -> 21883 bytes app/core/excel/converter.py | 157 ++++-- app/core/excel/merger.py | 59 ++- app/core/excel/processor.py | 59 ++- .../ocr/__pycache__/baidu_ocr.cpython-39.pyc | Bin 8830 -> 9073 bytes .../ocr/__pycache__/table_ocr.cpython-39.pyc | Bin 10208 -> 10983 bytes app/core/ocr/baidu_ocr.py | 63 ++- app/core/ocr/table_ocr.py | 169 ++++--- .../__pycache__/dialog_utils.cpython-39.pyc | Bin 0 -> 11180 bytes .../__pycache__/log_utils.cpython-39.pyc | Bin 3283 -> 4600 bytes app/core/utils/dialog_utils.py | 468 ++++++++++++++++++ app/core/utils/log_utils.py | 49 ++ .../__pycache__/ocr_service.cpython-39.pyc | Bin 2999 -> 3534 bytes .../tobacco_service.cpython-39.pyc | Bin 0 -> 7293 bytes app/services/ocr_service.py | 15 + app/services/tobacco_service.py | 255 ++++++++++ config/barcode_mappings.json | 35 ++ logs/__main__.active | 1 + logs/__main__.log | 54 ++ logs/app.core.excel.converter.active | 1 + logs/app.core.excel.converter.log | 106 ++++ ....core.excel.handlers.barcode_mapper.active | 1 + ...app.core.excel.handlers.barcode_mapper.log | 9 + ...el.handlers.unit_converter_handlers.active | 1 + ...excel.handlers.unit_converter_handlers.log | 39 ++ logs/app.core.excel.merger.active | 1 + logs/app.core.excel.merger.log | 19 + logs/app.core.excel.processor.active | 1 + logs/app.core.excel.processor.log | 445 +++++++++++++++++ logs/app.core.excel.validators.active | 1 + logs/app.core.ocr.baidu_ocr.active | 1 + logs/app.core.ocr.baidu_ocr.log | 11 + logs/app.core.ocr.table_ocr.active | 1 + logs/app.core.ocr.table_ocr.log | 51 ++ logs/app.core.utils.file_utils.active | 1 + logs/app.services.ocr_service.active | 1 + logs/app.services.ocr_service.log | 21 + logs/app.services.order_service.active | 1 + logs/app.services.order_service.log | 26 + logs/app.services.tobacco_service.active | 1 + logs/app.services.tobacco_service.log | 97 ++++ run.py | 423 ++++++---------- 启动器.py | 249 +++++++++- 46 files changed, 2510 insertions(+), 499 deletions(-) create mode 100644 app/core/utils/__pycache__/dialog_utils.cpython-39.pyc create mode 100644 app/core/utils/dialog_utils.py create mode 100644 app/services/__pycache__/tobacco_service.cpython-39.pyc create mode 100644 app/services/tobacco_service.py create mode 100644 config/barcode_mappings.json create mode 100644 logs/__main__.active create mode 100644 logs/app.core.excel.converter.active create mode 100644 logs/app.core.excel.handlers.barcode_mapper.active create mode 100644 logs/app.core.excel.handlers.unit_converter_handlers.active create mode 100644 logs/app.core.excel.merger.active create mode 100644 logs/app.core.excel.processor.active create mode 100644 logs/app.core.excel.validators.active create mode 100644 logs/app.core.ocr.baidu_ocr.active create mode 100644 logs/app.core.ocr.table_ocr.active create mode 100644 logs/app.core.utils.file_utils.active create mode 100644 logs/app.services.ocr_service.active create mode 100644 logs/app.services.order_service.active create mode 100644 logs/app.services.tobacco_service.active create mode 100644 logs/app.services.tobacco_service.log diff --git a/README.md b/README.md index d16cf22..bfb1a68 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ ## 版本信息 -- **当前版本**: v1.1 -- **发布日期**: 2025-05-07 +- **当前版本**: v1.5 +- **发布日期**: 2025-05-09 - **作者**: OCR订单处理团队 ## 功能特点 @@ -17,6 +17,11 @@ - **批量处理**:支持批量处理多张图片 - **图形界面**:提供简洁直观的图形界面,方便操作 - **命令行支持**:支持命令行方式调用,便于自动化处理 +- **OCR识别**: 支持图片中表格的自动识别和提取 +- **Excel处理**: 将OCR识别结果处理为规范的Excel表格 +- **订单合并**: 将多个采购单自动合并为一个总表 +- **完整流程**: 一键执行从OCR识别到订单合并的完整处理流程 +- **烟草订单处理**: 专门处理烟草公司特定格式的订单明细文件,生成银豹采购单 ## 系统架构 @@ -95,33 +100,56 @@ template_file = templates/银豹-采购单模板.xls ## 使用方法 -### 图形界面 +1. **启动系统** + - 双击运行 `启动器.py` 文件,启动图形界面 + - 或者通过命令行运行 `python run.py <命令> [选项]` -运行`启动器.py`启动图形界面: +2. **图形界面操作** + - **处理Excel文件**: 处理指定的Excel文件或最新的Excel文件 + - **OCR批量识别**: 批量处理input目录下的所有图片 + - **完整处理流程**: 一键执行OCR识别、Excel处理和订单合并 + - **处理单个图片**: 处理指定的单张图片 + - **合并采购单**: 合并多个采购单为一个总表 + - **处理烟草订单**: 处理烟草公司特定格式的订单明细文件,生成银豹采购单格式 + - **整理项目文件**: 整理项目文件结构 + - **清除处理缓存**: 清除处理缓存,使系统重新处理所有文件 + - **清理文件**: 清理所有数据文件 + - **切换主题**: 在浅色和深色主题之间切换 -```bash -python 启动器.py +## 命令行使用 + +系统支持通过命令行操作,基本用法: + +``` +python run.py <命令> [选项] ``` -图形界面包括以下功能: -- **处理单个文件**:选择并处理单个图片文件 -- **批量处理**:处理data/input目录中的所有图片文件 -- **合并处理**:合并多个采购单 -- **清理文件**:清理input和output目录中的文件 -- **查看日志**:实时显示处理日志 +支持的命令: -### 命令行模式 +1. **ocr**: OCR识别 + ``` + python run.py ocr [--input 图片路径] [--batch] [--batch-size 批大小] [--max-workers 最大线程数] + ``` -```bash -# 处理单个文件 -python run.py --file=image.jpg +2. **excel**: Excel处理 + ``` + python run.py excel [--input Excel文件路径] + ``` -# 批量处理目录中的所有文件 -python run.py --batch +3. **merge**: 订单合并 + ``` + python run.py merge [--input 采购单文件路径列表,以逗号分隔] + ``` -# 合并采购单 -python run.py --merge -``` +4. **pipeline**: 完整流程 + ``` + python run.py pipeline [--input 图片路径] + ``` + +5. **tobacco**: 烟草订单处理 + ``` + python run.py tobacco [--input 烟草订单明细文件路径] + ``` ## 单位处理规则 @@ -267,6 +295,53 @@ MIT License ## 更新日志 +### v1.5 (2025-05-09) + +#### 功能改进 +- 烟草订单处理结果展示:改进烟草订单处理完成后的结果展示界面 + - 美化结果 展示界面,显示订单时间、总金额和处理条目数 + - 添加文件信息展示,包括文件大小和创建时间 + - 提供打开文件、打开所在文件夹等便捷操作按钮 + - 统一与Excel处理结果展示风格,提升用户体验 + - 增强结果文件路径解析能力,确保正确找到并显示结果文件 +- 条码映射编辑功能: + - 添加图形化条码映射编辑工具,方便管理条码映射和特殊处理规则 + - 支持添加、修改和删除条码映射关系 + - 支持配置特殊处理规则,如乘数、目标单位、固定单价等 + - 自动保存到配置文件,便于后续使用 + +#### 问题修复 +- 修复烟草订单处理时出现双重弹窗问题 +- 修复烟草订单处理完成后结果展示弹窗无法正常显示的问题 +- 修复ConfigParser兼容性问题,支持标准ConfigParser对象 +- 修复百度OCR客户端中getint方法调用不兼容问题 +- 修复OCRService中缺少batch_process方法的问题,确保OCR功能正常工作 +- 改进日志管理,确保所有日志正确关闭 +- 优化UI界面,统一按钮样式 +- 修复启动器中处理烟草订单按钮的显示样式 +- 修复run.py中close_logger调用缺少参数的问题 + +#### 代码改进 +- 改进TobaccoService类对配置的处理方式,使用标准get方法 +- 添加fallback机制以增强配置健壮性 +- 优化启动器中结果预览逻辑,避免重复弹窗 +- 统一UI组件风格,提升用户体验 +- 增强错误处理,提供更清晰的错误信息 + +### v1.4 (2025-05-09) + +#### 新功能 +- 烟草订单处理:新增烟草公司特定格式订单明细文件处理功能 + - 支持自动处理标准烟草订单明细格式 + - 根据烟草公司"盒码"作为条码生成银豹采购单 + - 自动将"订单量"转换为"采购量"并计算采购单价 + - 处理结果以银豹采购单格式保存,方便直接导入 + +#### 功能优化 +- 配置兼容性:优化配置处理逻辑,兼容标准ConfigParser对象 +- 启动器优化:启动器界面增加"处理烟草订单"功能按钮 +- 代码结构优化:将烟草订单处理功能模块化,集成到整体服务架构 + ### v1.3 (2025-07-20) #### 功能优化 diff --git a/app/core/excel/__pycache__/converter.cpython-39.pyc b/app/core/excel/__pycache__/converter.cpython-39.pyc index 3e66958453045fd7d8ca5db54f9176f130deecaa..56e6fbb68ceabac0b7f35a3e797ebcf90f87b22f 100644 GIT binary patch delta 3261 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 R1tcJe^&k%la~@V;{|4pZhe`kd diff --git a/app/core/excel/__pycache__/merger.cpython-39.pyc b/app/core/excel/__pycache__/merger.cpython-39.pyc index c2627eec5d06d1f3513ec269cda41b4bd5ebea72..cd1b3bb7e596e72434f273ff71f3da8615b26f34 100644 GIT binary patch delta 2441 zcmZ8hYiu0V6`ngYJG$;# z%{|Y#=R4=#xA)%J8`UF`pajqVj&@A7y>KI%mgoKgB9q1lmBwUB#uO@3<(M?4G9S~J zHYvACRJ}l`k7~!%F+cUYQh?Tg6ks(>tJ;G!1ezekgjjew0^0BenMP<7v{BD*$x;iJ z7_9?KE!zOjV8AqSP}kE2P{(L9=-lM3Qq_t)~`Uy@QSqFSQ2Hrh)gONz zbtAxfDY_s*Y^}SE+U4H6Bx6vO?AXB{h;&3H(xFc9siU!374xmc9lj;)l6Fh9?uhz^ zY6QLST4^n4fTnnfiFtK*?d@9&l{c>i6V*oy_*M+0h!dF9^Z5xqGxIVE>_E=4)820jww+RSK=fnH<2ib5%IMDABolAcZKkN_;BRM zgY~%T0~i$#1qR5dcs20az#3GdKYtA2=iW{{ZRz`1dU-XwZhjNEO|)+G?h*eD_O#y@ z6CBP%-!f*QI5H)gL)Qm9SMYZNz-__K71$NxkOTMsEHIqc3lmfy;o|$y(ImEuuR`cT zh#@=-0EC&`c9c9bQVQ=Em&1wBvMq>zhFi!Uu^8S-25*i;KJY#H6a>LMDVEJsG9Shi z%04|0d+^V&gZoWR@A2c*3}>0a4ix#wY5d_v(O<9kVGLx56-}ENc23WyrZIkCRtKqG5YzE1I_pG;Si>MXvF~n43t)L=y-Z(ckp9XP1huR>e1g4YnCA=*1!oU&hRr z3Wl|;xZp6&WxUq>AMY69C5gFs@yr%lrt4F#@WM;;YVlD1%lICB9WW z|KJmY6qYb2Irum}!?X>ZH=^|!ge3~SCgN4y>80vxZWVVsyLMM6Qpa$(A{fswpjdMc zujO{*u8NuPH>C(b`SP(lr;mG=PJ+LJ>RN!IMCHOSE9XuuUcC-?SAvg;EeRSgf(59- z?A+b>9`Si%UCQlgB+N`I>@{E>l?t7- z_-65TS3Nl@-tF4qos$z7y8cXe8~IkWcmG;*`5e4?tvjKREx`Wph}$uRzlb?}a8yc+ z?}PPEr$^1OeExp!unn(y-1XPDiqBFHh`F8>a1j33)4Obb-6|)<*F8yX14NWM#EpmR zMSGHxlsKAf2)U)ZwHCzhlZ|9Xyq_E-Tzr#!faF9?Z%6;qb;5fgfqOZ?l>pb2JEO}+ zvC(7Vu-Mg`g!<=tuf>+;u{u9uB-KT>-W*Szk@viS+3qoa5k(wn{xO1kPd*N-l6a_7AX%*cTi2M7>V4J5^IUu(U~%YM)~T2VKsZb6QzzOUQdk}zo5_PlIj@0#^L E0*gLu_W%F@ delta 2407 zcmZ8hUu;uV7{BM<+uN>POX=2bs~amrwpC#|KoWFWMA<;lq5@H8pj>*+x{mJN=G5~wm@nLs_s#;X|Yy2Jd?{3&nVc| zXsK9GvC8^Shpz$uN8#^axvnxtD48cjnI@HltG=R4D|u~N8P~>jC`!Y!squym(f~^5 z43I+6^V&;leGf&`2<$aCI3Aj7m{zB?nR!s=!%`3dv+z7|PQp=*v=MjblnW{z=|-3L zuaIM;9zYon(5Q?Mn^xvl%wtM%nJDa+z3B=lH(q@Wst9N5zuN4D+DEU~#CQ7e##^7v z-#UGwcJ|_*U!Safcx>^#^Ea=2m9s5Yn>|~bJy*N>)#91YZoPYa$+_At`ixGI4y=jn zmHcsLx=h%C69+SJNImw+Gqq1nF3z5YsEZfp7cX32JoDPktCt_l? z8nt-@ym$+M7b-G0UoqV=FKk!cO4ZHN68AKadaCVsx_HOvS{q=T+uU0@Tq?7i?GD>j ziw;RqxL_8>Sbh`~;%BhT>Ynbf@~8~X@4^$JE}N*7A>X`ZPOwV~zhCqRpKNahoe~U_ zMlGeqNnDL~GAfgGatlv4+$6@`XuVbpM7r;~!zVmYE;(+&o~R7w#Y>UT zHu$DsFFBiVOHd5)$mE@eg$Byz#35=9mPEes<$F8vgbYF#LL9&g9x=I9vWmc!&0S9` zGb^j{K4C;Nk=xP`{n1wPwAdNlM>a0ZMK1>)831n>0L^iER^?kTmiB^KhCG6Y+0+r6 zQ$HJI$!i!WGK)=C_#jRq-wJSao4B6t5!ag@SdY#SDqgW&X1OJ^oF8K*g+@Px#**ee zu<~8S>gI!FuQ=AcJF*kiyAU21zcsHm>Ps!zO?HWUk{u)`cEI|8u#-u^SCd2J3GqYn zN?bbT(eWUHDMaea#8S2Oa`+?SKugN+g)AaGKuZO`4Zon?O4fM+j z8J^%bjK2(PnCqh$QYt0a55YD_WPyF1<(P?D*eV=p6aPfg;@i$un-9STCZz};FJRfO zW%48%4I(UY>38p8kR|W#3kx-;M^${kia8F#a{J z$Ln_KB$sUxf3NH73!rHPVFQAOfb7fnn&TN&>fD4KY2@o|;VWPvto3vupVc_;5*F6;_^6F)eC3Fksi#|C*NNqTy|+`zMHnzD@rE DurXjb diff --git a/app/core/excel/__pycache__/processor.cpython-39.pyc b/app/core/excel/__pycache__/processor.cpython-39.pyc index d39cafbdacef3d75efbd2d2555df09f9960554cb..a778a34c30322fd89f18673e0460b9d359965e67 100644 GIT binary patch delta 3537 zcma)8Yiv}<6~1%t?%nnJiJ#aQZ2SN(2AkN%Ziq!Oukx@>j3I$d>g9Up+FrB1cRP0% zV`^{`o=Ksh9U!PcW0xca+7gmQDM=G(Xp7XUk)pOgqFc39Dq}!VU#S{3B~^RQ?0Su? zMr9>`d*(aenK^Uj%&dQWk=(mT(zWz-j|88aBeVPd{aX5W*@cby9V|!{?$dF>=!s7`gQnT}}8sG!+<+o~ozOv@*v1U8G#0Cq-#bwcb2(%Ccz=xh)I17I69ZrBh6215+Skr#6D|b7%>8Wg!-ZF}c`jDG27$G7uDr1#r=F z;3{Y(aI>hZQ}WK^A1R|F0U67f_$cs=WnBq>RuvRhZl@87f;Yp=wM`a<#u|g-u?$Jz&Ds?mqbz>wsEqXGN9_2pIjD0wFHl&hCGa<^+ zIvMo1WPHIPMRJajp)w-vfdzNZ0a-518kQ$D&q$9;+ax+;kGxklJn`?v(qdqsoY_&0 zA9rra9KSv`@${>n(!_^1s^u%Z#CG>+p-{IL*kPwe^ntLy#|%-O?M|UuM5{%{myQ_H zBD%jP7}BE^a0Zi%Rm-octu32z9(`BPiulbP(OeLWzjOWe@$+}C@mq)9x_$c6t#?i= zExpe%e)Y=43vVPHHN03YD!g^+$i(4ee|h`J#QCv_v)3n19vc7A8xU54-kG;vdhO1Y zmzS2dd-H5HU>ZHaUR&waBfQ;J&@`1|Sc~-8vT4~4VW}c3%T_~XZ?Dd5*PzCXpwVkP z`puxhFS;5w+U@~uhfaeGVuD7GX}h#;3xnBA*od7GHG&a8EVxr=5tt!m^{#*(js#7^ zcIu3o%&XWAOAqz15|k63V!#1Z={;=Kfi! z7qk}$tAj7rkc1^@Edc1?;grRsosXt;sntk&xx-UKe6f1Zh}=96nMDY55wZ~GBa|ax z9=5w%vvfln&~1+u(OAS93`Y9A3ajHEr!|wVSZz928pS*!5RcDRLb}10;}kfz?Fw2n z*c*)4PO5iDdodV&tN1^&>dA0y;f%{N>Eyr5nN_q3c%N&9#sVhQ|DnR@_S+|Kk3P*h zd3J6fYZHcbidcll_<`IL8LPp(n*q@7C9I8C&FVSoPBaHOudXAf_|57$ z*)ISAhj$eDxGwfd^;ZZv%KH{wC1reW&HSRN&0r>C3oIY4`MkSkSwS*UZ*DxtXVG_( z|FGt~$wKK^<-dNj2>bX%nm+Xlht6k$ro$7+k{KNVdwGXG*!mApZ$yTm6 zY+te-39Ob^W>3JE?Fi_h(EsX!D)^aTT_D+A$3JQ+;e|^INtD+w8A`27dLBx6Qu&8V zUhlzO*-oYzy*eCA$PBRLYNCgj1_JgCR4G<;fNjU2D9T3U)SX%=s>54hnJgl1htFx4 z5jb5uQg6oO!F}4;P;~?tpBp;CkFTlEX$4HCvrEW&a6|q;NY@P3!?!fGk+mLpMCY(K(SHH~^ReAlI0WsuE5g2r zTor&y>(VB(-xfX_}fqmghlB7P58Js)cJ zl9jP@%^E4jALw|oM1x<$S>^bwExdHueDYLm?XrV%)=Q{+8R7c~-{ZeuzLoUxrj{+m zuOM*&Aeshn=gJSp-@H6=;_}@?&$A2sd`p}9T@+m8_gWq$=XvXjXNttdHIWrX*Us z*JML4<9}#h$WN{9uDXFyKSB5@!nAZS>hB_om#xzuK>SHu{OY>F+GIYqQ?$_MF7RnQ zX3P2~%04#qiJjq#HeXZU MLvtSg+vbh`1t9owfB*mh delta 3447 zcma)73v5%@8TPr?zJA4tWAcCy8WSggfh0Tvj5ZC=ARfWIlCHR@=Hh#kIKA<8j%@-o zEEEES!UpXr6biHn-O8(FFi)tXbRE;!RBaQ}(5C5X(liN&Rn?02kUDjmwEsWXI8(Gr zSn}s{zW+P_`Okm;^ZVad$WN{ikL>ZdEbytmSlKoAhUbDXu#i|RswGSmOIT1ySX8E~ zR@FAiqKM~+VpVK|wy>nyRfp>65P+3{wJVN6YuKp>eCAYKFmu5wN6zk63V?B|1*%8! zoD-Bnr3mJQYEidWE#@jOu*HfG*a2UTw!>niCnzOAPXHk>u&qZaJtrznAIfz?J_`I8&6TfSJhGjvWN|s#5&TV44IDD$E6d;GCayDhR5T z0N5w<4RF&M;A)j=z*Q>37E5pj`;$045DF4Qit6!>SZ7qg?B+gJ_?6(h0=~&V0;DX% zL?I)DSo%rAml6(G`YjQ$-_k91TOpew=39}zZ3WhrXCd2pRzh~z4qC|ih`3k4`2Y}* za>WCLm~wPGhh6QMh?~y~K;|AH$qNvGM=8YFS<86=14$K*%@2_MB)8tuZBvT4 zhoXMVuy+IlEl&A(z!Uf}ym>EfaHAAMHhk#=>{DC&{D;>@9-cUqJ#*>N?PJ;Z_K&`O z?!kw*LV8@y4xPykoy~r9YxLChhi?tK{JBrMoK@K?Se+DbxA9z3RZgjFn>4Y>C`ze4 z2@R%^4qa1JYB(PgNyFKevn7qfM4CpsC5EKwot@y{8jE-6)D5dBIx!rbYATYDQ(cBj zPp1;;R78oeyt7DL?qThY=lzvHTkI}UAeNCb(M!C7 zS1cqx;uU?wB{~H5JI7sr186Q2Iv;*$V;&aZXbwOtyXBn2uDLwyU(QX^T%;S=23I|4 z&wR@@AOr%))F4bl@B$e2KAFa2@lHAesUWNLRFe5@v8Rb_&Fu6raUox{1dS!A7d16b zm*Es08TMFGiFL+OhD}j-q&tJ68C(lnQaqpZWs=3$g(+XJYiF&u7R}|A0gm1E6m7FYG1;ft@0pLl}5YtO%kYBRXrRl&1 z)VzQ&E)y>T_iN-MY);wInpPaH2QVZ#kx=6b&8NYzX?h=AUx>X?7La&WH?xn+C>hDj zDgT3=v@mB?V>u6|2fb+M#g?G4s7m9kt*VyjY){n&sT++iv3pgUNPB$TibVsE*7E z%*0br9Uxr_kp1o;zU-5Svh0i~WAqJaU#fXFuh83kbN}K-eRc2?84Op2k4=h#b)P_FD! z3~N-?wEtHk0qE;A0+K!RSp7Gu*tP|e$WFF%!ESe5-ZD35akH9*Kj^?y88#}%J5{(d zO^?$2ZoI(g4iHd=DlwVvp?G&@v28?7+9_*k6`D#?rz!q=!nU}cf~&{-4i-MX&!$C< zS)z6$J=h>g1SvWA3dh;3M&a)AC zz3k(DpaUxr6)H*N1w?P7{WJpZZ#a?(4Qg{&iY`TNCIW90@8O6ylf^i~YYaNfU_VA; zv&AwE!t4U~DvdyCQ+}~4z-G8}{j~#{BgLDX!0t7bk><>3lT0dC;&L83ulPIYSui~> z=h~gkCFJGI(dI*f_abU9A$%X<8k@T8c@krLmbF)2M&f;dbOFF$e)z$IA6*|kdHu7) z$Lag*^JVL$D=7GYH80;tuCn9H_gC=OoIqAX;O_=s1hk`BD?+QgaLD80>Ej)97`g2T ztqAK8@VdhH7VzUJ!!`O?&tt&^W1kgrVfJL_J2 z0`Y%LacyhQ6NoJ$f%DqvOpwe}JIXEb@D3=TW?gqj5W6^fm1M=B-u|3Ql2lTj~dFD03q$ zM1U;i-p?Ey@qV%rM-BkPxt;kH!R+gc(A;QVdJ1b zMZo7oB?O*NGRWq(m$Sca@d+i>jI>qP-ACID1Uz+EO30Awq`99hp6*HP4h!)FeH#@Q X*v7VU@($~2`?2&JBm!)9`-cAl!?0?B diff --git a/app/core/excel/converter.py b/app/core/excel/converter.py index 9cd51ca..5cba87f 100644 --- a/app/core/excel/converter.py +++ b/app/core/excel/converter.py @@ -6,6 +6,8 @@ import re import logging +import os +import json from typing import Dict, Tuple, Optional, Any, List, Union from ..utils.log_utils import get_logger @@ -18,6 +20,9 @@ from .validators import ProductValidator logger = get_logger(__name__) +# 条码映射配置文件路径 +BARCODE_MAPPING_CONFIG = "config/barcode_mappings.json" + class UnitConverter: """ 单位转换器:处理不同单位之间的转换,支持从商品名称推断规格 @@ -27,60 +32,8 @@ class UnitConverter: """ 初始化单位转换器 """ - # 特殊条码配置 - self.special_barcodes = { - '6925019900087': { - 'multiplier': 10, # 数量乘以10 - 'target_unit': '瓶', # 目标单位 - 'description': '特殊处理:数量*10,单位转换为瓶' - }, - '6921168593804': { - 'multiplier': 30, # 数量乘以30 - 'target_unit': '瓶', # 目标单位 - 'description': 'NFC产品特殊处理:每箱30瓶' - }, - '6901826888138': { - 'multiplier': 30, # 数量乘以30 - 'target_unit': '瓶', # 目标单位 - 'fixed_price': 112/30, # 固定单价为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' - }, - '6907992501819': { - 'map_to': '6907992500133', # 映射到新条码 - 'description': '条码映射:6907992501819 -> 6907992500133' - }, - '6923644268916': { - 'map_to': '6923644268503', # 映射到新条码 - 'description': '条码映射:6923644268916 -> 6923644268503' - }, - '6923644283582': { - 'map_to': '6923644283575', # 映射到新条码 - 'description': '条码映射:6923644283582 -> 6923644283575' - }, - '6923644268930': { - 'map_to': '6923644268497', # 映射到新条码 - 'description': '条码映射:6923644268930 -> 6923644268497' - }, - '6923644210151': { - 'map_to': '6923644223458', # 映射到新条码 - 'description': '条码映射:6923644210151 -> 6923644223458' - } - # 可以添加更多特殊条码的配置 - } + # 加载特殊条码配置 + self.special_barcodes = self.load_barcode_mappings() # 规格推断的正则表达式模式 self.spec_patterns = [ @@ -447,4 +400,98 @@ class UnitConverter: # 没有找到适用的处理程序,保持不变 logger.info(f"其他单位处理: 保持原样 数量: {result.get('quantity', 0)}, 单价: {result.get('price', 0)}, 单位: {result.get('unit', '')}") - return result \ No newline at end of file + 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' + } + } + + 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) \ No newline at end of file diff --git a/app/core/excel/merger.py b/app/core/excel/merger.py index ca35f9f..0740943 100644 --- a/app/core/excel/merger.py +++ b/app/core/excel/merger.py @@ -36,35 +36,44 @@ class PurchaseOrderMerger: 采购单合并器:将多个采购单Excel文件合并成一个文件 """ - def __init__(self, config: Optional[ConfigManager] = None): + def __init__(self, config): """ 初始化采购单合并器 Args: - config: 配置管理器,如果为None则创建新的 + config: 配置信息 """ - logger.info("初始化PurchaseOrderMerger") - self.config = config or ConfigManager() + self.config = config - # 获取配置 - self.output_dir = self.config.get_path('Paths', 'output_folder', 'data/output', create=True) - - # 获取模板文件路径 - template_folder = self.config.get('Paths', 'template_folder', 'templates') - template_name = self.config.get('Templates', 'purchase_order', '银豹-采购单模板.xls') - - self.template_path = os.path.join(template_folder, template_name) - - # 检查模板文件是否存在 - if not os.path.exists(self.template_path): - logger.error(f"模板文件不存在: {self.template_path}") - raise FileNotFoundError(f"模板文件不存在: {self.template_path}") - - # 用于记录已合并的文件 - self.cache_file = os.path.join(self.output_dir, "merged_files.json") - self.merged_files = self._load_merged_files() - - logger.info(f"初始化完成,模板文件: {self.template_path}") + # 修复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]: """ @@ -73,11 +82,11 @@ class PurchaseOrderMerger: Returns: 合并记录字典 """ - return load_json(self.cache_file, {}) + return load_json(self.merged_files_json, {}) def _save_merged_files(self) -> None: """保存已合并文件的缓存""" - save_json(self.merged_files, self.cache_file) + save_json(self.merged_files, self.merged_files_json) def get_purchase_orders(self) -> List[str]: """ diff --git a/app/core/excel/processor.py b/app/core/excel/processor.py index 87231ea..a3c38d4 100644 --- a/app/core/excel/processor.py +++ b/app/core/excel/processor.py @@ -39,39 +39,44 @@ class ExcelProcessor: 提取条码、单价和数量,并按照采购单模板的格式填充 """ - def __init__(self, config: Optional[ConfigManager] = None): + def __init__(self, config): """ 初始化Excel处理器 Args: - config: 配置管理器,如果为None则创建新的 + config: 配置信息 """ - logger.info("初始化ExcelProcessor") - self.config = config or ConfigManager() + self.config = config - # 获取配置 - self.output_dir = self.config.get_path('Paths', 'output_folder', 'data/output', create=True) - self.temp_dir = self.config.get_path('Paths', 'temp_folder', 'data/temp', create=True) - - # 获取模板文件路径 - template_folder = self.config.get('Paths', 'template_folder', 'templates') - template_name = self.config.get('Templates', 'purchase_order', '银豹-采购单模板.xls') - - self.template_path = os.path.join(template_folder, template_name) - - # 检查模板文件是否存在 - if not os.path.exists(self.template_path): - logger.error(f"模板文件不存在: {self.template_path}") - raise FileNotFoundError(f"模板文件不存在: {self.template_path}") - - # 用于记录已处理的文件 - self.cache_file = os.path.join(self.output_dir, "processed_files.json") - self.processed_files = self._load_processed_files() - - # 创建单位转换器 - self.unit_converter = UnitConverter() - - logger.info(f"初始化完成,模板文件: {self.template_path}") + # 修复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]: """ diff --git a/app/core/ocr/__pycache__/baidu_ocr.cpython-39.pyc b/app/core/ocr/__pycache__/baidu_ocr.cpython-39.pyc index abeda2abb99beec6f05b2d52dcffd208d9387b51..0d04bf2336f7cff0e979f13ca685d6be877905f3 100644 GIT binary patch delta 1228 zcmZ`(O=ufO6rLHaR?=#BEy;?EQvb-{geA`lLKP(4?q**I+Y&p!1 zC^m9U>l_MgieVs!{6GQ?fzZ+#H@85qxdw9DK*%8q>9O}<`ku5gq_nflH}k&t=6i2u znB6<|_ZN1_vJ3+4m%DwJ-%Rb;&G=>r%oET(4&agk<)pwkErdAZp=+d|xnWm#BU!?= z+l+^~eoZSx-59WuMV2MtGr$)CUzEqd7jOHFz=!J$@Wr_aK9gH#iDUcr=cO8N%;e|t z%j$sXY*rZLe%G)dEHV$>D^o(6v`LC&o38ga=@R7>3**}L5U@-FE-|TXF)=2?IN!o( z7DPh1L8Klqk$onzo&hcjdYe#r5Ei>g>K|%E8Zy4f)^1XQ9|(66N4bGZC!6dRxx+d!^Mt21*f*?hbjD#a440RJTj_4N zDrwEnzWVdt>u-NEazXP$Cuh%yez=Rj5FF}97fZ{_M8}WXJC0%qwXRX2eIh>?nW}5|~+>0#Gj# zY4y8pOpbv;B6>(;DQZ#^Fco4nLldl*y&I9yI^SD8nxHmK>^`^mDE(6TiNo~vE=_(C z9y){CSp)|GGm6s)?Yd`hmRHrx2Ax%{%%KDGNQ@vHLl{L^Py;=q^w-_9J&$x}4j6}t zDh!3VaJ|N|EK1n1IESI<5iTHHR3rW0WeYf604PL+D~l^$Ra^qAkyV2OY4x)I@%aDM z=WD!Hk)jCEeylt(#@)&)cRR;cR!;{O;x1};Ayn05uJ2$4r~h4lJvT)6l*;YoryWa- zW8ehBB*MoCX@vHX;M?}YZd`cFFKq~_I@Qk1;*)aOZaTn N6CYqiQ9T=c_z#SR5EuXe delta 949 zcmZvaT}TvB6vyYz?0oFb%&y9cu4KAPMMLyqrVtTmMkL`TX^>mFtb50GqgJ^y62gY0 zQVIpZg;0}ldyt5TM2fIpdg`Ia=w%CfX_e?9dN1jmS=%RPxW7H;|G($#xijx?v+-iHXbj1f3qGR&Do{dh0^S!(%bcohc7o5X9CUJS5fNh z?PfY0l^KZLfFB5EA{0arp#gX@c(W~T1(}M}Unz&qfda#& z;3uIo+Zn&^Cf$iKoAuz zC%iLOdql$R-pdJNgpZ>r4^6nXQ+_J=Z8QAH*&rgrZ^tY#+{mBD8pr_u5PS9yi_hE3 diff --git a/app/core/ocr/__pycache__/table_ocr.cpython-39.pyc b/app/core/ocr/__pycache__/table_ocr.cpython-39.pyc index aa67f94961d2ce31c0c428f7946723b690793dac..37da3eb11d3997392ef4b0c14d848dd58b649c40 100644 GIT binary patch delta 4195 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 Optional[bytes]: """ diff --git a/app/core/ocr/table_ocr.py b/app/core/ocr/table_ocr.py index 725f3a4..7682c98 100644 --- a/app/core/ocr/table_ocr.py +++ b/app/core/ocr/table_ocr.py @@ -103,51 +103,65 @@ class ProcessedRecordManager: class OCRProcessor: """ - OCR处理器,用于表格识别与处理 + OCR处理器,负责协调OCR识别和结果处理 """ - def __init__(self, config: Optional[ConfigManager] = None): + def __init__(self, config): """ 初始化OCR处理器 Args: - config: 配置管理器,如果为None则创建新的 + config: 配置信息 """ - self.config = config or ConfigManager() + self.config = config - # 创建百度OCR客户端 - self.ocr_client = BaiduOCRClient(self.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]: + """ + 加载已处理的文件记录 - # 获取配置 - self.input_folder = self.config.get_path('Paths', 'input_folder', 'data/input', create=True) - self.output_folder = self.config.get_path('Paths', 'output_folder', 'data/output', create=True) - self.temp_folder = self.config.get_path('Paths', 'temp_folder', 'data/temp', create=True) - - # 确保目录结构正确 - for folder in [self.input_folder, self.output_folder, self.temp_folder]: - if not os.path.exists(folder): - os.makedirs(folder, exist_ok=True) - logger.info(f"创建目录: {folder}") - - # 记录实际路径 - 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)}") - - self.allowed_extensions = self.config.get_list('File', 'allowed_extensions', '.jpg,.jpeg,.png,.bmp') - self.max_file_size_mb = self.config.getfloat('File', 'max_file_size_mb', 4.0) - self.excel_extension = self.config.get('File', 'excel_extension', '.xlsx') - - # 处理性能配置 - self.max_workers = self.config.getint('Performance', 'max_workers', 4) - self.batch_size = self.config.getint('Performance', 'batch_size', 5) - self.skip_existing = self.config.getboolean('Performance', 'skip_existing', True) - - # 初始化处理记录管理器 - record_file = self.config.get('Paths', 'processed_record', 'data/processed_files.json') - self.record_manager = ProcessedRecordManager(record_file) - - logger.info(f"OCR处理器初始化完成,输入目录: {self.input_folder}, 输出目录: {self.output_folder}") + Returns: + 已处理的文件记录字典,键为输入文件路径,值为输出文件路径 + """ + return load_json(self.processed_files_json, {}) def get_unprocessed_images(self) -> List[str]: """ @@ -157,10 +171,16 @@ class OCRProcessor: 未处理的图片文件路径列表 """ # 获取所有图片文件 - image_files = get_files_by_extensions(self.input_folder, self.allowed_extensions) + image_files = get_files_by_extensions(self.input_folder, self.file_types) # 如果需要跳过已存在的文件 - if self.skip_existing: + skip_existing = True + try: + skip_existing = self.config.getboolean('Performance', 'skip_existing', fallback=True) + except: + pass + + if skip_existing: # 过滤已处理的文件 unprocessed_files = self.record_manager.get_unprocessed_files(image_files) logger.info(f"找到 {len(image_files)} 个图片文件,其中 {len(unprocessed_files)} 个未处理") @@ -186,13 +206,19 @@ class OCRProcessor: # 检查文件扩展名 ext = get_file_extension(image_path) - if ext not in self.allowed_extensions: + if ext not in self.file_types: logger.warning(f"不支持的文件类型: {ext}, 文件: {image_path}") return False # 检查文件大小 - if not is_file_size_valid(image_path, self.max_file_size_mb): - logger.warning(f"文件大小超过限制 ({self.max_file_size_mb}MB): {image_path}") + max_size_mb = 4.0 + try: + max_size_mb = float(self.config.get('File', 'max_file_size_mb', fallback='4.0')) + except: + 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 @@ -211,8 +237,15 @@ class OCRProcessor: if not self.validate_image(image_path): return None + # 获取是否跳过已处理文件的配置 + skip_existing = True + try: + skip_existing = self.config.getboolean('Performance', 'skip_existing', fallback=True) + except: + pass + # 如果需要跳过已处理的文件 - if self.skip_existing and self.record_manager.is_processed(image_path): + 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 @@ -220,12 +253,19 @@ class OCRProcessor: logger.info(f"开始处理图片: {image_path}") try: + # 获取Excel扩展名 + excel_extension = '.xlsx' + try: + excel_extension = self.config.get('File', 'excel_extension', fallback='.xlsx') + except: + pass + # 生成输出文件路径 file_name = os.path.splitext(os.path.basename(image_path))[0] - output_file = os.path.join(self.output_folder, f"{file_name}{self.excel_extension}") + output_file = os.path.join(self.output_folder, f"{file_name}{excel_extension}") # 检查是否已存在对应的Excel文件 - if os.path.exists(output_file) and self.skip_existing: + 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) @@ -304,31 +344,38 @@ class OCRProcessor: (总处理数, 成功处理数)元组 """ # 使用配置值或参数值 - batch_size = batch_size or self.batch_size - max_workers = max_workers or self.max_workers - + if batch_size is None: + try: + batch_size = self.config.getint('Performance', 'batch_size', fallback=5) + except: + batch_size = 5 + + if max_workers is None: + try: + max_workers = self.config.getint('Performance', 'max_workers', fallback=4) + except: + max_workers = 4 + # 获取未处理的图片 unprocessed_images = self.get_unprocessed_images() if not unprocessed_images: logger.warning("没有需要处理的图片") return 0, 0 - + total = len(unprocessed_images) - success = 0 - + 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-1)//batch_size + 1}, 大小: {len(batch)}") - - # 使用线程池并行处理 + batch = unprocessed_images[i:i+batch_size] + logger.info(f"处理批次 {i//batch_size+1}/{(total+batch_size-1)//batch_size}: {len(batch)} 个文件") + + # 使用多线程处理批次 with ThreadPoolExecutor(max_workers=max_workers) as executor: results = list(executor.map(self.process_image, batch)) - # 统计成功数 - success += sum(1 for result in results if result is not None) - - logger.info(f"批次处理完成, 成功: {sum(1 for result in results if result is not None)}/{len(batch)}") - - logger.info(f"所有图片处理完成, 总计: {total}, 成功: {success}") - return total, success \ No newline at end of file + # 统计成功数 + success_count += sum(1 for result in results if result is not None) + + logger.info(f"所有图片处理完成, 总计: {total}, 成功: {success_count}") + return total, success_count diff --git a/app/core/utils/__pycache__/dialog_utils.cpython-39.pyc b/app/core/utils/__pycache__/dialog_utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e27d99e63c7019f1351c5f3061eb82f5871fd494 GIT binary patch literal 11180 zcmbtaYj9M@mA-@e;2w4<|zmmN7VqmL)MU*r_BqWmCyoOI8_8k6^?+MBh7r zl&g(xL}uhzMu{KT29lA39Yd9YI4Rz?tG2dkv-@*@-r9ew8KkPM@{cWVZKbxd`G;)iTHfe0@`1j9O6^9@%$t2C${j4oLgQ**kcC-fTci=!pN zmaukUqD*^MNiHpY7t=&)S8mQ;IbWatN$vW(wNuyY?@!mxpNVYse+eebB z8)7LtV`uZ3&rEc}pdfRVG;O=_S%N|cUmaiT9|3Kps!l5tN=2z^jxw#PR01QslEE~l zO>3%R2P(=*wA#v$Sy3D?iW!soP>=uKKK;xom4DHWI;I^vsZrT6t8LTD z6Uq;I4r*hev9KJ)37u6~yA#Gp`r<1)`d<}wO6MUvKD4CTUIBMRP41~fU^@u=`D^jk z+sT%)F1Bpa@N;e`)$(FMflloZ1i40MFDO(B7tRl_`>Imy*t9^V6H2609wpc+I ztzax_FRLyW^%YbHCgw!hnj;GK|3{S8u2$H(vj$s#UMs|@#j7XIYh!KRJP$Z+Vka9~ zX4@!F$?LPpiB(s!&EB3D?fHGButinq&!c&eE!yunrJ(hYBuWX2JMk9ota9S)3uSds zWnW~;@etcWa)%MSvHvekl58qN)aN15XX}0YY^x|ktM475@N;p#`@}kf?BT_wz-#Tn z89uV`4DYk{?d(ykNx64cZ{44>Cfvg{)8HL`*RmZfNVgE>b!7#d*h#yTcND7TvC_Y& zP&EmBYL&CK+qY)Rmui>ap1C=3_x7vxUz}^I646C~$N3?vSCoj#&f2+5Z=%_+UMDu><(b>pX0KnVeLVi@ol5P! z7qN=^xrtBjOf<xN{miwwGrybpWE#WD?w{Uyd-n1>waM3Ilbe|fhH|E|Nuf0^AAK-&CwNp3h)jPF2r~TAo$IoQ!5-<2z&a$ao@sN+_#Qfh( zi_UIv$IhM;k8bbTm(<X~D!M;tN$z?NxZgil?S%x3aGW+lx*|du~rystI0ByHKq;eJV zfEtsvQ4g9dt0?UN2By`wJu*0|C%&}@;5&OHyMzSSF8sQ7^>mY6oQUT%0Lc__*Cb=X zfsW13ZQY#Tx|t<5Kh?YWJH4Bq6}zvWsn&n{`s^#$Yp37vFG#L%;?>%n=OsFgaa%rQ zq?h7r(Q?U9lYxC!xu}x;*NT=Kw(JzQ>Ec}k){XjZB2R$k4||^IJ@}oG#1qAIDW56W z*1_Qs`*5*vu*lO}1qZht+kP-LJbW-+a6L{spg69wV}6sK0zi5tWZz82`D!Pnu3uLmIEwGX>NmgR+1 zJ|kGcAE4F*fsF(<0sMdpn*mDXFV#-{cJ9mva#`mt)h9l#Rj&GlS+vYvxnBR(^Yvf8 zD_fvpY9GB0v1RE;ckb9(q6Nx5`P&!W(6i`jwQh*KF4|C1+dmqGFPD0_Sh9ypwtsJY z3+UWnYQUmB$_*ueTCg<;x7^wvLR;ihXt;PyeS zL{hfRvjZhNV~HssW~Myv1v3^KGbY!&ntj9#9ViaxGRHDGHz2Hw8#}YBrmvP(D5X%hjKb|eH;&C_d?bHA$aDM3{ZeSnB>AA+9rw=^ks^51bSu0zB#23;) zvTWLR16ezhx8%VKzCht+E!%QK11T#*XYZO%KJ)a`-`ne|f8z!ZWo*ow;k0qLZIBo9 zWP>nbewbEgi>e#4Y(7X0uDPdV+r@%we0%S{0}v;4<;4-#$Ylp@zKsTnqy}mAS(eKr zm+(gk74(cH-$1o+)5^J#dBf#KeTK+gl4>156 zA<>UNhZ$O=k~AwF&eQl>q{VH;fr@t23+gL$FVxZtKnfEngQBLN)AU?KqX4zjFT(oI z+<0ZNE#5tQqc-*OeCI#QJSSDLbh5)KxKXZoe!^PvRI?_U;MY~kO zoYZNW>{{bPYL4vTH}JLk036&&@&NIR7;Q|&uZCa5X;pn1x3!z%Fu;|{m=2ub;WQ6t z02g3d)pS%xb9Bd;HppXSIyh+vZ8r1KClqU*{#ETar)F+^AbHByVCvE6kH${?XzWYk z-~MFKZ7&T|bSXsLPFY7RH;OwuSj5eR4R&L)ayXMcbl7$~WX%HSGX>e9(~pwf_zq0u znuA52Puac|4#^2b2>_xM_*yA&;?(q9+;L`zyHtoL~kzhpoO zXEA7cvLF=dPN)^N3T6p6TCM5`bip3r45l;P3wl)<^j1v~T--VHwDPDgb&BL<1i~Ac6qd z3jx~@K*xx3D2|Lnn`n!R6(~bX(1z^8q&5+(1VwvCOFPkaHffi(w9V7TDltLZHQ#;Xk8&EBtkFRKdnscpDjZm9Uf|TLQa@MShjM~n9!Xt!t4!Wk%~Ul;UJ`yJ4US& zn@E zVl2_5UC8$aZCj;H(E9j}eG=^h9_`Z4o!6|Gpk2Diyc?RdpEqx)5)!oc&b!g0?OJ5s zO=7=r89>{Gc_sDcNo34~q|hm}Icg0+L|Y^!DkS9#o}}nU zU#kE^DFBHnt!DM!m~gCVw!J&cx4s-s^Idjz$m&3n@2bS)x-tDP>k-Dzi! zLY|j7%jEhYD?8-fAENf1PKRh;?kr!}4&6YUUE!=)bnF%EF{e||u5?x|q{Y}P*q5E9 zqJ5RKYGJ#l-@2V{Z*0YC`HaeS}&4b`IbWGGYo3BmII2AbhHtfX%UgA`(ZV(9@a#i+~{)g;N0w0-@ zp?pO3h5DP-+ST#9cix!&_-8WHJMV+Ereuaw9Ii1EDwS)}MvIO#9$Y#rbqu+dnNQBw zK6tZs_7}5PPu9vGiCo9a^;h1lzjkfrlgstjZq}w=x%>9GoD;3}$;-__(j`vg_vaD) zWedm!C2AkNTAP^sy#9jl&+?LFFm%tZ`+|@4^qkn)({n&X(}-Y9fiBc}7sCqsX&3AN~a~>3lmvviJxbt70zaMb#zB?|Tas z<(Zpr;;?&t+dv*|=A%i8shz!r)F5GQU+)$DXMa78q?Ih!PoJLs|;`#nG!-{yz7 zPdlYUwk`lbHNZO-o-tg3W*M#>PdKX8V~XMRr#A*J#dUc>ibQ zp;9*B)Vp)9y)}E~N@)`iO##9~k6+YgZcO5pXXeJOyBBW>u@&TV<;mKGNy+BV=8rp3 zBH2$Mu|{eD85E&hIPsIhbP+OI7sIZO*wzgoc+C!T3O?K@i6LT^0^}4Kzv1Cbfw?Av z>kPN~Bh*9RyZ;FU`jAtb1lY8SC62J$M81gzGbr#*8g9%}AN@Im-SagYe!m-&H2oyS zBW_Gm%9`}%H;Sbo_-!a5ggT1V4XlFrFb1bSrWztv>{3H|TwRXu=yorf8%Xgq?oWgC zo*a~K*cLG&<{0=2F|tvB{)QNhK_IL(wulFOB7>;FLBO<%9=22jTgEC;8`Erqp2Ns* zfyL7CHO2yt;b;)5-4L7r#RK&4adhD5Zp>gdMv=mGF|c2%k#m>ko}Z}y^kRu}SI8~Z zPE{mg_PrNsmFnDE7f2tAOtz2)K7xK1gGl@d4T6-kI8Z(YG#>|W!Ekhhl z9EkxO4H5*VKDzTyJebx|Th4|go3yJqo0XWaVl=O{cTO@8t^}KS&8G%*pBljVH2dIs zTL!!SE{t$bny31Y2tNQ6$)j zkIqvoyaY!1Ozb_1gC9c&ew=#Ism*H%zxfopf}fzCqX3BWgWko$`!XJNvcpKX<1wIA z$U=h*^DL#_tl>-=3AhZb5Q$teSbY3Mw)LwZRmGQRG-?+@4s%W64 zQfbtLQi;$?B)LyiqjcN7eo2y3N(KrgLW+d`khJnEljTT4#nr~&pQTj1X<7uAluFY! zIjH=FN@a^sDkdqF#^0jKWoR+w!e7Dy_)h_nCO=JOIwk%Zfhho29pFF5FRuMB30EbM zAkcE{y?s8p__bg2|Gf6zsKOtpU%!p#GtX!}NDCmZL%Iq=_sJ$HYjnIhbR? zu@G{R_}>h>kjCL3j^ef0F>Lju#>biA7{}nb*qURUga_ilWUv56nX-|0^J5AzoMf{d zFXZbC#WqH+lChxl(0rSG6?X#s9~>w!F`~IkaZLV)(JstmHb)KaQkvuZw>J(9j-WuB zH%<`m|1pQW7g}2gBZYVmQZ}+4##(zS^nWBCs(=G0VZ7`>)kGK{t`Li(n*mghezB|Be8XNg8W%{3jKD`jS9Vy9j510SKY>62aOx` zoCBd|qJ!BJ8P+eAO`8yy!E8E31pK{*fXL8Cz9$M(3MWY7gj~$rxa405oGh8|ym84d zLhwIpmA8^%zKa&2!$EQbgSleLcJ*w*b|c@TocmtRi(I-*A#$52>FMgZOo4wBRLO8( zs1ZU5tIAITD=!;ujlV(Q41qTZyaj-er-#a9blspA&B?o%AiTJSZ4}})yc>&*zqK2U zie~6BO;h84jF~XKP-~hN!CmasI`wv_xlU4a0^22Orl`e{e-CLJ)X^P(qLFTyyyZ%X zH2?@3-FP@^2!VWwQw3+FN_iMveagj5)9X#{ecFylgR7%k|HLIpN*QE`xK|YEP4!xZ zzf04Q7M8Y5aQ=O&UL63qK*G$ zRXpPAFf)7)HGG*Gj6*!j+`wMp--Zsr=RKCq9Cw3W04U-n{uK2LKPv(@m^nA}y}i#I z_~thr|F#<#5#0mNeDlet4!G)bZa7^m3}z3NI9xXi4`ol%Omyg+GTr>g1fD1GBLKWC z@l?U07!hw*JT=e{lH`M~Df0&WH`J$nVU*t&$)~d3i%=hK-9SI)#G_WO&p_o70k`)> zvjx05%6Fr_2w7q84Jn5~`*cKta6lV7>RamRbo|$dd8*C^a-OoN+{pd-p;Sh-aonHUOj6@e3DB^uA@9phF zn(wzXUr0#5m_-U5jUcWxydJ#D3Z1ps#TJ5|jPti?sOA-ye)UNEkN2G-v9cF-u+zXB*RdZv>PbrH2okKm~-qLF{oZs6HYTZ57Zbpvf(P!XL7 zun5})AHGwKFYM>1@s%-l3w0c`33`m%xjeqKdtJPXW^7m6>5Ja2<<7@qP*k$b!~r~h1o|gt?wOri*nvll-3A<|1Jaicie4oZwM2QsK=af9mIE)pHmhYiZFOjDsa#r$D z%Wn-9&%P~uE^PRujR;phdjCc5h9ZR9pVV>lj=;cV_%{5%O`&AOZjlD+!>ak;5}@4* zd6GZ~!)o!MxcI{UnN%vVM~TE#{(Jl;gFHZkkXqbNA3W;=#N1$iKP#sD`^CGt8}!y9 zH6tlyIX8_Zo;k%srBsh}CSq*g$`XVV%M0y7Myr&|>?TriLWW7ta%7j_CH!xMg`%Nw L}B)P%$17tP$>t^#`S)HV>6T?H}RW;EUiT^~D!K6kq(#Y*IKHXZe2j`|D=D z-_LyZejfb$h-r6sClD;>+A|k#_pO^x<6qW~-+1lNCZQ>MxUQb>b-E~_N$`7UFZgNj z(wms}(SGpy9%lz=2K;_Xrja%H!ykX?HH)z4VP}>ERm9?uy`{lB1~LxfuYw9t1%nU} z1w;kWDBjenIK<6Zh?;s!)Q}db5;$I|3(u&;D~TLh!&N0za_C*Ns)lN_DNH|6Lh5_M((qz^(&l931*SLd80p$cx9kT+ zZ{gC|3Z(u7L95UDPB8C!rFl8m$Vu0Ov;8qJ_G_0ds5=-KiAww4-3Ywje!M@L&0B}$ z>0Fbba8-c9bpc8ZP~nf1;?O3 zAw$J`&%d#FkCIjloK#H0rnY}IW^wI9Q7Fib^aSp~BH4r4JK$S5BE87%F9i&7eUkJS zz@V5CNn~6h6(BGW8SWE^d;)G%4KY>L2+M>RJ_VJkSID5q^;bzqnz0tbs0QDLzQ^_x zOPRoE#zir~u>^qe{}XuWbLmar@vqyk2jAUElrmBOto0{U6?S(yn$8@7O4u z$6gVt6J+)(#5P2H4Akm#Mc4D4dE0db@!*2}gJ{PD%k#@apr35K2HgVhqPeWDi0`Mx z31@_Q6BO4k+P)nGOm4)^ig;cq@$bX6qU+d9a>-KITOuym@wTu!yXS|W==Zaypv+H! zLYiPkL;+JV2%FhHoA?9|-4q3;D9{N`;xvc}51WICHPHB{%huTIU^m`N4yLBSklbN2 W!kTN;l1K4K+0xc|2!l~RTOer9~V2Tis zFOtF(%%CZ}nTPQk`{uvgL5z$klLL4~87()b^7k>yl>p5u<^!3?&cw*WC<4TMKv-l0 z6wwr&EGU?$dW*%=&&~f9OHzJ*&Mh{d{PgtHq9S9Ue31!=umlk{lNSi8F=|adE~vvO F007&CC?5a- diff --git a/app/core/utils/dialog_utils.py b/app/core/utils/dialog_utils.py new file mode 100644 index 0000000..af29ac0 --- /dev/null +++ b/app/core/utils/dialog_utils.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +对话框工具模块 +------------- +提供各种弹窗和对话框显示功能 +""" + +import os +import tkinter as tk +from tkinter import messagebox, ttk +from datetime import datetime + +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)) + + size_text = f"{file_size / 1024:.1f} KB" if file_size < 1024*1024 else f"{file_size / (1024*1024):.1f} MB" + + 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: + 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) + + # 底部按钮区域 + 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: + 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: + 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) + + # 导入当前映射数据 + 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) \ No newline at end of file diff --git a/app/core/utils/log_utils.py b/app/core/utils/log_utils.py index 099a2ec..ce765a6 100644 --- a/app/core/utils/log_utils.py +++ b/app/core/utils/log_utils.py @@ -97,6 +97,36 @@ def get_logger(name: str) -> logging.Logger: 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: """ 关闭日志记录器的所有处理器 @@ -113,6 +143,25 @@ def close_logger(name: str) -> None: _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: """ 清理日志活跃标记 diff --git a/app/services/__pycache__/ocr_service.cpython-39.pyc b/app/services/__pycache__/ocr_service.cpython-39.pyc index 9edaa89ea5281b5cdfa45b8ea47b53b4d9c98cfc..cd31aa9fcf0da228aa338bf437732f5d823dcbd1 100644 GIT binary patch delta 500 zcmdlkeomS%k(ZZ?0SFE)kj*&7vyso2QD_p7o5~Qyn8Fanl)@OroFY6qm(kK!B$XQo zc|c?ulO#h5&m86y-W0wT)+pW-Q7m%&DFQ$_zEqA>{uItROeumXLM<#&0x3+v44Pt_ zuQN_%WOUh_%bdo_xN`Cpj$jLBkTakF#AX3vXCN*X0}>?+3m8)v7cw$3)G#bys$r~Q zS_m?SsZ@kU-#rr)SPdipWozVMi+RkU2r@r6Q^JGU~K~a8kYH@LVW^Q77YH@s0 zVo7qw)2{h1n)g1Rz2oVGp7(n?C-*U_Og_y%&(INQiNAADaB5LmW^$??SZzGifESBa zzu3_He98)-u`l+ndD=hmX~%}i`#HoT_<*{K_(6m$h>!yjLU2MD$hyUgVw68ns2Jok z25v6KDhXURPL^Ymn(V;&mQ?|$GIp{Nmo6)lpP#1SF0~7*kDpHxu#9hLuIJunL0RUwQkRAX4 delta 188 zcmX>ny>&7I6? ztc;qIKX3$3wq}x??8E(*RSsx{-());T}FY)1w8Q_w^)+$^K**iCg0&vl;QzOaxk*6 fi0}(>iipVY6@di&GzE*4CQI^`Fv?Hv<8=T4qhTr% diff --git a/app/services/__pycache__/tobacco_service.cpython-39.pyc b/app/services/__pycache__/tobacco_service.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c04dc9a8dd8ba5a7b61be71fc109722d6f0f754 GIT binary patch literal 7293 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 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) + def validate_image(self, image_path: str) -> bool: """ 验证图片是否有效 diff --git a/app/services/tobacco_service.py b/app/services/tobacco_service.py new file mode 100644 index 0000000..d5ed574 --- /dev/null +++ b/app/services/tobacco_service.py @@ -0,0 +1,255 @@ +#!/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.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') + self.output_file = os.path.join(self.output_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 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 not order_data: + 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: + # 读取Excel文件 + df_old = pd.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") + } + + # 显示自定义对话框 + show_custom_dialog( + title="烟草订单处理结果", + message="烟草订单处理完成", + result_file=output_file, + time_info=order_time, + count_info=f"{total_count}个商品", + amount_info=f"¥{total_amount:.2f}", + additional_info=additional_info + ) + + # 记录日志 + logger.info(f"烟草公司订单处理成功,订单时间: {order_time}, 总金额: {total_amount}, 处理条目: {total_count}") \ No newline at end of file diff --git a/config/barcode_mappings.json b/config/barcode_mappings.json new file mode 100644 index 0000000..7d278cc --- /dev/null +++ b/config/barcode_mappings.json @@ -0,0 +1,35 @@ +{ + "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" + }, + "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" + } +} \ No newline at end of file diff --git a/logs/__main__.active b/logs/__main__.active new file mode 100644 index 0000000..b266a30 --- /dev/null +++ b/logs/__main__.active @@ -0,0 +1 @@ +Active since: 2025-05-09 16:01:39 \ No newline at end of file diff --git a/logs/__main__.log b/logs/__main__.log index 86403d2..98367b7 100644 --- a/logs/__main__.log +++ b/logs/__main__.log @@ -385,3 +385,57 @@ 2025-05-08 20:04:14,985 - __main__ - INFO - Excel处理成功,输出文件: D:\My Documents\python\orc-order-v2\data\output\采购单_微信图片_20250508194532.xls 2025-05-08 20:46:00,701 - __main__ - INFO - 处理Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250508194532.xlsx 2025-05-08 20:46:07,564 - __main__ - INFO - Excel处理成功,输出文件: D:\My Documents\python\orc-order-v2\data\output\采购单_微信图片_20250508194532.xls +2025-05-09 11:55:03,576 - __main__ - INFO - 配置信息: +2025-05-09 11:58:49,250 - __main__ - INFO - 配置信息: +2025-05-09 12:02:05,165 - __main__ - INFO - 配置信息: +2025-05-09 12:07:05,179 - __main__ - INFO - 配置信息: +2025-05-09 12:07:54,655 - __main__ - INFO - 配置信息: +2025-05-09 12:12:42,101 - __main__ - INFO - 配置信息: +2025-05-09 12:13:52,578 - __main__ - INFO - 配置信息: +2025-05-09 12:45:35,994 - __main__ - INFO - 配置信息: +2025-05-09 12:45:35,999 - __main__ - INFO - 开始烟草公司订单处理 +2025-05-09 12:45:36,000 - __main__ - INFO - 处理最新的烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 12:45:36,103 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:21:53,249 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:22:48,497 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:25:59,111 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:29:28,837 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:30:21,973 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:30:43,780 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:34:49,132 - __main__ - INFO - 开始烟草公司订单处理 +2025-05-09 13:34:49,291 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:34:49,291 - __main__ - INFO - 烟草订单处理完成,绝对路径: D:\My Documents\python\orc-order-v2\data\output\银豹采购单_烟草公司.xls +2025-05-09 13:37:56,253 - __main__ - INFO - 开始烟草公司订单处理 +2025-05-09 13:37:56,482 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:37:56,482 - __main__ - INFO - 烟草订单处理完成,绝对路径: D:\My Documents\python\orc-order-v2\data\output\银豹采购单_烟草公司.xls +2025-05-09 13:39:38,187 - __main__ - ERROR - 执行过程中发生错误: 'OrderService' object has no attribute 'merge_all_purchase_orders' +Traceback (most recent call last): + File "D:\My Documents\python\orc-order-v2\run.py", line 128, in main + result = order_service.merge_all_purchase_orders() +AttributeError: 'OrderService' object has no attribute 'merge_all_purchase_orders' +2025-05-09 13:39:52,436 - __main__ - INFO - 开始烟草公司订单处理 +2025-05-09 13:39:52,581 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:39:52,581 - __main__ - INFO - 烟草订单处理完成,绝对路径: D:\My Documents\python\orc-order-v2\data\output\银豹采购单_烟草公司.xls +2025-05-09 13:50:34,352 - __main__ - INFO - 开始烟草公司订单处理 +2025-05-09 13:50:34,773 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:50:34,773 - __main__ - INFO - 烟草订单处理完成,绝对路径: D:\My Documents\python\orc-order-v2\data\output\银豹采购单_烟草公司.xls +2025-05-09 13:52:17,577 - __main__ - INFO - 开始烟草公司订单处理 +2025-05-09 13:52:17,706 - __main__ - INFO - 烟草订单处理成功,输出文件: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:52:17,707 - __main__ - INFO - 烟草订单处理完成,绝对路径: D:\My Documents\python\orc-order-v2\data\output\银豹采购单_烟草公司.xls +2025-05-09 14:26:54,513 - __main__ - ERROR - 执行过程中发生错误: 'OrderService' object has no attribute 'process_latest_excel' +Traceback (most recent call last): + File "D:\My Documents\python\orc-order-v2\run.py", line 116, in main + result = order_service.process_latest_excel() +AttributeError: 'OrderService' object has no attribute 'process_latest_excel' +2025-05-09 14:27:08,881 - __main__ - ERROR - 执行过程中发生错误: 'OCRService' object has no attribute 'batch_process' +Traceback (most recent call last): + File "D:\My Documents\python\orc-order-v2\run.py", line 98, in main + total, success = ocr_service.batch_process( +AttributeError: 'OCRService' object has no attribute 'batch_process' +2025-05-09 14:27:31,662 - __main__ - ERROR - 执行过程中发生错误: 'OCRService' object has no attribute 'batch_process' +Traceback (most recent call last): + File "D:\My Documents\python\orc-order-v2\run.py", line 98, in main + total, success = ocr_service.batch_process( +AttributeError: 'OCRService' object has no attribute 'batch_process' +2025-05-09 14:32:56,697 - __main__ - INFO - 开始烟草公司订单处理 +2025-05-09 14:32:56,706 - __main__ - ERROR - 烟草订单处理失败 diff --git a/logs/app.core.excel.converter.active b/logs/app.core.excel.converter.active new file mode 100644 index 0000000..617fce6 --- /dev/null +++ b/logs/app.core.excel.converter.active @@ -0,0 +1 @@ +Active since: 2025-05-10 11:21:12 \ No newline at end of file diff --git a/logs/app.core.excel.converter.log b/logs/app.core.excel.converter.log index 9acdd9e..aebf1fc 100644 --- a/logs/app.core.excel.converter.log +++ b/logs/app.core.excel.converter.log @@ -1871,3 +1871,109 @@ 2025-05-08 20:46:01,871 - app.core.excel.converter - INFO - 解析容量(ml)规格: 400mL*15 -> 1*15 2025-05-08 20:46:01,872 - app.core.excel.converter - INFO - 解析容量(ml)规格: 480ml*15 -> 1*15 2025-05-08 20:46:01,873 - app.core.excel.converter - INFO - 解析容量(ml)规格: 500ml*15 -> 1*15 +2025-05-09 14:08:44,053 - app.core.excel.converter - INFO - 解析二级规格: 1*20 -> 1*20 +2025-05-09 14:08:44,053 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 10.0, 单位: 瓶 +2025-05-09 14:08:44,055 - app.core.excel.converter - INFO - 解析二级规格: 1*48 -> 1*48 +2025-05-09 14:08:44,055 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 10.0, 单价: 2.3, 单位: 杯 +2025-05-09 14:08:44,056 - app.core.excel.converter - INFO - 解析二级规格: 1*10组*5瓶 -> 1*10 +2025-05-09 14:08:44,056 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 9.0, 单位: 组 +2025-05-09 14:08:44,057 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:08:44,057 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:08:44,057 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:08:44,058 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:08:44,058 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:08:44,058 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:08:44,060 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:08:44,060 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:08:44,106 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:08:44,106 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 10.0, 单位: 瓶 +2025-05-09 14:08:44,107 - app.core.excel.converter - INFO - 解析二级规格: 1*20 -> 1*20 +2025-05-09 14:08:44,107 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 7.5, 单位: 瓶 +2025-05-09 14:08:44,108 - app.core.excel.converter - INFO - 解析二级规格: 1*20 -> 1*20 +2025-05-09 14:08:44,108 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 6.3, 单位: 瓶 +2025-05-09 14:08:44,108 - app.core.excel.converter - INFO - 解析二级规格: 1*20 -> 1*20 +2025-05-09 14:08:44,108 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 6.3, 单位: 瓶 +2025-05-09 14:08:44,109 - app.core.excel.converter - INFO - 解析二级规格: 1*24 -> 1*24 +2025-05-09 14:08:44,109 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 7.1, 单位: 瓶 +2025-05-09 14:08:44,110 - app.core.excel.converter - INFO - 解析二级规格: 1*16 -> 1*16 +2025-05-09 14:08:44,110 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 8.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:08:44,111 - app.core.excel.converter - INFO - 解析二级规格: 1*16 -> 1*16 +2025-05-09 14:08:44,111 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 4.0, 单价: 6.5, 单位: 杯 +2025-05-09 14:08:44,111 - app.core.excel.converter - INFO - 解析二级规格: 1*24 -> 1*24 +2025-05-09 14:08:44,111 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 5.5, 单位: 瓶 +2025-05-09 14:23:40,858 - app.core.excel.converter - INFO - 解析二级规格: 1*20 -> 1*20 +2025-05-09 14:23:40,865 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 10.0, 单位: 瓶 +2025-05-09 14:23:40,878 - app.core.excel.converter - INFO - 解析二级规格: 1*48 -> 1*48 +2025-05-09 14:23:40,878 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 10.0, 单价: 2.3, 单位: 杯 +2025-05-09 14:23:40,879 - app.core.excel.converter - INFO - 解析二级规格: 1*10组*5瓶 -> 1*10 +2025-05-09 14:23:40,880 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 9.0, 单位: 组 +2025-05-09 14:23:40,888 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:23:40,888 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:23:40,890 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:23:40,890 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:23:40,896 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:23:40,896 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:23:40,897 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:23:40,897 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:23:40,898 - app.core.excel.converter - INFO - 解析二级规格: 1*12 -> 1*12 +2025-05-09 14:23:40,899 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 10.0, 单位: 瓶 +2025-05-09 14:23:40,900 - app.core.excel.converter - INFO - 解析二级规格: 1*20 -> 1*20 +2025-05-09 14:23:40,900 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 7.5, 单位: 瓶 +2025-05-09 14:23:41,461 - app.core.excel.converter - INFO - 解析二级规格: 1*20 -> 1*20 +2025-05-09 14:23:41,461 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 6.3, 单位: 瓶 +2025-05-09 14:23:41,462 - app.core.excel.converter - INFO - 解析二级规格: 1*20 -> 1*20 +2025-05-09 14:23:41,462 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 6.3, 单位: 瓶 +2025-05-09 14:23:41,462 - app.core.excel.converter - INFO - 解析二级规格: 1*24 -> 1*24 +2025-05-09 14:23:41,463 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 2.0, 单价: 7.1, 单位: 瓶 +2025-05-09 14:23:41,463 - app.core.excel.converter - INFO - 解析二级规格: 1*16 -> 1*16 +2025-05-09 14:23:41,464 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 8.0, 单价: 3.0, 单位: 袋 +2025-05-09 14:23:41,465 - app.core.excel.converter - INFO - 解析二级规格: 1*16 -> 1*16 +2025-05-09 14:23:41,465 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 4.0, 单价: 6.5, 单位: 杯 +2025-05-09 14:23:41,466 - app.core.excel.converter - INFO - 解析二级规格: 1*24 -> 1*24 +2025-05-09 14:23:41,466 - app.core.excel.converter - INFO - 其他单位处理: 保持原样 数量: 6.0, 单价: 5.5, 单位: 瓶 +2025-05-09 14:31:54,333 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 14:31:54,334 - app.core.excel.converter - INFO - 解析容量(ml)规格: 260ML*24 -> 1*24 +2025-05-09 14:31:54,338 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 14:31:54,339 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 14:31:54,341 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 14:31:54,342 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 14:31:54,432 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 14:31:54,432 - app.core.excel.converter - INFO - 解析容量(ml)规格: 245ML*12 -> 1*12 +2025-05-09 14:31:54,433 - app.core.excel.converter - INFO - 解析容量(ml)规格: 125ML*36 -> 1*36 +2025-05-09 14:31:54,434 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 14:31:54,434 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*24 -> 1*24 +2025-05-09 14:31:54,435 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*24 -> 1*24 +2025-05-09 14:31:54,435 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*24 -> 1*24 +2025-05-09 14:31:54,436 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 14:32:21,071 - app.core.excel.converter - INFO - 解析容量(ml)规格: 500ml*15 -> 1*15 +2025-05-09 14:32:21,077 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 14:32:21,081 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 14:32:21,082 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 14:32:21,083 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 14:32:21,086 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 14:32:21,214 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 14:32:21,215 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 14:32:21,217 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 14:32:21,218 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 14:32:21,219 - app.core.excel.converter - INFO - 解析容量(L)规格: 1L*12 -> 1*12 +2025-05-09 15:15:10,369 - app.core.excel.converter - INFO - 条码映射配置保存成功,共6项 +2025-05-09 15:15:10,377 - app.core.excel.converter - INFO - 创建默认条码映射配置,共6项 +2025-05-09 16:01:39,293 - app.core.excel.converter - INFO - 成功加载条码映射配置,共6项 +2025-05-09 16:01:39,480 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 16:01:39,481 - app.core.excel.converter - INFO - 解析容量(ml)规格: 260ML*24 -> 1*24 +2025-05-09 16:01:39,482 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 16:01:39,483 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 16:01:39,484 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 16:01:39,484 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 16:01:39,485 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 16:01:39,711 - app.core.excel.converter - INFO - 解析容量(ml)规格: 245ML*12 -> 1*12 +2025-05-09 16:01:39,712 - app.core.excel.converter - INFO - 解析容量(ml)规格: 125ML*36 -> 1*36 +2025-05-09 16:01:39,713 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 16:01:39,714 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*24 -> 1*24 +2025-05-09 16:01:39,715 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*24 -> 1*24 +2025-05-09 16:01:39,716 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*24 -> 1*24 +2025-05-09 16:01:39,717 - app.core.excel.converter - INFO - 解析容量(ml)规格: 250ML*12 -> 1*12 +2025-05-09 16:03:48,340 - app.core.excel.converter - INFO - 成功加载条码映射配置,共6项 +2025-05-09 16:07:24,661 - app.core.excel.converter - INFO - 成功加载条码映射配置,共6项 +2025-05-09 16:08:24,335 - app.core.excel.converter - INFO - 条码映射配置保存成功,共7项 +2025-05-09 16:08:28,902 - app.core.excel.converter - INFO - 成功加载条码映射配置,共7项 diff --git a/logs/app.core.excel.handlers.barcode_mapper.active b/logs/app.core.excel.handlers.barcode_mapper.active new file mode 100644 index 0000000..617fce6 --- /dev/null +++ b/logs/app.core.excel.handlers.barcode_mapper.active @@ -0,0 +1 @@ +Active since: 2025-05-10 11:21:12 \ No newline at end of file diff --git a/logs/app.core.excel.handlers.barcode_mapper.log b/logs/app.core.excel.handlers.barcode_mapper.log index e69de29..bb7f523 100644 --- a/logs/app.core.excel.handlers.barcode_mapper.log +++ b/logs/app.core.excel.handlers.barcode_mapper.log @@ -0,0 +1,9 @@ +2025-05-09 14:31:54,337 - app.core.excel.handlers.barcode_mapper - INFO - 条码映射: 6923644283582 -> 6923644283575 +2025-05-09 14:31:54,340 - app.core.excel.handlers.barcode_mapper - INFO - 条码映射: 6923644268930 -> 6923644268497 +2025-05-09 14:31:54,341 - app.core.excel.handlers.barcode_mapper - INFO - 条码映射: 6923644268916 -> 6923644268503 +2025-05-09 14:31:54,432 - app.core.excel.handlers.barcode_mapper - INFO - 条码映射: 6920584471055 -> 6920584471017 +2025-05-09 14:31:54,433 - app.core.excel.handlers.barcode_mapper - INFO - 条码映射: 6925861571159 -> 69021824 +2025-05-09 14:31:54,434 - app.core.excel.handlers.barcode_mapper - INFO - 条码映射: 6923644210151 -> 6923644223458 +2025-05-09 14:31:54,435 - app.core.excel.handlers.barcode_mapper - INFO - 条码映射: 6907992501819 -> 6907992500133 +2025-05-09 16:01:39,710 - app.core.excel.handlers.barcode_mapper - INFO - 条码映射: 6920584471055 -> 6920584471017 +2025-05-09 16:01:39,712 - app.core.excel.handlers.barcode_mapper - INFO - 条码映射: 6925861571159 -> 69021824 diff --git a/logs/app.core.excel.handlers.unit_converter_handlers.active b/logs/app.core.excel.handlers.unit_converter_handlers.active new file mode 100644 index 0000000..617fce6 --- /dev/null +++ b/logs/app.core.excel.handlers.unit_converter_handlers.active @@ -0,0 +1 @@ +Active since: 2025-05-10 11:21:12 \ No newline at end of file diff --git a/logs/app.core.excel.handlers.unit_converter_handlers.log b/logs/app.core.excel.handlers.unit_converter_handlers.log index 6831ead..a6a8184 100644 --- a/logs/app.core.excel.handlers.unit_converter_handlers.log +++ b/logs/app.core.excel.handlers.unit_converter_handlers.log @@ -33,3 +33,42 @@ 2025-05-08 20:46:01,871 - app.core.excel.handlers.unit_converter_handlers - INFO - 赠品瓶单位处理: 保持原样 数量: 2.0, 单价: 0, 单位: 瓶 2025-05-08 20:46:01,872 - app.core.excel.handlers.unit_converter_handlers - INFO - 赠品瓶单位处理: 保持原样 数量: 1.0, 单价: 0, 单位: 瓶 2025-05-08 20:46:03,157 - app.core.excel.handlers.unit_converter_handlers - INFO - 赠品瓶单位处理: 保持原样 数量: 9.0, 单价: 0, 单位: 瓶 +2025-05-09 14:31:54,333 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 52.0 -> 4.333333333333333, 单位: 件 -> 瓶 +2025-05-09 14:31:54,334 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 3.0 -> 72.0, 单价: 50.0 -> 2.0833333333333335, 单位: 件 -> 瓶 +2025-05-09 14:31:54,338 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 30.0 -> 2.5, 单位: 件 -> 瓶 +2025-05-09 14:31:54,340 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 30.0 -> 2.5, 单位: 件 -> 瓶 +2025-05-09 14:31:54,341 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 30.0 -> 2.5, 单位: 件 -> 瓶 +2025-05-09 14:31:54,342 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 30.0 -> 2.5, 单位: 件 -> 瓶 +2025-05-09 14:31:54,432 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 4.0 -> 48.0, 单价: 45.0 -> 3.75, 单位: 件 -> 瓶 +2025-05-09 14:31:54,433 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 50.0 -> 4.166666666666667, 单位: 件 -> 瓶 +2025-05-09 14:31:54,433 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 72.0, 单价: 65.0 -> 1.8055555555555556, 单位: 件 -> 瓶 +2025-05-09 14:31:54,434 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 45.0 -> 3.75, 单位: 件 -> 瓶 +2025-05-09 14:31:54,435 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 3.0 -> 72.0, 单价: 55.0 -> 2.2916666666666665, 单位: 件 -> 瓶 +2025-05-09 14:31:54,435 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 3.0 -> 72.0, 单价: 63.0 -> 2.625, 单位: 件 -> 瓶 +2025-05-09 14:31:54,436 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 3.0 -> 72.0, 单价: 54.0 -> 2.25, 单位: 件 -> 瓶 +2025-05-09 14:31:54,436 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 +2025-05-09 14:32:21,072 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 15.0, 单价: 33.0 -> 2.2, 单位: 件 -> 瓶 +2025-05-09 14:32:21,077 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 +2025-05-09 14:32:21,081 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 +2025-05-09 14:32:21,082 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 +2025-05-09 14:32:21,084 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 +2025-05-09 14:32:21,086 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 +2025-05-09 14:32:21,214 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 +2025-05-09 14:32:21,215 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 +2025-05-09 14:32:21,217 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 +2025-05-09 14:32:21,218 - app.core.excel.handlers.unit_converter_handlers - INFO - 赠品件单位处理: 数量: 1.0 -> 12.0, 单价: 0, 单位: 件 -> 瓶 +2025-05-09 14:32:21,219 - app.core.excel.handlers.unit_converter_handlers - INFO - 赠品瓶单位处理: 保持原样 数量: 1.0, 单价: 0, 单位: 瓶 +2025-05-09 16:01:39,480 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 52.0 -> 4.333333333333333, 单位: 件 -> 瓶 +2025-05-09 16:01:39,481 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 3.0 -> 72.0, 单价: 50.0 -> 2.0833333333333335, 单位: 件 -> 瓶 +2025-05-09 16:01:39,482 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 30.0 -> 2.5, 单位: 件 -> 瓶 +2025-05-09 16:01:39,483 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 30.0 -> 2.5, 单位: 件 -> 瓶 +2025-05-09 16:01:39,484 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 30.0 -> 2.5, 单位: 件 -> 瓶 +2025-05-09 16:01:39,485 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 30.0 -> 2.5, 单位: 件 -> 瓶 +2025-05-09 16:01:39,485 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 4.0 -> 48.0, 单价: 45.0 -> 3.75, 单位: 件 -> 瓶 +2025-05-09 16:01:39,711 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 50.0 -> 4.166666666666667, 单位: 件 -> 瓶 +2025-05-09 16:01:39,712 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 72.0, 单价: 65.0 -> 1.8055555555555556, 单位: 件 -> 瓶 +2025-05-09 16:01:39,713 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 1.0 -> 12.0, 单价: 45.0 -> 3.75, 单位: 件 -> 瓶 +2025-05-09 16:01:39,714 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 3.0 -> 72.0, 单价: 55.0 -> 2.2916666666666665, 单位: 件 -> 瓶 +2025-05-09 16:01:39,715 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 3.0 -> 72.0, 单价: 63.0 -> 2.625, 单位: 件 -> 瓶 +2025-05-09 16:01:39,716 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 3.0 -> 72.0, 单价: 54.0 -> 2.25, 单位: 件 -> 瓶 +2025-05-09 16:01:39,717 - app.core.excel.handlers.unit_converter_handlers - INFO - 件单位处理: 数量: 2.0 -> 24.0, 单价: 42.0 -> 3.5, 单位: 件 -> 瓶 diff --git a/logs/app.core.excel.merger.active b/logs/app.core.excel.merger.active new file mode 100644 index 0000000..5367524 --- /dev/null +++ b/logs/app.core.excel.merger.active @@ -0,0 +1 @@ +Active since: 2025-05-09 16:01:38 \ No newline at end of file diff --git a/logs/app.core.excel.merger.log b/logs/app.core.excel.merger.log index bd77cdd..882f714 100644 --- a/logs/app.core.excel.merger.log +++ b/logs/app.core.excel.merger.log @@ -493,3 +493,22 @@ 2025-05-08 20:04:06,909 - app.core.excel.merger - INFO - 初始化完成,模板文件: templates\银豹-采购单模板.xls 2025-05-08 20:46:00,700 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger 2025-05-08 20:46:00,701 - app.core.excel.merger - INFO - 初始化完成,模板文件: templates\银豹-采购单模板.xls +2025-05-09 12:12:42,109 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger +2025-05-09 12:13:52,585 - app.core.excel.merger - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:13:52,585 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger完成,模板文件: templates\银豹-采购单模板.xls +2025-05-09 12:45:35,998 - app.core.excel.merger - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:45:35,998 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger完成,模板文件: templates\银豹-采购单模板.xls +2025-05-09 13:39:38,184 - app.core.excel.merger - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 13:39:38,186 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger完成,模板文件: templates\银豹-采购单模板.xls +2025-05-09 14:08:43,903 - app.core.excel.merger - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:08:43,903 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger完成,模板文件: templates\银豹-采购单模板.xls +2025-05-09 14:23:40,515 - app.core.excel.merger - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:23:40,515 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger完成,模板文件: templates\银豹-采购单模板.xls +2025-05-09 14:26:54,510 - app.core.excel.merger - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:26:54,511 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger完成,模板文件: templates\银豹-采购单模板.xls +2025-05-09 14:31:54,258 - app.core.excel.merger - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:31:54,259 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger完成,模板文件: templates\银豹-采购单模板.xls +2025-05-09 14:32:20,941 - app.core.excel.merger - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:32:20,942 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger完成,模板文件: templates\银豹-采购单模板.xls +2025-05-09 16:01:39,294 - app.core.excel.merger - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 16:01:39,294 - app.core.excel.merger - INFO - 初始化PurchaseOrderMerger完成,模板文件: templates\银豹-采购单模板.xls diff --git a/logs/app.core.excel.processor.active b/logs/app.core.excel.processor.active new file mode 100644 index 0000000..5367524 --- /dev/null +++ b/logs/app.core.excel.processor.active @@ -0,0 +1 @@ +Active since: 2025-05-09 16:01:38 \ No newline at end of file diff --git a/logs/app.core.excel.processor.log b/logs/app.core.excel.processor.log index 7137c3c..19d3197 100644 --- a/logs/app.core.excel.processor.log +++ b/logs/app.core.excel.processor.log @@ -5753,3 +5753,448 @@ ValueError: could not convert string to float: '2\n96' 2025-05-08 20:46:07,559 - app.core.excel.processor - INFO - 条码 6975176782460 填充:仅有赠品,采购量=0,赠品数量=9.0 2025-05-08 20:46:07,563 - app.core.excel.processor - INFO - 采购单已保存到: D:\My Documents\python\orc-order-v2\data\output\采购单_微信图片_20250508194532.xls 2025-05-08 20:46:07,564 - app.core.excel.processor - INFO - 采购单已保存到: D:\My Documents\python\orc-order-v2\data\output\采购单_微信图片_20250508194532.xls +2025-05-09 12:07:05,182 - app.core.excel.processor - INFO - 初始化ExcelProcessor +2025-05-09 12:07:54,661 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:07:54,661 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:07:54,661 - app.core.excel.processor - ERROR - 初始化ExcelProcessor失败: name 'TableHeaderFinder' is not defined +2025-05-09 12:12:42,106 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:12:42,107 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:12:42,108 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 12:13:52,582 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:13:52,582 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:13:52,584 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 12:45:35,997 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:45:35,998 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:45:35,998 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 13:39:38,182 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 13:39:38,183 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 13:39:38,183 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 14:08:43,902 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:08:43,902 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 14:08:43,902 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 14:08:43,903 - app.core.excel.processor - INFO - 开始处理Excel文件: D:/My Documents/python/orc-order-v2/data/output/高新-益选便利店销售单2025-05-09.xlsx +2025-05-09 14:08:43,986 - app.core.excel.processor - INFO - 成功读取Excel文件: D:/My Documents/python/orc-order-v2/data/output/高新-益选便利店销售单2025-05-09.xlsx, 共 21 行 +2025-05-09 14:08:43,992 - app.core.excel.processor - INFO - 找到可能的表头行: 第5行,评分: 60 +2025-05-09 14:08:43,992 - app.core.excel.processor - INFO - 识别到表头在第 5 行 +2025-05-09 14:08:44,045 - app.core.excel.processor - INFO - 使用表头行重新读取数据,共 16 行有效数据 +2025-05-09 14:08:44,045 - app.core.excel.processor - INFO - 找到精确匹配的条码列: 商品条码 +2025-05-09 14:08:44,045 - app.core.excel.processor - INFO - 使用条码列: 商品条码 +2025-05-09 14:08:44,045 - app.core.excel.processor - INFO - 找到name列: 商品名称 +2025-05-09 14:08:44,045 - app.core.excel.processor - INFO - 找到specification列: 规格 +2025-05-09 14:08:44,046 - app.core.excel.processor - INFO - 找到quantity列: 数量 +2025-05-09 14:08:44,046 - app.core.excel.processor - INFO - 找到unit列: 单位 +2025-05-09 14:08:44,046 - app.core.excel.processor - INFO - 找到price列: 单价 +2025-05-09 14:08:44,046 - app.core.excel.processor - INFO - 列名映射结果: {'barcode': '商品条码', 'name': '商品名称', 'specification': '规格', 'quantity': '数量', 'unit': '单位', 'price': '单价'} +2025-05-09 14:08:44,046 - app.core.excel.processor - INFO - 是否存在规格列: True +2025-05-09 14:08:44,047 - app.core.excel.processor - INFO - 第1行: 提取商品信息 条码=6901209255021, 名称=光明look噜渴458ml, 规格=, 数量=2.0, 单位=瓶, 单价=10.0 +2025-05-09 14:08:44,050 - app.core.excel.processor - INFO - 解析规格: 1*20 -> 包装数量=20 +2025-05-09 14:08:44,054 - app.core.excel.processor - INFO - 第2行: 提取商品信息 条码=6907992103587, 名称=伊利U形红枣杯160g, 规格=, 数量=10.0, 单位=杯, 单价=2.3 +2025-05-09 14:08:44,054 - app.core.excel.processor - INFO - 解析规格: 1*48 -> 包装数量=48 +2025-05-09 14:08:44,055 - app.core.excel.processor - INFO - 第3行: 提取商品信息 条码=6907992102726, 名称=伊利每益添100ml, 规格=, 数量=2.0, 单位=组, 单价=9.0 +2025-05-09 14:08:44,056 - app.core.excel.processor - INFO - 解析规格: 1*10组*5瓶 -> 包装数量=10 +2025-05-09 14:08:44,057 - app.core.excel.processor - INFO - 第4行: 提取商品信息 条码=6975382530176, 名称=海河草莓味牛奶220ml, 规格=, 数量=6.0, 单位=袋, 单价=3.0 +2025-05-09 14:08:44,057 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:08:44,057 - app.core.excel.processor - INFO - 第5行: 提取商品信息 条码=6975382531333, 名称=海河玫瑰荔枝味220g, 规格=, 数量=6.0, 单位=袋, 单价=3.0 +2025-05-09 14:08:44,057 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:08:44,058 - app.core.excel.processor - INFO - 第6行: 提取商品信息 条码=6975382531142, 名称=海河樱花白桃牛奶220ml, 规格=, 数量=6.0, 单位=袋, 单价=3.0 +2025-05-09 14:08:44,058 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:08:44,058 - app.core.excel.processor - INFO - 第7行: 提取商品信息 条码=6975382530350, 名称=海河可可牛奶220ml, 规格=, 数量=6.0, 单位=袋, 单价=3.0 +2025-05-09 14:08:44,060 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:08:44,106 - app.core.excel.processor - INFO - 第8行: 提取商品信息 条码=6907992106915, 名称=伊利天然牧场鲜牛奶405ml, 规格=, 数量=2.0, 单位=瓶, 单价=10.0 +2025-05-09 14:08:44,106 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:08:44,106 - app.core.excel.processor - INFO - 第9行: 提取商品信息 条码=6907992103594, 名称=伊利桶红枣酸牛奶450ml, 规格=, 数量=2.0, 单位=瓶, 单价=7.5 +2025-05-09 14:08:44,106 - app.core.excel.processor - INFO - 解析规格: 1*20 -> 包装数量=20 +2025-05-09 14:08:44,107 - app.core.excel.processor - INFO - 第10行: 提取商品信息 条码=6907992108018, 名称=伊利每益添果蔬益生菌饮品羽衣甘蓝+猕猴桃330ml, 规格=, 数量=2.0, 单位=瓶, 单价=6.3 +2025-05-09 14:08:44,107 - app.core.excel.processor - INFO - 解析规格: 1*20 -> 包装数量=20 +2025-05-09 14:08:44,108 - app.core.excel.processor - INFO - 第11行: 提取商品信息 条码=6907992108025, 名称=伊利每益添果蔬益生菌饮品红甜菜+樱桃330ml, 规格=, 数量=2.0, 单位=瓶, 单价=6.3 +2025-05-09 14:08:44,108 - app.core.excel.processor - INFO - 解析规格: 1*20 -> 包装数量=20 +2025-05-09 14:08:44,109 - app.core.excel.processor - INFO - 第12行: 提取商品信息 条码=6907992107639, 名称=伊利250ml畅轻西柚芒果+青稞爆珠风味发酵乳, 规格=, 数量=2.0, 单位=瓶, 单价=7.1 +2025-05-09 14:08:44,109 - app.core.excel.processor - INFO - 解析规格: 1*24 -> 包装数量=24 +2025-05-09 14:08:44,110 - app.core.excel.processor - INFO - 第13行: 提取商品信息 条码=6903979800999, 名称=菊乐嚼酸奶(燕麦百香果味)170g*16, 规格=, 数量=8.0, 单位=袋, 单价=3.0 +2025-05-09 14:08:44,110 - app.core.excel.processor - INFO - 解析规格: 1*16 -> 包装数量=16 +2025-05-09 14:08:44,110 - app.core.excel.processor - INFO - 第14行: 提取商品信息 条码=6907992106861, 名称=伊利-大口嚼180克, 规格=, 数量=4.0, 单位=杯, 单价=6.5 +2025-05-09 14:08:44,110 - app.core.excel.processor - INFO - 解析规格: 1*16 -> 包装数量=16 +2025-05-09 14:08:44,111 - app.core.excel.processor - INFO - 第15行: 提取商品信息 条码=6934665087653, 名称=蒙牛优益c原味340, 规格=, 数量=6.0, 单位=瓶, 单价=5.5 +2025-05-09 14:08:44,111 - app.core.excel.processor - INFO - 解析规格: 1*24 -> 包装数量=24 +2025-05-09 14:08:44,112 - app.core.excel.processor - INFO - 提取到 15 个商品信息 +2025-05-09 14:08:44,125 - app.core.excel.processor - INFO - 开始处理15 个产品信息 +2025-05-09 14:08:44,125 - app.core.excel.processor - INFO - 处理商品: 条码=6901209255021, 数量=2.0, 单价=10.0, 是否赠品=False +2025-05-09 14:08:44,126 - app.core.excel.processor - INFO - 发现正常商品:条码6901209255021, 数量=2.0, 单价=10.0 +2025-05-09 14:08:47,592 - app.core.excel.processor - INFO - 处理商品: 条码=6907992103587, 数量=10.0, 单价=2.3, 是否赠品=False +2025-05-09 14:08:47,592 - app.core.excel.processor - INFO - 发现正常商品:条码6907992103587, 数量=10.0, 单价=2.3 +2025-05-09 14:08:47,592 - app.core.excel.processor - INFO - 处理商品: 条码=6907992102726, 数量=2.0, 单价=9.0, 是否赠品=False +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 发现正常商品:条码6907992102726, 数量=2.0, 单价=9.0 +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 处理商品: 条码=6975382530176, 数量=6.0, 单价=3.0, 是否赠品=False +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 发现正常商品:条码6975382530176, 数量=6.0, 单价=3.0 +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 处理商品: 条码=6975382531333, 数量=6.0, 单价=3.0, 是否赠品=False +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 发现正常商品:条码6975382531333, 数量=6.0, 单价=3.0 +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 处理商品: 条码=6975382531142, 数量=6.0, 单价=3.0, 是否赠品=False +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 发现正常商品:条码6975382531142, 数量=6.0, 单价=3.0 +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 处理商品: 条码=6975382530350, 数量=6.0, 单价=3.0, 是否赠品=False +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 发现正常商品:条码6975382530350, 数量=6.0, 单价=3.0 +2025-05-09 14:08:47,593 - app.core.excel.processor - INFO - 处理商品: 条码=6907992106915, 数量=2.0, 单价=10.0, 是否赠品=False +2025-05-09 14:08:47,594 - app.core.excel.processor - INFO - 发现正常商品:条码6907992106915, 数量=2.0, 单价=10.0 +2025-05-09 14:08:47,594 - app.core.excel.processor - INFO - 处理商品: 条码=6907992103594, 数量=2.0, 单价=7.5, 是否赠品=False +2025-05-09 14:08:47,594 - app.core.excel.processor - INFO - 发现正常商品:条码6907992103594, 数量=2.0, 单价=7.5 +2025-05-09 14:08:47,594 - app.core.excel.processor - INFO - 处理商品: 条码=6907992108018, 数量=2.0, 单价=6.3, 是否赠品=False +2025-05-09 14:08:47,594 - app.core.excel.processor - INFO - 发现正常商品:条码6907992108018, 数量=2.0, 单价=6.3 +2025-05-09 14:08:47,594 - app.core.excel.processor - INFO - 处理商品: 条码=6907992108025, 数量=2.0, 单价=6.3, 是否赠品=False +2025-05-09 14:08:47,594 - app.core.excel.processor - INFO - 发现正常商品:条码6907992108025, 数量=2.0, 单价=6.3 +2025-05-09 14:08:47,594 - app.core.excel.processor - INFO - 处理商品: 条码=6907992107639, 数量=2.0, 单价=7.1, 是否赠品=False +2025-05-09 14:08:47,594 - app.core.excel.processor - INFO - 发现正常商品:条码6907992107639, 数量=2.0, 单价=7.1 +2025-05-09 14:08:47,595 - app.core.excel.processor - INFO - 处理商品: 条码=6903979800999, 数量=8.0, 单价=3.0, 是否赠品=False +2025-05-09 14:08:47,595 - app.core.excel.processor - INFO - 发现正常商品:条码6903979800999, 数量=8.0, 单价=3.0 +2025-05-09 14:08:47,595 - app.core.excel.processor - INFO - 处理商品: 条码=6907992106861, 数量=4.0, 单价=6.5, 是否赠品=False +2025-05-09 14:08:47,595 - app.core.excel.processor - INFO - 发现正常商品:条码6907992106861, 数量=4.0, 单价=6.5 +2025-05-09 14:08:47,595 - app.core.excel.processor - INFO - 处理商品: 条码=6934665087653, 数量=6.0, 单价=5.5, 是否赠品=False +2025-05-09 14:08:47,595 - app.core.excel.processor - INFO - 发现正常商品:条码6934665087653, 数量=6.0, 单价=5.5 +2025-05-09 14:08:47,595 - app.core.excel.processor - INFO - 分组后共15 个不同条码的商品 +2025-05-09 14:08:47,595 - app.core.excel.processor - INFO - 条码 6901209255021 处理结果:正常商品数量2.0,单价10.0,赠品数量0 +2025-05-09 14:08:47,595 - app.core.excel.processor - INFO - 条码 6907992103587 处理结果:正常商品数量10.0,单价2.3,赠品数量0 +2025-05-09 14:08:47,596 - app.core.excel.processor - INFO - 条码 6907992102726 处理结果:正常商品数量2.0,单价9.0,赠品数量0 +2025-05-09 14:08:47,596 - app.core.excel.processor - INFO - 条码 6975382530176 处理结果:正常商品数量6.0,单价3.0,赠品数量0 +2025-05-09 14:08:47,596 - app.core.excel.processor - INFO - 条码 6975382531333 处理结果:正常商品数量6.0,单价3.0,赠品数量0 +2025-05-09 14:08:47,596 - app.core.excel.processor - INFO - 条码 6975382531142 处理结果:正常商品数量6.0,单价3.0,赠品数量0 +2025-05-09 14:08:51,773 - app.core.excel.processor - INFO - 条码 6975382530350 处理结果:正常商品数量6.0,单价3.0,赠品数量0 +2025-05-09 14:08:51,773 - app.core.excel.processor - INFO - 条码 6907992106915 处理结果:正常商品数量2.0,单价10.0,赠品数量0 +2025-05-09 14:08:51,773 - app.core.excel.processor - INFO - 条码 6907992103594 处理结果:正常商品数量2.0,单价7.5,赠品数量0 +2025-05-09 14:08:51,774 - app.core.excel.processor - INFO - 条码 6907992108018 处理结果:正常商品数量2.0,单价6.3,赠品数量0 +2025-05-09 14:08:51,774 - app.core.excel.processor - INFO - 条码 6907992108025 处理结果:正常商品数量2.0,单价6.3,赠品数量0 +2025-05-09 14:08:51,774 - app.core.excel.processor - INFO - 条码 6907992107639 处理结果:正常商品数量2.0,单价7.1,赠品数量0 +2025-05-09 14:08:51,774 - app.core.excel.processor - INFO - 条码 6903979800999 处理结果:正常商品数量8.0,单价3.0,赠品数量0 +2025-05-09 14:08:51,774 - app.core.excel.processor - INFO - 条码 6907992106861 处理结果:正常商品数量4.0,单价6.5,赠品数量0 +2025-05-09 14:08:51,774 - app.core.excel.processor - INFO - 条码 6934665087653 处理结果:正常商品数量6.0,单价5.5,赠品数量0 +2025-05-09 14:08:51,778 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_高新-益选便利店销售单2025-05-09.xls +2025-05-09 14:08:51,780 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_高新-益选便利店销售单2025-05-09.xls +2025-05-09 14:23:40,514 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:23:40,514 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 14:23:40,514 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 14:23:40,516 - app.core.excel.processor - INFO - 开始处理Excel文件: D:/My Documents/python/orc-order-v2/data/output/高新-益选便利店销售单2025-05-09.xlsx +2025-05-09 14:23:40,658 - app.core.excel.processor - INFO - 成功读取Excel文件: D:/My Documents/python/orc-order-v2/data/output/高新-益选便利店销售单2025-05-09.xlsx, 共 21 行 +2025-05-09 14:23:40,668 - app.core.excel.processor - INFO - 找到可能的表头行: 第5行,评分: 60 +2025-05-09 14:23:40,669 - app.core.excel.processor - INFO - 识别到表头在第 5 行 +2025-05-09 14:23:40,841 - app.core.excel.processor - INFO - 使用表头行重新读取数据,共 16 行有效数据 +2025-05-09 14:23:40,841 - app.core.excel.processor - INFO - 找到精确匹配的条码列: 商品条码 +2025-05-09 14:23:40,841 - app.core.excel.processor - INFO - 使用条码列: 商品条码 +2025-05-09 14:23:40,842 - app.core.excel.processor - INFO - 找到name列: 商品名称 +2025-05-09 14:23:40,842 - app.core.excel.processor - INFO - 找到specification列: 规格 +2025-05-09 14:23:40,842 - app.core.excel.processor - INFO - 找到quantity列: 数量 +2025-05-09 14:23:40,843 - app.core.excel.processor - INFO - 找到unit列: 单位 +2025-05-09 14:23:40,843 - app.core.excel.processor - INFO - 找到price列: 单价 +2025-05-09 14:23:40,843 - app.core.excel.processor - INFO - 列名映射结果: {'barcode': '商品条码', 'name': '商品名称', 'specification': '规格', 'quantity': '数量', 'unit': '单位', 'price': '单价'} +2025-05-09 14:23:40,843 - app.core.excel.processor - INFO - 是否存在规格列: True +2025-05-09 14:23:40,845 - app.core.excel.processor - INFO - 第1行: 提取商品信息 条码=6901209255021, 名称=光明look噜渴458ml, 规格=, 数量=2.0, 单位=瓶, 单价=10.0 +2025-05-09 14:23:40,851 - app.core.excel.processor - INFO - 解析规格: 1*20 -> 包装数量=20 +2025-05-09 14:23:40,877 - app.core.excel.processor - INFO - 第2行: 提取商品信息 条码=6907992103587, 名称=伊利U形红枣杯160g, 规格=, 数量=10.0, 单位=杯, 单价=2.3 +2025-05-09 14:23:40,877 - app.core.excel.processor - INFO - 解析规格: 1*48 -> 包装数量=48 +2025-05-09 14:23:40,879 - app.core.excel.processor - INFO - 第3行: 提取商品信息 条码=6907992102726, 名称=伊利每益添100ml, 规格=, 数量=2.0, 单位=组, 单价=9.0 +2025-05-09 14:23:40,879 - app.core.excel.processor - INFO - 解析规格: 1*10组*5瓶 -> 包装数量=10 +2025-05-09 14:23:40,880 - app.core.excel.processor - INFO - 第4行: 提取商品信息 条码=6975382530176, 名称=海河草莓味牛奶220ml, 规格=, 数量=6.0, 单位=袋, 单价=3.0 +2025-05-09 14:23:40,888 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:23:40,889 - app.core.excel.processor - INFO - 第5行: 提取商品信息 条码=6975382531333, 名称=海河玫瑰荔枝味220g, 规格=, 数量=6.0, 单位=袋, 单价=3.0 +2025-05-09 14:23:40,890 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:23:40,891 - app.core.excel.processor - INFO - 第6行: 提取商品信息 条码=6975382531142, 名称=海河樱花白桃牛奶220ml, 规格=, 数量=6.0, 单位=袋, 单价=3.0 +2025-05-09 14:23:40,896 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:23:40,897 - app.core.excel.processor - INFO - 第7行: 提取商品信息 条码=6975382530350, 名称=海河可可牛奶220ml, 规格=, 数量=6.0, 单位=袋, 单价=3.0 +2025-05-09 14:23:40,897 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:23:40,898 - app.core.excel.processor - INFO - 第8行: 提取商品信息 条码=6907992106915, 名称=伊利天然牧场鲜牛奶405ml, 规格=, 数量=2.0, 单位=瓶, 单价=10.0 +2025-05-09 14:23:40,898 - app.core.excel.processor - INFO - 解析规格: 1*12 -> 包装数量=12 +2025-05-09 14:23:40,899 - app.core.excel.processor - INFO - 第9行: 提取商品信息 条码=6907992103594, 名称=伊利桶红枣酸牛奶450ml, 规格=, 数量=2.0, 单位=瓶, 单价=7.5 +2025-05-09 14:23:40,899 - app.core.excel.processor - INFO - 解析规格: 1*20 -> 包装数量=20 +2025-05-09 14:23:40,900 - app.core.excel.processor - INFO - 第10行: 提取商品信息 条码=6907992108018, 名称=伊利每益添果蔬益生菌饮品羽衣甘蓝+猕猴桃330ml, 规格=, 数量=2.0, 单位=瓶, 单价=6.3 +2025-05-09 14:23:40,900 - app.core.excel.processor - INFO - 解析规格: 1*20 -> 包装数量=20 +2025-05-09 14:23:41,461 - app.core.excel.processor - INFO - 第11行: 提取商品信息 条码=6907992108025, 名称=伊利每益添果蔬益生菌饮品红甜菜+樱桃330ml, 规格=, 数量=2.0, 单位=瓶, 单价=6.3 +2025-05-09 14:23:41,461 - app.core.excel.processor - INFO - 解析规格: 1*20 -> 包装数量=20 +2025-05-09 14:23:41,462 - app.core.excel.processor - INFO - 第12行: 提取商品信息 条码=6907992107639, 名称=伊利250ml畅轻西柚芒果+青稞爆珠风味发酵乳, 规格=, 数量=2.0, 单位=瓶, 单价=7.1 +2025-05-09 14:23:41,462 - app.core.excel.processor - INFO - 解析规格: 1*24 -> 包装数量=24 +2025-05-09 14:23:41,463 - app.core.excel.processor - INFO - 第13行: 提取商品信息 条码=6903979800999, 名称=菊乐嚼酸奶(燕麦百香果味)170g*16, 规格=, 数量=8.0, 单位=袋, 单价=3.0 +2025-05-09 14:23:41,463 - app.core.excel.processor - INFO - 解析规格: 1*16 -> 包装数量=16 +2025-05-09 14:23:41,464 - app.core.excel.processor - INFO - 第14行: 提取商品信息 条码=6907992106861, 名称=伊利-大口嚼180克, 规格=, 数量=4.0, 单位=杯, 单价=6.5 +2025-05-09 14:23:41,464 - app.core.excel.processor - INFO - 解析规格: 1*16 -> 包装数量=16 +2025-05-09 14:23:41,466 - app.core.excel.processor - INFO - 第15行: 提取商品信息 条码=6934665087653, 名称=蒙牛优益c原味340, 规格=, 数量=6.0, 单位=瓶, 单价=5.5 +2025-05-09 14:23:41,466 - app.core.excel.processor - INFO - 解析规格: 1*24 -> 包装数量=24 +2025-05-09 14:23:41,467 - app.core.excel.processor - INFO - 提取到 15 个商品信息 +2025-05-09 14:23:41,480 - app.core.excel.processor - INFO - 开始处理15 个产品信息 +2025-05-09 14:23:41,480 - app.core.excel.processor - INFO - 处理商品: 条码=6901209255021, 数量=2.0, 单价=10.0, 是否赠品=False +2025-05-09 14:23:41,481 - app.core.excel.processor - INFO - 发现正常商品:条码6901209255021, 数量=2.0, 单价=10.0 +2025-05-09 14:23:41,481 - app.core.excel.processor - INFO - 处理商品: 条码=6907992103587, 数量=10.0, 单价=2.3, 是否赠品=False +2025-05-09 14:23:41,481 - app.core.excel.processor - INFO - 发现正常商品:条码6907992103587, 数量=10.0, 单价=2.3 +2025-05-09 14:23:41,481 - app.core.excel.processor - INFO - 处理商品: 条码=6907992102726, 数量=2.0, 单价=9.0, 是否赠品=False +2025-05-09 14:23:41,481 - app.core.excel.processor - INFO - 发现正常商品:条码6907992102726, 数量=2.0, 单价=9.0 +2025-05-09 14:23:41,481 - app.core.excel.processor - INFO - 处理商品: 条码=6975382530176, 数量=6.0, 单价=3.0, 是否赠品=False +2025-05-09 14:23:41,481 - app.core.excel.processor - INFO - 发现正常商品:条码6975382530176, 数量=6.0, 单价=3.0 +2025-05-09 14:23:41,481 - app.core.excel.processor - INFO - 处理商品: 条码=6975382531333, 数量=6.0, 单价=3.0, 是否赠品=False +2025-05-09 14:23:41,482 - app.core.excel.processor - INFO - 发现正常商品:条码6975382531333, 数量=6.0, 单价=3.0 +2025-05-09 14:23:41,482 - app.core.excel.processor - INFO - 处理商品: 条码=6975382531142, 数量=6.0, 单价=3.0, 是否赠品=False +2025-05-09 14:23:41,482 - app.core.excel.processor - INFO - 发现正常商品:条码6975382531142, 数量=6.0, 单价=3.0 +2025-05-09 14:23:45,553 - app.core.excel.processor - INFO - 处理商品: 条码=6975382530350, 数量=6.0, 单价=3.0, 是否赠品=False +2025-05-09 14:23:45,553 - app.core.excel.processor - INFO - 发现正常商品:条码6975382530350, 数量=6.0, 单价=3.0 +2025-05-09 14:23:45,553 - app.core.excel.processor - INFO - 处理商品: 条码=6907992106915, 数量=2.0, 单价=10.0, 是否赠品=False +2025-05-09 14:23:45,553 - app.core.excel.processor - INFO - 发现正常商品:条码6907992106915, 数量=2.0, 单价=10.0 +2025-05-09 14:23:45,553 - app.core.excel.processor - INFO - 处理商品: 条码=6907992103594, 数量=2.0, 单价=7.5, 是否赠品=False +2025-05-09 14:23:45,553 - app.core.excel.processor - INFO - 发现正常商品:条码6907992103594, 数量=2.0, 单价=7.5 +2025-05-09 14:23:45,553 - app.core.excel.processor - INFO - 处理商品: 条码=6907992108018, 数量=2.0, 单价=6.3, 是否赠品=False +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 发现正常商品:条码6907992108018, 数量=2.0, 单价=6.3 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 处理商品: 条码=6907992108025, 数量=2.0, 单价=6.3, 是否赠品=False +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 发现正常商品:条码6907992108025, 数量=2.0, 单价=6.3 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 处理商品: 条码=6907992107639, 数量=2.0, 单价=7.1, 是否赠品=False +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 发现正常商品:条码6907992107639, 数量=2.0, 单价=7.1 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 处理商品: 条码=6903979800999, 数量=8.0, 单价=3.0, 是否赠品=False +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 发现正常商品:条码6903979800999, 数量=8.0, 单价=3.0 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 处理商品: 条码=6907992106861, 数量=4.0, 单价=6.5, 是否赠品=False +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 发现正常商品:条码6907992106861, 数量=4.0, 单价=6.5 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 处理商品: 条码=6934665087653, 数量=6.0, 单价=5.5, 是否赠品=False +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 发现正常商品:条码6934665087653, 数量=6.0, 单价=5.5 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 分组后共15 个不同条码的商品 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 条码 6901209255021 处理结果:正常商品数量2.0,单价10.0,赠品数量0 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 条码 6907992103587 处理结果:正常商品数量10.0,单价2.3,赠品数量0 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 条码 6907992102726 处理结果:正常商品数量2.0,单价9.0,赠品数量0 +2025-05-09 14:23:45,554 - app.core.excel.processor - INFO - 条码 6975382530176 处理结果:正常商品数量6.0,单价3.0,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6975382531333 处理结果:正常商品数量6.0,单价3.0,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6975382531142 处理结果:正常商品数量6.0,单价3.0,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6975382530350 处理结果:正常商品数量6.0,单价3.0,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6907992106915 处理结果:正常商品数量2.0,单价10.0,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6907992103594 处理结果:正常商品数量2.0,单价7.5,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6907992108018 处理结果:正常商品数量2.0,单价6.3,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6907992108025 处理结果:正常商品数量2.0,单价6.3,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6907992107639 处理结果:正常商品数量2.0,单价7.1,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6903979800999 处理结果:正常商品数量8.0,单价3.0,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6907992106861 处理结果:正常商品数量4.0,单价6.5,赠品数量0 +2025-05-09 14:23:45,555 - app.core.excel.processor - INFO - 条码 6934665087653 处理结果:正常商品数量6.0,单价5.5,赠品数量0 +2025-05-09 14:23:49,343 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_高新-益选便利店销售单2025-05-09.xls +2025-05-09 14:23:49,345 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_高新-益选便利店销售单2025-05-09.xls +2025-05-09 14:26:54,509 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:26:54,509 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 14:26:54,509 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 14:31:54,257 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:31:54,258 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 14:31:54,258 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 14:31:54,259 - app.core.excel.processor - INFO - 开始处理Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250509142624.xlsx +2025-05-09 14:31:54,289 - app.core.excel.processor - INFO - 成功读取Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250509142624.xlsx, 共 16 行 +2025-05-09 14:31:54,293 - app.core.excel.processor - INFO - 找到可能的表头行: 第1行,评分: 45 +2025-05-09 14:31:54,294 - app.core.excel.processor - INFO - 识别到表头在第 1 行 +2025-05-09 14:31:54,326 - app.core.excel.processor - INFO - 使用表头行重新读取数据,共 15 行有效数据 +2025-05-09 14:31:54,327 - app.core.excel.processor - INFO - 找到精确匹配的条码列: 商品条码 +2025-05-09 14:31:54,327 - app.core.excel.processor - INFO - 使用条码列: 商品条码 +2025-05-09 14:31:54,327 - app.core.excel.processor - INFO - 找到name列(部分匹配): 商品条码 +2025-05-09 14:31:54,327 - app.core.excel.processor - INFO - 找到specification列: 规格 +2025-05-09 14:31:54,327 - app.core.excel.processor - INFO - 找到quantity列: 数量 +2025-05-09 14:31:54,327 - app.core.excel.processor - INFO - 找到unit列: 单位 +2025-05-09 14:31:54,327 - app.core.excel.processor - INFO - 找到price列: 单价 +2025-05-09 14:31:54,328 - app.core.excel.processor - INFO - 列名映射结果: {'barcode': '商品条码', 'name': '商品条码', 'specification': '规格', 'quantity': '数量', 'unit': '单位', 'price': '单价'} +2025-05-09 14:31:54,328 - app.core.excel.processor - INFO - 是否存在规格列: True +2025-05-09 14:31:54,329 - app.core.excel.processor - INFO - 第1行: 提取商品信息 条码=6907992508344, 名称=6907992508344.0, 规格=, 数量=1.0, 单位=件, 单价=52.0 +2025-05-09 14:31:54,334 - app.core.excel.processor - INFO - 第2行: 提取商品信息 条码=6903979000979, 名称=6903979000979.0, 规格=, 数量=3.0, 单位=件, 单价=50.0 +2025-05-09 14:31:54,335 - app.core.excel.processor - INFO - 第3行: 提取商品信息 条码=6923644283582, 名称=6923644283582.0, 规格=, 数量=1.0, 单位=件, 单价=30.0 +2025-05-09 14:31:54,338 - app.core.excel.processor - INFO - 第4行: 提取商品信息 条码=6923644268909, 名称=6923644268909.0, 规格=, 数量=2.0, 单位=件, 单价=30.0 +2025-05-09 14:31:54,340 - app.core.excel.processor - INFO - 第5行: 提取商品信息 条码=6923644268930, 名称=6923644268930.0, 规格=, 数量=2.0, 单位=件, 单价=30.0 +2025-05-09 14:31:54,341 - app.core.excel.processor - INFO - 第6行: 提取商品信息 条码=6923644268916, 名称=6923644268916.0, 规格=, 数量=2.0, 单位=件, 单价=30.0 +2025-05-09 14:31:54,342 - app.core.excel.processor - INFO - 第7行: 提取商品信息 条码=6923644266318, 名称=6923644266318.0, 规格=, 数量=4.0, 单位=件, 单价=45.0 +2025-05-09 14:31:54,432 - app.core.excel.processor - INFO - 第8行: 提取商品信息 条码=6920584471055, 名称=6920584471055.0, 规格=, 数量=2.0, 单位=件, 单价=50.0 +2025-05-09 14:31:54,433 - app.core.excel.processor - INFO - 第9行: 提取商品信息 条码=6925861571159, 名称=6925861571159.0, 规格=, 数量=2.0, 单位=件, 单价=65.0 +2025-05-09 14:31:54,434 - app.core.excel.processor - INFO - 第10行: 提取商品信息 条码=6925861571466, 名称=6925861571466.0, 规格=, 数量=1.0, 单位=件, 单价=45.0 +2025-05-09 14:31:54,434 - app.core.excel.processor - INFO - 第11行: 提取商品信息 条码=6923644210151, 名称=6923644210151.0, 规格=, 数量=3.0, 单位=件, 单价=55.0 +2025-05-09 14:31:54,435 - app.core.excel.processor - INFO - 第12行: 提取商品信息 条码=6907992501819, 名称=6907992501819.0, 规格=, 数量=3.0, 单位=件, 单价=63.0 +2025-05-09 14:31:54,435 - app.core.excel.processor - INFO - 第13行: 提取商品信息 条码=6907992502052, 名称=6907992502052.0, 规格=, 数量=3.0, 单位=件, 单价=54.0 +2025-05-09 14:31:54,436 - app.core.excel.processor - INFO - 第14行: 提取商品信息 条码=6907992507385, 名称=6907992507385.0, 规格=, 数量=2.0, 单位=件, 单价=42.0 +2025-05-09 14:31:54,436 - app.core.excel.processor - INFO - 提取到 14 个商品信息 +2025-05-09 14:31:54,446 - app.core.excel.processor - INFO - 开始处理14 个产品信息 +2025-05-09 14:31:54,447 - app.core.excel.processor - INFO - 处理商品: 条码=6907992508344, 数量=12.0, 单价=4.333333333333333, 是否赠品=False +2025-05-09 14:31:54,448 - app.core.excel.processor - INFO - 发现正常商品:条码6907992508344, 数量=12.0, 单价=4.333333333333333 +2025-05-09 14:31:54,448 - app.core.excel.processor - INFO - 处理商品: 条码=6903979000979, 数量=72.0, 单价=2.0833333333333335, 是否赠品=False +2025-05-09 14:31:57,685 - app.core.excel.processor - INFO - 发现正常商品:条码6903979000979, 数量=72.0, 单价=2.0833333333333335 +2025-05-09 14:31:57,685 - app.core.excel.processor - INFO - 处理商品: 条码=6923644283575, 数量=12.0, 单价=2.5, 是否赠品=False +2025-05-09 14:31:57,685 - app.core.excel.processor - INFO - 发现正常商品:条码6923644283575, 数量=12.0, 单价=2.5 +2025-05-09 14:31:57,685 - app.core.excel.processor - INFO - 处理商品: 条码=6923644268909, 数量=24.0, 单价=2.5, 是否赠品=False +2025-05-09 14:31:57,685 - app.core.excel.processor - INFO - 发现正常商品:条码6923644268909, 数量=24.0, 单价=2.5 +2025-05-09 14:31:57,686 - app.core.excel.processor - INFO - 处理商品: 条码=6923644268497, 数量=24.0, 单价=2.5, 是否赠品=False +2025-05-09 14:31:57,686 - app.core.excel.processor - INFO - 发现正常商品:条码6923644268497, 数量=24.0, 单价=2.5 +2025-05-09 14:31:57,686 - app.core.excel.processor - INFO - 处理商品: 条码=6923644268503, 数量=24.0, 单价=2.5, 是否赠品=False +2025-05-09 14:31:57,686 - app.core.excel.processor - INFO - 发现正常商品:条码6923644268503, 数量=24.0, 单价=2.5 +2025-05-09 14:31:57,686 - app.core.excel.processor - INFO - 处理商品: 条码=6923644266318, 数量=48.0, 单价=3.75, 是否赠品=False +2025-05-09 14:31:57,686 - app.core.excel.processor - INFO - 发现正常商品:条码6923644266318, 数量=48.0, 单价=3.75 +2025-05-09 14:31:57,687 - app.core.excel.processor - INFO - 处理商品: 条码=6920584471017, 数量=24.0, 单价=4.166666666666667, 是否赠品=False +2025-05-09 14:31:57,687 - app.core.excel.processor - INFO - 发现正常商品:条码6920584471017, 数量=24.0, 单价=4.166666666666667 +2025-05-09 14:31:57,687 - app.core.excel.processor - INFO - 处理商品: 条码=69021824, 数量=72.0, 单价=1.8055555555555556, 是否赠品=False +2025-05-09 14:31:57,687 - app.core.excel.processor - INFO - 发现正常商品:条码69021824, 数量=72.0, 单价=1.8055555555555556 +2025-05-09 14:31:57,687 - app.core.excel.processor - INFO - 处理商品: 条码=6925861571466, 数量=12.0, 单价=3.75, 是否赠品=False +2025-05-09 14:31:57,687 - app.core.excel.processor - INFO - 发现正常商品:条码6925861571466, 数量=12.0, 单价=3.75 +2025-05-09 14:31:57,687 - app.core.excel.processor - INFO - 处理商品: 条码=6923644223458, 数量=72.0, 单价=2.2916666666666665, 是否赠品=False +2025-05-09 14:31:57,687 - app.core.excel.processor - INFO - 发现正常商品:条码6923644223458, 数量=72.0, 单价=2.2916666666666665 +2025-05-09 14:31:57,688 - app.core.excel.processor - INFO - 处理商品: 条码=6907992500133, 数量=72.0, 单价=2.625, 是否赠品=False +2025-05-09 14:31:57,688 - app.core.excel.processor - INFO - 发现正常商品:条码6907992500133, 数量=72.0, 单价=2.625 +2025-05-09 14:31:57,688 - app.core.excel.processor - INFO - 处理商品: 条码=6907992502052, 数量=72.0, 单价=2.25, 是否赠品=False +2025-05-09 14:31:57,688 - app.core.excel.processor - INFO - 发现正常商品:条码6907992502052, 数量=72.0, 单价=2.25 +2025-05-09 14:31:57,688 - app.core.excel.processor - INFO - 处理商品: 条码=6907992507385, 数量=24.0, 单价=3.5, 是否赠品=False +2025-05-09 14:31:57,688 - app.core.excel.processor - INFO - 发现正常商品:条码6907992507385, 数量=24.0, 单价=3.5 +2025-05-09 14:31:57,688 - app.core.excel.processor - INFO - 分组后共14 个不同条码的商品 +2025-05-09 14:31:57,688 - app.core.excel.processor - INFO - 条码 6907992508344 处理结果:正常商品数量12.0,单价4.333333333333333,赠品数量0 +2025-05-09 14:31:57,688 - app.core.excel.processor - INFO - 条码 6903979000979 处理结果:正常商品数量72.0,单价2.0833333333333335,赠品数量0 +2025-05-09 14:31:57,689 - app.core.excel.processor - INFO - 条码 6923644283575 处理结果:正常商品数量12.0,单价2.5,赠品数量0 +2025-05-09 14:31:57,689 - app.core.excel.processor - INFO - 条码 6923644268909 处理结果:正常商品数量24.0,单价2.5,赠品数量0 +2025-05-09 14:31:57,689 - app.core.excel.processor - INFO - 条码 6923644268497 处理结果:正常商品数量24.0,单价2.5,赠品数量0 +2025-05-09 14:31:57,689 - app.core.excel.processor - INFO - 条码 6923644268503 处理结果:正常商品数量24.0,单价2.5,赠品数量0 +2025-05-09 14:31:57,689 - app.core.excel.processor - INFO - 条码 6923644266318 处理结果:正常商品数量48.0,单价3.75,赠品数量0 +2025-05-09 14:32:02,676 - app.core.excel.processor - INFO - 条码 6920584471017 处理结果:正常商品数量24.0,单价4.166666666666667,赠品数量0 +2025-05-09 14:32:02,677 - app.core.excel.processor - INFO - 条码 69021824 处理结果:正常商品数量72.0,单价1.8055555555555556,赠品数量0 +2025-05-09 14:32:02,677 - app.core.excel.processor - INFO - 条码 6925861571466 处理结果:正常商品数量12.0,单价3.75,赠品数量0 +2025-05-09 14:32:02,677 - app.core.excel.processor - INFO - 条码 6923644223458 处理结果:正常商品数量72.0,单价2.2916666666666665,赠品数量0 +2025-05-09 14:32:02,677 - app.core.excel.processor - INFO - 条码 6907992500133 处理结果:正常商品数量72.0,单价2.625,赠品数量0 +2025-05-09 14:32:02,677 - app.core.excel.processor - INFO - 条码 6907992502052 处理结果:正常商品数量72.0,单价2.25,赠品数量0 +2025-05-09 14:32:02,677 - app.core.excel.processor - INFO - 条码 6907992507385 处理结果:正常商品数量24.0,单价3.5,赠品数量0 +2025-05-09 14:32:02,682 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_微信图片_20250509142624.xls +2025-05-09 14:32:02,684 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_微信图片_20250509142624.xls +2025-05-09 14:32:20,938 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:32:20,939 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 14:32:20,940 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 14:32:20,954 - app.core.excel.processor - INFO - 开始处理Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250509142700.xlsx +2025-05-09 14:32:21,010 - app.core.excel.processor - INFO - 成功读取Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250509142700.xlsx, 共 13 行 +2025-05-09 14:32:21,017 - app.core.excel.processor - INFO - 找到可能的表头行: 第1行,评分: 45 +2025-05-09 14:32:21,018 - app.core.excel.processor - INFO - 识别到表头在第 1 行 +2025-05-09 14:32:21,057 - app.core.excel.processor - INFO - 使用表头行重新读取数据,共 12 行有效数据 +2025-05-09 14:32:21,057 - app.core.excel.processor - INFO - 找到精确匹配的条码列: 商品条码 +2025-05-09 14:32:21,057 - app.core.excel.processor - INFO - 使用条码列: 商品条码 +2025-05-09 14:32:21,058 - app.core.excel.processor - INFO - 找到name列(部分匹配): 商品条码 +2025-05-09 14:32:21,058 - app.core.excel.processor - INFO - 找到specification列: 规格 +2025-05-09 14:32:21,066 - app.core.excel.processor - INFO - 找到quantity列: 数量 +2025-05-09 14:32:21,066 - app.core.excel.processor - INFO - 找到unit列: 单位 +2025-05-09 14:32:21,066 - app.core.excel.processor - INFO - 找到price列: 单价 +2025-05-09 14:32:21,066 - app.core.excel.processor - INFO - 列名映射结果: {'barcode': '商品条码', 'name': '商品条码', 'specification': '规格', 'quantity': '数量', 'unit': '单位', 'price': '单价'} +2025-05-09 14:32:21,066 - app.core.excel.processor - INFO - 是否存在规格列: True +2025-05-09 14:32:21,068 - app.core.excel.processor - INFO - 第1行: 提取商品信息 条码=6922456805012, 名称=6922456805012.0, 规格=, 数量=1.0, 单位=件, 单价=33.0 +2025-05-09 14:32:21,068 - app.core.excel.processor - INFO - 解析规格: 500ml*15 -> 包装数量=15 +2025-05-09 14:32:21,073 - app.core.excel.processor - INFO - 第2行: 提取商品信息 条码=6922456892067, 名称=6922456892067.0, 规格=, 数量=2.0, 单位=件, 单价=42.0 +2025-05-09 14:32:21,075 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,078 - app.core.excel.processor - INFO - 第3行: 提取商品信息 条码=6922456891985, 名称=6922456891985.0, 规格=, 数量=1.0, 单位=件, 单价=42.0 +2025-05-09 14:32:21,078 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,082 - app.core.excel.processor - INFO - 第4行: 提取商品信息 条码=6922456889944, 名称=6922456889944.0, 规格=, 数量=1.0, 单位=件, 单价=42.0 +2025-05-09 14:32:21,082 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,083 - app.core.excel.processor - INFO - 第5行: 提取商品信息 条码=6922456896362, 名称=6922456896362.0, 规格=, 数量=1.0, 单位=件, 单价=42.0 +2025-05-09 14:32:21,083 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,086 - app.core.excel.processor - INFO - 第6行: 提取商品信息 条码=6922456889920, 名称=6922456889920.0, 规格=, 数量=1.0, 单位=件, 单价=42.0 +2025-05-09 14:32:21,086 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,087 - app.core.excel.processor - INFO - 第7行: 提取商品信息 条码=6922456843571, 名称=6922456843571.0, 规格=, 数量=1.0, 单位=件, 单价=42.0 +2025-05-09 14:32:21,088 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,215 - app.core.excel.processor - INFO - 第8行: 提取商品信息 条码=6922456840259, 名称=6922456840259.0, 规格=, 数量=1.0, 单位=件, 单价=42.0 +2025-05-09 14:32:21,215 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,216 - app.core.excel.processor - INFO - 第9行: 提取商品信息 条码=6922456889982, 名称=6922456889982.0, 规格=, 数量=1.0, 单位=件, 单价=42.0 +2025-05-09 14:32:21,216 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,217 - app.core.excel.processor - INFO - 第10行: 提取商品信息 条码=6922456896362, 名称=6922456896362.0, 规格=, 数量=1.0, 单位=件, 单价=0 +2025-05-09 14:32:21,218 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,218 - app.core.excel.processor - INFO - 第11行: 提取商品信息 条码=6922456896362, 名称=6922456896362.0, 规格=, 数量=1.0, 单位=瓶, 单价=0 +2025-05-09 14:32:21,218 - app.core.excel.processor - INFO - 解析规格: 1L*12 -> 包装数量=12 +2025-05-09 14:32:21,219 - app.core.excel.processor - INFO - 提取到 11 个商品信息 +2025-05-09 14:32:21,230 - app.core.excel.processor - INFO - 开始处理11 个产品信息 +2025-05-09 14:32:21,231 - app.core.excel.processor - INFO - 处理商品: 条码=6922456805012, 数量=15.0, 单价=2.2, 是否赠品=False +2025-05-09 14:32:21,231 - app.core.excel.processor - INFO - 发现正常商品:条码6922456805012, 数量=15.0, 单价=2.2 +2025-05-09 14:32:21,231 - app.core.excel.processor - INFO - 处理商品: 条码=6922456892067, 数量=24.0, 单价=3.5, 是否赠品=False +2025-05-09 14:32:21,231 - app.core.excel.processor - INFO - 发现正常商品:条码6922456892067, 数量=24.0, 单价=3.5 +2025-05-09 14:32:21,231 - app.core.excel.processor - INFO - 处理商品: 条码=6922456891985, 数量=12.0, 单价=3.5, 是否赠品=False +2025-05-09 14:32:21,232 - app.core.excel.processor - INFO - 发现正常商品:条码6922456891985, 数量=12.0, 单价=3.5 +2025-05-09 14:32:21,232 - app.core.excel.processor - INFO - 处理商品: 条码=6922456889944, 数量=12.0, 单价=3.5, 是否赠品=False +2025-05-09 14:32:21,232 - app.core.excel.processor - INFO - 发现正常商品:条码6922456889944, 数量=12.0, 单价=3.5 +2025-05-09 14:32:21,232 - app.core.excel.processor - INFO - 处理商品: 条码=6922456896362, 数量=12.0, 单价=3.5, 是否赠品=False +2025-05-09 14:32:21,232 - app.core.excel.processor - INFO - 发现正常商品:条码6922456896362, 数量=12.0, 单价=3.5 +2025-05-09 14:32:21,232 - app.core.excel.processor - INFO - 处理商品: 条码=6922456889920, 数量=12.0, 单价=3.5, 是否赠品=False +2025-05-09 14:32:21,232 - app.core.excel.processor - INFO - 发现正常商品:条码6922456889920, 数量=12.0, 单价=3.5 +2025-05-09 14:32:21,233 - app.core.excel.processor - INFO - 处理商品: 条码=6922456843571, 数量=12.0, 单价=3.5, 是否赠品=False +2025-05-09 14:32:21,233 - app.core.excel.processor - INFO - 发现正常商品:条码6922456843571, 数量=12.0, 单价=3.5 +2025-05-09 14:32:21,233 - app.core.excel.processor - INFO - 处理商品: 条码=6922456840259, 数量=12.0, 单价=3.5, 是否赠品=False +2025-05-09 14:32:24,203 - app.core.excel.processor - INFO - 发现正常商品:条码6922456840259, 数量=12.0, 单价=3.5 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 处理商品: 条码=6922456889982, 数量=12.0, 单价=3.5, 是否赠品=False +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 发现正常商品:条码6922456889982, 数量=12.0, 单价=3.5 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 处理商品: 条码=6922456896362, 数量=12.0, 单价=0, 是否赠品=True +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 发现赠品:条码6922456896362, 数量=12.0 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 处理商品: 条码=6922456896362, 数量=1.0, 单价=0, 是否赠品=True +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 发现赠品:条码6922456896362, 数量=1.0 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 分组后共9 个不同条码的商品 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 条码 6922456805012 处理结果:正常商品数量15.0,单价2.2,赠品数量0 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 条码 6922456892067 处理结果:正常商品数量24.0,单价3.5,赠品数量0 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 条码 6922456891985 处理结果:正常商品数量12.0,单价3.5,赠品数量0 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 条码 6922456889944 处理结果:正常商品数量12.0,单价3.5,赠品数量0 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 条码 6922456896362 处理结果:正常商品数量12.0,单价3.5,赠品数量13.0 +2025-05-09 14:32:24,204 - app.core.excel.processor - INFO - 条码 6922456889920 处理结果:正常商品数量12.0,单价3.5,赠品数量0 +2025-05-09 14:32:24,205 - app.core.excel.processor - INFO - 条码 6922456843571 处理结果:正常商品数量12.0,单价3.5,赠品数量0 +2025-05-09 14:32:24,205 - app.core.excel.processor - INFO - 条码 6922456840259 处理结果:正常商品数量12.0,单价3.5,赠品数量0 +2025-05-09 14:32:24,205 - app.core.excel.processor - INFO - 条码 6922456889982 处理结果:正常商品数量12.0,单价3.5,赠品数量0 +2025-05-09 14:32:24,205 - app.core.excel.processor - INFO - 条码 6922456896362 填充:采购量=12.0,赠品数量13.0 +2025-05-09 14:32:24,299 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_微信图片_20250509142700.xls +2025-05-09 14:32:24,300 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_微信图片_20250509142700.xls +2025-05-09 16:01:39,292 - app.core.excel.processor - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 16:01:39,292 - app.core.excel.processor - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 16:01:39,293 - app.core.excel.processor - INFO - 初始化ExcelProcessor完成,模板文件: templates/银豹-采购单模板.xls +2025-05-09 16:01:39,295 - app.core.excel.processor - INFO - 开始处理Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250509142624.xlsx +2025-05-09 16:01:39,349 - app.core.excel.processor - INFO - 成功读取Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250509142624.xlsx, 共 16 行 +2025-05-09 16:01:39,363 - app.core.excel.processor - INFO - 找到可能的表头行: 第1行,评分: 45 +2025-05-09 16:01:39,363 - app.core.excel.processor - INFO - 识别到表头在第 1 行 +2025-05-09 16:01:39,469 - app.core.excel.processor - INFO - 使用表头行重新读取数据,共 15 行有效数据 +2025-05-09 16:01:39,469 - app.core.excel.processor - INFO - 找到精确匹配的条码列: 商品条码 +2025-05-09 16:01:39,469 - app.core.excel.processor - INFO - 使用条码列: 商品条码 +2025-05-09 16:01:39,469 - app.core.excel.processor - INFO - 找到name列(部分匹配): 商品条码 +2025-05-09 16:01:39,469 - app.core.excel.processor - INFO - 找到specification列: 规格 +2025-05-09 16:01:39,469 - app.core.excel.processor - INFO - 找到quantity列: 数量 +2025-05-09 16:01:39,470 - app.core.excel.processor - INFO - 找到unit列: 单位 +2025-05-09 16:01:39,470 - app.core.excel.processor - INFO - 找到price列: 单价 +2025-05-09 16:01:39,470 - app.core.excel.processor - INFO - 列名映射结果: {'barcode': '商品条码', 'name': '商品条码', 'specification': '规格', 'quantity': '数量', 'unit': '单位', 'price': '单价'} +2025-05-09 16:01:39,470 - app.core.excel.processor - INFO - 是否存在规格列: True +2025-05-09 16:01:39,474 - app.core.excel.processor - INFO - 第1行: 提取商品信息 条码=6907992508344, 名称=6907992508344.0, 规格=, 数量=1.0, 单位=件, 单价=52.0 +2025-05-09 16:01:39,481 - app.core.excel.processor - INFO - 第2行: 提取商品信息 条码=6903979000979, 名称=6903979000979.0, 规格=, 数量=3.0, 单位=件, 单价=50.0 +2025-05-09 16:01:39,481 - app.core.excel.processor - INFO - 第3行: 提取商品信息 条码=6923644283582, 名称=6923644283582.0, 规格=, 数量=1.0, 单位=件, 单价=30.0 +2025-05-09 16:01:39,482 - app.core.excel.processor - INFO - 第4行: 提取商品信息 条码=6923644268909, 名称=6923644268909.0, 规格=, 数量=2.0, 单位=件, 单价=30.0 +2025-05-09 16:01:39,483 - app.core.excel.processor - INFO - 第5行: 提取商品信息 条码=6923644268930, 名称=6923644268930.0, 规格=, 数量=2.0, 单位=件, 单价=30.0 +2025-05-09 16:01:39,484 - app.core.excel.processor - INFO - 第6行: 提取商品信息 条码=6923644268916, 名称=6923644268916.0, 规格=, 数量=2.0, 单位=件, 单价=30.0 +2025-05-09 16:01:39,485 - app.core.excel.processor - INFO - 第7行: 提取商品信息 条码=6923644266318, 名称=6923644266318.0, 规格=, 数量=4.0, 单位=件, 单价=45.0 +2025-05-09 16:01:39,487 - app.core.excel.processor - INFO - 第8行: 提取商品信息 条码=6920584471055, 名称=6920584471055.0, 规格=, 数量=2.0, 单位=件, 单价=50.0 +2025-05-09 16:01:39,712 - app.core.excel.processor - INFO - 第9行: 提取商品信息 条码=6925861571159, 名称=6925861571159.0, 规格=, 数量=2.0, 单位=件, 单价=65.0 +2025-05-09 16:01:39,713 - app.core.excel.processor - INFO - 第10行: 提取商品信息 条码=6925861571466, 名称=6925861571466.0, 规格=, 数量=1.0, 单位=件, 单价=45.0 +2025-05-09 16:01:39,714 - app.core.excel.processor - INFO - 第11行: 提取商品信息 条码=6923644210151, 名称=6923644210151.0, 规格=, 数量=3.0, 单位=件, 单价=55.0 +2025-05-09 16:01:39,715 - app.core.excel.processor - INFO - 第12行: 提取商品信息 条码=6907992501819, 名称=6907992501819.0, 规格=, 数量=3.0, 单位=件, 单价=63.0 +2025-05-09 16:01:39,715 - app.core.excel.processor - INFO - 第13行: 提取商品信息 条码=6907992502052, 名称=6907992502052.0, 规格=, 数量=3.0, 单位=件, 单价=54.0 +2025-05-09 16:01:39,716 - app.core.excel.processor - INFO - 第14行: 提取商品信息 条码=6907992507385, 名称=6907992507385.0, 规格=, 数量=2.0, 单位=件, 单价=42.0 +2025-05-09 16:01:39,717 - app.core.excel.processor - INFO - 提取到 14 个商品信息 +2025-05-09 16:01:39,730 - app.core.excel.processor - INFO - 开始处理14 个产品信息 +2025-05-09 16:01:39,731 - app.core.excel.processor - INFO - 处理商品: 条码=6907992508344, 数量=12.0, 单价=4.333333333333333, 是否赠品=False +2025-05-09 16:01:39,731 - app.core.excel.processor - INFO - 发现正常商品:条码6907992508344, 数量=12.0, 单价=4.333333333333333 +2025-05-09 16:01:39,731 - app.core.excel.processor - INFO - 处理商品: 条码=6903979000979, 数量=72.0, 单价=2.0833333333333335, 是否赠品=False +2025-05-09 16:01:39,731 - app.core.excel.processor - INFO - 发现正常商品:条码6903979000979, 数量=72.0, 单价=2.0833333333333335 +2025-05-09 16:01:39,731 - app.core.excel.processor - INFO - 处理商品: 条码=6923644283582, 数量=12.0, 单价=2.5, 是否赠品=False +2025-05-09 16:01:39,731 - app.core.excel.processor - INFO - 发现正常商品:条码6923644283582, 数量=12.0, 单价=2.5 +2025-05-09 16:01:39,731 - app.core.excel.processor - INFO - 处理商品: 条码=6923644268909, 数量=24.0, 单价=2.5, 是否赠品=False +2025-05-09 16:01:39,731 - app.core.excel.processor - INFO - 发现正常商品:条码6923644268909, 数量=24.0, 单价=2.5 +2025-05-09 16:01:44,609 - app.core.excel.processor - INFO - 处理商品: 条码=6923644268930, 数量=24.0, 单价=2.5, 是否赠品=False +2025-05-09 16:01:44,609 - app.core.excel.processor - INFO - 发现正常商品:条码6923644268930, 数量=24.0, 单价=2.5 +2025-05-09 16:01:44,609 - app.core.excel.processor - INFO - 处理商品: 条码=6923644268916, 数量=24.0, 单价=2.5, 是否赠品=False +2025-05-09 16:01:44,609 - app.core.excel.processor - INFO - 发现正常商品:条码6923644268916, 数量=24.0, 单价=2.5 +2025-05-09 16:01:44,609 - app.core.excel.processor - INFO - 处理商品: 条码=6923644266318, 数量=48.0, 单价=3.75, 是否赠品=False +2025-05-09 16:01:44,609 - app.core.excel.processor - INFO - 发现正常商品:条码6923644266318, 数量=48.0, 单价=3.75 +2025-05-09 16:01:44,610 - app.core.excel.processor - INFO - 处理商品: 条码=6920584471017, 数量=24.0, 单价=4.166666666666667, 是否赠品=False +2025-05-09 16:01:44,610 - app.core.excel.processor - INFO - 发现正常商品:条码6920584471017, 数量=24.0, 单价=4.166666666666667 +2025-05-09 16:01:44,610 - app.core.excel.processor - INFO - 处理商品: 条码=69021824, 数量=72.0, 单价=1.8055555555555556, 是否赠品=False +2025-05-09 16:01:44,610 - app.core.excel.processor - INFO - 发现正常商品:条码69021824, 数量=72.0, 单价=1.8055555555555556 +2025-05-09 16:01:44,610 - app.core.excel.processor - INFO - 处理商品: 条码=6925861571466, 数量=12.0, 单价=3.75, 是否赠品=False +2025-05-09 16:01:44,610 - app.core.excel.processor - INFO - 发现正常商品:条码6925861571466, 数量=12.0, 单价=3.75 +2025-05-09 16:01:44,610 - app.core.excel.processor - INFO - 处理商品: 条码=6923644210151, 数量=72.0, 单价=2.2916666666666665, 是否赠品=False +2025-05-09 16:01:44,610 - app.core.excel.processor - INFO - 发现正常商品:条码6923644210151, 数量=72.0, 单价=2.2916666666666665 +2025-05-09 16:01:44,611 - app.core.excel.processor - INFO - 处理商品: 条码=6907992501819, 数量=72.0, 单价=2.625, 是否赠品=False +2025-05-09 16:01:44,611 - app.core.excel.processor - INFO - 发现正常商品:条码6907992501819, 数量=72.0, 单价=2.625 +2025-05-09 16:01:44,611 - app.core.excel.processor - INFO - 处理商品: 条码=6907992502052, 数量=72.0, 单价=2.25, 是否赠品=False +2025-05-09 16:01:44,611 - app.core.excel.processor - INFO - 发现正常商品:条码6907992502052, 数量=72.0, 单价=2.25 +2025-05-09 16:01:44,611 - app.core.excel.processor - INFO - 处理商品: 条码=6907992507385, 数量=24.0, 单价=3.5, 是否赠品=False +2025-05-09 16:01:44,611 - app.core.excel.processor - INFO - 发现正常商品:条码6907992507385, 数量=24.0, 单价=3.5 +2025-05-09 16:01:44,611 - app.core.excel.processor - INFO - 分组后共14 个不同条码的商品 +2025-05-09 16:01:44,611 - app.core.excel.processor - INFO - 条码 6907992508344 处理结果:正常商品数量12.0,单价4.333333333333333,赠品数量0 +2025-05-09 16:01:44,611 - app.core.excel.processor - INFO - 条码 6903979000979 处理结果:正常商品数量72.0,单价2.0833333333333335,赠品数量0 +2025-05-09 16:01:44,612 - app.core.excel.processor - INFO - 条码 6923644283582 处理结果:正常商品数量12.0,单价2.5,赠品数量0 +2025-05-09 16:01:44,612 - app.core.excel.processor - INFO - 条码 6923644268909 处理结果:正常商品数量24.0,单价2.5,赠品数量0 +2025-05-09 16:01:44,612 - app.core.excel.processor - INFO - 条码 6923644268930 处理结果:正常商品数量24.0,单价2.5,赠品数量0 +2025-05-09 16:01:44,612 - app.core.excel.processor - INFO - 条码 6923644268916 处理结果:正常商品数量24.0,单价2.5,赠品数量0 +2025-05-09 16:01:44,612 - app.core.excel.processor - INFO - 条码 6923644266318 处理结果:正常商品数量48.0,单价3.75,赠品数量0 +2025-05-09 16:01:44,612 - app.core.excel.processor - INFO - 条码 6920584471017 处理结果:正常商品数量24.0,单价4.166666666666667,赠品数量0 +2025-05-09 16:01:44,612 - app.core.excel.processor - INFO - 条码 69021824 处理结果:正常商品数量72.0,单价1.8055555555555556,赠品数量0 +2025-05-09 16:01:44,612 - app.core.excel.processor - INFO - 条码 6925861571466 处理结果:正常商品数量12.0,单价3.75,赠品数量0 +2025-05-09 16:01:44,612 - app.core.excel.processor - INFO - 条码 6923644210151 处理结果:正常商品数量72.0,单价2.2916666666666665,赠品数量0 +2025-05-09 16:01:44,613 - app.core.excel.processor - INFO - 条码 6907992501819 处理结果:正常商品数量72.0,单价2.625,赠品数量0 +2025-05-09 16:01:51,983 - app.core.excel.processor - INFO - 条码 6907992502052 处理结果:正常商品数量72.0,单价2.25,赠品数量0 +2025-05-09 16:01:51,983 - app.core.excel.processor - INFO - 条码 6907992507385 处理结果:正常商品数量24.0,单价3.5,赠品数量0 +2025-05-09 16:01:51,987 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_微信图片_20250509142624.xls +2025-05-09 16:01:51,989 - app.core.excel.processor - INFO - 采购单已保存到: data/output\采购单_微信图片_20250509142624.xls diff --git a/logs/app.core.excel.validators.active b/logs/app.core.excel.validators.active new file mode 100644 index 0000000..617fce6 --- /dev/null +++ b/logs/app.core.excel.validators.active @@ -0,0 +1 @@ +Active since: 2025-05-10 11:21:12 \ No newline at end of file diff --git a/logs/app.core.ocr.baidu_ocr.active b/logs/app.core.ocr.baidu_ocr.active new file mode 100644 index 0000000..1fe4767 --- /dev/null +++ b/logs/app.core.ocr.baidu_ocr.active @@ -0,0 +1 @@ +Active since: 2025-05-09 16:01:37 \ No newline at end of file diff --git a/logs/app.core.ocr.baidu_ocr.log b/logs/app.core.ocr.baidu_ocr.log index e51cdd7..2afc301 100644 --- a/logs/app.core.ocr.baidu_ocr.log +++ b/logs/app.core.ocr.baidu_ocr.log @@ -69,3 +69,14 @@ 2025-05-07 21:54:55,605 - app.core.ocr.baidu_ocr - INFO - 成功获取访问令牌 2025-05-07 22:28:51,887 - app.core.ocr.baidu_ocr - INFO - 成功获取访问令牌 2025-05-08 19:45:41,386 - app.core.ocr.baidu_ocr - INFO - 成功获取访问令牌 +2025-05-09 11:58:49,251 - app.core.ocr.baidu_ocr - ERROR - 初始化失败: getint() takes 3 positional arguments but 4 were given +2025-05-09 12:02:05,168 - app.core.ocr.baidu_ocr - ERROR - 初始化失败: getint() takes 3 positional arguments but 4 were given +2025-05-09 12:07:05,181 - app.core.ocr.baidu_ocr - ERROR - 初始化失败: getint() takes 3 positional arguments but 4 were given +2025-05-09 12:07:54,656 - app.core.ocr.baidu_ocr - ERROR - 初始化失败: getint() takes 3 positional arguments but 4 were given +2025-05-09 12:12:42,103 - app.core.ocr.baidu_ocr - ERROR - 初始化失败: getint() takes 3 positional arguments but 4 were given +2025-05-09 12:13:52,580 - app.core.ocr.baidu_ocr - ERROR - 初始化失败: getint() takes 3 positional arguments but 4 were given +2025-05-09 12:45:35,995 - app.core.ocr.baidu_ocr - ERROR - 初始化失败: getint() takes 3 positional arguments but 4 were given +2025-05-09 14:27:08,879 - app.core.ocr.baidu_ocr - ERROR - 初始化失败: getint() takes 3 positional arguments but 4 were given +2025-05-09 14:27:31,660 - app.core.ocr.baidu_ocr - ERROR - 初始化失败: getint() takes 3 positional arguments but 4 were given +2025-05-09 14:31:02,533 - app.core.ocr.baidu_ocr - INFO - 成功获取访问令牌 +2025-05-09 14:31:02,581 - app.core.ocr.baidu_ocr - INFO - 成功获取访问令牌 diff --git a/logs/app.core.ocr.table_ocr.active b/logs/app.core.ocr.table_ocr.active new file mode 100644 index 0000000..1fe4767 --- /dev/null +++ b/logs/app.core.ocr.table_ocr.active @@ -0,0 +1 @@ +Active since: 2025-05-09 16:01:37 \ No newline at end of file diff --git a/logs/app.core.ocr.table_ocr.log b/logs/app.core.ocr.table_ocr.log index f6daaea..e0a9d6a 100644 --- a/logs/app.core.ocr.table_ocr.log +++ b/logs/app.core.ocr.table_ocr.log @@ -680,3 +680,54 @@ 2025-05-08 20:46:00,694 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output 2025-05-08 20:46:00,694 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp 2025-05-08 20:46:00,695 - app.core.ocr.table_ocr - INFO - OCR处理器初始化完成,输入目录: D:\My Documents\python\orc-order-v2\data\input, 输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:02:05,168 - app.core.ocr.table_ocr - INFO - 初始化OCRProcessor完成:输入目录=data/input, 输出目录=data/output +2025-05-09 12:02:05,169 - app.core.ocr.table_ocr - INFO - 使用输入目录: D:\My Documents\python\orc-order-v2\data\input +2025-05-09 12:02:05,169 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:02:05,170 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:07:05,181 - app.core.ocr.table_ocr - INFO - 使用输入目录: D:\My Documents\python\orc-order-v2\data\input +2025-05-09 12:07:05,181 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:07:05,181 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:07:05,181 - app.core.ocr.table_ocr - INFO - 允许的文件类型: ['.jpg', '.jpeg', '.png', '.bmp'] +2025-05-09 12:07:05,182 - app.core.ocr.table_ocr - INFO - 初始化OCRProcessor完成:输入目录=data/input, 输出目录=data/output +2025-05-09 12:07:54,657 - app.core.ocr.table_ocr - INFO - 使用输入目录: D:\My Documents\python\orc-order-v2\data\input +2025-05-09 12:07:54,657 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:07:54,657 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:07:54,657 - app.core.ocr.table_ocr - INFO - 允许的文件类型: ['.jpg', '.jpeg', '.png', '.bmp'] +2025-05-09 12:07:54,657 - app.core.ocr.table_ocr - INFO - 初始化OCRProcessor完成:输入目录=data/input, 输出目录=data/output +2025-05-09 12:12:42,103 - app.core.ocr.table_ocr - INFO - 使用输入目录: D:\My Documents\python\orc-order-v2\data\input +2025-05-09 12:12:42,104 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:12:42,104 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:12:42,104 - app.core.ocr.table_ocr - INFO - 允许的文件类型: ['.jpg', '.jpeg', '.png', '.bmp'] +2025-05-09 12:12:42,104 - app.core.ocr.table_ocr - INFO - 初始化OCRProcessor完成:输入目录=data/input, 输出目录=data/output +2025-05-09 12:13:52,580 - app.core.ocr.table_ocr - INFO - 使用输入目录: D:\My Documents\python\orc-order-v2\data\input +2025-05-09 12:13:52,581 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:13:52,581 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:13:52,581 - app.core.ocr.table_ocr - INFO - 允许的文件类型: ['.jpg', '.jpeg', '.png', '.bmp'] +2025-05-09 12:13:52,581 - app.core.ocr.table_ocr - INFO - 初始化OCRProcessor完成:输入目录=data/input, 输出目录=data/output +2025-05-09 12:45:35,996 - app.core.ocr.table_ocr - INFO - 使用输入目录: D:\My Documents\python\orc-order-v2\data\input +2025-05-09 12:45:35,996 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 12:45:35,996 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 12:45:35,996 - app.core.ocr.table_ocr - INFO - 允许的文件类型: ['.jpg', '.jpeg', '.png', '.bmp'] +2025-05-09 12:45:35,996 - app.core.ocr.table_ocr - INFO - 初始化OCRProcessor完成:输入目录=data/input, 输出目录=data/output +2025-05-09 14:27:08,879 - app.core.ocr.table_ocr - INFO - 使用输入目录: D:\My Documents\python\orc-order-v2\data\input +2025-05-09 14:27:08,880 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:27:08,880 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 14:27:08,880 - app.core.ocr.table_ocr - INFO - 允许的文件类型: ['.jpg', '.jpeg', '.png', '.bmp'] +2025-05-09 14:27:08,880 - app.core.ocr.table_ocr - INFO - 初始化OCRProcessor完成:输入目录=data/input, 输出目录=data/output +2025-05-09 14:27:31,661 - app.core.ocr.table_ocr - INFO - 使用输入目录: D:\My Documents\python\orc-order-v2\data\input +2025-05-09 14:27:31,661 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:27:31,661 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 14:27:31,662 - app.core.ocr.table_ocr - INFO - 允许的文件类型: ['.jpg', '.jpeg', '.png', '.bmp'] +2025-05-09 14:27:31,662 - app.core.ocr.table_ocr - INFO - 初始化OCRProcessor完成:输入目录=data/input, 输出目录=data/output +2025-05-09 14:31:02,077 - app.core.ocr.table_ocr - INFO - 使用输入目录: D:\My Documents\python\orc-order-v2\data\input +2025-05-09 14:31:02,077 - app.core.ocr.table_ocr - INFO - 使用输出目录: D:\My Documents\python\orc-order-v2\data\output +2025-05-09 14:31:02,078 - app.core.ocr.table_ocr - INFO - 使用临时目录: D:\My Documents\python\orc-order-v2\data\temp +2025-05-09 14:31:02,078 - app.core.ocr.table_ocr - INFO - 允许的文件类型: ['.jpg', '.jpeg', '.png', '.bmp'] +2025-05-09 14:31:02,078 - app.core.ocr.table_ocr - INFO - 初始化OCRProcessor完成:输入目录=data/input, 输出目录=data/output +2025-05-09 14:31:02,079 - app.core.ocr.table_ocr - INFO - 找到 2 个图片文件,其中 2 个未处理 +2025-05-09 14:31:02,079 - app.core.ocr.table_ocr - INFO - 处理批次 1/1: 2 个文件 +2025-05-09 14:31:02,085 - app.core.ocr.table_ocr - INFO - 开始处理图片: data/input\微信图片_20250509142624.jpg +2025-05-09 14:31:02,105 - app.core.ocr.table_ocr - INFO - 开始处理图片: data/input\微信图片_20250509142700.jpg +2025-05-09 14:31:04,140 - app.core.ocr.table_ocr - INFO - 图片处理成功: data/input\微信图片_20250509142624.jpg, 输出文件: data/output\微信图片_20250509142624.xlsx +2025-05-09 14:31:04,271 - app.core.ocr.table_ocr - INFO - 图片处理成功: data/input\微信图片_20250509142700.jpg, 输出文件: data/output\微信图片_20250509142700.xlsx +2025-05-09 14:31:04,274 - app.core.ocr.table_ocr - INFO - 所有图片处理完成, 总计: 2, 成功: 2 diff --git a/logs/app.core.utils.file_utils.active b/logs/app.core.utils.file_utils.active new file mode 100644 index 0000000..2ec83bf --- /dev/null +++ b/logs/app.core.utils.file_utils.active @@ -0,0 +1 @@ +Active since: 2025-05-09 16:01:36 \ No newline at end of file diff --git a/logs/app.services.ocr_service.active b/logs/app.services.ocr_service.active new file mode 100644 index 0000000..1fe4767 --- /dev/null +++ b/logs/app.services.ocr_service.active @@ -0,0 +1 @@ +Active since: 2025-05-09 16:01:37 \ No newline at end of file diff --git a/logs/app.services.ocr_service.log b/logs/app.services.ocr_service.log index e89077d..c7b637f 100644 --- a/logs/app.services.ocr_service.log +++ b/logs/app.services.ocr_service.log @@ -275,3 +275,24 @@ 2025-05-08 20:04:06,907 - app.services.ocr_service - INFO - OCRService初始化完成 2025-05-08 20:46:00,690 - app.services.ocr_service - INFO - 初始化OCRService 2025-05-08 20:46:00,696 - app.services.ocr_service - INFO - OCRService初始化完成 +2025-05-09 11:55:03,577 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 11:58:49,250 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 12:02:05,166 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 12:07:05,179 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 12:07:05,182 - app.services.ocr_service - INFO - OCRService初始化完成 +2025-05-09 12:07:54,655 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 12:07:54,658 - app.services.ocr_service - INFO - OCRService初始化完成 +2025-05-09 12:12:42,102 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 12:12:42,104 - app.services.ocr_service - INFO - OCRService初始化完成 +2025-05-09 12:13:52,579 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 12:13:52,581 - app.services.ocr_service - INFO - OCRService初始化完成 +2025-05-09 12:45:35,994 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 12:45:35,996 - app.services.ocr_service - INFO - OCRService初始化完成 +2025-05-09 14:27:08,878 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 14:27:08,880 - app.services.ocr_service - INFO - OCRService初始化完成 +2025-05-09 14:27:31,659 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 14:27:31,662 - app.services.ocr_service - INFO - OCRService初始化完成 +2025-05-09 14:31:02,076 - app.services.ocr_service - INFO - 初始化OCRService +2025-05-09 14:31:02,078 - app.services.ocr_service - INFO - OCRService初始化完成 +2025-05-09 14:31:02,078 - app.services.ocr_service - INFO - OCRService.batch_process被调用,转发到process_images_batch +2025-05-09 14:31:02,078 - app.services.ocr_service - INFO - OCRService开始批量处理图片, batch_size=5, max_workers=4 diff --git a/logs/app.services.order_service.active b/logs/app.services.order_service.active new file mode 100644 index 0000000..5367524 --- /dev/null +++ b/logs/app.services.order_service.active @@ -0,0 +1 @@ +Active since: 2025-05-09 16:01:38 \ No newline at end of file diff --git a/logs/app.services.order_service.log b/logs/app.services.order_service.log index cf0cdb2..d2ff2c6 100644 --- a/logs/app.services.order_service.log +++ b/logs/app.services.order_service.log @@ -315,3 +315,29 @@ 2025-05-08 20:46:00,697 - app.services.order_service - INFO - 初始化OrderService 2025-05-08 20:46:00,701 - app.services.order_service - INFO - OrderService初始化完成 2025-05-08 20:46:00,750 - app.services.order_service - INFO - OrderService开始处理指定Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250508194532.xlsx +2025-05-09 12:07:05,182 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 12:07:54,658 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 12:12:42,104 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 12:13:52,581 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 12:13:52,586 - app.services.order_service - INFO - OrderService初始化完成 +2025-05-09 12:45:35,997 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 12:45:35,999 - app.services.order_service - INFO - OrderService初始化完成 +2025-05-09 13:39:38,178 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 13:39:38,187 - app.services.order_service - INFO - OrderService初始化完成 +2025-05-09 14:08:43,900 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 14:08:43,903 - app.services.order_service - INFO - OrderService初始化完成 +2025-05-09 14:08:43,903 - app.services.order_service - INFO - OrderService开始处理指定Excel文件: D:/My Documents/python/orc-order-v2/data/output/高新-益选便利店销售单2025-05-09.xlsx +2025-05-09 14:23:40,512 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 14:23:40,516 - app.services.order_service - INFO - OrderService初始化完成 +2025-05-09 14:23:40,516 - app.services.order_service - INFO - OrderService开始处理指定Excel文件: D:/My Documents/python/orc-order-v2/data/output/高新-益选便利店销售单2025-05-09.xlsx +2025-05-09 14:26:54,507 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 14:26:54,511 - app.services.order_service - INFO - OrderService初始化完成 +2025-05-09 14:31:54,256 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 14:31:54,259 - app.services.order_service - INFO - OrderService初始化完成 +2025-05-09 14:31:54,259 - app.services.order_service - INFO - OrderService开始处理指定Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250509142624.xlsx +2025-05-09 14:32:20,936 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 14:32:20,942 - app.services.order_service - INFO - OrderService初始化完成 +2025-05-09 14:32:20,954 - app.services.order_service - INFO - OrderService开始处理指定Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250509142700.xlsx +2025-05-09 16:01:39,291 - app.services.order_service - INFO - 初始化OrderService +2025-05-09 16:01:39,294 - app.services.order_service - INFO - OrderService初始化完成 +2025-05-09 16:01:39,295 - app.services.order_service - INFO - OrderService开始处理指定Excel文件: D:/My Documents/python/orc-order-v2/data/output/微信图片_20250509142624.xlsx diff --git a/logs/app.services.tobacco_service.active b/logs/app.services.tobacco_service.active new file mode 100644 index 0000000..b266a30 --- /dev/null +++ b/logs/app.services.tobacco_service.active @@ -0,0 +1 @@ +Active since: 2025-05-09 16:01:39 \ No newline at end of file diff --git a/logs/app.services.tobacco_service.log b/logs/app.services.tobacco_service.log new file mode 100644 index 0000000..2ac9467 --- /dev/null +++ b/logs/app.services.tobacco_service.log @@ -0,0 +1,97 @@ +2025-05-09 12:45:35,999 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 12:45:36,000 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 12:45:36,102 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 12:45:36,103 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 12:45:36,103 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:11:06,843 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:11:06,844 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:11:06,923 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:11:06,924 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:11:06,925 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:11:53,142 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:11:53,143 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:11:53,195 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:11:53,196 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:11:53,196 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:13:30,197 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:13:30,197 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:13:30,253 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:13:30,256 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:13:30,256 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:16:20,406 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:16:20,407 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:16:20,583 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:16:20,584 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:16:20,596 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:18:16,271 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:18:16,271 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:18:16,334 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:18:16,335 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:18:16,336 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:19:40,681 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:19:40,681 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:19:40,735 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:19:40,736 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:19:40,736 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:21:06,878 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:21:06,879 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:21:06,918 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:21:06,919 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:21:06,920 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:21:53,150 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:21:53,150 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:21:53,248 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:21:53,248 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:21:53,249 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:22:48,435 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:22:48,435 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:22:48,496 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:22:48,497 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:22:48,497 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:25:59,038 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:25:59,038 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:25:59,110 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:25:59,110 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:25:59,110 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:29:28,788 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:29:28,788 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:29:28,834 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:29:28,835 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:29:28,836 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:30:21,809 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:30:21,809 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:30:21,940 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:30:21,966 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:30:21,972 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:30:43,719 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:30:43,719 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:30:43,779 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:30:43,779 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:30:43,780 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:34:49,133 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:34:49,136 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:34:49,289 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:34:49,290 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:34:49,291 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:37:56,254 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:37:56,254 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:37:56,481 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:37:56,481 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:37:56,481 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:39:52,438 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509114847.xlsx +2025-05-09 13:39:52,438 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509114847.xlsx +2025-05-09 13:39:52,580 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:39:52,581 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-05-06, 总金额: 12836.76, 处理条目: 36 +2025-05-09 13:39:52,581 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:50:34,355 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509134955.xlsx +2025-05-09 13:50:34,355 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509134955.xlsx +2025-05-09 13:50:34,766 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:50:34,766 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-04-27, 总金额: 10844.48, 处理条目: 34 +2025-05-09 13:50:34,772 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:52:17,578 - app.services.tobacco_service - INFO - 找到最新烟草订单明细文件: data/output\订单明细20250509135149.xlsx +2025-05-09 13:52:17,579 - app.services.tobacco_service - INFO - 开始处理烟草公司订单: data/output\订单明细20250509135149.xlsx +2025-05-09 13:52:17,705 - app.services.tobacco_service - INFO - 采购单生成成功: data/output\银豹采购单_烟草公司.xls +2025-05-09 13:52:17,705 - app.services.tobacco_service - INFO - 烟草公司订单处理成功,订单时间: 2025-04-21, 总金额: 9550.10, 处理条目: 30 +2025-05-09 13:52:17,706 - app.services.tobacco_service - INFO - 采购单已生成: data/output\银豹采购单_烟草公司.xls +2025-05-09 14:32:56,705 - app.services.tobacco_service - WARNING - 未找到烟草公司订单明细文件 +2025-05-09 14:32:56,706 - app.services.tobacco_service - ERROR - 未找到可处理的烟草订单明细文件 diff --git a/run.py b/run.py index f7cea95..180bc97 100644 --- a/run.py +++ b/run.py @@ -13,318 +13,193 @@ import argparse from typing import List, Optional from app.config.settings import ConfigManager -from app.core.utils.log_utils import get_logger, close_logger +from app.core.utils.log_utils import get_logger, close_all_loggers, set_log_level from app.services.ocr_service import OCRService from app.services.order_service import OrderService +from app.services.tobacco_service import TobaccoService logger = get_logger(__name__) -def create_parser() -> argparse.ArgumentParser: +def parse_args(): """ - 创建命令行参数解析器 + 解析命令行参数 Returns: - 参数解析器 + 解析后的参数 """ parser = argparse.ArgumentParser(description='OCR订单处理系统') # 通用选项 parser.add_argument('--config', type=str, help='配置文件路径') + parser.add_argument('--log-level', type=str, choices=['debug', 'info', 'warning', 'error', 'critical'], help='日志级别') # 子命令 subparsers = parser.add_subparsers(dest='command', help='子命令') # OCR识别命令 ocr_parser = subparsers.add_parser('ocr', help='OCR识别') - ocr_parser.add_argument('--input', type=str, help='输入图片文件路径') - ocr_parser.add_argument('--batch', action='store_true', help='批量处理模式') - ocr_parser.add_argument('--batch-size', type=int, help='批处理大小') - ocr_parser.add_argument('--max-workers', type=int, help='最大线程数') + ocr_parser.add_argument('--input', type=str, help='输入图片路径') + ocr_parser.add_argument('--batch', action='store_true', help='批量处理') + ocr_parser.add_argument('--batch-size', type=int, default=5, help='批处理大小') + ocr_parser.add_argument('--max-workers', type=int, default=4, help='最大线程数') # Excel处理命令 excel_parser = subparsers.add_parser('excel', help='Excel处理') - excel_parser.add_argument('--input', type=str, help='输入Excel文件路径,如果不指定则处理最新的文件') + excel_parser.add_argument('--input', type=str, help='输入Excel文件路径') - # 订单合并命令 - merge_parser = subparsers.add_parser('merge', help='订单合并') - merge_parser.add_argument('--input', type=str, help='输入采购单文件路径列表,以逗号分隔,如果不指定则合并所有采购单') + # 合并命令 + merge_parser = subparsers.add_parser('merge', help='合并采购单') + merge_parser.add_argument('--input', type=str, help='输入采购单文件路径(逗号分隔)') # 完整流程命令 - pipeline_parser = subparsers.add_parser('pipeline', help='完整流程') - pipeline_parser.add_argument('--input', type=str, help='输入图片文件路径,如果不指定则处理所有图片') + pipeline_parser = subparsers.add_parser('pipeline', help='完整处理流程') + pipeline_parser.add_argument('--input', type=str, help='输入图片路径') + pipeline_parser.add_argument('--merge', action='store_true', help='是否合并采购单') - return parser + # 烟草订单处理 + tobacco_parser = subparsers.add_parser('tobacco', help='处理烟草订单') + tobacco_parser.add_argument('--input', type=str, help='输入订单明细文件路径') + + # 解析参数 + parsed_args = parser.parse_args() + + return parsed_args -def run_ocr(ocr_service: OCRService, args) -> bool: +def main(): """ - 运行OCR识别 + 主函数入口 - Args: - ocr_service: OCR服务 - args: 命令行参数 - Returns: - 处理是否成功 + 退出码 """ - if args.input: - if not os.path.exists(args.input): - logger.error(f"输入文件不存在: {args.input}") - return False - - if not ocr_service.validate_image(args.input): - logger.error(f"输入文件无效: {args.input}") - return False - - logger.info(f"处理单个图片: {args.input}") - result = ocr_service.process_image(args.input) - - if result: - logger.info(f"OCR处理成功,输出文件: {result}") - return True - else: - logger.error("OCR处理失败") - return False - elif args.batch: - logger.info("批量处理模式") - total, success = ocr_service.process_images_batch(args.batch_size, args.max_workers) - - if total == 0: - logger.warning("没有找到需要处理的文件") - return False - - logger.info(f"批量处理完成,总计: {total},成功: {success}") - return success > 0 - else: - # 列出未处理的文件 - files = ocr_service.get_unprocessed_images() - - if not files: - logger.info("没有未处理的文件") - return True - - logger.info(f"未处理的文件 ({len(files)}):") - for file in files: - logger.info(f" {file}") - - return True - -def run_excel(order_service: OrderService, args) -> bool: - """ - 运行Excel处理 + # 解析命令行参数 + args = parse_args() - Args: - order_service: 订单服务 - args: 命令行参数 - - Returns: - 处理是否成功 - """ - if args.input: - if not os.path.exists(args.input): - logger.error(f"输入文件不存在: {args.input}") - return False - - logger.info(f"处理Excel文件: {args.input}") - result = order_service.process_excel(args.input) - else: - latest_file = order_service.get_latest_excel() - if not latest_file: - logger.warning("未找到可处理的Excel文件") - return False - - logger.info(f"处理最新的Excel文件: {latest_file}") - result = order_service.process_excel(latest_file) - - if result: - logger.info(f"Excel处理成功,输出文件: {result}") - return True - else: - logger.error("Excel处理失败") - return False - -def run_merge(order_service: OrderService, args) -> bool: - """ - 运行订单合并 - - Args: - order_service: 订单服务 - args: 命令行参数 - - Returns: - 处理是否成功 - """ - if args.input: - # 分割输入文件列表 - file_paths = [path.strip() for path in args.input.split(',')] - - # 检查文件是否存在 - for path in file_paths: - if not os.path.exists(path): - logger.error(f"输入文件不存在: {path}") - return False - - logger.info(f"合并指定的采购单文件: {file_paths}") - result = order_service.merge_orders(file_paths) - else: - # 获取所有采购单文件 - file_paths = order_service.get_purchase_orders() - if not file_paths: - logger.warning("未找到采购单文件") - return False - - logger.info(f"合并所有采购单文件: {len(file_paths)} 个") - result = order_service.merge_orders() - - if result: - logger.info(f"订单合并成功,输出文件: {result}") - return True - else: - logger.error("订单合并失败") - return False - -def run_pipeline(ocr_service: OCRService, order_service: OrderService, args) -> bool: - """ - 运行完整流程 - - Args: - ocr_service: OCR服务 - order_service: 订单服务 - args: 命令行参数 - - Returns: - 处理是否成功 - """ - # 1. OCR识别 - logger.info("=== 流程步骤 1: OCR识别 ===") - - if args.input: - if not os.path.exists(args.input): - logger.error(f"输入文件不存在: {args.input}") - return False - - if not ocr_service.validate_image(args.input): - logger.error(f"输入文件无效: {args.input}") - return False - - logger.info(f"处理单个图片: {args.input}") - ocr_result = ocr_service.process_image(args.input) - - if not ocr_result: - logger.error("OCR处理失败") - return False - - logger.info(f"OCR处理成功,输出文件: {ocr_result}") - else: - # 批量处理所有图片 - logger.info("批量处理所有图片") - total, success = ocr_service.process_images_batch() - - if total == 0: - logger.warning("没有找到需要处理的图片") - # 继续下一步,因为可能已经有处理好的Excel文件 - elif success == 0: - logger.error("OCR处理失败,没有成功处理的图片") - return False - else: - logger.info(f"OCR处理完成,总计: {total},成功: {success}") - - # 2. Excel处理 - logger.info("=== 流程步骤 2: Excel处理 ===") - - latest_file = order_service.get_latest_excel() - if not latest_file: - logger.warning("未找到可处理的Excel文件") - return False - - logger.info(f"处理最新的Excel文件: {latest_file}") - excel_result = order_service.process_excel(latest_file) - - if not excel_result: - logger.error("Excel处理失败") - return False - - logger.info(f"Excel处理成功,输出文件: {excel_result}") - - # 3. 订单合并 - logger.info("=== 流程步骤 3: 订单合并 ===") - - # 获取所有采购单文件 - file_paths = order_service.get_purchase_orders() - if not file_paths: - logger.warning("未找到采购单文件,跳过合并步骤") - logger.info("=== 完整流程处理成功(未执行合并步骤)===") - # 非错误状态,继续执行 - return True - - # 有文件需要合并 - logger.info(f"发现 {len(file_paths)} 个采购单文件") - - if len(file_paths) == 1: - logger.warning(f"只有1个采购单文件 {file_paths[0]},无需合并") - logger.info("=== 完整流程处理成功(只有一个文件,跳过合并)===") - return True - - logger.info(f"合并所有采购单文件: {len(file_paths)} 个") - merge_result = order_service.merge_orders() - - if not merge_result: - logger.error("订单合并失败") - return False - - logger.info(f"订单合并成功,输出文件: {merge_result}") - - logger.info("=== 完整流程处理成功 ===") - return True - -def main(args: Optional[List[str]] = None) -> int: - """ - 主函数 - - Args: - args: 命令行参数,如果为None则使用sys.argv - - Returns: - 退出状态码 - """ - parser = create_parser() - parsed_args = parser.parse_args(args) - - if parsed_args.command is None: - parser.print_help() + if not args.command: + argparse.ArgumentParser().print_help() return 1 + # 加载配置 + config_path = args.config + config_manager = ConfigManager(config_path) + config = config_manager.config + + # 设置日志级别 + log_level = getattr(args, 'log_level', None) + if log_level: + set_log_level(log_level) + try: - # 创建配置管理器 - config = ConfigManager(parsed_args.config) if parsed_args.config else ConfigManager() - - # 创建服务 - ocr_service = OCRService(config) - order_service = OrderService(config) - - # 根据命令执行不同功能 - if parsed_args.command == 'ocr': - success = run_ocr(ocr_service, parsed_args) - elif parsed_args.command == 'excel': - success = run_excel(order_service, parsed_args) - elif parsed_args.command == 'merge': - success = run_merge(order_service, parsed_args) - elif parsed_args.command == 'pipeline': - success = run_pipeline(ocr_service, order_service, parsed_args) - else: - parser.print_help() - return 1 + if args.command == 'ocr': + # OCR识别处理 + ocr_service = OCRService(config) + if args.batch: + # 批量处理 + total, success = ocr_service.batch_process( + batch_size=args.batch_size, + max_workers=args.max_workers + ) + return 0 if success > 0 else 1 + else: + # 处理单个文件 + result = ocr_service.process_image(args.input) + return 0 if result else 1 + + elif args.command == 'excel': + # Excel处理 + order_service = OrderService(config) + if args.input: + # 处理指定文件 + result = order_service.process_excel(args.input) + else: + # 处理最新文件 + result = order_service.process_latest_excel() + return 0 if result else 1 - return 0 if success else 1 - + elif args.command == 'merge': + # 合并采购单 + order_service = OrderService(config) + if args.input: + # 合并指定文件 + file_list = args.input.split(',') + result = order_service.merge_purchase_orders(file_list) + else: + # 合并所有采购单 + result = order_service.merge_all_purchase_orders() + return 0 if result else 1 + + elif args.command == 'pipeline': + # 完整流程 + ocr_service = OCRService(config) + order_service = OrderService(config) + + # 1. OCR处理 + if args.input: + # 处理单个文件 + excel_file = ocr_service.process_image(args.input) + else: + # 批量处理 + total, success = ocr_service.batch_process() + if success == 0: + logger.error("OCR处理失败,没有成功处理任何文件") + return 1 + excel_file = None # 批量处理不返回具体文件 + + # 2. Excel处理 + if excel_file: + # 处理指定的Excel文件 + result = order_service.process_excel(excel_file) + else: + # 处理最新的Excel文件 + result = order_service.process_latest_excel() + + if not result: + logger.error("Excel处理失败") + return 1 + + # 3. 合并采购单(可选) + if args.merge: + result = order_service.merge_all_purchase_orders() + if not result: + logger.warning("合并采购单失败") + # 不影响整体流程,继续执行 + + return 0 + + elif args.command == 'tobacco': + # 烟草订单处理 + tobacco_service = TobaccoService(config) + if args.input: + # 处理指定文件 + logger.info(f"开始处理烟草订单,输入文件: {args.input}") + result = tobacco_service.process_tobacco_order(args.input) + else: + # 处理最新文件 + logger.info("开始烟草公司订单处理") + result = tobacco_service.process_tobacco_order() + + # 检查结果是否为None + if result is None: + logger.error("烟草订单处理失败") + return 1 + else: + logger.info(f"烟草订单处理成功,输出文件: {result}") + # 确保result是绝对路径 + if not os.path.isabs(result): + result = os.path.abspath(result) + logger.info(f"烟草订单处理完成,绝对路径: {result}") + return 0 + + else: + logger.error(f"未知命令: {args.command}") + return 1 + except Exception as e: - logger.error(f"执行过程中发生错误: {e}") - import traceback - logger.error(traceback.format_exc()) + logger.error(f"执行过程中发生错误: {e}", exc_info=True) return 1 - finally: - # 关闭日志 - close_logger(__name__) + # 关闭所有日志记录器 + close_all_loggers() -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main()) \ No newline at end of file diff --git a/启动器.py b/启动器.py index b17eab3..4951e41 100644 --- a/启动器.py +++ b/启动器.py @@ -21,6 +21,10 @@ import json import re from typing import Dict, List, Optional, Any +# 导入自定义对话框工具 +from app.core.utils.dialog_utils import show_custom_dialog, show_barcode_mapping_dialog +from app.core.excel.converter import UnitConverter + # 全局变量,用于跟踪任务状态 RUNNING_TASK = None THEME_MODE = "light" # 默认浅色主题 @@ -200,8 +204,8 @@ def run_command_with_logging(command, log_widget, status_bar=None, on_complete=N if on_complete: log_widget.after(0, lambda: on_complete(process.returncode, output_text)) - # 如果处理成功,显示成功信息 - if process.returncode == 0: + # 如果处理成功且没有指定on_complete回调函数,则显示默认成功信息 + 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)) @@ -434,7 +438,7 @@ def show_pipeline_result_preview(output): # 添加处理结果提示(即使没有可合并文件也显示成功) no_files_match = re.search(r'未找到可合并的文件', output) if no_files_match: - tk.Label(preview, text="未找到可合并文件,但其他步骤已成功执行", font=("Arial", 12)).pack(pady=0) + 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) @@ -758,7 +762,7 @@ def main(): text="处理Excel文件", width=button_width, height=button_height, - command=lambda: process_excel_file(log_text, status_bar) + command=lambda: process_excel_file_with_status(log_text, status_bar) ).pack(side=tk.LEFT, padx=button_padx) # OCR批量识别 @@ -789,7 +793,7 @@ def main(): text="处理单个图片", width=button_width, height=button_height, - command=lambda: process_single_image(log_text, status_bar) + command=lambda: process_single_image_with_status(log_text, status_bar) ).pack(side=tk.LEFT, padx=button_padx) # 第三行 @@ -818,6 +822,15 @@ def main(): row4 = tk.Frame(button_area) row4.pack(fill=tk.X, pady=button_pady) + # 处理烟草订单按钮 + tk.Button( + row4, + text="处理烟草订单", + width=button_width, + height=button_height, + command=lambda: run_command_with_logging(["python", "run.py", "tobacco"], log_text, status_bar, on_complete=show_tobacco_result_preview) + ).pack(side=tk.LEFT, padx=button_padx) + # 清除处理缓存按钮 tk.Button( row4, @@ -827,15 +840,6 @@ def main(): command=lambda: clean_cache(log_text) ).pack(side=tk.LEFT, padx=button_padx) - # 清理文件按钮 - tk.Button( - row4, - text="清理文件", - width=button_width, - height=button_height, - command=lambda: clean_data_files(log_text) - ).pack(side=tk.LEFT, padx=button_padx) - # 第五行 row5 = tk.Frame(button_area) row5.pack(fill=tk.X, pady=button_pady) @@ -858,6 +862,50 @@ def main(): command=lambda: os.startfile(os.path.abspath("data/output")) ).pack(side=tk.LEFT, padx=button_padx) + # 第六行 + row6 = tk.Frame(button_area) + row6.pack(fill=tk.X, pady=button_pady) + + # 清理文件按钮 + tk.Button( + row6, + text="清理文件", + width=button_width, + height=button_height, + command=lambda: clean_data_files(log_text) + ).pack(side=tk.LEFT, padx=button_padx) + + # 切换主题按钮 + tk.Button( + row6, + text="切换主题", + width=button_width, + height=button_height, + command=lambda: toggle_theme(root, log_text, status_bar) + ).pack(side=tk.LEFT, padx=button_padx) + + # 第七行 + row7 = tk.Frame(button_area) + row7.pack(fill=tk.X, pady=button_pady) + + # 演示自定义弹窗按钮 + tk.Button( + row7, + text="自定义弹窗演示", + width=button_width, + height=button_height, + command=lambda: show_demo_dialog(log_text) + ).pack(side=tk.LEFT, padx=button_padx) + + # 条码映射编辑按钮 + tk.Button( + row7, + text="编辑条码映射", + width=button_width, + height=button_height, + command=lambda: edit_barcode_mappings(log_text) + ).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) @@ -1046,5 +1094,178 @@ def center_window(window): y = (window.winfo_screenheight() // 2) - (height // 2) window.geometry('{}x{}+{}+{}'.format(width, height, x, y)) +def show_tobacco_result_preview(returncode, output): + """显示烟草订单处理结果预览""" + # 只在成功时显示结果预览 + if returncode != 0: + return + + try: + # 查找输出文件路径 + 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) + + # 使弹窗居中显示 + 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 = f"{file_size / 1024:.1f} KB" if file_size < 1024*1024 else f"{file_size / (1024*1024):.1f} MB" + + 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: + 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=preview.destroy).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=preview.destroy).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请检查日志了解详细信息。" + ) + +def show_demo_dialog(log_widget): + """演示自定义弹窗功能""" + try: + add_to_log(log_widget, "显示自定义弹窗演示...\n", "info") + + # 创建一个示例结果文件路径 + sample_file = os.path.join(os.path.abspath("data/output"), "样例文件.xlsx") + + # 获取当前时间 + current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # 创建其他信息 + additional_info = { + "客户名称": "示例客户", + "订单编号": "ORD-20250509-001", + "处理类型": "自定义处理" + } + + # 显示自定义弹窗 + show_custom_dialog( + title="自定义弹窗演示", + message="这是一个自定义弹窗示例", + result_file=sample_file, # 文件可能不存在,会展示文件未找到的情况 + time_info=current_time, + count_info="50个商品", + amount_info="¥1,234.56", + additional_info=additional_info + ) + + add_to_log(log_widget, "自定义弹窗已显示\n", "success") + except Exception as e: + add_to_log(log_widget, f"显示自定义弹窗时出错: {str(e)}\n", "error") + +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)}") + if __name__ == "__main__": main() \ No newline at end of file