Compare commits

...

177 Commits

Author SHA1 Message Date
禹翔辉
06e9d5a538 Accept Merge Request #2004: (feature/功能刀具拆解单优化_1 -> develop)
Merge Request: Merge branch 'feature/功能刀具拆解单优化' into feature/功能刀具拆解单优化_1

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2004
2025-04-15 17:22:50 +08:00
yuxianghui
b9aac6c558 Merge branch 'feature/功能刀具拆解单优化' into feature/功能刀具拆解单优化_1 2025-04-15 17:21:31 +08:00
yuxianghui
2de0e9f02f 处理功能刀具预警没有自动创建预警记录和拆解单问题 2025-04-15 17:20:16 +08:00
胡尧
722b601890 Accept Merge Request #2003: (release/release_2.11 -> develop)
Merge Request: 修改质检单的质检员字段

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2003?initial=true
2025-04-15 17:14:51 +08:00
胡尧
20722c12b8 修改质检单的质检员字段 2025-04-15 17:08:43 +08:00
禹翔辉
56f2ea0356 Accept Merge Request #2002: (feature/功能刀具拆解单优化 -> develop)
Merge Request: 功能刀具添加状态变更跟踪

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2002
2025-04-15 16:58:28 +08:00
yuxianghui
bc85c457ad 功能刀具添加状态变更跟踪 2025-04-15 16:46:49 +08:00
禹翔辉
7eeea92a3e Accept Merge Request #2001: (feature/功能刀具拆解单优化 -> develop)
Merge Request: 功能刀具拆解单添加可以选择线边刀库的功能刀具进行拆解

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2001
2025-04-15 15:09:36 +08:00
yuxianghui
d672f3f4d7 功能刀具拆解单添加可以选择线边刀库的功能刀具进行拆解 2025-04-15 15:05:23 +08:00
黄焱
c79cf2e5ad Accept Merge Request #2000: (feature/前端样式修改 -> develop)
Merge Request: 删除多余字段

Created By: @黄焱
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @黄焱
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2000?initial=true
2025-04-15 11:26:42 +08:00
hyyy
33a5fc0ff4 删除多余字段 2025-04-15 11:24:45 +08:00
黄焱
2dcaa25952 Accept Merge Request #1999: (feature/前端样式修改 -> develop)
Merge Request: 修改刀片刀杆样式

Created By: @黄焱
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @黄焱
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1999
2025-04-15 09:43:20 +08:00
hyyy
ba88070fad 修改刀片刀杆样式 2025-04-15 09:31:42 +08:00
马广威
3f940992be Accept Merge Request #1998: (feature/制造功能优化 -> develop)
Merge Request: 调整报告,增加稼动率接口(暂未调用)

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1998?initial=true
2025-04-14 17:24:04 +08:00
mgw
197ae6bc01 去掉基础数据 2025-04-14 17:22:27 +08:00
mgw
07336326ce 优化稼动率接口 2025-04-14 17:16:38 +08:00
mgw
c93553e78e 增加稼动率接口 2025-04-14 16:42:33 +08:00
mgw
91d79008e1 故障时长提取 2025-04-14 11:21:24 +08:00
禹翔辉
8cdf77f609 Accept Merge Request #1997: (feature/功能刀具组装初始化优化 -> develop)
Merge Request: 功能刀具组装自动根据BOM配置初始物料信息优化

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1997
2025-04-14 10:34:47 +08:00
yuxianghui
37edc858c2 1 2025-04-14 10:32:26 +08:00
yuxianghui
17fdf20e03 功能刀具组装自动根据BOM配置初始物料信息优化 2025-04-14 10:30:51 +08:00
胡尧
ec934abc42 Accept Merge Request #1996: (feature/6679 -> develop)
Merge Request: 给仓储岗增加修改工单的权限

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1996
2025-04-11 16:04:02 +08:00
胡尧
cc030957fb 给仓储岗增加修改工单的权限 2025-04-11 16:02:24 +08:00
mgw
87786dbd80 调整故障时长 2025-04-11 14:16:18 +08:00
禹翔辉
9d0ffd23b2 Accept Merge Request #1995: (feature/刀具组装扫描优化 -> develop)
Merge Request: 处理功能刀具组装时,有时扫描货位编码验证刀具信息扫不到货位的问题

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1995
2025-04-10 14:27:04 +08:00
yuxianghui
3fb56f15c8 处理功能刀具组装时,有时扫描货位编码验证刀具信息扫不到货位的问题 2025-04-10 14:24:25 +08:00
mgw
bdf4696c08 调整待完成工单明细 2025-04-09 16:56:53 +08:00
mgw
6c926bf081 调整质检取值 2025-04-09 16:39:21 +08:00
mgw
ddb0c304b9 修改字段路径 2025-04-09 15:57:13 +08:00
mgw
cf8c14e738 调整查询范围 2025-04-09 15:22:41 +08:00
黄焱
6bd6816495 Accept Merge Request #1994: (feature/前端样式修改 -> develop)
Merge Request: 功能刀具组装优化需求

Created By: @黄焱
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @黄焱
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1994?initial=true
2025-04-09 14:03:06 +08:00
hyyy
2bae98950e 功能刀具组装优化需求 2025-04-09 13:57:48 +08:00
胡尧
ec379a7541 Accept Merge Request #1993: (feature/6679 -> develop)
Merge Request: 增加不同工作中心配置相同接驳站的功能

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1993?initial=true
2025-04-08 17:08:20 +08:00
胡尧
119acf1543 Accept Merge Request #1992: (feature/6686 -> develop)
Merge Request: agv配置不可修改

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1992
2025-04-08 17:07:57 +08:00
禹翔辉
0f6f1aae24 Accept Merge Request #1991: (feature/功能刀具拆解优化_1 -> develop)
Merge Request: 将寿命到期拆解创建的组装单添加到对应安全库存组装单列表

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1991
2025-04-08 17:01:56 +08:00
yuxianghui
c40ecfb6ce 将寿命到期拆解创建的组装单添加到对应安全库存组装单列表 2025-04-08 17:00:00 +08:00
禹翔辉
a51a4c2fbb Accept Merge Request #1990: (feature/功能刀具拆解优化_1 -> develop)
Merge Request: 功能刀具拆解寿命到期刀具创建新的组装单时,添加几个参数的值。

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1990?initial=true
2025-04-08 15:59:04 +08:00
yuxianghui
315e2aa03d 功能刀具拆解寿命到期刀具创建新的组装单时,添加几个参数的值。 2025-04-08 15:56:08 +08:00
胡尧
10bea40159 增加不同工作中心配置相同接驳站的功能 2025-04-08 10:29:29 +08:00
马广威
78ba8d0ead Accept Merge Request #1989: (feature/制造功能优化 -> develop)
Merge Request: 调整报告页码

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1989
2025-04-08 10:11:41 +08:00
mgw
e61742cc5b Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2025-04-08 10:11:05 +08:00
mgw
d0d1a640d9 调整报告页码 2025-04-08 10:10:36 +08:00
禹翔辉
e613a2f283 Accept Merge Request #1987: (feature/功能刀具拆解优化 -> develop)
Merge Request: 新增对寿命未到期且位置在线边刀库的功能刀具进行拆解时,不直接报错,而是进行二次确认是否进行拆除。

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1987
2025-04-08 09:59:09 +08:00
马广威
88e83c0e14 Accept Merge Request #1988: (feature/制造功能优化 -> develop)
Merge Request: 调整报告产品取值

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1988
2025-04-08 09:48:48 +08:00
mgw
f912a81e7b 调整报告产品取值 2025-04-08 09:48:05 +08:00
yuxianghui
e09226e966 新增对寿命未到期且位置在线边刀库的功能刀具进行拆解时,不直接报错,而是进行二次确认是否进行拆除。 2025-04-08 09:44:46 +08:00
胡尧
8a7a90ff0d agv配置不可修改 2025-04-07 17:04:34 +08:00
黄焱
80f259651c Accept Merge Request #1986: (feature/前端样式修改 -> develop)
Merge Request: 修复没加引号字段

Created By: @黄焱
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @黄焱
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1986?initial=true
2025-04-02 09:05:31 +08:00
hyyy
1c57ee0be1 修复没加引号字段 2025-04-02 09:04:38 +08:00
黄焱
c732bbad62 Accept Merge Request #1984: (feature/前端样式修改 -> develop)
Merge Request: 还原代码

Created By: @黄焱
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @黄焱
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1984?initial=true
2025-04-02 08:54:03 +08:00
马广威
5285fcd066 Accept Merge Request #1985: (feature/制造功能优化 -> develop)
Merge Request: 零件名称调为可写

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1985?initial=true
2025-04-02 08:50:06 +08:00
mgw
d318d8cb32 零件名称调为可写 2025-04-02 08:49:24 +08:00
hyyy
5b9dc05653 还原代码 2025-04-02 08:48:27 +08:00
hyyy
a513592b21 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/前端样式修改 2025-04-02 08:36:23 +08:00
胡尧
e686ea9469 Accept Merge Request #1983: (feature/commercially_launched -> develop)
Merge Request: Merge branch 'develop' into feature/commercially_launched

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1983
2025-04-01 20:45:15 +08:00
胡尧
651918c51c Merge branch 'develop' into feature/commercially_launched 2025-04-01 20:42:36 +08:00
胡尧
7b13dfcc0e Accept Merge Request #1982: (feature/tool_standard_library_process -> develop)
Merge Request: 采购申请添加字段的翻译

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1982
2025-04-01 20:32:39 +08:00
liaodanlong
60e139d5e0 采购申请添加字段的翻译 2025-04-01 16:59:40 +08:00
胡尧
8d5ea0ae19 去掉采购申请不同补货组不能合并的检查 2025-04-01 11:07:08 +08:00
胡尧
d7597359ba 处理多个表面工艺,确认供货路线报错的问题 2025-03-31 16:50:50 +08:00
胡尧
f8309bfaba Merge branch 'develop' into feature/commercially_launched 2025-03-31 16:07:11 +08:00
胡尧
7ed756f922 修改报错翻译 2025-03-31 16:06:50 +08:00
禹翔辉
e837b84a50 Accept Merge Request #1981: (feature/调拨验证方法优化 -> develop)
Merge Request: 1、优化调拨单验证方法;2、隐藏请购明细列表视图字段

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1981
2025-03-31 15:57:51 +08:00
yuxianghui
e7cb100ab1 1、优化调拨单验证方法;2、隐藏请购明细列表视图字段 2025-03-31 15:55:37 +08:00
mgw
d00c9dd38c Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-31 13:02:30 +08:00
胡尧
1d857be16a 修改获取编程文件根目录 2025-03-31 09:28:30 +08:00
马广威
5914e4ca6e Accept Merge Request #1980: (feature/制造功能优化 -> develop)
Merge Request: 调整字段显隐

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1980?initial=true
2025-03-31 09:12:35 +08:00
mgw
d96970fb96 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2025-03-31 09:11:44 +08:00
mgw
0af9064fce 调整字段显隐 2025-03-31 09:11:21 +08:00
胡尧
21148ae74b 屏蔽sf获取编程文件的逻辑 2025-03-31 09:06:36 +08:00
胡尧
1a3590b6b6 屏蔽物流下单的按钮 2025-03-30 15:03:18 +08:00
胡尧
b55c6c1fe7 修改前置三元检测文件根目录 2025-03-30 11:16:40 +08:00
mgw
8c61dcac29 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-28 14:25:58 +08:00
马广威
41d4e9785f Accept Merge Request #1979: (feature/制造功能优化 -> develop)
Merge Request: 调整页脚布局

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1979?initial=true
2025-03-28 14:24:14 +08:00
mgw
5bf86930e9 调整页脚布局 2025-03-28 14:23:41 +08:00
mgw
7ad9885377 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-28 14:05:29 +08:00
mgw
71433c18b7 Merge branch 'feature/commercially_launched' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-28 14:03:21 +08:00
马广威
4b60ad307b Accept Merge Request #1978: (feature/制造功能优化 -> develop)
Merge Request: Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1978?initial=true
2025-03-28 14:02:11 +08:00
mgw
1a5c8e5f56 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2025-03-28 14:01:17 +08:00
mgw
8b1e12eb9f 质检报告优化 2025-03-28 14:00:55 +08:00
胡尧
dbf2257a88 Merge branch 'feature/commercially_launched' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-28 13:37:37 +08:00
胡尧
f34c01d1b0 解决表面工艺外协调拨单验证报错的问题 2025-03-28 13:37:29 +08:00
廖丹龙
9c73062593 Accept Merge Request #1977: (feature/tool_standard_library_process -> develop)
Merge Request: 产品加工面部代码还原

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1977?initial=true
2025-03-28 10:10:56 +08:00
liaodanlong
878fef18df 产品加工面部代码还原 2025-03-28 10:03:41 +08:00
liaodanlong
8348c4fc48 Merge branch 'refs/heads/develop' into feature/commercially_launched 2025-03-27 16:42:22 +08:00
廖丹龙
8643fb2385 Accept Merge Request #1976: (feature/tool_standard_library_process -> develop)
Merge Request: 子制造订单零件图号零件名称问题

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1976
2025-03-27 16:41:19 +08:00
liaodanlong
77744e75d7 子制造订单零件图号零件名称问题 2025-03-27 16:38:57 +08:00
胡尧
4cbcf08da8 销售单默认筛选供货方式待确认 2025-03-27 16:10:07 +08:00
mgw
af2a589679 添加翻译文件 2025-03-27 15:59:39 +08:00
胡尧
4b6f04aa9d 修改字段显示位置 2025-03-27 15:51:16 +08:00
廖丹龙
4634d43012 Accept Merge Request #1975: (feature/tool_standard_library_process -> develop)
Merge Request: 调试信息

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1975
2025-03-27 15:23:00 +08:00
liaodanlong
dd6e8b6707 调试信息 2025-03-27 15:21:15 +08:00
mgw
55337815c7 修改dashboard当日完成数据计算逻辑 2025-03-27 10:42:20 +08:00
廖丹龙
0ccb7cb3d1 Accept Merge Request #1974: (feature/tool_standard_library_process -> develop)
Merge Request: 子制造订单零件图号与零件名称获取方式修改

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1974
2025-03-26 17:24:40 +08:00
liaodanlong
d2155b17b4 Merge branch 'refs/heads/develop' into feature/tool_standard_library_process
# Conflicts:
#	sf_manufacturing/models/product_template.py
2025-03-26 17:01:13 +08:00
liaodanlong
11a5217430 子制造订单零件图号与零件名称获取方式修改 2025-03-26 16:57:47 +08:00
管欢
855e0eb1c2 Accept Merge Request #1973: (feature/零件图号筛选 -> develop)
Merge Request: 坯料冗余新增描述字段

Created By: @管欢
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @管欢
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1973
2025-03-26 14:50:07 +08:00
mgw
6312bb988a Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-25 15:04:15 +08:00
mgw
fe9548a0d1 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-25 14:08:06 +08:00
胡尧
0347eb48e4 销售订单行增加交期字段,销售订单列表默认值修改为供货方式待确认 2025-03-25 13:48:17 +08:00
mgw
0aae15cbce Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-25 13:32:55 +08:00
mgw
5a7d70fb6b Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-25 13:27:51 +08:00
mgw
8ea8bf1f48 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-25 10:40:48 +08:00
liaodanlong
df78019226 Merge remote-tracking branch 'origin/feature/commercially_launched' into feature/commercially_launched 2025-03-25 10:39:22 +08:00
liaodanlong
6ad945b720 产品加工面板空值处理 2025-03-25 10:39:02 +08:00
mgw
3285d4da57 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-25 10:35:00 +08:00
liaodanlong
60539462a0 报错处理 2025-03-25 10:02:39 +08:00
liaodanlong
81b425ae0c 调拨单零件图号零件名称处理 2025-03-24 17:28:16 +08:00
liaodanlong
33fabc068a 报错处理 2025-03-24 16:06:11 +08:00
liaodanlong
db4dd33709 报错处理 2025-03-24 15:54:59 +08:00
liaodanlong
4acb0fa0ba Merge branch 'refs/heads/develop' into feature/commercially_launched 2025-03-24 15:39:26 +08:00
胡尧
c5ad94c5f3 Merge branch 'develop' into feature/commercially_launched 2025-03-24 14:56:16 +08:00
胡尧
43c6686240 Merge branch 'develop' into feature/commercially_launched 2025-03-24 14:29:47 +08:00
mgw
5c35eae859 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-24 14:03:21 +08:00
mgw
fde28bed8a Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-24 13:54:14 +08:00
mgw
16ae845ad9 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-24 13:41:39 +08:00
胡尧
e10648ad07 Merge branch 'develop' into feature/commercially_launched 2025-03-24 11:13:48 +08:00
mgw
d2b02bb6f7 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-24 11:03:07 +08:00
胡尧
0e1c44c3ac Merge branch 'develop' into feature/commercially_launched 2025-03-24 09:56:19 +08:00
胡尧
5ffbe4c6fc Merge branch 'feature/commercially_launched' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-24 09:00:22 +08:00
胡尧
5ae167c133 去掉取消自动加工原因 2025-03-24 09:00:16 +08:00
mgw
0702e1dd51 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-21 18:26:58 +08:00
mgw
e861897527 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-21 18:18:29 +08:00
胡尧
3bb909c2ee Merge branch 'develop' into feature/commercially_launched 2025-03-21 15:39:56 +08:00
胡尧
da19b86bf5 Merge branch 'develop' into feature/commercially_launched 2025-03-21 15:29:49 +08:00
胡尧
dc318769af Merge branch 'develop' into feature/commercially_launched 2025-03-21 15:13:28 +08:00
mgw
311b95bca5 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-21 13:18:22 +08:00
胡尧
80118b61c2 Merge branch 'develop' into feature/commercially_launched 2025-03-21 11:24:02 +08:00
mgw
94d0c14e1f Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-20 16:23:01 +08:00
mgw
3f6f9bb709 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-20 15:44:11 +08:00
mgw
49a1ec353a Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-20 08:49:47 +08:00
mgw
b89cfb899b Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 15:44:21 +08:00
胡尧
0ff0cc5fbd Merge branch 'develop' into feature/commercially_launched 2025-03-19 15:41:51 +08:00
mgw
37173968fd Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 13:18:42 +08:00
mgw
470482b7e2 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 13:06:52 +08:00
mgw
5b51cc3de4 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 12:55:23 +08:00
mgw
9e939467e5 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 11:35:27 +08:00
mgw
b05492615f Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 11:23:49 +08:00
mgw
32ed0e9693 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 11:18:28 +08:00
mgw
623ebe3ec3 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 11:09:16 +08:00
mgw
da06688571 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 11:02:40 +08:00
mgw
c01451336d Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 10:24:26 +08:00
mgw
2db5068e85 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-19 10:06:52 +08:00
mgw
c955953335 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-18 16:51:19 +08:00
mgw
9220c4b7c4 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-18 16:42:51 +08:00
mgw
70b21c607e Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-18 16:31:48 +08:00
胡尧
4fe7300ec0 Merge branch 'develop' into feature/commercially_launched 2025-03-18 15:56:19 +08:00
mgw
282458c945 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-18 13:45:19 +08:00
胡尧
f6e87493d3 Merge branch 'develop' into feature/commercially_launched 2025-03-18 11:28:23 +08:00
mgw
e141f0af2c Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-18 10:41:01 +08:00
mgw
4618c83b2f Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-18 09:45:00 +08:00
mgw
e89400f04e Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/commercially_launched 2025-03-18 09:18:47 +08:00
胡尧
051f8128e9 Merge branch 'develop' into feature/commercially_launched 2025-03-17 15:05:47 +08:00
胡尧
8f61f258b1 解决冲突 2025-03-14 16:08:37 +08:00
胡尧
a864845d2b 解决销售订单form中,tree内显示模型的问题 2025-03-14 16:06:33 +08:00
胡尧
a6a2e53111 Merge branch 'develop' into feature/commercially_launched 2025-03-14 13:52:18 +08:00
胡尧
a11329eaf8 Merge branch 'develop' into feature/commercially_launched 2025-03-13 14:51:21 +08:00
胡尧
d571b77915 修改工单新模型显示 2025-03-13 14:50:26 +08:00
胡尧
24897f07f8 获取编程单,不传递模型参数 2025-03-13 13:58:13 +08:00
胡尧
53779b89a7 Merge branch 'develop' into feature/commercially_launched 2025-03-13 13:06:26 +08:00
胡尧
a1a94867f0 Merge branch 'develop' into feature/commercially_launched 2025-03-13 11:34:17 +08:00
胡尧
0a666f568d 解决待发货获取不到模型名字的问题 2025-03-13 10:52:14 +08:00
胡尧
ad8ec770b6 Merge branch 'develop' into feature/commercially_launched 2025-03-13 09:17:33 +08:00
胡尧
3cc3c48ab3 Merge branch 'develop' into feature/commercially_launched 2025-03-13 08:47:59 +08:00
胡尧
f5da36a82c 修改销售订单模型显示 2025-03-12 17:26:19 +08:00
胡尧
da489555b0 去掉多余的字段 2025-03-12 17:17:21 +08:00
胡尧
29337bfceb 调整模型显示 2025-03-12 17:05:29 +08:00
hyyy
ef0d05a29d Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/前端样式修改 2025-03-11 13:29:19 +08:00
胡尧
b8bec37e15 Merge branch 'develop' into feature/commercially_launched 2025-03-11 09:06:43 +08:00
胡尧
dedc820b50 Merge branch 'develop' into feature/commercially_launched 2025-03-10 16:31:35 +08:00
胡尧
2ccedc95f2 Merge branch 'feature/mrp_bug_fixed' into feature/commercially_launched 2025-03-06 16:24:36 +08:00
胡尧
b276f616e5 成品供应商默认取模板中最后一个 2025-03-06 14:03:31 +08:00
胡尧
cb645aa1b9 增加自动化产线的零件供货路线初始化为自动化产线加工 2025-03-06 13:59:14 +08:00
胡尧
2409dab8b0 增加非自动化原因 2025-03-05 14:27:41 +08:00
胡尧
e8fc38e6ed Merge branch 'develop' into feature/commercially_launched 2025-03-04 09:32:07 +08:00
胡尧
52e585e637 解决冲突 2025-02-20 13:51:24 +08:00
胡尧
05dac9fb0c 调整模型上传的流程 2025-02-20 13:36:05 +08:00
57 changed files with 18496 additions and 228 deletions

View File

@@ -1,6 +1,6 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_request
# * jikimo_purchase_request
#
# Translators:
# Jeffery Chen Fan <jeffery9@gmail.com>, 2016
@@ -614,7 +614,7 @@ msgstr "手动开票"
#. module: purchase_request
#: model:ir.model.fields,field_description:purchase_request.field_purchase_request_line_make_purchase_order__sync_data_planned
msgid "Match existing PO lines by Scheduled Date"
msgstr ""
msgstr "仅匹配计划日期相同的采购订单行"
#. module: purchase_request
#: model:ir.model.fields,field_description:purchase_request.field_purchase_request__message_has_error
@@ -862,7 +862,7 @@ msgstr "采购申请 %s 已完成"
#: code:addons/purchase_request/wizard/purchase_request_line_make_purchase_order.py:0
#, python-format
msgid "Purchase Request %s is not approved or in progress"
msgstr "采购申请 %s 未获批准或进行中"
msgstr "采购申请 %s 状态非已批准或进行中"
#. module: purchase_request
#: model:ir.model,name:purchase_request.model_purchase_request_allocation

View File

@@ -2,7 +2,7 @@
<record id="view_purchase_request_form_sf" model="ir.ui.view">
<field name="name">purchase.request.sf.form</field>
<field name="model">purchase.request</field>
<field name="inherit_id" ref="purchase_request.view_purchase_request_form" />
<field name="inherit_id" ref="purchase_request.view_purchase_request_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='button_draft']" position="attributes">
<attribute name="string">重置草稿</attribute>
@@ -21,19 +21,20 @@
<record id="view_purchase_request_line_tree_sf" model="ir.ui.view">
<field name="name">purchase.request.line.sf.tree</field>
<field name="model">purchase.request.line</field>
<field name="inherit_id" ref="purchase_request.purchase_request_line_tree" />
<field name="inherit_id" ref="purchase_request.purchase_request_line_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='requested_by']" position="replace">
<field name="supply_method"/>
</xpath>
<xpath expr="//field[@name='assigned_to']" position="replace">
<xpath expr="//field[@name='assigned_to']" position="attributes">
<attribute name="invisible">True</attribute>
</xpath>
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="invisible">True</attribute>
</xpath>
<xpath expr="//field[@name='supplier_id']" position="after">
<field name="requested_by" widget="many2one_avatar_user"/>
<field name="assigned_to" widget="many2one_avatar_user"/>
<field name="assigned_to" widget="many2one_avatar_user" invisible="1"/>
</xpath>
<xpath expr="//field[@name='purchased_qty']" position="attributes">
<attribute name="string">采购数量</attribute>
@@ -44,7 +45,7 @@
<xpath expr="//field[@name='product_id']" position="after">
<field name="related_product"/>
<field name="part_number"/>
<field name="part_name"/>
<field name="part_name" invisible="1"/>
</xpath>
</field>
</record>
@@ -52,7 +53,7 @@
<record id="view_purchase_request_line_search_sf" model="ir.ui.view">
<field name="name">purchase.request.line.sf.search</field>
<field name="model">purchase.request.line</field>
<field name="inherit_id" ref="purchase_request.purchase_request_line_search" />
<field name="inherit_id" ref="purchase_request.purchase_request_line_search"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='product_id']" position="after">
<field name="supply_method"/>

View File

@@ -87,6 +87,20 @@ class PurchaseRequestLineMakePurchaseOrder(models.TransientModel):
"type": "ir.actions.act_window",
}
def _check_valid_request_line(self, request_line_ids):
for line in self.env["purchase.request.line"].browse(request_line_ids):
if line.request_id.state not in ["approved", "in_progress"]:
raise UserError(
_("采购申请 %s 未审批或未进行中")
% line.request_id.name
)
super(PurchaseRequestLineMakePurchaseOrder, self)._check_valid_request_line(request_line_ids)
@api.model
def check_group(self, request_lines):
# 去掉合并必须同一采购组的限制
pass
class PurchaseRequestLineMakePurchaseOrderItem(models.TransientModel):
_inherit = "purchase.request.line.make.purchase.order.item"

File diff suppressed because it is too large Load Diff

View File

@@ -9,5 +9,6 @@ class MrpBom(models.Model):
# 成品的供应商从模板中获取
if product_type == 'product':
bom_id.subcontractor_id = product.product_tmpl_id.seller_ids.partner_id.id
if product.product_tmpl_id.seller_ids:
bom_id.subcontractor_id = product.product_tmpl_id.seller_ids[-1].partner_id.id
return bom_id

View File

@@ -130,7 +130,7 @@ class QualityPoint(models.Model):
class QualityCheck(models.Model):
_inherit = "quality.check"
part_name = fields.Char('零件名称', related='product_id.part_name')
part_name = fields.Char('零件名称', related='product_id.part_name', readonly=False, store=True)
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=False, store=True)
material_name = fields.Char('材料名称', compute='_compute_material_name')
@@ -206,7 +206,15 @@ class QualityCheck(models.Model):
('NG', 'NG')
], string='出厂检验报告结果', default='OK')
measure_operator = fields.Many2one('res.users', string='操机员')
quality_manager = fields.Many2one('res.users', string='质检员')
quality_manager = fields.Many2one('res.users', string='质检员', compute='_compute_quality_manager')
@api.depends('measure_line_ids')
def _compute_quality_manager(self):
for record in self:
if record.measure_line_ids:
record.quality_manager = record.env.user.id
else:
record.quality_manager = False
# 流水号(从1开始最大99)
serial_number = fields.Integer('流水号', default=1, readonly=True)
@@ -336,7 +344,6 @@ class QualityCheck(models.Model):
# 7. 更新其他信息
self.serial_number += 1
self.quality_manager = self.env.user.id
if self.publish_status == 'canceled' and self.picking_id.state == 'done':
self.upload_factory_report()

View File

@@ -5,7 +5,7 @@
<field name="model">quality.check.measure.line</field>
<field name="arch" type="xml">
<tree editable="bottom" class="measureTable">
<field name="sequence" class="measureTableSequence"/>
<!-- <field name="sequence" class="measureTableSequence"/> -->
<!-- <field name="column_nums"/> -->
<field name="measure_item"/>
<field name="measure_value1" attrs="{ 'column_invisible': [('parent.column_nums', '&lt;', 1)] }"/>

View File

@@ -267,13 +267,13 @@
<field name="company_id" invisible="1"/>
<field name="categ_type" invisible="1"/>
<field name="product_id" attrs="{'invisible' : [('measure_on', '=', 'operation')]}"/>
<field name="part_name" attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<field name="part_name" attrs="{'invisible': [('categ_type', '!=', '成品')], 'readonly': [('publish_status', '=', 'published')]}"/>
<field name="part_number" attrs="{'invisible': [('categ_type', '!=', '成品')], 'readonly': [('publish_status', '=', 'published')]}"/>
<field name="material_name" attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<field name="total_qty" attrs="{'invisible': ['|', ('measure_on', '!=', 'product'), ('is_out_check', '=', False)]}"/>
<field name="check_qty" attrs="{'invisible': [('measure_on', '!=', 'product')], 'readonly': [('publish_status', '=', 'published')]}"/>
<field name="check_qty" attrs="{'invisible': ['|', ('measure_on', '!=', 'product'), ('is_out_check', '=', False)], 'readonly': [('publish_status', '=', 'published')]}"/>
<!-- <field name="categ_type"/> -->
<field name="report_number_id"/>
<field name="report_number_id" attrs="{'invisible': ['|', ('measure_on', '!=', 'product'), ('is_out_check', '=', False)]}"/>
<field name="column_nums" invisible="1"/>
<field name="publish_status" invisible="1"/>
<field name="show_lot_text" invisible="1"/>
@@ -320,7 +320,7 @@
<field name="team_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="user_id" string="Control Person" invisible="1"/>
<field name="measure_operator" string="操机员" attrs="{'readonly': [('publish_status', '=', 'published')]}"/>
<field name="measure_operator" string="操机员" attrs="{'invisible': ['|', ('measure_on', '!=', 'product'), ('is_out_check', '=', False)], 'readonly': [('publish_status', '=', 'published')]}"/>
</group>
</group>

View File

@@ -65,7 +65,7 @@
<field name="lot_id" position="after">
<field name="workorder_id" invisible="1"/>
<field name="production_id" invisible="1"/>
<field name="finished_lot_id" attrs="{'invisible': [('finished_lot_id', '=', False)]}" groups="stock.group_production_lot"/>
<!-- <field name="finished_lot_id" attrs="{'invisible': [('finished_lot_id', '=', False)]}" groups="stock.group_production_lot"/> -->
</field>
<xpath expr="//field[@name='lot_id']" position="after">
<field name="lot_id" attrs="{'invisible': [('workorder_id', '=', False)]}" groups="stock.group_production_lot" string="Component Lot/Serial"/>

View File

@@ -32,6 +32,7 @@ class FixtureModel(models.Model):
multi_mounting_type_id = fields.Many2one('sf.multi_mounting.type', string="联装类型")
brand_id = fields.Many2one('sf.machine.brand', string="品牌")
model_file = fields.Binary(string="图片")
glb_url = fields.Char(string="图片")
status = fields.Boolean('状态')
active = fields.Boolean('有效', default=False)

View File

@@ -158,6 +158,8 @@
<!-- <field name="upload_model_file" widget="many2many_binary"/>-->
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': [('model_file', '=', False)]}"/>
<field name="glb_url" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': [('glb_url', '=', False)]}"/>
</group>
</group>
<notebook>

View File

@@ -29,7 +29,7 @@ class Sf_Bf_Connect(http.Controller):
bfm_process_order_list = json.loads(kw['bfm_process_order_list'])
order_id = request.env['sale.order'].with_user(request.env.ref("base.user_admin")).sale_order_create(
company_id, kw['delivery_name'], kw['delivery_telephone'], kw['delivery_address'],
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'])
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], model_display_version=kw.get('model_display_version'))
i = 1
# 给sale_order的default_code字段赋值
aa = request.env['sale.order'].sudo().search([('name', '=', order_id.name)])

View File

@@ -32,7 +32,7 @@
<field name="is_bill" invisible="True"/>
<field name="logistics_status" invisible="True"/>
<field name="logistics_way" invisible="True"/>
<button string="物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"
<!-- <button string="物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary" -->
attrs="{'invisible': ['|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('is_bill', '=', True), ('logistics_way', '=', '自提')]}"/>
<button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"
attrs="{'invisible': ['|', '|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('logistics_status', '=', '2'), ('is_bill', '=', False), ('logistics_way', '=', '自提')]}"/>

View File

@@ -44,7 +44,7 @@ class ResProductTemplate(models.Model):
else:
return self.env.ref('sf_dlm.product_uom_cubic_millimeter')
# model_file = fields.Binary('模型文件')
model_file = fields.Binary('模型文件')
# 胚料的库存路线设置
# def _get_routes(self, route_type):

View File

@@ -16,15 +16,21 @@
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name='is_bfm' invisible="1"/>
<field name='categ_type' invisible="1"/>
<field name='glb_url' invisible="1"/>
<field name='part_name' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
<field name='manual_quotation' attrs="{'invisible':[('glb_url', '=', False)]}"/>
<field name="is_customer_provided" attrs="{'invisible': [('categ_type', 'not in', ['成品', '坯料'])], 'readonly': True}" />
<field name="upload_model_file"
widget="many2many_binary"
attrs="{'invisible': ['|', '|',('categ_type', '!=', '成品'),('categ_type', '=', False),('is_bfm','=', True)]}"/>
<field name="model_name" invisible="1"/>
<field name="upload_model_file" widget="many2many_binary" attrs="{'invisible': [('upload_model_file', '=', False)]}"/>
<field name="model_url"
widget="binary_download"
filename_field="model_name"
attrs="{'invisible': ['|', '|',('categ_type', '!=', '成品'),('categ_type', '=', False),('model_url', '=', False)]}"/>
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': ['|','|', ('categ_type', '!=', '成品'),('categ_type', '=', False),('model_file', '=', False)]}"/>
<field name="glb_url" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': ['|','|', ('categ_type', '!=', '成品'),('categ_type', '=', False),('glb_url', '=', False)]}"/>
<field name='cutting_tool_type' invisible="1"/>
<field name="fixture_material_type" invisible="1"/>
<field name="embryo_model_type_id" string="模型类型" options="{'no_create': True}"
@@ -68,6 +74,7 @@
</field>
<xpath expr="//field[@name='uom_id']" position="before">
<field name="is_manual_processing" attrs="{'invisible': [('categ_type', 'not in', ['成品', '坯料'])], 'readonly': True}" />
<field name="auto_machining" attrs="{'invisible': [('categ_type', 'not in', ['成品', '坯料'])], 'readonly': True}" />
</xpath>
<xpath expr="//label[@for='volume']" position="before">
<label for="length" string="尺寸"

View File

@@ -5,7 +5,7 @@ import json
import base64
import logging
import psycopg2
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from odoo import http, fields
from odoo.http import request
@@ -414,7 +414,7 @@ class Sf_Dashboard_Connect(http.Controller):
# 工单计划量切换为CNC工单
plan_data_total_counts = work_order_obj.search_count(
[('production_id.production_line_id.name', '=', line),
[('production_line_id.name', '=', line), ('id', '!=', 8061),
('state', 'in', ['ready', 'progress', 'done']), ('routing_type', '=', 'CNC加工')])
# # 工单完成量
@@ -423,13 +423,13 @@ class Sf_Dashboard_Connect(http.Controller):
# 工单完成量切换为CNC工单
plan_data_finish_counts = work_order_obj.search_count(
[('production_id.production_line_id.name', '=', line),
[('production_line_id.name', '=', line),
('state', 'in', ['done']), ('routing_type', '=', 'CNC加工')])
# 超期完成量
# 搜索所有已经完成的工单
plan_data_overtime = work_order_obj.search([
('production_id.production_line_id.name', '=', line),
('production_line_id.name', '=', line),
('state', 'in', ['done']),
('routing_type', '=', 'CNC加工')
])
@@ -448,9 +448,14 @@ class Sf_Dashboard_Connect(http.Controller):
])
# 过滤出那些检测结果状态为 '返工' 或 '报废' 的记录
faulty_plans = plan_data.filtered(lambda p: any(
result.test_results in ['返工', '报废'] for result in p.production_id.detection_result_ids
))
# faulty_plans = plan_data.filtered(lambda p: any(
# result.test_results in ['返工', '报废'] for result in p.production_id.detection_result_ids
# ))
faulty_plans = request.env['quality.check'].sudo().search([
('operation_id.name', '=', 'CNC加工'),
('quality_state', 'in', ['fail'])
])
# 查找制造订单取消与归档的数量
cancel_order_count = production_obj.search_count(
@@ -567,7 +572,7 @@ class Sf_Dashboard_Connect(http.Controller):
"""
res = {'status': 1, 'message': '成功', 'data': {}}
# plan_obj = request.env['sf.production.plan'].sudo()
plan_obj = request.env['mrp.production'].sudo()
# plan_obj = request.env['mrp.workorder'].sudo().search([('routing_type', '=', 'CNC加工')])
line_list = ast.literal_eval(kw['line_list'])
begin_time_str = kw['begin_time'].strip('"')
end_time_str = kw['end_time'].strip('"')
@@ -617,11 +622,19 @@ class Sf_Dashboard_Connect(http.Controller):
for time_interval in time_intervals:
start_time, end_time = time_interval
orders = plan_obj.search([
# orders = plan_obj.search([
# ('production_line_id.name', '=', line),
# ('state', 'in', ['done']),
# (date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')),
# (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间
# ])
orders = request.env['mrp.workorder'].sudo().search([
('routing_type', '=', 'CNC加工'), # 将第一个条件合并进来
('production_line_id.name', '=', line),
('state', 'in', ['done']),
(date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')),
(date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间
(date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S'))
])
# 使用小时和分钟作为键,确保每个小时的数据有独立的键
@@ -638,18 +651,22 @@ class Sf_Dashboard_Connect(http.Controller):
for date in date_list:
next_day = date + timedelta(days=1)
orders = plan_obj.search([('production_line_id.name', '=', line), ('state', 'in', ['done']),
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
])
rework_orders = plan_obj.search(
[('production_line_id.name', '=', line), ('state', 'in', ['rework']),
orders = request.env['mrp.workorder'].sudo().search(
[('production_id.production_line_id.name', '=', line), ('state', 'in', ['done']),
('routing_type', '=', 'CNC加工'),
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
])
not_passed_orders = plan_obj.search(
[('production_line_id.name', '=', line), ('state', 'in', ['scrap', 'cancel']),
rework_orders = request.env['mrp.workorder'].sudo().search(
[('production_id.production_line_id.name', '=', line), ('state', 'in', ['rework']),
('routing_type', '=', 'CNC加工'),
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
])
not_passed_orders = request.env['mrp.workorder'].sudo().search(
[('production_id.production_line_id.name', '=', line), ('state', 'in', ['scrap', 'cancel']),
('routing_type', '=', 'CNC加工'),
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
])
@@ -751,11 +768,14 @@ class Sf_Dashboard_Connect(http.Controller):
for line in line_list:
# 未完成订单
not_done_orders = plan_obj.search(
[('production_line_id.name', '=', line), ('state', 'not in', ['finished']),
('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True)
# not_done_orders = plan_obj.search(
# [('production_line_id.name', '=', line), ('state', 'not in', ['finished']),
# ('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True)
# ])
not_done_orders = request.env['mrp.workorder'].sudo().search(
[('production_line_id.name', '=', line), ('state', 'in', ['ready', 'progress']),
('routing_type', '=', 'CNC加工')
])
# print(not_done_orders)
# 完成订单
# 获取当前时间并计算24小时前的时间
@@ -807,16 +827,18 @@ class Sf_Dashboard_Connect(http.Controller):
'draft': '待排程',
'done': '已排程',
'processing': '生产中',
'finished': '已完成'
'finished': '已完成',
'ready': '待加工',
'progress': '生产中',
}
line_dict = {
'sequence': id_to_sequence[order.id],
'workorder_name': order.name,
'workorder_name': order.production_id.name,
'blank_name': blank_name,
'material': material,
'dimensions': dimensions,
'order_qty': order.product_qty,
'order_qty': 1,
'state': state_dict[order.state],
}
@@ -897,15 +919,17 @@ class Sf_Dashboard_Connect(http.Controller):
cur.execute(sql2, (item,))
result2 = cur.fetchall()
# print('result2========', result2)
#
for row in result:
res['data'][item] = {'idle_count': row[0]}
alarm_count = []
for row in result2:
alarm_count.append(row[1])
if row[0]:
total_alarm_time += abs(float(row[0]))
if float(row[0]) >= 28800:
continue
# total_alarm_time += abs(float(row[0]))
total_alarm_time += float(row[0])
else:
total_alarm_time += 0.0
if len(list(set(alarm_count))) == 1:
@@ -915,6 +939,7 @@ class Sf_Dashboard_Connect(http.Controller):
alarm_count_num = 1
else:
alarm_count_num = len(list(set(alarm_count)))
res['data'][item]['total_alarm_time'] = total_alarm_time / 3600
res['data'][item]['alarm_count_num'] = alarm_count_num
@@ -942,7 +967,7 @@ class Sf_Dashboard_Connect(http.Controller):
# machine_list = ast.literal_eval(kw['machine_list'])
# for item in machine_list:
# machine_data = equipment_obj.search([('code', '=', item)])
for log in maintenance_logs_obj.search([]):
for log in maintenance_logs_obj.search([], order='id desc', limit=30):
res['data'].append({
'name': log.name,
'alarm_time': log.alarm_time.strftime('%Y-%m-%d %H:%M:%S'),
@@ -1332,7 +1357,7 @@ class Sf_Dashboard_Connect(http.Controller):
for result in results:
alarm_last_24_nums.append(result[1])
if result[0]:
if float(result[0]) >= 1000:
if float(result[0]) >= 28800:
continue
alarm_last_24_time += float(result[0])
else:
@@ -1350,7 +1375,7 @@ class Sf_Dashboard_Connect(http.Controller):
for result in results:
alarm_all_nums.append(result[1])
if result[0]:
if float(result[0]) >= 1000:
if float(result[0]) >= 28800:
continue
alarm_all_time += float(result[0])
else:
@@ -1385,3 +1410,207 @@ class Sf_Dashboard_Connect(http.Controller):
conn.close()
return json.dumps(res)
@http.route('/api/utilization/rate', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
def UtilizationRate(self, **kw):
"""
获取稼动率
"""
logging.info("kw=:%s" % kw)
res = {'status': 1, 'message': '成功', 'data': {}}
# 获取请求的机床数据
machine_list = ast.literal_eval(kw['machine_list'])
line = kw['line']
orders = request.env['mrp.workorder'].sudo().search([
('routing_type', '=', 'CNC加工'), # 将第一个条件合并进来
('production_line_id.name', '=', line),
('state', 'in', ['done'])
])
faulty_plans = request.env['quality.check'].sudo().search([
('operation_id.name', '=', 'CNC加工'),
('quality_state', 'in', ['fail'])
])
# 计算时间范围
now = datetime.now()
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
total_power_on_time = 0
month_power_on_time = 0
today_power_on_time = 0
today_power_on_dict = {}
today_data = []
month_data = []
today_check_ng = []
month_check_ng = []
total_alarm_time = 0
today_alarm_time = 0
month_alarm_time = 0
for order in orders:
time = datetime.strptime(order.date_finished, "%Y-%m-%d %H:%M:%S")
if time >= today_start:
today_data.append(order)
if time >= month_start:
month_data.append(order)
for faulty_plan in faulty_plans:
time = faulty_plan.write_date
if time >= today_start:
today_check_ng.append(faulty_plan)
if time >= month_start:
month_check_ng.append(faulty_plan)
# 连接数据库
conn = psycopg2.connect(**db_config)
for item in machine_list:
with conn.cursor() as cur:
cur.execute("""
(
SELECT power_on_time, 'latest' AS record_type
FROM device_data
WHERE device_name = %s
AND power_on_time IS NOT NULL
ORDER BY time DESC
LIMIT 1
)
UNION ALL
(
SELECT power_on_time, 'month_first' AS record_type
FROM device_data
WHERE device_name = %s
AND power_on_time IS NOT NULL
AND time >= date_trunc('month', CURRENT_DATE) -- ✅ 修复日期函数
AND time < (date_trunc('month', CURRENT_DATE) + INTERVAL '1 month')::date
ORDER BY time ASC
LIMIT 1
)
UNION ALL
(
SELECT power_on_time, 'day_first' AS record_type
FROM device_data
WHERE device_name = %s
AND power_on_time IS NOT NULL
AND time::date = CURRENT_DATE -- ✅ 更高效的写法
ORDER BY time ASC
LIMIT 1
);
""", (item, item, item))
results = cur.fetchall()
print(results)
if len(results) >= 1:
total_power_on_time += convert_to_seconds(results[0][0])
else:
total_power_on_time += 0
if len(results) >= 2:
month_power_on_time += convert_to_seconds(results[1][0])
else:
month_power_on_time += 0
if len(results) >= 3:
today_power_on_time += convert_to_seconds(results[2][0])
today_power_on_dict[item] = today_power_on_time
else:
today_power_on_time += 0
print(total_power_on_time, month_power_on_time, today_power_on_time)
with conn.cursor() as cur:
cur.execute("""
SELECT DISTINCT ON (alarm_start_time) alarm_time, alarm_start_time
FROM device_data
WHERE device_name = %s AND alarm_start_time IS NOT NULL
ORDER BY alarm_start_time, time;
""", (item,))
results = cur.fetchall()
today_data = []
month_data = []
for record in results:
if record[0]:
if float(record[0]) >= 28800:
continue
total_alarm_time += float(record[0])
else:
total_alarm_time += 0.0
alarm_start = datetime.strptime(record[1], "%Y-%m-%d %H:%M:%S")
if alarm_start >= today_start:
today_data.append(record)
if alarm_start >= month_start:
month_data.append(record)
for today in today_data:
if today[0]:
if float(today[0]) >= 28800:
continue
today_alarm_time += float(today[0])
else:
today_alarm_time += 0.0
for month in month_data:
if month[0]:
if float(month[0]) >= 28800:
continue
month_alarm_time += float(month[0])
else:
month_alarm_time += 0.0
conn.close()
print('报警时间=============', total_alarm_time, month_alarm_time, today_alarm_time)
logging.info("报警时间=%s" % total_alarm_time)
logging.info("报警时间=%s" % month_alarm_time)
logging.info("报警时间=%s" % today_alarm_time)
# 计算时间开动率(累计、月、日)
if total_power_on_time:
total_power_on_rate = (total_power_on_time - total_alarm_time) / total_power_on_time
else:
total_power_on_rate = 0
if month_power_on_time:
month_power_on_rate = (total_power_on_time - month_power_on_time - month_alarm_time) / month_power_on_time
else:
month_power_on_rate = 0
if today_power_on_time:
today_power_on_rate = (total_power_on_time - today_power_on_time - today_alarm_time) / today_power_on_time
else:
today_power_on_rate = 0
print("总开动率: %s" % total_power_on_rate)
print("月开动率: %s" % month_power_on_rate)
print("日开动率: %s" % today_power_on_rate)
# 计算性能开动率(累计、月、日)
print('===========',orders)
print(len(orders))
total_performance_rate = len(orders) * 30 * 60 / (total_power_on_time - total_alarm_time)
month_performance_rate = len(month_data) * 30 * 60 / (month_power_on_time - month_alarm_time)
today_performance_rate = len(today_data) * 30 * 60 / (today_power_on_time - today_alarm_time) if today_power_on_time != 0 else 0
print("总性能率: %s" % total_performance_rate)
print("月性能率: %s" % month_performance_rate)
print("日性能率: %s" % today_performance_rate)
# 计算累计合格率
total_pass_rate = (len(orders) - len(today_check_ng)) / len(orders) if len(orders) != 0 else 0
month_pass_rate = (len(month_data) - len(month_check_ng)) / len(month_data) if len(month_data) != 0 else 0
today_pass_rate = (len(today_data) - len(today_check_ng)) / len(today_data) if len(today_data) != 0 else 0
print("总合格率: %s" % total_pass_rate)
print("月合格率: %s" % month_pass_rate)
print("日合格率: %s" % today_pass_rate)
# # 返回数据
# res['data'][item] = {
# 'total_utilization_rate': total_power_on_rate * total_performance_rate * total_pass_rate,
# 'month_utilization_rate': month_power_on_rate * month_performance_rate * month_pass_rate,
# 'today_utilization_rate': today_power_on_rate * today_performance_rate * today_pass_rate,
# }
res['data'] = {
'total_utilization_rate': total_power_on_rate * total_performance_rate * total_pass_rate,
'month_utilization_rate': month_power_on_rate * month_performance_rate * month_pass_rate,
'today_utilization_rate': today_power_on_rate * today_performance_rate * today_pass_rate,
}
return json.dumps(res)

View File

@@ -27,7 +27,8 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
bfm_process_order_list = json.loads(kw['bfm_process_order_list'])
order_id = request.env['sale.order'].with_user(request.env.ref("base.user_admin")).sale_order_create(
company_id, kw['delivery_name'], kw['delivery_telephone'], kw['delivery_address'],
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], kw['order_number'], state='draft')
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], kw['order_number'], state='draft',
model_display_version=kw.get('model_display_version'))
i = 1
# 给sale_order的default_code字段赋值
# aa = request.env['sale.order'].sudo().search([('name', '=', order_id.name)])

View File

@@ -87,11 +87,12 @@ class AgvScheduling(models.Model):
agv_route_type: AGV任务类型
workorders: 工单
"""
scheduling = None
_logger.info('创建AGV调度任务\r\n起点为【%s】,任务类型为【%s】,工单为【%s' % (agv_start_site_name, agv_route_type, workorders))
if not workorders:
raise UserError(_('工单不能为空'))
agv_start_site = self.env['sf.agv.site'].sudo().search([('name', '=', agv_start_site_name)], limit=1)
if not agv_start_site:
agv_start_sites = self.env['sf.agv.site'].sudo().search([('name', '=', agv_start_site_name)])
if not agv_start_sites:
raise UserError(_('不存在名称为【%s】的接驳站,请先创建!' % agv_start_site_name))
# 如果存在相同任务类型工单的AGV调度任务则提示错误
agv_scheduling = self.sudo().search([
@@ -107,24 +108,32 @@ class AgvScheduling(models.Model):
(','.join(repetitive_workorders.mapped('production_id.name')), agv_scheduling.name)
)
# 如果只有唯一任务路线,则自动赋予终点接驳站跟任务名称
agv_routes = self.env['sf.agv.task.route'].sudo().search([
('route_type', '=', agv_route_type),
('start_site_id', 'in', agv_start_sites.ids)
])
vals = {
'start_site_id': agv_start_site.id,
'agv_route_type': agv_route_type,
'workorder_ids': workorders.ids,
# 'workpiece_delivery_ids': deliveries.mapped('id') if deliveries else [],
'task_create_time': fields.Datetime.now()
}
# 如果只有唯一任务路线,则自动赋予终点接驳站跟任务名称
agv_routes = self.env['sf.agv.task.route'].sudo().search([
('route_type', '=', agv_route_type),
('start_site_id', '=', agv_start_site.id)
])
if not agv_routes:
raise UserError(_('不存在起点为【%s】的【%s】任务路线,请先创建!' % (agv_start_site_name, agv_route_type)))
# 如果路线中包含起点与终点相同的接驳站则不创建AGV调度任务
if agv_routes.filtered(lambda r: r.start_site_id.name == r.end_site_id.name):
return True
# 配送类型相同的接驳站为同一个,取第一个即可
vals.update({
'start_site_id': agv_routes[0].start_site_id.id,
})
idle_route = None
if len(agv_routes) == 1:
idle_route = agv_routes[0]
vals.update({'end_site_id': idle_route.end_site_id.id, 'agv_route_id': idle_route.id})
vals.update({
'end_site_id': idle_route.end_site_id.id, 'agv_route_id': idle_route.id
})
else:
# 判断终点接驳站是否为空闲
idle_routes = agv_routes.filtered(lambda r: r.end_site_id.state == '空闲')
@@ -132,7 +141,10 @@ class AgvScheduling(models.Model):
# 将空闲的路线按照终点接驳站名称排序
idle_routes = sorted(idle_routes, key=lambda r: r.end_site_id.name)
idle_route = idle_routes[0]
vals.update({'end_site_id': idle_route.end_site_id.id, 'agv_route_id': idle_route.id})
vals.update({
'end_site_id': idle_route.end_site_id.id, 'agv_route_id': idle_route.id
})
try:
scheduling = self.env['sf.agv.scheduling'].sudo().create(vals)
# 触发空闲接驳站状态更新,触发新任务下发

View File

@@ -24,7 +24,7 @@ class AgvSetting(models.Model):
# name必须唯一
_sql_constraints = [
('name_uniq', 'unique (name)', '站点编号必须唯一!'),
('name_uniq', 'unique (name, workcenter_id)', '同一工作中心的站点编号必须唯一!'),
]
# def update_site_state(self):
@@ -68,11 +68,12 @@ class AgvSetting(models.Model):
"""
if isinstance(agv_site_state_arr, dict):
for agv_site_name, is_occupy in agv_site_state_arr.items():
agv_site = self.env['sf.agv.site'].sudo().search([('name', '=', agv_site_name)])
if agv_site:
agv_site.state = is_occupy
agv_sites = self.env['sf.agv.site'].sudo().search([('name', '=', agv_site_name)])
if agv_sites:
agv_sites.state = is_occupy
if notify:
self.env['sf.agv.scheduling'].on_site_state_change(agv_site.id, agv_site.state)
for agv_site in agv_sites:
self.env['sf.agv.scheduling'].on_site_state_change(agv_site.id, agv_site.state)
else:
_logger.error("更新失败:接驳站站点错误!%s" % agv_site_name)
raise UserError("更新失败:接驳站站点错误!")

View File

@@ -5,6 +5,8 @@ import logging
import json
import os
import re
import traceback
import requests
from itertools import groupby
from collections import defaultdict, namedtuple
@@ -25,6 +27,7 @@ class MrpProduction(models.Model):
maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests")
request_ids = fields.One2many('maintenance.request', 'production_id')
model_file = fields.Binary('模型文件', related='product_id.model_file')
glb_url = fields.Char('模型文件', related='product_id.glb_url')
schedule_state = fields.Selection([('未排', '未排'), ('已排', '已排'), ('已完成', '已完成')],
string='排程状态', default='未排')
work_order_state = fields.Selection([('未排', '未排'), ('已排', '已排'), ('已完成', '已完成')],
@@ -256,14 +259,46 @@ class MrpProduction(models.Model):
], string='工序状态', default='待装夹')
# 零件图号
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
part_number = fields.Char('零件图号', compute='_compute_part_info', store=True)
# 上传零件图纸
part_drawing = fields.Binary('零件图纸', related='product_id.machining_drawings', readonly=True)
quality_standard = fields.Binary('质检标准', related='product_id.quality_standard', readonly=True)
part_name = fields.Char(string='零件名称', related='product_id.part_name', readonly=True)
part_name = fields.Char(string='零件名称', compute='_compute_part_info', store=True)
@api.depends('product_id')
def _compute_part_info(self):
try:
for production_id in self:
if production_id.product_id.categ_id.type == '成品':
production_id.part_number = production_id.product_id.part_number
production_id.part_name = production_id.product_id.part_name
elif production_id.product_id.categ_id.type == '坯料':
product_name = ''
match = re.search(r'(S\d{5}-\d)', production_id.product_id.name)
# 如果匹配成功,提取结果
if match:
product_name = match.group(0)
if production_id.sale_order_id:
sale_order = production_id.sale_order_id
else:
sale_order_name = ''
match = re.search(r'(S\d+)', production_id.product_id.name)
if match:
sale_order_name = match.group(0)
sale_order = self.env['sale.order'].sudo().search(
[('name', '=', sale_order_name)])
logging.info("product_name is :%s" % product_name)
filtered_order_line = sale_order.order_line.filtered(
lambda production: re.search(f'{product_name}$', production.product_id.name)
)
if filtered_order_line:
production_id.part_number = filtered_order_line.part_number
production_id.part_name = filtered_order_line.part_name
except Exception as e:
traceback_error = traceback.format_exc()
logging.error("制造订单零件图号 零件名称获取失败:%s" % traceback_error)
# 判断制造的产品类型
production_product_type = fields.Selection([
@@ -720,14 +755,16 @@ class MrpProduction(models.Model):
'model_order_no': cnc.product_id.default_code,
'user': cnc.env.user.name,
'programme_way': programme_way,
'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
cnc.product_id.model_file).decode('utf-8'),
# 'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
# cnc.product_id.model_file).decode('utf-8'),
# 'glb_url': cnc.product_id.glb_url,
'part_name': cnc.product_id.part_name,
'part_number': cnc.product_id.part_number,
'machining_drawings': base64.b64encode(cnc.product_id.machining_drawings).decode(
'utf-8') if cnc.product_id.machining_drawings else '',
'machining_drawings_name': cnc.product_id.machining_drawings_name,
'machining_drawings_mimetype': cnc.product_id.machining_drawings_mimetype,
# 'model_id': cnc.product_id.model_id,
}
# 打印出除了 model_file 之外的所有键值对
for key, value in res.items():

View File

@@ -289,6 +289,7 @@ class ResMrpWorkOrder(models.Model):
cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序")
tray_code = fields.Char(string="托盘编码")
glb_file = fields.Binary("glb模型文件", related='production_id.model_file')
glb_url = fields.Char("glb模型文件", related='production_id.glb_url')
is_subcontract = fields.Boolean(string='是否外协')
surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数")
@@ -735,7 +736,8 @@ class ResMrpWorkOrder(models.Model):
local_filename = self.save_name + '.xls'
local_file_path = os.path.join(local_dir_path, local_filename)
logging.info('local_file_path:%s' % local_file_path)
remote_path = '/home/ftp/ftp_root/ThreeTest/XT/Before/' + local_filename
# remote_path = '/home/ftp/ftp_root/ThreeTest/XT/Before/' + local_filename
remote_path = '/ThreeTest/XT/Before/' + local_filename
logging.info('remote_path:%s' % remote_path)
is_get_detection_file = self.env['ir.config_parameter'].sudo().get_param('is_get_detection_file')
if not is_get_detection_file:
@@ -1532,7 +1534,7 @@ class ResMrpWorkOrder(models.Model):
# workorder.rfid_code_old = rfid_code
# workorder.rfid_code = False
logging.info('workorder.rfid_code:%s' % workorder.rfid_code)
# if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺', '切割']:
if is_production_id is True:
logging.info('product_qty:%s' % record.production_id.product_qty)
for move_raw_id in record.production_id.move_raw_ids:
@@ -1547,6 +1549,17 @@ class ResMrpWorkOrder(models.Model):
# if raw_move:
# raw_move.write({'state': 'done'})
if record.production_id.state != 'rework':
# 如果工单包含了外协工序,需要预留数量
if self.move_raw_ids.move_orig_ids.subcontract_workorder_id:
location_id = self.move_raw_ids.location_id
quant = self.move_raw_ids.lot_ids.quant_ids.filtered(lambda q: q.location_id.id == location_id.id)
if quant.reserved_quantity == 0:
self.env['stock.quant']._update_reserved_quantity(
self.move_raw_ids.product_id,
location_id,
quant.quantity,
lot_id=quant.lot_id,
)
record.production_id.button_mark_done1()
# record.production_id.state = 'done'
@@ -1850,7 +1863,7 @@ class CNCprocessing(models.Model):
# 将FTP的多面的程序单文件下载到临时目录
def download_file_tmp(self, production_no, processing_panel):
remotepath = os.path.join('/home/ftp/ftp_root/NC', production_no, 'return', processing_panel)
remotepath = os.path.join('/', production_no, 'return', processing_panel)
serverdir = os.path.join('/tmp', production_no, 'return', processing_panel)
ftp_resconfig = self.env['res.config.settings'].get_values()
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],

View File

@@ -30,6 +30,7 @@ class ResProductMo(models.Model):
model_width = fields.Float('模型宽(mm)', digits=(16, 3))
model_height = fields.Float('模型高(mm)', digits=(16, 3))
model_volume = fields.Float('模型体积(m³)')
model_area = fields.Float('模型表面积(m²)')
model_machining_precision = fields.Selection(selection=_get_machining_precision, string='加工精度')
model_processing_panel = fields.Char('模型加工面板')
model_remark = fields.Char('模型备注说明')
@@ -777,11 +778,40 @@ class ResProductMo(models.Model):
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
machining_drawings = fields.Binary('2D加工图纸', readonly=True)
quality_standard = fields.Binary('质检标准', readonly=True)
part_name = fields.Char(string='零件名称', readonly=True)
part_number = fields.Char(string='零件图号', readonly=True)
part_name = fields.Char(string='零件名称', compute='_compute_related_product', readonly=True, store=True)
part_number = fields.Char(string='零件图号', compute='_compute_related_product', readonly=True, store=True)
machining_drawings_name = fields.Char(string='零件图号名称', readonly=True)
machining_drawings_mimetype = fields.Char(string='零件图号类型', readonly=True)
model_url = fields.Char('模型文件地址')
glb_url = fields.Char('glb文件地址')
area = fields.Float('表面积(m²)')
auto_machining = fields.Boolean('自动化加工(模型识别)', default=False)
model_id = fields.Char('模型id')
@api.depends('name')
def _compute_related_product(self):
for record in self:
if record.categ_id.name == '坯料':
product_name = ''
match = re.search(r'(S\d{5}-\d)', record.name)
# 如果匹配成功,提取结果
if match:
product_name = match.group(0)
sale_order_name = ''
match_sale = re.search(r'S(\d+)', record.name)
if match_sale:
sale_order_name = match_sale.group(0)
sale_order = self.env['sale.order'].sudo().search(
[('name', '=', sale_order_name)])
if sale_order:
filtered_order_line = sale_order.order_line.filtered(
lambda order_line: re.search(f'{product_name}$', order_line.product_id.name)
)
record.part_number = filtered_order_line.product_id.part_number if filtered_order_line else None
record.part_name = filtered_order_line.product_id.part_name if filtered_order_line else None
@api.constrains('tool_length')
def _check_tool_length_size(self):
if self.tool_length > 1000000:
@@ -852,7 +882,7 @@ class ResProductMo(models.Model):
copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy()
copy_product_id.product_tmpl_id.active = True
model_type = self.env['sf.model.type'].search([], limit=1)
attachment = self.attachment_create(item['model_name'], item['model_data'])
# attachment = self.attachment_create(item['model_name'], item['model_data'])
# 获取坯料冗余配置
if not item.get('embryo_redundancy'):
embryo_redundancy_id = model_type.embryo_tolerance_id
@@ -875,10 +905,14 @@ class ResProductMo(models.Model):
'length': item['model_long'],
'width': item['model_width'],
'height': item['model_height'],
'volume': item['model_long'] * item['model_width'] * item['model_height'],
'model_file': '' if not item['model_file'] else base64.b64decode(item['model_file']),
'model_name': attachment.name if attachment else None,
'upload_model_file': [(6, 0, [attachment.id])] if attachment else None,
'volume': item['model_volume'],
'area': item['model_area'],
# 'model_file': '' if not item['model_file'] else base64.b64decode(item['model_file']),
'model_url': item['model_url'],
'glb_url': item['glb_url'],
'model_name': item['model_name'],
'auto_machining': item['auto_machining'],
# 'upload_model_file': [(6, 0, [attachment.id])] if attachment else None,
'list_price': item['price'],
'materials_id': self.env['sf.production.materials'].search(
[('materials_no', '=', item['texture_code'])]).id,
@@ -898,6 +932,7 @@ class ResProductMo(models.Model):
'part_name': item.get('part_name') or '',
'machining_drawings_name': item.get('machining_drawings_name') or '',
'machining_drawings_mimetype': item.get('machining_drawings_mimetype') or '',
'model_id': item['model_id'],
}
tax_id = self.env['account.tax'].sudo().search(
[('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')])
@@ -980,15 +1015,14 @@ class ResProductMo(models.Model):
vals = {
'name': '%s-%s-%s [%s %s-%s * %s * %s]' % ('R',
order_id.name, i, materials_id.name, materials_type_id.name,
item['model_long'] + embryo_redundancy_id.long,
item['model_width'] + embryo_redundancy_id.width,
item['model_height'] + embryo_redundancy_id.height),
'length': item['model_long'] + embryo_redundancy_id.long,
'width': item['model_width'] + embryo_redundancy_id.width,
'height': item['model_height'] + embryo_redundancy_id.height,
'volume': (item['model_long'] + embryo_redundancy_id.long) * (
item['model_width'] + embryo_redundancy_id.width) * (
item['model_height'] + embryo_redundancy_id.height),
self.format_float(item['model_long'] + embryo_redundancy_id.long),
self.format_float(item['model_width'] + embryo_redundancy_id.width),
self.format_float(item['model_height'] + embryo_redundancy_id.height)),
'length': self.format_float(item['model_long'] + embryo_redundancy_id.long),
'width': self.format_float(item['model_width'] + embryo_redundancy_id.width),
'height': self.format_float(item['model_height'] + embryo_redundancy_id.height),
'volume': self.format_float(item['blank_volume']),
'area': self.format_float(item['blank_area']),
'embryo_model_type_id': model_type.id,
'list_price': item['price'],
'materials_id': materials_id.id,
@@ -1081,6 +1115,9 @@ class ResProductMo(models.Model):
base64_data = base64.b64encode(image_data)
return base64_data
# 增加产品表面积
class ResProductFixture(models.Model):
_inherit = 'product.template'
@@ -1093,6 +1130,7 @@ class ResProductFixture(models.Model):
fixture_material_type = fields.Char(string="夹具物料类型", related='fixture_material_id.name')
multi_mounting_type_id = fields.Many2one('sf.multi_mounting.type', string="联装类型")
model_file = fields.Binary(string="3D模型图")
glb_url = fields.Char(string="3D模型图")
# 夹具物料基本参数
diameter = fields.Float('直径(mm)', digits=(16, 2))

View File

@@ -59,7 +59,7 @@ class QuickEasyOrder(models.Model):
product_id = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_default').sudo().with_context(active_test=False).product_variant_id
# user_id = request.env.ref('base.user_admin').sudo()
order_id = self.env['sale.order'].sale_order_create(company_id, 'XXXXX', 'XXXXX', 'XXXXX',
str(datetime.now()), '现结', '支付宝', state='draft')
str(datetime.now()), '现结', '支付宝', state='draft', model_display_version='v2')
order_id.default_code = obj.name
i = 1
for item in res['bfm_process_order_list']:

View File

@@ -1,5 +1,7 @@
import logging
import json
import re
from odoo import models, fields, api, _
from odoo.exceptions import UserError
@@ -23,6 +25,9 @@ class SaleOrder(models.Model):
def confirm_to_supply_method(self):
self.state = 'supply method'
for line in self.order_line:
if line.product_id.auto_machining:
line.supply_method = 'automation'
def action_confirm(self):
if self._get_forbidden_state_confirm() & set(self.mapped('state')):
@@ -57,18 +62,25 @@ class SaleOrder(models.Model):
order_id = self
product = line.product_id
# 拼接方法需要的item结构
# 拼接方法需要的item结构,成品的模型数据信息就是坯料的数据信息
item = {
'texture_code': product.materials_id.materials_no,
'texture_type_code': product.materials_type_id.materials_no,
'model_long': product.length,
'model_width': product.width,
'model_height': product.height,
'blank_volume': product.model_volume,
'blank_area': product.model_area,
'price': product.list_price,
'embryo_redundancy_id': line.embryo_redundancy_id,
}
product_name = ''
match = re.search(r'(S\d{5}-\d)', product.name)
# 如果匹配成功,提取结果
if match:
product_name = match.group(0)
# 获取成品名结尾-n的n
product_seria = int(product.name.split('-')[-1])
product_seria = int(product_name.split('-')[-1])
# 成品供货方式为采购则不生成bom
if line.supply_method != 'purchase':
bom_data = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).get_bom(product)
@@ -151,7 +163,7 @@ class SaleOrder(models.Model):
'purchase',
product_seria,
product)
if purchase_embryo == -3:
if purchase_embryo and purchase_embryo == -3:
raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配')
else:
# 产品配置bom
@@ -198,3 +210,14 @@ class SaleOrderLine(models.Model):
if vals['supply_method'] == 'purchase' and line.is_incoming_material:
raise UserError('当前(%s)产品为客供料,不能选择外购' % ','.join(line.mapped('product_id.name')))
return super(SaleOrderLine, self).write(vals)
cancel_auto_machining = fields.Boolean('是否取消自动化加工', compute='_compute_cancel_auto_machining', store=True)
cancel_auto_machining_reason = fields.Char('更改供货原因')
@api.depends('product_id', 'supply_method')
def _compute_cancel_auto_machining(self):
for line in self:
line.cancel_auto_machining = True if line.product_id.auto_machining \
and line.supply_method != 'automation' else False

View File

@@ -355,9 +355,9 @@ class StockRule(models.Model):
)
for p in production_process:
logging.info('production_process:%s' % p.name)
process_parameter = production_item.product_id.model_process_parameters_ids.filtered(
process_parameters = production_item.product_id.model_process_parameters_ids.filtered(
lambda pm: pm.process_id.id == p.id)
if process_parameter:
for process_parameter in process_parameters:
i += 1
route_production_process = self.env[
'mrp.routing.workcenter'].search(
@@ -688,7 +688,8 @@ class StockPicking(models.Model):
# 如果当前工单是是制造订单的最后一个工艺外协工单
if workorder == next((workorder for workorder in reversed(sorted_workorders) if workorder.is_subcontract),
None):
move_dest_id = item.move_raw_ids[0].id
if item.move_raw_ids:
move_dest_id = item.move_raw_ids[0].id
else:
# 从sorted_workorders中找到上一工单的move
if len(sorted_workorders) > 1:
@@ -724,6 +725,7 @@ class StockPicking(models.Model):
moves_out._action_confirm()
moves_out._assign_picking_post_process(new=new_picking)
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
def _compute_state(self):
super(StockPicking, self)._compute_state()
@@ -799,7 +801,7 @@ class ReStockMove(models.Model):
continue
logging.info('制造订单的调拨单 %s', move.origin)
production_id = self.env['mrp.production'].sudo().search(
[('name', '=', move.origin)], limit=1)
[('name', '=', move.origin.split(',')[0] if move.origin else '')], limit=1)
if not production_id:
continue
product_name = ''
@@ -847,6 +849,7 @@ class ReStockMove(models.Model):
# 'route_ids': False if not route else [(4, route.id)],
'date_deadline': datetime.now(),
'picking_type_id': picking_type_id,
# 'is_subcontract': True,
}
return move_values
@@ -1117,6 +1120,13 @@ class ReStockMove(models.Model):
self.state = 'assigned'
return self.action_show_details()
def _prepare_move_line_vals(self, quantity=None, reserved_quant=None):
res = super(ReStockMove, self)._prepare_move_line_vals(quantity, reserved_quant)
if self.subcontract_workorder_id:
if self.subcontract_workorder_id.production_id.move_raw_ids.move_line_ids:
res['lot_id'] = self.subcontract_workorder_id.production_id.move_raw_ids.move_line_ids[0].lot_id.id
return res
class ReStockQuant(models.Model):
_inherit = 'stock.quant'

View File

@@ -15,6 +15,23 @@
</field>
</record>
<record id="view_agv_site_form" model="ir.ui.view">
<field name="name">agv.site.form</field>
<field name="model">sf.agv.site</field>
<field name="arch" type="xml">
<form create="false" edit="false">
<sheet>
<group>
<field name="name" readonly="1" required="1"/>
<field name="workcenter_id" readonly="1" required="1" options="{'no_create': True}"/>
<field name="state" readonly="1" required="1"/>
<field name="divide_the_work" readonly="1" required="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_agv_site_form" model="ir.actions.act_window">
<field name="name">AGV站点</field>
<field name="res_model">sf.agv.site</field>
@@ -39,7 +56,8 @@
<field name="route_type" string="类型" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name="start_site_id" required="1" options="{'no_create': True}" string="起点接驳站"
attrs="{'readonly': [('id', '!=', False)]}"/>
<field name="end_site_id" required="1" options="{'no_create': True}" string="终点接驳站"/>
<field name="end_site_id" required="1" options="{'no_create': True}" string="终点接驳站"
attrs="{'readonly': [('id', '!=', False)]}"/>
<!-- <field name="destination_production_line_id" required="1" options="{'no_create': True}"-->
<!-- attrs="{'readonly': [('id', '!=', False)]}"/>-->
<field name="workcenter_id"/>

View File

@@ -450,7 +450,9 @@
</button>
</div>
<field name="product_id" position="after">
<field name="model_file" string="产品模型" readonly="1" widget="Viewer3D"/>
<field name="model_file" string="产品模型" readonly="1" widget="Viewer3D" attrs="{'invisible': [('model_file', '=', False)]}"/>
<field name="glb_url" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': [('glb_url', '=', False)]}"/>
</field>
</field>
</record>

View File

@@ -251,7 +251,8 @@
<field name="date_planned_finished" invisible="1"/>
<field name="duration" widget="mrp_timer"
invisible="1" sum="real duration"/>
<field name="glb_file" readonly="1" widget="Viewer3D" string="加工模型"/>
<field name="glb_file" readonly="1" widget="Viewer3D" string="加工模型" attrs="{'invisible': [('glb_file', '=', False)]}"/>
<field name="glb_url" readonly="1" widget="Viewer3D" string="加工模型" attrs="{'invisible': [('glb_url', '=', False)]}"/>
<field name="manual_quotation" readonly="1"
attrs="{'invisible': [('routing_type', 'not in', ['CNC加工', '人工线下加工'])]}"/>
<field name="processing_panel" readonly="1"

View File

@@ -18,9 +18,13 @@
<xpath expr="//page/field[@name='order_line']/tree/field[@name='remark']" position="before">
<field name="supply_method" attrs="{'invisible': [('state', '=', 'draft')], 'required': [('state', '=', 'supply method')]}" />
</xpath>
<xpath expr="//field[@name='order_line']/tree/field[@name='model_glb_file']" position="before">
<xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="after">
<field name="part_number" optional="show" class="section_and_note_text"/>
</xpath>
</xpath>
<!-- <xpath expr="//field[@name='order_line']/tree/field[@name='remark']" position="before"> -->
<!-- <field name="cancel_auto_machining" invisible="1"/> -->
<!-- <field name="cancel_auto_machining_reason" optional="show" attrs="{'required': [('cancel_auto_machining', '=', True),('state', 'not in', ['draft', 'sent'])]}"/> -->
<!-- </xpath> -->
<!-- <xpath expr="//header/button[@name='action_cancel']" position="attributes"> -->
<!-- <attribute name="attrs">{'invisible': [('state', '!=', 'draft')]}</attribute> -->
@@ -67,7 +71,7 @@
<record id="sale.action_quotations_with_onboarding" model="ir.actions.act_window">
<field name="search_view_id" ref="jikimo_sale_order_view_search_inherit_quotation_supply_method"/>
<field name="context">{'search_default_draft': 1}</field>
<field name="context">{'search_default_supply_method': 1}</field>
</record>
<record id="action_quotations_supply_method" model="ir.actions.act_window">

View File

@@ -117,17 +117,30 @@ class WorkpieceDeliveryWizard(models.TransientModel):
item.button_finish()
# return scheduling.read()[0]
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'target': 'new',
'params': {
'message': f'任务下发成功AGV任务调度编号为【{scheduling.name}',
'type': 'success',
'sticky': False,
'next': {'type': 'ir.actions.act_window_close'},
if isinstance(scheduling, bool) and scheduling is True:
return{
'type': 'ir.actions.client',
'tag': 'display_notification',
'target': 'new',
'params': {
'message': f'解除装夹成功',
'type': 'success',
'sticky': False,
'next': {'type': 'ir.actions.act_window_close'},
}
}
else:
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'target': 'new',
'params': {
'message': f'任务下发成功AGV任务调度编号为【{scheduling.name}',
'type': 'success',
'sticky': False,
'next': {'type': 'ir.actions.act_window_close'},
}
}
}
except Exception as e:
logging.info('%s任务下发失败:%s', self.delivery_type, e)
raise UserError(f'{self.delivery_type}任务下发失败:{e}') from e

View File

@@ -191,7 +191,8 @@ class SFMessageWork(models.Model):
def write(self, vals):
res = super(SFMessageWork, self).write(vals)
if ('leave_id' in vals and vals['leave_id'] is False or 'date_planned_start' in vals and vals['date_planned_start'] is False) \
and self.schedule_state != '未排':
self.add_queue('计划数据异常跟踪')
for record in self:
if ('leave_id' in vals and vals['leave_id'] is False or 'date_planned_start' in vals and vals['date_planned_start'] is False) \
and record.schedule_state != '未排':
record.add_queue('计划数据异常跟踪')
return res

View File

@@ -48,11 +48,11 @@
<div class="col-6">
<p>售后服务: <span t-field="o.company_id.phone"/></p>
<p>公司名称: <span t-field="o.company_id.name"/></p>
<p>公司网址: <span t-field="o.company_id.website"/></p>
<p>公司邮箱: <span t-field="o.company_id.email"/></p>
<p>加工工厂: <span t-field="o.company_id.factory_name"/></p>
</div>
<div class="col-6">
<p>加工工厂: <span t-field="o.company_id.factory_name"/></p>
<p>公司网址: <span t-field="o.company_id.website"/></p>
<p>公司邮箱: <span t-field="o.company_id.email"/></p>
</div>
</div>
<!-- <div style="border-top: 2px solid black;"></div> -->
@@ -61,6 +61,29 @@
</div>
</div>
</template>
<!-- 定义页脚模板无页码 -->
<template id="html_report_quality_footer">
<div class="footer">
<div style="border-top: 3px solid black;"></div>
<div class="row">
<div class="col-6">
<p>售后服务: <span t-field="o.company_id.phone"/></p>
<p>公司名称: <span t-field="o.company_id.name"/></p>
<p>加工工厂: <span t-field="o.company_id.factory_name"/></p>
</div>
<div class="col-6">
<p>公司网址: <span t-field="o.company_id.website"/></p>
<p>公司邮箱: <span t-field="o.company_id.email"/></p>
</div>
</div>
<!-- <div style="border-top: 2px solid black;"></div> -->
<div class="text-center">
<span><span>1</span> 页/共 <span>1</span></span>
</div>
</div>
</template>
<template id="report_quality_inspection">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
@@ -68,12 +91,12 @@
<t t-call="sf_quality.report_quality_header"/>
<div class="page" style="min-height: 800px; position: relative; padding-bottom: 150px;">
<div class="page" style="min-height: 800px; position: relative; padding-bottom: 250px;">
<table class="table table-sm o_main_table mt-4" style="border: 1px solid black;">
<tr>
<td style="width: 15%; border: 1px solid black;"><strong>产品名称:</strong></td>
<td style="width: 35%; border: 1px solid black;"><span t-field="o.product_id.name"/></td>
<td style="width: 35%; border: 1px solid black;"><span t-field="o.part_name"/></td>
<td style="width: 15%; border: 1px solid black;"><strong>材料:</strong></td>
<td style="width: 35%; border: 1px solid black;"><span t-field="o.material_name"/></td>
</tr>
@@ -187,4 +210,131 @@
</t>
</t>
</template>
<template id="html_report_quality_inspection">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="web.basic_layout">
<t t-call="sf_quality.report_quality_header"/>
<div class="page" style="min-height: 800px; position: relative; padding-bottom: 250px;">
<table class="table table-sm o_main_table mt-4" style="border: 1px solid black;">
<tr>
<td style="width: 15%; border: 1px solid black;"><strong>产品名称:</strong></td>
<td style="width: 35%; border: 1px solid black;"><span t-field="o.part_name"/></td>
<td style="width: 15%; border: 1px solid black;"><strong>材料:</strong></td>
<td style="width: 35%; border: 1px solid black;"><span t-field="o.material_name"/></td>
</tr>
<tr>
<td style="border: 1px solid black;"><strong>图号:</strong></td>
<td style="border: 1px solid black;"><span t-field="o.part_number"/></td>
<td style="border: 1px solid black;"><strong>日期:</strong></td>
<td style="border: 1px solid black;"><span t-field="o.write_date"/></td>
</tr>
<tr>
<td style="border: 1px solid black;"><strong>总数量:</strong></td>
<td style="border: 1px solid black;"><span t-field="o.total_qty"/></td>
<td style="border: 1px solid black;"><strong>检验数量:</strong></td>
<td style="border: 1px solid black;"><span t-field="o.check_qty"/></td>
</tr>
</table>
<h4 class="text-center mt-4">检验结果</h4>
<div class="" style="position: relative;">
<table class="table table-sm mt-2" style="border: 1px solid black;">
<thead>
<tr>
<th style="border: 1px solid black;" class="text-center" rowspan="2">检测项目<br/>(图示尺寸)</th>
<th style="border: 1px solid black;" t-att-colspan="o.column_nums" class="text-center">测量值</th>
<th style="border: 1px solid black; vertical-align: middle;" class="text-center" rowspan="2">判定</th>
<th style="border: 1px solid black; vertical-align: middle;" class="text-center" rowspan="2">备注</th>
</tr>
<tr>
<!-- <th style="border: 1px solid black;"></th> -->
<th style="border: 1px solid black;" t-if="o.column_nums >= 1" class="text-center">1</th>
<th style="border: 1px solid black;" t-if="o.column_nums >= 2" class="text-center">2</th>
<th style="border: 1px solid black;" t-if="o.column_nums >= 3" class="text-center">3</th>
<th style="border: 1px solid black;" t-if="o.column_nums >= 4" class="text-center">4</th>
<th style="border: 1px solid black;" t-if="o.column_nums >= 5" class="text-center">5</th>
<!-- <th style="border: 1px solid black;"></th>
<th style="border: 1px solid black;"></th> -->
</tr>
</thead>
<tbody>
<tr t-foreach="o.measure_line_ids" t-as="line">
<td style="border: 1px solid black;" class="text-center"><span t-field="line.measure_item"/></td>
<td style="border: 1px solid black;" t-if="o.column_nums >= 1" class="text-center"><span t-field="line.measure_value1"/></td>
<td style="border: 1px solid black;" t-if="o.column_nums >= 2" class="text-center"><span t-field="line.measure_value2"/></td>
<td style="border: 1px solid black;" t-if="o.column_nums >= 3" class="text-center"><span t-field="line.measure_value3"/></td>
<td style="border: 1px solid black;" t-if="o.column_nums >= 4" class="text-center"><span t-field="line.measure_value4"/></td>
<td style="border: 1px solid black;" t-if="o.column_nums >= 5" class="text-center"><span t-field="line.measure_value5"/></td>
<td style="border: 1px solid black;" class="text-center"><span t-field="line.measure_result"/></td>
<td style="border: 1px solid black;" class="text-center"><span t-field="line.remark"/></td>
</tr>
</tbody>
</table>
<img src="/sf_quality/static/img/pass.png" style="width: 200px; height: 200px;position: absolute; bottom: 20px; right: 20%;"/>
</div>
<div style="clear: both; margin-top: 30px; padding-top: 10px;">
<div style="display: inline-block;">
<span style="font-size: 18px; font-weight: bold;">检验结论: </span>
<span t-if="o.report_result == 'OK'" style="margin-left: 30px; display: inline-block;">
<svg width="20" height="20" style="vertical-align: middle;">
<rect x="1" y="1" width="18" height="18" fill="none" stroke="black" stroke-width="1.5"/>
<path d="M4 10 L9 15 L16 6" stroke="black" stroke-width="2" fill="none"/>
</svg>
<span style="margin-left: 5px;">合格</span>
</span>
<span t-else="" style="margin-left: 30px; display: inline-block;">
<svg width="20" height="20" style="vertical-align: middle;">
<rect x="1" y="1" width="18" height="18" fill="none" stroke="black" stroke-width="1.5"/>
</svg>
<span style="margin-left: 5px;">合格</span>
</span>
<span t-if="o.report_result == 'NG'" style="margin-left: 50px; display: inline-block;">
<svg width="20" height="20" style="vertical-align: middle;">
<rect x="1" y="1" width="18" height="18" fill="none" stroke="black" stroke-width="1.5"/>
<path d="M4 10 L9 15 L16 6" stroke="black" stroke-width="2" fill="none"/>
</svg>
<span style="margin-left: 5px;">不合格</span>
</span>
<span t-else="" style="margin-left: 50px; display: inline-block;">
<svg width="20" height="20" style="vertical-align: middle;">
<rect x="1" y="1" width="18" height="18" fill="none" stroke="black" stroke-width="1.5"/>
</svg>
<span style="margin-left: 5px;">不合格</span>
</span>
</div>
</div>
<div class="row mt-4">
<div class="col-6">
<p><strong>操作员: </strong> <span t-field="o.measure_operator"/></p>
</div>
<div class="col-6">
<p><strong>质检员: </strong> <span t-field="o.quality_manager"/></p>
</div>
</div>
<div style="border-top: 3px solid black;"></div>
<!-- 添加合格标签 -->
<!-- <div class="row mt-5">
<div class="col-12 text-center">
<p></p>
</div>
</div> -->
<!-- 页脚固定在底部 -->
<!-- <div style="position: absolute; bottom: 0; left: 0; right: 0;"> -->
<t t-call="sf_quality.html_report_quality_footer"/>
<!-- </div> -->
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -18,7 +18,7 @@
<field name="name">预览检验报告</field>
<field name="model">quality.check</field>
<field name="report_type">qweb-html</field>
<field name="report_name">sf_quality.report_quality_inspection</field>
<field name="report_name">sf_quality.html_report_quality_inspection</field>
<field name="binding_type">report</field>
</record>
</odoo>

View File

@@ -26,6 +26,7 @@ class QualityCheck(models.Model):
string='生产线')
equipment_id = fields.Many2one(related='workorder_id.equipment_id', string='加工设备')
model_file = fields.Binary(related='workorder_id.glb_file', string='加工模型')
glb_url = fields.Char(related='workorder_id.glb_url', string='加工模型')
detection_report = fields.Binary(related='workorder_id.detection_report', readonly=True, string='检测报告')
test_results = fields.Selection([("合格", "合格"), ("返工", "返工")], string="检测结果",

View File

@@ -12,6 +12,7 @@ class SfQualityCncTest(models.Model):
production_id = fields.Many2one(related='workorder_id.production_id', string='制造订单')
product_id = fields.Many2one(related='workorder_id.product_id', string='产品')
model_file = fields.Binary(related='workorder_id.glb_file', string='加工模型')
glb_url = fields.Char(related='workorder_id.glb_url', string='加工模型')
processing_panel = fields.Char(related='workorder_id.processing_panel', string='加工面')
equipment_id = fields.Many2one(related='workorder_id.equipment_id', string='加工设备')
production_line_id = fields.Many2one(related='workorder_id.production_line_id',

View File

@@ -13,6 +13,8 @@
<field name="equipment_id" attrs="{'invisible': [('production_id', '=', False)]}"/>
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': ['|',('model_file', '=', False), ('production_id', '=', False)]}"/>
<field name="glb_url" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': ['|',('glb_url', '=', False), ('production_id', '=', False)]}"/>
</xpath>
<xpath expr="//field[@name='partner_id']" position="after">
<field name="processing_panel" attrs="{'invisible': [('production_id', '=', False)]}"/>

View File

@@ -87,7 +87,8 @@
<field name="product_id"/>
<field name="production_line_id"/>
<field name="equipment_id"/>
<field name="model_file" widget="Viewer3D"/>
<field name="model_file" widget="Viewer3D" attrs="{'invisible': [('model_file', '=', False)]}"/>
<field name="glb_url" widget="Viewer3D" attrs="{'invisible': [('glb_url', '=', False)]}"/>
</group>
<group>
<field name="part_name"/>

View File

@@ -314,7 +314,7 @@ class QuickEasyOrder(models.Model):
company_id = self.env.ref('base.main_company').sudo()
# user_id = request.env.ref('base.user_admin').sudo()
order_id = self.env['sale.order'].sale_order_create(company_id, 'XXXXX', 'XXXXX', 'XXXXX',
str(datetime.now()), '现结', '支付宝')
str(datetime.now()), '现结', '支付宝', 'v2')
i = 1
# 给sale_order的default_code字段赋值
aa = self.env['sale.order'].sudo().search([('name', '=', order_id.name)])

View File

@@ -237,7 +237,7 @@ class QuickEasyOrder(models.Model):
company_id = self.env.ref('base.main_company').sudo()
# user_id = request.env.ref('base.user_admin').sudo()
order_id = self.env['sale.order'].sale_order_create(company_id, 'XXXXX', 'XXXXX', 'XXXXX',
str(datetime.now()), '现结', '支付宝')
str(datetime.now()), '现结', '支付宝', 'v2')
i = 1
# 给sale_order的default_code字段赋值
aa = self.env['sale.order'].sudo().search([('name', '=', order_id.name)])

View File

@@ -61,9 +61,12 @@ class ReSaleOrder(models.Model):
order_code = fields.Char('平台订单号', readonly=True)
model_display_version = fields.Char('模型展示版本', default="v1")
# 业务平台分配工厂后在智能工厂先创建销售订单
def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address,
deadline_of_delivery, payments_way, pay_way, order_number, state='sale'):
deadline_of_delivery, payments_way, pay_way, order_number, state='sale',
model_display_version='v1'):
now_time = datetime.datetime.now()
partner = self.get_customer()
data = {
@@ -80,6 +83,7 @@ class ReSaleOrder(models.Model):
'payments_way': payments_way,
'pay_way': pay_way,
'order_code': order_number,
'model_display_version': model_display_version,
}
if deadline_of_delivery:
# deadline_of_delivery字段存在为false字符串情况
@@ -138,11 +142,15 @@ class ReSaleOrder(models.Model):
product.materials_id.name),
'price_unit': product.list_price,
'product_uom_qty': item['number'],
'model_glb_file': base64.b64decode(item['model_file']) if item['model_file'] else None,
# 'model_glb_file': base64.b64decode(item['model_file']) if item['model_file'] else None,
'model_url': item['model_url'],
'glb_url': item['glb_url'],
'remark': item.get('remark'),
'embryo_redundancy_id': item.get('embryo_redundancy_id'),
'is_incoming_material': True if item.get('embryo_redundancy_id') else False,
'manual_quotation': item.get('manual_quotation')
'manual_quotation': item.get('manual_quotation'),
'model_id': item['model_id'],
'delivery_end_date': item['delivery_end_date'],
}
return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
@@ -245,6 +253,7 @@ class ResaleOrderLine(models.Model):
# part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
part_name = fields.Char('零件名称', related='product_id.part_name', readonly=True)
model_glb_file = fields.Binary('模型的glb文件', compute='_compute_model_glb_file', store=True)
glb_url = fields.Char('glb文件地址', compute='_compute_model_glb_file', store=True)
# product_template_id = fields.Many2one(
# string="产品",
# comodel_name='product.template',
@@ -261,6 +270,10 @@ class ResaleOrderLine(models.Model):
is_incoming_material = fields.Boolean('客供料', compute='_compute_is_incoming_material', store=True)
embryo_redundancy_id = fields.Many2one('sf.embryo.redundancy', '坯料冗余')
manual_quotation = fields.Boolean('人工编程', default=False)
model_url = fields.Char('模型文件地址')
model_id = fields.Char('模型id')
delivery_end_date = fields.Date('交货截止日期')
@api.depends('embryo_redundancy_id')
def _compute_is_incoming_material(self):
@@ -273,6 +286,8 @@ class ResaleOrderLine(models.Model):
if line.product_template_id:
if not line.model_glb_file:
line.model_glb_file = line.product_id.product_tmpl_id.model_file
if not line.glb_url:
line.glb_url = line.product_id.product_tmpl_id.glb_url
if not line.price_unit:
line.price_unit = line.product_id.product_tmpl_id.list_price

View File

@@ -50,9 +50,13 @@
<group>
<field name="customer_id" context="{'is_customer': True }"
options="{'no_create': True}" required="1"/>
<field name="upload_model_file" widget="many2many_binary"/>
<field name="upload_model_file" widget="many2many_binary" attrs="{'invisible': [('upload_model_file', '=', False)]}"/>
<!-- <field name="model_url" widget="binary_download" filename_field="model_name" readonly="1" string="模型文件"
attrs="{'invisible': [('model_url', '=', False)]}"/> -->
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': [('model_file', '=', False)]}"/>
<!-- <field name="glb_url" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': [('glb_url', '=', False)]}"/> -->
<label for="model_length" string="尺寸(mm)"
attrs='{"invisible": [("model_file","=",False)]}'/>
<div class="test_model"

View File

@@ -98,12 +98,15 @@
<field name="deadline_of_delivery" readonly="0"/>
<field name="payments_way" invisible="1"/>
<field name="pay_way" invisible="1"/>
<field name="model_display_version" invisible="1"/>
<!-- <field name="schedule_status" readonly="1"/> -->
</field>
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="before">
<field name="model_glb_file" widget="Viewer3D" optional="show"
string="模型文件" attrs="{'readonly': [('state', 'in', ['draft'])], 'isInList': True}"/>
<field name="part_name" optional="hide"/>
string="模型文件" readonly="1" attrs="{'column_invisible': [('parent.model_display_version', '!=', 'v1')], 'isInList': True}"/>
<field name="glb_url" widget="Viewer3D" optional="show"
string="模型文件" readonly="1" attrs="{'column_invisible': [('parent.model_display_version', '!=', 'v2')], 'isInList': True}"/>
<field name="part_name" optional="show"/>
</xpath>
<xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after">
<field name="remark"/>
@@ -133,6 +136,10 @@
<xpath expr="//field[@name='order_line']/tree/field[@name='product_uom']" position="attributes">
<attribute name="optional">hide</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/tree/field[@name='remark']" position="before">
<field name="delivery_end_date" optional="hide"/>
</xpath>
<field name="user_id" position="attributes">
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
</field>

View File

@@ -88,13 +88,23 @@ class StockPicking(models.Model):
self.send_to_bfm()
return info
def _action_done(self):
"""处理创建欠单时,新单据验证序列号无法使用问题"""
todo_moves = self.move_ids.filtered(
lambda self: self.state in ['draft', 'waiting', 'partially_available', 'assigned', 'confirmed'])
res = super(StockPicking, self)._action_done()
todo_move = todo_moves.filtered(lambda mv: mv.quantity_done == 0)
if todo_move:
todo_move.move_line_nosuggest_ids.write({'qty_done': 1})
return res
def deal_move_ids(self, send_move_ids, send_move_line_ids):
move_ids = [] # 本次发货单
move_line_ids = [] # 本次发货单行
if send_move_ids:
for item in send_move_ids:
val = {
'name': item.product_id.upload_model_file.display_name,
'name': item.product_id.upload_model_file.display_name if item.product_id.upload_model_file else item.product_id.model_name,
'quantity_done': item.quantity_done,
'date': date_utils.json_default(item.date) if item.date else None,
'description_picking': item.description_picking,

View File

@@ -38,6 +38,7 @@
'web.assets_qweb': [
],
'web.assets_backend': [
'sf_tool_management/static/src/change.scss'
]
},

View File

@@ -387,7 +387,7 @@ class FunctionalToolAssembly(models.Model):
else:
raise ValidationError('刀柄选择错误,请重新确认!!!')
else:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode)])
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode.upper())])
if location:
if location == record.integral_freight_barcode_id:
tool_assembly_id.integral_verify = True
@@ -782,10 +782,11 @@ class FunctionalToolAssembly(models.Model):
"""根据BOM对刀具物料进行初始配置"""
options = bom.get('options')
# 配置刀柄信息
for handle_id in bom.get('handle_ids'):
handle_ids = self._get_old_tool_material_lot(bom.get('handle_ids'))
for handle_id in handle_ids:
if handle_id:
if not self.handle_product_id:
self.handle_product_id = handle_id.id
self.handle_product_id = handle_id.product_id.id
break
# 刀柄之外的物料配置
@@ -820,19 +821,20 @@ class FunctionalToolAssembly(models.Model):
location_id = self.env['stock.location'].search([('name', '=', '刀具房')])
stock_quant = self.env['stock.quant'].sudo().search(
[('location_id', '=', location_id.id), ('product_id', 'in', material_ids.ids), ('quantity', '>', '0')],
order='lot_id', limit=1)
order='lot_id')
if stock_quant:
return stock_quant.lot_id
return [quant.lot_id for quant in stock_quant]
else:
raise ValidationError(f'{material_ids[0].cutting_tool_material_id.name}】物料库存不足,请先进行盘点或采购')
def _get_shelf_location_lot(self, lot_id):
def _get_shelf_location_lot(self, lot_ids):
"""根据所给的刀具物料批次号,返回一个刀具物料货位、批次信息"""
location_lots = self.env['sf.shelf.location.lot'].sudo().search([('lot_id', '=', lot_id.id)])
if not location_lots:
raise ValidationError(f'没有查询到批次为【{lot_id.name}】物料的货位信息!')
else:
return location_lots[0]
for lot_id in lot_ids:
location_lots = self.env['sf.shelf.location.lot'].sudo().search([('lot_id', '=', lot_id.id)])
if location_lots:
return location_lots[0]
raise ValidationError(f'{lot_ids[0].product_id.cutting_tool_material_id.name}】物料在货位库存不足,请先进行盘点入库')
def _get_inventory_bom(self, inventory_id):
"""获取BOM的刀具物料产品信息"""
@@ -1240,7 +1242,7 @@ class FunctionalToolDismantle(models.Model):
functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True, tracking=True,
domain=[('functional_tool_status', '!=', '已拆除'),
('current_location', '=', '刀具房')])
('current_location', 'in', ['刀具房', '线边刀库'])])
@api.onchange('functional_tool_id')
def _onchange_functional_tool_id(self):
@@ -1437,14 +1439,26 @@ class FunctionalToolDismantle(models.Model):
def confirmation_disassembly(self):
logging.info('%s刀具确认开始拆解' % self.dismantle_cause)
code = self.code
context = self.env.context
if self.functional_tool_id.functional_tool_status == '已拆除':
raise ValidationError('Rfid为【%s】名称为【%s】的功能刀具已经拆解,请勿重复操作!' % (
self.functional_tool_id.rfid_dismantle, self.name))
# 对拆解的功能刀具进行校验,只有在刀具房的功能刀具才能拆解
elif self.functional_tool_id.functional_tool_status != '报警':
if self.functional_tool_id.tool_room_num == 0:
if self.functional_tool_id.current_location == '机内刀库':
raise ValidationError('Rfid为【%s】的功能刀具当前位置为【%s】,不能进行拆解!' % (
self.rfid, self.functional_tool_id.current_location))
elif not context.get('TRUE_DISASSEMBLE') and self.functional_tool_id.current_location == '线边刀库':
return {
'type': 'ir.actions.act_window',
'res_model': 'sf.functional.tool.dismantle.wiard',
'name': '刀具寿命未到期',
'view_mode': 'form',
'target': 'new',
'context': {
'default_functional_tool_dismantle_id': self.id,
'TRUE_DISASSEMBLE': True}
}
# 目标重复校验
self.location_duplicate_check()
datas = {'scrap': [], 'picking': []}
@@ -1521,11 +1535,18 @@ class FunctionalToolDismantle(models.Model):
'functional_tool_name': self.functional_tool_id.name,
'handle_code_id': self.handle_lot_id.id,
'handle_product_id': self.handle_product_id.id,
'functional_tool_diameter': self.functional_tool_id.functional_tool_diameter,
'knife_tip_r_angle': self.functional_tool_id.knife_tip_r_angle,
'tool_loading_length': self.functional_tool_id.tool_loading_length,
'functional_tool_length': self.functional_tool_id.functional_tool_length,
'loading_task_source': '3',
'use_tool_time': fields.Datetime.now() + timedelta(hours=4),
'reason_for_applying': '刀具寿命到期'
})
# 将新的组装单更新到对应的功能刀具安全库存的组装单列表中
self.functional_tool_id.safe_inventory_id.sudo().sf_functional_tool_assembly_ids = [(4, assembly_id.id)]
return {
'type': 'ir.actions.act_window',
'res_model': 'sf.functional.tool.assembly',

View File

@@ -10,6 +10,7 @@ from odoo.exceptions import ValidationError
class FunctionalCuttingToolEntity(models.Model):
_name = 'sf.functional.cutting.tool.entity'
_inherit = ['mail.thread']
_description = '功能刀具列表'
_order = 'functional_tool_status'
@@ -41,7 +42,7 @@ class FunctionalCuttingToolEntity(models.Model):
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
alarm_value = fields.Integer(string='报警值(min)', readonly=True)
used_value = fields.Integer(string='已使用值(min)', readonly=True)
functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')],
functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')], tracking=True,
string='状态', store=True, default='正常')
current_location_id = fields.Many2one('stock.location', string='当前位置', compute='_compute_current_location_id',
store=True)
@@ -62,16 +63,27 @@ class FunctionalCuttingToolEntity(models.Model):
for item in self:
if item:
if item.functional_tool_status == '报警':
# 创建报警刀具拆解单
self.env['sf.functional.tool.dismantle'].sudo().create({
'functional_tool_id': item.ids[0],
'dismantle_cause': '寿命到期报废'
})
# 创建刀具报警记录
self.env['sf.functional.tool.warning'].sudo().create({
'rfid': item.rfid,
'functional_tool_id': item.ids[0]
})
self.create_tool_dismantle()
def set_functional_tool_status(self):
# self.write({
# 'functional_tool_status': '报警'
# })
self.functional_tool_status = '报警'
self.create_tool_dismantle()
def create_tool_dismantle(self):
for item in self:
# 创建报警刀具拆解单
self.env['sf.functional.tool.dismantle'].sudo().create({
'functional_tool_id': item.ids[0],
'dismantle_cause': '寿命到期报废'
})
# 创建刀具报警记录
self.env['sf.functional.tool.warning'].sudo().create({
'rfid': item.rfid,
'functional_tool_id': item.ids[0]
})
@api.depends('barcode_id.quant_ids', 'barcode_id.quant_ids.location_id', 'functional_tool_status',
'current_shelf_location_id', 'stock_num')
@@ -263,7 +275,7 @@ class FunctionalCuttingToolEntity(models.Model):
functional_tool_model_ids.append(functional_tool_model.id)
return [(6, 0, functional_tool_model_ids)]
dismantle_num = fields.Integer('拆解单数量', compute='_compute_dismantle_num', store=True)
dismantle_num = fields.Integer('拆解单数量', compute='_compute_dismantle_num', tracking=True, store=True)
dismantle_ids = fields.One2many('sf.functional.tool.dismantle', 'functional_tool_id', '拆解单')
@api.depends('dismantle_ids')

View File

@@ -107,11 +107,17 @@ class SfMaintenanceEquipment(models.Model):
if functional_tool_id.current_location != '机内刀库':
# 对功能刀具进行移动到生产线
functional_tool_id.tool_inventory_displacement_out()
functional_tool_id.write({
'max_lifetime_value': data['MaxLife'],
'used_value': data['UseLife'],
'functional_tool_status': tool_install_time.get(data['State'])
})
data_tool = {
'max_lifetime_value': data['MaxLife'],
'used_value': data['UseLife'],
'functional_tool_status': tool_install_time.get(data['State'])
}
if (functional_tool_id.functional_tool_status != '报警'
and tool_install_time.get(data['State']) == '报警'):
functional_tool_id.write(data_tool)
functional_tool_id.create_tool_dismantle()
else:
functional_tool_id.write(data_tool)
else:
logging.info('获取的【%s】设备不存在!!!' % data['DeviceId'])
else:

View File

@@ -41,3 +41,6 @@ access_sf_functional_tool_dismantle_group_plan_dispatch,sf.functional.tool.disma
access_jikimo_bom,jikimo.bom,model_jikimo_bom,base.group_user,1,1,1,1
access_jikimo_bom_wizard,jikimo.bom.wizard,model_jikimo_bom_wizard,base.group_user,1,1,1,1
access_sf_functional_tool_dismantle_wiard,sf.functional.tool.dismantle.wiard,model_sf_functional_tool_dismantle_wiard,sf_base.group_sf_tool_user,1,1,1,0
access_sf_functional_tool_dismantle_wiard_group_plan_dispatch,sf.functional.tool.dismantle.wiard,model_sf_functional_tool_dismantle_wiard,sf_base.group_plan_dispatch,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
41
42
43
44
45
46

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

View File

@@ -1,17 +1,47 @@
.modal-content .o_cp_buttons {
display:none
}
// .modal-content .o_cp_buttons {
// display:none
// }
.modal-content .o_control_panel {
display:none
}
// .modal-content .o_control_panel {
// display:none
// }
.modal-content .o_list_button {
// .modal-content .o_list_button {
// }
// .o_form_view .o_field_widget .o_list_renderer {
// width: 100%!important;
// margin:0 auto;
// overflow: auto;
// }
.o_field_widget.o_readonly_modifier.o_field_char.text-success[name=handle_freight_rfid],
.o_field_widget.o_readonly_modifier.o_field_many2one.text-success[name=integral_freight_barcode_id] {
a.text-success{
span {
color: #999;
}
}
}
.o_form_view .o_field_widget .o_list_renderer {
width: 100%!important;
margin:0 auto;
overflow: auto;
.custom_group:has(.text-success){
position: relative;
&::after{
content: '';
display: block;
width: 72px;
height: 72px;
background: url('/sf_tool_management/static/images/replaceIcon.png') no-repeat center center;
background-size: 100%;
position: absolute;
bottom: 20px;
left: 300px;
}
}
.o_field_widget.o_readonly_modifier.o_field_char.text-success[name=handle_freight_rfid] {
display: flex;
align-items: center;
> span {
color: #999;
}
}

View File

@@ -42,6 +42,7 @@
<field name="arch" type="xml">
<form create="0" edit="0" delete="0">
<header>
<button name="set_functional_tool_status" string="报警" type="object" invisible="1"/>
<!-- <button name="enroll_functional_tool_entity" string="功能刀具注册" type="object"-->
<!-- class="btn-primary"/>-->
<field name="functional_tool_status" widget="statusbar" statusbar_visible="正常,报警,已拆除"/>
@@ -192,6 +193,10 @@
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>

View File

@@ -531,10 +531,10 @@
<div>
<separator string="刀柄:" style="font-size: 13px;"/>
</div>
<group>
<group class="custom_group" >
<field name="handle_code_id" string="序列号" placeholder="请选择"
options="{'no_create': True, 'no_quick_create': True}"/>
<field name="handle_freight_rfid" string="Rfid"/>
<field name="handle_freight_rfid" string="Rfid" decoration-success="handle_freight_rfid"/>
<field name="handle_product_id" string="名称"/>
<field name="cutting_tool_cutterhandle_model_id" string="型号"/>
<field name="handle_specification_id" string="规格"/>
@@ -554,15 +554,15 @@
<separator string="整体式刀具:" style="font-size: 13px;"/>
</div>
<group>
<group>
<field name="integral_freight_barcode_id" string="货位"/>
<group class="custom_group">
<field name="integral_freight_barcode_id" string="货位" decoration-success="integral_verify == True"/>
<field name="integral_lot_id" string="批次"/>
<field name="integral_product_id" string="名称"/>
<field name="cutting_tool_integral_model_id" string="型号"/>
<field name="integral_specification_id" string="规格"/>
<field name="sf_tool_brand_id_1" string="品牌"/>
</group>
<group>
<group invisible="1">
<field name="integral_verify" string="" readonly="1"/>
</group>
</group>
@@ -582,8 +582,8 @@
<separator string="刀片:" style="font-size: 13px;"/>
</div>
<group>
<group>
<field name="blade_freight_barcode_id" string="货位"/>
<group class="custom_group">
<field name="blade_freight_barcode_id" string="货位" decoration-success="blade_verify == True"/>
<field name="blade_lot_id" string="批次"/>
<field name="blade_product_id" string="名称"/>
<field name="cutting_tool_blade_model_id" string="型号"/>
@@ -607,8 +607,8 @@
<separator string="刀杆:" style="font-size: 13px;"/>
</div>
<group>
<group>
<field name="bar_freight_barcode_id" string="货位"/>
<group class="custom_group">
<field name="bar_freight_barcode_id" string="货位" decoration-success="bar_verify == True"/>
<field name="bar_lot_id" string="批次"/>
<field name="bar_product_id" string="名称"/>
<field name="cutting_tool_cutterbar_model_id" string="型号"/>
@@ -631,8 +631,8 @@
<separator string="刀盘:" style="font-size: 13px;"/>
</div>
<group>
<group>
<field name="pad_freight_barcode_id" string="货位"/>
<group class="custom_group">
<field name="pad_freight_barcode_id" string="货位" decoration-success="pad_verify == True"/>
<field name="pad_lot_id" string="批次"/>
<field name="pad_product_id" string="名称"/>
<field name="cutting_tool_cutterpad_model_id" string="型号"/>

View File

@@ -770,3 +770,12 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# }
class FunctionalToolDismantle(models.TransientModel):
_name = 'sf.functional.tool.dismantle.wiard'
_description = '功能刀具拆解二次确认'
functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', '拆解单')
def confirm(self):
self.functional_tool_dismantle_id.confirmation_disassembly()
return True

View File

@@ -444,4 +444,19 @@
<field name="view_id" ref="sf_functional_tool_assembly_order_form"/>
<field name="target">new</field>
</record>
<record id="sf_functional_tool_dismantle_wiard_form" model="ir.ui.view">
<field name="name">刀具拆解</field>
<field name="model">sf.functional.tool.dismantle.wiard</field>
<field name="arch" type="xml">
<form>
<div>刀具寿命未到期,是否继续拆解?</div>
<footer>
<button string="确定" name="confirm" type="object" class="btn-primary"/>
<button string="取消" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>

View File

@@ -150,4 +150,4 @@ access_sf_shelf_lot_group_user,sf.shelf.location.lot.group_user,model_sf_shelf_l
access_ir_model_group_sf_stock_user,ir_model_group_sf_stock_user,base.model_ir_model,sf_base.group_sf_stock_user,1,1,0,0
access_mrp_workorder_group_sf_stock_user,mrp_workorder_group_sf_stock_user,mrp.model_mrp_workorder,sf_base.group_sf_stock_user,1,0,0,0
access_mrp_workorder_group_sf_stock_user,mrp_workorder_group_sf_stock_user,mrp.model_mrp_workorder,sf_base.group_sf_stock_user,1,1,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
150
151
152
153

View File

@@ -6,10 +6,7 @@ import win32gui
import win32con
import logging
import time
# 配置日志记录
logging.basicConfig(filename='service.log', level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
import re
app = FastAPI()
@@ -19,11 +16,11 @@ class FileUploadRequest(BaseModel):
# FTP 服务器配置信息
ftp_host = '110.52.114.162'
ftp_port = 10021
ftp_host = '47.119.33.43'
ftp_port = 21
ftp_user = 'ftpuser'
ftp_password = '123456'
ftp_directory = '/home/ftp/ftp_root/ThreeTest/XT/Before/'
ftp_password = 'FTPftp123'
ftp_directory = 'ThreeTest/XT/Before/'
def find_child_window(parent_hwnd, class_name):
@@ -63,25 +60,95 @@ def find_child_window_by_title(parent_hwnd, title):
return child_hwnds
# 获取 ComboBox 的句柄
def get_combobox_handle(parent_handle):
combo_handle = win32gui.FindWindowEx(parent_handle, 0, "ComboBox", None)
if combo_handle == 0:
raise Exception("ComboBox not found")
return combo_handle
# 获取 ComboBox 中的所有选项
def get_combobox_items(combo_handle):
count = win32gui.SendMessage(combo_handle, win32con.CB_GETCOUNT, 0, 0)
items = []
for i in range(count):
length = win32gui.SendMessage(combo_handle, win32con.CB_GETLBTEXTLEN, i, 0)
buffer = win32gui.PyMakeBuffer(length + 1)
win32gui.SendMessage(combo_handle, win32con.CB_GETLBTEXT, i, buffer)
byte_data = buffer.tobytes()
# 尝试多种编码方式
text = None
# 尝试多种编码方式包括utf-16le
for encoding in ['utf-16le', 'utf-8', 'gbk', 'latin-1']:
try:
decoded_text = byte_data.decode(encoding).rstrip('\x00')
# 如果解码后的文本看起来是合理的,就接受它
if any(char.isprintable() for char in decoded_text):
text = decoded_text
break
except UnicodeDecodeError:
continue
# 如果所有解码方式都失败,或者内容仍有大量乱码,显示为十六进制字符串
if text is None or not all(char.isprintable() or char.isspace() for char in text):
text = byte_data.hex()
items.append(text)
return items
# 获取当前选定项
def get_combobox_selected(combo_handle):
index = win32gui.SendMessage(combo_handle, win32con.CB_GETCURSEL, 0, 0)
if index == -1:
return None
length = win32gui.SendMessage(combo_handle, win32con.CB_GETLBTEXTLEN, index, 0)
buffer = win32gui.PyMakeBuffer(1024) # 调整缓冲区大小
win32gui.SendMessage(combo_handle, win32con.CB_GETLBTEXT, index, buffer)
# 尝试多种编码方式进行解码
for encoding in ['utf-16le', 'utf-8', 'latin-1']:
try:
# 解码
raw_text = buffer.tobytes().decode(encoding, errors='ignore').rstrip('\x00')
# 使用正则表达式查找 "数字 + 月" 格式的部分
match = re.search(r'\d+月', raw_text)
if match:
return match.group()
# 使用正则表达式提取有效字符(中文、数字、字母和常见标点)
filtered_text = re.findall(r'[\w\u4e00-\u9fa5]+', raw_text)
# 返回匹配到的第一个有效部分
if filtered_text:
return filtered_text[0].strip()
except UnicodeDecodeError:
continue # 尝试下一个编码方式
# 如果所有解码方式都失败,返回 None
return None
# 设置 ComboBox 的值
def set_combobox_value(combo_handle, value):
items = get_combobox_items(combo_handle)
try:
index = items.index(value)
win32gui.SendMessage(combo_handle, win32con.CB_SETCURSEL, index, 0)
except ValueError:
raise Exception("Value not found in ComboBox")
def set_path_and_save(filename):
parent_hwnd = win32gui.FindWindow(None, '另存为')
parent_hwnd = win32gui.FindWindow(None, '保存Excel文件')
if parent_hwnd == 0:
raise HTTPException(status_code=404, detail="没有找到保存报告的窗口,请检查!")
# 这里假设“地址:”是你需要的部分标题
address_hwnds = find_child_window_by_partial_title(parent_hwnd, "地址:")
# 确保找到的窗口句柄有效
if not address_hwnds:
raise HTTPException(status_code=404, detail="未找到地址框,请联系管理员!")
# 假设找到的第一个窗口是目标组件
address_hwnd = address_hwnds[0]
logging.info(f"找到地址框地址: {win32gui.GetWindowText(address_hwnd)}")
# 设置路径
local_file_path = os.path.join(win32gui.GetWindowText(address_hwnd).split(' ')[1], filename)
combo_handle = get_combobox_handle(parent_hwnd)
#logging.info(f"ComboBox Items: {get_combobox_items(combo_handle)}")
logging.info(f"Current Selected: {get_combobox_selected(combo_handle)}")
local_file_path = "C:\\RationalDMIS64\\Output\\" + get_combobox_selected(combo_handle) + "\\" + filename
logging.info(f"设置路径: {local_file_path}")
path_hwnds = find_child_window(parent_hwnd, 'Edit')
@@ -115,7 +182,6 @@ def wait_for_file_to_save(filepath, timeout=30):
def upload_file_to_ftp(local_file):
if not os.path.isfile(local_file):
raise HTTPException(status_code=204, detail="文件未找到")
@@ -157,4 +223,4 @@ async def upload_file(request: FileUploadRequest):
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
uvicorn.run(app, host="0.0.0.0", port=8999)

View File

@@ -27,7 +27,10 @@ export class StepViewer extends Component {
formatUrl() {
var url = '';
if (this.props.value) {
if (this.props.value.slice(-1) == 'b' && !isNaN(this.props.value.split(' ')[0])) {
if (this.props.value.startsWith('http')) {
// 从url读取文件内容
url = this.props.value;
} else if (this.props.value.slice(-1) == 'b' && !isNaN(this.props.value.split(' ')[0])) {
var url_props = {
base_url: session['web.base.url'],
model: this.props.record.resModel,
@@ -37,21 +40,19 @@ export class StepViewer extends Component {
url = url_props['base_url'].replace('http://', 'https://') + '/web/content/' + url_props['model'] + '/' + url_props['id'] + '/' + url_props['field'] + '?download=true';
// url = 'http://localhost:8069'+'/web/content/'+url_props['model']+'/'+url_props['id']+'/'+url_props['field']+'?download=true'
// console.log('url111111', url)
return url;
} else {
url = "data:model/gltf-binary;base64," + this.props.value;
// console.log('url2', url)
return url;
// localStorage.setItem('url',url)
// let new_url = localStorage.getItem(('url'))
// var oViewer = document.getElementsByTagName('model-viewer')[0];
// return new_url
// url = "web_widget_model_viewer/static/src/images/not_model.png";
}
} else {
// var oImg = document.getElementsByClassName('test')[0]
// console.log(oImg)
}
return url;
}
}