Compare commits

..

187 Commits

Author SHA1 Message Date
胡尧
97a26dfa06 修改工单通知筛选条件 2024-10-23 15:50:01 +08:00
胡尧
1224e0e094 修改工单通知筛选条件 2024-10-23 15:38:09 +08:00
胡尧
a571a870d3 修改工单通知筛选条件 2024-10-23 15:33:48 +08:00
胡尧
451e70b7c7 Accept Merge Request #1434: (feature/workorder_exceptions -> develop)
Merge Request: 修改无功能刀具原因话术

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1434
2024-10-21 17:03:34 +08:00
胡尧
6c1c2ca0fc 修改无功能刀具原因话术 2024-10-21 17:02:59 +08:00
廖丹龙
e7420365cf Accept Merge Request #1433: (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/1433
2024-10-21 16:09:08 +08:00
liaodanlong
736a18518c 制造订单添加订单交期字段信息 2024-10-21 16:07:43 +08:00
liaodanlong
41b287d559 制造订单添加订单交期字段信息 2024-10-21 16:06:03 +08:00
胡尧
5d8e0bda08 Accept Merge Request #1432: (feature/workorder_exceptions -> develop)
Merge Request: 处理设备故障的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1432?initial=true
2024-10-21 15:41:06 +08:00
胡尧
e9dbbaedf4 处理设备故障的问题 2024-10-21 15:40:38 +08:00
胡尧
92ae6be3bd Accept Merge Request #1431: (feature/workorder_exceptions -> develop)
Merge Request: 修改模板标题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1431
2024-10-21 14:59:57 +08:00
胡尧
b00038aaed 修改YC0004消息推送 2024-10-21 14:59:16 +08:00
胡尧
86c1880cdb 修改模板标题 2024-10-21 14:41:09 +08:00
廖丹龙
cfd2dda4e6 Accept Merge Request #1430: (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/1430
2024-10-21 14:34:07 +08:00
liaodanlong
c01e9a4d39 制造订单添加订单交期字段信息 2024-10-21 14:18:53 +08:00
廖丹龙
88ff4bbaa9 Accept Merge Request #1429: (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/1429?initial=true
2024-10-21 14:01:20 +08:00
liaodanlong
f62c70d354 Merge branch 'refs/heads/develop' into feature/销售和排程添加消息推送 2024-10-21 13:57:24 +08:00
liaodanlong
22c9de86f6 制造订单添加订单交期字段信息 2024-10-21 13:56:34 +08:00
胡尧
b362f74336 Accept Merge Request #1428: (feature/workorder_exceptions -> develop)
Merge Request: 修改接口参数

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1428?initial=true
2024-10-21 13:47:36 +08:00
胡尧
81cfbfb540 修改接口参数 2024-10-21 11:46:14 +08:00
胡尧
668db4475f Accept Merge Request #1427: (feature/workorder_exceptions -> develop)
Merge Request: 修改单元测试

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1427?initial=true
2024-10-21 11:37:48 +08:00
胡尧
2af21bc4ee 修改单元测试 2024-10-21 11:37:01 +08:00
管欢
e6614a624f Accept Merge Request #1426: (feature/auxiliary_files_upload -> 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/1426
2024-10-21 10:11:36 +08:00
guanhuan
124bc8478e 辅助文件上传 2024-10-21 10:09:19 +08:00
guanhuan
1a3a178ec6 Revert "辅助文件上传"
This reverts commit cae5149fba.
2024-10-21 10:08:35 +08:00
guanhuan
cae5149fba 辅助文件上传 2024-10-21 10:07:49 +08:00
管欢
5c4c036948 Accept Merge Request #1425: (feature/auxiliary_files_upload -> 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/1425
2024-10-21 10:01:22 +08:00
guanhuan
4003d6a652 Merge branch 'refs/heads/develop' into feature/auxiliary_files_upload
# Conflicts:
#	sf_dlm_management/views/product_template_management_view.xml
2024-10-21 09:50:09 +08:00
胡嘉莹
0e8e81e4cb Accept Merge Request #1423: (feature/临时分支 -> develop)
Merge Request: sf销售订单明细新增是否带料及带料尺寸字段

Created By: @胡嘉莹
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @胡嘉莹
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1423
2024-10-18 16:44:46 +08:00
hujiaying
8cff3d8377 sf销售订单详情新增是否带料,带料尺寸,修改bfm分配工厂,sf接收订单生成销售订单新增两个字段,并修改订单详情及订单详情表单新增字段显示 2024-10-18 16:39:15 +08:00
guanhuan
b132771c92 辅助文件上传 2024-10-18 14:32:20 +08:00
马广威
cbaf0d79c1 Accept Merge Request #1422: (feature/制造功能优化 -> develop)
Merge Request: 增加设备oee处获取数据的定时器

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1422?initial=true
2024-10-18 10:18:28 +08:00
mgw
953d675dcf Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-10-18 10:17:38 +08:00
mgw
182eb83090 暂时屏蔽24数据 2024-10-18 10:17:22 +08:00
mgw
67a607b053 增加设备oee处获取数据的定时器 2024-10-18 10:05:55 +08:00
禹翔辉
33d23c28b1 Accept Merge Request #1421: (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/1421
2024-10-18 09:21:43 +08:00
yuxianghui
571fb29482 Merge branch 'feature/用刀校验优化' into feature/工单状态优化 2024-10-18 09:14:39 +08:00
yuxianghui
1dae20e055 处理制造订单、工单的状态计算方法没有触发的问题 2024-10-18 09:13:34 +08:00
hujiaying
6be9d44572 Merge remote-tracking branch 'origin/develop' into feature/临时分支 2024-10-18 08:40:57 +08:00
mgw
8a459e7e90 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-10-17 17:54:59 +08:00
mgw
4c486e53aa 设备oee界面数据准备 2024-10-17 17:54:32 +08:00
yuxianghui
19509a3ce2 1 2024-10-17 17:54:08 +08:00
胡嘉莹
4d424e90d3 Accept Merge Request #1420: (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/1420?initial=true
2024-10-17 17:49:26 +08:00
hujiaying
9bbf613bcb 修改生成完工入库提醒,订单发货提醒跳转到表单详情 2024-10-17 17:39:43 +08:00
禹翔辉
f5ea0ec153 Accept Merge Request #1419: (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/1419?initial=true
2024-10-17 17:04:12 +08:00
yuxianghui
ea6c0f7d0b Merge branch 'feature/程序用刀校验优化' into feature/用刀校验优化 2024-10-17 17:02:17 +08:00
yuxianghui
763009a3c0 1、优化手动返工时,cnc用刀校验逻辑 2024-10-17 17:01:20 +08:00
guanhuan
cf34ac5bbc 辅助文件上传 2024-10-17 16:31:13 +08:00
禹翔辉
0faedd35d7 Accept Merge Request #1418: (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/1418
2024-10-17 16:01:42 +08:00
yuxianghui
135b97d4f8 1 2024-10-17 16:00:44 +08:00
yuxianghui
61f3aff768 Merge branch 'feature/制造订单状态优化_3' into feature/程序用刀校验优化 2024-10-17 15:52:06 +08:00
yuxianghui
9e369f0150 修改调用创建cam程序用刀计划方法的判断条件 2024-10-17 15:51:00 +08:00
杨金灵
16d50f5bf2 Accept Merge Request #1417: (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/1417?initial=true
2024-10-17 15:40:23 +08:00
jinling.yang
80f0454996 工作中心添加质检权限 2024-10-17 15:37:08 +08:00
jinling.yang
9b9d811594 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-17 15:33:51 +08:00
jinling.yang
008ae20329 Merge branch 'feature/检测结果添加质检权限' into develop 2024-10-17 15:33:29 +08:00
杨金灵
80b3b4b0f7 Accept Merge Request #1416: (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/1416
2024-10-17 15:26:29 +08:00
jinling.yang
d64b480496 检测结果添加质检权限 2024-10-17 15:25:13 +08:00
禹翔辉
854ec8da4e Accept Merge Request #1415: (feature/制造订单状态优化_3 -> develop)
Merge Request: 1

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1415?initial=true
2024-10-17 14:43:48 +08:00
yuxianghui
d25b871854 1 2024-10-17 14:42:35 +08:00
禹翔辉
37aafe7b30 Accept Merge Request #1414: (feature/制造订单状态优化_3 -> develop)
Merge Request: 1、优化手动获取编程的接口,添加获取编程完成之后进行用刀校验;2、处理 权限问题-工单详情缺少【时间跟踪】tab;3、用刀校验方法添加日志

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1414
2024-10-17 14:29:32 +08:00
yuxianghui
26910f7b15 Merge branch 'feature/制造订单状态优化_2' into feature/制造订单状态优化_3 2024-10-17 14:25:05 +08:00
杨金灵
3ea2acd46e Accept Merge Request #1413: (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/1413?initial=true
2024-10-17 14:23:36 +08:00
yuxianghui
303462ba9c Merge branch 'feature/制造订单状态优化_1' into feature/制造订单状态优化_2 2024-10-17 14:22:59 +08:00
jinling.yang
53fad50af6 修复工单定时器 2024-10-17 14:22:43 +08:00
yuxianghui
1245323b9d 1、优化手动获取编程的接口,添加获取编程完成之后进行用刀校验;2、处理 权限问题-工单详情缺少【时间跟踪】tab;3、用刀校验方法添加日志 2024-10-17 14:22:09 +08:00
杨金灵
4d8e86cff3 Accept Merge Request #1412: (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/1412
2024-10-17 14:08:18 +08:00
jinling.yang
7bc7d2059c 还原代码 2024-10-17 14:06:16 +08:00
jinling.yang
f9c209e85c Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-17 13:47:40 +08:00
jinling.yang
6ae783387c Merge branch 'feature/修复加工质检' into develop 2024-10-17 13:47:18 +08:00
杨金灵
7c0202afc6 Accept Merge Request #1411: (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/1411?initial=true
2024-10-17 13:47:00 +08:00
jinling.yang
9ad582612b 还原注释代码 2024-10-17 13:43:43 +08:00
jinling.yang
d1db917432 修复加工质检 2024-10-17 11:58:54 +08:00
杨金灵
847293385d Accept Merge Request #1410: (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/1410?initial=true
2024-10-17 11:34:40 +08:00
jinling.yang
4e8eccfd0b 还原代码 2024-10-17 11:33:20 +08:00
jinling.yang
5cb5306471 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-17 11:19:28 +08:00
jinling.yang
9a5b45b969 Merge branch 'feature/加工质检添加权限' into develop 2024-10-17 11:19:04 +08:00
杨金灵
7c82bbf3da Accept Merge Request #1409: (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/1409?initial=true
2024-10-17 11:18:39 +08:00
jinling.yang
9177acf277 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/加工质检添加权限
# Conflicts:
#	sf_quality/views/quality_cnc_test_view.xml
2024-10-17 11:03:08 +08:00
jinling.yang
93187d7f4a Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-17 11:01:57 +08:00
jinling.yang
94b1551de2 加工质检添加权限 2024-10-17 11:01:42 +08:00
马广威
1c713d3278 Accept Merge Request #1408: (feature/制造功能优化 -> develop)
Merge Request: 修改维护翻译为设备

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1408?initial=true
2024-10-17 10:26:36 +08:00
禹翔辉
bdef93fca3 Accept Merge Request #1407: (feature/制造订单状态优化_1 -> develop)
Merge Request: 优化制造订单无效刀自动编程方法

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1407?initial=true
2024-10-17 10:17:02 +08:00
yuxianghui
e9e55c72b9 Merge branch 'feature/制造订单状态优化' into feature/制造订单状态优化_1 2024-10-17 10:15:23 +08:00
yuxianghui
919450aafb 优化制造订单无效刀自动编程方法 2024-10-17 10:13:54 +08:00
jinling.yang
78f486ad7c Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-17 10:12:36 +08:00
jinling.yang
ccdfcb5e50 Merge branch 'feature/优化加工质检' into develop 2024-10-17 10:12:20 +08:00
杨金灵
9b275536e9 Accept Merge Request #1406: (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/1406?initial=true
2024-10-17 10:10:51 +08:00
jinling.yang
bf39ed10b4 还原代码 2024-10-17 10:03:45 +08:00
jinling.yang
0e8bda3369 修复加工质检 2024-10-17 09:58:24 +08:00
mgw
87bb22857a 修改维护翻译为设备 2024-10-17 09:19:47 +08:00
jinling.yang
9cd8d9d823 修复验证 2024-10-16 17:59:34 +08:00
马广威
931732f75e Accept Merge Request #1405: (feature/制造功能优化 -> develop)
Merge Request: CNC自动生产线生产业绩看板优化需求

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1405?initial=true
2024-10-16 17:33:34 +08:00
mgw
35ace3b3eb Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-10-16 17:29:41 +08:00
mgw
4b4601ae85 CNC自动生产线生产业绩看板优化需求 2024-10-16 17:29:25 +08:00
禹翔辉
46337855a4 Accept Merge Request #1404: (feature/制造订单状态优化 -> develop)
Merge Request: 1、处理 因为权限导致的功能刀具安全库存列表点击任意数据报错; 2、处理 下发程序校验刀具有无效刀时制造订单状态不对问题

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1404?initial=true
2024-10-16 17:04:00 +08:00
yuxianghui
43f8aec70a Merge branch 'feature/刀具页面存档权限设置' into feature/制造订单状态优化 2024-10-16 17:02:18 +08:00
yuxianghui
a21b4302d4 1、处理 因为权限导致的功能刀具安全库存列表点击任意数据报错; 2、处理 下发程序校验刀具有无效刀时制造订单状态不对问题 2024-10-16 17:01:15 +08:00
jinling.yang
4adc3b700a Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/工单定时器修复时区问题 2024-10-16 15:32:47 +08:00
杨金灵
42b5a32708 Accept Merge Request #1403: (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/1403?initial=true
2024-10-16 15:00:58 +08:00
jinling.yang
296e30e5fd Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-16 14:59:16 +08:00
jinling.yang
90718cc989 Merge branch 'feature/修复工单write方法' into develop 2024-10-16 14:53:37 +08:00
杨金灵
857930e169 Accept Merge Request #1402: (feature/修复工单write方法 -> develop)
Merge Request: 修复工单write方法

Created By: @杨金灵
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @杨金灵
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1402
2024-10-16 14:50:14 +08:00
jinling.yang
9b1b6e2b72 修复工单修改方法 2024-10-16 14:49:54 +08:00
jinling.yang
37217b0dd9 修复工单write方法 2024-10-16 14:46:31 +08:00
杨金灵
f138eab47a Accept Merge Request #1401: (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/1401?initial=true
2024-10-16 14:16:54 +08:00
jinling.yang
4e4c53927b 下发编程单接口添加输出 2024-10-16 14:15:37 +08:00
jinling.yang
fab1d77d64 还原注释代码 2024-10-16 14:07:35 +08:00
jinling.yang
f4f7087465 添加2D图纸和质量标准2个字段 2024-10-16 14:06:18 +08:00
jinling.yang
020da1d510 Merge branch 'feature/auxiliary_files_upload' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化加工质检 2024-10-16 11:49:37 +08:00
jinling.yang
2956f13ee7 优化加工质检 2024-10-16 11:49:05 +08:00
guanhuan
939f3d58f4 产品新增2D加工图纸,质检标准 2024-10-16 11:41:15 +08:00
胡尧
3d85b7863c Accept Merge Request #1400: (feature/workorder_exceptions -> develop)
Merge Request: 工单异常记录及消息通知

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1400?initial=true
2024-10-16 10:23:19 +08:00
胡尧
54abb7a9f7 增加备注 2024-10-16 10:22:30 +08:00
胡尧
9ca9b337ef 解决sf_quality报错问题,增加单元测试 2024-10-16 10:19:41 +08:00
胡尧
92c4bcb049 解决冲突 2024-10-15 15:25:31 +08:00
胡尧
ce5cb17e31 工单异常处理 2024-10-15 15:14:16 +08:00
杨金灵
6330929c04 Accept Merge Request #1399: (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/1399?initial=true
2024-10-15 11:56:14 +08:00
jinling.yang
79a753b609 优化质检生产仓看板 2024-10-15 11:55:10 +08:00
jinling.yang
30ebc62697 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-15 09:30:58 +08:00
jinling.yang
28b218a13b Merge branch 'feature/销售订单和工单逾期消息推送' into develop 2024-10-15 09:30:25 +08:00
杨金灵
cd24430ea9 Accept Merge Request #1398: (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/1398
2024-10-15 09:30:08 +08:00
jinling.yang
f4daf94f7b 还原代码 2024-10-15 09:29:23 +08:00
jinling.yang
4acce194d9 Merge branch 'feature/销售订单和工单逾期消息推送' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/销售订单和工单逾期消息推送 2024-10-15 09:27:16 +08:00
jinling.yang
761e8d4579 还原代码 2024-10-15 09:26:55 +08:00
杨金灵
284c66ad86 Merge branch refs/heads/develop into refs/heads/feature/销售订单和工单逾期消息推送 2024-10-15 09:17:21 +08:00
jinling.yang
6c7c10924a 还原注释代码 2024-10-15 09:07:11 +08:00
jinling.yang
8f2d5129b1 还原代码 2024-10-15 09:06:13 +08:00
jinling.yang
2a067778bc 优化质量检测(加工检测)及消息推送 2024-10-14 17:53:38 +08:00
禹翔辉
299cc2f12f Accept Merge Request #1397: (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/1397?initial=true
2024-10-14 16:04:41 +08:00
yuxianghui
ce705abd20 刀具页面存档权限设置为只有超级管理员才能存档 2024-10-14 16:03:21 +08:00
胡尧
e2bd36ca16 工单异常处理 2024-10-14 15:18:27 +08:00
禹翔辉
e2dbd41e8f Accept Merge Request #1396: (feature/工单form视图优化 -> 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/1396
2024-10-14 13:47:43 +08:00
yuxianghui
050a61f334 Merge branch 'feature/制造订单功能刀具状态优化' into feature/工单form视图优化 2024-10-14 13:45:24 +08:00
马广威
0fa7c1b2d7 Accept Merge Request #1395: (feature/制造功能优化 -> develop)
Merge Request: 调整“驾驶舱”的机床状态与工厂产线实际不一致的问题

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1395?initial=true
2024-10-14 13:45:17 +08:00
yuxianghui
e1af6ba2f5 1、完成 工件装夹工单详情页版面优化需求 2024-10-14 13:41:52 +08:00
禹翔辉
4a928735eb Accept Merge Request #1394: (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/1394?initial=true
2024-10-11 17:59:10 +08:00
yuxianghui
fdc2af4a39 Merge branch 'feature/销售订单按钮优化' into feature/制造订单功能刀具状态优化 2024-10-11 17:56:51 +08:00
yuxianghui
70b3daad73 1、删除功能刀具tree视图图片字段;2、修改货位看板关联展示字段;3、获取编程单接口调用cnc用刀校验方法添加报错处理; 2024-10-11 17:53:12 +08:00
jinling.yang
d8bade64e1 优化质量:添加加工质检 2024-10-11 17:52:33 +08:00
胡尧
f779c492d8 Accept Merge Request #1393: (feature/流程用扫码完成 -> develop)
Merge Request: 解决销售单不能新增的bug

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1393?initial=true
2024-10-11 15:04:50 +08:00
胡尧
a7b98f1e5e 解决销售单不能新增的bug 2024-10-11 15:03:46 +08:00
胡嘉莹
797eb9b159 Accept Merge Request #1392: (feature/临时分支 -> develop)
Merge Request: 修改消息发送前已入库或已发货消息发送内容为null

Created By: @胡嘉莹
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @胡嘉莹
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1392?initial=true
2024-10-11 10:10:57 +08:00
hujiaying
c3e40fd3aa 修改消息发送前已入库或已发货消息发送内容为null 2024-10-11 09:52:42 +08:00
胡嘉莹
0ed07b024a Accept Merge Request #1391: (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/1391?initial=true
2024-10-11 08:54:03 +08:00
hujiaying
22da51729b 修改项目升级初始化数据问题 2024-10-11 08:47:56 +08:00
廖丹龙
c3be2894c9 Accept Merge Request #1386: (feature/销售和排程添加消息推送 -> develop)
Merge Request: 产品 qty_available字段名称修改为库存数量

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1386
2024-10-10 17:55:49 +08:00
胡嘉莹
e08f968f1a Accept Merge Request #1390: (feature/临时分支 -> develop)
Merge Request: 新增sf生产完工入库提醒,订单发货提醒代码

Created By: @胡嘉莹
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @胡嘉莹
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1390
2024-10-10 17:53:57 +08:00
jinling.yang
351815ad91 优化销售订单+工单逾期预警和已1逾期代码 2024-10-10 17:36:35 +08:00
yuxianghui
25a90f3966 1、获取mrs编程接口优化,重新编程接口优化,创建CAM方法优化,cnc用刀校验逻辑优化 2024-10-10 17:31:56 +08:00
hujiaying
50bb50f5ab 修改计划排程,超过小时产能提示产线的小时产能以及超出的件数 2024-10-10 16:47:25 +08:00
hujiaying
d1ff7c196d 解决合并冲突 2024-10-10 16:08:23 +08:00
hujiaying
298d2391de Merge remote-tracking branch 'origin/develop' into feature/临时分支
# Conflicts:
#	sf_message/models/sf_message_stock_picking.py
2024-10-10 15:54:07 +08:00
hujiaying
49cbeee261 编写sf生产完工入库提醒,订单发货提醒代码 2024-10-10 15:52:14 +08:00
mgw
b104b358ea Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-10-10 14:01:56 +08:00
mgw
786fca2937 调整“驾驶舱”的机床状态与工厂产线实际不一致的问题 2024-10-10 14:01:39 +08:00
马广威
ca6d1f51df Accept Merge Request #1388: (feature/制造功能优化 -> develop)
Merge Request: 调整24h开机时长为0的问题;去掉x偏差角度的控制

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1388?initial=true
2024-10-10 11:49:22 +08:00
mgw
f324453351 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-10-10 11:36:35 +08:00
mgw
d0f5aca707 调整24h开机时长为0的问题;去掉x偏差角度的控制 2024-10-10 11:36:18 +08:00
胡尧
f0cb047e8c Accept Merge Request #1387: (release/release_2.4 -> develop)
Merge Request: 解决空料架配送的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1387
2024-10-10 11:06:01 +08:00
jinling.yang
02467d5220 优化工单消息推送 2024-10-09 17:58:47 +08:00
yuxianghui
f18c0e3eaf 1、重构cnc用刀校验方法,优化下发编程单后校验cnc用刀的逻辑;2、优化CAM创建方法;3、优化获取mrs编程单接口、优化编程单更新接口; 2024-10-09 17:52:20 +08:00
liaodanlong
c55f0b4c39 产品 qty_available字段名称修改为库存数量 2024-10-09 17:45:57 +08:00
jinling.yang
2639a6ac6b 优化销售订单逾期和预警消息推送 2024-10-09 16:42:53 +08:00
廖丹龙
52c1992814 Accept Merge Request #1383: (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/1383
2024-10-09 16:35:27 +08:00
胡嘉莹
b1fbf4344e Accept Merge Request #1385: (feature/临时分支 -> develop)
Merge Request: 修改custom_many2many_checkboxes组件,优化图片展示方式,及点击图片放大的预览样式

Created By: @胡嘉莹
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @胡嘉莹
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1385
2024-10-09 16:28:52 +08:00
hujiaying
a1b9f2dd3b 产品看板新增品牌字段,如果产品没有品牌字段则不展示品牌字段 2024-10-09 16:21:14 +08:00
hujiaying
441cfaffce 优化代码 2024-10-09 16:01:27 +08:00
hujiaying
75e1f5387d 修改coustom_many2many_checkboxes组件的展示方式,控制图片展示大小,修改点击预览图展示的样式优化 2024-10-09 16:01:12 +08:00
马广威
3f0fda7aac Accept Merge Request #1384: (feature/制造功能优化 -> develop)
Merge Request: 调整依赖、配置

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1384?initial=true
2024-10-09 10:50:58 +08:00
liaodanlong
cc5452d14c 消息推送url链接逻辑修改 2024-10-09 10:26:20 +08:00
liaodanlong
5aff8c1737 消息推送url链接逻辑修改 2024-10-09 10:14:48 +08:00
jinling.yang
a00f4af923 优化销售订单逾期 2024-10-08 17:50:59 +08:00
yuxianghui
62a2aed7d9 销售订单按钮顺序优化为: 确认接单/拒绝接单/创建结算单/通过Email发送 2024-10-08 14:26:12 +08:00
胡尧
e99f01104e Accept Merge Request #1382: (release/release_2.4 -> develop)
Merge Request: 解决logo不显示的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1382?initial=true
2024-10-08 09:20:31 +08:00
mgw
1de4704046 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化
# Conflicts:
#	sf_message/__manifest__.py
2024-09-30 10:51:54 +08:00
mgw
0d65e67140 调整依赖 2024-09-30 10:48:40 +08:00
jinling.yang
ccd01c9c75 优化合并多条发送销售订单逾期预警 2024-09-29 17:51:50 +08:00
liaodanlong
0b127ff419 Merge remote-tracking branch 'origin/feature/销售和排程添加消息推送' into feature/销售和排程添加消息推送 2024-09-29 17:12:25 +08:00
liaodanlong
d4a01d9b8a 处理会计凭证生成重复名称报错问题 2024-09-29 17:11:37 +08:00
jinling.yang
c6065653f0 优化逾期 2024-09-29 16:40:52 +08:00
jinling.yang
fd0de5ae09 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/销售订单和工单逾期消息推送
# Conflicts:
#	sf_message/__manifest__.py
#	sf_message/data/bussiness_node.xml
#	sf_message/models/sf_message_sale.py
2024-09-29 15:43:19 +08:00
mgw
83ca18d7d5 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-09-29 14:02:04 +08:00
mgw
11666b9ae1 静态数据时序库移位后的相应配置调整 2024-09-29 14:01:44 +08:00
jinling.yang
7235f242b2 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/销售订单和工单逾期消息推送
# Conflicts:
#	sf_message/__manifest__.py
#	sf_message/data/bussiness_node.xml
2024-09-27 09:11:56 +08:00
jinling.yang
7fef8f4c77 添加业务节点 2024-09-25 17:50:00 +08:00
jinling.yang
2e3a9a8b80 添加提醒时间 2024-09-25 11:18:37 +08:00
94 changed files with 6187 additions and 676 deletions

View File

@@ -3,8 +3,8 @@
'name': "jikimo_account_process",
'summary': """
Short (1 phrase/line) summary of the module's purpose, used as
subtitle on modules listing or apps.openerp.com""",
处理会计凭证生成重复名称报错问题
""",
'description': """
Long description of module's purpose

View File

@@ -1,41 +1,99 @@
.zoomed {
position: fixed !important;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(10);
.processing-capabilities-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 10px;
width: 100%;
}
.many2many_flex {
display: flex;
.grid-item {
display: flex;
align-items: center;
}
.many2many_flex>div {
margin-right: 15px;
display: flex;
flex-direction: column;
align-items: center;
.item-content {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
/*控制图片大小*/
.item-icon {
width: 50px;
height: 50px;
margin-bottom: 5px;
}
.many2many_flex>div>:nth-child(2) {
position: relative;
.item-label {
font-size: 12px;
word-break: break-word;
}
.close {
width: 20px;
height: 20px;
position: absolute;
top: -8.8px;
right: -8.8px;
color: #fff;
background-color: #000;
opacity: 0;
text-align: center;
line-height: 20px;
font-size: 18px;
@media (max-width: 1200px) {
.processing-capabilities-grid {
grid-template-columns: repeat(4, 1fr);
}
}
.img_close {
opacity: 1;
transform: scale(0.1);
cursor: pointer;
@media (max-width: 768px) {
.processing-capabilities-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 480px) {
.processing-capabilities-grid {
grid-template-columns: repeat(2, 1fr);
}
}
.image-preview-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.9);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
opacity: 0;
transition: opacity 0.3s ease;
}
.image-preview-container.show {
opacity: 1;
}
.image-preview {
max-width: 90%;
max-height: 90%;
object-fit: contain;
box-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
border-radius: 5px;
transform: scale(0.9);
transition: transform 0.3s ease;
}
.image-preview-container.show .image-preview {
transform: scale(1);
}
.image-preview-close {
position: absolute;
top: 20px;
right: 30px;
color: #fff;
font-size: 40px;
font-weight: bold;
transition: 0.3s;
cursor: pointer;
opacity: 0.7;
}
.image-preview-close:hover,
.image-preview-close:focus {
opacity: 1;
text-decoration: none;
cursor: pointer;
}

View File

@@ -4,35 +4,57 @@ import {Many2ManyCheckboxesField} from "@web/views/fields/many2many_checkboxes/m
import {registry} from "@web/core/registry";
export class MyCustomWidget extends Many2ManyCheckboxesField {
// 你可以重写或者添加一些方法和属性
// 例如你可以重写setup方法来添加一些事件监听器或者初始化一些变量
setup() {
super.setup(); // 调用父类的setup方法
// 你自己的代码
super.setup();
}
onImageClick(event) {
// 放大图片逻辑
// 获取图片元素
const img = event.target;
const close = img.nextSibling;
onImageClick(event, src) {
event.preventDefault();
event.stopPropagation();
// 实现放大图片逻辑
// 比如使用 CSS 放大
img.parentElement.classList.add('zoomed');
close.classList.add('img_close');
}
// 创建预览框
const previewContainer = document.createElement('div');
previewContainer.className = 'image-preview-container';
onCloseClick(event) {
const close = event.target;
const img = close.previousSibling;
img.parentElement.classList.remove('zoomed');
close.classList.remove('img_close');
const previewImg = document.createElement('img');
previewImg.src = src;
previewImg.className = 'image-preview';
// 设置放大的预览图片大小
previewImg.style.width = '600px';
previewImg.style.height = 'auto'; // 保持宽高比
const closeButton = document.createElement('span');
closeButton.innerHTML = '×';
closeButton.className = 'image-preview-close';
previewContainer.appendChild(previewImg);
previewContainer.appendChild(closeButton);
document.body.appendChild(previewContainer);
// 添加关闭预览的事件监听器
const closePreview = () => {
previewContainer.classList.remove('show');
setTimeout(() => {
document.body.removeChild(previewContainer);
}, 300);
};
closeButton.addEventListener('click', closePreview);
// 点击预览框外部也可以关闭
previewContainer.addEventListener('click', (e) => {
if (e.target === previewContainer) {
closePreview();
}
});
// 使用 setTimeout 来触发过渡效果
setTimeout(() => {
previewContainer.classList.add('show');
}, 10);
}
}
MyCustomWidget.template = "jikimo_frontend.MyCustomWidget";
// MyCustomWidget.supportedTypes = ['many2many'];
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);

View File

@@ -2,27 +2,22 @@
<templates xml:space="preserve">
<t t-name="jikimo_frontend.MyCustomWidget" owl="1">
<div aria-atomic="true" class="many2many_flex">
<div aria-atomic="true" class="many2many_flex processing-capabilities-grid">
<t t-foreach="items" t-as="item" t-key="item[0]">
<div>
<div class="grid-item">
<CheckBox
value="isSelected(item)"
disabled="props.readonly"
onChange="(ev) => this.onChange(item[0], ev)"
>
<t t-esc="item[1]"/>
<div class="item-content">
<img t-att-src="item[2]" class="item-icon" t-on-click="(ev) => this.onImageClick(ev, item[2])"/>
<span class="item-label"><t t-esc="item[1]"/></span>
</div>
</CheckBox>
<div t-on-dblclick="onImageClick">
<t>
<img t-att-src="item[2]" width="50" height="50"/>
<div class="close" t-on-click="onCloseClick">×</div>
</t>
</div>
</div>
</t>
</div>
</t>
</templates>
</templates>

View File

@@ -108,6 +108,10 @@ td.o_required_modifier {
}
.color_3 {
background-color: #808080;
}
.color_4 {
background-color: rgb(255, 150, 0);
}

View File

@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import models
from . import controllers

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': '机企猫 工单异常记录',
'version': '1.0',
'summary': '记录工单的异常日志',
'sequence': 1,
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['sf_manufacturing', 'sf_mrs_connect'],
'data': [
'views/mrp_workorder_views.xml',
'security/ir.model.access.csv',
],
'demo': [
],
'license': 'LGPL-3',
'installable': True,
'application': False,
'auto_install': False,
}

View File

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

View File

@@ -0,0 +1,89 @@
from odoo import http, fields
from odoo.http import request
import json
import logging
from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect
from odoo.addons.sf_manufacturing.controllers.controllers import Manufacturing_Connect
_logger = logging.getLogger(__name__)
class WorkorderExceptionConroller(http.Controller):
@http.route('/AutoDeviceApi/BillError', type='json', auth='public', methods=['GET', 'POST'], csrf=False,
cors="*")
def workder_exception(self, **kw):
"""
记录工单异常
:param kw:
:return:
"""
_logger.info('workder_exception:%s' % kw)
try:
res = {'Succeed': True, 'ErrorCode': 0, 'Error': ''}
datas = request.httprequest.data
ret = json.loads(datas)
if not ret.get('RfidCode') or not ret.get('coding'):
res = {'Succeed': False, 'ErrorCode': 400, 'Error': '参数错误'}
return json.JSONEncoder().encode(res)
# 通过RfidCode获取就绪的CNC工单
workorder = request.env['mrp.workorder'].sudo().search([
('rfid_code', '=', ret['RfidCode']),
('routing_type', '=', 'CNC加工'),
])
if not workorder:
res = {'Succeed': False, 'ErrorCode': 401, 'Error': '无效的工单'}
return json.JSONEncoder().encode(res)
# 创建工单异常记录,关联工单
request.env['jikimo.workorder.exception'].sudo().create({
'workorder_id': workorder.id,
'exception_code': ret.get('coding'),
'exception_content': ret.get('Error', '')
})
except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
_logger.info('workder_exception error:%s' % e)
return json.JSONEncoder().encode(res)
class SfMrsConnectController(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):
"""
更新工单异常记录【'YC001', 'YC004'
"""
res = super(SfMrsConnectController, self).get_cnc_processing_create(**kw)
# 如果有未完成的YC0001、YC0004异常记录则标记为完成
res = json.loads(res)
_logger.info('已进入工单异常:%s' % res)
if res.get('production_ids'):
try:
productions = request.env['mrp.production'].sudo().search([('id', 'in', res.get('production_ids'))])
if productions.workorder_ids:
productions.workorder_ids.handle_exception(['YC0001', 'YC0004'])
except Exception as e:
_logger.info('更新工单异常记录失败:%s' % e)
return json.JSONEncoder().encode(res)
class ManufactruingController(Manufacturing_Connect):
@http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def button_Work_START(self, **kw):
"""
更新工单异常记录【'YC0002', 'YC0003'
"""
res = super(ManufactruingController, self).button_Work_START(**kw)
res = json.loads(res)
_logger.info('已进入工单异常:%s' % res)
if res.get('workorder_id'):
try:
workorder = request.env['mrp.workorder'].sudo().browse(int(res.get('workorder_id')))
workorder.handle_exception(['YC0002', 'YC0003'])
except Exception as e:
_logger.info('更新工单异常记录失败:%s' % e)
return json.JSONEncoder().encode(res)

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import jikimo_workorder_exception
from . import mrp_workorder

View File

@@ -0,0 +1,14 @@
from odoo import models, fields
class JikimoWorkorderException(models.Model):
_name = 'jikimo.workorder.exception'
_description = '工单异常记录'
_order = 'id desc'
workorder_id = fields.Many2one('mrp.workorder', string='工单')
exception_code = fields.Char('异常编码')
exception_content = fields.Char('反馈的异常/问题信息')
completion_time = fields.Datetime('处理完成时间')
state = fields.Selection([('pending', '进行中'), ('done', '已处理')], string='状态', default='pending')

View File

@@ -0,0 +1,40 @@
from odoo import models, fields
import logging
_logger = logging.getLogger(__name__)
class MrpWorkorder(models.Model):
_inherit = 'mrp.workorder'
exception_ids = fields.One2many('jikimo.workorder.exception', 'workorder_id', string='工单异常记录')
def write(self, values):
if values.get('test_results') and self.exception_ids:
pending_exception = self.exception_ids.filtered(
lambda exc: exc.state == 'pending' and exc.exception_code == 'YC0005'
)
if pending_exception:
pending_exception.write({
'completion_time': fields.Datetime.now(),
'state': 'done'
})
return super(MrpWorkorder, self).write(values)
def handle_exception(self, exception_codes):
"""
处理异常
:param exception_codes: 需要处理的异常编码列表
"""
if not isinstance(exception_codes, list):
exception_codes = [exception_codes]
if self.exception_ids:
_logger.info('workorder.exception_ids:%s' % self.exception_ids)
pending_exception = self.exception_ids.filtered(
lambda exc: exc.state == 'pending' and exc.exception_code in exception_codes
)
_logger.info('pending_exception:%s' % pending_exception)
if pending_exception:
pending_exception.write({
'completion_time': fields.Datetime.now(),
'state': 'done'
})

View File

@@ -0,0 +1,2 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_jikimo_workorder_exception","access.jikimo.workorder.exception","model_jikimo_workorder_exception","mrp.group_mrp_user",1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_jikimo_workorder_exception access.jikimo.workorder.exception model_jikimo_workorder_exception mrp.group_mrp_user 1 1 1 0

View File

@@ -0,0 +1,2 @@
from . import common
from . import test_jikimo_workorder_exception

View File

@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, Command
from odoo.tests.common import TransactionCase, HttpCase, tagged, Form
import json
import time
import base64
from lxml import etree
@tagged('post_install', '-at_install')
class TestJikimoWorkorderExceptionCommon(TransactionCase):
def setUp(self):
super(TestJikimoWorkorderExceptionCommon, self).setUp()
# 获取名字为“1#自动生产线”的制造中心
workcenter = self.env['mrp.workcenter'].search([('name', '=', '1#自动生产线')], limit=1)
# 创建一个产品
product_product = self.env['product.product'].create({
'name': '测试产品',
'type': 'product',
})
uom_unit = self.env.ref('uom.product_uom_unit')
# 创建一个bom
self.bom = self.env['mrp.bom'].create({
'product_id': product_product.id,
'product_tmpl_id': product_product.product_tmpl_id.id,
'product_uom_id': uom_unit.id,
'product_qty': 1.0,
'type': 'normal',
})
# 创建一个制造订单
self.production = self.env['mrp.production'].create({
'name': 'Test Production',
'product_id': product_product.id,
'bom_id': self.bom.id,
'company_id': self.env.ref('base.main_company').id,
})
# 创建一个测试工单
self.workorder = self.env['mrp.workorder'].create({
'name': 'Test order',
'workcenter_id': workcenter.id,
'product_uom_id': self.bom.product_uom_id.id,
'production_id': self.production.id,
'duration_expected': 1.0,
'rfid_code': 'test-123456',
'routing_type': 'CNC加工'
})

View File

@@ -0,0 +1,53 @@
import json
from datetime import datetime
from odoo.addons.jikimo_workorder_exception.tests.common import TestJikimoWorkorderExceptionCommon
class TestJikimoWorkorderException(TestJikimoWorkorderExceptionCommon):
def test_create_exception_record(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0001',
'exception_content': '无CNC编程'
})
self.assertTrue(exception_record)
self.assertEqual(exception_record.exception_content, '无CNC编程')
self.assertEqual(exception_record.workorder_id.id, self.workorder.id)
self.assertEqual(exception_record.exception_code, 'YC0001')
def test_handle_exception(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0001',
'exception_content': '无CNC编程'
})
self.workorder.handle_exception('YC0001')
self.assertEqual(exception_record.state, 'done')
# 判断完成时间是否为当前分钟
self.assertEqual(exception_record.completion_time.minute, datetime.now().minute)
def test_handle_exception_with_invalid_code(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0001',
'exception_content': '无CNC编程'
})
self.workorder.handle_exception(['YC0002', 'YC0004'])
self.assertEqual(exception_record.state, 'pending')
self.assertEqual(exception_record.completion_time, False)
def test_handle_exception_with_test_results(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0005',
'exception_content': '工单加工失败'
})
self.workorder.write({
'test_results': '返工',
'reason': 'cutter',
'detailed_reason': '刀坏了',
})
self.assertEqual(exception_record.state, 'done')
self.assertEqual(exception_record.completion_time.minute, datetime.now().minute)

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<record id="jikimo_workorder_exception_form_view_inherit" model="ir.ui.view">
<field name="name">mrp.workorder.form</field>
<field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
<field name="arch" type="xml">
<xpath expr="//notebook/page[last()]" position="after">
<page string="异常记录" name="workorder_exception" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}">
<field name="exception_ids" nolabel="1" readonly="1">
<tree create="false" delete="false" edit="false">
<field name="exception_content" string="反馈的异常/问题信息"/>
<field name="create_date" string="时间"/>
<field name="completion_time"/>
</tree>
</field>
</page>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import models

View File

@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': '机企猫 工单异常消息通知',
'version': '1.0',
'summary': '当产生工单异常时,发送消息通知',
'sequence': 1,
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['jikimo_workorder_exception', 'jikimo_message_notify'],
'data': [
'data/bussiness_node.xml',
'data/template_data.xml',
# 'security/ir.model.access.csv',
],
'demo': [
],
'license': 'LGPL-3',
'installable': True,
'application': False,
'auto_install': False,
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" ?>
<odoo>
<data noupdate="1">
<record id="bussiness_no_functional_tool" model="jikimo.message.bussiness.node">
<field name="name">无功能刀具</field>
<field name="model">jikimo.workorder.exception</field>
</record>
<record id="bussiness_no_position_data" model="jikimo.message.bussiness.node">
<field name="name">无定位数据</field>
<field name="model">jikimo.workorder.exception</field>
</record>
<record id="bussiness_processing_failure" model="jikimo.message.bussiness.node">
<field name="name">加工失败</field>
<field name="model">jikimo.workorder.exception</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" ?>
<odoo>
<data noupdate="1">
<record id="template_no_function_tool" model="jikimo.message.template">
<field name="name">生产线无功能刀具提醒</field>
<field name="model_id" ref="jikimo_workorder_exception_notify.model_jikimo_workorder_exception"/>
<field name="model">jikimo.workorder.exception</field>
<field name="bussiness_node_id" ref="bussiness_no_functional_tool"/>
<field name="msgtype">markdown</field>
<field name="urgency">urgent</field>
<field name="content">### 生产线无功能刀具提醒
单号:工单[{{workorder_id.production_id.name}}]({{url}})
原因:生产线无加工程序要用的功能刀具</field>
</record>
<record id="template_no_position_data" model="jikimo.message.template">
<field name="name">工单无定位数据提醒</field>
<field name="model_id" ref="jikimo_workorder_exception_notify.model_jikimo_workorder_exception"/>
<field name="model">jikimo.workorder.exception</field>
<field name="bussiness_node_id" ref="bussiness_no_position_data"/>
<field name="msgtype">markdown</field>
<field name="urgency">urgent</field>
<field name="content">### 工单无定位数据提醒
单号:工单[{{workorder_id.production_id.name}}]({{url}})
原因:无装夹定位测量数据</field>
</record>
<record id="template_processing_failure" model="jikimo.message.template">
<field name="name">工单加工失败提醒</field>
<field name="model_id" ref="jikimo_workorder_exception_notify.model_jikimo_workorder_exception"/>
<field name="model">jikimo.workorder.exception</field>
<field name="bussiness_node_id" ref="bussiness_processing_failure"/>
<field name="msgtype">markdown</field>
<field name="urgency">urgent</field>
<field name="content">### 工单加工失败提醒
单号:工单[{{workorder_id.production_id.name}}]({{url}})
原因:加工失败,工件下产线处理</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import jikimo_message_template
from . import jikimo_workorder_exception

View File

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

View File

@@ -0,0 +1,61 @@
from odoo import models, api
from odoo.addons.sf_base.commons.common import Common
import requests, logging
_logger = logging.getLogger(__name__)
class JikimoWorkorderException(models.Model):
_name = 'jikimo.workorder.exception'
_inherit = ['jikimo.workorder.exception', 'jikimo.message.dispatch']
@api.model_create_multi
def create(self, vals_list):
res = super(JikimoWorkorderException, self).create(vals_list)
# 根据异常编码发送消息提醒
try:
for rec in res:
if rec.exception_code == 'YC0001':
# 无CNC程序调用cloud接口
data = {'name': rec.workorder_id.production_id.programming_no, 'exception_code': 'YC0001'}
configsettings = self.env['res.config.settings'].sudo().get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/message/workorder_exception'
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('无CNC程序异常消息推送接口:%s' % ret)
elif rec.exception_code == 'YC0002':
# 无功能刀具
rec.add_queue('无功能刀具')
elif rec.exception_code == 'YC0003':
# 无定位数据
rec.add_queue('无定位数据')
elif rec.exception_code == 'YC0004':
# 无FTP文件调用cloud接口
data = {'name': rec.workorder_id.production_id.programming_no, 'exception_code': 'YC0004'}
configsettings = self.env['res.config.settings'].sudo().get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/message/workorder_exception'
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('无FTP文件异常消息推送接口:%s' % ret)
elif rec.exception_code == 'YC0005':
# 加工失败
rec.add_queue('加工失败')
except Exception as e:
_logger.error('异常编码发送消息提醒失败:%s' % e)
return res
def _get_message(self, message_queue_ids):
contents = super(JikimoWorkorderException, self)._get_message(message_queue_ids)
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('mrp.mrp_production_action').id
for index, content in enumerate(contents):
exception_id = self.env['jikimo.workorder.exception'].browse(message_queue_ids[index].res_id)
url = url + '/web#id=%s&view_type=form&action=%s' % (exception_id.workorder_id.production_id.id, action_id)
contents[index] = content.replace('{{url}}', url)
return contents

View File

@@ -0,0 +1,2 @@
from . import common
from . import test_jikimo_workorder_exception_notify

View File

@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, Command
from odoo.tests.common import TransactionCase, HttpCase, tagged, Form
import json
import time
import base64
from lxml import etree
@tagged('post_install', '-at_install')
class TestJikimoWorkorderExceptionNotifyCommonNotify(TransactionCase):
def setUp(self):
super(TestJikimoWorkorderExceptionNotifyCommonNotify, self).setUp()
# 获取最后一个工单
self.workorder = self.env['mrp.workorder'].search([], order='id desc', limit=1)

View File

@@ -0,0 +1,113 @@
import json
from datetime import datetime
from odoo.addons.jikimo_workorder_exception_notify.tests.common import TestJikimoWorkorderExceptionNotifyCommonNotify
class TestJikimoWorkorderExceptionNotify(TestJikimoWorkorderExceptionNotifyCommonNotify):
def test_create_message_template(self):
self.assertTrue(self.env['jikimo.message.template'].search([
('name', '=', '生产线无功能刀具提醒'),
('model', '=', 'jikimo.workorder.exception')
]))
self.assertTrue(self.env['jikimo.message.template'].search([
('name', '=', '工单无定位数据提醒'),
('model', '=', 'jikimo.workorder.exception')
]))
self.assertTrue(self.env['jikimo.message.template'].search([
('name', '=', '工单加工失败提醒'),
('model', '=', 'jikimo.workorder.exception')
]))
def test_create_message_queue_yc0001(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0001',
'exception_content': '无CNC程序'
})
message_record = self.env['jikimo.message.queue'].search([
('res_id', '=', exception_record.id),
('model', '=', 'jikimo.workorder.exception'),
('message_status', '=', 'pending')
])
self.assertFalse(message_record)
def test_create_message_queue_yc0002(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0002',
'exception_content': '无功能刀具'
})
bussiness_node = self.env['jikimo.message.bussiness.node'].search([
('name', '=', '无功能刀具'),
('model', '=', 'jikimo.workorder.exception')
])
message_template = self.env['jikimo.message.template'].search([
('bussiness_node_id', '=', bussiness_node.id),
('model', '=', 'jikimo.workorder.exception')
])
message_record = self.env['jikimo.message.queue'].search([
('res_id', '=', exception_record.id),
('model', '=', 'jikimo.workorder.exception'),
('message_status', '=', 'pending'),
('message_template_id', '=', message_template.id)
])
self.assertTrue(message_record)
def test_create_message_queue_yc0003(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0003',
'exception_content': '无定位数据'
})
bussiness_node = self.env['jikimo.message.bussiness.node'].search([
('name', '=', '无定位数据'),
('model', '=', 'jikimo.workorder.exception')
])
message_template = self.env['jikimo.message.template'].search([
('bussiness_node_id', '=', bussiness_node.id),
('model', '=', 'jikimo.workorder.exception')
])
message_record = self.env['jikimo.message.queue'].search([
('res_id', '=', exception_record.id),
('model', '=', 'jikimo.workorder.exception'),
('message_status', '=', 'pending'),
('message_template_id', '=', message_template.id)
])
self.assertTrue(message_record)
def test_create_message_queue_yc0004(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0004',
'exception_content': '无CNC程序'
})
message_record = self.env['jikimo.message.queue'].search([
('res_id', '=', exception_record.id),
('model', '=', 'jikimo.workorder.exception'),
('message_status', '=', 'pending')
])
self.assertFalse(message_record)
def test_get_message(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0002',
'exception_content': '无功能刀具'
})
message_queue_ids = self.env['jikimo.message.queue'].search([
('res_id', '=', exception_record.id),
('model', '=', 'jikimo.workorder.exception'),
('message_status', '=', 'pending')
])
message = self.env['jikimo.workorder.exception']._get_message(message_queue_ids)
self.assertTrue(message)

View File

@@ -1033,7 +1033,7 @@
name="Overview"
action="quality_alert_team_action"
parent="menu_quality_root"
sequence="5"/>
sequence="5" active="False"/>
<menuitem
id="menu_quality_control"

View File

@@ -38,3 +38,17 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
logging.info('get_maintenance_tool_groups_Info error:%s' % e)
return json.JSONEncoder().encode(res)
class MultiInheritController():
_sub_classes = []
def __init_subclass__(cls):
"""
多继承解决多个字类时方法调用super的问题
"""
super().__init_subclass__()
if len(cls._sub_classes) > 0 and cls not in cls._sub_classes:
cls.__bases__ = (cls._sub_classes[-1],)
if cls not in cls._sub_classes:
cls._sub_classes.append(cls)

View File

@@ -109,7 +109,7 @@
<field name="name">form.sf.machine_tool.type</field>
<field name="model">sf.machine_tool.type</field>
<field name="arch" type="xml">
<form string="机床型号" delete="0">
<form string="机床型号" delete="0">
<sheet>
<div class="oe_title">
<h1>
@@ -129,31 +129,28 @@
<field name="machine_tool_picture" widget="image" nolabel="1"/>
</group>
</group>
<group string="加工能力">
<group string="加工能力">
<div>
<field name='jg_image_id' widget="custom_many2many_checkboxes">
<field name='jg_image_id' widget="custom_many2many_checkboxes">
<tree>
<field name="name"/>
<field name="image" widget="image"/>
<tree>
<field name="name"/>
<field name="image" widget="image"
options="{'size': [100, 100], 'click enlarge': True}"/>
</tree>
</field>
</tree>
</field>
</div>
</group>
<group string="冷却方式">
<div>
<field name='lq_image_id' widget="custom_many2many_checkboxes">
<field name='lq_image_id' widget="custom_many2many_checkboxes">
<tree>
<field name="name"/>
<field name="image" widget="image"
options="{'size': [100, 100], 'click enlarge': True}"/>
<tree>
<field name="name"/>
<field name="image" widget="image"/>
</tree>
</field>
</tree>
</field>
</div>
</group>
@@ -178,7 +175,7 @@
<field name="workbench_H" class="o_address_zip" required="1"
options="{'format': false}"/>
</div>
<field name="workpiece_load"/>
<field name="workpiece_load"/>
<label for="machine_tool_L" string="机床尺寸(mm)"/>
<div class="test_model">
<label for="machine_tool_L" string="长"/>
@@ -192,7 +189,7 @@
<field name="machine_tool_H" class="o_address_zip"
options="{'format': false}"/>
</div>
<label for="T_trough_num" string="T型槽尺寸:"/>
<label for="T_trough_num" string="T型槽尺寸:"/>
<div class="test_model">
<label for="T_trough_num" string="槽数"/>
<field name="T_trough_num" class="o_address_zip"
@@ -205,20 +202,20 @@
<field name="T_trough_distance" class="o_address_zip"
options="{'format': false}"/>
</div>
<!-- <field name="feed_speed" required="1"/>-->
<!-- <label for="precision_min" string="X轴定位精度(mm)"/>-->
<!-- <div class="test_model">-->
<!-- <label for="precision_min" string="最小(min)"/>-->
<!-- <field name="precision_min" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="precision_max" string="最大(max)"/>-->
<!-- <field name="precision_max" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- </div>-->
<!-- <field name="feed_speed" required="1"/>-->
<!-- <label for="precision_min" string="X轴定位精度(mm)"/>-->
<!-- <div class="test_model">-->
<!-- <label for="precision_min" string="最小(min)"/>-->
<!-- <field name="precision_min" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="precision_max" string="最大(max)"/>-->
<!-- <field name="precision_max" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- </div>-->
<!-- <field name="lead_screw" required="1"/>-->
<!-- <field name="guide_rail" required="1"/>-->
<!-- <field name="lead_screw" required="1"/>-->
<!-- <field name="guide_rail" required="1"/>-->
<field name="number_of_axles" required="1" widget="radio"
options="{'horizontal': true}"/>
<label for="x_axis" string="加工行程(mm)"
@@ -258,7 +255,7 @@
</group>
<group string="主轴">
<field name="taper_type_id" required="1"/>
<label for="distance_min" string="主轴端面-工作台距离(mm)"/>
<label for="distance_min" string="主轴端面-工作台距离(mm)"/>
<div class="test_model">
<label for="distance_min" string="最小(min)"/>
<field name="distance_min" class="o_address_zip"
@@ -268,7 +265,7 @@
<field name="distance_max" class="o_address_zip"
options="{'format': false}"/>
</div>
<field name="rotate_speed" string="主轴最高转速(r/min)"
<field name="rotate_speed" string="主轴最高转速(r/min)"
options="{'format': false}"/>
<field name="spindle_center_distance"/>
<field name="spindle_continuous_power"/>
@@ -286,50 +283,50 @@
<page string="进给/精度参数">
<group>
<group string="进给参数">
<field name="X_axis_rapid_traverse_speed"/>
<field name="Y_axis_rapid_traverse_speed"/>
<field name="Z_axis_rapid_traverse_speed"/>
<field name="a_axis_rapid_traverse_speed"/>
<field name="b_axis_rapid_traverse_speed"/>
<field name="c_axis_rapid_traverse_speed"/>
<field name="straight_cutting_feed_rate"/>
<field name="rotary_cutting_feed_rate"/>
<field name="X_axis_rapid_traverse_speed"/>
<field name="Y_axis_rapid_traverse_speed"/>
<field name="Z_axis_rapid_traverse_speed"/>
<field name="a_axis_rapid_traverse_speed"/>
<field name="b_axis_rapid_traverse_speed"/>
<field name="c_axis_rapid_traverse_speed"/>
<field name="straight_cutting_feed_rate"/>
<field name="rotary_cutting_feed_rate"/>
</group>
<group string="精度参数">
<field name="X_precision"/>
<field name="X_precision_repeat"/>
<field name="Y_precision"/>
<field name="Y_precision_repeat"/>
<field name="Z_precision"/>
<field name="Z_precision_repeat"/>
<field name="a_precision"/>
<field name="a_precision_repeat"/>
<field name="b_precision"/>
<field name="b_precision_repeat"/>
<field name="c_precision"/>
<field name="c_precision_repeat"/>
<field name="X_precision"/>
<field name="X_precision_repeat"/>
<field name="Y_precision"/>
<field name="Y_precision_repeat"/>
<field name="Z_precision"/>
<field name="Z_precision_repeat"/>
<field name="a_precision"/>
<field name="a_precision_repeat"/>
<field name="b_precision"/>
<field name="b_precision_repeat"/>
<field name="c_precision"/>
<field name="c_precision_repeat"/>
</group>
</group>
</page>
<page string="刀库参数">
<group>
<page string="刀库参数">
<group>
<group string="刀具">
<!-- <field name="knife_type" required="1"/>-->
<!-- <field name="knife_type" required="1"/>-->
<field name="number_of_knife_library" required="1" options="{'format': false}"/>
<!-- <field name="tool_speed" required="1"/>-->
<!-- <field name="tool_speed" required="1"/>-->
<field name="tool_full_diameter_max"/>
<field name="tool_perimeter_diameter_max"/>
<field name="tool_long_max"/>
<!-- <label for="tool_diameter_min" string="刀具刀径(mm)"/>-->
<!-- <div class="test_model">-->
<!-- <label for="tool_diameter_min" string="最小(min)"/>-->
<!-- <field name="tool_diameter_min" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="tool_diameter_max" string="最大(max)"/>-->
<!-- <field name="tool_diameter_max" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- </div>-->
<!-- <label for="tool_diameter_min" string="刀具刀径(mm)"/>-->
<!-- <div class="test_model">-->
<!-- <label for="tool_diameter_min" string="最小(min)"/>-->
<!-- <field name="tool_diameter_min" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="tool_diameter_max" string="最大(max)"/>-->
<!-- <field name="tool_diameter_max" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- </div>-->
<field name="tool_quality_max"/>
<field name="T_tool_time"/>
<field name="C_tool_time"/>

View File

@@ -10,7 +10,7 @@
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['sf_base', 'web_widget_model_viewer', 'mrp_subcontracting', 'purchase_stock', 'uom', ],
'depends': ['sf_base', 'mrp_subcontracting', 'purchase_stock', 'uom'],
'data': [
'data/product_data.xml',
'data/uom_data.xml',

View File

@@ -16,6 +16,8 @@
<field name='is_bfm' invisible="1"/>
<field name='categ_type' invisible="1"/>
<field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<field name='machining_drawings' attrs="{'invisible': [('categ_type', '!=', '成品')]}" widget="adaptive_viewer"/>
<field name='quality_standard' attrs="{'invisible': [('categ_type', '!=', '成品')]}" widget="adaptive_viewer"/>
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
<field name="upload_model_file"
widget="many2many_binary"

View File

@@ -12,7 +12,7 @@
'category': 'sf',
'author': 'jikimo',
'website': 'https://sf.cs.jikimo.com',
'depends': ['web', 'mail', 'sf_base', 'sf_manufacturing', 'barcodes', ],
'depends': ['web', 'sf_manufacturing', 'barcodes'],
'data': [
# 定义权限组放在最上面
# 权限组

View File

@@ -15,7 +15,7 @@ db_config = {
"user": "postgres",
"password": "postgres",
"port": "5432",
"host": "172.16.10.113"
"host": "172.16.10.131"
}
@@ -24,6 +24,8 @@ def convert_to_seconds(time_str):
if time_str is None:
return 0
if time_str == 0:
return 0
pattern = r"(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?"
@@ -400,20 +402,45 @@ class Sf_Dashboard_Connect(http.Controller):
try:
plan_obj = request.env['sf.production.plan'].sudo()
production_obj = request.env['mrp.production'].sudo()
work_order_obj = request.env['mrp.workorder'].sudo()
line_list = ast.literal_eval(kw['line_list'])
# print('line_list: %s' % line_list)
for line in line_list:
# 工单计划量
plan_data_total_counts = production_obj.search_count(
[('production_line_id.name', '=', line), ('state', 'not in', ['cancel']),
('active', '=', True)])
# 工单完成量
plan_data_finish_counts = plan_obj.search_count(
[('production_line_id.name', '=', line), ('state', 'in', ['finished'])])
# # 工单计划量
# plan_data_plan_counts = plan_obj.search_count(
# [('production_line_id.name', '=', line), ('state', 'not in', ['finished'])])
# plan_data_total_counts = production_obj.search_count(
# [('production_line_id.name', '=', line), ('state', 'not in', ['cancel']),
# ('active', '=', True)])
# 工单计划量切换为CNC工单
plan_data_total_counts = work_order_obj.search_count(
[('production_id.production_line_id.name', '=', line),
('state', 'in', ['ready', 'progress', 'done']), ('routing_type', '=', 'CNC加工')])
# # 工单完成量
# plan_data_finish_counts = plan_obj.search_count(
# [('production_line_id.name', '=', line), ('state', 'in', ['finished'])])
# 工单完成量切换为CNC工单
plan_data_finish_counts = work_order_obj.search_count(
[('production_id.production_line_id.name', '=', line),
('state', 'in', ['done']), ('routing_type', '=', 'CNC加工')])
# 超期完成量
# 搜索所有已经完成的工单
plan_data_overtime = work_order_obj.search([
('production_id.production_line_id.name', '=', line),
('state', 'in', ['done']),
('routing_type', '=', 'CNC加工')
])
# 使用 filtered 进行字段比较
plan_data_overtime_counts = plan_data_overtime.filtered(
lambda order: order.date_finished > order.date_planned_finished
)
# 获取数量
plan_data_overtime_counts = len(plan_data_overtime_counts)
# 查找符合条件的生产计划记录
plan_data = plan_obj.search([
@@ -515,7 +542,10 @@ class Sf_Dashboard_Connect(http.Controller):
'on_time_rate': on_time_rate,
# 'detection_data': detection_data,
'detection_data': plan_data_finish_counts,
'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts
'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts,
'plan_data_overtime_counts': plan_data_overtime_counts,
'overtime_rate': plan_data_overtime_counts / plan_data_finish_counts
if plan_data_finish_counts > 0 else 0,
}
res['data'][line] = data
@@ -1242,6 +1272,7 @@ class Sf_Dashboard_Connect(http.Controller):
time_threshold = datetime.now() - timedelta(days=1)
alarm_last_24_time = 0.0
alarm_all_time = 0.0
def fetch_result_as_dict(cursor):
"""辅助函数:将查询结果转为字典"""
@@ -1302,17 +1333,49 @@ class Sf_Dashboard_Connect(http.Controller):
alarm_last_24_time += float(result[0])
else:
alarm_last_24_time += 0.0
alarm_all_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;
""", (item,))
results = cur.fetchall()
for result in results:
alarm_all_nums.append(result[1])
if result[0]:
if float(result[0]) >= 1000:
continue
alarm_all_time += float(result[0])
else:
alarm_all_time += 0.0
# with conn.cursor() as cur:
# cur.execute("""
# SELECT * FROM device_data
# WHERE device_name = %s
# AND total_count IS NOT NULL
# ORDER BY time ASC
# LIMIT 1;
# """, (item, ))
# total_count = fetch_result_as_dict(cur)
# 返回数据
res['data'][item] = {
'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0,
'cut_time': last_all_time['process_time'] if last_all_time['process_time'] is not None else 0,
'cut_24_time': last_24_time['process_time'] if last_24_time['process_time'] is not None else 0,
'cut_24_time': last_24_time['process_time'] if last_24_time 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,
'power_on_24_time': last_24_time['power_on_time'] if last_24_time 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,
'alarm_all_time': alarm_all_time,
'alarm_all_nums': len(list(set(alarm_all_nums)))
# 'total_count': total_count['total_count'] if total_count else 0
}
conn.close()

View File

@@ -217,7 +217,7 @@ class Machine_ftp(models.Model):
status = fields.Boolean('机床在线状态', readonly=True)
# run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], string='机床运行状态',
# readonly=True, default='0')
run_status = fields.Char('机床运行状态', readonly=True)
# run_status = fields.Char('机床运行状态', readonly=True)
run_time = fields.Char('机床累计运行时长', readonly=True)
# 机床系统日期
system_date = fields.Char('机床系统日期', readonly=True)

View File

@@ -11,6 +11,7 @@
'security/group_security.xml',
'security/ir.model.access.csv',
'security/ir_rule_data.xml',
'data/scheduled_actions.xml',
'views/maintenance_logs_views.xml',
'views/maintenance_equipment_oee_views.xml',
'views/maintenance_views.xml',

View File

@@ -0,0 +1,14 @@
<odoo>
<data noupdate="1">
<record id="ir_cron_oee_get_running_datas" model="ir.cron">
<field name="name">设备运行数据</field>
<field name="model_id" ref="model_maintenance_equipment_oee"/>
<field name="state">code</field>
<field name="code">model.get_running_datas()</field>
<field name="interval_number">15</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="active" eval="True"/>
</record>
</data>
</odoo>

3583
sf_maintenance/i18n/zh_CN.po Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,8 @@ class SfMaintenanceEquipment(models.Model):
crea_url = "/api/machine_tool/create"
run_status = fields.Char('机床运行状态', readonly=True)
# AGV运行日志
agv_logs = fields.One2many('maintenance.equipment.agv.log', 'equipment_id', string='AGV运行日志')
# 1212修改后的字段

View File

@@ -12,6 +12,8 @@ def convert_to_seconds(time_str):
if time_str is None:
return 0
if time_str == 0:
return 0
pattern = r"(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?"
@@ -86,6 +88,69 @@ class SfMaintenanceEquipmentOEE(models.Model):
begin_time = fields.Date('开始时间')
end_time = fields.Date('结束时间')
def get_running_datas(self):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
url_time = base_url + '/api/RunningTimeDetail'
cnc_list_obj = self.env['maintenance.equipment'].sudo().search(
[('function_type', '!=', False), ('active', '=', True)])
machine_list = list(map(lambda x: x.code, cnc_list_obj))
# print('machine_list: %s' % machine_list)
data_time = {
"machine_list": str(machine_list)
}
# 发送POST请求
response_time = requests.post(url_time, json={}, data=data_time)
# print(response_time.json())
if response_time.status_code == 200:
result_time = response_time.json()
if result_time['status'] == 1:
real_dict = result_time['data']
for key in real_dict:
# print(key)
equipment_obj = self.env['maintenance.equipment.oee'].sudo().search([('equipment_code', '=', key)])
if real_dict[key]['power_on_time'] == 0:
equipment_obj.online_time = 0
equipment_obj.idle_time = 0
equipment_obj.idle_rate = 0
equipment_obj.work_rate = 0
equipment_obj.fault_time = 0
equipment_obj.fault_rate = 0
equipment_obj.fault_nums = 0
equipment_obj.idle_nums = 0
equipment_obj.work_time = 0
else:
equipment_obj.online_time = round(convert_to_seconds(real_dict[key]['power_on_time']) / 3600, 2)
equipment_obj.work_time = round(convert_to_seconds(real_dict[key]['cut_time']) / 3600, 2)
equipment_obj.fault_nums = real_dict[key]['alarm_all_nums']
equipment_obj.idle_nums = real_dict[key]['idle_count']
equipment_obj.fault_time = round((float(real_dict[key]['alarm_all_time']) if real_dict[key][
'alarm_all_time'] else 0) / 3600, 2)
equipment_obj.idle_time = float(equipment_obj.online_time) - float(
equipment_obj.work_time) if equipment_obj.online_time and equipment_obj.work_time else 0
equipment_obj.idle_rate = round(
float(equipment_obj.idle_time) / (
float(equipment_obj.online_time) if equipment_obj.online_time else 1) * 100, 2)
equipment_obj.work_rate = round(
float(equipment_obj.work_time) / (
float(equipment_obj.online_time) if equipment_obj.online_time else 1) * 100, 2)
equipment_obj.fault_rate = round(
float(equipment_obj.fault_time) / (
float(equipment_obj.online_time) if equipment_obj.online_time else 1) * 100, 2)
# 获取当前时间的时间戳
current_timestamp = datetime.datetime.now().timestamp()
# 机床上线时间段
first_online_duration = current_timestamp - int(equipment_obj.equipment_id.first_online_time.timestamp())
if equipment_obj.online_time:
equipment_obj.offline_time = round((first_online_duration - float(equipment_obj.online_time)) / 3600, 2)
else:
equipment_obj.offline_time = False
# equipment_obj.offline_time = equipment_obj.equipment_id.first_online_time - (
# float(equipment_obj.online_time) if equipment_obj.online_time else 0)
# 获取日志详情
def get_day_logs(self):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
@@ -122,24 +187,36 @@ class SfMaintenanceEquipmentOEE(models.Model):
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)
if real_dict['power_on_24_time'] == 0:
self.online_time = 0
self.idle_time = 0
self.idle_rate = 0
self.work_rate = 0
self.fault_time = 0
self.fault_rate = 0
self.fault_nums = 0
self.idle_nums = 0
self.work_time = 0
else:
self.online_time = round((convert_to_seconds(real_dict['power_on_time']) - convert_to_seconds(
real_dict['power_on_24_time'])) / 3600, 2)
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']
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()

View File

@@ -79,12 +79,12 @@
</group>
</group>
<notebook>
<page string="24H日志详情">
<group>
<button name="get_day_logs" type="object" string="查看24H日志" t-attf-style="white-space:nowrap;"/>
</group>
<field name="day_logs_detail" readonly="1" widget="html"/>
<!-- <notebook> -->
<!-- <page string="24H日志详情"> -->
<!-- <group> -->
<!-- <button name="get_day_logs" type="object" string="查看24H日志" t-attf-style="white-space:nowrap;"/> -->
<!-- </group> -->
<!-- <field name="day_logs_detail" readonly="1" widget="html"/> -->
<!-- <field name="page_num"/> -->
<!-- <group> -->
<!-- <group> -->
@@ -109,7 +109,7 @@
<!-- </div> -->
<!-- </div> -->
<!-- </group> -->
</page>
<!-- </page> -->
<!-- <page string="历史日志详情"> -->
<!-- <group> -->
<!-- <group> -->
@@ -132,7 +132,7 @@
<!-- </group> -->
<!-- <field name="history_logs_detail"/> -->
<!-- </page> -->
</notebook>
<!-- </notebook> -->
</sheet>
</form>
</field>

View File

@@ -1142,14 +1142,16 @@
</div>
<div class="show_state" t-attf-class="oe_kanban_global_click o_kanban_record_has_image_fill o_hr_kanban_record oe_kanban_card oe_kanban_global_click
">
<div t-attf-class="#{record.state.raw_value == '正常' ? 'color_1' : ''}"></div>
<div t-attf-class="#{record.state.raw_value == '故障' ? 'color_2' : ''}"></div>
<div t-attf-class="#{record.state.raw_value == '不可用' ? 'color_3' : ''}"></div>
<div t-attf-class="#{record.run_status.raw_value == '运行中' ? 'color_1' : ''}"></div>
<div t-attf-class="#{record.run_status.raw_value == '待机' ? 'color_4' : ''}"></div>
<div t-attf-class="#{record.run_status.raw_value == '故障' ? 'color_2' : ''}"></div>
<div t-attf-class="#{record.run_status.raw_value == '离线' ? 'color_3' : ''}"></div>
<p class="o_kanban_record_bottom state_zc"
t-attf-class="#{record.state.raw_value == '正常' ? 'font_color_1' : ''}
#{record.state.raw_value == '故障' ? 'font_color_2' : ''}
#{record.state.raw_value == '不可用' ? 'font_color_3' : ''}">
<field name="state"/>
t-attf-class="#{record.run_status.raw_value == '运行中' ? 'font_color_1' : ''}
#{record.run_status.raw_value == '待机' ? 'font_color_4' : ''}
#{record.run_status.raw_value == '故障' ? 'font_color_2' : ''}
#{record.run_status.raw_value == '离线' ? 'font_color_3' : ''}">
<field name="run_status"/>
</p>
</div>
</div>

View File

@@ -189,6 +189,7 @@ class Manufacturing_Connect(http.Controller):
request.env['sf.production.plan'].sudo().search([('production_id', '=', production_id)]).write(
{'actual_start_time': workorder.date_start,
'state': 'processing'})
res.update({'workorder_id': workorder.id})
except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
@@ -595,14 +596,6 @@ class Manufacturing_Connect(http.Controller):
if panel_workorder:
panel_workorder.write({'production_line_state': '已下产线'})
workorder.write({'state': 'to be detected'})
# workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
# [
# ('rfid_code', '=', rfid_code), ('type', '=', '下产线'),
# ('production_id', '=', order.production_id.id),
# ('workorder_id', '=', order.id),
# ('workorder_state', '=', 'done')])
# if workpiece_delivery:
# delivery_Arr.append(workpiece_delivery.id)
else:
res = {'Succeed': False, 'ErrorCode': 204,
'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
@@ -695,4 +688,4 @@ class Manufacturing_Connect(http.Controller):
except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': str(e)}
logging.info('AGVDownProduct error:%s' % e)
return json.JSONEncoder().encode(res)
return json.JSONEncoder().encode(res)

View File

@@ -18,7 +18,7 @@ class MrpProduction(models.Model):
_inherit = 'mrp.production'
_description = "制造订单"
_order = 'create_date desc'
deadline_of_delivery = fields.Date('订单交期', tracking=True, compute='_compute_deadline_of_delivery')
# tray_ids = fields.One2many('sf.tray', 'production_id', string="托盘")
maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests")
request_ids = fields.One2many('maintenance.request', 'production_id')
@@ -34,6 +34,16 @@ class MrpProduction(models.Model):
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True)
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id')
def _compute_deadline_of_delivery(self):
for production in self:
sale_order_ids = production.procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id.ids
if not sale_order_ids or len(sale_order_ids) < 1:
continue
sale_id = self.env['sale.order'].sudo().browse(sale_order_ids[0])
if sale_id:
production.deadline_of_delivery = sale_id.deadline_of_delivery
@api.depends('workorder_ids.tool_state_remark')
def _compute_tool_state_remark(self):
for item in self:
@@ -118,10 +128,12 @@ class MrpProduction(models.Model):
], string='工序状态', default='待装夹')
# 零件图号
part_number = fields.Char('零件图号')
part_number = fields.Char('零件图号', readonly=True)
# 上传零件图纸
part_drawing = fields.Binary('零件图纸')
part_drawing = fields.Binary('零件图纸', readonly=True)
quality_standard = fields.Binary('质检标准', readonly=True)
@api.depends('product_id.manual_quotation')
def _compute_manual_quotation(self):
@@ -296,8 +308,13 @@ class MrpProduction(models.Model):
# 编程单更新
def update_programming_state(self):
try:
manufacturing_type = 'rework'
if self.is_scrap:
manufacturing_type = 'scrap'
elif self.tool_state == '2':
manufacturing_type = 'invalid_tool_rework'
res = {'programming_no': self.programming_no,
'manufacturing_type': 'rework' if self.is_scrap is False else 'scrap'}
'manufacturing_type': manufacturing_type}
logging.info('res=%s:' % res)
configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
@@ -943,6 +960,8 @@ class MrpProduction(models.Model):
if production.programming_no in program_to_production_names:
productions_not_delivered = self.env['mrp.production'].search(
[('programming_no', '=', production.programming_no), ('programming_state', '=', '已编程未下发')])
productions = self.env['mrp.production'].search(
[('programming_no', '=', production.programming_no), ('state', 'not in', ('cancel', 'done'))])
rework_workorder = production.workorder_ids.filtered(lambda m: m.state == 'rework')
if rework_workorder:
for rework_item in rework_workorder:
@@ -955,6 +974,13 @@ class MrpProduction(models.Model):
productions_not_delivered.write(
{'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
# 对制造订单所以面的cnc工单的程序用刀进行校验
try:
logging.info(f'已更新制造订单:{productions_not_delivered}')
productions.production_cnc_tool_checkout()
except Exception as e:
logging.info(f'对cnc工单的程序用刀进行校验报错{e}')
# 从cloud获取重新编程过的最新程序
def get_new_program(self, processing_panel):
try:

View File

@@ -40,7 +40,7 @@ class ResMrpRoutingWorkcenter(models.Model):
def get_company_id(self):
self.company_id = self.env.user.company_id.id
company_id = fields.Many2one('res.company', compute="get_company_id", related=False)
company_id = fields.Many2one('res.company', compute="get_company_id", related=False, store=True)
# 排产的时候, 根据坯料的长宽高比对一下机床的最大加工尺寸.不符合就不要分配给这个加工中心(机床).
# 工单对应的工作中心,根据工序中的工作中心去匹配,

View File

@@ -231,13 +231,13 @@ class ResWorkcenter(models.Model):
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))
date_planned, sum_qty, default_capacity, date_planned_working_hours))
if sum_qty >= default_capacity:
return False
return True
# 处理排程是否超过小时产能
def deal_available_single_machine_capacity(self, date_planned):
def deal_available_single_machine_capacity(self, date_planned, count):
date_planned_start = date_planned.strftime('%Y-%m-%d %H:00:00')
date_planned_end = date_planned + timedelta(hours=1)
@@ -249,7 +249,11 @@ class ResWorkcenter(models.Model):
if plan_ids:
sum_qty = sum([p.product_qty for p in plan_ids])
if sum_qty >= self.production_line_hour_capacity:
production_line_hour_capacity = self.production_line_hour_capacity
if sum_qty >= production_line_hour_capacity:
message = '当前计划开始时间不能预约排程,超过生产线小时产能(%d件)%d' % (
production_line_hour_capacity, count)
raise UserError(message)
return False
return True

View File

@@ -59,7 +59,7 @@ class ResMrpWorkOrder(models.Model):
compute='_compute_state', store=True,
default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True)
# state = fields.Selection(selection_add=[('to be detected', "待检测"), ('rework', '返工')], tracking=True)
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效')
@api.depends('production_id.manual_quotation')
def _compute_manual_quotation(self):
@@ -225,6 +225,9 @@ class ResMrpWorkOrder(models.Model):
material_height = fields.Float(string='')
# 零件图号
part_number = fields.Char(related='production_id.part_number', string='零件图号')
machining_drawings = fields.Binary('2D加工图纸', related='production_id.part_drawing', readonly=True)
quality_standard = fields.Binary('质检标准', related='production_id.quality_standard', readonly=True)
# 工序状态
process_state = fields.Selection([
('待装夹', '待装夹'),
@@ -1197,8 +1200,8 @@ class ResMrpWorkOrder(models.Model):
if record.is_rework is False:
if not record.material_center_point:
raise UserError("坯料中心点为空,请检查")
if record.X_deviation_angle <= 0:
raise UserError("X偏差角度小于等于0请检查本次计算的X偏差角度为%s" % record.X_deviation_angle)
# if record.X_deviation_angle <= 0:
# raise UserError("X偏差角度小于等于0请检查本次计算的X偏差角度为%s" % record.X_deviation_angle)
record.process_state = '待加工'
# record.write({'process_state': '待加工'})
record.production_id.process_state = '待加工'

View File

@@ -774,6 +774,8 @@ class ResProductMo(models.Model):
# bfm下单
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
part_number = fields.Char(string='零件图号', readonly=True)
machining_drawings = fields.Binary('2D加工图纸', readonly=True)
quality_standard = fields.Binary('质检标准', readonly=True)
@api.constrains('tool_length')
def _check_tool_length_size(self):
@@ -873,6 +875,8 @@ class ResProductMo(models.Model):
'manual_quotation': item['manual_quotation'] or False,
'part_number': item.get('part_number') or '',
'active': True,
'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode(item['machining_drawings']),
'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']),
}
tax_id = self.env['account.tax'].sudo().search(
[('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')])

View File

@@ -272,6 +272,10 @@ class StockRule(models.Model):
if quick_easy_order:
production.write({'part_number': quick_easy_order.part_drawing_number,
'part_drawing': quick_easy_order.machining_drawings})
else:
production.write({'part_number': production.product_id.part_number,
'part_drawing': production.product_id.machining_drawings,
'quality_standard': production.product_id.quality_standard})
if sale_order:
# sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(company_id).create({

View File

@@ -103,10 +103,20 @@ access_mrp_production_split_multi_group_sf_mrp_user,access.mrp.production.split.
access_mrp_production_split_group_sf_mrp_user,access.mrp.production.split,mrp.model_mrp_production_split,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_production_split_line_group_sf_mrp_user,access.mrp.production.split.line,mrp.model_mrp_production_split_line,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_workcenter_capacity_manager_group_sf_mrp_user,mrp.workcenter.capacity.manager,mrp.model_mrp_workcenter_capacity,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_workcenter_group_quality,mrp_workcenter_group_quality,model_mrp_workcenter,sf_base.group_quality,1,0,0,0
access_mrp_workcenter_group_quality_director,mrp_workcenter_group_quality_director,model_mrp_workcenter,sf_base.group_quality_director,1,0,0,0
access_sf_detection_result_group_quality,sf_detection_result_group_quality,model_sf_detection_result,sf_base.group_quality,1,0,1,0
access_sf_detection_result_group_quality_director,sf_detection_result_group_quality_director,model_sf_detection_result,sf_base.group_quality_director,1,0,1,0
access_mrp_workcenter_productivity_loss_group_quality,mrp_workcenter_productivity_loss_group_quality,mrp.model_mrp_workcenter_productivity_loss,sf_base.group_quality,1,0,0,0
access_mrp_workcenter_productivity_loss_group_quality_director,mrp_workcenter_productivity_loss_group_quality_director,mrp.model_mrp_workcenter_productivity_loss,sf_base.group_quality_director,1,0,0,0
access_mrp_workcenter_productivity_group_quality,mrp_workcenter_productivity_group_quality,mrp.model_mrp_workcenter_productivity,sf_base.group_quality,1,1,1,0
access_mrp_workcenter_productivity_group_quality_director,mrp_workcenter_productivity_group_quality_director,mrp.model_mrp_workcenter_productivity,sf_base.group_quality_director,1,1,1,0
access_mrp_production_group_plan_dispatch,mrp_production,model_mrp_production,sf_base.group_plan_dispatch,1,1,0,0
access_mrp_workorder,mrp_workorder,model_mrp_workorder,sf_base.group_plan_dispatch,1,1,1,0
access_mrp_production_group_quality,mrp_production,model_mrp_production,sf_base.group_quality,1,1,0,0
access_mrp_production_group_quality_director,mrp_production,model_mrp_production,sf_base.group_quality_director,1,1,0,0
access_mrp_workorder_group_quality,mrp_workorder,model_mrp_workorder,sf_base.group_quality,1,1,0,0
access_mrp_workorder_group_quality_director,mrp_workorder,model_mrp_workorder,sf_base.group_quality_director,1,1,0,0
access_mrp_workorder,mrp_workorder,model_mrp_workorder,sf_base.group_plan_dispatch,1,1,0,0
access_sf_production_line_group_plan_dispatch,sf.production.line,model_sf_production_line,sf_base.group_plan_dispatch,1,0,0,0
access_sf_production_line_group_plan_director,sf.production.line,model_sf_production_line,sf_base.group_plan_director,1,1,1,0
access_sf_production_line,sf.production.line,model_sf_production_line,sf_maintenance.sf_group_equipment_user,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
103 access_mrp_production_split_line_group_sf_mrp_user access.mrp.production.split.line mrp.model_mrp_production_split_line sf_base.group_sf_mrp_user 1 1 1 0
104 access_mrp_workcenter_capacity_manager_group_sf_mrp_user mrp.workcenter.capacity.manager mrp.model_mrp_workcenter_capacity sf_base.group_sf_mrp_user 1 1 1 0
105 access_mrp_production_group_plan_dispatch access_mrp_workcenter_group_quality mrp_production mrp_workcenter_group_quality model_mrp_production model_mrp_workcenter sf_base.group_plan_dispatch sf_base.group_quality 1 1 0 0 0
106 access_mrp_workorder access_mrp_workcenter_group_quality_director mrp_workorder mrp_workcenter_group_quality_director model_mrp_workorder model_mrp_workcenter sf_base.group_plan_dispatch sf_base.group_quality_director 1 1 0 1 0 0
107 access_sf_production_line_group_plan_dispatch access_sf_detection_result_group_quality sf.production.line sf_detection_result_group_quality model_sf_production_line model_sf_detection_result sf_base.group_plan_dispatch sf_base.group_quality 1 0 0 1 0
108 access_sf_detection_result_group_quality_director sf_detection_result_group_quality_director model_sf_detection_result sf_base.group_quality_director 1 0 1 0
109 access_mrp_workcenter_productivity_loss_group_quality mrp_workcenter_productivity_loss_group_quality mrp.model_mrp_workcenter_productivity_loss sf_base.group_quality 1 0 0 0
110 access_mrp_workcenter_productivity_loss_group_quality_director mrp_workcenter_productivity_loss_group_quality_director mrp.model_mrp_workcenter_productivity_loss sf_base.group_quality_director 1 0 0 0
111 access_mrp_workcenter_productivity_group_quality mrp_workcenter_productivity_group_quality mrp.model_mrp_workcenter_productivity sf_base.group_quality 1 1 1 0
112 access_mrp_workcenter_productivity_group_quality_director mrp_workcenter_productivity_group_quality_director mrp.model_mrp_workcenter_productivity sf_base.group_quality_director 1 1 1 0
113 access_mrp_production_group_plan_dispatch mrp_production model_mrp_production sf_base.group_plan_dispatch 1 1 0 0
114 access_sf_production_line_group_plan_director access_mrp_production_group_quality sf.production.line mrp_production model_sf_production_line model_mrp_production sf_base.group_plan_director sf_base.group_quality 1 1 1 0 0
115 access_sf_production_line access_mrp_production_group_quality_director sf.production.line mrp_production model_sf_production_line model_mrp_production sf_maintenance.sf_group_equipment_user sf_base.group_quality_director 1 1 1 0 0
116 access_mrp_workorder_group_quality mrp_workorder model_mrp_workorder sf_base.group_quality 1 1 0 0
117 access_mrp_workorder_group_quality_director mrp_workorder model_mrp_workorder sf_base.group_quality_director 1 1 0 0
118 access_mrp_workorder mrp_workorder model_mrp_workorder sf_base.group_plan_dispatch 1 1 0 0
119 access_sf_production_line_group_plan_dispatch sf.production.line model_sf_production_line sf_base.group_plan_dispatch 1 0 0 0
120 access_mrp_workcenter access_sf_production_line_group_plan_director mrp_workcenter sf.production.line model_mrp_workcenter model_sf_production_line sf_base.group_plan_dispatch sf_base.group_plan_director 1 1 1 0
121 access_mrp_bom_group_plan_dispatch access_sf_production_line mrp.bom sf.production.line mrp.model_mrp_bom model_sf_production_line sf_base.group_plan_dispatch sf_maintenance.sf_group_equipment_user 1 0 1 0 1 0
122 access_mrp_bom_line access_mrp_workcenter mrp.bom.line mrp_workcenter mrp.model_mrp_bom_line model_mrp_workcenter sf_base.group_plan_dispatch 1 0 1 0 1 0

View File

@@ -98,9 +98,11 @@
<field name="production_line_id" readonly="1"/>
<!-- <field name="production_line_state" readonly="1"/>-->
<field name="part_number" string="成品的零件图号"/>
<field name="part_drawing"/>
<field name="part_drawing" widget="adaptive_viewer"/>
<field name="quality_standard" widget="adaptive_viewer"/>
<field name="tool_state"/>
<field name="tool_state_remark" string="备注" attrs="{'invisible': [('tool_state', '!=', '1')]}"/>
<field name="deadline_of_delivery" readonly="1"/>
<field name="tool_state_remark2" invisible="1"/>
</xpath>
<xpath expr="//header//button[@name='action_cancel']" position="replace">
@@ -296,8 +298,11 @@
</attribute>
</xpath>
<xpath expr="//sheet//notebook//page[@name='operations']//field[@name='workorder_ids']" position="replace">
<field name="workorder_ids" attrs="{'readonly': ['|', ('state', '!=', 'test_value'), '&amp;', ('state', '=', 'done'), ('is_locked', '=', True)]}" context="{'tree_view_ref': 'mrp.mrp_production_workorder_tree_editable_view', 'default_product_uom_id': product_uom_id, 'from_manufacturing_order': True}"/>
<xpath 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">
@@ -348,8 +353,11 @@
<field name="arch" type="xml">
<xpath expr="//tree" position="attributes">
<attribute name="default_order">sequence</attribute>
<attribute name="decoration-warning">delivery_warning == 'warning'</attribute>
<attribute name="decoration-danger">delivery_warning == 'overdue'</attribute>
</xpath>
<xpath expr="//field[@name='state']" position="replace">
<field name="delivery_warning" invisible="True"/>
<field name="state" widget="badge" decoration-warning="state == 'progress'"
decoration-success="state == 'done'" decoration-danger="state in ('cancel','rework')"
decoration-muted="state == 'to be detected'"
@@ -556,7 +564,12 @@
</div>
<field name="priority" widget="priority"/>
</div>
<t t-if="record.brand_id.raw_value">
<div class="mt-1">
品牌:
<field name="brand_id"></field>
</div>
</t>
<div name="product_specification_id" class="mt-1">
规格:
<field name="specification_id"/>

View File

@@ -101,7 +101,9 @@
<!-- <field name="target">fullscreen</field>-->
<field name="target">current</field>
<field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>
<field name="context">{'search_default_product': 1, 'search_default_workcenter_id': active_id}</field>
<field name="context">{'search_default_product': 1, 'search_default_workcenter_id':
active_id,'search_default_filter_order_warning':1,'search_default_filter_order_overdue':1}
</field>
<field name="help" type="html">
<p class="o_view_nocontent_workorder">
没有工单要做!
@@ -221,15 +223,54 @@
</page>
</xpath>
<xpath expr="//label[1]" position="before">
<field name='routing_type' readonly="1"/>
<field name='process_state' attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<!-- -->
<field name="production_id" invisible="0"/>
<field name="duration_expected" invisible="1"/>
<field name="date_planned_start" invisible="1"/>
<field name="date_planned_finished" invisible="1"/>
<field name="duration" widget="mrp_timer"
invisible="1" sum="real duration"/>
<field name="glb_file" readonly="1" widget="Viewer3D" string="加工模型"/>
<field name="manual_quotation" readonly="1"
attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
<field name="processing_panel" readonly="1"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="equipment_id" readonly="1"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/>
<field name="production_line_id"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/>
<field name="production_line_state" readonly="1"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/>
<field name='routing_type' invisible="1"/>
<field name='process_state' invisible="1"/>
<field name='tag_type' readonly="1" attrs='{"invisible": [("tag_type","=",False)]}'
decoration-danger="tag_type == '重新加工'"/>
<field name="rfid_code" force_save="1" readonly="1" cache="True"
<field name="rfid_code" force_save="1" readonly="0" cache="True"
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
</xpath>
<xpath expr="//form//sheet//group//group//div[2]" position="replace">
</xpath>
<xpath expr="//form//sheet//group//group//div[1]" position="after">
<field name="save_name" widget="CopyClipboardChar"
attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/>
<label for="material_length" string="物料尺寸"/>
<div class="o_address_format">
<label for="material_length" string="长"/>
<field name="material_length" class="o_address_zip"/>
<span>&amp;nbsp;</span>
<label for="material_width" string="宽"/>
<field name="material_width" class="o_address_zip"/>
<span>&amp;nbsp;</span>
<label for="material_height" string="高"/>
<field name="material_height" class="o_address_zip"/>
</div>
<field name="part_number" string="成品的零件图号"/>
<field name="machining_drawings" widget="adaptive_viewer" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
<field name="quality_standard" widget="adaptive_viewer" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
</xpath>
<xpath expr="//label[1]" position="attributes">
<attribute name="string">计划加工时间</attribute>
</xpath>
@@ -246,76 +287,12 @@
<field name='materiel_width' string="宽"/>
<field name='materiel_height' string="高"/>
</xpath>
<field name="production_id" position="after" invisible="0">
<group>
<field name="date_planned_start" invisible="1"/>
<field name="date_planned_finished" invisible="1"/>
<!-- <field name="production_id" readonly="1"/>-->
<field name="duration" widget="mrp_timer"
attrs="{'invisible': [('production_state','=', 'draft')], 'readonly': [('is_user_working', '=', True)]}"
sum="real duration"/>
<field name="glb_file" readonly="1" widget="Viewer3D" string="加工模型"/>
<field name="manual_quotation" readonly="1"
attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
<field name="processing_panel" readonly="1"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="equipment_id" readonly="1"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/>
<field name="production_line_id"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="production_line_state" readonly="1"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/>
<!-- <field name="functional_fixture_id" -->
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> -->
<!-- <field name="functional_fixture_code" force_save="1" -->
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> -->
<!-- <field name="functional_fixture_type_id" -->
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> -->
</group>
<!-- <group>-->
<!-- <div>-->
<!-- <label for="glb_file" string="加工模型"/>-->
<!-- <field name="glb_file" readonly="1" widget="Viewer3D"/>-->
<!-- </div>-->
<!-- &lt;!&ndash; <field name="glb_file" string="模型" readonly="1" widget="Viewer3D"/>&ndash;&gt;-->
<!-- </group>-->
<!-- <field name="processing_panel" readonly="1" attrs="{'invisible': [('routing_type', 'in', ('获取CNC加工程序','装夹','解除装夹',-->
<!-- '前置三元定位检测','后置三元质量检测','解除装夹'))]}"/>-->
</field>
<!-- <page string="Components" name="components">-->
<xpath expr="//page[1]" position="before">
<!-- <page string="装夹托盘" attrs='{"invisible": [("routing_type","!=","装夹")]}'>-->
<!-- <group>-->
<!-- <field name="routing_type" invisible="1"/>-->
<!-- <field name="tray_code"/>-->
<!-- <field name="tray_id" readonly="1"/>-->
<!-- </group>-->
<!-- <group>-->
<!-- <field name="pro_code" readonly="1" attrs='{"invisible": [("pro_code_ok","=",False)]}'-->
<!-- style="color:green"/>-->
<!-- <field name="pro_code" readonly="1" attrs='{"invisible": [("pro_code_ok","!=",False)]}'/>-->
<!-- <div>-->
<!-- <field name="pro_code_ok" invisible="1"/>-->
<!-- </div>-->
<!-- </group>-->
<!-- <div class="col-12 col-lg-6 o_setting_box">-->
<!-- <button type="object" class="oe_highlight" name="gettray" string="绑定托盘"-->
<!-- attrs='{"invisible": ["|","|",("tray_id","!=",False),("state","!=","progress"),("production_id","=",False)]}'/>-->
<!-- </div>-->
<!-- </page>-->
<page string="工件装夹" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'>
<group>
<field name="_barcode_scanned" widget="barcode_handler"/>
<!-- <group string="卡盘">-->
<!-- <field name="chuck_serial_number"/>-->
<!-- <field name="chuck_name"/>-->
<!-- <field name="chuck_brand_id"/>-->
<!-- <field name="chuck_type_id"/>-->
<!-- <field name="chuck_model_id"/>-->
<!-- </group>-->
<group string="托盘">
<field name="tray_serial_number" readonly="1" string="序列号"/>
</group>
@@ -330,10 +307,6 @@
<field name="tray_model_id" readonly="1" string="型号"/>
</group>
</group>
<group string="加工图纸">
<!-- 隐藏加工图纸字段名 -->
<field name="processing_drawing" widget="pdf_viewer" string="" readonly="1"/>
</group>
<group string="预调程序信息">
<field name="preset_program_information" colspan="2" nolabel="1"
placeholder="如有预调程序信息请在此处输入....."/>
@@ -520,7 +493,8 @@
<xpath expr="//form//header" position="inside">
<button type="object" class="oe_highlight jikimo_button_confirm" name="get_three_check_datas"
string="获取数据" attrs='{"invisible": ["|", ("state","!=","progress"), ("routing_type","!=","装夹预调")]}'/>
string="获取数据"
attrs='{"invisible": ["|", ("state","!=","progress"), ("routing_type","!=","装夹预调")]}'/>
</xpath>
@@ -571,9 +545,7 @@
<!-- <field name="button_state" invisible="1"/>-->
</tree>
</field>
<group>
<field name="cnc_worksheet" string="工作指令" widget="pdf_viewer"/>
</group>
</page>
<page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<field name="cmm_ids" widget="one2many" string="CMM程序" readonly="1">
@@ -602,33 +574,49 @@
</page>
</xpath>
<xpath expr="//form//sheet//group//group//div[1]" position="after">
<label for="date_start" string="实际加工时间"/>
<div class="oe_inline">
<field name="date_start" class="mr8 oe_inline"/>
<strong class="mr8 oe_inline"></strong>
<field name="date_finished" class="oe_inline"/>
</div>
<!-- <xpath expr="//form//sheet//group//group//div[1]" position="after">-->
<!-- <label for="date_start" string="实际加工时间"/>-->
<!-- <div class="oe_inline">-->
<!-- <field name="date_start" class="mr8 oe_inline"/>-->
<!-- <strong class="mr8 oe_inline">到</strong>-->
<!-- <field name="date_finished" class="oe_inline"/>-->
<!-- </div>-->
<!-- </xpath>-->
<xpath expr="//page[@name='time_tracking']//field[@name='time_ids']//tree//field[@name='date_end']"
position="after">
<field name="duration" string="实际时长"/>
</xpath>
<xpath expr="//form//sheet//group//group//div[3]" position="after">
<field name="save_name" widget="CopyClipboardChar"
attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/>
<label for="material_length" string="物料尺寸"/>
<div class="o_address_format">
<label for="material_length" string="长"/>
<field name="material_length" class="o_address_zip"/>
<span>&amp;nbsp;</span>
<label for="material_width" string="宽"/>
<field name="material_width" class="o_address_zip"/>
<span>&amp;nbsp;</span>
<label for="material_height" string="高"/>
<field name="material_height" class="o_address_zip"/>
</div>
<field name="part_number" string="成品的零件图号"/>
<xpath expr="//page[@name='time_tracking']" position="attributes">
<attribute name="groups">
mrp.group_mrp_manager,sf_base.group_sf_mrp_manager,sf_base.group_sf_equipment_user,sf_base.group_sf_order_user
</attribute>
</xpath>
</field>
</record>
<record id="view_mrp_production_workorder_tray_form_inherit_sf_1" model="ir.ui.view">
<field name="name">mrp.production.workorder.tray.form.inherit.sf.1</field>
<field name="model">mrp.workorder</field>
<field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/>
<field name="arch" type="xml">
<xpath expr="//form//sheet//group//group[2]" position="replace">
<group string="装夹图纸" attrs="{'invisible': [('routing_type', '!=', '装夹预调')]}">
<!-- 隐藏加工图纸字段名 -->
<field name="processing_drawing" widget="pdf_viewer" string="" readonly="1"/>
<!-- <field name="production_id" invisible="0"/>-->
</group>
<group string="工作指令" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}">
<field name="cnc_worksheet" string="" widget="pdf_viewer"/>
</group>
</xpath>
<!-- <xpath expr="//form//sheet//group//group[1]" position="before">-->
<!-- <field name="production_id"/>-->
<!-- </xpath>-->
</field>
</record>
<record id="workcenter_form_workorder_search" model="ir.ui.view">
<field name="name">custom.workorder.search</field>
<field name="model">mrp.workorder</field>
@@ -640,6 +628,12 @@
<xpath expr="//filter[@name='progress']" position="after">
<filter string="待检测" name="state" domain="[('state','=','to be detected')]"/>
</xpath>
<xpath expr="//filter[@name='date_start_filter']" position="before">
<separator/>
<filter string="预警" name="filter_order_warning" domain="[('delivery_warning', '=', 'warning')]"/>
<filter string="逾期" name="filter_order_overdue" domain="[('delivery_warning', '=', 'overdue')]"/>
<separator/>
</xpath>
</field>
</record>

View File

@@ -11,12 +11,13 @@
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify', 'stock'],
'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify', 'stock', 'sf_quality', 'mrp'],
'data': [
'data/bussiness_node.xml',
# 'data/cron_data.xml',
'data/cron_data.xml',
'data/template_data.xml',
'security/ir.model.access.csv',
'views/mrp_workorder_views.xml',
],
'test': [
],

View File

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

View File

@@ -15,12 +15,13 @@ class MessageSfMrsConnect(Sf_Mrs_Connect):
def get_cnc_processing_create(self, **kw):
res = super(MessageSfMrsConnect, self).get_cnc_processing_create(**kw)
res = json.loads(res)
_logger.info('已进入消息推送:%s' % 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')
tool_state_valid_productions = productions.filtered(lambda x: x.tool_state == '2')
if tool_state_valid_productions:
data = {
'name': tool_state_valid_productions[0].programming_no
@@ -38,3 +39,22 @@ class MessageSfMrsConnect(Sf_Mrs_Connect):
_logger.info('无效用刀异常消息推送接口:%s' % e)
return json.JSONEncoder().encode(res)
@http.route('/api/maintenance_logs/notify', type='json', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
def maintenance_logs_notify(self, **kw):
res = {'code': 200, 'message': '设备故障日志信息推送成功'}
datas = request.httprequest.data
ret = json.loads(datas)
log_id = ret.get('log_id')
if not log_id:
res = {'code': 400, 'message': '设备故障日志id不能为空'}
return json.JSONEncoder().encode(res)
try:
if not isinstance(log_id, list):
log_id = [log_id]
maintenance_logs = request.env['sf.maintenance.logs'].sudo().search([('id', 'in', [int(id) for id in log_id])])
if maintenance_logs:
maintenance_logs.add_queue('设备故障')
except Exception as e:
res = {'code': 400, 'message': '设备故障信息推送失败', 'error': str(e)}
return json.JSONEncoder().encode(res)

View File

@@ -12,15 +12,16 @@
<field name="model">sale.order</field>
</record>
<!-- <record id="bussiness_sale_order_overdue_warning" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">销售订单逾期预警</field>-->
<!-- <field name="model">sale.order</field>-->
<!-- </record>-->
<record id="bussiness_sale_order_overdue_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="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>
@@ -48,42 +49,62 @@
<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="production_completed_warehouse_reminder" model="jikimo.message.bussiness.node">
<field name="name">生产完工入库提醒</field>
<field name="model">mrp.production</field>
</record>
<record id="order_delivery_reminder" model="jikimo.message.bussiness.node">
<field name="name">订单发货提醒</field>
<field name="model">stock.picking</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_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_unclamp_overdue_warning" 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" model="jikimo.message.bussiness.node">-->
<!-- <field name="name">解除装夹工单逾期</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_surface_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" 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>
<record id="bussiness_quality_cnc_test" model="jikimo.message.bussiness.node">
<field name="name">待质量判定</field>
<field name="model">quality.cnc.test</field>
</record>
<record id="bussiness_maintenance_logs" model="jikimo.message.bussiness.node">
<field name="name">设备故障</field>
<field name="model">sf.maintenance.logs</field>
</record>
</data>
</odoo>

View File

@@ -1,24 +1,11 @@
<odoo>
<data noupdate="1">
<record model="ir.cron" id="ir_cron_sale_order_overdue_warning">
<field name="name">销售订单逾期预警</field>
<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="code">model._overdue_or_warning_func()</field>
<field name="interval_number">10</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
@@ -27,11 +14,11 @@
</record>
<record model="ir.cron" id="ir_cron_mrp_workorder_overdue_warning">
<field name="name">装夹预调工单逾期预警</field>
<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="code">model._overdue_or_warning_func()</field>
<field name="interval_number">10</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
@@ -39,122 +26,17 @@
<field name="active" eval="True"/>
</record>
<record model="ir.cron" id="ir_cron_mrp_workorder_overdue">
<field name="name">工单已逾期</field>
<record model="ir.cron" id="ir_cron_mrp_workorder_recover_time_warning">
<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="code">model._recover_time_warning_func()</field>
<field name="interval_number">10</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

@@ -2,7 +2,7 @@
<odoo>
<data noupdate="1">
<record id="template_pending_order" model="jikimo.message.template">
<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>
@@ -16,7 +16,7 @@
</record>
<record id="template_to_be_confirm" model="jikimo.message.template">
<field name="name">确认接单</field>
<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"/>
@@ -27,6 +27,31 @@
事项:{{mrp_production_count}}个制造订单待计划排程
</field>
</record>
<record id="template_sale_order_overdue_warning" 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_sale_order_overdue_warning"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 销售订单逾期预警
事项:共有[{{warning_num}}]({{url}})个销售订单有逾期风险
</field>
</record>
<record id="template_sale_order_overdue" 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_sale_order_overdue"/>
<field name="msgtype">markdown</field>
<field name="urgency">urgent</field>
<field name="content">### 销售订单已逾期提醒
事项:共有[{{overdue_num}}]({{url}})个销售订单已逾期
</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"/>
@@ -63,11 +88,107 @@
事项:共{{number}}个工单已下发,请查收知悉</field>
</record>
<record id="template_mrp_workorder_pre_overdue_warning" 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_pre_overdue_warning"/>
<field name="msgtype">markdown</field>
<field name="send_type">timing</field>
<field name="urgency">normal</field>
<field name="content">### 工单逾期预警
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
</record>
<record id="template_mrp_workorder_pre_overdue" 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_pre_overdue"/>
<field name="msgtype">markdown</field>
<field name="send_type">timing</field>
<field name="urgency">normal</field>
<field name="content">### 工单已逾期提醒
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
</record>
<record id="template_mrp_workorder_cnc_overdue_warning" model="jikimo.message.template">
<field name="name">CNC加工工单逾期预警</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_cnc_overdue_warning"/>
<field name="msgtype">markdown</field>
<field name="send_type">timing</field>
<field name="urgency">normal</field>
<field name="content">### 工单逾期预警
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
</record>
<record id="template_mrp_workorder_cnc_overdue" model="jikimo.message.template">
<field name="name">CNC加工工单已逾期</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_cnc_overdue"/>
<field name="msgtype">markdown</field>
<field name="send_type">timing</field>
<field name="urgency">normal</field>
<field name="content">### 工单已逾期提醒
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
</record>
<record id="template_mrp_workorder_unclamp_overdue_warning" 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_unclamp_overdue_warning"/>
<field name="msgtype">markdown</field>
<field name="send_type">timing</field>
<field name="urgency">normal</field>
<field name="content">### 工单逾期预警
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
</record>
<record id="template_mrp_workorder_unclamp_overdue" 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_unclamp_overdue"/>
<field name="msgtype">markdown</field>
<field name="send_type">timing</field>
<field name="urgency">normal</field>
<field name="content">### 工单已逾期提醒
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
</record>
<record id="template_mrp_workorder_surface_overdue_warning" 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_surface_overdue_warning"/>
<field name="msgtype">markdown</field>
<field name="send_type">timing</field>
<field name="urgency">normal</field>
<field name="content">### 工单逾期预警
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
</record>
<record id="template_mrp_workorder_surface_overdue" 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_surface_overdue"/>
<field name="msgtype">markdown</field>
<field name="send_type">timing</field>
<field name="urgency">normal</field>
<field name="content">### 工单已逾期提醒
事项:共有[{{overdue_num}}]({{url}})工单已逾期</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="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>
@@ -75,13 +196,13 @@
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 调拨入库通知:
单号:调拨入库单[{{name}}]({{request_url}})
单号:调拨入库单[{{name}}]({{transfer_inventory_special_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="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>
@@ -89,13 +210,13 @@
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 功能刀具寿命到期提醒:
单号:拆解单[{{code}}]({{request_url}})
单号:拆解单[{{code}}]({{tool_expired_remind_special_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="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>
@@ -103,8 +224,56 @@
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 功能刀具组装通知:
单号:组装任务单[{{name}}]({{request_url}})
单号:组装任务单[{{name}}]({{tool_assembly_special_url}})
事项:{{use_tool_time}}前完成组装</field>
</record>
<record id="template_production_completed_remind" model="jikimo.message.template">
<!-- <field name="menu_id" ref="mrp.menu_mrp_root"/>-->
<!-- <field name="action_id" ref="mrp.mrp_production_action"/>-->
<field name="name">生产完工入库提醒</field>
<field name="model_id" ref="mrp.model_mrp_production"/>
<field name="model">mrp.production</field>
<field name="bussiness_node_id" ref="production_completed_warehouse_reminder"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 生产完工入库提醒:
单号:生产入库单[{{name}}]({{request_url}})
事项:销售订单{{sale_order_name}}已全部产出,请入库处理</field>
</record>
<record id="template_order_delivery_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="order_delivery_reminder"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 订单发货提醒:
单号:发料出库单[{{name}}]({{request_url}})
事项:销售订单{{sale_order_name}}已全部产出并入库,请及时发货</field>
</record>
<record id="template_quality_cnc_test" model="jikimo.message.template">
<field name="name">待质量判定</field>
<field name="model_id" ref="sf_quality.model_quality_cnc_test"/>
<field name="model">quality.cnc.test</field>
<field name="bussiness_node_id" ref="bussiness_quality_cnc_test"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 待质量判定提醒
事项:共有[{{judge_num}}]({{url}})个工单需判定质量结果</field>
</record>
<record id="template_maintenance_logs" model="jikimo.message.template">
<field name="name">设备故障</field>
<field name="model_id" ref="sf_maintenance.model_sf_maintenance_logs"/>
<field name="model">sf.maintenance.logs</field>
<field name="bussiness_node_id" ref="bussiness_maintenance_logs"/>
<field name="msgtype">markdown</field>
<field name="urgency">urgent</field>
<field name="content">### 设备故障及异常提醒:
机台号:[{{maintenance_equipment_id.name}}]({{url}})
事项:{{create_date}}故障报警</field>
</record>
</data>
</odoo>

View File

@@ -7,3 +7,6 @@ from . import sf_message_functional_tool_assembly
from . import sf_message_purchase
from . import sf_message_workorder
from . import sf_message_functional_tool_dismantle
from . import sf_message_mrp_production
from . import sf_message_quality_cnc_test
from . import sf_message_maintenance_logs

View File

@@ -13,3 +13,14 @@ class SFMessagefunctionalToolAssembly(models.Model):
if obj.loading_task_source == '0' and obj.assemble_status == '0':
obj.add_queue('功能刀具组装')
return result
def get_special_url(self,id,tmplate_name,special_name,model_id):
menu_id = 0
action_id = 0
if tmplate_name=='调拨入库' and special_name== 'tool_assembly_special_url':
menu_id = self.env.ref('mrp.menu_mrp_root').id
action_id = self.env.ref('sf_tool_management.sf_functional_tool_assembly_view_act').id
return super(SFMessagefunctionalToolAssembly, self).get_url(id, menu_id, action_id,model_id)
else:
return super(SFMessagefunctionalToolAssembly, self).get_special_url(id, tmplate_name, special_name, model_id)

View File

@@ -17,3 +17,13 @@ class SFMessagefunctionalToolDismantle(models.Model):
if obj.dismantle_cause in ['寿命到期报废', '崩刀报废'] and obj.state == '待拆解':
obj.add_queue('功能刀具寿命到期')
return result
def get_special_url(self,id,tmplate_name,special_name,model_id):
menu_id = 0
action_id = 0
if tmplate_name=='调拨入库' and special_name== 'tool_expired_remind_special_url':
menu_id = self.env.ref('mrp.menu_mrp_root').id
action_id = self.env.ref('sf_tool_management.sf_functional_tool_dismantle_view_act').id
return super(SFMessagefunctionalToolDismantle, self).get_url(id, menu_id, action_id,model_id)
else:
return super(SFMessagefunctionalToolDismantle, self).get_special_url(id, tmplate_name, special_name, model_id)

View File

@@ -0,0 +1,22 @@
from odoo import models, fields, api
class SFMessageMaintenanceLogs(models.Model):
_name = 'sf.maintenance.logs'
_inherit = ['sf.maintenance.logs', 'jikimo.message.dispatch']
@api.model_create_multi
def create(self, vals_list):
res = super(SFMessageMaintenanceLogs, self).create(vals_list)
for rec in res:
rec.add_queue('设备故障')
return res
def _get_message(self, message_queue_ids):
contents = super(SFMessageMaintenanceLogs, self)._get_message(message_queue_ids)
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('sf_maintenance.action_maintenance_logs').id
for index, content in enumerate(contents):
maintenance_logs_id = self.env['sf.maintenance.logs'].browse(message_queue_ids[index].res_id)
url = url + '/web#id=%s&view_type=form&action=%s' % (maintenance_logs_id.id, action_id)
contents[index] = content.replace('{{url}}', url)
return contents

View File

@@ -0,0 +1,57 @@
import logging
import re
from odoo import models, fields, api, _
from urllib.parse import urlencode
class SFMessageMrpProduction(models.Model):
_name = 'mrp.production'
_description = "制造订单"
_inherit = ['mrp.production', 'jikimo.message.dispatch']
@api.depends(
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
'workorder_ids.state', 'product_qty', 'qty_producing')
def _compute_state(self):
super(SFMessageMrpProduction, self)._compute_state()
for record in self:
if record.state in ['scrap', 'done']:
# 查询制造订单下的所有未完成的生产订单
mrp_production = record.env['mrp.production'].search(
[('origin', '=', record.origin), ('state', 'not in', ['scrap', 'done'])])
if not mrp_production:
mrp_production_queue = self.env["jikimo.message.queue"].search([('res_id', '=', record.id)])
if not mrp_production_queue:
record.add_queue('生产完工入库提醒')
# 获取发送消息内容
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
mrp_production = self.env['mrp.production'].search([('id', '=', int(message_queue_id.res_id))])
if mrp_production and len(mrp_production) > 0:
stock_picking_sfp = self.env['stock.picking'].search(
[('origin', '=', mrp_production.origin), ('picking_type_id.sequence_code', '=', 'SFP'),
('state', '=', 'assigned')], limit=1)
if stock_picking_sfp:
url = self.request_url(stock_picking_sfp.id)
content = content.replace('{{name}}', stock_picking_sfp.name).replace(
'{{sale_order_name}}', mrp_production.origin).replace('{{request_url}}', url)
contents.append(content)
logging.info('生产完工入库提醒: %s' % contents)
return contents
def request_url(self, id):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('stock.action_picking_tree_all').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id
# 查询参数
params = {'id': id, 'menu_id': menu_id, 'action': action_id, 'model': 'mrp.production',
'view_type': 'form'}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + query_string
return full_url

View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
import logging
from datetime import datetime, timedelta
from odoo import models, fields, api, _
class SFMessageQualityCncTest(models.Model):
_name = 'quality.cnc.test'
_inherit = ['quality.cnc.test', 'jikimo.message.dispatch']
def create(self, vals_list):
res = super(SFMessageQualityCncTest, self).create(vals_list)
if res:
try:
logging.info('add_queue res:%s' % res)
res.add_queue('待质量判定')
except Exception as e:
logging.info('add_queue error:%s' % e)
return res
# 继承并重写jikimo.message.dispatch的_get_message()
def _get_message(self, message_queue_ids):
contents = []
url = self.env['ir.config_parameter'].get_param('web.base.url')
i = 0
for item in message_queue_ids:
if item.message_template_id.bussiness_node_id.name == '待质量判定':
content = item.message_template_id.content
i += 1
if i >= 1:
action_id = self.env.ref('sf_quality.action_quality_cnc_test').id
url_with_id = f"{url}/web#view_type=list&action={action_id}"
content_template = content.replace('{{judge_num}}', str(i))
content_template = content_template.replace('{{url}}', url_with_id)
contents.append(content_template)
return contents

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import logging
from datetime import datetime, timedelta
from odoo import models, fields, api, _
@@ -7,10 +8,12 @@ class SFMessageSale(models.Model):
_name = 'sale.order'
_inherit = ['sale.order', 'jikimo.message.dispatch']
@api.model_create_multi
def create(self, vals_list):
res = super(SFMessageSale, self).create(vals_list)
if res:
try:
logging.info('add_queue res:%s' % res)
res.add_queue('待接单')
except Exception as e:
logging.info('add_queue error:%s' % e)
@@ -41,16 +44,20 @@ class SFMessageSale(models.Model):
# 继承并重写jikimo.message.dispatch的_get_message()
def _get_message(self, message_queue_ids):
contents = []
bussiness_node = None
url = self.env['ir.config_parameter'].get_param('web.base.url')
current_time_strf = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
current_time = self.env['sf.sync.common'].sudo().get_add_time(current_time_strf)
current_time_datetime = datetime.strptime(current_time, '%Y-%m-%d %H:%M:%S')
time_range = timedelta(minutes=2)
i = 0
for item in message_queue_ids:
# 待接单的处理
if item.message_template_id.bussiness_node_id.name == '待接单':
content = super(SFMessageSale, self)._get_message(item)
action_id = self.env.ref('sale.action_quotations_with_onboarding').id
url = f"{url}/web#id={item.res_id}&view_type=form&action={action_id}"
content = content[0].replace('{{url}}', url)
url_with_id = f"{url}/web#id={item.res_id}&view_type=form&action={action_id}"
content = content[0].replace('{{url}}', url_with_id)
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))])
@@ -58,16 +65,77 @@ class SFMessageSale(models.Model):
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)
url_with_id = f"{url}/web#view_type=list&action={action_id}"
content = content[0].replace('{{product_id}}', product).replace('{{url}}', url_with_id)
contents.append(content)
elif item.message_template_id.bussiness_node_id.name in ['销售订单逾期预警', '销售订单已逾期']:
bussiness_node = item.message_template_id.bussiness_node_id.name
for reminder_time in item.message_template_id.reminder_time_ids:
content = item.message_template_id.content
target_time = datetime.combine(current_time_datetime.date(), datetime.min.time()).replace(
hour=reminder_time.time_point,
minute=0,
second=0,
microsecond=0
)
logging.info(current_time)
logging.info(target_time)
if target_time - time_range <= current_time_datetime <= target_time + time_range:
search_condition = [
('delivery_warning', '=', 'warning')] if bussiness_node == '销售订单逾期预警' else [
('delivery_warning', '=', 'overdue')]
record = self.sudo().search(search_condition + [('id', '=', int(item.res_id))])
if record:
i += 1
if i >= 1:
action_id = self.env.ref('sale.action_orders').id
url_with_id = f"{url}/web#view_type=list&action={action_id}"
content_template = content.replace('{{url}}', url_with_id)
if bussiness_node == '销售订单逾期预警':
content = content_template.replace('{{warning_num}}', str(i))
elif bussiness_node == '销售订单已逾期':
content = content_template.replace('{{overdue_num}}', str(i))
contents.append(content)
return contents
# # 销售订单逾期预警
# def _overdue_warning_func(self):
# sale_order_
# return 1
#
# # 销售订单已逾期
# def _overdue_func(self):
# return 1
# # 销售订单逾期预警和已逾期
def _overdue_or_warning_func(self):
today = datetime.today().date()
deadline_check = today + timedelta(days=1)
logging.info(f"today: {today}, deadline_check: {deadline_check}")
sale_order = self.sudo().search([('state', 'in', ['sale']), ('deadline_of_delivery', '!=', False)])
for item in sale_order:
production = self.env['mrp.production'].search([('origin', '=', item.name)])
production_not_done = production.filtered(lambda p: p.state not in ['done', 'scrap', 'cancel'])
production_done_count = len(production.filtered(lambda p: p.state in ['done', 'scrap', 'cancel']))
if len(production_not_done) != item.mrp_production_count:
if deadline_check == item.deadline_of_delivery:
item.delivery_warning = 'warning'
elif today == item.deadline_of_delivery:
item.delivery_warning = 'overdue'
elif production_done_count == item.mrp_production_count:
if item.delivery_status in ['pending', 'partial']:
if deadline_check == item.deadline_of_delivery:
item.delivery_warning = 'warning'
elif today == item.deadline_of_delivery:
item.delivery_warning = 'overdue'
else:
continue
overdue_orders = self.sudo().search([('delivery_warning', 'in', ['warning', 'overdue'])])
for wo in overdue_orders:
message_template = self.env["jikimo.message.template"].search([
("model", "=", self._name),
("bussiness_node_id", "=", self.env.ref('sf_message.bussiness_sale_order_overdue_warning').id)
])
sale_order_has = self.env['jikimo.message.queue'].search([
('res_id', '=', wo.id),
('message_status', '=', 'pending'),
('message_template_id', '=', message_template.id)
])
if not sale_order_has:
if wo.delivery_warning == 'warning':
wo.add_queue('销售订单逾期预警')
elif wo.delivery_warning == 'overdue':
wo.add_queue('销售订单已逾期')

View File

@@ -1,3 +1,4 @@
import logging
import re
from odoo import models, fields, api, _
from urllib.parse import urlencode
@@ -23,6 +24,29 @@ class SFMessageStockPicking(models.Model):
if record.state == 'assigned' and record.check_in == 'PC':
record.add_queue('坯料发料提醒')
if record.picking_type_id.sequence_code == 'SFP' and record.state == 'done':
stock_picking_sfp = record.env['stock.picking'].search(
[('origin', '=', record.origin), ('state', '!=', 'done'),
('picking_type_id.sequence_code', '=', 'SFP')])
if not stock_picking_sfp:
stock_picking_send = self.env["jikimo.message.queue"].search([('res_id', '=', record.id)])
if not stock_picking_send:
record.add_queue('订单发货提醒')
def deal_stock_picking_sfp(self, message_queue_id): # 处理订单发货提醒
content = None
stock_picking = self.env['stock.picking'].search([('id', '=', int(message_queue_id.res_id))])
stock_picking_out = self.env['stock.picking'].search(
[('origin', '=', stock_picking.origin), ('state', '=', 'assigned'),
('picking_type_id.sequence_code', '=', 'OUT')])
if stock_picking_out and len(stock_picking_out) > 0:
content = message_queue_id.message_template_id.content
url = self.request_url1(stock_picking_out.id)
content = content.replace('{{name}}', stock_picking_out.name).replace(
'{{sale_order_name}}', stock_picking_out.origin).replace('{{request_url}}', url)
logging.info('订单发货提醒: %s' % content)
return content
def _get_message(self, message_queue_ids):
contents = []
product_id = []
@@ -46,10 +70,21 @@ class SFMessageStockPicking(models.Model):
'{{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
elif message_queue_id.message_template_id.name == '订单发货提醒':
content = self.deal_stock_picking_sfp(message_queue_id)
if content:
contents.append(content)
return contents
def get_special_url(self, id, tmplate_name, special_name, model_id):
menu_id = 0
action_id = 0
if tmplate_name == '调拨入库' and special_name == 'transfer_inventory_special_url':
menu_id = self.env.ref('stock.menu_stock_root').id
action_id = self.env.ref('stock.action_picking_tree_ready').id
return super(SFMessageStockPicking, self).get_url(id, menu_id, action_id, model_id)
else:
return super(SFMessageStockPicking, self).get_special_url(id, tmplate_name, special_name, model_id)
def request_url(self):
url = self.env['ir.config_parameter'].get_param('web.base.url')
@@ -63,3 +98,16 @@ class SFMessageStockPicking(models.Model):
# 拼接URL
full_url = url + "/web#" + query_string
return full_url
def request_url1(self, id):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('stock.action_picking_tree_all').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id
# 查询参数
params = {'id': id, 'menu_id': menu_id, 'action': action_id, 'model': 'stock.picking',
'view_type': 'form'}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + query_string
return full_url

View File

@@ -14,4 +14,6 @@ class SfMessageTemplate(models.Model):
res.append('sf.functional.tool.dismantle')
res.append('purchase.order')
res.append('mrp.workorder')
res.append('sf.maintenance.logs')
res.append('quality.cnc.test')
return res

View File

@@ -1,3 +1,4 @@
from datetime import datetime, timedelta
from odoo import models, fields, api, _
import logging, json
import requests
@@ -6,11 +7,12 @@ from urllib.parse import urlencode
_logger = logging.getLogger(__name__)
class SFMessageWork(models.Model):
_name = 'mrp.workorder'
_inherit = ['mrp.workorder', 'jikimo.message.dispatch']
@api.depends('production_availability', 'blocked_by_workorder_ids.state')
@api.depends('production_availability', 'blocked_by_workorder_ids.state', 'production_id.tool_state')
def _compute_state(self):
super(SFMessageWork, self)._compute_state()
for workorder in self:
@@ -23,6 +25,17 @@ class SFMessageWork(models.Model):
def _get_message(self, message_queue_ids):
contents = []
product_id = []
bussiness_node = None
url = self.env['ir.config_parameter'].get_param('web.base.url')
current_time_strf = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
current_time = self.env['sf.sync.common'].sudo().get_add_time(current_time_strf)
current_time_datetime = datetime.strptime(current_time, '%Y-%m-%d %H:%M:%S')
time_range = timedelta(minutes=2)
template_names = {
'预警': ['装夹预调工单逾期预警', 'CNC加工工单逾期预警', '解除装夹工单逾期预警', '表面工艺工单逾期预警'],
'已逾期': ['装夹预调工单已逾期', 'CNC加工工单已逾期', '解除装夹工单已逾期', '表面工艺工单已逾期']
}
i = 0
for message_queue_id in message_queue_ids:
if message_queue_id.message_template_id.name == '工单已下发通知':
content = message_queue_id.message_template_id.content
@@ -37,11 +50,42 @@ class SFMessageWork(models.Model):
'{{request_url}}', url)
product_id.append(mrp_workorder_line.product_id.id)
contents.append(content)
elif message_queue_id.message_template_id.name in template_names['预警'] + template_names['已逾期']:
item = message_queue_id.message_template_id
bussiness_node = item.bussiness_node_id.name
for reminder_time in item.reminder_time_ids:
content = item.content
target_time = datetime.combine(current_time_datetime.date(), datetime.min.time()).replace(
hour=reminder_time.time_point,
minute=0,
second=0,
microsecond=0
)
logging.info(current_time)
logging.info(target_time)
logging.info(target_time - time_range)
logging.info(target_time + time_range)
if target_time - time_range <= current_time_datetime <= target_time + time_range:
search_condition = [
('delivery_warning', '=', 'warning')] if bussiness_node in template_names['预警'] else [
('delivery_warning', '=', 'overdue')]
record = self.sudo().search(search_condition + [('id', '=', int(item.res_id))])
if record:
i += 1
if i >= 1:
action_id = self.env.ref('sf_message.mrp_workorder_action_notify').id
url_with_id = f"{url}/web#view_type=list&action={action_id}"
content_template = content.replace('{{url}}', url_with_id)
if bussiness_node in template_names['预警']:
content = content_template.replace('{{warning_num}}', str(i))
elif bussiness_node in template_names['已逾期']:
content = content_template.replace('{{overdue_num}}', str(i))
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
action_id = self.env.ref('sf_message.mrp_workorder_action_notify').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',
@@ -52,3 +96,63 @@ class SFMessageWork(models.Model):
full_url = url + "/web#" + query_string
return full_url
def _overdue_or_warning_func(self):
workorders = self.env['mrp.workorder'].search([("state", "in", ["ready", "progress", "to be detected"])])
grouped_workorders = {}
for workorder in workorders:
routing_type = workorder.routing_type
if routing_type not in grouped_workorders:
grouped_workorders[routing_type] = []
grouped_workorders[routing_type].append(workorder)
for routing_type, orders in grouped_workorders.items():
print(f"Routing Type: {routing_type}, Orders: {len(orders)}")
for item in orders:
if item.date_planned_finished:
current_time_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
current_time = self.env['sf.sync.common'].sudo().get_add_time(current_time_str)
current_time_datetime = datetime.strptime(current_time, '%Y-%m-%d %H:%M:%S')
date_planned_finished_str = self.env['sf.sync.common'].sudo().get_add_time(
item.date_planned_finished.strftime("%Y-%m-%d %H:%M:%S"))
date_planned_finished = datetime.strptime(date_planned_finished_str, '%Y-%m-%d %H:%M:%S')
twelve_hours_ago = current_time_datetime - timedelta(hours=12)
if current_time_datetime >= date_planned_finished:
logging.info("------overdue-------")
logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, "
f"Planned Finish: {date_planned_finished}")
item.delivery_warning = 'overdue'
elif twelve_hours_ago <= current_time_datetime <= date_planned_finished:
logging.info("------warning-------")
logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, "
f"Planned Finish: {date_planned_finished}")
item.delivery_warning = 'warning'
business_node_ids = {
'装夹预调': self.env.ref('sf_message.bussiness_mrp_workorder_pre_overdue_warning').id,
'CNC加工': self.env.ref('sf_message.bussiness_mrp_workorder_cnc_overdue_warning').id,
'解除装夹': self.env.ref('sf_message.bussiness_mrp_workorder_unclamp_overdue_warning').id,
'表面工艺': self.env.ref('sf_message.bussiness_mrp_workorder_surface_overdue_warning').id,
}
message_templates = {key: self.env["jikimo.message.template"].sudo().search([
("model", "=", self._name),
("bussiness_node_id", "=", business_node_ids[key])
]) for key in business_node_ids}
for item in orders:
if item.delivery_warning in ['overdue', 'warning']:
bussiness_node_id = business_node_ids.get(item.routing_type)
if bussiness_node_id and message_templates[item.routing_type]:
message_queue_ids = self.env["jikimo.message.queue"].sudo().search([
("message_template_id", "=", message_templates[item.routing_type].id),
("message_status", "=", "pending"),
("res_id", "=", item.id)
])
if not message_queue_ids:
overdue_message = '工单已逾期' if item.delivery_warning == 'overdue' else '工单逾期预警'
queue_method_name = f'add_queue'
# 构建参数列表其中包含item.routing_type和overdue_message
args = [f'{item.routing_type}{overdue_message}']
# 获取add_queue方法并调用它传入参数列表
getattr(item, queue_method_name)(*args)
def _recover_time_warning_func(self):
workorder_done = self.env['mrp.workorder'].search([("state", "in", ["done", "rework", "cancel"])])
workorder_overdue = workorder_done.filtered(lambda x: x.delivery_warning in ['overdue', 'warning'])
workorder_overdue.write({'delivery_warning': 'normal'})

View File

@@ -1,22 +1,28 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_jikimo_message_template_group_sale_salemanager,jikimo_message_template,model_jikimo_message_template,sf_base.group_sale_salemanager,1,1,1,0
access_jikimo_message_template_group_purchase,jikimo_message_template,model_jikimo_message_template,sf_base.group_purchase,1,1,1,0
access_jikimo_message_template_group_sf_stock_user,jikimo_message_template,model_jikimo_message_template,sf_base.group_sf_stock_user,1,1,1,0
access_jikimo_message_template_group_sf_order_user,jikimo_message_template,model_jikimo_message_template,sf_base.group_sf_order_user,1,1,1,0
access_jikimo_message_template_group_sf_tool_user,jikimo_message_template,model_jikimo_message_template,sf_base.group_sf_tool_user,1,1,1,0
access_jikimo_message_template_group_sale_salemanager,jikimo_message_template,jikimo_message_notify.model_jikimo_message_template,sf_base.group_sale_salemanager,1,1,1,0
access_jikimo_message_template_group_purchase,jikimo_message_template,jikimo_message_notify.model_jikimo_message_template,sf_base.group_purchase,1,1,1,0
access_jikimo_message_template_group_sf_stock_user,jikimo_message_template,jikimo_message_notify.model_jikimo_message_template,sf_base.group_sf_stock_user,1,1,1,0
access_jikimo_message_template_group_sf_order_user,jikimo_message_template,jikimo_message_notify.model_jikimo_message_template,sf_base.group_sf_order_user,1,1,1,0
access_jikimo_message_template_group_sf_tool_user,jikimo_message_template,jikimo_message_notify.model_jikimo_message_template,sf_base.group_sf_tool_user,1,1,1,0
access_jikimo_message_bussiness_node_group_sale_salemanager,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_sale_salemanager,1,1,1,0
access_jikimo_message_bussiness_node_group_purchase,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_purchase,1,1,1,0
access_jikimo_message_bussiness_node_group_sf_stock_user,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_sf_stock_user,1,1,1,0
access_jikimo_message_bussiness_node_group_sf_order_user,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_sf_order_user,1,1,1,0
access_jikimo_message_bussiness_node_group_sf_tool_user,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_sf_tool_user,1,1,1,0
access_jikimo_message_bussiness_node_group_sale_salemanager,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_sale_salemanager,1,1,1,0
access_jikimo_message_bussiness_node_group_purchase,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_purchase,1,1,1,0
access_jikimo_message_bussiness_node_group_sf_stock_user,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_sf_stock_user,1,1,1,0
access_jikimo_message_bussiness_node_group_sf_order_user,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_sf_order_user,1,1,1,0
access_jikimo_message_bussiness_node_group_sf_tool_user,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_sf_tool_user,1,1,1,0
access_jikimo_message_queue_group_sale_salemanager,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_sale_salemanager,1,1,1,0
access_jikimo_message_queue_group_purchase,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_purchase,1,1,1,0
access_jikimo_message_queue_group_sf_stock_user,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_sf_stock_user,1,1,1,0
access_jikimo_message_queue_group_sf_order_user,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_sf_order_user,1,1,1,0
access_jikimo_message_queue_group_sf_tool_user,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_sf_tool_user,1,1,1,0
access_jikimo_message_queue_group_sale_salemanager,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_sale_salemanager,1,1,1,0
access_jikimo_message_queue_group_purchase,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_purchase,1,1,1,0
access_jikimo_message_queue_group_sf_stock_user,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_sf_stock_user,1,1,1,0
access_jikimo_message_queue_group_sf_order_user,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_sf_order_user,1,1,1,0
access_jikimo_message_queue_group_sf_tool_user,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_sf_tool_user,1,1,1,0
access_jikimo_message_reminder_time_group_sale_salemanager,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_sale_salemanager,1,1,1,0
access_jikimo_message_reminder_time_group_purchase,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_purchase,1,1,1,0
access_jikimo_message_reminder_time_group_sf_stock_user,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_sf_stock_user,1,1,1,0
access_jikimo_message_reminder_time_group_sf_order_user,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_sf_order_user,1,1,1,0
access_jikimo_message_reminder_time_group_sf_tool_user,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_sf_tool_user,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_jikimo_message_template_group_sale_salemanager jikimo_message_template model_jikimo_message_template jikimo_message_notify.model_jikimo_message_template sf_base.group_sale_salemanager 1 1 1 0
3 access_jikimo_message_template_group_purchase jikimo_message_template model_jikimo_message_template jikimo_message_notify.model_jikimo_message_template sf_base.group_purchase 1 1 1 0
4 access_jikimo_message_template_group_sf_stock_user jikimo_message_template model_jikimo_message_template jikimo_message_notify.model_jikimo_message_template sf_base.group_sf_stock_user 1 1 1 0
5 access_jikimo_message_template_group_sf_order_user jikimo_message_template model_jikimo_message_template jikimo_message_notify.model_jikimo_message_template sf_base.group_sf_order_user 1 1 1 0
6 access_jikimo_message_template_group_sf_tool_user jikimo_message_template model_jikimo_message_template jikimo_message_notify.model_jikimo_message_template sf_base.group_sf_tool_user 1 1 1 0
7 access_jikimo_message_bussiness_node_group_sale_salemanager jikimo_message_bussiness_node model_jikimo_message_bussiness_node jikimo_message_notify.model_jikimo_message_bussiness_node sf_base.group_sale_salemanager 1 1 1 0
8 access_jikimo_message_bussiness_node_group_purchase jikimo_message_bussiness_node model_jikimo_message_bussiness_node jikimo_message_notify.model_jikimo_message_bussiness_node sf_base.group_purchase 1 1 1 0
9 access_jikimo_message_bussiness_node_group_sf_stock_user jikimo_message_bussiness_node model_jikimo_message_bussiness_node jikimo_message_notify.model_jikimo_message_bussiness_node sf_base.group_sf_stock_user 1 1 1 0
10 access_jikimo_message_bussiness_node_group_sf_order_user jikimo_message_bussiness_node model_jikimo_message_bussiness_node jikimo_message_notify.model_jikimo_message_bussiness_node sf_base.group_sf_order_user 1 1 1 0
11 access_jikimo_message_bussiness_node_group_sf_tool_user jikimo_message_bussiness_node model_jikimo_message_bussiness_node jikimo_message_notify.model_jikimo_message_bussiness_node sf_base.group_sf_tool_user 1 1 1 0
12 access_jikimo_message_queue_group_sale_salemanager jikimo_message_queue model_jikimo_message_queue jikimo_message_notify.model_jikimo_message_queue sf_base.group_sale_salemanager 1 1 1 0
13 access_jikimo_message_queue_group_purchase jikimo_message_queue model_jikimo_message_queue jikimo_message_notify.model_jikimo_message_queue sf_base.group_purchase 1 1 1 0
14 access_jikimo_message_queue_group_sf_stock_user jikimo_message_queue model_jikimo_message_queue jikimo_message_notify.model_jikimo_message_queue sf_base.group_sf_stock_user 1 1 1 0
15 access_jikimo_message_queue_group_sf_order_user jikimo_message_queue model_jikimo_message_queue jikimo_message_notify.model_jikimo_message_queue sf_base.group_sf_order_user 1 1 1 0
16 access_jikimo_message_queue_group_sf_tool_user jikimo_message_queue model_jikimo_message_queue jikimo_message_notify.model_jikimo_message_queue sf_base.group_sf_tool_user 1 1 1 0
17 access_jikimo_message_reminder_time_group_sale_salemanager jikimo_message_reminder_time jikimo_message_notify.model_jikimo_message_reminder_time sf_base.group_sale_salemanager 1 1 1 0
18 access_jikimo_message_reminder_time_group_purchase jikimo_message_reminder_time jikimo_message_notify.model_jikimo_message_reminder_time sf_base.group_purchase 1 1 1 0
19 access_jikimo_message_reminder_time_group_sf_stock_user jikimo_message_reminder_time jikimo_message_notify.model_jikimo_message_reminder_time sf_base.group_sf_stock_user 1 1 1 0
20 access_jikimo_message_reminder_time_group_sf_order_user jikimo_message_reminder_time jikimo_message_notify.model_jikimo_message_reminder_time sf_base.group_sf_order_user 1 1 1 0
21 access_jikimo_message_reminder_time_group_sf_tool_user jikimo_message_reminder_time jikimo_message_notify.model_jikimo_message_reminder_time sf_base.group_sf_tool_user 1 1 1 0
22
23
24
25
26
27
28

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.actions.act_window" id="mrp_workorder_action_notify">
<field name="name">工单</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">mrp.workorder</field>
<field name="view_mode">tree,form</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('mrp.mrp_production_workorder_tree_editable_view')}) ]"/>
<!-- (0, 0, {'view_mode': 'kanban', 'view_id': ref('mrp.workcenter_line_kanban')})-->
<!-- <field name="target">fullscreen</field>-->
<field name="target">current</field>
<field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>
<field name="context">{'search_default_product': 1, 'search_default_workcenter_id':
active_id,'search_default_filter_order_warning':1,'search_default_filter_order_overdue':1,
'search_default_ready': 1, 'search_default_progress': 1}
</field>
<field name="help" type="html">
<p class="o_view_nocontent_workorder">
没有工单要做!
</p>
<p>
工作订单是作为制造订单的一部分执行的操作。
工序在物料清单中定义或直接添加到制造订单中。
</p>
<p>
使用工作台工作中心控制面板直接登记车间中的操作.
平板电脑为您的工人提供工作表,并允许他们报废产品,跟踪时间,
发起维护请求,执行质量测试等.
</p>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,10 @@
<?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>
</data>
</odoo>

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

@@ -3,11 +3,12 @@ import logging
import os
import json
import base64
from odoo import http
from odoo import http, fields, models
from odoo.http import request
from odoo.addons.sf_base.controllers.controllers import MultiInheritController
class Sf_Mrs_Connect(http.Controller):
class Sf_Mrs_Connect(http.Controller, MultiInheritController):
@http.route('/api/cnc_processing/create', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
cors="*")
@@ -25,7 +26,7 @@ class Sf_Mrs_Connect(http.Controller):
ret = json.loads(ret['result'])
logging.info('下发编程单:%s' % ret)
domain = [('programming_no', '=', ret['programming_no'])]
if ret['manufacturing_type'] == 'scrap':
if ret['manufacturing_type'] in ('scrap', 'invalid_tool_rework'):
domain += [('state', 'not in', ['done', 'scrap', 'cancel'])]
productions = request.env['mrp.production'].with_user(
request.env.ref("base.user_admin")).search(domain)
@@ -81,26 +82,40 @@ class Sf_Mrs_Connect(http.Controller):
if files_panel:
for file in files_panel:
file_extension = os.path.splitext(file)[1]
logging.info('file_extension:%s' % file_extension)
if file_extension.lower() == '.pdf':
panel_file_path = os.path.join(program_path_tmp_panel, file)
logging.info('panel_file_path:%s' % panel_file_path)
logging.info('更新工作指令:%s' % cnc_workorder)
cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
logging.info('更新工作指令完成:%s' % cnc_workorder)
pre_workorder = productions.workorder_ids.filtered(
lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done', 'rework'
'cancel'] and ap.processing_panel == panel)
if pre_workorder:
logging.info('更新加工图纸:%s' % pre_workorder)
pre_workorder.write(
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
logging.info('更新加工图纸完成:%s' % pre_workorder)
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
logging.info('已更新制造订单编程状态:%s' % productions.ids)
res.update({
'production_ids': productions.ids
})
# 对制造订单所以面的cnc工单的程序用刀进行校验
try:
logging.info(f'已更新制造订单:{productions}')
productions.production_cnc_tool_checkout()
except Exception as e:
logging.info(f'对cnc工单的程序用刀进行校验报错{e}')
return json.JSONEncoder().encode(res)
return json.JSONEncoder().encode(res)
else:
res = {'status': 0, 'message': '该制造订单暂未开始'}
return json.JSONEncoder().encode(res)
except Exception as e:
res = {'status': -1, 'message': '系统解析失败'}
request.cr.rollback()
logging.info('get_cnc_processing_create error:%s' % e)
return json.JSONEncoder().encode(res)

View File

@@ -75,7 +75,7 @@ class sf_production_plan(models.Model):
if self.date_planned_start:
self.date_planned_finished = self.date_planned_start + timedelta(hours=1)
#处理计划状态非待排程,计划结束时间为空的数据处理
# 处理计划状态非待排程,计划结束时间为空的数据处理
def deal_no_date_planned_finished(self):
plans = self.env['sf.production.plan'].search(
[('date_planned_finished', '=', False), ('state', 'in', ['processing', 'done', 'finished'])])
@@ -90,6 +90,7 @@ class sf_production_plan(models.Model):
for item in plans:
if item.date_planned_start:
item.order_deadline = item.date_planned_start + timedelta(days=7)
@api.model
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None):
@@ -218,7 +219,7 @@ class sf_production_plan(models.Model):
return num
def do_production_schedule(self):
def do_production_schedule(self, count=1):
"""
排程方法
"""
@@ -226,7 +227,7 @@ class sf_production_plan(models.Model):
if not record.production_line_id:
raise ValidationError("未选择生产线")
else:
is_schedule = self.deal_processing_schedule(record.date_planned_start)
is_schedule = self.deal_processing_schedule(record.date_planned_start, count)
if not is_schedule:
raise ValidationError("排程失败")
workorder_id_list = record.production_id.workorder_ids.ids
@@ -281,7 +282,7 @@ class sf_production_plan(models.Model):
}
# 处理是否可排程
def deal_processing_schedule(self, date_planned_start):
def deal_processing_schedule(self, date_planned_start, count):
for record in self:
workcenter_ids = record.production_line_id.mrp_workcenter_ids
if not workcenter_ids:
@@ -296,7 +297,7 @@ class sf_production_plan(models.Model):
raise UserError('当前计划开始时间不能预约排程,请在工作时间内排程')
if not production_lines.deal_available_default_capacity(date_planned_start): # 判断生产线是否可排程
raise UserError('当前计划开始时间不能预约排程,生产线今日没有可排程的资源')
if not production_lines.deal_available_single_machine_capacity(date_planned_start): # 判断生产线是否可排程
if not production_lines.deal_available_single_machine_capacity(date_planned_start, count): # 判断生产线是否可排程
raise UserError('当前计划开始时间不能预约排程,生产线该时间段没有可排程的资源')
return True

View File

@@ -33,7 +33,9 @@ class Action_Plan_All_Wizard(models.TransientModel):
# 使用传递过来的计划ID
temp_plan_ids = self.plan_ids
# 在这里添加您的逻辑来处理这些ID
count = len(temp_plan_ids) + 1
for plan in temp_plan_ids:
count = count - 1
# 处理每个计划
# 比如更新计划状态、分配资源等
# 示例plan.state = 'scheduled'
@@ -42,7 +44,7 @@ class Action_Plan_All_Wizard(models.TransientModel):
plan_obj = self.env['sf.production.plan'].browse(plan.id)
plan_obj.production_line_id = self.production_line_id.id
plan.date_planned_start = self.date_planned_start
plan_obj.do_production_schedule()
plan_obj.do_production_schedule(count)
# plan_obj.state = 'done'
print('处理计划:', plan.id, '完成')

View File

@@ -13,10 +13,11 @@
'author': 'jikimo',
'website': 'https://sf.cs.jikimo.com',
# 此处依赖sf_manufacturing是因为我要重写其中的一个字段operation_id的string故需要sf_manufacturing先安装
'depends': ['quality_control'],
'depends': ['quality_control', 'web_widget_model_viewer', 'sf_manufacturing'],
'data': [
'security/ir.model.access.csv',
'views/view.xml'
'views/view.xml',
'views/quality_cnc_test_view.xml'
],
'assets': {

View File

@@ -3,3 +3,4 @@
from . import custom_quality
from . import quality
from . import quality_cnc_test

View File

@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class SfQualityCncTest(models.Model):
_name = 'quality.cnc.test'
_description = 'CNC加工质检'
name = fields.Char('单号', default=lambda self: self.env['ir.sequence'].next_by_code('quality.cnc.test'))
workorder_id = fields.Many2one('mrp.workorder')
production_id = fields.Many2one(related='workorder_id.production_id', string='制造订单')
product_id = fields.Many2one(related='workorder_id.product_id', string='产品')
model_file = fields.Binary(related='workorder_id.glb_file', string='加工模型')
processing_panel = fields.Char(related='workorder_id.processing_panel', string='加工面')
equipment_id = fields.Many2one(related='workorder_id.equipment_id', string='加工设备')
production_line_id = fields.Many2one(related='workorder_id.production_line_id',
string='生产线')
part_number = fields.Char(related='workorder_id.part_number', string='成品零件图号')
detection_report = fields.Binary(related='workorder_id.detection_report', readonly=True, string='检测报告')
state = fields.Selection([
('waiting', '待判定'),
('done', '已完成')], string='状态', default='waiting')
result = fields.Selection([
('pass', '合格'),
('fail', '不合格')], string='判定结果')
number = fields.Integer('数量', default=1)
test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], string="检测结果")
reason = fields.Selection(
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"), ("operate computer", "操机"),
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因")
detailed_reason = fields.Text('详细原因')
# machining_drawings = fields.Binary(related='workorder_id.machining_drawings', string='2D加工图纸', readonly=True)
# quality_standard = fields.Binary(related='workorder_id.quality_standard', string='质检标准', readonly=True)
def submit_pass(self):
if self.test_results in ['返工', '报废']:
raise UserError(_('请重新选择【判定结果】-【检测结果】'))
self.write({'result': 'pass', 'test_results': '合格', 'state': 'done'})
self.workorder_id.write({'test_results': self.test_results})
self.workorder_id.button_finish()
def submit_fail(self):
if not self.test_results:
raise UserError(_('请填写【判定结果】里的信息'))
if self.test_results == '合格':
raise UserError(_('请重新选择【判定结果】-【检测结果】'))
self.write({'result': 'fail', 'test_results': self.test_results, 'state': 'done'})
self.workorder_id.write(
{'test_results': self.test_results, 'reason': self.reason, 'detailed_reason': self.detailed_reason})
self.workorder_id.button_finish()
@api.onchange('test_results')
def _onchange_test_results(self):
if self.test_results == '合格':
self.reason = False
self.detailed_reason = False
class SfQualityWorkOrder(models.Model):
_inherit = 'mrp.workorder'
def button_finish(self):
super(SfQualityWorkOrder, self).button_finish()
if self.routing_type == 'CNC加工':
quality_cnc_test = self.env['quality.cnc.test'].search([('workorder_id', '=', self.id)])
if quality_cnc_test:
quality_cnc_test.write({'result': 'fail' if self.test_results in ['返工', '报废'] else 'pass',
'test_results': self.test_results, 'state': 'done',
'reason': self.reason,
'detailed_reason': self.detailed_reason,
'detection_report': self.detection_report})
def write(self, vals):
res = super(SfQualityWorkOrder, self).write(vals)
for item in self:
if item.state == 'to be detected':
quality_cnc_test = self.env['quality.cnc.test'].search([('workorder_id', '=', item.id)])
if not quality_cnc_test:
self.env['quality.cnc.test'].sudo().create({'workorder_id': item.id})
return res

View File

@@ -67,5 +67,11 @@ access_quality_alert_stage,quality.alert.stage,quality.model_quality_alert_stage
access_stock_move_group_quality,stock_move_group_quality,stock.model_stock_move,sf_base.group_quality,1,1,0,0
access_stock_move_group_quality_director,stock_move_group_quality_director,stock.model_stock_move,sf_base.group_quality_director,1,1,0,0
access_quality_cnc_test_group_quality,quality_cnc_test_group_quality,model_quality_cnc_test,sf_base.group_quality,1,1,0,0
access_quality_cnc_test_group_quality_director,quality_cnc_test_group_quality_director,model_quality_cnc_test,sf_base.group_quality_director,1,1,0,0
access_quality_cnc_test_group_sf_equipment_user,quality_cnc_test_group_sf_equipment_user,model_quality_cnc_test,sf_base.group_sf_equipment_user,1,1,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
67
68
69
70
71
72
73
74
75
76
77

View File

@@ -0,0 +1,195 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="sequence_quality_cnc_test" model="ir.sequence">
<field name="name">加工质检单编码规则</field>
<field name="code">quality.cnc.test</field>
<field name="prefix">QCT</field>
<field name="padding">5</field>
<field name="company_id" eval="False"/>
</record>
<record id="quality_cnc_test_view_tree" model="ir.ui.view">
<field name="name">quality.cnc.test.view.tree</field>
<field name="model">quality.cnc.test</field>
<field name="arch" type="xml">
<tree sample="1">
<field name="name"/>
<field name="production_id"/>
<field name="processing_panel"/>
<field name="product_id"/>
<field name="part_number"/>
<field name="number"/>
<field name="state" widget="badge"
decoration-success="state == 'done'"
decoration-warning="state == 'waiting'"/>
<field name="result" widget="badge"
decoration-success="result == 'pass'"
decoration-danger="result == 'fail'"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="quality_cnc_test_search">
<field name="name">search.quality.cnc.test</field>
<field name="model">quality.cnc.test</field>
<field name="arch" type="xml">
<search string="加工质检">
<filter name="filter_waiting" string="待判定" domain="[('state', '=', 'waiting')]"/>
<separator/>
<field name="production_id" string="制造订单"
filter_domain="[('production_id', 'ilike', self)]"/>
<field name="product_id" string="产品"
filter_domain="[('product_id', 'ilike', self)]"/>
<searchpanel>
<field name="state" icon="fa-filter" enable_counters="1"/>
<field name="result" icon="fa-filter" enable_counters="1"/>
</searchpanel>
</search>
</field>
</record>
<record id="action_quality_cnc_test" model="ir.actions.act_window">
<field name="name">加工质检</field>
<field name="res_model">quality.cnc.test</field>
<field name="view_mode">tree,form</field>
<field name="context">{ 'search_default_filter_waiting':1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
暂无加工质检单
</p>
</field>
</record>
<record model="ir.ui.view" id="quality_cnc_test_view_form">
<field name="name">quality.cnc.test.form.</field>
<field name="model">quality.cnc.test</field>
<field name="arch" type="xml">
<form>
<header>
<button string="合格" type="object" name="submit_pass"
class="oe_highlight" confirm="是否确认提交?"
attrs="{'invisible': [('result','!=', False)]}"/>
<button string="不合格" type="object" name="submit_fail"
class="oe_highlight" confirm="是否确认提交?"
attrs="{'invisible': [('result','!=', False)]}"/>
<field name="state" widget="statusbar"/>
<field name="result" invisible="1"/>
</header>
<sheet>
<h2>
<field name="name" readonly="1"/>
</h2>
<group>
<group>
<field name="production_id"/>
<field name="product_id"/>
<field name="production_line_id"/>
<field name="equipment_id"/>
<field name="model_file" widget="Viewer3D"/>
</group>
<group>
<field name="part_number"/>
<field name="processing_panel"/>
</group>
</group>
<notebook>
<page string="检测报告">
<field name="detection_report" string="" widget="pdf_viewer"/>
</page>
<page string="判定结果">
<group>
<field name="test_results" attrs="{'readonly': [('state','=', 'done')]}"/>
<field name="reason"
attrs="{'readonly': [('state','=', 'done')],'required': [('test_results','in', ['返工','报废'])],'invisible': [('test_results','in', ['合格',False])]}"/>
<field name="detailed_reason"
attrs="{'readonly': [('state','=', 'done')],'required': [('reason','!=', False)],'invisible': [('test_results','in', ['合格',False])]}"/>
</group>
</page>
<page string="2D图纸">
<!-- <field name="machining_drawings" string="" widget="pdf_viewer"/>-->
</page>
<page string="客户质量标准">
<!-- <field name="quality_standard" string=""/>-->
</page>
<page string="其他" attrs="{'invisible': [('state','=', 'waiting')]}">
<group>
<field name="write_uid" widget='many2one_avatar_user' string="判定人" readonly="1"/>
<field name="write_date" string="判定时间" readonly="1"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="quality_cnc_test_view_kanban" model="ir.ui.view">
<field name="name">quality.cnc.test.view.kanban</field>
<field name="model">quality.cnc.test</field>
<field name="arch" type="xml">
<kanban sample="1" class="o_kanban_product_template">
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_card oe_kanban_global_click">
<div class="oe_kanban_details">
<div class="o_kanban_record_top mb-0">
<div class="o_kanban_record_headings">
<strong class="o_kanban_record_title">
<field name="name"/>
</strong>
</div>
</div>
<div>
<div>
<field name="production_id"/>
</div>
<div>
<field name="processing_panel"/>
</div>
<div>
<field name="test_results"
widget="label_selection"
options="{'classes': {'合格': 'success', '返工': 'warning', '报废': 'danger'}}"/>
</div>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<menuitem
id="menu_quality_cnc_test"
name="加工质检"
action="action_quality_cnc_test"
sequence="21"
parent="quality_control.menu_quality_control"
/>
<record id="action_quality_cnc_test_kanban" model="ir.actions.act_window">
<field name="name">驾驶舱</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">quality.cnc.test</field>
<field name="view_mode">kanban,tree,form</field>
<field name="view_id" ref="quality_cnc_test_view_kanban"/>
<field name="search_view_id" ref="quality_cnc_test_search"/>
<field name="domain">[]</field>
<field name="context">{ 'search_default_filter_waiting':1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
暂无加工质检单
</p>
</field>
</record>
<menuitem id="menu_quality_cnc_test_dashboard"
name="驾驶舱"
action="action_quality_cnc_test_kanban"
parent="quality_control.menu_quality_root"
sequence="5"/>
</odoo>

View File

@@ -39,9 +39,9 @@
<field name="model">quality.point</field>
<field name="inherit_id" ref="quality.quality_point_view_form"/>
<field name="arch" type="xml">
<!-- <xpath expr="//sheet//group//group//field[@name='title']" position="replace"> -->
<!-- <field name="title" class="custom_required" required="1"/> -->
<!-- </xpath> -->
<!-- <xpath expr="//sheet//group//group//field[@name='title']" position="replace"> -->
<!-- <field name="title" class="custom_required" required="1"/> -->
<!-- </xpath> -->
<xpath expr="//sheet//group//group//field[@name='title']" position="attributes">
<attribute name="class">custom_required</attribute>
<attribute name="required">1</attribute>

View File

@@ -55,6 +55,8 @@ class ReSaleOrder(models.Model):
store=True, readonly=False, copy=False, precompute=True,
states=READONLY_FIELD_STATES, default=fields.Datetime.now)
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效')
# 业务平台分配工厂后在智能工厂先创建销售订单
def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address,
deadline_of_delivery, payments_way, pay_way):
@@ -125,7 +127,9 @@ class ReSaleOrder(models.Model):
'price_unit': product.list_price,
'product_uom_qty': item['number'],
'model_glb_file': base64.b64decode(item['model_file']),
'remark': item.get('remark')
'remark': item.get('remark'),
'is_incoming_material': item.get('is_incoming_material'),
'incoming_size': item.get('incoming_size'),
}
return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
@@ -166,6 +170,9 @@ class ResaleOrderLine(models.Model):
check_status = fields.Selection(related='order_id.check_status')
remark = fields.Char('备注')
is_incoming_material = fields.Boolean('是否带料', default=False)
incoming_size = fields.Char('带料尺寸')
@api.depends('product_template_id')
def _compute_model_glb_file(self):
for line in self:

View File

@@ -80,8 +80,8 @@
<field name="unit_price"/>
<field name="price" options="{'format': false}"/>
<field name="part_drawing_number"/>
<field name="machining_drawings" filename="machining_drawings_name" widget="pdf_viewer"/>
<field name="machining_drawings_name" invisible="1"/>
<!-- <field name="machining_drawings" filename="machining_drawings_name" widget="pdf_viewer"/>-->
<!-- <field name="machining_drawings_name" invisible="1"/>-->
<field name="sale_order_id"
attrs='{"invisible": [("sale_order_id","=",False)],"readonly": [("sale_order_id","!=",False)]}'/>
</group>

View File

@@ -17,11 +17,6 @@
<xpath expr="//field[@name='user_id']" position="replace">
<field name="user_id" widget="many2one_avatar_user" context="{'is_sale': True }"/>
</xpath>
<xpath expr="//form/header/button[@name='action_quotation_send'][1]" position="replace">
<button name="action_quotation_send" string="通过EMAIL发送" type="object"
class="btn-primary" data-hotkey="g" context="{'validate_analytic': True}"
attrs="{'invisible': ['|','&amp;',('check_status', '!=', 'approved'),('state', 'in', ['draft','cancel']),'&amp;',('check_status', '=', 'approved'),('state', 'in', ['sale','cancel'])]}"/>
</xpath>
<xpath expr="//form/header/button[@name='action_confirm']" position="after">
<button name="submit" string="提交" type="object"
context="{'default_order_id':active_id}"
@@ -52,6 +47,39 @@
</attribute>
<attribute name="string">拒绝接单</attribute>
</xpath>
<!-- ======================= 销售订单按钮顺序优化 start ======================= -->
<xpath expr="//form/header/button[@name='action_quotation_send'][1]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//form/header/button[@name='action_quotation_send'][4]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//form/header/button[@id='create_invoice']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//form/header/button[@id='create_invoice_percentage']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//form/header/button[@name='action_cancel']" position="after">
<button id="create_invoice" name="%(sale.action_view_sale_advance_payment_inv)d"
string="创建结算单"
type="action" class="btn-primary" data-hotkey="q"
attrs="{'invisible': [('invoice_status', '!=', 'to invoice')]}"/>
<button id="create_invoice_percentage" name="%(sale.action_view_sale_advance_payment_inv)d"
string="创建结算单"
type="action" context="{'default_advance_payment_method': 'percentage'}" data-hotkey="q"
attrs="{'invisible': ['|',('invoice_status', '!=', 'no'), ('state', '!=', 'sale')]}"/>
<button name="action_quotation_send" string="通过EMAIL发送" type="object"
class="btn-primary" data-hotkey="g" context="{'validate_analytic': True}"
attrs="{'invisible': ['|','&amp;',('check_status', '!=', 'approved'),('state', 'in', ['draft','cancel']),'&amp;',('check_status', '=', 'approved'),('state', 'in', ['sale','cancel'])]}"/>
<button name="action_quotation_send" string="通过EMAIL发送" type="object" states="sent,sale"
data-hotkey="g" context="{'validate_analytic': True}"/>
</xpath>
<!-- ====================== 销售订单按钮顺序优化 end======================== -->
<xpath expr="//form/header/button[@name='action_draft']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
@@ -67,7 +95,7 @@
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
</field>
<field name="payment_term_id" position="after">
<field name="deadline_of_delivery" attrs="{'readonly': [('state', 'in', ('sale','cancel'))]}"/>
<field name="deadline_of_delivery" readonly="1"/>
<field name="payments_way" attrs="{'readonly': [('state', 'in', ('sale','cancel'))]}"/>
<field name="pay_way" attrs="{'readonly': [('state', 'in', ('sale','cancel'))]}"/>
<!-- <field name="schedule_status" readonly="1"/> -->
@@ -78,6 +106,7 @@
</xpath>
<xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after">
<field name="remark"/>
</xpath>
<xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="attributes">
<attribute name="options">{'no_create': True}</attribute>
@@ -89,6 +118,8 @@
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="replace">
<field name="name" widget="section_and_note_text" optional="show"
string="参数说明(长/宽/高/体积/精度/材质)"/>
<field name="is_incoming_material" optional="hide"/>
<field name="incoming_size" optional="hide"/>
</xpath>
<field name="user_id" position="attributes">
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
@@ -133,6 +164,11 @@
<xpath expr="//button[@name='action_cancel']" position="attributes">
<attribute name="string">拒绝接单</attribute>
</xpath>
<!--新增带料字段-->
<xpath expr="//field[@name='order_line']/form//group//group//field[@name='analytic_distribution']" position="after">
<field name="is_incoming_material"/>
<field name="incoming_size" attrs="{'invisible': [('is_incoming_material', '=', False)],'readonly':1}"/>
</xpath>
</field>
</record>
@@ -180,6 +216,20 @@
</field>
</record>
<record id="sale_order_view_search_inherit_sale_message" model="ir.ui.view">
<field name="name">sale.order.message.search.view</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.sale_order_view_search_inherit_sale"/>
<field name="mode">primary</field>
<field name="arch" type="xml">
<xpath expr="//filter[@name='upselling']" position="after">
<separator/>
<filter string="预警" name="filter_order_warning" domain="[('delivery_warning', '=', 'warning')]"/>
<filter string="逾期" name="filter_order_overdue" domain="[('delivery_warning', '=', 'overdue')]"/>
</xpath>
</field>
</record>
<record id="view_order_tree_inherit_sf" model="ir.ui.view">
<field name="name">sale.order.tree</field>
<field name="model">sale.order</field>
@@ -189,18 +239,15 @@
<!-- <attribute name="default_order">schedule_status desc,date_order asc</attribute> -->
<attribute name="default_order">create_date desc</attribute>
<attribute name="create">False</attribute>
<attribute name="decoration-warning">delivery_warning == 'warning'</attribute>
<attribute name="decoration-danger">delivery_warning == 'overdue'</attribute>
</tree>
<field name="name" position="attributes">
<attribute name="string">订单号</attribute>
</field>
<!-- <field name="amount_total" position="after"> -->
<!-- <field name="schedule_status" widget="badge" -->
<!-- decoration-success="schedule_status == 'received'" -->
<!-- decoration-warning="schedule_status == 'to process'" -->
<!-- decoration-danger="schedule_status == 'to receive'" -->
<!-- decoration-muted="schedule_status == 'to process'" -->
<!-- decoration-info="schedule_status == 'to schedule'"/> -->
<!-- </field> -->
<field name="amount_total" position="after">
<field name="delivery_warning" invisible="1"/>
</field>
</field>
</record>
@@ -230,5 +277,12 @@
"search_default_filter_to_sell":1,"sale_multi_pricelist_product_template": 1}
</field>
</record>
<record id="sale.action_orders" model="ir.actions.act_window">
<field name="search_view_id" ref="sale_order_view_search_inherit_sale_message"/>
<field name="context">{ 'search_default_filter_order_warning':1,'search_default_filter_order_overdue':1}
</field>
</record>
</data>
</odoo>

View File

@@ -6,7 +6,7 @@
'summary': '智能工厂刀具管理',
'sequence': 1,
'description': """
在本模块,定义了主要的角色、菜单、基础业务对象
在本模块,定义了刀具相关的模型和视图,以及相关的业务逻辑。
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',

View File

@@ -234,7 +234,7 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
sf_functional_tool_assembly_id = fields.Many2one('sf.functional.tool.assembly', '功能刀具组装', readonly=True)
active = fields.Boolean(string='已归档', default=True)
active = fields.Boolean(string='已归档', default=True, groups='base.user_root')
@api.depends('functional_tool_name')
def _compute_tool_number(self):
@@ -314,37 +314,41 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'applicant': None,
'sf_functional_tool_assembly_id': None})
def create_cam_work_plan(self, cnc_processing):
def create_cam_work_plan(self, cnc_ids):
"""
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
"""
# 获取编程单号
programming_no = cnc_processing.workorder_id.production_id.programming_no
programming_no = cnc_ids[0].workorder_id.production_id.programming_no
logging.info(f'编程单号:{programming_no}')
cam_id = self.env['sf.cam.work.order.program.knife.plan'].sudo().search(
[('programming_no', '=', programming_no),
('functional_tool_name', '=', cnc_processing.cutting_tool_name)])
logging.info(f'CAM装刀计划{cam_id}')
if not cam_id:
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
'name': cnc_processing.workorder_id.production_id.name,
'programming_no': programming_no,
'cam_procedure_code': cnc_processing.program_name,
'filename': cnc_processing.cnc_id.name,
'functional_tool_name': cnc_processing.cutting_tool_name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'process_type': cnc_processing.processing_type,
'margin_x_y': float(cnc_processing.margin_x_y),
'margin_z': float(cnc_processing.margin_z),
'finish_depth': float(cnc_processing.depth_of_processing_z),
'extension_length': float(cnc_processing.cutting_tool_extension_length),
'shank_model': cnc_processing.cutting_tool_handle_type,
'estimated_processing_time': cnc_processing.estimated_processing_time,
})
logging.info('CAM工单程序用刀计划创建成功')
# 创建装刀请求
knife_plan.apply_for_tooling()
for cnc_processing in cnc_ids:
tool_name = cnc_processing.cutting_tool_name
cam_id = self.env['sf.cam.work.order.program.knife.plan'].sudo().search(
[('programming_no', '=', programming_no),
('functional_tool_name', '=', tool_name)])
if cam_id:
logging.info(f'编程单号{programming_no}功能刀具名称{tool_name}已存在CAM装刀计划{cam_id}')
else:
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
'name': cnc_processing.workorder_id.production_id.name,
'programming_no': programming_no,
'cam_procedure_code': cnc_processing.program_name,
'filename': cnc_processing.cnc_id.name,
'functional_tool_name': tool_name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'process_type': cnc_processing.processing_type,
'margin_x_y': float(cnc_processing.margin_x_y),
'margin_z': float(cnc_processing.margin_z),
'finish_depth': float(cnc_processing.depth_of_processing_z),
'extension_length': float(cnc_processing.cutting_tool_extension_length),
'shank_model': cnc_processing.cutting_tool_handle_type,
'estimated_processing_time': cnc_processing.estimated_processing_time,
})
logging.info(f'创建CAM工单程序用刀计划{knife_plan}')
# 创建装刀请求
knife_plan.apply_for_tooling()
logging.info('CAM工单程序用刀计划创建已完成')
def unlink_cam_plan(self, production):
for item in production:
@@ -1275,7 +1279,7 @@ class FunctionalToolDismantle(models.Model):
item.picking_num = 0
state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解', tracking=True)
active = fields.Boolean('有效', default=True)
active = fields.Boolean('有效', default=True, groups='base.user_root')
# 刀柄
handle_product_id = fields.Many2one('product.product', string='刀柄', compute='_compute_functional_tool_num',

View File

@@ -402,7 +402,7 @@ class FunctionalToolWarning(models.Model):
dispose_time = fields.Char('处理时间', readonly=True)
dispose_func = fields.Char('处理方法/措施', readonly=True)
active = fields.Boolean(string='已归档', default=True)
active = fields.Boolean(string='已归档', default=True, groups='base.user_root')
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具名称')

View File

@@ -29,7 +29,7 @@ class CNCprocessing(models.Model):
# else:
# raise ValidationError("MES装刀指令发送失败")
def cnc_tool_checkout(self, cnc_processing_ids):
def cnc_tool_checkout_1(self, cnc_processing_ids):
"""
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
"""
@@ -128,13 +128,6 @@ class CNCprocessing(models.Model):
})
logging.info('工单cnc程序用刀校验已完成')
@api.model_create_multi
def create(self, vals):
obj = super(CNCprocessing, self).create(vals)
# 调用CAM工单程序用刀计划创建方法
self.cnc_tool_checkout(obj)
return obj
class MrpWorkCenter(models.Model):
_inherit = 'mrp.workcenter'
@@ -143,3 +136,88 @@ class MrpWorkCenter(models.Model):
action = self.env.ref('sf_tool_management.sf_functional_tool_assembly_view_act')
result = action.read()[0]
return result
class MrpProduction(models.Model):
_inherit = 'mrp.production'
def production_cnc_tool_checkout(self):
logging.info('开始进行工单cnc程序用刀校验')
invalid_tool = [] # 无效刀
invalid_tool_processing_panel = [] # 无效刀加工面
missing_tool_1 = [] # 缺刀(机内、线边)
missing_tool_2 = [] # 缺刀(库存)
for item in self:
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ['rework', 'cancel'])
for workorder_id in workorder_ids:
if workorder_id.cnc_ids:
for cnc_id in workorder_id.cnc_ids:
tool_name = cnc_id.cutting_tool_name
# 查询功能刀具在清单中是否存在
tool_inventory_id = self.env['sf.tool.inventory'].sudo().search([('name', '=', tool_name)])
if not tool_inventory_id:
invalid_tool.append(tool_name)
invalid_tool_processing_panel.append(workorder_id.processing_panel)
continue
# 查询功能刀具是否存在库存
functional_tools = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('tool_name_id', '=', tool_inventory_id.id), ('functional_tool_status', '=', '正常')])
if not functional_tools.filtered(lambda p: p.current_location in ('线边刀库', '机内刀库')):
missing_tool_1.append(tool_name) # 判断为 ('线边刀库', '机内刀库') 缺刀
if not functional_tools:
missing_tool_2.append(tool_name) # 判断为 库存缺刀
break
# 修改cnc程序的刀具状态
workorder_ids = self.env['mrp.workorder'].sudo().search([('production_id', 'in', self.ids)])
if invalid_tool:
logging.info(f'无效刀:{invalid_tool}')
# 修改cnc程序的刀具状态为 ‘无效刀’
cnc_ids = self.env['sf.cnc.processing'].sudo().search(
[('workorder_id', 'in', workorder_ids.ids), ('cutting_tool_name', 'in', invalid_tool)])
if cnc_ids:
for cnc_id in cnc_ids:
cnc_id.tool_state = '2'
# cnc_ids.write({'tool_state': '2'})
# 创建制造订单无效刀检测结果记录
for production_id in self:
for processing_panel in list(set(invalid_tool_processing_panel)):
if not production_id.detection_result_ids.filtered(
lambda a: (a.processing_panel == processing_panel and a.detailed_reason == '无效功能刀具'
and a.handle_result == '待处理' and a.routing_type == 'CNC加工'
and a.rework_reason == 'programming' and a.test_results == '返工')):
production_id.detection_result_ids.create({
'production_id': production_id.id,
'processing_panel': processing_panel,
'routing_type': 'CNC加工',
'rework_reason': 'programming', # 原因:编程(programming)
'detailed_reason': '无效功能刀具',
'test_results': '返工',
'handle_result': '待处理'
})
# 自动调用重新获取编程的方法
logging.info('cnc用刀校验到无效刀自动调用重新编程方法update_programming_state()')
self[0].update_programming_state()
self[0].write({'is_rework': False})
# 修改制造订单 编程状态变为“编程中” 制造订单状态为‘返工’
self.write({'programming_state': '编程中', 'work_state': '编程中', 'state': 'rework'})
if missing_tool_1:
logging.info(f'线边、机内缺刀:{missing_tool_1}')
# 修改 修改cnc程序的刀具状态 为 ‘缺刀’
cnc_ids = self.env['sf.cnc.processing'].sudo().search(
[('workorder_id', 'in', workorder_ids.ids), ('cutting_tool_name', 'in', missing_tool_1)])
if cnc_ids:
for cnc_id in cnc_ids:
cnc_id.tool_state = '1'
# cnc_ids.write({'tool_state': '1'})
if missing_tool_2 and invalid_tool == []:
logging.info(f'库存缺刀:{missing_tool_2}')
# 调用CAM工单程序用刀计划创建方法
cnc_ids = self.env['sf.cnc.processing'].sudo().search(
[('workorder_id', 'in', workorder_ids.filtered(lambda a: a.production_id == self[0]).ids),
('cutting_tool_name', 'in', missing_tool_2)])
if cnc_ids:
logging.info('调用CAM工单程序用刀计划创建方法')
self.env['sf.cam.work.order.program.knife.plan'].sudo().create_cam_work_plan(cnc_ids)
if not invalid_tool and not missing_tool_1:
logging.info('校验cnc用刀正常!')
logging.info('工单cnc程序用刀校验完成')

View File

@@ -10,7 +10,6 @@
<field name="barcode_id" invisible="1"/>
<field name="rfid"/>
<field name="tool_name_id"/>
<field name="image" widget='image'/>
<field name="tool_groups_id"/>
<field name="functional_tool_diameter"/>
<field name="knife_tip_r_angle"/>

View File

@@ -40,7 +40,7 @@
<field name="cutting_tool_model_id"/>
<field name="specification_id"/>
<field name="brand_id"/>
<field name="qty_available"/>
<field name="qty_available" string="库存数量"/>
</tree>
</field>
</page>

View File

@@ -338,7 +338,7 @@ class ShelfLocation(models.Model):
_name = 'sf.shelf.location'
_inherit = ['printing.utils']
_description = '货位'
_rec_name = 'barcode'
# _rec_name = 'barcode'
_order = 'id asc, create_date asc'
# current_location_id = fields.Many2one('sf.shelf.location', string='当前位置')

View File

@@ -0,0 +1,160 @@
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import os
from ftplib import FTP
import win32gui
import win32con
import logging
import time
# 配置日志记录
logging.basicConfig(filename='service.log', level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
app = FastAPI()
class FileUploadRequest(BaseModel):
filename: str
# FTP 服务器配置信息
ftp_host = '110.52.114.162'
ftp_port = 10021
ftp_user = 'ftpuser'
ftp_password = '123456'
ftp_directory = '/home/ftp/ftp_root/ThreeTest/XT/Before/'
def find_child_window(parent_hwnd, class_name):
def enum_child_windows(hwnd, lparam):
class_name = win32gui.GetClassName(hwnd)
if class_name == lparam:
child_hwnds.append(hwnd)
return True
child_hwnds = []
win32gui.EnumChildWindows(parent_hwnd, enum_child_windows, class_name)
return child_hwnds
def find_child_window_by_partial_title(parent_hwnd, partial_title):
def enum_child_windows(hwnd, lparam):
# 获取窗口的标题
title = win32gui.GetWindowText(hwnd)
# 检查标题是否包含指定的部分标题
if partial_title in title:
child_hwnds.append(hwnd)
return True
child_hwnds = []
win32gui.EnumChildWindows(parent_hwnd, enum_child_windows, None)
return child_hwnds
def find_child_window_by_title(parent_hwnd, title):
def enum_child_windows(hwnd, lparam):
if win32gui.GetWindowText(hwnd) == lparam:
child_hwnds.append(hwnd)
return True
child_hwnds = []
win32gui.EnumChildWindows(parent_hwnd, enum_child_windows, title)
return child_hwnds
def set_path_and_save(filename):
parent_hwnd = win32gui.FindWindow(None, '另存为')
if parent_hwnd == 0:
raise HTTPException(status_code=404, detail="没有找到保存报告的窗口,请检查!")
# 这里假设“地址:”是你需要的部分标题
address_hwnds = find_child_window_by_partial_title(parent_hwnd, "地址:")
# 确保找到的窗口句柄有效
if not address_hwnds:
raise HTTPException(status_code=404, detail="未找到地址框,请联系管理员!")
# 假设找到的第一个窗口是目标组件
address_hwnd = address_hwnds[0]
logging.info(f"找到地址框地址: {win32gui.GetWindowText(address_hwnd)}")
# 设置路径
local_file_path = os.path.join(win32gui.GetWindowText(address_hwnd).split(' ')[1], filename)
logging.info(f"设置路径: {local_file_path}")
path_hwnds = find_child_window(parent_hwnd, 'Edit')
if not path_hwnds:
raise HTTPException(status_code=404, detail="未找到路径框")
path_hwnd = path_hwnds[0]
win32gui.SendMessage(path_hwnd, win32con.WM_SETTEXT, 0, filename)
button_hwnds = find_child_window_by_title(parent_hwnd, '保存(&S)')
if not button_hwnds:
raise HTTPException(status_code=404, detail="未找到保存按钮")
save_button_hwnd = button_hwnds[0]
win32gui.PostMessage(save_button_hwnd, win32con.BM_CLICK, 0, 0)
return local_file_path
def wait_for_file_to_save(filepath, timeout=30):
start_time = time.time()
while time.time() - start_time < timeout:
if os.path.isfile(filepath):
return True
time.sleep(0.1)
return False
def upload_file_to_ftp(local_file):
if not os.path.isfile(local_file):
raise HTTPException(status_code=204, detail="文件未找到")
ftp = FTP()
try:
ftp.connect(ftp_host, ftp_port)
ftp.login(ftp_user, ftp_password)
ftp.cwd(ftp_directory)
with open(local_file, 'rb') as file:
ftp.storbinary(f'STOR {os.path.basename(local_file)}', file)
return True
except Exception as e:
print(f"文件上传失败: {e}")
return False
finally:
ftp.quit()
@app.post("/get/check/report")
async def upload_file(request: FileUploadRequest):
# 设置路径框并点击保存
local_file_path = set_path_and_save(request.filename)
logging.info(f"文件上传请求: {request.filename}")
logging.info(f"文件保存路径: {local_file_path}")
# 等待文件保存完成
if not wait_for_file_to_save(local_file_path):
raise HTTPException(status_code=500, detail="文件保存超时")
# 上传文件到 FTP
success = upload_file_to_ftp(local_file_path)
if success:
ftp_file_path = os.path.join(ftp_directory, request.filename)
return {"ftp_file_path": ftp_file_path}
else:
raise HTTPException(status_code=500, detail="文件上传失败")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)

View File

@@ -0,0 +1,5 @@
app.py是主程序文件主要功能是监听装夹自动保存文件并将其上传到FTP服务器。
需要讲app.py做成一个exe文件可以用pyinstaller工具。
然后在windows的计划任务中执行此exe文件即可。