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", { patch(WebClient.prototype, "kolpolok_custom_title_and_favicon.WebClient", {
setup() { setup() {
this._super(); this._super();
this.title.setParts({ zopenerp: "JIKIMO" }); // this.title.setParts({ zopenerp: "JIKIMO" });
}, },
}); });

View File

@@ -16,7 +16,7 @@
<!-- hide 登录页面 powerd by odoo 及管理数据库 --> <!-- hide 登录页面 powerd by odoo 及管理数据库 -->
<template id="login_page_layout" inherit_id="web.login_layout" name="Login Page Layout"> <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> </template>
<!-- 隐藏odoo版本信息 --> <!-- 隐藏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('前缀') prefix = fields.Char('前缀')
postfix = fields.Char('后缀') postfix = fields.Char('后缀')
diameter = fields.Float('直径(mm)') diameter = fields.Float('直径(mm)')
angle = fields.Float('R角(mm)') angle = fields.Float('R角(mm)',default=0)
tool_length = fields.Float('刀具总长(mm)') tool_length = fields.Float('刀具总长(mm)')
blade_length = fields.Float('避空长/刃长(mm)') blade_length = fields.Float('避空长/刃长(mm)')
knife_head_name = fields.Char('刀头名称') knife_head_name = fields.Char('刀头名称')

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -162,7 +162,7 @@ class Sf_Dashboard_Connect(http.Controller):
# 关机时长:初次上线时间 - 通电时间 # 关机时长:初次上线时间 - 通电时间
'power_off_time': power_off_time, 'power_off_time': power_off_time,
# 关机率:关机时长/初次上线时间 # 关机率:关机时长/初次上线时间
'power_off_rate': power_off_rate, # 'power_off_rate': power_off_rate,
'first_online_duration': first_online_duration, 'first_online_duration': first_online_duration,
# 停机时间:关机时间 - 运行时间 # 停机时间:关机时间 - 运行时间
# 停机时长:关机时间 - 初次上线时间 # 停机时长:关机时间 - 初次上线时间
@@ -187,11 +187,11 @@ class Sf_Dashboard_Connect(http.Controller):
""" """
res = {'status': 1, 'message': '成功', 'data': {}} res = {'status': 1, 'message': '成功', 'data': {}}
logging.info('前端请求日志数据的参数为:%s' % kw) logging.info('前端请求日志数据的参数为:%s' % kw)
try:
# 连接数据库 # 连接数据库
conn = psycopg2.connect(**db_config) conn = psycopg2.connect(**db_config)
cur = conn.cursor() cur = conn.cursor()
try:
machine_list = ast.literal_eval(kw['machine_list']) machine_list = ast.literal_eval(kw['machine_list'])
begin_time_str = kw['begin_time'].strip('"') begin_time_str = kw['begin_time'].strip('"')
end_time_str = kw['end_time'].strip('"') end_time_str = kw['end_time'].strip('"')
@@ -231,6 +231,100 @@ class Sf_Dashboard_Connect(http.Controller):
res['message'] = '前端请求日志数据失败,原因:%s' % e res['message'] = '前端请求日志数据失败,原因:%s' % e
return json.dumps(res) 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机床列表 # 返回CNC机床列表
@http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False, @http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
cors="*") cors="*")
@@ -378,7 +472,8 @@ class Sf_Dashboard_Connect(http.Controller):
pass_rate = 1 pass_rate = 1
if pass_nums: if pass_nums:
pass_rate = round( 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( rework_rate = round(
@@ -418,8 +513,9 @@ class Sf_Dashboard_Connect(http.Controller):
'plan_data_progress_deviation': plan_data_progress_deviation, 'plan_data_progress_deviation': plan_data_progress_deviation,
'plan_data_rework_counts': plan_data_rework_counts, 'plan_data_rework_counts': plan_data_rework_counts,
'on_time_rate': on_time_rate, 'on_time_rate': on_time_rate,
'detection_data': detection_data, # 'detection_data': detection_data,
'pass_rate': pass_rate 'detection_data': plan_data_finish_counts,
'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts
} }
res['data'][line] = data res['data'][line] = data
@@ -489,11 +585,14 @@ class Sf_Dashboard_Connect(http.Controller):
for time_interval in time_intervals: for time_interval in time_intervals:
start_time, end_time = time_interval start_time, end_time = time_interval
# print(start_time, end_time)
orders = plan_obj.search([('production_line_id.name', '=', line), ('state', 'in', ['finished']), orders = plan_obj.search([
(date_field_name, '>=', start_time.strftime('%Y-%m-%d 00:00:00')), ('production_line_id.name', '=', line),
(date_field_name, '<', end_time.strftime('%Y-%m-%d 00:00:00')) ('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') # 只取小时:分钟:秒作为键 key = start_time.strftime('%H:%M:%S') # 只取小时:分钟:秒作为键
time_count_dict[key] = len(orders) 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) ('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True)
]) ])
# print(not_done_orders) # print(not_done_orders)
# 完成订单 # 完成订单
# 获取当前时间并计算24小时前的时间
current_time = datetime.now()
time_24_hours_ago = current_time - timedelta(hours=24)
finish_orders = plan_obj.search([ finish_orders = plan_obj.search([
('production_line_id.name', '=', line), ('state', 'in', ['finished']), ('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) # print(finish_orders)
@@ -687,6 +792,8 @@ class Sf_Dashboard_Connect(http.Controller):
not_done_data.append(line_dict) not_done_data.append(line_dict)
for finish_order in finish_orders: for finish_order in finish_orders:
if not finish_order.actual_end_time:
continue
blank_name = '' blank_name = ''
try: try:
blank_name = finish_order.production_id.move_raw_ids[0].product_id.name 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, 'material': material,
'dimensions': dimensions, 'dimensions': dimensions,
'order_qty': finish_order.product_qty, '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) done_data.append(line_dict)
@@ -745,10 +853,10 @@ class Sf_Dashboard_Connect(http.Controller):
''' '''
sql2 = ''' 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 FROM device_data
WHERE device_name = %s AND alarm_time IS NOT NULL WHERE device_name = %s AND alarm_start_time IS NOT NULL
ORDER BY alarm_time, time; ORDER BY alarm_start_time, time;
''' '''
# 执行SQL命令 # 执行SQL命令
@@ -764,8 +872,11 @@ class Sf_Dashboard_Connect(http.Controller):
res['data'][item] = {'idle_count': row[0]} res['data'][item] = {'idle_count': row[0]}
alarm_count = [] alarm_count = []
for row in result2: for row in result2:
alarm_count.append(row[0]) alarm_count.append(row[1])
if row[0]:
total_alarm_time += abs(float(row[0])) total_alarm_time += abs(float(row[0]))
else:
total_alarm_time += 0.0
if len(list(set(alarm_count))) == 1: if len(list(set(alarm_count))) == 1:
if list(set(alarm_count))[0] is None: if list(set(alarm_count))[0] is None:
alarm_count_num = 0 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) logging.info('前端请求机床数据的参数为:%s' % kw)
# 连接数据库
conn = psycopg2.connect(**db_config)
cur = conn.cursor()
try: try:
# 获取请求的机床数据 maintenance_logs_obj = request.env['sf.maintenance.logs'].sudo()
# # 获取请求的机床数据
# machine_list = ast.literal_eval(kw['machine_list']) # machine_list = ast.literal_eval(kw['machine_list'])
# idle_times = []
# idle_dict = {}
# for item in machine_list: # for item in machine_list:
sql = ''' # machine_data = equipment_obj.search([('code', '=', item)])
SELECT DISTINCT ON (alarm_time) alarm_time, alarm_message, system_date, system_time, alarm_repair_time for log in maintenance_logs_obj.search([]):
FROM device_data res['data'].append({
WHERE alarm_time IS NOT NULL 'name': log.name,
ORDER BY alarm_time, time; '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: except Exception as e:
print(f"An error occurred: {e}") logging.error(f"An error occurred: {e}")
return json.dumps(res) return json.dumps(res)
finally:
cur.close()
conn.close()
# 设备oee # 设备oee
@http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") @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) conn = psycopg2.connect(**db_config)
# 获取请求的机床数据 # 获取请求的机床数据
machine_list = ast.literal_eval(kw['machine_list']) 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): def fetch_result_as_dict(cursor):
"""辅助函数:将查询结果转为字典""" """辅助函数:将查询结果转为字典"""
columns = [desc[0] for desc in cursor.description] columns = [desc[0] for desc in cursor.description]
return dict(zip(columns, cursor.fetchone())) if cursor.rowcount != 0 else None return dict(zip(columns, cursor.fetchone())) if cursor.rowcount != 0 else None
# 获取当前时间的时间戳
current_timestamp = datetime.now().timestamp()
for item in machine_list: 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: with conn.cursor() as cur:
cur.execute(""" cur.execute("""
SELECT * FROM device_data SELECT * FROM device_data
WHERE device_name = %s WHERE device_name = %s
AND device_state != '离线' AND device_state != '离线' AND process_time IS NOT NULL
ORDER BY time DESC ORDER BY time DESC
LIMIT 1; LIMIT 1;
""", (item,)) """, (item,))
last_all_time = fetch_result_as_dict(cur) 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] = { res['data'][item] = {
'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0, '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, '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() conn.close()

View File

@@ -285,26 +285,6 @@ class Machine_ftp(models.Model):
# # 开动率 # # 开动率
run_rate = fields.Char('开动率', readonly=True) 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): class WorkCenterBarcode(models.Model):
""" """

View File

@@ -14,7 +14,7 @@
<group string='状态监控'> <group string='状态监控'>
<group> <group>
<!-- <field name="timestamp"/> --> <!-- <field name="timestamp"/> -->
<field name="status"/> <!-- <field name="status"/> -->
<field name="run_status"/> <field name="run_status"/>
<field name="run_time"/> <field name="run_time"/>
<field name="system_date"/> <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-*- # -*-coding:utf-8-*-
from odoo import fields, models from odoo import fields, models, api
class SfMaintenanceLogs(models.Model): class SfMaintenanceLogs(models.Model):
_name = 'sf.maintenance.logs' _name = 'sf.maintenance.logs'
_description = '设备故障日志' _description = '设备故障日志'
_order = 'alarm_time desc'
code = fields.Char(string='编码') code = fields.Char(string='编码', readonly=True)
name = fields.Char(string='名称') name = fields.Char(string='名称', compute='_compute_name')
type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型') type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型')
brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌') brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌')
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='机台号') maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='机台号')
@@ -28,3 +29,13 @@ class SfMaintenanceLogs(models.Model):
fault_duration = fields.Float(string='故障时长') fault_duration = fields.Float(string='故障时长')
note = fields.Text(string='备注') note = fields.Text(string='备注')
active = fields.Boolean('Active', default=True) 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 -*- # -*- coding: utf-8 -*-
import re
import json
import datetime
import requests
from odoo import api, fields, models, _ 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): class SfMaintenanceEquipmentOEE(models.Model):
@@ -9,24 +50,225 @@ class SfMaintenanceEquipmentOEE(models.Model):
name = fields.Char('设备oee') name = fields.Char('设备oee')
equipment_id = fields.Many2one('maintenance.equipment', '机台号', equipment_id = fields.Many2one('maintenance.equipment', '机台号',
domain="[('category_id.equipment_type', '=', '机床'),('state_zc', '=', '已注册')]") 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') type_id = fields.Many2one('sf.machine_tool.type', '型号', related='equipment_id.type_id')
machine_tool_picture = fields.Binary('设备图片', related='equipment_id.machine_tool_picture') machine_tool_picture = fields.Binary('设备图片', related='equipment_id.machine_tool_picture')
state = fields.Selection( state = fields.Selection(
[("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"), [("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"),
("封存(报废)", "封存(报废)")], ("封存(报废)", "封存(报废)")],
default='正常', string="机床状态", related='equipment_id.state') default='正常', string="机床状态", related='equipment_id.state')
run_time = fields.Float('加工时长(h)')
equipment_time = fields.Float('开机时长(h)') online_time = fields.Char('开机时长(小时)', reaonly='True')
done_nums = fields.Integer('加工件数')
utilization_rate = fields.Char('可用率') offline_time = fields.Char('关机时长(小时)', reaonly='True')
fault_time = fields.Float('故障时长') idle_nums = fields.Integer('待机次数', reaonly='True')
fault_nums = fields.Integer('故障次数') # 待机时长
# 故障率
fault_rate = fields.Char('故障率') 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', '设备故障日志', sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志',
related='equipment_id.sf_maintenance_logs_ids') 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): def name_get(self):
result = [] result = []
@@ -95,4 +337,3 @@ class SfMaintenanceEquipmentOEELogDetail(models.Model):
log_id = fields.Many2one('maintenance.equipment.oee.logs', '日志') log_id = fields.Many2one('maintenance.equipment.oee.logs', '日志')
# equipment_code = fields.Char('设备编码', related='log_id.equipment_code') # equipment_code = fields.Char('设备编码', related='log_id.equipment_code')
equipment_code = fields.Char('设备编码', readonly='True') 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_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_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_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"> <field name="arch" type="xml">
<tree> <tree>
<field name="equipment_id"/> <field name="equipment_id"/>
<field name="equipment_time"/> <field name="online_time"/>
<field name="run_time"/> <field name="work_time"/>
<field name="done_nums"/> <field name="work_rate"/>
<field name="utilization_rate"/>
<field name="fault_time"/> <field name="fault_time"/>
<field name="fault_nums"/> <field name="fault_nums"/>
<field name="fault_rate"/> <field name="fault_rate"/>
</tree> </tree>
</field> </field>
</record> </record>
@@ -37,32 +37,102 @@
<group> <group>
<group> <group>
<field name="type_id" readonly="1"/> <group>
<field name="equipment_time"/> <field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
<field name="run_time"/> <field name="type_id"/>
<field name="done_nums"/> <field name="state"/>
<field name="utilization_rate"/> <field name="equipment_code"/>
<field name="fault_time"/> </group>
<field name="fault_nums"/>
</group> </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>
</group> </group>
<!-- <notebook> --> <notebook>
<!-- <page string="运行日志"> --> <page string="24H日志详情">
<!-- <field name="oee_logs"> --> <group>
<!-- <tree create="1" edit="1" delete="1" editable="bottom"> --> <button name="get_day_logs" type="object" string="查看24H日志" t-attf-style="white-space:nowrap;"/>
<!-- <field name = 'run_time'/> --> </group>
<!-- <field name = 'state'/> --> <field name="day_logs_detail" readonly="1" widget="html"/>
<!-- <field name = 'workorder_id'/> --> <!-- <field name="page_num"/> -->
<!-- <field name = 'time'/> --> <!-- <group> -->
<!-- <field name = 'color' widget="color"/> --> <!-- <group> -->
<!-- </tree> --> <!-- <button name="previous_day_logs" type="object" string="上一页" t-attf-style="white-space:nowrap;"/> -->
<!-- </field> --> <!-- </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> --> <!-- </page> -->
<!-- </notebook> --> </notebook>
</sheet> </sheet>
</form> </form>
</field> </field>

View File

@@ -8,8 +8,8 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="type" optional="hide"/> <field name="type" optional="hide"/>
<field name="brand"/> <!-- <field name="brand"/> -->
<field name="maintenance_equipment_id"/> <field name="name"/>
<field name="code_location" optional="hide"/> <field name="code_location" optional="hide"/>
<field name="fault_code" optional="hide"/> <field name="fault_code" optional="hide"/>
<field name="alarm_time"/> <field name="alarm_time"/>
@@ -37,13 +37,14 @@
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<h1> <h1>
<field name="code" readonly="1"/> <field name="name" readonly="1"/>
</h1> </h1>
</div> </div>
<group> <group>
<group> <group>
<!-- <field name="name"/> -->
<field name="code"/>
<!-- <field name="type" required="1" widget="radio" options="{'horizontal': true}"/> --> <!-- <field name="type" required="1" widget="radio" options="{'horizontal': true}"/> -->
<field name="maintenance_equipment_id"/> <field name="maintenance_equipment_id"/>
<field name="brand"/> <field name="brand"/>
@@ -57,7 +58,6 @@
</group> </group>
<group> <group>
<field name="operator"/> <field name="operator"/>
<field name="fault_process"/> <field name="fault_process"/>
<!-- <field name="alarm_way" required="1" widget="radio" options="{'horizontal': true}"/> --> <!-- <field name="alarm_way" required="1" widget="radio" options="{'horizontal': true}"/> -->
<field name="recovery_time"/> <field name="recovery_time"/>
@@ -105,249 +105,6 @@
</field> </field>
</record> </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 --> <!-- Action -->
<record id="action_maintenance_logs" model="ir.actions.act_window"> <record id="action_maintenance_logs" model="ir.actions.act_window">

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
import datetime import datetime
import logging
from datetime import timedelta, time from datetime import timedelta, time
from collections import defaultdict from collections import defaultdict
from odoo import fields, models, api from odoo import fields, models, api
@@ -6,6 +7,8 @@ from odoo.addons.resource.models.resource import Intervals
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
import math import math
_logger = logging.getLogger(__name__)
class ResWorkcenter(models.Model): class ResWorkcenter(models.Model):
_name = "mrp.workcenter" _name = "mrp.workcenter"
@@ -163,6 +166,19 @@ class ResWorkcenter(models.Model):
else: else:
record.effective_working_hours_day = 0 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): def get_current_day_of_week(self, datetime):
day_num = datetime.weekday() day_num = datetime.weekday()
@@ -211,7 +227,12 @@ class ResWorkcenter(models.Model):
('state', 'not in', ['draft', 'cancel'])]) ('state', 'not in', ['draft', 'cancel'])])
if plan_ids: if plan_ids:
sum_qty = sum([p.product_qty for p in 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 False
return True return True

View File

@@ -1082,6 +1082,12 @@ class ResMrpWorkOrder(models.Model):
# 重写工单开始按钮方法 # 重写工单开始按钮方法
def button_start(self): 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 == '装夹预调': if self.routing_type == '装夹预调':
# 判断是否有坯料的序列号信息 # 判断是否有坯料的序列号信息
boolean = False boolean = False
@@ -1821,6 +1827,11 @@ class WorkPieceDelivery(models.Model):
else: else:
raise UserError("接驳站暂未反馈站点实时状态,请稍后再试") 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小车 # 配送至avg小车
def _delivery_avg(self): def _delivery_avg(self):
config = self.env['res.config.settings'].get_values() config = self.env['res.config.settings'].get_values()
@@ -1880,7 +1891,7 @@ class WorkPieceDelivery(models.Model):
logging.info('delivery_item-name:%s' % delivery_item.name) logging.info('delivery_item-name:%s' % delivery_item.name)
delivery_item.write({ delivery_item.write({
'task_delivery_time': fields.Datetime.now(), 'task_delivery_time': fields.Datetime.now(),
'status': '待配送' 'status': '已下发'
}) })
if delivery_item.type == "上产线": if delivery_item.type == "上产线":
delivery_item.workorder_id.write({'is_delivery': True}) 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_id = fields.Many2one('sf.production.materials', string='材料')
materials_type_id = fields.Many2one('sf.materials.model', string='材料型号', materials_type_id = fields.Many2one('sf.materials.model', string='材料型号',
domain="[('materials_id', '=', materials_id)]") 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', server_product_process_parameters_id = fields.Many2one('sf.production.process.parameter',
string='表面工艺参数(服务产品)') string='表面工艺参数(服务产品)')
model_process_parameters_ids = fields.Many2many('sf.production.process.parameter', 'process_parameter_rel', 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='类型', cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型',
domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]") domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
# cutting_tool_type_id = fields.Many2one(related='cutting_tool_model_id.cutting_tool_type_id', string='类型',
brand_id = fields.Many2one('sf.machine.brand', '品牌') # domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
# brand_id = fields.Many2one('sf.machine.brand', '品牌')
tool_length = fields.Float('长度(mm)') brand_id = fields.Many2one(related='cutting_tool_model_id.brand_id', string='品牌')
tool_width = fields.Float('宽度(mm)') # 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_height = fields.Float('高度(mm)')
tool_thickness = fields.Float('厚度(mm)') # tool_thickness = fields.Float('厚度(mm)')
tool_weight = fields.Float('重量(kg)') tool_thickness = fields.Float(related='specification_id.thickness', string='厚度(mm)')
tool_hardness = fields.Integer('硬度(hrc)') # specification_id.thickness
coating_material = fields.Char('涂层材质') # 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_total_length = fields.Float('总长度(mm)', digits=(6, 1))
cutting_tool_shank_length = fields.Float('柄部长度(mm)', digits=(6, 1)) cutting_tool_total_length = fields.Float(related='specification_id.total_length', string='长度(mm)', digits=(6, 1))
cutting_tool_blade_length = fields.Float('刃部长度(mm)') # specification_id.total_length
cutting_tool_blade_number = fields.Selection( # cutting_tool_shank_length = fields.Float('柄部长度(mm)', digits=(6, 1))
[('0', '0'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8')], cutting_tool_shank_length = fields.Float(related='specification_id.handle_length', string='柄部长度(mm)',
string='刃数(个)', default='0') 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_length = fields.Float('颈部长度(mm)', digits=(6, 1))
cutting_tool_neck_diameter = fields.Float('颈部直径(mm)', digits=(6, 1)) cutting_tool_neck_length = fields.Float(related='specification_id.neck_length', string='颈部长度(mm)', digits=(6, 1))
cutting_tool_shank_diameter = fields.Float('柄部直径(mm)', digits=(6, 1)) # specification_id.neck_length
cutting_tool_blade_tip_diameter = fields.Float('刀尖直径(mm)', digits=(6, 1)) # cutting_tool_neck_diameter = fields.Float('颈部直径(mm)', digits=(6, 1))
cutting_tool_blade_tip_taper = fields.Integer('刀尖锥度(°)') cutting_tool_neck_diameter = fields.Float(related='specification_id.neck_diameter', string='颈部直径(mm)',
cutting_tool_blade_helix_angle = fields.Integer('刃部螺旋角(°)') digits=(6, 1))
cutting_tool_blade_type = fields.Char('刃部类型') # specification_id.neck_diameter
cutting_tool_pitch = fields.Float('牙距(mm)') # cutting_tool_shank_diameter = fields.Float('柄部直径(mm)', digits=(6, 1))
cutting_tool_blade_width = fields.Float('刃部宽度(mm)') cutting_tool_shank_diameter = fields.Float(related='specification_id.handle_diameter', string='柄部直径(mm)', digits=(6, 1))
cutting_tool_blade_depth = fields.Float('刃部深度(mm)') # 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 = fields.Float('切削深度(mm)')
cutting_tool_cut_depth_max = fields.Float('最大切削深度(mm)') # cutting_tool_cut_depth_max = fields.Float('最大切削深度(mm)')
cutting_tool_coarse_medium_fine = fields.Selection([('', ''), ('', ''), ('', '')], '粗/中/精') cutting_tool_cut_depth_max = fields.Float(related='specification_id.cut_depth_max', string='最大切削深度(mm)')
cutting_tool_run_out_accuracy_max = fields.Float('端跳精度max', digits=(6, 1)) # specification_id.cut_depth_max
cutting_tool_run_out_accuracy_min = fields.Float('端跳精度min', digits=(6, 1)) # cutting_tool_coarse_medium_fine = fields.Selection([('粗', '粗'), ('中', '中'), ('精', '精')], '粗/中/精')
cutting_tool_blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20) cutting_tool_coarse_medium_fine = fields.Selection(related='cutting_tool_model_id.integral_coarse_medium_fine', string='粗/中/精')
cutting_tool_blade_tip_r_size = fields.Float('刀尖R角(mm)') # 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', fit_blade_shape_id = fields.Many2one('maintenance.equipment.image',
'适配刀片形状', domain=[('type', '=', '刀片形状')]) '适配刀片形状', domain=[('type', '=', '刀片形状')])
suitable_machining_method_ids = fields.Many2many('maintenance.equipment.image', suitable_machining_method_ids = fields.Many2many('maintenance.equipment.image',
@@ -429,44 +491,97 @@ class ResProductMo(models.Model):
# if not self.cutting_direction_ids: # if not self.cutting_direction_ids:
# raise ValidationError("请选择走刀方向") # 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') feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'product_template_id', string='每齿走刀量fz')
cutting_tool_diameter = fields.Float('刀具直径(mm)') cutting_tool_diameter = fields.Float('刀具直径(mm)')
cutting_tool_rear_angle = fields.Integer('后角(°)') # cutting_tool_rear_angle = fields.Integer('后角(°)')
cutting_tool_main_included_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( cutting_tool_chuck_id = fields.Many2one(
'sf.cutting_tool.standard.library', 'sf.cutting_tool.standard.library',
domain="[('cutting_tool_type', '=', '夹头')]", domain="[('cutting_tool_type', '=', '夹头')]",
string='适用夹头型号') string='适用夹头型号')
# 刀片参数 # 刀片参数
cutting_tool_cut_blade_length = fields.Float('切削刃长(mm)') # cutting_tool_cut_blade_length = fields.Float('切削刃长(mm)')
cutting_tool_blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20) cutting_tool_cut_blade_length = fields.Float(related='specification_id.cutting_blade_length',
cutting_tool_top_angle = fields.Integer('顶角(°)') string='切削刃长(mm)')
cutting_tool_inscribed_circle_diameter = fields.Float('内接圆直径(mm)') # specification_id.cutting_blade_length
cutting_tool_install_aperture_diameter = fields.Float('安装孔直径(mm)') # cutting_tool_blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20)
cutting_tool_chip_breaker_groove = fields.Selection([('', ''), ('单面', '单面'), ('双面', '双面')], 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='有无断屑槽') string='有无断屑槽')
cutting_tool_chip_breaker_type_code = fields.Char('断屑槽型代号') # specification_id.chip_breaker_groove
cutting_tool_bladed_teeth_model = fields.Selection( # cutting_tool_chip_breaker_type_code = fields.Char('断屑槽型代号')
[('', ''), ('V牙型', 'V牙型'), ('米制全牙型', '米制全牙型'), ('美制全牙型', '美制全牙型'), cutting_tool_chip_breaker_type_code = fields.Char(related='specification_id.chip_breaker_type_code',
('惠氏全牙型', '惠氏全牙型'), ('BSPT全牙型', 'BSPT全牙型'), ('NPT全牙型', 'NPT全牙型'), string='断屑槽型代号')
('UNJ全牙型', 'UNJ全牙型'), ('DIN405圆牙型', 'DIN405圆牙型'), ('ACME梯形', 'ACME梯形'), # specification_id.chip_breaker_type_code
('石油管螺纹刀片', '石油管螺纹刀片'), ('矮牙ACME梯形', '矮牙ACME梯形'), # cutting_tool_bladed_teeth_model = fields.Selection(
('Trapeze30° 103', 'Trapeze30° 103')], string='刀片牙型', default='') # [('无', '无'), ('V牙型', 'V牙型'), ('米制全牙型', '米制全牙型'), ('美制全牙型', '美制全牙型'),
cutting_tool_blade_blade_number = fields.Selection( # ('惠氏全牙型', '惠氏全牙型'), ('BSPT全牙型', 'BSPT全牙型'), ('NPT全牙型', 'NPT全牙型'),
[('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), # ('UNJ全牙型', 'UNJ全牙型'), ('DIN405圆牙型', 'DIN405圆牙型'), ('ACME梯形', 'ACME梯形'),
('7', '7'), ('8', '8'), ('9', '9'), ('10', '10')], # ('石油管螺纹刀片', '石油管螺纹刀片'), ('矮牙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='刀片的刃数(个)') string='刀片的刃数(个)')
# specification_id.blade_blade_number
cutting_tool_thread_model = fields.Selection([('', ''), ('外螺纹', '外螺纹'), ('内螺纹', '内螺纹')], # cutting_tool_thread_model = fields.Selection([('无', '无'), ('外螺纹', '外螺纹'), ('内螺纹', '内螺纹')],
# string='螺纹类型')
cutting_tool_thread_model = fields.Selection(related='specification_id.thread_model',
string='螺纹类型') string='螺纹类型')
cutting_tool_thread_num = fields.Float('每英寸螺纹数(tpi)') # specification_id.thread_model
cutting_tool_blade_tip_height_tolerance = fields.Char('刀尖高度公差(mm)', size=20) # cutting_tool_thread_num = fields.Float('每英寸螺纹数(tpi)')
cutting_tool_inscribed_circle_tolerance = fields.Char('内接圆公差(mm)', size=20) cutting_tool_thread_num = fields.Float(related='specification_id.thread_num',
cutting_tool_thickness_tolerance = fields.Char('厚度公差(mm)', size=20) string='每英寸螺纹数(tpi)')
# specification_id.thread_num
cutting_tool_jump_accuracy = fields.Char('径跳精度(mm)') # 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_working_hardness = fields.Integer('加工硬度(hrc)')
cutting_tool_cutter_bar_ids = fields.Many2many( cutting_tool_cutter_bar_ids = fields.Many2many(
'sf.cutting_tool.standard.library', 'sf.cutting_tool.standard.library',
@@ -485,55 +600,153 @@ class ResProductMo(models.Model):
string='适用刀盘型号' # 使用空列表作为默认值 string='适用刀盘型号' # 使用空列表作为默认值
) )
# 刀杆/参数 # 刀杆/参数
cutting_tool_knife_head_height = fields.Float('刀头高度(mm)') # cutting_tool_knife_head_height = fields.Float('刀头高度(mm)')
cutting_tool_knife_head_width = fields.Float('刀头宽度(mm)') cutting_tool_knife_head_height = fields.Float(related='specification_id.knife_head_height',
cutting_tool_knife_head_length = fields.Float('刀头度(mm)') string='刀头度(mm)')
cutting_tool_blade_diameter = fields.Float('刃径/刃部直径(mm)') # specification_id.knife_head_height
cutting_tool_cutter_arbor_diameter = fields.Float('刀杆直径(mm)') # cutting_tool_knife_head_width = fields.Float('刀头宽度(mm)')
cutting_tool_min_machining_aperture = fields.Integer('最小加工孔径(mm)') cutting_tool_knife_head_width = fields.Float(related='specification_id.knife_head_width',
cutting_tool_install_blade_tip_num = fields.Integer('可装刀片数/齿数(个)') string='刀头宽度(mm)')
cutting_tool_installing_structure = fields.Char('安装结构', size=20) # 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( cutting_tool_blade_id = fields.Many2one(
'sf.cutting_tool.standard.library', 'sf.cutting_tool.standard.library',
domain="[('cutting_tool_type', '=', '刀片')]", domain="[('cutting_tool_type', '=', '刀片')]",
string='适用刀片型号' # 使用空列表作为默认值 string='适用刀片型号' # 使用空列表作为默认值
) )
cutting_tool_tool_shim = fields.Char('适配刀垫型号', size=50) # cutting_tool_blade_id = fields.Many2one(related='specification_id.blade_id',
cutting_tool_cotter_pin = fields.Char('适配销钉型号', size=50) # domain="[('cutting_tool_type', '=', '刀片')]",
cutting_tool_pressing_plate = fields.Char('适配压板型号', size=50) # string='适用刀片型号')
cutting_tool_screw = fields.Char('适配螺钉型号', size=50) # specification_id.blade_id
cutting_tool_wrench = fields.Char('适配扳手型号') # cutting_tool_tool_shim = fields.Char('适配刀垫型号', size=50)
cutting_tool_is_cooling_hole = fields.Boolean('有无冷却孔', default=False) cutting_tool_tool_shim = fields.Char(related='specification_id.tool_shim',
cutting_tool_locating_slot_code = fields.Char('定位槽代号', size=20) 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_cutter_head_diameter = fields.Float('刀盘直径(mm)')
cutting_tool_interface_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_max = fields.Float('最大夹持直径')
cutting_tool_clamping_diameter_min = fields.Float('最小夹持直径') cutting_tool_clamping_diameter_max = fields.Float(related='specification_id.max_clamping_diameter',
cutting_tool_flange_length = fields.Float('法兰柄长(mm)') string='最大夹持直径')
cutting_tool_flange_diameter = fields.Float('法兰直径(mm)') # specification_id.max_clamping_diameter
cutting_tool_is_safety_lock = fields.Boolean('有无安全锁', default=False) # cutting_tool_clamping_diameter_min = fields.Float('最小夹持直径')
cutting_tool_is_high_speed_cutting = fields.Boolean('可高速切削', default=False) cutting_tool_clamping_diameter_min = fields.Float(related='specification_id.min_clamping_diameter',
cutting_tool_change_time = fields.Integer('换刀时间(s)') string='最小夹持直径')
cutting_tool_clamping_way = fields.Char('夹持方式') # specification_id.min_clamping_diameter
cutting_tool_fit_chuck_size = fields.Char('适配夹头尺寸') # cutting_tool_flange_length = fields.Float('法兰柄长(mm)')
cutting_tool_taper_shank_model = fields.Char('锥柄型号') 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_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_cooling_type = fields.Char('冷却类型')
cutting_tool_dynamic_balance_class = 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_taper = fields.Integer('锥度(°)')
cutting_tool_top_diameter = fields.Float('顶部直径') cutting_tool_taper = fields.Integer(related='specification_id.taper',
cutting_tool_outer_diameter = fields.Float('外径(mm)') string='锥度(°)')
cutting_tool_inner_diameter = fields.Float('内径(mm)') # specification_id.taper
cooling_suit_type_ids = fields.Char('适用冷却套型号') # cutting_tool_top_diameter = fields.Float('顶部直径')
cutting_tool_max_load_capacity = fields.Float('最大负载能力(kg)') cutting_tool_top_diameter = fields.Float(related='specification_id.top_diameter',
cutting_tool_er_size_model = fields.Char('尺寸型号') 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( # cutting_tool_handle_ids = fields.Many2many(
# 'sf.cutting_tool.standard.library', # 'sf.cutting_tool.standard.library',
# relation='product_cutting_tool_library_chuck_handle_rel', # relation='product_cutting_tool_library_chuck_handle_rel',
@@ -548,6 +761,10 @@ class ResProductMo(models.Model):
domain="[('cutting_tool_type', '=', '刀柄')]", domain="[('cutting_tool_type', '=', '刀柄')]",
string='适用刀柄型号' 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([('未注册', '未注册'), ('已注册', '已注册'), ('注册失败', '注册失败')], register_state = fields.Selection([('未注册', '未注册'), ('已注册', '已注册'), ('注册失败', '注册失败')],

View File

@@ -296,6 +296,10 @@
</attribute> </attribute>
</xpath> </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"> <xpath expr="//sheet//notebook//page[@name='operations']" position="after">
<page string="检测结果" attrs="{'invisible': [('detection_result_ids', '=', [])]}"> <page string="检测结果" attrs="{'invisible': [('detection_result_ids', '=', [])]}">
<field name="detection_result_ids" string="" readonly="0"> <field name="detection_result_ids" string="" readonly="0">

View File

@@ -520,7 +520,7 @@
<xpath expr="//form//header" position="inside"> <xpath expr="//form//header" position="inside">
<button type="object" class="oe_highlight jikimo_button_confirm" name="get_three_check_datas" <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> </xpath>
@@ -797,7 +797,7 @@
<field name="feeder_station_start_id" readonly="1" force_save="1"/> <field name="feeder_station_start_id" readonly="1" force_save="1"/>
<!-- <field name="type" readonly="1"/>--> <!-- <field name="type" readonly="1"/>-->
<field name="feeder_station_destination_id" readonly="1" force_save="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" <button name="action_delivery_history" type="object" class="btn btn-link text-info" icon="fa-history"
string="历史"/> string="历史"/>
</tree> </tree>

View File

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

View File

@@ -11,9 +11,12 @@
""", """,
'category': 'sf', 'category': 'sf',
'website': 'https://www.sf.jikimo.com', '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': [
'data/bussiness_node.xml' 'data/bussiness_node.xml',
# 'data/cron_data.xml',
'data/template_data.xml',
], ],
'test': [ '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" ?> <?xml version="1.0" ?>
<odoo> <odoo>
<data noupdate="1"> <data noupdate="1">
<!--销售订单-->
<record id="bussiness_pending_order" model="jikimo.message.bussiness.node"> <record id="bussiness_pending_order" model="jikimo.message.bussiness.node">
<field name="name">待接单</field> <field name="name">待接单</field>
<field name="model">sale.order</field> <field name="model">sale.order</field>
@@ -10,5 +11,79 @@
<field name="name">确认接单</field> <field name="name">确认接单</field>
<field name="model">sale.order</field> <field name="model">sale.order</field>
</record> </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> </data>
</odoo> </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_functional_tool_assembly
from . import sf_message_purchase from . import sf_message_purchase
from . import sf_message_workorder 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): class SFMessagefunctionalToolAssembly(models.Model):
_name = 'sf.functional.tool.assembly' _name = 'sf.functional.tool.assembly'
_description = "刀具组装单"
_inherit = ['sf.functional.tool.assembly', 'jikimo.message.dispatch'] _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 odoo import models, fields, api, _
from urllib.parse import urlencode
class SFMessagePurchase(models.Model): class SFMessagePurchase(models.Model):
_name = 'purchase.order' _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 -*- # -*- coding: utf-8 -*-
import logging
from odoo import models, fields, api, _ from odoo import models, fields, api, _
@@ -21,19 +22,52 @@ class SFMessageSale(models.Model):
if res is True: if res is True:
try: try:
self.add_queue('确认接单') 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: except Exception as e:
logging.info('add_queue error:%s' % e) logging.info('add_queue error:%s' % e)
return res return res
# 继承并重写jikimo.message.dispatch的_get_message() # 继承并重写jikimo.message.dispatch的_get_message()
def _get_message(self, message_queue_ids): def _get_message(self, message_queue_ids):
res = super(SFMessageSale, self)._get_message(message_queue_ids) contents = []
if message_queue_ids.message_template_id.bussiness_node_id.name == '确认接单': url = self.env['ir.config_parameter'].get_param('web.base.url')
# sale_order = self.env['sale.order'].search([('id', '=', message_queue_ids.model.res_id)]) for item in message_queue_ids:
sale_order_line = self.env['sale.order.line'].search([('order_id', '=', int(message_queue_ids.res_id))]) # 待接单的处理
if len(sale_order_line) == 1: if item.message_template_id.bussiness_node_id.name == '待接单':
product = sale_order_line[0].product_id.name content = super(SFMessageSale, self)._get_message(item)
elif len(sale_order_line) > 1: action_id = self.env.ref('sale.action_quotations_with_onboarding').id
product = '%s...' % sale_order_line[0].product_id.name url = f"{url}/web#id={item.res_id}&view_type=form&action={action_id}"
res[0] = res[0].replace('{{product_id}}', product) content = content[0].replace('{{url}}', url)
return res 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 odoo import models, fields, api, _
from urllib.parse import urlencode
class SFMessageStockPicking(models.Model): class SFMessageStockPicking(models.Model):
_name = 'stock.picking' _name = 'stock.picking'
_description = "库存调拨"
_inherit = ['stock.picking', 'jikimo.message.dispatch'] _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): def _get_message_model(self):
res = super(SfMessageTemplate, self)._get_message_model() res = super(SfMessageTemplate, self)._get_message_model()
res.append("sale.order") 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 return res

View File

@@ -1,6 +1,54 @@
from odoo import models, fields, api, _ 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): class SFMessageWork(models.Model):
_name = 'mrp.workorder' _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: if cnc_workorder_has.cnc_ids:
cnc_workorder_has.cmm_ids.sudo().unlink() cnc_workorder_has.cmm_ids.sudo().unlink()
cnc_workorder_has.cnc_ids.sudo().unlink() cnc_workorder_has.cnc_ids.sudo().unlink()
request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan( # request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
production) # production)
cnc_workorder_has.write( cnc_workorder_has.write(
{'cnc_ids': cnc_workorder_has.cnc_ids.sudo()._json_cnc_processing(panel, ret), {'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)}) '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( pre_workorder.write(
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())}) {'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
productions.write({'programming_state': '已编程', 'work_state': '已编程'}) productions.write({'programming_state': '已编程', 'work_state': '已编程'})
res.update({
'production_ids': productions.ids
})
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
else: else:
res = {'status': 0, 'message': '该制造订单暂未开始'} res = {'status': 0, 'message': '该制造订单暂未开始'}

View File

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

View File

@@ -175,7 +175,7 @@ class ResConfigSettings(models.TransientModel):
new_price = res_order_lines_map.get(str(index)) new_price = res_order_lines_map.get(str(index))
if order_line: 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 )]) order_price = self.env['order.price'].sudo().search([('sale_order_id', '=',need_change_sale_order.id )])
if not order_price: if not order_price:
self.env['order.price'].sudo().create({'sale_order_id':need_change_sale_order.id}) 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'], 'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'], 'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_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'], 'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'], 'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[ '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'], 'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'], 'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_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'], 'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'], 'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[ '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 'basic_parameters_cutter_head' in result['cutting_tool_basic_parameters_yesterday_list']:
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']: if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']:
basic_parameters_cutter_head_list = json.loads( basic_parameters_cutter_head_list = result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']
result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head'])
if basic_parameters_cutter_head_list: if basic_parameters_cutter_head_list:
for cutter_head_item in basic_parameters_cutter_head_list: for cutter_head_item in basic_parameters_cutter_head_list:
cutter_head = self.search( cutter_head = self.search(
@@ -3031,7 +3032,8 @@ class CuttingToolBasicParameters(models.Model):
'interface_diameter': cutter_head_item['interface_diameter'], 'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'], 'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_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'], 'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'], 'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[ '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'], 'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'], 'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_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'], 'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'], 'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[ '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 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_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" <menuitem sequence="22" name="销售订单bfm对比" id="menu_sale_order_bfm_price"
action="order_price_tree_act" action="order_price_tree_act"
parent="sale.sale_order_menu" 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"> <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" sequence="150"
action="sf_production_plan_action" action="sf_production_plan_action"
groups="sf_base.group_plan_dispatch" 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"> --> <!-- <record model="ir.ui.menu" id="mrp_custom_menu" inherit_id="mrp.menu_mrp_manufacturing"> -->
@@ -338,7 +339,7 @@
name="空料架配送" name="空料架配送"
sequence="11" sequence="11"
action="sf_manufacturing.sf_workpiece_delivery_empty_racks_act" 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" parent="mrp.menu_mrp_manufacturing"
/> />
<!-- <menuitem --> <!-- <menuitem -->

View File

@@ -74,6 +74,8 @@ class StockPicking(models.Model):
def send_to_bfm(self): def send_to_bfm(self):
skip_backorder = self.env.context.get('skip_backorder') skip_backorder = self.env.context.get('skip_backorder')
cancel_backorder_ids = self.env.context.get('picking_ids_not_to_backorder')
# 下发发货到bfm # 下发发货到bfm
config = self.env['res.config.settings'].get_values() config = self.env['res.config.settings'].get_values()
move_ids, move_line_ids = self.deal_move_ids(self.move_ids, self.move_line_ids) 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, 'state': self.state,
'backorder_id': self.deal_send_backorder_id(self.backorder_id), 'backorder_id': self.deal_send_backorder_id(self.backorder_id),
'backorder_ids': self.deal_send_backorder_id(self.backorder_ids), '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, 'move_type': self.move_type,
}, },
} }
url1 = config['bfm_url_new'] + '/api/stock/deliver_goods' url1 = config['bfm_url_new'] + '/api/stock/deliver_goods'
json_str = json.dumps(data) 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) r = requests.post(url1, json=data, data=None)
if r.status_code == 200: if r.status_code == 200:
result = json.loads(r.json()['result']) result = json.loads(r.json()['result'])

View File

@@ -185,6 +185,7 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
_description = 'CAM工单程序用刀计划' _description = 'CAM工单程序用刀计划'
name = fields.Char('工单任务编号') name = fields.Char('工单任务编号')
programming_no = fields.Char('编程单号')
cam_procedure_code = fields.Char('程序名') cam_procedure_code = fields.Char('程序名')
filename = fields.Char('文件') filename = fields.Char('文件')
cam_cutter_spacing_code = fields.Char('刀号') cam_cutter_spacing_code = fields.Char('刀号')
@@ -317,8 +318,18 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
""" """
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划 根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
""" """
# 获取编程单号
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({ knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
'name': cnc_processing.workorder_id.production_id.name, 'name': cnc_processing.workorder_id.production_id.name,
'programming_no': programming_no,
'cam_procedure_code': cnc_processing.program_name, 'cam_procedure_code': cnc_processing.program_name,
'filename': cnc_processing.cnc_id.name, 'filename': cnc_processing.cnc_id.name,
'functional_tool_name': cnc_processing.cutting_tool_name, 'functional_tool_name': cnc_processing.cutting_tool_name,

View File

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

View File

@@ -95,6 +95,10 @@ class CNCprocessing(models.Model):
# tool_state_remark1 = f'{key}无效刀:{data1.get(key)}' # tool_state_remark1 = f'{key}无效刀:{data1.get(key)}'
# 无效刀处理逻辑 # 无效刀处理逻辑
# 1、创建制造订单无效刀检测结果记录 # 1、创建制造订单无效刀检测结果记录
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('创建制造订单无效刀检测结果记录!') logging.info('创建制造订单无效刀检测结果记录!')
production_id.detection_result_ids.create({ production_id.detection_result_ids.create({
'production_id': production_id.id, 'production_id': production_id.id,

View File

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