Compare commits

...

170 Commits

Author SHA1 Message Date
胡尧
39afc99b8f Merge branch 'release/release_2.4' 2024-10-11 09:29:34 +08:00
胡尧
b74bc62804 处理下发AGV小车任务报错的问题 2024-10-10 10:49:16 +08:00
胡尧
94f57629e5 增加空料架配送菜单权限 2024-10-09 17:23:03 +08:00
胡尧
e4c845a9f6 解决空料架配送不能正常下发AGV任务的问题 2024-10-09 14:08:38 +08:00
胡尧
d239509299 解决空料架配送不能正常下发AGV任务的问题 2024-10-09 13:53:49 +08:00
胡尧
457f0aa2ac 修复login页logo不显示的问题 2024-10-08 09:19:06 +08:00
胡嘉莹
84266364e3 Accept Merge Request #1381: (develop -> release/release_2.4)
Merge Request: 修改计划排程

Created By: @胡嘉莹
Accepted By: @胡嘉莹
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1381?initial=true
2024-09-29 17:25:11 +08:00
管欢
ea88d8284a Accept Merge Request #1380: (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/1380
2024-09-29 17:09:47 +08:00
guanhuan
d2ec420f57 域名获取修改 2024-09-29 17:05:42 +08:00
guanhuan
97d33adabd 域名获取修改 2024-09-29 17:03:49 +08:00
胡尧
c11f3cc66c Merge branch 'develop' into release/release_2.4 2024-09-29 16:51:41 +08:00
廖丹龙
6b4a7e35a9 Accept Merge Request #1375: (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/1375
2024-09-29 16:48:53 +08:00
guanhuan
11100c9260 域名获取修改 2024-09-29 16:47:35 +08:00
胡嘉莹
941c3ca43a Accept Merge Request #1379: (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/1379?initial=true
2024-09-29 16:47:10 +08:00
hujiaying
05f9528ca9 修改计划排程代码 2024-09-29 16:44:48 +08:00
杨金灵
b205945f65 Accept Merge Request #1378: (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/1378?initial=true
2024-09-29 16:43:54 +08:00
jinling.yang
c1dc28488a 修复待接单路径 2024-09-29 16:42:32 +08:00
jinling.yang
547d6608e6 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-09-29 15:40:50 +08:00
jinling.yang
dacb3cc076 Merge branch 'feature/消息模版初始化添加相关模版' into develop 2024-09-29 15:33:51 +08:00
胡尧
282657fbca Merge branch 'release/release_2.4' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into release/release_2.4 2024-09-29 15:32:37 +08:00
杨金灵
7e516c6f0b Accept Merge Request #1377: (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/1377
2024-09-29 15:31:28 +08:00
jinling.yang
34e2a49bef 注释部分不上的代码 2024-09-29 15:30:18 +08:00
jinling.yang
ff4bdd2f2d 还原代码 2024-09-29 15:27:27 +08:00
jinling.yang
b239fdf847 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-09-29 15:24:39 +08:00
jinling.yang
47feb4cf3c 消息模版初始化添加相关模版 2024-09-29 15:24:28 +08:00
胡嘉莹
63b732ff42 Accept Merge Request #1376: (develop -> release/release_2.4)
Merge Request: 排程计划bug合并

Created By: @胡嘉莹
Accepted By: @胡嘉莹
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1376?initial=true
2024-09-29 11:42:53 +08:00
胡嘉莹
50d63c28d6 Accept Merge Request #1374: (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/1374?initial=true
2024-09-29 10:36:32 +08:00
hujiaying
73b7ff7d1b 修改计划排程选择日期有生成量,不能排程问题 2024-09-29 10:33:19 +08:00
jinling.yang
ccdcd01372 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop
# Conflicts:
#	sf_message/__manifest__.py
2024-09-29 09:18:07 +08:00
liaodanlong
198296f0f8 价格计算 2024-09-27 18:04:39 +08:00
廖丹龙
f122343e31 Accept Merge Request #1373: (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/1373?initial=true
2024-09-27 18:02:25 +08:00
liaodanlong
82fa39f1a3 价格计算 2024-09-27 18:00:34 +08:00
廖丹龙
841e1b4ce2 Accept Merge Request #1372: (feature/销售和排程添加消息推送 -> develop)
Merge Request: d刀具标准库数据同步

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1372?initial=true
2024-09-27 17:46:09 +08:00
liaodanlong
1ab62d7724 d刀具标准库数据同步 2024-09-27 17:43:47 +08:00
胡尧
28a46d395b Accept Merge Request #1371: (feature/程序用刀异常提醒 -> develop)
Merge Request: 增加日志

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1371
2024-09-27 15:19:21 +08:00
胡尧
64c66f1272 增加日志 2024-09-27 15:18:27 +08:00
马广威
f8d957486b Accept Merge Request #1370: (feature/制造功能优化 -> develop)
Merge Request: 优化调整相关数据返回结构等

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1370
2024-09-27 14:47:16 +08:00
mgw
1866607967 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-27 14:41:41 +08:00
mgw
40efdf6f3b 隐藏status字段 2024-09-27 14:41:23 +08:00
胡尧
f910df3ce5 Accept Merge Request #1369: (feature/程序用刀异常提醒 -> develop)
Merge Request: 去掉多余的无效刀异常推送

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1369?initial=true
2024-09-27 14:39:55 +08:00
胡尧
c99c96a9ea 去掉多余的无效刀异常推送 2024-09-27 14:39:29 +08:00
胡尧
95cc557577 Accept Merge Request #1368: (feature/程序用刀异常提醒 -> develop)
Merge Request: 程序用刀异常提醒

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1368?initial=true
2024-09-27 14:38:10 +08:00
mgw
fa78389f47 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-27 14:31:39 +08:00
mgw
f7381c43aa 调整url的获取方式;暂时屏蔽历史日志部分 2024-09-27 14:31:22 +08:00
mgw
76c5db61da 增加24h的oee参数 2024-09-27 14:13:57 +08:00
胡尧
88ffc34a68 程序用刀异常提醒 2024-09-27 14:00:56 +08:00
禹翔辉
4f65b34aeb Accept Merge Request #1367: (feature/无效刀校验优化 -> develop)
Merge Request: cnc校验刀无效刀创建检测结果时先检测是否已经存在待处理记录

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1367?initial=true
2024-09-27 13:36:44 +08:00
yuxianghui
4a26d18b46 Merge branch 'feature/下发编程优化' into feature/无效刀校验优化 2024-09-27 13:34:10 +08:00
yuxianghui
664ac8128a cnc校验刀无效刀创建检测结果时先检测是否已经存在待处理记录 2024-09-27 13:32:55 +08:00
廖丹龙
ce285818cf Accept Merge Request #1366: (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/1366?initial=true
2024-09-27 11:55:16 +08:00
liaodanlong
6f7811a843 调拨入库、刀具组装,拆解消息推送模板预置数据 2024-09-27 11:53:55 +08:00
廖丹龙
54ed90e892 Accept Merge Request #1365: (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/1365?initial=true
2024-09-27 10:32:56 +08:00
liaodanlong
f8060113d9 产品关联数据字段修改 2024-09-27 10:14:13 +08:00
mgw
48ab891991 调整设备oee结构,去掉设备运行日志 2024-09-27 10:07:02 +08:00
guanhuan
7f384c3f56 消息模板初始数据 2024-09-27 09:36:51 +08:00
guanhuan
01a2771dfb Revert "消息模板初始数据"
This reverts commit 45b6214ddd.
2024-09-27 09:35:18 +08:00
guanhuan
45b6214ddd 消息模板初始数据 2024-09-27 09:33:17 +08:00
mgw
c96ff3f5b4 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-27 09:20:36 +08:00
mgw
d84758232e 优化值为空时的逻辑 2024-09-27 09:20:19 +08:00
廖丹龙
479953e082 Accept Merge Request #1364: (feature/销售和排程添加消息推送 -> develop)
Merge Request: r角默认值

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1364?initial=true
2024-09-27 09:12:03 +08:00
jinling.yang
27881589d4 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop
# Conflicts:
#	sf_message/__manifest__.py
#	sf_message/models/sf_message_workorder.py
2024-09-27 09:10:19 +08:00
liaodanlong
79ec3f2c91 r角默认值 2024-09-27 09:09:48 +08:00
管欢
715b4181be Accept Merge Request #1363: (feature/销售和排程添加消息推送 -> develop)
Merge Request: 删除重复we_employee_id

Created By: @管欢
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @管欢
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1363
2024-09-26 18:05:49 +08:00
liaodanlong
0ccda10c65 Merge remote-tracking branch 'origin/feature/销售和排程添加消息推送' into feature/销售和排程添加消息推送 2024-09-26 17:58:20 +08:00
liaodanlong
5b4376b5f9 r角默认值 2024-09-26 17:58:04 +08:00
guanhuan
1050f7616b 删除重复we_employee_id 2024-09-26 17:57:17 +08:00
禹翔辉
3a9cc0c09c Accept Merge Request #1362: (feature/下发编程优化 -> develop)
Merge Request: 屏蔽重新下发编程单时调用删除CAM程序用刀计划记录方法

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1362?initial=true
2024-09-26 16:38:07 +08:00
yuxianghui
4d63b90373 屏蔽重新下发编程单时调用删除CAM程序用刀计划记录方法 2024-09-26 16:36:49 +08:00
胡尧
43c4614650 Accept Merge Request #1361: (feature/程序用刀异常提醒 -> develop)
Merge Request: 屏蔽title写死JIKIMO的代码

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1361
2024-09-26 15:34:46 +08:00
胡尧
eba9ccf083 屏蔽title写死JIKIMO的代码 2024-09-26 15:33:39 +08:00
廖丹龙
947100a9d4 Accept Merge Request #1360: (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/1360?initial=true
2024-09-26 14:57:11 +08:00
liaodanlong
ed4924651a Merge remote-tracking branch 'origin/feature/销售和排程添加消息推送' into feature/销售和排程添加消息推送 2024-09-26 14:55:32 +08:00
liaodanlong
3cc2bb94fe 刀具拆解消息推送 2024-09-26 14:54:43 +08:00
管欢
8ecb3eb50a Accept Merge Request #1358: (feature/销售和排程添加消息推送 -> develop)
Merge Request: 消息通知url修改

Created By: @管欢
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @管欢
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1358
2024-09-26 14:09:10 +08:00
禹翔辉
819d89c278 Accept Merge Request #1359: (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/1359?initial=true
2024-09-26 14:06:53 +08:00
yuxianghui
66d47c60bc Merge branch 'feature/CAM优化' into feature/刀具标准库同步接口优化 2024-09-26 14:05:09 +08:00
mgw
0340563749 筛选加工时间不为空的24h数据 2024-09-26 14:04:35 +08:00
yuxianghui
271e23a67f 1、刀具标准库数据同步接口优化 2024-09-26 14:01:03 +08:00
guanhuan
de42382f58 Merge branch 'refs/heads/feature/程序用刀异常提醒' into feature/销售和排程添加消息推送
# Conflicts:
#	sf_message/models/sf_message_workorder.py
2024-09-26 13:54:28 +08:00
guanhuan
3728809d10 消息通知url修改 2024-09-26 13:43:47 +08:00
guanhuan
d4e2ace8a6 消息通知url修改 2024-09-26 12:36:00 +08:00
mgw
1d4188df7e 增加24h的故障时间返回 2024-09-26 11:11:46 +08:00
胡尧
a2323293ca Accept Merge Request #1357: (feature/程序用刀异常提醒 -> develop)
Merge Request: 无效刀判断后调用cloud发送消息推送接口

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1357
2024-09-26 10:31:26 +08:00
胡尧
29bd1c2968 解决冲突 2024-09-26 10:30:40 +08:00
胡尧
6c35ec13fd 无效刀判断后调用cloud发送消息推送接口 2024-09-26 10:28:38 +08:00
廖丹龙
83107b05e2 Accept Merge Request #1356: (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/1356?initial=true
2024-09-26 09:38:52 +08:00
liaodanlong
5fb7165306 调拨入库消息推送 2024-09-26 09:22:02 +08:00
liaodanlong
c569b60d5c 手动创建的拆解单不生成消息推送 2024-09-26 09:21:04 +08:00
mgw
bd2748659a 去掉关机率 2024-09-25 17:57:24 +08:00
jinling.yang
3ee233c0bc Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-09-25 17:45:34 +08:00
jinling.yang
d63081dffa 优化销售订单+工单逾期 2024-09-25 17:45:15 +08:00
马广威
0932ec95bf Accept Merge Request #1355: (feature/制造功能优化 -> develop)
Merge Request: 调整设备故障日志;增加24小时的运行数据

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1355?initial=true
2024-09-25 16:32:12 +08:00
mgw
7361da0e5d Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-25 16:29:05 +08:00
mgw
2dbddf532c 增加24小时的运行数据 2024-09-25 16:28:45 +08:00
管欢
eb867e62d8 Accept Merge Request #1354: (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/1354
2024-09-25 14:39:12 +08:00
liaodanlong
d75504960a Merge remote-tracking branch 'origin/feature/销售和排程添加消息推送' into feature/销售和排程添加消息推送 2024-09-25 14:37:05 +08:00
liaodanlong
93efbf742e 产品刀具参数物料与物料号数据关联 2024-09-25 14:36:32 +08:00
guanhuan
7c3ac138b5 工单已下发通知 2024-09-25 14:31:31 +08:00
mgw
63444d3dd1 调整默认值 2024-09-25 14:10:11 +08:00
mgw
2fcad742b8 调整alarm logs的返回数据 2024-09-25 14:08:05 +08:00
mgw
f341ef5e83 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-25 13:51:09 +08:00
mgw
d488824e3d 增加分页接口;合并日志状态相同数据 2024-09-25 13:50:50 +08:00
杨金灵
0c28700f75 Accept Merge Request #1353: (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/1353
2024-09-25 13:35:56 +08:00
禹翔辉
48d97f3e57 Accept Merge Request #1352: (feature/CAM优化 -> develop)
Merge Request: 添加CNC缺刀创建CAM日志

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1352?initial=true
2024-09-25 12:27:10 +08:00
jinling.yang
ef17c9920c 修复销售+排程消息推送 2024-09-25 12:00:46 +08:00
yuxianghui
ef643a5a72 Merge branch 'feature/程序用刀校验优化' into feature/CAM优化 2024-09-25 11:53:10 +08:00
yuxianghui
b7ff8d0bd5 添加CNC缺刀创建CAM日志 2024-09-25 11:52:29 +08:00
mgw
1e721d68bf 调整视图与增加字段 2024-09-25 11:41:23 +08:00
mgw
7454297dcd 调整设备故障日志 2024-09-25 11:24:01 +08:00
guanhuan
4e0a023c36 Merge remote-tracking branch 'origin/feature/销售和排程添加消息推送' into feature/销售和排程添加消息推送 2024-09-25 10:49:10 +08:00
guanhuan
155c5eb329 坯料采购提醒 2024-09-25 10:48:35 +08:00
jinling.yang
45718ab925 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-09-25 09:49:43 +08:00
廖丹龙
562c8dda8d Accept Merge Request #1350: (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/1350?initial=true
2024-09-24 17:59:43 +08:00
liaodanlong
84a37a970f 调拨入库消息推送 2024-09-24 17:57:03 +08:00
管欢
37cc02e97a Accept Merge Request #1349: (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/1349
2024-09-24 16:33:23 +08:00
guanhuan
7a8753408b 连接跳转 2024-09-24 16:23:45 +08:00
黄焱
eb853d0be9 Accept Merge Request #1345: (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/1345
2024-09-24 15:37:33 +08:00
廖丹龙
52438733d7 Accept Merge Request #1348: (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/1348?initial=true
2024-09-24 15:04:58 +08:00
liaodanlong
b986dd8473 刀具组装与拆解信息推送 2024-09-24 14:58:32 +08:00
jinling.yang
98fdb581fb Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-09-24 13:57:01 +08:00
胡尧
ea7380288c Accept Merge Request #1347: (feature/流程用扫码完成 -> develop)
Merge Request: 修改任务下发逻辑

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1347?initial=true
2024-09-24 11:43:54 +08:00
胡尧
9beecab21d 修改任务下发逻辑 2024-09-24 11:42:58 +08:00
jinling.yang
2e6932e054 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-09-24 11:39:33 +08:00
杨金灵
5ca9e028d8 Accept Merge Request #1346: (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/1346?initial=true
2024-09-24 11:19:11 +08:00
hy
64e2b71a34 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/前端样式修改 2024-09-24 11:15:10 +08:00
jinling.yang
8d52c94aed Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-09-24 11:15:04 +08:00
jinling.yang
9d91a1c99f 删除不要的模块 2024-09-24 11:14:55 +08:00
hy
d6fdeafef6 制造-刀具标准库界面样式显示有问题 2024-09-24 11:14:08 +08:00
guanhuan
371b3a9d65 Merge remote-tracking branch 'origin/feature/销售和排程添加消息推送' into feature/销售和排程添加消息推送 2024-09-24 10:57:02 +08:00
guanhuan
36c1c7b170 单已下发通知 2024-09-24 10:56:23 +08:00
liaodanlong
38d3a7901d 刀具组装与拆解信息推送 2024-09-24 10:23:09 +08:00
禹翔辉
2223259d13 Accept Merge Request #1344: (feature/程序用刀校验优化 -> develop)
Merge Request: CAM用刀添加编程单号字段,优化CNC程序用刀校验缺刀生成的CAM用刀计划记录的判断条件,优化tree和form视图;

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1344?initial=true
2024-09-24 09:53:35 +08:00
yuxianghui
aba270182d Merge branch 'feature/产品优化' into feature/程序用刀校验优化 2024-09-24 09:51:42 +08:00
yuxianghui
c9378fc9fe CAM用刀添加编程单号字段,优化CNC程序用刀校验缺刀生成的CAM用刀计划记录的判断条件,优化tree和form视图; 2024-09-24 09:50:44 +08:00
liaodanlong
378850682d 错误日志信息调整 2024-09-23 17:50:25 +08:00
liaodanlong
02c35803da Merge remote-tracking branch 'origin/feature/销售和排程添加消息推送' into feature/销售和排程添加消息推送 2024-09-23 17:47:30 +08:00
liaodanlong
75b60c1ec8 bom清单整体式刀具匹配条件修改 2024-09-23 17:47:03 +08:00
guanhuan
2cd4424ba1 Merge remote-tracking branch 'origin/feature/销售和排程添加消息推送' into feature/销售和排程添加消息推送 2024-09-23 17:12:26 +08:00
guanhuan
d52f0aed6e 坯料发料提醒 2024-09-23 17:11:53 +08:00
liaodanlong
d197fc5b9e 保留小数点后两位 2024-09-23 16:58:58 +08:00
guanhuan
34280fe24b 坯料发料提醒 2024-09-23 16:43:29 +08:00
胡尧
fd88a37aec Accept Merge Request #1343: (feature/wechat_message -> develop)
Merge Request: 修改屏蔽登录页footer

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1343
2024-09-23 16:38:19 +08:00
胡尧
b5f5826c80 Accept Merge Request #1342: (feature/wechat_message -> develop)
Merge Request: 处理皮肤问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1342?initial=true
2024-09-23 16:10:00 +08:00
马广威
2a14a630d5 Accept Merge Request #1341: (feature/制造功能优化 -> develop)
Merge Request: 调整记录匹配条件;优化排程单状态变化

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1341?initial=true
2024-09-23 14:30:57 +08:00
mgw
ef8ea2599f Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-23 14:30:09 +08:00
mgw
e9ab4270a9 调整记录匹配条件;优化排程单状态变化 2024-09-23 14:29:52 +08:00
廖丹龙
a99d651509 Accept Merge Request #1340: (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/1340
2024-09-23 14:25:01 +08:00
胡嘉莹
c54a5b36d4 Accept Merge Request #1339: (feature/update_production_line -> 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/1339
2024-09-23 14:24:03 +08:00
管欢
ec66ea76ba Accept Merge Request #1330: (feature/org_info_synchronous -> develop)
Merge Request: 用户新增企业微信id

Created By: @管欢
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @管欢
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1330
2024-09-23 13:36:06 +08:00
liaodanlong
8643c41193 代码还原 2024-09-23 13:33:05 +08:00
liaodanlong
bed0483496 Merge remote-tracking branch 'refs/remotes/origin/develop' into feature/销售和排程添加消息推送 2024-09-23 13:31:52 +08:00
liaodanlong
a648208656 Merge remote-tracking branch 'origin/feature/销售和排程添加消息推送' into feature/销售和排程添加消息推送 2024-09-23 13:31:46 +08:00
liaodanlong
98af6d0530 Merge remote-tracking branch 'refs/remotes/origin/develop' into feature/销售和排程添加消息推送 2024-09-23 13:31:27 +08:00
guanhuan
5af1953e04 坯料采购提醒 2024-09-23 13:20:31 +08:00
hujiaying
b1a08be57b bfm加工订单隐藏字段 ,待发货明细中,接单日期、发货日期顺序改变,欠单如果没有发货不要显示发货时间 、更改逾期状态逻辑。 2024-09-23 12:27:31 +08:00
马广威
15981aadf1 Accept Merge Request #1338: (feature/制造功能优化 -> develop)
Merge Request: 去掉工单明细处删除按钮;已完成工单取24小时内

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1338?initial=true
2024-09-23 12:09:20 +08:00
mgw
e19cb52e70 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-23 12:08:30 +08:00
mgw
5269d09d0e 去掉工单明细处删除按钮;已完成工单取24小时内 2024-09-23 12:08:02 +08:00
liaodanlong
e7e64720c6 消息推送 2024-09-23 11:55:28 +08:00
liaodanlong
a6701a842e 刀尖r角字段修改 2024-09-23 11:55:11 +08:00
胡尧
d697bd13a1 Accept Merge Request #1337: (feature/修改网站标题 -> develop)
Merge Request: 修改网站标题写死的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1337
2024-09-23 11:21:58 +08:00
胡尧
6e20a466ce 修改网站标题写死的问题 2024-09-23 11:21:17 +08:00
jinling.yang
759e4a481d Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-09-23 10:32:27 +08:00
jinling.yang
1213afe834 Merge branch 'feature/销售和排程添加消息推送' into develop 2024-09-23 10:32:18 +08:00
mgw
68f8c94332 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-23 08:55:40 +08:00
mgw
ddfb233452 修复按钮固定条件显示问题 2024-09-23 08:55:23 +08:00
mgw
eb7d9e4168 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-20 16:38:30 +08:00
mgw
8706e25b0d 增加24h与历史日志的数据拿取 2024-09-20 16:33:56 +08:00
guanhuan
56f1ba0f25 用户新增企业微信id 2024-09-20 14:24:50 +08:00
杨金灵
f230ad55fb Accept Merge Request #1284: (hotfix/修复报废-外协入库验证 -> master)
Merge Request: 修复报废-外协入库验证

Created By: @杨金灵
Accepted By: @杨金灵
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1284
2024-09-06 13:47:55 +08:00
62 changed files with 1639 additions and 735 deletions

View File

@@ -6,6 +6,6 @@ import { patch } from "web.utils";
patch(WebClient.prototype, "kolpolok_custom_title_and_favicon.WebClient", {
setup() {
this._super();
this.title.setParts({ zopenerp: "JIKIMO" });
// this.title.setParts({ zopenerp: "JIKIMO" });
},
});

View File

@@ -16,7 +16,7 @@
<!-- hide 登录页面 powerd by odoo 及管理数据库 -->
<template id="login_page_layout" inherit_id="web.login_layout" name="Login Page Layout">
<xpath expr="//div[@class='card-body']/div[last()]" position="replace"></xpath>
<!-- <xpath expr="//div[@class='card-body']/div[last()]" position="replace"></xpath> -->
</template>
<!-- 隐藏odoo版本信息 -->

View File

@@ -1 +0,0 @@
from . import models

View File

@@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': '机企猫智能工厂 消息提醒',
'version': '1.0',
'summary': '智能工厂消息提醒模块',
'sequence': 1,
'description': """
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['jikimo_message_notify'],
'data': [
'security/ir.model.access.csv',
'data/bussiness_node.xml',
# 'views/sf_message_template_view.xml',
],
'test': [
],
'license': 'LGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" ?>
<odoo>
<data>
<record id="bussiness_1" model="jikimo.message.bussiness.node">
<field name="name">订单确认</field>
<field name="model">sale.order</field>
</record>
</data>
</odoo>

View File

@@ -1,2 +0,0 @@
from . import jikimo_message_template
from . import sale_order

View File

@@ -1,10 +0,0 @@
from odoo import models, fields, api
class JikimoMessageTemplate(models.Model):
_inherit = "jikimo.message.template"
def _get_message_model(self):
res = super(JikimoMessageTemplate, self)._get_message_model()
res.append("sale.order")
return res

View File

@@ -1,12 +0,0 @@
from odoo import models, fields, api
class SaleOrder(models.Model):
_name = "sale.order"
_description = "销售订单"
_inherit = ["sale.order", "jikimo.message.dispatch"]
def create(self, vals_list):
res = super(SaleOrder, self).create(vals_list)
res.add_queue('订单确认')
return res

View File

@@ -1,5 +0,0 @@
<odoo>
<data>
</data>
</odoo>

View File

@@ -1,6 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink

View File

@@ -1,76 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © <2016> <top hy>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<data>
<record id="sf_message_template_view_form" model="ir.ui.view">
<field name="name">sf.message.template.view.form</field>
<field name="model">message.template</field>
<field name="arch" type="xml">
<form string="消息模板">
<sheet>
<div class="oe_title">
<label for="name"/>
<h1>
<field name="name" class="w-100" required="1"/>
</h1>
</div>
<group>
<!-- <field name="type"/>-->
<field name="notify_model_id"/>
<field name="content" widget="html" class="oe-bordered-editor"
options="{'style-inline': true, 'codeview': true, 'dynamic_placeholder': true}"/>
<field name="description"/>
<field name="msgtype"/>
<field name="notification_department_id"/>
<field name="notification_employee_ids" widget="many2many_tags"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="sf_message_template_view_tree" model="ir.ui.view">
<field name="name">sf.message.template.view.tree</field>
<field name="model">message.template</field>
<field name="arch" type="xml">
<tree string="消息模板">
<field name="name"/>
<!-- <field name="type"/>-->
<field name="content"/>
<field name="msgtype"/>
<field name="notification_department_id"/>
<field name="notification_employee_ids" widget="many2many_tags"/>
<field name="description"/>
</tree>
</field>
</record>
<record id="sf_message_template_search_view" model="ir.ui.view">
<field name="name">sf.message.template.search.view</field>
<field name="model">message.template</field>
<field name="arch" type="xml">
<search>
<field name="name" string="模糊搜索"
filter_domain="['|','|',('name','like',self),('description','like',self)]"/>
<field name="name"/>
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
</search>
</field>
</record>
<!--定义单证类型视图动作-->
<record id="sf_message_template_action" model="ir.actions.act_window">
<field name="name">消息模板</field>
<field name="res_model">message.template</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="sf_message_template_view_tree"/>
</record>
<menuitem id="msg_set_menu" name="消息设置" parent="base.menu_administration" sequence="1"/>
<menuitem id="sf_message_template_send_menu" name="消息模板" parent="msg_set_menu"
action="sf_message_template_action" sequence="1"/>
</data>
</odoo>

View File

@@ -321,7 +321,7 @@ class ToolInventory(models.Model):
prefix = fields.Char('前缀')
postfix = fields.Char('后缀')
diameter = fields.Float('直径(mm)')
angle = fields.Float('R角(mm)')
angle = fields.Float('R角(mm)',default=0)
tool_length = fields.Float('刀具总长(mm)')
blade_length = fields.Float('避空长/刃长(mm)')
knife_head_name = fields.Char('刀头名称')

View File

@@ -23,7 +23,7 @@ class ToolMaterialsBasicParameters(models.Model):
handle_length = fields.Float('柄部长度(mm)')
blade_tip_diameter = fields.Float('刀尖直径(mm)')
blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20)
tip_r_size = fields.Float('刀尖R角(mm)')
tip_r_size = fields.Float('刀尖R角(mm)',default=0)
blade_tip_taper = fields.Integer('刀尖锥度(°)')
blade_diameter = fields.Float('刃部直径(mm)')
blade_length = fields.Float('刃部长度(mm)')
@@ -38,7 +38,7 @@ class ToolMaterialsBasicParameters(models.Model):
width = fields.Float('宽度(mm)')
cutting_blade_length = fields.Float('切削刃长(mm)')
relief_angle = fields.Integer('后角(°)')
blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20)
blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20,default='0')
inscribed_circle_diameter = fields.Float('内接圆直径IC/D(mm)')
install_aperture_diameter = fields.Float('安装孔直径(mm)')
chip_breaker_groove = fields.Selection([('', ''), ('单面', '单面'), ('双面', '双面')],

View File

@@ -159,9 +159,6 @@ td.o_required_modifier {
display:inline;
}
.diameter{
display: flex !important;
justify-content: flex-start !important;
align-items: center !important;
}
.o_address_format {
display: flex !important;

View File

@@ -55,8 +55,7 @@ class StatusChange(models.Model):
logging.info('接口已经执行=============')
else:
traceback_error = traceback.format_exc()
logging.error("bfm订单状态同步失败:%s request info %s" % traceback_error)
logging.error('/api/get/state/get_order 请求失败{}'.format(ret))
logging.error("bfm订单状态同步失败:%s" % traceback_error)
raise UserError('工厂加工同步订单状态到bfm失败')
except UserError as e:
traceback_error = traceback.format_exc()

View File

@@ -7,7 +7,7 @@
'sequence': 1,
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['hr'],
'depends': ['base', 'hr'],
'data': [
'views/hr_employee.xml',
'views/res_config_settings_views.xml',

View File

@@ -20,7 +20,9 @@ class JkmPracticeEmployee(models.Model):
if result['employee_list']:
for employee_info in result['employee_list']:
if employee_info['work_email']:
self.sudo().search([('work_email', '=', employee_info['work_email'])]).write(
{'we_id': employee_info['we_id']})
hr_employee = self.sudo().search([('work_email', '=', employee_info['work_email'])])
hr_employee.write({'we_id': employee_info['we_id']})
if hr_employee.user_id:
hr_employee.user_id.write({'we_employee_id': employee_info['we_id']})
else:
logging.info('_employee_info_sync error:%s' % result['message'])

View File

@@ -30,7 +30,6 @@
'views/machine_info_present.xml',
'views/delivery_record.xml',
'views/res_config_settings_views.xml',
'views/maintenance_views.xml',
],
'assets': {

View File

@@ -162,7 +162,7 @@ class Sf_Dashboard_Connect(http.Controller):
# 关机时长:初次上线时间 - 通电时间
'power_off_time': power_off_time,
# 关机率:关机时长/初次上线时间
'power_off_rate': power_off_rate,
# 'power_off_rate': power_off_rate,
'first_online_duration': first_online_duration,
# 停机时间:关机时间 - 运行时间
# 停机时长:关机时间 - 初次上线时间
@@ -187,11 +187,11 @@ class Sf_Dashboard_Connect(http.Controller):
"""
res = {'status': 1, 'message': '成功', 'data': {}}
logging.info('前端请求日志数据的参数为:%s' % kw)
# 连接数据库
conn = psycopg2.connect(**db_config)
cur = conn.cursor()
try:
# 连接数据库
conn = psycopg2.connect(**db_config)
cur = conn.cursor()
machine_list = ast.literal_eval(kw['machine_list'])
begin_time_str = kw['begin_time'].strip('"')
end_time_str = kw['end_time'].strip('"')
@@ -231,6 +231,100 @@ class Sf_Dashboard_Connect(http.Controller):
res['message'] = '前端请求日志数据失败,原因:%s' % e
return json.dumps(res)
finally:
if cur:
cur.close()
if conn:
conn.close()
@http.route('/api/logs/page_data', type='http', auth='public', methods=['GET', 'POST'],
csrf=False, cors="*")
def logs_page_data(self, **kw):
"""
拿到日志数据返回给大屏展示(支持时间戳分页)
:param kw:
:return:
"""
res = {'status': 1, 'message': '成功', 'data': {}}
logging.info('前端请求日志数据的参数为:%s' % kw)
# 连接数据库
conn = psycopg2.connect(**db_config)
cur = conn.cursor()
try:
# 获取并解析传递的参数
machine_list = ast.literal_eval(kw.get('machine_list', '[]'))
begin_time_str = kw.get('begin_time', '').strip('"')
end_time_str = kw.get('end_time', '').strip('"')
page = int(kw.get('page', 1)) # 默认页码为1
page_size = int(kw.get('page_size', 80)) # 默认每页条数为10
begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
# 计算分页的 offset
offset = (page - 1) * page_size
# 先查询符合条件的总记录数
total_records = 0
for item in machine_list:
count_sql = '''
SELECT COUNT(*)
FROM device_data
WHERE device_name = %s AND time >= %s AND time <= %s;
'''
# 执行总记录数查询
cur.execute(count_sql, (item, begin_time, end_time))
record_count = cur.fetchone()[0] # 获取总记录数
total_records += record_count
# 计算总页数
if total_records > 0:
total_pages = (total_records + page_size - 1) // page_size # 向上取整
else:
total_pages = 0
# 将总页数和总记录数返回到响应中
res['total_records'] = total_records
res['total_pages'] = total_pages
for item in machine_list:
sql = '''
SELECT time, device_state, program_name
FROM device_data
WHERE device_name = %s AND time >= %s AND time <= %s
ORDER BY time DESC
LIMIT %s OFFSET %s;
'''
# 执行SQL命令使用参数绑定
cur.execute(sql, (item, begin_time, end_time, page_size, offset))
results = cur.fetchall()
# 将数据按照 equipment_code 进行分组
if item not in res['data']:
res['data'][item] = []
for result in results:
res['data'][item].append({
'time': result[0].strftime('%Y-%m-%d %H:%M:%S'),
'state': result[1],
'production_name': result[2],
})
return json.dumps(res) # 返回分页数据
except Exception as e:
logging.info('前端请求日志数据失败,原因:%s' % e)
res['status'] = -1
res['message'] = '前端请求日志数据失败,原因:%s' % e
return json.dumps(res)
finally:
if cur:
cur.close()
if conn:
conn.close()
# 返回CNC机床列表
@http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
cors="*")
@@ -378,7 +472,8 @@ class Sf_Dashboard_Connect(http.Controller):
pass_rate = 1
if pass_nums:
pass_rate = round(
(len(pass_nums) / detection_data if len(plan_data_finish_orders) > 0 else 0), 3)
# (len(pass_nums) / detection_data if len(plan_data_finish_orders) > 0 else 0), 3)
(len(pass_nums) / len(plan_data_finish_orders) if len(plan_data_finish_orders) > 0 else 0), 3)
# 返工率
rework_rate = round(
@@ -418,8 +513,9 @@ class Sf_Dashboard_Connect(http.Controller):
'plan_data_progress_deviation': plan_data_progress_deviation,
'plan_data_rework_counts': plan_data_rework_counts,
'on_time_rate': on_time_rate,
'detection_data': detection_data,
'pass_rate': pass_rate
# 'detection_data': detection_data,
'detection_data': plan_data_finish_counts,
'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts
}
res['data'][line] = data
@@ -489,11 +585,14 @@ class Sf_Dashboard_Connect(http.Controller):
for time_interval in time_intervals:
start_time, end_time = time_interval
# print(start_time, end_time)
orders = plan_obj.search([('production_line_id.name', '=', line), ('state', 'in', ['finished']),
(date_field_name, '>=', start_time.strftime('%Y-%m-%d 00:00:00')),
(date_field_name, '<', end_time.strftime('%Y-%m-%d 00:00:00'))
])
orders = plan_obj.search([
('production_line_id.name', '=', line),
('state', 'in', ['finished']),
(date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')),
(date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间
])
# 使用小时和分钟作为键,确保每个小时的数据有独立的键
key = start_time.strftime('%H:%M:%S') # 只取小时:分钟:秒作为键
time_count_dict[key] = len(orders)
@@ -626,10 +725,16 @@ class Sf_Dashboard_Connect(http.Controller):
('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True)
])
# print(not_done_orders)
# 完成订单
# 获取当前时间并计算24小时前的时间
current_time = datetime.now()
time_24_hours_ago = current_time - timedelta(hours=24)
finish_orders = plan_obj.search([
('production_line_id.name', '=', line), ('state', 'in', ['finished']),
('production_id.state', 'not in', ['cancel']), ('active', '=', True)
('production_id.state', 'not in', ['cancel']), ('active', '=', True),
('actual_end_time', '>=', time_24_hours_ago)
])
# print(finish_orders)
@@ -687,6 +792,8 @@ class Sf_Dashboard_Connect(http.Controller):
not_done_data.append(line_dict)
for finish_order in finish_orders:
if not finish_order.actual_end_time:
continue
blank_name = ''
try:
blank_name = finish_order.production_id.move_raw_ids[0].product_id.name
@@ -707,7 +814,8 @@ class Sf_Dashboard_Connect(http.Controller):
'material': material,
'dimensions': dimensions,
'order_qty': finish_order.product_qty,
'finish_time': finish_order.actual_end_time.strftime('%Y-%m-%d %H:%M:%S'),
'finish_time': finish_order.actual_end_time.strftime(
'%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' '
}
done_data.append(line_dict)
@@ -745,10 +853,10 @@ class Sf_Dashboard_Connect(http.Controller):
'''
sql2 = '''
SELECT DISTINCT ON (alarm_time) alarm_time, alarm_repair_time
SELECT DISTINCT ON (alarm_start_time) alarm_time, alarm_start_time
FROM device_data
WHERE device_name = %s AND alarm_time IS NOT NULL
ORDER BY alarm_time, time;
WHERE device_name = %s AND alarm_start_time IS NOT NULL
ORDER BY alarm_start_time, time;
'''
# 执行SQL命令
@@ -764,8 +872,11 @@ class Sf_Dashboard_Connect(http.Controller):
res['data'][item] = {'idle_count': row[0]}
alarm_count = []
for row in result2:
alarm_count.append(row[0])
total_alarm_time += abs(float(row[0]))
alarm_count.append(row[1])
if row[0]:
total_alarm_time += abs(float(row[0]))
else:
total_alarm_time += 0.0
if len(list(set(alarm_count))) == 1:
if list(set(alarm_count))[0] is None:
alarm_count_num = 0
@@ -791,54 +902,27 @@ class Sf_Dashboard_Connect(http.Controller):
"""
查询设备的异常情况
"""
res = {'status': 1, 'message': '成功', 'data': {}}
res = {'status': 1, 'message': '成功', 'data': []}
logging.info('前端请求机床数据的参数为:%s' % kw)
# 连接数据库
conn = psycopg2.connect(**db_config)
cur = conn.cursor()
try:
# 获取请求的机床数据
maintenance_logs_obj = request.env['sf.maintenance.logs'].sudo()
# # 获取请求的机床数据
# machine_list = ast.literal_eval(kw['machine_list'])
# idle_times = []
# idle_dict = {}
# for item in machine_list:
sql = '''
SELECT DISTINCT ON (alarm_time) alarm_time, alarm_message, system_date, system_time, alarm_repair_time
FROM device_data
WHERE alarm_time IS NOT NULL
ORDER BY alarm_time, time;
# machine_data = equipment_obj.search([('code', '=', item)])
for log in maintenance_logs_obj.search([]):
res['data'].append({
'name': log.name,
'alarm_time': log.alarm_time.strftime('%Y-%m-%d %H:%M:%S'),
'fault_alarm_info': log.fault_alarm_info if log.fault_alarm_info else ' ',
'fault_process': log.fault_process if log.fault_process else ' ',
})
'''
# 执行SQL命令
cur.execute(sql)
result = cur.fetchall()
# print('result', result)
# 将查询结果转换为字典列表
data = []
for row in result:
record = {
'alarm_time': row[0],
'alarm_message': row[1],
'system_date': row[2],
'system_time': row[3],
'alarm_repair_time': row[4]
}
data.append(record)
# 将数据填充到返回结果中
res['data'] = data
# 返回统计结果
return json.dumps(res, ensure_ascii=False)
except Exception as e:
print(f"An error occurred: {e}")
return json.dumps(res)
finally:
cur.close()
conn.close()
logging.error(f"An error occurred: {e}")
return json.dumps(res)
# 设备oee
@http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
@@ -1155,27 +1239,80 @@ class Sf_Dashboard_Connect(http.Controller):
conn = psycopg2.connect(**db_config)
# 获取请求的机床数据
machine_list = ast.literal_eval(kw['machine_list'])
time_threshold = datetime.now() - timedelta(days=1)
alarm_last_24_time = 0.0
def fetch_result_as_dict(cursor):
"""辅助函数:将查询结果转为字典"""
columns = [desc[0] for desc in cursor.description]
return dict(zip(columns, cursor.fetchone())) if cursor.rowcount != 0 else None
# 获取当前时间的时间戳
current_timestamp = datetime.now().timestamp()
for item in machine_list:
euipment_obj = request.env['maintenance.equipment'].sudo().search([('code', '=', item)])
# 机床上线时间段
first_online_duration = current_timestamp - euipment_obj.first_online_time.timestamp()
with conn.cursor() as cur:
cur.execute("""
SELECT * FROM device_data
WHERE device_name = %s
AND device_state != '离线'
ORDER BY time DESC
LIMIT 1;
""", (item,))
SELECT * FROM device_data
WHERE device_name = %s
AND device_state != '离线' AND process_time IS NOT NULL
ORDER BY time DESC
LIMIT 1;
""", (item,))
last_all_time = fetch_result_as_dict(cur)
with conn.cursor() as cur:
cur.execute("""
SELECT * FROM device_data
WHERE device_name = %s
AND device_state != '离线' AND time >= %s AND process_time IS NOT NULL
ORDER BY time ASC
LIMIT 1;
""", (item, time_threshold))
last_24_time = fetch_result_as_dict(cur)
with conn.cursor() as cur:
cur.execute("""
SELECT COUNT(*)
FROM (
SELECT DISTINCT ON (idle_start_time) idle_start_time
FROM device_data
WHERE device_name = %s AND idle_start_time IS NOT NULL AND time >= %s
ORDER BY idle_start_time, time
) subquery;
""", (item, time_threshold))
idle_count = cur.fetchone()[0]
alarm_last_24_nums = []
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 AND time >= %s;
""", (item, time_threshold))
results = cur.fetchall()
for result in results:
alarm_last_24_nums.append(result[1])
if result[0]:
if float(result[0]) >= 1000:
continue
alarm_last_24_time += float(result[0])
else:
alarm_last_24_time += 0.0
# 返回数据
res['data'][item] = {
'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0,
'cut_time': last_all_time['process_time'] if last_all_time['process_time'] is not None else 0,
'power_on_time': last_all_time['power_on_time'] if last_all_time['power_on_time'] is not None else 0
'cut_24_time': last_24_time['process_time'] if last_24_time['process_time'] is not None else 0,
'power_on_time': last_all_time['power_on_time'] if last_all_time['power_on_time'] is not None else 0,
'power_on_24_time': last_24_time['power_on_time'] if last_24_time['power_on_time'] is not None else 0,
'alarm_last_24_time': alarm_last_24_time,
'alarm_last_24_nums': len(list(set(alarm_last_24_nums))),
'idle_count': idle_count,
'first_online_time': first_online_duration,
}
conn.close()

View File

@@ -285,26 +285,6 @@ class Machine_ftp(models.Model):
# # 开动率
run_rate = fields.Char('开动率', readonly=True)
# 同步CNC设备到oee
def sync_oee(self):
"""
同步CNC设备到oee
:return:
"""
for record in self:
record.ensure_one()
cnc_oee_dict = {
'equipment_id': record.id,
'type_id': record.type_id.id,
'machine_tool_picture': record.machine_tool_picture,
'equipment_code': record.code,
'function_type': record.function_type,
}
if self.env['maintenance.equipment.oee.logs'].search([('equipment_id', '=', record.id)]):
self.env['maintenance.equipment.oee.logs'].write(cnc_oee_dict)
else:
self.env['maintenance.equipment.oee.logs'].create(cnc_oee_dict)
class WorkCenterBarcode(models.Model):
"""

View File

@@ -14,7 +14,7 @@
<group string='状态监控'>
<group>
<!-- <field name="timestamp"/> -->
<field name="status"/>
<!-- <field name="status"/> -->
<field name="run_status"/>
<field name="run_time"/>
<field name="system_date"/>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0"?>
<odoo>
<!-- 修改设备列表视图-->
<record id="sf_machine_hr_equipment_view_tree_inherit" model="ir.ui.view">
<field name="name">sf.machine.hr.equipment.view.tree.inherit</field>
<field name="model">maintenance.equipment</field>
<field name="inherit_id" ref="maintenance.hr_equipment_view_tree"/>
<field name="arch" type="xml">
<xpath expr="//tree" position="inside">
<header>
<button name="sync_oee" type="object" string="同步设备至OEE"/>
</header>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,13 +1,14 @@
# -*-coding:utf-8-*-
from odoo import fields, models
from odoo import fields, models, api
class SfMaintenanceLogs(models.Model):
_name = 'sf.maintenance.logs'
_description = '设备故障日志'
_order = 'alarm_time desc'
code = fields.Char(string='编码')
name = fields.Char(string='名称')
code = fields.Char(string='编码', readonly=True)
name = fields.Char(string='名称', compute='_compute_name')
type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型')
brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌')
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='机台号')
@@ -28,3 +29,13 @@ class SfMaintenanceLogs(models.Model):
fault_duration = fields.Float(string='故障时长')
note = fields.Text(string='备注')
active = fields.Boolean('Active', default=True)
@api.depends('code')
def _compute_name(self):
for record in self:
if record.code:
record.name = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).name
record.maintenance_equipment_id = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).id
else:
record.name = ''

View File

@@ -1,5 +1,46 @@
# -*- coding: utf-8 -*-
import re
import json
import datetime
import requests
from odoo import api, fields, models, _
from odoo.exceptions import UserError
def convert_to_seconds(time_str):
# 修改正则表达式,使 H、M、S 部分可选
if time_str is None:
return 0
pattern = r"(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?"
match = re.match(pattern, time_str)
if match:
# 提取各时间单位如果某个单位缺失则默认设为0
hours = int(match.group(1)) if match.group(1) else 0
minutes = int(match.group(2)) if match.group(2) else 0
seconds = int(match.group(3)) if match.group(3) else 0
# 计算总秒数
total_seconds = hours * 3600 + minutes * 60 + seconds
if total_seconds == 0:
# return None
pattern = r"(?:(\d+)小时)?(?:(\d+)分钟)?(?:(\d+)秒)?"
match = re.match(pattern, time_str)
if match:
# 提取各时间单位如果某个单位缺失则默认设为0
hours = int(match.group(1)) if match.group(1) else 0
minutes = int(match.group(2)) if match.group(2) else 0
seconds = int(match.group(3)) if match.group(3) else 0
# 计算总秒数
total_seconds = hours * 3600 + minutes * 60 + seconds
return total_seconds
else:
return None
return total_seconds
class SfMaintenanceEquipmentOEE(models.Model):
@@ -9,24 +50,225 @@ class SfMaintenanceEquipmentOEE(models.Model):
name = fields.Char('设备oee')
equipment_id = fields.Many2one('maintenance.equipment', '机台号',
domain="[('category_id.equipment_type', '=', '机床'),('state_zc', '=', '已注册')]")
equipment_code = fields.Char('设备编码', related='equipment_id.code', store=True)
type_id = fields.Many2one('sf.machine_tool.type', '型号', related='equipment_id.type_id')
machine_tool_picture = fields.Binary('设备图片', related='equipment_id.machine_tool_picture')
state = fields.Selection(
[("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"),
("封存(报废)", "封存(报废)")],
default='正常', string="机床状态", related='equipment_id.state')
run_time = fields.Float('加工时长(h)')
equipment_time = fields.Float('开机时长(h)')
done_nums = fields.Integer('加工件数')
utilization_rate = fields.Char('可用率')
fault_time = fields.Float('故障时长')
fault_nums = fields.Integer('故障次数')
# 故障率
fault_rate = fields.Char('故障率')
online_time = fields.Char('开机时长(小时)', reaonly='True')
offline_time = fields.Char('关机时长(小时)', reaonly='True')
idle_nums = fields.Integer('待机次数', reaonly='True')
# 待机时长
idle_time = fields.Char('待机时长(小时)', reaonly='True')
# 待机率
idle_rate = fields.Char('待机率(%)', reaonly='True')
work_time = fields.Char('加工时长(小时)', reaonly='True')
work_rate = fields.Char('可用率(%)', reaonly='True')
fault_time = fields.Char('故障时长(小时)', reaonly='True')
fault_rate = fields.Char('故障率(%)', reaonly='True')
fault_nums = fields.Integer('故障次数', reaonly='True')
# 设备故障日志
sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志',
related='equipment_id.sf_maintenance_logs_ids')
oee_logs = fields.One2many('maintenance.equipment.oee.logs', 'equipment_oee_id', string='运行日志')
day_logs_detail = fields.Html('日运行日志详情')
history_logs_detail = fields.Html('历史运行日志详情')
begin_time = fields.Date('开始时间')
end_time = fields.Date('结束时间')
# 获取日志详情
def get_day_logs(self):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
print(base_url)
config = self.env['ir.config_parameter'].sudo()
# url = 'http://172.16.10.112:8069/api/logs/list'
# url_time = 'http://localhost:9069/api/RunningTimeDetail'
url = base_url + '/api/logs/list'
url_time = base_url + '/api/RunningTimeDetail'
machine_list = [self.equipment_code]
begin_time = datetime.datetime.now().strftime('%Y-%m-%d') + ' 00:00:00'
end_time = datetime.datetime.now().strftime('%Y-%m-%d') + ' 23:59:59'
# 请求的数据
data = {
"machine_list": str(machine_list),
"begin_time": begin_time,
"end_time": end_time
}
data_time = {
"machine_list": str(machine_list)
}
print(data)
# 发送POST请求
response = requests.post(url, json={}, data=data)
response_time = requests.post(url_time, json={}, data=data_time)
# print(response.json()) # 输出服务器返回的响应
print(response_time.json())
if response_time.status_code == 200:
result_time = response_time.json()
real_dict = result_time['data'][self.equipment_code]
print('=', result_time)
if result_time['status'] == 1:
self.online_time = round((convert_to_seconds(real_dict['power_on_time']) - convert_to_seconds(
real_dict['power_on_24_time'])) / 3600, 2)
self.work_time = round(
(convert_to_seconds(real_dict['cut_time']) - convert_to_seconds(real_dict['cut_24_time'])) / 3600,
2)
self.offline_time = 24 - (float(self.online_time) if self.online_time else 0)
self.idle_time = float(self.online_time) - float(
self.work_time) if self.online_time and self.work_time else 0
self.idle_rate = round(
float(self.idle_time) / (float(self.online_time) if self.online_time else 1) * 100, 2)
self.work_rate = round(
float(self.work_time) / (float(self.online_time) if self.online_time else 1) * 100, 2)
self.fault_time = (float(real_dict['alarm_last_24_time']) if real_dict[
'alarm_last_24_time'] else 0) / 3600
self.fault_rate = round(
float(self.fault_time) / (float(self.online_time) if self.online_time else 1) * 100, 2)
self.fault_nums = real_dict['alarm_last_24_nums']
self.idle_nums = real_dict['idle_count']
if response.status_code == 200:
result = response.json()
print('============', result)
if result['status'] == 1:
logs_list = result['data'][self.equipment_code]
logs_detail = ''
log_state = ''
for log in logs_list:
if log['state'] != log_state:
print('loooooooooooooooooooogs', log)
production_name = log['production_name'] if log['production_name'] else ' '
logs_detail += '<tr><td>' + log['time'] + '</td><td>' + log[
'state'] + '</td><td>' + production_name + '</td></tr>'
log_state = log['state']
# self.day_logs_detail = '<table><tr><th>时间</th><th>事件/状态</th><th>加工工单</th></tr>' + logs_detail + '</table>'
self.day_logs_detail = '''
<table border="1" style="border-collapse: collapse; width: 100%; text-align: center;">
<tr style="background-color: #f2f2f2;">
<th style="padding: 8px; border: 1px solid #ddd;">时间</th>
<th style="padding: 8px; border: 1px solid #ddd;">事件/状态</th>
<th style="padding: 8px; border: 1px solid #ddd;">加工工单</th>
</tr>
{logs_detail}
</table>
'''.format(logs_detail=logs_detail)
else:
self.day_logs_detail = '获取日志失败'
else:
self.day_logs_detail = '获取日志失败'
# 获取历史日志详情
def get_history_logs(self):
config = self.env['ir.config_parameter'].sudo()
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
# url = 'http://172.16.10.112:8069/api/logs/list'
url = base_url + '/api/logs/list'
url_time = base_url + '/api/RunningTimeDetail'
machine_list = [self.equipment_code]
if not self.begin_time:
raise UserError('请选择开始时间')
if not self.end_time:
raise UserError('请选择结束时间')
begin_time = self.begin_time.strftime('%Y-%m-%d') + ' 00:00:00'
end_time = self.end_time.strftime('%Y-%m-%d') + ' 23:59:59'
# 请求的数据
data = {
"machine_list": str(machine_list),
"begin_time": begin_time,
"end_time": end_time
}
print(data)
# 发送POST请求
response = requests.post(url, json={}, data=data)
print(response.json()) # 输出服务器返回的响应
if response.status_code == 200:
result = response.json()
print('============', result)
if result['status'] == 1:
logs_list = result['data'][self.equipment_code]
logs_detail = ''
log_state = ''
for log in logs_list:
if log['state'] != log_state:
production_name = log['production_name'] if log['production_name'] else ' '
logs_detail += '<tr><td>' + log['time'] + '</td><td>' + log[
'state'] + '</td><td>' + production_name + '</td></tr>'
log_state = log['state']
# self.day_logs_detail = '<table><tr><th>时间</th><th>事件/状态</th><th>加工工单</th></tr>' + logs_detail + '</table>'
self.history_logs_detail = '''
<table border="1" style="border-collapse: collapse; width: 100%; text-align: center;">
<tr style="background-color: #f2f2f2;">
<th style="padding: 8px; border: 1px solid #ddd;">时间</th>
<th style="padding: 8px; border: 1px solid #ddd;">事件/状态</th>
<th style="padding: 8px; border: 1px solid #ddd;">加工工单</th>
</tr>
{logs_detail}
</table>
'''.format(logs_detail=logs_detail)
else:
self.history_logs_detail = '获取日志失败'
else:
self.history_logs_detail = '获取日志失败'
# 下载历史日志
def download_history_logs(self):
config = self.env['ir.config_parameter'].sudo()
url = 'http://172.16.10.112:8069/api/logs/list'
machine_list = [self.equipment_code]
if not self.begin_time:
raise UserError('请选择开始时间')
if not self.end_time:
raise UserError('请选择结束时间')
begin_time = self.begin_time.strftime('%Y-%m-%d') + ' 00:00:00'
end_time = self.end_time.strftime('%Y-%m-%d') + ' 23:59:59'
# 请求的数据
data = {
"machine_list": str(machine_list),
"begin_time": begin_time,
"end_time": end_time
}
print(data)
# 发送POST请求
response = requests.post(url, json={}, data=data)
print(response.json()) # 输出服务器返回的响应
if response.status_code == 200:
result = response.json()
print('============', result)
if result['status'] == 1:
logs_list = result['data'][self.equipment_code]
logs_detail = ''
for log in logs_list:
production_name = log['production_name'] if log['production_name'] else ' '
# todo 下载日志
else:
self.history_logs_detail = '下载日志失败'
else:
self.history_logs_detail = '下载日志失败'
def name_get(self):
result = []
@@ -95,4 +337,3 @@ class SfMaintenanceEquipmentOEELogDetail(models.Model):
log_id = fields.Many2one('maintenance.equipment.oee.logs', '日志')
# equipment_code = fields.Char('设备编码', related='log_id.equipment_code')
equipment_code = fields.Char('设备编码', readonly='True')

View File

@@ -67,6 +67,3 @@ access_sf_cutting_tool_type_admin_sf_group_equipment_user,sf_cutting_tool_type_a
access_sf_cutting_tool_type_group_purchase_director_sf_group_equipment_user,sf_cutting_tool_type_group_purchase_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
access_sf_cutting_tool_type_group_sale_director_sf_group_equipment_user,sf_cutting_tool_type_group_sale_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
access_sf_cutting_tool_type_group_plan_director_sf_group_equipment_user,sf_cutting_tool_type_group_plan_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
access_maintenance_equipment_oee_logs,maintenance_equipment_oee_logs,model_maintenance_equipment_oee_logs,sf_maintenance.sf_group_equipment_manager,1,1,1,1
access_maintenance_equipment_oee_log_detail,maintenance_equipment_oee_log_detail,model_maintenance_equipment_oee_log_detail,sf_maintenance.sf_group_equipment_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
67
68
69

View File

@@ -8,13 +8,13 @@
<field name="arch" type="xml">
<tree>
<field name="equipment_id"/>
<field name="equipment_time"/>
<field name="run_time"/>
<field name="done_nums"/>
<field name="utilization_rate"/>
<field name="online_time"/>
<field name="work_time"/>
<field name="work_rate"/>
<field name="fault_time"/>
<field name="fault_nums"/>
<field name="fault_rate"/>
</tree>
</field>
</record>
@@ -37,32 +37,102 @@
<group>
<group>
<field name="type_id" readonly="1"/>
<field name="equipment_time"/>
<field name="run_time"/>
<field name="done_nums"/>
<field name="utilization_rate"/>
<field name="fault_time"/>
<field name="fault_nums"/>
<group>
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
<field name="type_id"/>
<field name="state"/>
<field name="equipment_code"/>
</group>
</group>
<group>
<field name="machine_tool_picture" widget="image" readonly="1"/>
<group>
<!-- <field name="state" nolabel="1"/> -->
<!-- <field name="state" string=""/> -->
</group>
<group>
<field name="machine_tool_picture" widget="image" nolabel="1"/>
</group>
</group>
</group>
<group>
<group>
<group>
<field name="online_time" readonly="1"/>
<field name="offline_time" readonly="1"/>
<field name="fault_rate" readonly="1"/>
</group>
<group>
<field name="idle_nums" readonly="1"/>
<field name="fault_time" readonly="1"/>
<field name="fault_nums" readonly="1"/>
</group>
</group>
<group>
<group>
<field name="idle_time"/>
<field name="idle_rate"/>
</group>
<group>
<field name="work_time"/>
<field name="work_rate"/>
</group>
</group>
</group>
<!-- <notebook> -->
<!-- <page string="运行日志"> -->
<!-- <field name="oee_logs"> -->
<!-- <tree create="1" edit="1" delete="1" editable="bottom"> -->
<!-- <field name = 'run_time'/> -->
<!-- <field name = 'state'/> -->
<!-- <field name = 'workorder_id'/> -->
<!-- <field name = 'time'/> -->
<!-- <field name = 'color' widget="color"/> -->
<!-- </tree> -->
<!-- </field> -->
<notebook>
<page string="24H日志详情">
<group>
<button name="get_day_logs" type="object" string="查看24H日志" t-attf-style="white-space:nowrap;"/>
</group>
<field name="day_logs_detail" readonly="1" widget="html"/>
<!-- <field name="page_num"/> -->
<!-- <group> -->
<!-- <group> -->
<!-- <button name="previous_day_logs" type="object" string="上一页" t-attf-style="white-space:nowrap;"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <button name="next_day_logs" type="object" string="下一页" t-attf-style="white-space:nowrap;"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- <field name="day_logs_detail"/> -->
<!-- <field name="day_logs_detail" widget="html" nolabel="1"/> -->
<!-- <field name="day_logs_detail" widget="html" nolabel="1" class="oe_form_field oe_form_field_html"/> -->
<!-- <field name="day_logs_detail" widget="html" nolabel="1" class="oe_form_field oe_form_field_html" options='{"class": "o_form_readonly"}'/> -->
<!-- <field name="day_logs_detail" widget="html" nolabel="1" class="oe_form_field oe_form_field_html" options='{"class": "o_form_readonly", "readonly": true, "style": "width: 100%; height: 400px;"}'/> -->
<!-- <group> -->
<!-- <div class="oe_html_field"> -->
<!-- <div id="pagination_day_logs"> -->
<!-- <button id="prev_page_day_logs" disabled="true">Previous</button> -->
<!-- <button id="next_page_day_logs">Next</button> -->
<!-- </div> -->
<!-- </div> -->
<!-- </group> -->
</page>
<!-- <page string="历史日志详情"> -->
<!-- <group> -->
<!-- <group> -->
<!-- <group> -->
<!-- <field name="begin_time"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="end_time"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- <group> -->
<!-- <group> -->
<!-- <button name="get_history_logs" type="object" string="查看历史日志" t-attf-style="white-space:nowrap;"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <button name="download_history_logs" type="object" string="下载历史日志" t-attf-style="white-space:nowrap;"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- </group> -->
<!-- <field name="history_logs_detail"/> -->
<!-- </page> -->
<!-- </notebook> -->
</notebook>
</sheet>
</form>
</field>

View File

@@ -8,8 +8,8 @@
<field name="arch" type="xml">
<tree>
<field name="type" optional="hide"/>
<field name="brand"/>
<field name="maintenance_equipment_id"/>
<!-- <field name="brand"/> -->
<field name="name"/>
<field name="code_location" optional="hide"/>
<field name="fault_code" optional="hide"/>
<field name="alarm_time"/>
@@ -37,13 +37,14 @@
<sheet>
<div class="oe_title">
<h1>
<field name="code" readonly="1"/>
<field name="name" readonly="1"/>
</h1>
</div>
<group>
<group>
<!-- <field name="name"/> -->
<field name="code"/>
<!-- <field name="type" required="1" widget="radio" options="{'horizontal': true}"/> -->
<field name="maintenance_equipment_id"/>
<field name="brand"/>
@@ -57,7 +58,6 @@
</group>
<group>
<field name="operator"/>
<field name="fault_process"/>
<!-- <field name="alarm_way" required="1" widget="radio" options="{'horizontal': true}"/> -->
<field name="recovery_time"/>
@@ -105,249 +105,6 @@
</field>
</record>
<!-- 设备运行日志 -->
<record id="view_maintenance_logs_run_tree" model="ir.ui.view">
<field name="name">maintenance.logs.run.tree</field>
<field name="model">maintenance.equipment.oee.logs</field>
<field name="arch" type="xml">
<tree>
<field name="equipment_id"/>
</tree>
</field>
</record>
<record id="view_maintenance_logs_run_form" model="ir.ui.view">
<field name="name">maintenance.logs.run.form</field>
<field name="model">maintenance.equipment.oee.logs</field>
<field name="arch" type="xml">
<!-- <form string="设备运行日志"> -->
<!-- <header> -->
<!-- <field name="equipment_id" readonly="1"/> -->
<!-- </header> -->
<!-- <sheet> -->
<!-- <div class="oe_title"> -->
<!-- <h1> -->
<!-- <field name="start_time" readonly="1"/> -->
<!-- </h1> -->
<!-- </div> -->
<!-- <group> -->
<!-- <group> -->
<!-- <field name="stop_time" readonly="1"/> -->
<!-- <field name="duration" readonly="1"/> -->
<!-- <field name="oee" readonly="1"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="note"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- </sheet> -->
<!-- </form> -->
<form string="设备运行日志">
<!-- <header> -->
<!-- <field name="name" readonly="1"/> -->
<!-- </header> -->
<sheet>
<div class="oe_title">
<h1>
<field name="name"/>
</h1>
</div>
<group>
<group>
<group>
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
<field name="type_id"/>
<field name="state"/>
<field name="equipment_code"/>
<field name="function_type"/>
</group>
</group>
<group>
<group>
<!-- <field name="state" nolabel="1"/> -->
<field name="state" string=""/>
</group>
<group>
<field name="machine_tool_picture" widget="image" nolabel="1"/>
</group>
</group>
</group>
<group>
<group>
<group>
<field name="online_time" readonly="1"/>
<field name="offline_time" readonly="1"/>
<field name="fault_rate" readonly="1"/>
</group>
<group>
<field name="offline_nums" readonly="1"/>
<field name="fault_time" readonly="1"/>
<field name="fault_nums" readonly="1"/>
</group>
</group>
<group>
<group>
<field name="idle_time"/>
<field name="idle_rate"/>
</group>
<group>
<field name="work_time"/>
<field name="work_rate"/>
</group>
</group>
</group>
<notebook>
<page string="24H日志详情">
<!-- 筛选出24小时内的日志 -->
<!-- <field name="detail_ids" domain="[('time','&lt;',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> -->
<field name="detail_ids" domain="[('state','ilike','加工')]">
<tree>
<!-- <field name="sequence"/> -->
<field name="time"/>
<field name="state"/>
<field name="production_name"/>
</tree>
<!-- <form> -->
<!-- <field name="sequence"/> -->
<!-- <field name="time"/> -->
<!-- <field name="state"/> -->
<!-- <field name="production_id"/> -->
<!-- </form> -->
</field>
</page>
<page string="历史日志详情">
<field name="detail_ids">
<tree>
<!-- <field name="sequence"/> -->
<field name="time"/>
<field name="state"/>
<field name="production_name"/>
</tree>
<!-- <form> -->
<!-- <field name="sequence"/> -->
<!-- <field name="time"/> -->
<!-- <field name="state"/> -->
<!-- <field name="production_id"/> -->
<!-- </form> -->
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- <record id="view_maintenance_logs_run_search" model="ir.ui.view"> -->
<!-- <field name="name">maintenance.logs.run.search</field> -->
<!-- <field name="model">maintenance.equipment.oee.logs</field> -->
<!-- <field name="arch" type="xml"> -->
<!-- <search> -->
<!-- <field name="equipment_id"/> -->
<!-- <field name="start_time"/> -->
<!-- <field name="stop_time"/> -->
<!-- <field name="duration"/> -->
<!-- <field name="oee"/> -->
<!-- <field name="note"/> -->
<!-- </search> -->
<!-- </field> -->
<!-- </record> -->
<!-- 设备运行日志详情 -->
<record id="view_maintenance_logs_run_detail_tree" model="ir.ui.view">
<field name="name">maintenance.logs.run.detail.tree</field>
<field name="model">maintenance.equipment.oee.log.detail</field>
<field name="arch" type="xml">
<tree>
<!-- <field name="sequence"/> -->
<field name="time"/>
<field name="state"/>
<field name="production_name"/>
</tree>
</field>
</record>
<record id="view_maintenance_logs_run_detail_form" model="ir.ui.view">
<field name="name">maintenance.logs.run.detail.form</field>
<field name="model">maintenance.equipment.oee.log.detail</field>
<field name="arch" type="xml">
<form string="设备运行日志详情">
<sheet>
<group>
<group>
<field name="state"/>
<!-- <field name="production_id"/> -->
</group>
<group>
<!-- <field name="sequence"/> -->
<field name="time"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!-- <record id="view_maintenance_logs_run_detail_search" model="ir.ui.view"> -->
<!-- <field name="name">maintenance.logs.run.detail.search</field> -->
<!-- <field name="model">maintenance.equipment.oee.logs.detail</field> -->
<!-- <field name="arch" type="xml"> -->
<!-- <search> -->
<!-- <field name="equipment_id"/> -->
<!-- <field name="start_time"/> -->
<!-- <field name="stop_time"/> -->
<!-- <field name="duration"/> -->
<!-- <field name="oee"/> -->
<!-- <field name="note"/> -->
<!-- </search> -->
<!-- </field> -->
<!-- </record> -->
<!-- 设备运行日志详情action -->
<!-- <record id="action_maintenance_logs_run_detail" model="ir.actions.act_window"> -->
<!-- <field name="name">设备运行日志详情</field> -->
<!-- <field name="type">ir.actions.act_window</field> -->
<!-- <field name="res_model">maintenance.equipment.oee.logs.detail</field> -->
<!-- <field name="view_mode">tree,form</field> -->
<!-- <field name="view_id" ref="view_maintenance_logs_run_detail_tree"/> -->
<!-- <field name="help" type="html"> -->
<!-- <p class="oe_view_nocontent_create"> -->
<!-- 设备运行日志详情 -->
<!-- </p> -->
<!-- </field> -->
<!-- -->
<!-- </record> -->
<record id="action_maintenance_logs_run" model="ir.actions.act_window">
<field name="name">设备运行日志</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">maintenance.equipment.oee.logs</field>
<!-- <field name="search_view_id" ref="view_maintenance_logs_run_search"/> -->
<field name="view_mode">tree,form</field>
<!-- <field name="view_mode">form</field> -->
<field name="view_id" ref="view_maintenance_logs_run_tree"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
设备运行日志
</p>
</field>
</record>
<menuitem name="设备运行日志" id="menu_maintenance_logs_run" parent="maintenance.menu_m_request"
sequence="10" action="action_maintenance_logs_run"/>
<!-- Action -->
<record id="action_maintenance_logs" model="ir.actions.act_window">

View File

@@ -156,17 +156,26 @@ class AgvScheduling(models.Model):
if agv_site_state == '空闲':
# 查询终点接驳站为agv_site_id的AGV路线
task_routes = self.env['sf.agv.task.route'].sudo().search([('end_site_id', '=', agv_site_id)])
agv_scheduling = self.env['sf.agv.scheduling'].sudo().search(
agv_schedulings = self.env['sf.agv.scheduling'].sudo().search(
[('state', '=', '待下发'), ('agv_route_type', 'in', task_routes.mapped('route_type'))],
order='id asc',
limit=1
)
task_route = task_routes.filtered(
lambda r: r.start_site_id == agv_scheduling.start_site_id and r.start_site_id == agv_scheduling.start_site_id
)
if task_route:
# 下发AGV调度任务并修改接驳站状态为占用
agv_scheduling.dispatch_scheduling(task_route)
for agv_scheduling in agv_schedulings:
# 找到所有起点接驳站匹配的路线
start_matched_task_routes = task_routes.filtered(
lambda r: r.start_site_id == agv_scheduling.start_site_id
)
# 如果调度任务有终点接驳站,找到终点接驳站匹配的路线
if agv_scheduling.end_site_id:
matched_task_routes = start_matched_task_routes.filtered(
lambda r: r.end_site_id == agv_scheduling.end_site_id
)
else:
matched_task_routes = start_matched_task_routes
if matched_task_routes:
# 下发AGV调度任务并修改接驳站状态为占用
agv_scheduling.dispatch_scheduling(matched_task_routes[0])
break;
def _delivery_avg(self):
config = self.env['res.config.settings'].get_values()

View File

@@ -990,8 +990,8 @@ class MrpProduction(models.Model):
panel_workorder.cmm_ids.sudo().unlink()
if panel_workorder.cnc_ids:
panel_workorder.cnc_ids.sudo().unlink()
self.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
production)
# self.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
# production)
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
# processing_panel)
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)

View File

@@ -1,4 +1,5 @@
import datetime
import logging
from datetime import timedelta, time
from collections import defaultdict
from odoo import fields, models, api
@@ -6,6 +7,8 @@ from odoo.addons.resource.models.resource import Intervals
from odoo.exceptions import UserError, ValidationError
import math
_logger = logging.getLogger(__name__)
class ResWorkcenter(models.Model):
_name = "mrp.workcenter"
@@ -163,6 +166,19 @@ class ResWorkcenter(models.Model):
else:
record.effective_working_hours_day = 0
# 计算传入时间日有效工作时长
def _compute_effective_working_hours_day1(self, date):
effective_working_hours_day = 0
for record in self:
attendance_ids = [p for p in record.resource_calendar_id.attendance_ids if
p.dayofweek == self.get_current_day_of_week(date)]
if attendance_ids:
for attendance_id in attendance_ids:
if attendance_id.hour_from and attendance_id.hour_to:
effective_working_hours_day += attendance_id.hour_to - attendance_id.hour_from
return effective_working_hours_day
# 获取传入时间是星期几
def get_current_day_of_week(self, datetime):
day_num = datetime.weekday()
@@ -211,7 +227,12 @@ class ResWorkcenter(models.Model):
('state', 'not in', ['draft', 'cancel'])])
if plan_ids:
sum_qty = sum([p.product_qty for p in plan_ids])
if sum_qty >= self.default_capacity:
date_planned_working_hours = self._compute_effective_working_hours_day1(date_planned)
default_capacity = round(
self.production_line_hour_capacity * date_planned_working_hours, 2)
_logger.info('排程日期:%s,计划数量:%s,日产能:%s,日工时:%s' % (
date_planned, sum_qty, default_capacity, date_planned_working_hours))
if sum_qty >= default_capacity:
return False
return True

View File

@@ -1082,6 +1082,12 @@ class ResMrpWorkOrder(models.Model):
# 重写工单开始按钮方法
def button_start(self):
if self.routing_type == 'CNC加工':
self.env['sf.production.plan'].sudo().search([('name', '=', self.production_id.name)]).write({
'state': 'processing',
'actual_start_time': datetime.now()
})
if self.routing_type == '装夹预调':
# 判断是否有坯料的序列号信息
boolean = False
@@ -1820,6 +1826,11 @@ class WorkPieceDelivery(models.Model):
return is_free
else:
raise UserError("接驳站暂未反馈站点实时状态,请稍后再试")
def delivery_avg(self):
is_agv_task_dispatch = self.env['ir.config_parameter'].sudo().get_param('is_agv_task_dispatch')
if is_agv_task_dispatch:
self._delivery_avg()
# 配送至avg小车
def _delivery_avg(self):
@@ -1880,7 +1891,7 @@ class WorkPieceDelivery(models.Model):
logging.info('delivery_item-name:%s' % delivery_item.name)
delivery_item.write({
'task_delivery_time': fields.Datetime.now(),
'status': '待配送'
'status': '已下发'
})
if delivery_item.type == "上产线":
delivery_item.workorder_id.write({'is_delivery': True})

View File

@@ -44,6 +44,9 @@ class ResProductMo(models.Model):
materials_id = fields.Many2one('sf.production.materials', string='材料')
materials_type_id = fields.Many2one('sf.materials.model', string='材料型号',
domain="[('materials_id', '=', materials_id)]")
# materials_type_id = fields.Many2one(related='cutting_tool_model_id.material_model_id', string='材料型号',
# domain="[('materials_id', '=', materials_id)]")
# cutting_tool_model_id.material_model_id
server_product_process_parameters_id = fields.Many2one('sf.production.process.parameter',
string='表面工艺参数(服务产品)')
model_process_parameters_ids = fields.Many2many('sf.production.process.parameter', 'process_parameter_rel',
@@ -57,41 +60,100 @@ class ResProductMo(models.Model):
cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型',
domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
brand_id = fields.Many2one('sf.machine.brand', '品牌')
tool_length = fields.Float('长度(mm)')
tool_width = fields.Float('宽度(mm)')
# cutting_tool_type_id = fields.Many2one(related='cutting_tool_model_id.cutting_tool_type_id', string='类型',
# domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
# brand_id = fields.Many2one('sf.machine.brand', '品牌')
brand_id = fields.Many2one(related='cutting_tool_model_id.brand_id', string='品牌')
# cutting_tool_model_id.brand_id
# tool_length = fields.Float('长度(mm)')
tool_length = fields.Float(related='specification_id.length', string='长度(mm)')
# specification_id.length
# tool_width = fields.Float('宽度(mm)')
tool_width = fields.Float(related='specification_id.width', string='宽度(mm)')
# specification_id.width
tool_height = fields.Float('高度(mm)')
tool_thickness = fields.Float('厚度(mm)')
tool_weight = fields.Float('重量(kg)')
tool_hardness = fields.Integer('硬度(hrc)')
coating_material = fields.Char('涂层材质')
# tool_thickness = fields.Float('厚度(mm)')
tool_thickness = fields.Float(related='specification_id.thickness', string='厚度(mm)')
# specification_id.thickness
# tool_weight = fields.Float('重量(kg)')
tool_weight = fields.Float(related='specification_id.weight', string='重量(kg)')
# specification_id.weight
# tool_hardness = fields.Integer('硬度(hrc)')
tool_hardness = fields.Integer(related='cutting_tool_model_id.tool_hardness', string='硬度(hrc)')
# cutting_tool_model_id.tool_hardness
# coating_material = fields.Char('涂层材质')
coating_material = fields.Char(related='cutting_tool_model_id.coating_material', string='涂层材质')
# cutting_tool_model_id.coating_material
# 整体式刀具特有字段
cutting_tool_total_length = fields.Float('总长度(mm)', digits=(6, 1))
cutting_tool_shank_length = fields.Float('柄部长度(mm)', digits=(6, 1))
cutting_tool_blade_length = fields.Float('刃部长度(mm)')
cutting_tool_blade_number = fields.Selection(
[('0', '0'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8')],
string='刃数(个)', default='0')
# cutting_tool_total_length = fields.Float('总长度(mm)', digits=(6, 1))
cutting_tool_total_length = fields.Float(related='specification_id.total_length', string='长度(mm)', digits=(6, 1))
# specification_id.total_length
# cutting_tool_shank_length = fields.Float('柄部长度(mm)', digits=(6, 1))
cutting_tool_shank_length = fields.Float(related='specification_id.handle_length', string='柄部长度(mm)',
digits=(6, 1))
# specification_id.handle_length
# cutting_tool_blade_length = fields.Float('刃部长度(mm)')
cutting_tool_blade_length = fields.Float(related='specification_id.blade_length', string='刃部长度(mm)')
# specification_id.blade_length
# cutting_tool_blade_number = fields.Selection(
# [('0', '0'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8')],
# string='刃数(个)', default='0')
cutting_tool_blade_number = fields.Selection(related='specification_id.blade_number', string='刃数(个)')
# specification_id.blade_number
# 整体式刀具新增字段
cutting_tool_neck_length = fields.Float('颈部长度(mm)', digits=(6, 1))
cutting_tool_neck_diameter = fields.Float('颈部直径(mm)', digits=(6, 1))
cutting_tool_shank_diameter = fields.Float('柄部直径(mm)', digits=(6, 1))
cutting_tool_blade_tip_diameter = fields.Float('刀尖直径(mm)', digits=(6, 1))
cutting_tool_blade_tip_taper = fields.Integer('刀尖锥度(°)')
cutting_tool_blade_helix_angle = fields.Integer('刃部螺旋角(°)')
cutting_tool_blade_type = fields.Char('刃部类型')
cutting_tool_pitch = fields.Float('牙距(mm)')
cutting_tool_blade_width = fields.Float('刃部宽度(mm)')
cutting_tool_blade_depth = fields.Float('刃部深度(mm)')
# cutting_tool_neck_length = fields.Float('颈部长度(mm)', digits=(6, 1))
cutting_tool_neck_length = fields.Float(related='specification_id.neck_length', string='颈部长度(mm)', digits=(6, 1))
# specification_id.neck_length
# cutting_tool_neck_diameter = fields.Float('颈部直径(mm)', digits=(6, 1))
cutting_tool_neck_diameter = fields.Float(related='specification_id.neck_diameter', string='颈部直径(mm)',
digits=(6, 1))
# specification_id.neck_diameter
# cutting_tool_shank_diameter = fields.Float('柄部直径(mm)', digits=(6, 1))
cutting_tool_shank_diameter = fields.Float(related='specification_id.handle_diameter', string='柄部直径(mm)', digits=(6, 1))
# specification_id.handle_diameter
# cutting_tool_blade_tip_diameter = fields.Float('刀尖直径(mm)', digits=(6, 1))
cutting_tool_blade_tip_diameter = fields.Float(related='specification_id.blade_tip_diameter', string='刀尖直径(mm)',
digits=(6, 1))
# specification_id.blade_tip_diameter
# cutting_tool_blade_tip_taper = fields.Integer('刀尖锥度(°)')
cutting_tool_blade_tip_taper = fields.Integer(related='specification_id.blade_tip_taper', string='刀尖锥度(°)')
# specification_id.blade_tip_taper
# cutting_tool_blade_helix_angle = fields.Integer('刃部螺旋角(°)')
cutting_tool_blade_helix_angle = fields.Integer(related='specification_id.blade_helix_angle', string='刃部螺旋角(°)')
# specification_id.blade_helix_angle
# cutting_tool_blade_type = fields.Char('刃部类型')
cutting_tool_blade_type = fields.Char(related='cutting_tool_model_id.blade_type', string='刃部类型')
# cutting_tool_pitch = fields.Float('牙距(mm)')
cutting_tool_pitch = fields.Float(related='specification_id.pitch', string='牙距(mm)')
# specification_id.pitch
# cutting_tool_blade_width = fields.Float('刃部宽度(mm)')
cutting_tool_blade_width = fields.Float(related='specification_id.blade_width', string='刃部宽度(mm)')
# specification_id.blade_width
# cutting_tool_blade_depth = fields.Float('刃部深度(mm)')
cutting_tool_blade_depth = fields.Float(related='specification_id.blade_depth', string='刃部深度(mm)')
# specification_id.blade_depth
cutting_tool_cut_depth = fields.Float('切削深度(mm)')
cutting_tool_cut_depth_max = fields.Float('最大切削深度(mm)')
cutting_tool_coarse_medium_fine = fields.Selection([('', ''), ('', ''), ('', '')], '粗/中/精')
cutting_tool_run_out_accuracy_max = fields.Float('端跳精度max', digits=(6, 1))
cutting_tool_run_out_accuracy_min = fields.Float('端跳精度min', digits=(6, 1))
cutting_tool_blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20)
cutting_tool_blade_tip_r_size = fields.Float('刀尖R角(mm)')
# cutting_tool_cut_depth_max = fields.Float('最大切削深度(mm)')
cutting_tool_cut_depth_max = fields.Float(related='specification_id.cut_depth_max', string='最大切削深度(mm)')
# specification_id.cut_depth_max
# cutting_tool_coarse_medium_fine = fields.Selection([('粗', '粗'), ('中', '中'), ('精', '精')], '粗/中/精')
cutting_tool_coarse_medium_fine = fields.Selection(related='cutting_tool_model_id.integral_coarse_medium_fine', string='粗/中/精')
# cutting_tool_model_id.integral_coarse_medium_fine
# cutting_tool_run_out_accuracy_max = fields.Float('端跳精度max', digits=(6, 1))
cutting_tool_run_out_accuracy_max = fields.Char(related='cutting_tool_model_id.integral_run_out_accuracy_max', string='端跳精度max', digits=(6, 1))
# cutting_tool_model_id.integral_run_out_accuracy_max
# cutting_tool_run_out_accuracy_min = fields.Float('端跳精度min', digits=(6, 1))
cutting_tool_run_out_accuracy_min = fields.Char(related='cutting_tool_model_id.integral_run_out_accuracy_min',
string='端跳精度min', digits=(6, 1))
# cutting_tool_model_id.integral_run_out_accuracy_min
# cutting_tool_blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20)
cutting_tool_blade_tip_working_size = fields.Char(related='specification_id.blade_tip_working_size',
string='刀尖倒角度(°)', size=20)
# specification_id.blade_tip_working_size
# cutting_tool_blade_tip_r_size = fields.Float('刀尖R角(mm)')
cutting_tool_blade_tip_r_size = fields.Float(related='specification_id.tip_r_size',
string='刀尖R角(mm)')
# specification_id.tip_r_size
fit_blade_shape_id = fields.Many2one('maintenance.equipment.image',
'适配刀片形状', domain=[('type', '=', '刀片形状')])
suitable_machining_method_ids = fields.Many2many('maintenance.equipment.image',
@@ -429,44 +491,97 @@ class ResProductMo(models.Model):
# if not self.cutting_direction_ids:
# raise ValidationError("请选择走刀方向")
cutting_speed_ids = fields.One2many('sf.cutting.speed', 'product_template_id', string='切削速度Vc')
# cutting_speed_ids = fields.One2many('sf.cutting.speed', 'product_template_id', string='切削速度Vc')
cutting_speed_ids = fields.One2many(related='cutting_tool_model_id.cutting_speed_ids',
string='切削速度Vc')
# cutting_tool_model_id.cutting_speed_ids
feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'product_template_id', string='每齿走刀量fz')
cutting_tool_diameter = fields.Float('刀具直径(mm)')
cutting_tool_rear_angle = fields.Integer('后角(°)')
cutting_tool_main_included_angle = fields.Integer('主偏角(°)')
# cutting_tool_rear_angle = fields.Integer('后角(°)')
cutting_tool_rear_angle = fields.Integer(related='specification_id.relief_angle',
string='后角(°)')
# specification_id.relief_angle
# cutting_tool_main_included_angle = fields.Integer('主偏角(°)')
cutting_tool_main_included_angle = fields.Integer(related='specification_id.main_included_angle',
string='主偏角(°)')
# specification_id.main_included_angle
# 适用夹头型号可以多选
cutting_tool_chuck_id = fields.Many2one(
'sf.cutting_tool.standard.library',
domain="[('cutting_tool_type', '=', '夹头')]",
string='适用夹头型号')
# 刀片参数
cutting_tool_cut_blade_length = fields.Float('切削刃长(mm)')
cutting_tool_blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20)
cutting_tool_top_angle = fields.Integer('顶角(°)')
cutting_tool_inscribed_circle_diameter = fields.Float('内接圆直径(mm)')
cutting_tool_install_aperture_diameter = fields.Float('安装孔直径(mm)')
cutting_tool_chip_breaker_groove = fields.Selection([('', ''), ('单面', '单面'), ('双面', '双面')],
string='有无断屑槽')
cutting_tool_chip_breaker_type_code = fields.Char('断屑槽型代号')
cutting_tool_bladed_teeth_model = fields.Selection(
[('', ''), ('V牙型', 'V牙型'), ('米制全牙型', '米制全牙型'), ('美制全牙型', '美制全牙型'),
('惠氏全牙型', '惠氏全牙型'), ('BSPT全牙型', 'BSPT全牙型'), ('NPT全牙型', 'NPT全牙型'),
('UNJ全牙型', 'UNJ全牙型'), ('DIN405圆牙型', 'DIN405圆牙型'), ('ACME梯形', 'ACME梯形'),
('石油管螺纹刀片', '石油管螺纹刀片'), ('矮牙ACME梯形', '矮牙ACME梯形'),
('Trapeze30° 103', 'Trapeze30° 103')], string='刀片牙型', default='')
cutting_tool_blade_blade_number = fields.Selection(
[('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'),
('7', '7'), ('8', '8'), ('9', '9'), ('10', '10')],
string='刀片的刃数(个)')
# cutting_tool_cut_blade_length = fields.Float('切削刃长(mm)')
cutting_tool_cut_blade_length = fields.Float(related='specification_id.cutting_blade_length',
string='切削刃长(mm)')
# specification_id.cutting_blade_length
# cutting_tool_blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20)
cutting_tool_blade_tip_circular_arc_radius = fields.Char(related='specification_id.blade_tip_circular_arc_radius',
string='刀尖圆弧半径(mm)')
# specification_id.blade_tip_circular_arc_radius
# cutting_tool_top_angle = fields.Integer('顶角(°)')
cutting_tool_top_angle = fields.Integer(related='specification_id.top_angle',
string='顶角(°)')
# specification_id.top_angle
# cutting_tool_inscribed_circle_diameter = fields.Float('内接圆直径(mm)')
cutting_tool_inscribed_circle_diameter = fields.Float(related='specification_id.inscribed_circle_diameter',
string='内接圆直径(mm)')
# specification_id.inscribed_circle_diameter
# cutting_tool_install_aperture_diameter = fields.Float('安装孔直径(mm)')
cutting_tool_install_aperture_diameter = fields.Float(related='specification_id.install_aperture_diameter',
string='安装孔直径(mm)')
# specification_id.install_aperture_diameter
# cutting_tool_chip_breaker_groove = fields.Selection([('无', '无'), ('单面', '单面'), ('双面', '双面')],
# string='有无断屑槽')
cutting_tool_chip_breaker_groove = fields.Selection(related='specification_id.chip_breaker_groove',
string='有无断屑槽')
# specification_id.chip_breaker_groove
# cutting_tool_chip_breaker_type_code = fields.Char('断屑槽型代号')
cutting_tool_chip_breaker_type_code = fields.Char(related='specification_id.chip_breaker_type_code',
string='断屑槽型代号')
# specification_id.chip_breaker_type_code
# cutting_tool_bladed_teeth_model = fields.Selection(
# [('无', '无'), ('V牙型', 'V牙型'), ('米制全牙型', '米制全牙型'), ('美制全牙型', '美制全牙型'),
# ('惠氏全牙型', '惠氏全牙型'), ('BSPT全牙型', 'BSPT全牙型'), ('NPT全牙型', 'NPT全牙型'),
# ('UNJ全牙型', 'UNJ全牙型'), ('DIN405圆牙型', 'DIN405圆牙型'), ('ACME梯形', 'ACME梯形'),
# ('石油管螺纹刀片', '石油管螺纹刀片'), ('矮牙ACME梯形', '矮牙ACME梯形'),
# ('Trapeze30° 103', 'Trapeze30° 103')], string='刀片牙型', default='无')
cutting_tool_bladed_teeth_model = fields.Selection(related='specification_id.blade_teeth_model',
string='断屑槽型代号')
# specification_id.blade_teeth_model
# cutting_tool_blade_blade_number = fields.Selection(
# [('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'),
# ('7', '7'), ('8', '8'), ('9', '9'), ('10', '10')],
# string='刀片的刃数(个)')
cutting_tool_blade_blade_number = fields.Selection(related='specification_id.blade_blade_number',
string='刀片的刃数(个)')
# specification_id.blade_blade_number
cutting_tool_thread_model = fields.Selection([('', ''), ('外螺纹', '外螺纹'), ('内螺纹', '内螺纹')],
string='螺纹类型')
cutting_tool_thread_num = fields.Float('每英寸螺纹数(tpi)')
cutting_tool_blade_tip_height_tolerance = fields.Char('刀尖高度公差(mm)', size=20)
cutting_tool_inscribed_circle_tolerance = fields.Char('内接圆公差(mm)', size=20)
cutting_tool_thickness_tolerance = fields.Char('厚度公差(mm)', size=20)
cutting_tool_jump_accuracy = fields.Char('径跳精度(mm)')
# cutting_tool_thread_model = fields.Selection([('无', '无'), ('外螺纹', '外螺纹'), ('内螺纹', '内螺纹')],
# string='螺纹类型')
cutting_tool_thread_model = fields.Selection(related='specification_id.thread_model',
string='螺纹类型')
# specification_id.thread_model
# cutting_tool_thread_num = fields.Float('每英寸螺纹数(tpi)')
cutting_tool_thread_num = fields.Float(related='specification_id.thread_num',
string='每英寸螺纹数(tpi)')
# specification_id.thread_num
# cutting_tool_blade_tip_height_tolerance = fields.Char('刀尖高度公差(mm)', size=20)
cutting_tool_blade_tip_height_tolerance = fields.Char(related='specification_id.blade_tip_height_tolerance',
string='刀尖高度公差(mm)')
# specification_id.blade_tip_height_tolerance
# cutting_tool_inscribed_circle_tolerance = fields.Char('内接圆公差(mm)', size=20)
cutting_tool_inscribed_circle_tolerance = fields.Char(related='specification_id.inscribed_circle_tolerance',
string='内接圆公差(mm)')
# specification_id.inscribed_circle_tolerance
# cutting_tool_thickness_tolerance = fields.Char('厚度公差(mm)', size=20)
cutting_tool_thickness_tolerance = fields.Char(related='specification_id.thickness_tolerance',
string='厚度公差(mm)')
# specification_id.thickness_tolerance
# cutting_tool_jump_accuracy = fields.Char('径跳精度(mm)')
cutting_tool_jump_accuracy = fields.Char(related='specification_id.run_out_accuracy',
string='径跳精度(mm)')
# specification_id.run_out_accuracy
cutting_tool_working_hardness = fields.Integer('加工硬度(hrc)')
cutting_tool_cutter_bar_ids = fields.Many2many(
'sf.cutting_tool.standard.library',
@@ -485,55 +600,153 @@ class ResProductMo(models.Model):
string='适用刀盘型号' # 使用空列表作为默认值
)
# 刀杆/参数
cutting_tool_knife_head_height = fields.Float('刀头高度(mm)')
cutting_tool_knife_head_width = fields.Float('刀头宽度(mm)')
cutting_tool_knife_head_length = fields.Float('刀头度(mm)')
cutting_tool_blade_diameter = fields.Float('刃径/刃部直径(mm)')
cutting_tool_cutter_arbor_diameter = fields.Float('刀杆直径(mm)')
cutting_tool_min_machining_aperture = fields.Integer('最小加工孔径(mm)')
cutting_tool_install_blade_tip_num = fields.Integer('可装刀片数/齿数(个)')
cutting_tool_installing_structure = fields.Char('安装结构', size=20)
# cutting_tool_knife_head_height = fields.Float('刀头高度(mm)')
cutting_tool_knife_head_height = fields.Float(related='specification_id.knife_head_height',
string='刀头度(mm)')
# specification_id.knife_head_height
# cutting_tool_knife_head_width = fields.Float('刀头宽度(mm)')
cutting_tool_knife_head_width = fields.Float(related='specification_id.knife_head_width',
string='刀头宽度(mm)')
# cutting_tool_knife_head_length = fields.Float('刀头长度(mm)')
cutting_tool_knife_head_length = fields.Float(related='specification_id.knife_head_length',
string='刀头长度(mm)')
# cutting_tool_blade_diameter = fields.Float('刃径/刃部直径(mm)')
cutting_tool_blade_diameter = fields.Float(related='specification_id.blade_diameter',
string='刃径/刃部直径(mm)')
# specification_id.blade_diameter
# cutting_tool_cutter_arbor_diameter = fields.Float('刀杆直径(mm)')
cutting_tool_cutter_arbor_diameter = fields.Float(related='specification_id.cutter_arbor_diameter',
string='刀杆直径(mm)')
# specification_id.cutter_arbor_diameter
# cutting_tool_min_machining_aperture = fields.Integer('最小加工孔径(mm)')
cutting_tool_min_machining_aperture = fields.Integer(related='specification_id.min_machining_aperture',
string='最小加工孔径(mm)')
# specification_id.min_machining_aperture
# cutting_tool_install_blade_tip_num = fields.Integer('可装刀片数/齿数(个)')
cutting_tool_install_blade_tip_num = fields.Integer(related='specification_id.install_blade_tip_num',
string='可装刀片数/齿数(个)')
# specification_id.install_blade_tip_num
# cutting_tool_installing_structure = fields.Char('安装结构', size=20)
cutting_tool_installing_structure = fields.Char(related='specification_id.installing_structure',
string='安装结构')
# specification_id.installing_structure
cutting_tool_blade_id = fields.Many2one(
'sf.cutting_tool.standard.library',
domain="[('cutting_tool_type', '=', '刀片')]",
string='适用刀片型号' # 使用空列表作为默认值
)
cutting_tool_tool_shim = fields.Char('适配刀垫型号', size=50)
cutting_tool_cotter_pin = fields.Char('适配销钉型号', size=50)
cutting_tool_pressing_plate = fields.Char('适配压板型号', size=50)
cutting_tool_screw = fields.Char('适配螺钉型号', size=50)
cutting_tool_wrench = fields.Char('适配扳手型号')
cutting_tool_is_cooling_hole = fields.Boolean('有无冷却孔', default=False)
cutting_tool_locating_slot_code = fields.Char('定位槽代号', size=20)
# cutting_tool_blade_id = fields.Many2one(related='specification_id.blade_id',
# domain="[('cutting_tool_type', '=', '刀片')]",
# string='适用刀片型号')
# specification_id.blade_id
# cutting_tool_tool_shim = fields.Char('适配刀垫型号', size=50)
cutting_tool_tool_shim = fields.Char(related='specification_id.tool_shim',
string='适配刀垫型号')
# specification_id.tool_shim
# cutting_tool_cotter_pin = fields.Char('适配销钉型号', size=50)
cutting_tool_cotter_pin = fields.Char(related='specification_id.cotter_pin',
string='适配销钉型号')
# cutting_tool_pressing_plate = fields.Char('适配压板型号', size=50)
cutting_tool_pressing_plate = fields.Char(related='specification_id.pressing_plate',
string='适配压板型号')
# cutting_tool_screw = fields.Char('适配螺钉型号', size=50)
cutting_tool_screw = fields.Char(related='specification_id.screw',
string='适配螺钉型号')
# specification_id.screw
# cutting_tool_wrench = fields.Char('适配扳手型号')
cutting_tool_wrench = fields.Char(related='specification_id.spanner',
string='适配扳手型号')
# specification_id.spanner
# cutting_tool_is_cooling_hole = fields.Boolean('有无冷却孔', default=False)
cutting_tool_is_cooling_hole = fields.Boolean(related='specification_id.is_cooling_hole',
string='有无冷却孔')
# specification_id.is_cooling_hole
# cutting_tool_locating_slot_code = fields.Char('定位槽代号', size=20)
cutting_tool_locating_slot_code = fields.Char(related='specification_id.locating_slot_code',
string='定位槽代号')
# specification_id.locating_slot_code
# 刀盘参数
cutting_tool_cutter_head_diameter = fields.Float('刀盘直径(mm)')
cutting_tool_interface_diameter = fields.Float('接口直径(mm)')
# cutting_tool_cutter_head_diameter = fields.Float('刀盘直径(mm)')
cutting_tool_cutter_head_diameter = fields.Float(related='specification_id.cutter_head_diameter',
string='刀盘直径(mm)')
# specification_id.cutter_head_diameter
# cutting_tool_interface_diameter = fields.Float('接口直径(mm)')
cutting_tool_interface_diameter = fields.Float(related='specification_id.interface_diameter',
string='接口直径(mm)')
# specification_id.interface_diameter
# 刀柄参数
cutting_tool_clamping_diameter_max = fields.Float('最大夹持直径')
cutting_tool_clamping_diameter_min = fields.Float('最小夹持直径')
cutting_tool_flange_length = fields.Float('法兰柄长(mm)')
cutting_tool_flange_diameter = fields.Float('法兰直径(mm)')
cutting_tool_is_safety_lock = fields.Boolean('有无安全锁', default=False)
cutting_tool_is_high_speed_cutting = fields.Boolean('可高速切削', default=False)
cutting_tool_change_time = fields.Integer('换刀时间(s)')
cutting_tool_clamping_way = fields.Char('夹持方式')
cutting_tool_fit_chuck_size = fields.Char('适配夹头尺寸')
cutting_tool_taper_shank_model = fields.Char('锥柄型号')
# cutting_tool_clamping_diameter_max = fields.Float('最大夹持直径')
cutting_tool_clamping_diameter_max = fields.Float(related='specification_id.max_clamping_diameter',
string='最大夹持直径')
# specification_id.max_clamping_diameter
# cutting_tool_clamping_diameter_min = fields.Float('最小夹持直径')
cutting_tool_clamping_diameter_min = fields.Float(related='specification_id.min_clamping_diameter',
string='最小夹持直径')
# specification_id.min_clamping_diameter
# cutting_tool_flange_length = fields.Float('法兰柄长(mm)')
cutting_tool_flange_length = fields.Float(related='specification_id.flange_shank_length',
string='法兰柄长(mm)')
# cutting_tool_flange_diameter = fields.Float('法兰直径(mm)')
cutting_tool_flange_diameter = fields.Float(related='specification_id.flange_diameter',
string='法兰直径(mm)')
# cutting_tool_is_safety_lock = fields.Boolean('有无安全锁', default=False)
cutting_tool_is_safety_lock = fields.Boolean(related='specification_id.is_safe_lock',
string='有无安全锁')
# cutting_tool_is_high_speed_cutting = fields.Boolean('可高速切削', default=False)
cutting_tool_is_high_speed_cutting = fields.Boolean(related='specification_id.is_quick_cutting',
string='可高速切削')
# cutting_tool_change_time = fields.Integer('换刀时间(s)')
cutting_tool_change_time = fields.Integer(related='specification_id.tool_changing_time',
string='换刀时间(s)')
# cutting_tool_clamping_way = fields.Char('夹持方式')
cutting_tool_clamping_way = fields.Char(related='specification_id.clamping_mode',
string='夹持方式')
# cutting_tool_fit_chuck_size = fields.Char('适配夹头尺寸')
cutting_tool_fit_chuck_size = fields.Char(related='specification_id.fit_chuck_size',
string='适配夹头尺寸')
# cutting_tool_taper_shank_model = fields.Char('锥柄型号')
cutting_tool_taper_shank_model = fields.Char(related='specification_id.taper_shank_model',
string='锥柄型号')
cutting_tool_standard_speed = fields.Integer('标准转速(n/min)')
cutting_tool_speed_max = fields.Integer('最大转速(n/min)')
# cutting_tool_speed_max = fields.Integer('最大转速(n/min)')
cutting_tool_speed_max = fields.Integer(related='specification_id.max_rotate_speed',
string='最大转速(n/min)')
# specification_id.max_rotate_speed
cutting_tool_cooling_type = fields.Char('冷却类型')
cutting_tool_dynamic_balance_class = fields.Char('动平衡等级')
cutting_tool_fit_nut_model = fields.Char('适用锁紧螺母型号')
# cutting_tool_fit_nut_model = fields.Char('适用锁紧螺母型号')
cutting_tool_fit_nut_model = fields.Char(related='specification_id.nut',
string='适用锁紧螺母型号')
# specification_id.nut
# 夹头参数
cutting_tool_taper = fields.Integer('锥度(°)')
cutting_tool_top_diameter = fields.Float('顶部直径')
cutting_tool_outer_diameter = fields.Float('外径(mm)')
cutting_tool_inner_diameter = fields.Float('内径(mm)')
cooling_suit_type_ids = fields.Char('适用冷却套型号')
cutting_tool_max_load_capacity = fields.Float('最大负载能力(kg)')
cutting_tool_er_size_model = fields.Char('尺寸型号')
# cutting_tool_taper = fields.Integer('锥度(°)')
cutting_tool_taper = fields.Integer(related='specification_id.taper',
string='锥度(°)')
# specification_id.taper
# cutting_tool_top_diameter = fields.Float('顶部直径')
cutting_tool_top_diameter = fields.Float(related='specification_id.top_diameter',
string='顶部直径')
# specification_id.top_diameter
# cutting_tool_outer_diameter = fields.Float('外径(mm)')
# specification_id.outer_diameter
cutting_tool_outer_diameter = fields.Float(related='specification_id.outer_diameter',
string='外径(mm)')
# cutting_tool_inner_diameter = fields.Float('内径(mm)')
cutting_tool_inner_diameter = fields.Float(related='specification_id.inner_diameter',
string='内径(mm)')
# specification_id.inner_diameter
# cooling_suit_type_ids = fields.Char('适用冷却套型号')
cooling_suit_type_ids = fields.Char(related='specification_id.cooling_jacket',
string='适用冷却套型号')
# specification_id.cooling_jacket
# cutting_tool_max_load_capacity = fields.Float('最大负载能力(kg)')
cutting_tool_max_load_capacity = fields.Float(related='specification_id.max_load_capacity',
string='最大负载能力(kg)')
# specification_id.max_load_capacity
# cutting_tool_er_size_model = fields.Char('尺寸型号')
cutting_tool_er_size_model = fields.Char(related='specification_id.er_size_model',
string='尺寸型号')
# specification_id.er_size_model
# cutting_tool_handle_ids = fields.Many2many(
# 'sf.cutting_tool.standard.library',
# relation='product_cutting_tool_library_chuck_handle_rel',
@@ -548,6 +761,10 @@ class ResProductMo(models.Model):
domain="[('cutting_tool_type', '=', '刀柄')]",
string='适用刀柄型号'
)
# cutting_tool_handle_id = fields.Many2one(related='cutting_tool_model_id.handle_id',
# domain="[('cutting_tool_type', '=', '刀柄')]",
# string='适用刀柄型号')
# cutting_tool_model_id.handle_id
# 注册状态
register_state = fields.Selection([('未注册', '未注册'), ('已注册', '已注册'), ('注册失败', '注册失败')],

View File

@@ -296,6 +296,10 @@
</attribute>
</xpath>
<xpath expr="//sheet//notebook//page[@name='operations']//field[@name='workorder_ids']" position="replace">
<field name="workorder_ids" attrs="{'readonly': ['|', ('state', '!=', 'test_value'), '&amp;', ('state', '=', 'done'), ('is_locked', '=', True)]}" context="{'tree_view_ref': 'mrp.mrp_production_workorder_tree_editable_view', 'default_product_uom_id': product_uom_id, 'from_manufacturing_order': True}"/>
</xpath>
<xpath expr="//sheet//notebook//page[@name='operations']" position="after">
<page string="检测结果" attrs="{'invisible': [('detection_result_ids', '=', [])]}">
<field name="detection_result_ids" string="" readonly="0">

View File

@@ -520,7 +520,7 @@
<xpath expr="//form//header" position="inside">
<button type="object" class="oe_highlight jikimo_button_confirm" name="get_three_check_datas"
string="获取数据" attrs='{"invisible": [("state","!=","progress"), ("routing_type","!=","装夹预调")]}'/>
string="获取数据" attrs='{"invisible": ["|", ("state","!=","progress"), ("routing_type","!=","装夹预调")]}'/>
</xpath>
@@ -797,7 +797,7 @@
<field name="feeder_station_start_id" readonly="1" force_save="1"/>
<!-- <field name="type" readonly="1"/>-->
<field name="feeder_station_destination_id" readonly="1" force_save="1"/>
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
<button name="delivery_avg" type="object" string="配送" class="oe_highlight"/>
<button name="action_delivery_history" type="object" class="btn btn-link text-info" icon="fa-history"
string="历史"/>
</tree>

View File

@@ -1 +1,2 @@
from . import models
from . import models
from . import controllers

View File

@@ -11,9 +11,12 @@
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify'],
'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify', 'stock'],
'data': [
'data/bussiness_node.xml'
'data/bussiness_node.xml',
# 'data/cron_data.xml',
'data/template_data.xml',
],
'test': [
],

View File

@@ -0,0 +1 @@
from . import main

View File

@@ -0,0 +1,40 @@
import json
import requests
import logging
from odoo import http
from odoo.http import request
from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect
from odoo.addons.sf_base.commons.common import Common
_logger = logging.getLogger(__name__)
class MessageSfMrsConnect(Sf_Mrs_Connect):
@http.route('/api/cnc_processing/create', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
cors="*")
def get_cnc_processing_create(self, **kw):
res = super(MessageSfMrsConnect, self).get_cnc_processing_create(**kw)
res = json.loads(res)
if res.get('production_ids'):
try:
_logger.info('已编程的制造订单:%s' % res.get('production_ids'))
productions = request.env['mrp.production'].sudo().search([('id', 'in', res.get('production_ids'))])
# 过滤programming_state为已编程,tool_state为2的制造订单
tool_state_valid_productions = productions.filtered(lambda x: x.programming_state == '已编程' and x.tool_state == '2')
if tool_state_valid_productions:
data = {
'name': tool_state_valid_productions[0].programming_no
}
# 请求cloud接口发送微信消息推送
configsettings = request.env['res.config.settings'].sudo().get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/message/invalid_tool_state'
config_url = configsettings['sf_url'] + url
data['token'] = configsettings['token']
ret = requests.post(config_url, json=data, headers=config_header)
ret = ret.json()
_logger.info('无效用刀异常消息推送接口:%s' % ret)
except Exception as e:
_logger.info('无效用刀异常消息推送接口:%s' % e)
return json.JSONEncoder().encode(res)

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" ?>
<odoo>
<data noupdate="1">
<!--销售订单-->
<record id="bussiness_pending_order" model="jikimo.message.bussiness.node">
<field name="name">待接单</field>
<field name="model">sale.order</field>
@@ -10,5 +11,79 @@
<field name="name">确认接单</field>
<field name="model">sale.order</field>
</record>
<!-- <record id="bussiness_sale_order_overdue_warning" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">销售订单逾期预警</field>-->
<!-- <field name="model">sale.order</field>-->
<!-- </record>-->
<!-- <record id="bussiness_sale_order_overdue" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">销售订单已逾期</field>-->
<!-- <field name="model">sale.order</field>-->
<!-- </record>-->
<record id="transfer_inventory" model="jikimo.message.bussiness.node">
<field name="name">调拨入库</field>
<field name="model">stock.picking</field>
</record>
<record id="tool_assembly" model="jikimo.message.bussiness.node">
<field name="name">功能刀具组装</field>
<field name="model">sf.functional.tool.assembly</field>
</record>
<record id="tool_dismantle" model="jikimo.message.bussiness.node">
<field name="name">功能刀具寿命到期</field>
<field name="model">sf.functional.tool.dismantle</field>
</record>
<record id="bussiness_material_purchase_remind" model="jikimo.message.bussiness.node">
<field name="name">坯料采购提醒</field>
<field name="model">purchase.order</field>
</record>
<record id="bussiness_material_picking_remind" model="jikimo.message.bussiness.node">
<field name="name">坯料发料提醒</field>
<field name="model">stock.picking</field>
</record>
<!--工单-->
<record id="bussiness_mrp_workorder_remind" model="jikimo.message.bussiness.node">
<field name="name">工单已下发通知</field>
<field name="model">mrp.workorder</field>
</record>
<!-- <record id="bussiness_mrp_workorder_pre_overdue_warning" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">装夹预调工单逾期预警</field>-->
<!-- <field name="model">mrp.workorder</field>-->
<!-- </record>-->
<!-- <record id="bussiness_mrp_workorder_pre_overdue" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">装夹预调工单已逾期</field>-->
<!-- <field name="model">mrp.workorder</field>-->
<!-- </record>-->
<!-- <record id="bussiness_mrp_workorder_cnc_overdue_warning" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">CNC工单逾期预警</field>-->
<!-- <field name="model">mrp.workorder</field>-->
<!-- </record>-->
<!-- <record id="bussiness_mrp_workorder_cnc_overdue" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">CNC工单已逾期</field>-->
<!-- <field name="model">mrp.workorder</field>-->
<!-- </record>-->
<!-- <record id="bussiness_mrp_workorder_unclamp_overdue_warning" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">解除装夹工单逾期预警</field>-->
<!-- <field name="model">mrp.workorder</field>-->
<!-- </record>-->
<!-- <record id="bussiness_mrp_workorder_unclamp_overdue" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">解除装夹工单已逾期</field>-->
<!-- <field name="model">mrp.workorder</field>-->
<!-- </record>-->
<!-- <record id="bussiness_mrp_workorder_surface_overdue_warning" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">表面工艺工单逾期预警</field>-->
<!-- <field name="model">mrp.workorder</field>-->
<!-- </record>-->
<!-- <record id="bussiness_mrp_workorder_surface_overdue" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">表面工艺工单已逾期</field>-->
<!-- <field name="model">mrp.workorder</field>-->
<!-- </record>-->
</data>
</odoo>

View File

@@ -0,0 +1,160 @@
<odoo>
<data noupdate="1">
<record model="ir.cron" id="ir_cron_sale_order_overdue_warning">
<field name="name">销售订单逾期预警</field>
<field name="model_id" ref="model_sale_order"/>
<field name="state">code</field>
<field name="code">model._overdue_warning_func()</field>
<field name="interval_number">1</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
<field name="user_id" ref="base.user_root"/>
<field name="active" eval="True"/>
</record>
<record model="ir.cron" id="ir_cron_sale_order_overdue">
<field name="name">销售订单已逾期</field>
<field name="model_id" ref="model_sale_order"/>
<field name="state">code</field>
<field name="code">model._overdue_func()</field>
<field name="interval_number">1</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
<field name="user_id" ref="base.user_root"/>
<field name="active" eval="True"/>
</record>
<record model="ir.cron" id="ir_cron_mrp_workorder_overdue_warning">
<field name="name">装夹预调工单逾期预警</field>
<field name="model_id" ref="model_mrp_workorder"/>
<field name="state">code</field>
<field name="code">model._overdue_warning_func()</field>
<field name="interval_number">1</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
<field name="user_id" ref="base.user_root"/>
<field name="active" eval="True"/>
</record>
<record model="ir.cron" id="ir_cron_mrp_workorder_overdue">
<field name="name">工单已逾期</field>
<field name="model_id" ref="model_mrp_workorder"/>
<field name="state">code</field>
<field name="code">model._overdue_func()</field>
<field name="interval_number">1</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
<field name="user_id" ref="base.user_root"/>
<field name="active" eval="True"/>
</record>
<!-- -->
<!-- <record model="ir.cron" id="ir_cron_mrp_workorder_overdue_warning">-->
<!-- <field name="name">工单逾期预警</field>-->
<!-- <field name="model_id" ref="model_mrp_workorder"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">model._overdue_warning_func()</field>-->
<!-- <field name="interval_number">1</field>-->
<!-- <field name="interval_type">minutes</field>-->
<!-- <field name="numbercall">-1</field>-->
<!-- <field name="doall" eval="False"/>-->
<!-- <field name="user_id" ref="base.user_root"/>-->
<!-- <field name="active" eval="True"/>-->
<!-- </record>-->
<!-- <record model="ir.cron" id="ir_cron_mrp_workorder_pre_overdue">-->
<!-- <field name="name">工单已逾期</field>-->
<!-- <field name="model_id" ref="model_mrp_workorder"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">model._overdue_func()</field>-->
<!-- <field name="interval_number">1</field>-->
<!-- <field name="interval_type">minutes</field>-->
<!-- <field name="numbercall">-1</field>-->
<!-- <field name="doall" eval="False"/>-->
<!-- <field name="user_id" ref="base.user_root"/>-->
<!-- <field name="active" eval="True"/>-->
<!-- </record>-->
<!-- -->
<!-- <record model="ir.cron" id="ir_cron_mrp_workorder_pre_overdue_warning">-->
<!-- <field name="name">工单逾期预警</field>-->
<!-- <field name="model_id" ref="model_mrp_workorder"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">model._overdue_warning_func()</field>-->
<!-- <field name="interval_number">1</field>-->
<!-- <field name="interval_type">minutes</field>-->
<!-- <field name="numbercall">-1</field>-->
<!-- <field name="doall" eval="False"/>-->
<!-- <field name="user_id" ref="base.user_root"/>-->
<!-- <field name="active" eval="True"/>-->
<!-- </record>-->
<!-- <record model="ir.cron" id="ir_cron_mrp_workorder_pre_overdue">-->
<!-- <field name="name">工单已逾期</field>-->
<!-- <field name="model_id" ref="model_mrp_workorder"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">model._overdue_func()</field>-->
<!-- <field name="interval_number">1</field>-->
<!-- <field name="interval_type">minutes</field>-->
<!-- <field name="numbercall">-1</field>-->
<!-- <field name="doall" eval="False"/>-->
<!-- <field name="user_id" ref="base.user_root"/>-->
<!-- <field name="active" eval="True"/>-->
<!-- </record>-->
<!-- -->
<!-- -->
<!-- <record model="ir.cron" id="ir_cron_mrp_workorder_pre_overdue_warning">-->
<!-- <field name="name">工单逾期预警</field>-->
<!-- <field name="model_id" ref="model_mrp_workorder"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">model._overdue_warning_func()</field>-->
<!-- <field name="interval_number">1</field>-->
<!-- <field name="interval_type">minutes</field>-->
<!-- <field name="numbercall">-1</field>-->
<!-- <field name="doall" eval="False"/>-->
<!-- <field name="user_id" ref="base.user_root"/>-->
<!-- <field name="active" eval="True"/>-->
<!-- </record>-->
<!-- <record model="ir.cron" id="ir_cron_mrp_workorder_pre_overdue">-->
<!-- <field name="name">工单已逾期</field>-->
<!-- <field name="model_id" ref="model_mrp_workorder"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">model._overdue_func()</field>-->
<!-- <field name="interval_number">1</field>-->
<!-- <field name="interval_type">minutes</field>-->
<!-- <field name="numbercall">-1</field>-->
<!-- <field name="doall" eval="False"/>-->
<!-- <field name="user_id" ref="base.user_root"/>-->
<!-- <field name="active" eval="True"/>-->
<!-- </record>-->
<!-- -->
<!-- <record model="ir.cron" id="ir_cron_mrp_workorder_pre_overdue_warning">-->
<!-- <field name="name">工单逾期预警</field>-->
<!-- <field name="model_id" ref="model_mrp_workorder"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">model._overdue_warning_func()</field>-->
<!-- <field name="interval_number">1</field>-->
<!-- <field name="interval_type">minutes</field>-->
<!-- <field name="numbercall">-1</field>-->
<!-- <field name="doall" eval="False"/>-->
<!-- <field name="user_id" ref="base.user_root"/>-->
<!-- <field name="active" eval="True"/>-->
<!-- </record>-->
<!-- <record model="ir.cron" id="ir_cron_mrp_workorder_pre_overdue">-->
<!-- <field name="name">工单已逾期</field>-->
<!-- <field name="model_id" ref="model_mrp_workorder"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">model._overdue_func()</field>-->
<!-- <field name="interval_number">1</field>-->
<!-- <field name="interval_type">minutes</field>-->
<!-- <field name="numbercall">-1</field>-->
<!-- <field name="doall" eval="False"/>-->
<!-- <field name="user_id" ref="base.user_root"/>-->
<!-- <field name="active" eval="True"/>-->
<!-- </record>-->
</data>
</odoo>

View File

@@ -0,0 +1,110 @@
<?xml version="1.0" ?>
<odoo>
<data noupdate="1">
<record id="template_pending_order" model="jikimo.message.template">
<field name="name">待接单</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="model">sale.order</field>
<field name="bussiness_node_id" ref="bussiness_pending_order"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 待接单提醒:
单号:销售订单[{{name}}]({{url}})
事项:请确认是否接单。
</field>
</record>
<record id="template_to_be_confirm" model="jikimo.message.template">
<field name="name">确认接单</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="model">sale.order</field>
<field name="bussiness_node_id" ref="bussiness_to_be_confirm"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 待排程提醒:
单号:产品[{{product_id}}]({{url}})
事项:{{mrp_production_count}}个制造订单待计划排程
</field>
</record>
<record id="template_material_purchase_remind" model="jikimo.message.template">
<field name="name">坯料采购提醒</field>
<field name="model_id" ref="purchase.model_purchase_order"/>
<field name="model">purchase.order</field>
<field name="bussiness_node_id" ref="bussiness_material_purchase_remind"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 坯料采购通知:
单号:采购单[{{name}}]({{request_url}})
事项:请确认坯料采购单并处理</field>
</record>
<record id="template_material_picking_remind" model="jikimo.message.template">
<field name="name">坯料发料提醒</field>
<field name="model_id" ref="stock.model_stock_picking"/>
<field name="model">stock.picking</field>
<field name="bussiness_node_id" ref="bussiness_material_picking_remind"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 坯料发料提醒:
单号:产品[{{product_id}}]({{request_url}})
事项:共{{number}}个生产发料单待确认处理</field>
</record>
<record id="template_mrp_workorder_remind" model="jikimo.message.template">
<field name="name">工单已下发通知</field>
<field name="model_id" ref="mrp_workorder.model_mrp_workorder"/>
<field name="model">mrp.workorder</field>
<field name="bussiness_node_id" ref="bussiness_mrp_workorder_remind"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 工单已下发通知:
单号:产品[{{product_id}}]({{request_url}})
事项:共{{number}}个工单已下发,请查收知悉</field>
</record>
<record id="template_transfer_inventory_remind" model="jikimo.message.template">
<field name="menu_id" ref="stock.menu_stock_root"/>
<field name="action_id" ref="stock.action_picking_tree_ready"/>
<field name="name">调拨入库</field>
<field name="model_id" ref="stock.model_stock_picking"/>
<field name="model">stock.picking</field>
<field name="bussiness_node_id" ref="transfer_inventory"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 调拨入库通知:
单号:调拨入库单[{{name}}]({{request_url}})
事项:完成刀具物料上架入库</field>
</record>
<record id="template_tool_expired_remind" model="jikimo.message.template">
<field name="menu_id" ref="mrp.menu_mrp_root"/>
<field name="action_id" ref="sf_tool_management.sf_functional_tool_dismantle_view_act"/>
<field name="name">功能刀具寿命到期</field>
<field name="model_id" ref="sf_tool_management.model_sf_functional_tool_dismantle"/>
<field name="model">sf.functional.tool.dismantle</field>
<field name="bussiness_node_id" ref="tool_dismantle"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 功能刀具寿命到期提醒:
单号:拆解单[{{code}}]({{request_url}})
事项:{{functional_tool_id.tool_name_id.name}}寿命已到期,需拆解</field>
</record>
<record id="template_tool_assembly_remind" model="jikimo.message.template">
<field name="menu_id" ref="mrp.menu_mrp_root"/>
<field name="action_id" ref="sf_tool_management.sf_functional_tool_assembly_view_act"/>
<field name="name">功能刀具组装</field>
<field name="model_id" ref="sf_tool_management.model_sf_functional_tool_assembly"/>
<field name="model">sf.functional.tool.assembly</field>
<field name="bussiness_node_id" ref="tool_assembly"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 功能刀具组装通知:
单号:组装任务单[{{name}}]({{request_url}})
事项:{{use_tool_time}}前完成组装</field>
</record>
</data>
</odoo>

View File

@@ -6,3 +6,4 @@ from . import sf_message_cam_program
from . import sf_message_functional_tool_assembly
from . import sf_message_purchase
from . import sf_message_workorder
from . import sf_message_functional_tool_dismantle

View File

@@ -3,4 +3,13 @@ from odoo import models, fields, api, _
class SFMessagefunctionalToolAssembly(models.Model):
_name = 'sf.functional.tool.assembly'
_description = "刀具组装单"
_inherit = ['sf.functional.tool.assembly', 'jikimo.message.dispatch']
@api.model_create_multi
def create(self, vals):
result = super(SFMessagefunctionalToolAssembly, self).create(vals)
for obj in result:
if obj.loading_task_source == '0' and obj.assemble_status == '0':
obj.add_queue('功能刀具组装')
return result

View File

@@ -0,0 +1,19 @@
from odoo import models, api
class SFMessagefunctionalToolDismantle(models.Model):
_name = 'sf.functional.tool.dismantle'
_description = "刀具拆解单"
_inherit = ['sf.functional.tool.dismantle', 'jikimo.message.dispatch']
@api.model
def create(self, vals):
# 判断是否为web页面创建请求
is_web_request = self.env.context.get('is_web_request', False)
result = super(SFMessagefunctionalToolDismantle, self).create(vals)
if is_web_request:
return result
for obj in result:
if obj.dismantle_cause in ['寿命到期报废', '崩刀报废'] and obj.state == '待拆解':
obj.add_queue('功能刀具寿命到期')
return result

View File

@@ -1,6 +1,33 @@
from odoo import models, fields, api, _
from urllib.parse import urlencode
class SFMessagePurchase(models.Model):
_name = 'purchase.order'
_inherit = ['purchase.order', 'jikimo.message.dispatch']
_inherit = ['purchase.order', 'jikimo.message.dispatch']
def _get_message(self, message_queue_ids):
contents = []
for message_queue_id in message_queue_ids:
if message_queue_id.message_template_id.name == '坯料采购提醒':
content = message_queue_id.message_template_id.content
url = self.request_url(int(message_queue_id.res_id))
purchase_order_line = self.env['purchase.order'].search([('id', '=', int(message_queue_id.res_id))])
content = content.replace('{{name}}', purchase_order_line.name).replace(
'{{request_url}}', url)
contents.append(content)
return contents
def request_url(self, id):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('purchase.purchase_form_action').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_website_payment')]).id
# 查询参数
params = {'id': id, 'menu_id': menu_id, 'action': action_id,
'model': 'purchase.order',
'view_type': 'form'}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + query_string
return full_url

View File

@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import logging
from odoo import models, fields, api, _
@@ -21,19 +22,52 @@ class SFMessageSale(models.Model):
if res is True:
try:
self.add_queue('确认接单')
picking_ids = self.mrp_production_ids
purchase_order_id = []
if picking_ids:
for picking_id in picking_ids:
purchase_order_ids = (
picking_id.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id |
picking_id.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id).ids
purchase_order_id.extend(purchase_order_ids)
if purchase_order_id:
purchase_order_list = self.env['purchase.order'].search([('id', 'in', purchase_order_id)])
for purchase_order_info in purchase_order_list:
purchase_order_info.add_queue('坯料采购提醒')
except Exception as e:
logging.info('add_queue error:%s' % e)
return res
# 继承并重写jikimo.message.dispatch的_get_message()
def _get_message(self, message_queue_ids):
res = super(SFMessageSale, self)._get_message(message_queue_ids)
if message_queue_ids.message_template_id.bussiness_node_id.name == '确认接单':
# sale_order = self.env['sale.order'].search([('id', '=', message_queue_ids.model.res_id)])
sale_order_line = self.env['sale.order.line'].search([('order_id', '=', int(message_queue_ids.res_id))])
if len(sale_order_line) == 1:
product = sale_order_line[0].product_id.name
elif len(sale_order_line) > 1:
product = '%s...' % sale_order_line[0].product_id.name
res[0] = res[0].replace('{{product_id}}', product)
return res
contents = []
url = self.env['ir.config_parameter'].get_param('web.base.url')
for item in message_queue_ids:
# 待接单的处理
if item.message_template_id.bussiness_node_id.name == '待接单':
content = super(SFMessageSale, self)._get_message(item)
action_id = self.env.ref('sale.action_quotations_with_onboarding').id
url = f"{url}/web#id={item.res_id}&view_type=form&action={action_id}"
content = content[0].replace('{{url}}', url)
contents.append(content)
# 确认接单的处理
elif item.message_template_id.bussiness_node_id.name == '确认接单':
content = super(SFMessageSale, self)._get_message(item)
sale_order_line = self.env['sale.order.line'].search([('order_id', '=', int(item.res_id))])
product = sale_order_line[0].product_id.name if len(sale_order_line) == 1 else '%s...' % \
sale_order_line[
0].product_id.name
action_id = self.env.ref('sf_plan.sf_production_plan_action1').id
url = f"{url}/web#view_type=list&action={action_id}"
content = content[0].replace('{{product_id}}', product).replace('{{url}}', url)
contents.append(content)
return contents
# # 销售订单逾期预警
# def _overdue_warning_func(self):
# sale_order_
# return 1
#
# # 销售订单已逾期
# def _overdue_func(self):
# return 1

View File

@@ -1,6 +1,65 @@
import re
from odoo import models, fields, api, _
from urllib.parse import urlencode
class SFMessageStockPicking(models.Model):
_name = 'stock.picking'
_inherit = ['stock.picking', 'jikimo.message.dispatch']
_description = "库存调拨"
_inherit = ['stock.picking', 'jikimo.message.dispatch']
@api.model_create_multi
def create(self, vals):
result = super(SFMessageStockPicking, self).create(vals)
for obj in result:
if obj.location_id.name == '进货' and obj.location_dest_id.name == '刀具房':
obj.add_queue('调拨入库')
return result
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
def _compute_state(self):
super(SFMessageStockPicking, self)._compute_state()
for record in self:
if record.state == 'assigned' and record.check_in == 'PC':
record.add_queue('坯料发料提醒')
def _get_message(self, message_queue_ids):
contents = []
product_id = []
for message_queue_id in message_queue_ids:
i = 0
if message_queue_id.message_template_id.name == '坯料发料提醒':
content = message_queue_id.message_template_id.content
stock_picking_line = self.env['stock.picking'].search([('id', '=', int(message_queue_id.res_id))])
mrp_production_info = self.env['mrp.production'].search(
[('name', '=', stock_picking_line.origin)])
mrp_production_list = self.env['mrp.production'].search(
[('product_id', '=', mrp_production_info.product_id.id)])
for mrp_production_line in mrp_production_list:
picking_ids = mrp_production_line.picking_ids
for picking_id in picking_ids:
if picking_id.state == 'assigned' and picking_id.check_in == 'PC':
i += 1
if i > 0 and mrp_production_info.product_id.id not in product_id:
url = self.request_url()
content = content.replace('{{product_id}}', mrp_production_info.product_id.name).replace(
'{{number}}', str(i)).replace('{{request_url}}', url)
product_id.append(mrp_production_info.product_id.id)
contents.append(content)
return contents
else:
res = super(SFMessageStockPicking, self)._get_message(message_queue_id)
return res
def request_url(self):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('stock.stock_picking_type_action').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id
# 查询参数
params = {'menu_id': menu_id, 'action': action_id, 'model': 'stock.picking',
'view_type': 'kanban'}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + query_string
return full_url

View File

@@ -9,4 +9,9 @@ class SfMessageTemplate(models.Model):
def _get_message_model(self):
res = super(SfMessageTemplate, self)._get_message_model()
res.append("sale.order")
res.append("stock.picking")
res.append('sf.functional.tool.assembly')
res.append('sf.functional.tool.dismantle')
res.append('purchase.order')
res.append('mrp.workorder')
return res

View File

@@ -1,6 +1,54 @@
from odoo import models, fields, api, _
import logging, json
import requests
from odoo.addons.sf_base.commons.common import Common
from urllib.parse import urlencode
_logger = logging.getLogger(__name__)
class SFMessageWork(models.Model):
_name = 'mrp.workorder'
_inherit = ['mrp.workorder', 'jikimo.message.dispatch']
_inherit = ['mrp.workorder', 'jikimo.message.dispatch']
@api.depends('production_availability', 'blocked_by_workorder_ids.state')
def _compute_state(self):
super(SFMessageWork, self)._compute_state()
for workorder in self:
if workorder.state == 'ready' and workorder.routing_type == '装夹预调':
jikimo_message_queue = self.env['jikimo.message.queue'].sudo().search(
[('res_id', '=', workorder.id), ("message_status", "=", "pending")])
if not jikimo_message_queue:
workorder.add_queue('工单已下发通知')
def _get_message(self, message_queue_ids):
contents = []
product_id = []
for message_queue_id in message_queue_ids:
if message_queue_id.message_template_id.name == '工单已下发通知':
content = message_queue_id.message_template_id.content
mrp_workorder_line = self.env['mrp.workorder'].search([('id', '=', int(message_queue_id.res_id))])
mrp_workorder_list = self.env['mrp.workorder'].search(
[('product_id', '=', mrp_workorder_line.product_id.id), ('state', '=', 'ready'),
('routing_type', '=', '装夹预调')])
if len(mrp_workorder_list) > 0 and mrp_workorder_line.product_id.id not in product_id:
url = self.request_url()
content = content.replace('{{product_id}}', mrp_workorder_line.product_id.name).replace(
'{{number}}', str(len(mrp_workorder_list))).replace(
'{{request_url}}', url)
product_id.append(mrp_workorder_line.product_id.id)
contents.append(content)
return contents
def request_url(self):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('sf_manufacturing.mrp_workorder_action_tablet').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_stock_dropshipping')]).id
# 查询参数
params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder',
'view_type': 'list', 'active_id': 1}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + query_string
return full_url

View File

@@ -62,8 +62,8 @@ class Sf_Mrs_Connect(http.Controller):
if cnc_workorder_has.cnc_ids:
cnc_workorder_has.cmm_ids.sudo().unlink()
cnc_workorder_has.cnc_ids.sudo().unlink()
request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
production)
# request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
# production)
cnc_workorder_has.write(
{'cnc_ids': cnc_workorder_has.cnc_ids.sudo()._json_cnc_processing(panel, ret),
'cmm_ids': cnc_workorder_has.cmm_ids.sudo()._json_cmm_program(panel, ret)})
@@ -93,6 +93,9 @@ class Sf_Mrs_Connect(http.Controller):
pre_workorder.write(
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
res.update({
'production_ids': productions.ids
})
return json.JSONEncoder().encode(res)
else:
res = {'status': 0, 'message': '该制造订单暂未开始'}

View File

@@ -18,7 +18,7 @@ class OrderPrice(models.Model):
return True
except ValueError:
return False
@api.depends('sale_order_id.remark')
@api.depends('sale_order_id.order_line.remark')
def _compute_bfm_amount_total(self):
for record in self:
amount_total = 0

View File

@@ -175,7 +175,7 @@ class ResConfigSettings(models.TransientModel):
new_price = res_order_lines_map.get(str(index))
if order_line:
# 修改单价
order_line.write({'remark': new_price*order_line.product_uom_qty})
order_line.write({'remark': round(new_price*order_line.product_uom_qty,2)})
order_price = self.env['order.price'].sudo().search([('sale_order_id', '=',need_change_sale_order.id )])
if not order_price:
self.env['order.price'].sudo().create({'sale_order_id':need_change_sale_order.id})

View File

@@ -2676,7 +2676,8 @@ class CuttingToolBasicParameters(models.Model):
'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_length'],
'cutting_depth': cutter_head_item['cutting_depth_max'],
'cutting_blade_length': cutter_head_item['cutting_blade_length'],
'cut_depth_max': cutter_head_item['cutting_depth_max'],
'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
@@ -2698,7 +2699,8 @@ class CuttingToolBasicParameters(models.Model):
'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_length'],
'cutting_depth': cutter_head_item['cutting_depth_max'],
'cutting_blade_length': cutter_head_item['cutting_blade_length'],
'cut_depth_max': cutter_head_item['cutting_depth_max'],
'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
@@ -3011,8 +3013,7 @@ class CuttingToolBasicParameters(models.Model):
})
if 'basic_parameters_cutter_head' in result['cutting_tool_basic_parameters_yesterday_list']:
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']:
basic_parameters_cutter_head_list = json.loads(
result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head'])
basic_parameters_cutter_head_list = result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']
if basic_parameters_cutter_head_list:
for cutter_head_item in basic_parameters_cutter_head_list:
cutter_head = self.search(
@@ -3031,7 +3032,8 @@ class CuttingToolBasicParameters(models.Model):
'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_length'],
'cutting_depth': cutter_head_item['cutting_depth_max'],
'cutting_blade_length': cutter_head_item['cutting_blade_length'],
'cut_depth_max': cutter_head_item['cutting_depth_max'],
'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
@@ -3053,7 +3055,8 @@ class CuttingToolBasicParameters(models.Model):
'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_length'],
'cutting_depth': cutter_head_item['cutting_depth_max'],
'cutting_blade_length': cutter_head_item['cutting_blade_length'],
'cut_depth_max': cutter_head_item['cutting_depth_max'],
'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[

View File

@@ -1,7 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_static_resource_datasync,sf_static_resource_datasync,model_sf_static_resource_datasync,base.group_user,1,1,1,1
access_order_price,order.price,model_order_price,base.group_user,1,1,1,1
access_order_price,order.price,model_order_price,sf_base.group_sale_director,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sf_static_resource_datasync sf_static_resource_datasync model_sf_static_resource_datasync base.group_user 1 1 1 1
3 access_order_price order.price model_order_price base.group_user sf_base.group_sale_director 1 1 1 1
4

View File

@@ -8,7 +8,7 @@
<menuitem sequence="22" name="销售订单bfm对比" id="menu_sale_order_bfm_price"
action="order_price_tree_act"
parent="sale.sale_order_menu"
groups="base.group_user"
groups="sf_base.group_sale_director"
/>
<record id="view_order_price_tree" model="ir.ui.view">

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

View File

@@ -278,6 +278,7 @@
sequence="150"
action="sf_production_plan_action"
groups="sf_base.group_plan_dispatch"
web_icon="sf_plan,static/description/计划.png"
/>
<!-- <record model="ir.ui.menu" id="mrp_custom_menu" inherit_id="mrp.menu_mrp_manufacturing"> -->
@@ -338,7 +339,7 @@
name="空料架配送"
sequence="11"
action="sf_manufacturing.sf_workpiece_delivery_empty_racks_act"
groups="base.group_system"
groups="sf_base.group_sf_order_user,sf_base.group_sf_mrp_manager,sf_base.group_sf_equipment_user"
parent="mrp.menu_mrp_manufacturing"
/>
<!-- <menuitem -->

View File

@@ -74,6 +74,8 @@ class StockPicking(models.Model):
def send_to_bfm(self):
skip_backorder = self.env.context.get('skip_backorder')
cancel_backorder_ids = self.env.context.get('picking_ids_not_to_backorder')
# 下发发货到bfm
config = self.env['res.config.settings'].get_values()
move_ids, move_line_ids = self.deal_move_ids(self.move_ids, self.move_line_ids)
@@ -92,13 +94,13 @@ class StockPicking(models.Model):
'state': self.state,
'backorder_id': self.deal_send_backorder_id(self.backorder_id),
'backorder_ids': self.deal_send_backorder_id(self.backorder_ids),
'cancel_backorder_ids': skip_backorder,
'cancel_backorder_ids': True if skip_backorder and cancel_backorder_ids else False, # 没有欠单判断
'move_type': self.move_type,
},
}
url1 = config['bfm_url_new'] + '/api/stock/deliver_goods'
json_str = json.dumps(data)
print('json_str', json_str)
logging.info('json_str= %s', json_str)
r = requests.post(url1, json=data, data=None)
if r.status_code == 200:
result = json.loads(r.json()['result'])

View File

@@ -185,6 +185,7 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
_description = 'CAM工单程序用刀计划'
name = fields.Char('工单任务编号')
programming_no = fields.Char('编程单号')
cam_procedure_code = fields.Char('程序名')
filename = fields.Char('文件')
cam_cutter_spacing_code = fields.Char('刀号')
@@ -317,23 +318,33 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
"""
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
"""
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
'name': cnc_processing.workorder_id.production_id.name,
'cam_procedure_code': cnc_processing.program_name,
'filename': cnc_processing.cnc_id.name,
'functional_tool_name': cnc_processing.cutting_tool_name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'process_type': cnc_processing.processing_type,
'margin_x_y': float(cnc_processing.margin_x_y),
'margin_z': float(cnc_processing.margin_z),
'finish_depth': float(cnc_processing.depth_of_processing_z),
'extension_length': float(cnc_processing.cutting_tool_extension_length),
'shank_model': cnc_processing.cutting_tool_handle_type,
'estimated_processing_time': cnc_processing.estimated_processing_time,
})
logging.info('CAM工单程序用刀计划创建成功')
# 创建装刀请求
knife_plan.apply_for_tooling()
# 获取编程单号
programming_no = cnc_processing.workorder_id.production_id.programming_no
logging.info(f'编程单号:{programming_no}')
cam_id = self.env['sf.cam.work.order.program.knife.plan'].sudo().search(
[('programming_no', '=', programming_no),
('functional_tool_name', '=', cnc_processing.cutting_tool_name)])
logging.info(f'CAM装刀计划{cam_id}')
if not cam_id:
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
'name': cnc_processing.workorder_id.production_id.name,
'programming_no': programming_no,
'cam_procedure_code': cnc_processing.program_name,
'filename': cnc_processing.cnc_id.name,
'functional_tool_name': cnc_processing.cutting_tool_name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'process_type': cnc_processing.processing_type,
'margin_x_y': float(cnc_processing.margin_x_y),
'margin_z': float(cnc_processing.margin_z),
'finish_depth': float(cnc_processing.depth_of_processing_z),
'extension_length': float(cnc_processing.cutting_tool_extension_length),
'shank_model': cnc_processing.cutting_tool_handle_type,
'estimated_processing_time': cnc_processing.estimated_processing_time,
})
logging.info('CAM工单程序用刀计划创建成功')
# 创建装刀请求
knife_plan.apply_for_tooling()
def unlink_cam_plan(self, production):
for item in production:

View File

@@ -84,12 +84,12 @@ class jikimo_bom(models.Model):
if option.name == '整体式刀具':
domain = ['&'] + domain + [
'|',
'&',
# 刀具直径
('cutting_tool_blade_diameter', '=', self.tool_inventory_id.diameter),
# r角
('cutting_tool_blade_tip_working_size', '=', self.tool_inventory_id.angle)]
('cutting_tool_blade_tip_r_size', '=', self.tool_inventory_id.angle)]
if option.name == '刀杆':
domain = ['&'] + domain + [
("cutting_tool_cutter_arbor_diameter", "=", self.tool_inventory_id.diameter)]

View File

@@ -95,16 +95,20 @@ class CNCprocessing(models.Model):
# tool_state_remark1 = f'{key}无效刀:{data1.get(key)}'
# 无效刀处理逻辑
# 1、创建制造订单无效刀检测结果记录
logging.info('创建制造订单无效刀检测结果记录!')
production_id.detection_result_ids.create({
'production_id': production_id.id,
'processing_panel': key,
'routing_type': 'CNC加工',
'rework_reason': 'programming', # 原因:编程(programming)
'detailed_reason': '无效功能刀具',
'test_results': '返工',
'handle_result': '待处理'
})
if not production_id.detection_result_ids.filtered(
lambda a: (a.processing_panel == key and a.detailed_reason == '无效功能刀具'
and a.handle_result == '待处理' and a.routing_type == 'CNC加工'
and a.rework_reason == 'programming' and a.test_results == '返工')):
logging.info('创建制造订单无效刀检测结果记录!')
production_id.detection_result_ids.create({
'production_id': production_id.id,
'processing_panel': key,
'routing_type': 'CNC加工',
'rework_reason': 'programming', # 原因:编程(programming)
'detailed_reason': '无效功能刀具',
'test_results': '返工',
'handle_result': '待处理'
})
# 修改当前面装夹预调工单的 is_rework 为 True
# work_ids = production_id.workorder_ids.filtered(
# lambda a: a.routing_type == '装夹预调' and a.processing_panel == key and not a.is_rework)

View File

@@ -283,21 +283,22 @@
<field name="arch" type="xml">
<tree create="0">
<field name="name" string="工单编码"/>
<field name="cam_procedure_code"/>
<field name="filename"/>
<field name="programming_no"/>
<field name="cam_procedure_code" optional="hide"/>
<field name="filename" optional="hide"/>
<field name="functional_tool_name" string="刀具名称"/>
<field name="cam_cutter_spacing_code"/>
<field name="diameter" optional="hide"/>
<field name="tool_included_angle" optional="hide"/>
<field name="process_type"/>
<field name="process_type" optional="hide"/>
<field name="margin_x_y"/>
<field name="margin_z"/>
<field name="finish_depth"/>
<field name="extension_length" string="刀具伸出长度(mm)"/>
<field name="shank_model"/>
<field name="estimated_processing_time"/>
<field name="need_knife_time"/>
<field name="applicant_time"/>
<field name="need_knife_time" optional="hide"/>
<field name="applicant_time" optional="hide"/>
<field name="plan_execute_status"/>
<field name="production_line_id" invisible="1"/>
@@ -332,6 +333,7 @@
</div>
<group>
<group>
<field name="programming_no"/>
<field name="cam_procedure_code"/>
<field name="filename"/>
<field name="production_line_id"/>
@@ -388,6 +390,7 @@
<field name="model">sf.cam.work.order.program.knife.plan</field>
<field name="arch" type="xml">
<search>
<field name="programming_no"/>
<field name="name" string="工单编码"/>
<field name="cam_procedure_code"/>
<field name="filename"/>
@@ -1043,7 +1046,7 @@
<field name="res_model">sf.functional.tool.dismantle</field>
<field name="view_mode">tree,form,search</field>
<field name="search_view_id" ref="sf_functional_tool_dismantle_search"/>
<field name="context">{'search_default_no_dismantle_state':1}</field>
<field name="context">{'search_default_no_dismantle_state':1,'is_web_request':True}</field>
</record>
</data>
</odoo>