Compare commits

...

134 Commits

Author SHA1 Message Date
guanhuan
9665cdfc84 发送消息添加权限 2024-10-29 08:58:33 +08:00
guanhuan
b4fbbd48fb 精度显示修改 2024-10-28 11:46:36 +08:00
guanhuan
3559d67c05 精度显示修改 2024-10-28 11:43:10 +08:00
guanhuan
18a7dbbff9 辅助文件上传 2024-10-28 10:21:33 +08:00
guanhuan
5363557faf 快速订单创建报错 2024-10-25 16:36:54 +08:00
guanhuan
4f1d518ef3 加工精度修改 2024-10-25 14:02:37 +08:00
guanhuan
86d97ef331 2D加工图纸和质检标准位置调整 2024-10-25 11:55:43 +08:00
guanhuan
519ce0d5bb 工单下发调整 2024-10-25 11:29:13 +08:00
管欢
ab10271b4d Accept Merge Request #1460: (feature/machining_accuracy_sync -> 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/1460
2024-10-25 09:04:47 +08:00
杨金灵
ee148239d2 Accept Merge Request #1459: (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/1459
2024-10-24 17:35:44 +08:00
jinling.yang
4cc03aee9b 优化模版 2024-10-24 17:35:21 +08:00
jinling.yang
31a703952c 修复销售订单和工单消息提醒 2024-10-24 17:32:40 +08:00
jinling.yang
ae08c5b56e Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-24 16:55:43 +08:00
jinling.yang
dc76dcdc2f Merge branch 'feature/修复销售订单完成时效' into develop 2024-10-24 16:52:08 +08:00
杨金灵
6a040d16ea Accept Merge Request #1458: (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/1458?initial=true
2024-10-24 16:51:52 +08:00
jinling.yang
30e8d04b70 添加销售订单是否完成并恢复正常时效定时器 2024-10-24 16:50:27 +08:00
jinling.yang
2b3375ad41 修复销售订单完成时效 2024-10-24 16:40:25 +08:00
jinling.yang
8a059a5520 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-24 16:20:38 +08:00
jinling.yang
49a2f02b54 Merge branch 'feature/修复工单提醒' into develop 2024-10-24 16:20:09 +08:00
禹翔辉
ef92f24d35 Accept Merge Request #1456: (feature/维保请求优化 -> develop)
Merge Request: 1、添加维保请求的相关权限;2、优化维保请求tree视图、form视图和搜索视图;

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1456
2024-10-24 16:18:08 +08:00
杨金灵
0207914592 Accept Merge Request #1457: (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/1457
2024-10-24 16:17:54 +08:00
jinling.yang
5776c97744 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/修复工单提醒 2024-10-24 16:16:11 +08:00
jinling.yang
180cdf2a08 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-24 16:15:51 +08:00
jinling.yang
47720948ff 修复工单提醒 2024-10-24 16:15:30 +08:00
yuxianghui
7814a2b622 Merge branch 'feature/工单状态优化' into feature/维保请求优化 2024-10-24 16:12:57 +08:00
yuxianghui
06981fb894 1、添加维保请求的相关权限;2、优化维保请求tree视图、form视图和搜索视图; 2024-10-24 16:12:09 +08:00
马广威
19dbd9901d Accept Merge Request #1455: (feature/制造功能优化 -> develop)
Merge Request: 处理工单的组件不存在时报错的问题

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1455?initial=true
2024-10-24 16:06:50 +08:00
mgw
4985b0a85d Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-10-24 16:05:03 +08:00
mgw
39f99d6ce7 处理工单的组件不存在时报错的问题 2024-10-24 16:04:38 +08:00
马广威
c8f25ea4b3 Accept Merge Request #1454: (feature/制造功能优化 -> develop)
Merge Request: 增加对Enter的判断

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1454?initial=true
2024-10-24 15:51:11 +08:00
mgw
cab9e08066 增加对Enter的判断 2024-10-24 15:50:32 +08:00
马广威
2b83f82989 Accept Merge Request #1453: (feature/制造功能优化 -> develop)
Merge Request: 将扫描rfid绑定并开启装夹工单写成widget形式

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1453
2024-10-24 15:34:06 +08:00
mgw
598e8fee9c Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-10-24 15:32:41 +08:00
mgw
6f3a788101 将扫描rfid绑定并开启装夹工单写成widget形式 2024-10-24 15:32:15 +08:00
jinling.yang
30ff349b37 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-24 15:17:59 +08:00
管欢
e264306fed Accept Merge Request #1452: (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/1452
2024-10-24 14:58:34 +08:00
jinling.yang
4018797384 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-24 14:57:01 +08:00
guanhuan
f557cb8d10 零件图纸,质检标准显示位置修改 2024-10-24 14:55:36 +08:00
jinling.yang
a1efde6ef9 Merge branch 'feature/修复销售订单逾期过期' into develop 2024-10-24 14:41:10 +08:00
杨金灵
cf34e28e35 Accept Merge Request #1451: (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/1451?initial=true
2024-10-24 14:40:28 +08:00
jinling.yang
b7595fe4ec Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/修复销售订单逾期过期 2024-10-24 14:28:07 +08:00
jinling.yang
2551d82a99 修复销售订单逾期过期 2024-10-24 14:27:44 +08:00
管欢
0cedba8ea4 Accept Merge Request #1450: (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/1450
2024-10-24 14:24:18 +08:00
guanhuan
d64a814251 制造订单零件图纸,质检标准显示 2024-10-24 11:33:10 +08:00
胡尧
86d5de4fa1 Accept Merge Request #1449: (feature/plan_slow -> develop)
Merge Request: 解决排程报错

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1449?initial=true
2024-10-24 11:30:06 +08:00
胡尧
ed15958319 解决报错 2024-10-24 11:29:36 +08:00
廖丹龙
0bf9c752f6 Accept Merge Request #1442: (feature/machining_accuracy_sync -> 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/1442
2024-10-24 11:23:20 +08:00
杨金灵
e62eb060fb Accept Merge Request #1448: (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/1448?initial=true
2024-10-24 10:54:00 +08:00
jinling.yang
563b44adb1 添加输出 2024-10-24 10:53:04 +08:00
jinling.yang
d28fd5d787 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-24 10:35:52 +08:00
jinling.yang
41c357d124 Merge branch 'feature/修复设备文件' into develop 2024-10-24 10:32:46 +08:00
杨金灵
f94d52a4d9 Accept Merge Request #1447: (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/1447?initial=true
2024-10-24 10:30:39 +08:00
jinling.yang
74dc31b083 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-24 10:28:41 +08:00
jinling.yang
3b1fca529a Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-24 10:28:07 +08:00
jinling.yang
843eeb8a89 修复设备文件 2024-10-24 10:27:46 +08:00
胡尧
12e81ec702 Accept Merge Request #1446: (feature/plan_slow -> develop)
Merge Request: 解决排程慢的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1446
2024-10-24 10:15:55 +08:00
jinling.yang
fe2af8a4ce Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into develop 2024-10-24 10:13:28 +08:00
jinling.yang
f337a30aba Merge branch 'feature/优化加工质检' into develop 2024-10-24 10:09:45 +08:00
杨金灵
7f3a8d877f Accept Merge Request #1445: (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/1445
2024-10-24 10:09:29 +08:00
jinling.yang
5e6a7d0a39 还原代码 2024-10-24 10:07:56 +08:00
jinling.yang
5788a157c5 还原代码 2024-10-24 10:03:18 +08:00
胡尧
0b70447333 修改排程逻辑 2024-10-24 09:47:20 +08:00
jinling.yang
de8ba77bef 优化加工质检页面 2024-10-24 09:22:35 +08:00
胡尧
1026c0edd0 修改排程逻辑 2024-10-24 09:18:21 +08:00
管欢
f366b650d0 Accept Merge Request #1444: (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/1444
2024-10-23 17:54:42 +08:00
guanhuan
6054ce39f3 附件文件名 2024-10-23 17:43:03 +08:00
禹翔辉
e1e9dc425b Accept Merge Request #1443: (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/1443
2024-10-23 17:12:17 +08:00
yuxianghui
3a2a942f3b Merge branch 'feature/设备维保优化' into feature/工单状态优化 2024-10-23 17:05:47 +08:00
yuxianghui
bf9d848f10 1、工单状态优化 2024-10-23 17:04:35 +08:00
禹翔辉
3fd17302f5 Accept Merge Request #1440: (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/1440
2024-10-23 15:51:06 +08:00
胡尧
db9cee3e28 Accept Merge Request #1441: (feature/workorder_exceptions -> develop)
Merge Request: 修改工单通知筛选条件

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1441?initial=true
2024-10-23 15:50:31 +08:00
胡尧
97a26dfa06 修改工单通知筛选条件 2024-10-23 15:50:01 +08:00
yuxianghui
cebd895811 Merge branch 'feature/设备模块优化' into feature/设备维保优化 2024-10-23 15:49:13 +08:00
yuxianghui
bb6c208d37 设备维保计划优化 2024-10-23 15:48:33 +08:00
胡尧
921f2c3503 Accept Merge Request #1439: (feature/workorder_exceptions -> develop)
Merge Request: 修改工单通知筛选条件

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1439?initial=true
2024-10-23 15:38:55 +08:00
胡尧
1224e0e094 修改工单通知筛选条件 2024-10-23 15:38:09 +08:00
胡尧
a571a870d3 修改工单通知筛选条件 2024-10-23 15:33:48 +08:00
胡尧
a28d20b3bf 修改排程逻辑 2024-10-23 15:30:05 +08:00
管欢
d4e0d36166 Accept Merge Request #1438: (feature/machining_accuracy_sync -> 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/1438
2024-10-23 14:00:41 +08:00
jinling.yang
39579aef10 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化加工质检
# Conflicts:
#	sf_message/models/sf_message_maintenance_logs.py
2024-10-23 11:56:16 +08:00
jinling.yang
1fe8fd6933 优化定时器代码 2024-10-23 11:55:43 +08:00
yuxianghui
98923c1797 1、设备维保优化 2024-10-22 17:52:20 +08:00
廖丹龙
a580a12d69 Accept Merge Request #1437: (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/1437?initial=true
2024-10-22 13:56:38 +08:00
liaodanlong
0d512e2e43 制造订单添加订单交期字段信息 2024-10-22 13:55:24 +08:00
廖丹龙
103069c554 Accept Merge Request #1436: (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/1436?initial=true
2024-10-22 13:48:28 +08:00
yuxianghui
f2482b5128 处理功能刀具产生库存移动时,功能刀具列表的功能刀具位置没有实时发生变更的问题 2024-10-22 13:45:08 +08:00
liaodanlong
da38d24111 制造订单添加订单交期字段信息 2024-10-22 13:33:53 +08:00
廖丹龙
1f0ebe71c7 Accept Merge Request #1435: (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/1435?initial=true
2024-10-22 11:56:28 +08:00
liaodanlong
f897955f68 制造订单添加订单交期字段信息 2024-10-22 11:45:08 +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
51 changed files with 1076 additions and 299 deletions

View File

@@ -21,8 +21,8 @@ class WorkorderExceptionConroller(http.Controller):
try: try:
res = {'Succeed': True, 'ErrorCode': 0, 'Error': ''} res = {'Succeed': True, 'ErrorCode': 0, 'Error': ''}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas)['Datas'] ret = json.loads(datas)
if not ret.get('RfidCode') or not ret.get('ErrorType'): if not ret.get('RfidCode') or not ret.get('coding'):
res = {'Succeed': False, 'ErrorCode': 400, 'Error': '参数错误'} res = {'Succeed': False, 'ErrorCode': 400, 'Error': '参数错误'}
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
@@ -38,7 +38,7 @@ class WorkorderExceptionConroller(http.Controller):
# 创建工单异常记录,关联工单 # 创建工单异常记录,关联工单
request.env['jikimo.workorder.exception'].sudo().create({ request.env['jikimo.workorder.exception'].sudo().create({
'workorder_id': workorder.id, 'workorder_id': workorder.id,
'exception_code': ret.get('ErrorType'), 'exception_code': ret.get('coding'),
'exception_content': ret.get('Error', '') 'exception_content': ret.get('Error', '')
}) })

View File

@@ -1,2 +1,5 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_jikimo_workorder_exception","access.jikimo.workorder.exception","model_jikimo_workorder_exception","mrp.group_mrp_user",1,1,1,0 "access_jikimo_workorder_exception","access.jikimo.workorder.exception","model_jikimo_workorder_exception","mrp.group_mrp_user",1,1,1,0
"access_jikimo_workorder_exception_group_quality","access.jikimo.workorder.exception.group_quality","model_jikimo_workorder_exception","sf_base.group_quality",1,1,1,0
"access_jikimo_workorder_exception_group_quality_director","access.jikimo.workorder.exception.group_quality_director","model_jikimo_workorder_exception","sf_base.group_quality_director",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
3 access_jikimo_workorder_exception_group_quality access.jikimo.workorder.exception.group_quality model_jikimo_workorder_exception sf_base.group_quality 1 1 1 0
4 access_jikimo_workorder_exception_group_quality_director access.jikimo.workorder.exception.group_quality_director model_jikimo_workorder_exception sf_base.group_quality_director 1 1 1 0
5

View File

@@ -10,7 +10,7 @@
<field name="urgency">urgent</field> <field name="urgency">urgent</field>
<field name="content">### 生产线无功能刀具提醒 <field name="content">### 生产线无功能刀具提醒
单号:工单[{{workorder_id.production_id.name}}]({{url}}) 单号:工单[{{workorder_id.production_id.name}}]({{url}})
原因:生产线无加工程序用的{{function_tool_name}}名称功能刀具</field> 原因:生产线无加工程序用的功能刀具</field>
</record> </record>
<record id="template_no_position_data" model="jikimo.message.template"> <record id="template_no_position_data" model="jikimo.message.template">
<field name="name">工单无定位数据提醒</field> <field name="name">工单无定位数据提醒</field>
@@ -19,7 +19,7 @@
<field name="bussiness_node_id" ref="bussiness_no_position_data"/> <field name="bussiness_node_id" ref="bussiness_no_position_data"/>
<field name="msgtype">markdown</field> <field name="msgtype">markdown</field>
<field name="urgency">urgent</field> <field name="urgency">urgent</field>
<field name="content">### 生产线无功能刀具提醒 <field name="content">### 工单无定位数据提醒
单号:工单[{{workorder_id.production_id.name}}]({{url}}) 单号:工单[{{workorder_id.production_id.name}}]({{url}})
原因:无装夹定位测量数据</field> 原因:无装夹定位测量数据</field>
</record> </record>

View File

@@ -34,7 +34,7 @@ class JikimoWorkorderException(models.Model):
rec.add_queue('无定位数据') rec.add_queue('无定位数据')
elif rec.exception_code == 'YC0004': elif rec.exception_code == 'YC0004':
# 无FTP文件调用cloud接口 # 无FTP文件调用cloud接口
data = {'name': rec.workorder_id.programming_no, 'exception_code': 'YC0004'} data = {'name': rec.workorder_id.production_id.programming_no, 'exception_code': 'YC0004'}
configsettings = self.env['res.config.settings'].sudo().get_values() configsettings = self.env['res.config.settings'].sudo().get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key']) config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/message/workorder_exception' url = '/api/message/workorder_exception'

View File

@@ -14,12 +14,25 @@ class TestJikimoWorkorderExceptionNotify(TestJikimoWorkorderExceptionNotifyCommo
('model', '=', 'jikimo.workorder.exception') ('model', '=', 'jikimo.workorder.exception')
])) ]))
self.assertTrue(self.env['jikimo.message.template'].search([ self.assertTrue(self.env['jikimo.message.template'].search([
('name', '=', '加工失败'), ('name', '=', '工单加工失败提醒'),
('model', '=', 'jikimo.workorder.exception') ('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程序'
})
def test_create_message_queue(self): 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({ exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id, 'workorder_id': self.workorder.id,
'exception_code': 'YC0002', 'exception_code': 'YC0002',
@@ -44,6 +57,44 @@ class TestJikimoWorkorderExceptionNotify(TestJikimoWorkorderExceptionNotifyCommo
]) ])
self.assertTrue(message_record) 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): def test_get_message(self):
exception_record = self.env['jikimo.workorder.exception'].create({ exception_record = self.env['jikimo.workorder.exception'].create({

View File

@@ -9,7 +9,7 @@
""", """,
'category': 'sf', 'category': 'sf',
'website': 'https://www.sf.jikimo.com', 'website': 'https://www.sf.jikimo.com',
'depends': ['sf_sale', 'sf_dlm', 'sf_manufacturing'], 'depends': ['sf_sale', 'sf_dlm', 'sf_manufacturing','jikimo_attachment_viewer'],
'data': [ 'data': [
'data/stock_data.xml', 'data/stock_data.xml',
'views/product_template_management_view.xml', 'views/product_template_management_view.xml',

View File

@@ -16,8 +16,6 @@
<field name='is_bfm' invisible="1"/> <field name='is_bfm' invisible="1"/>
<field name='categ_type' invisible="1"/> <field name='categ_type' invisible="1"/>
<field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/> <field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<!-- <field name='machining_drawings' attrs="{'invisible': [('categ_type', '!=', '成品')]}" widget="image"/>-->
<!-- <field name='quality_standard' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>-->
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/> <field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
<field name="upload_model_file" <field name="upload_model_file"
widget="many2many_binary" widget="many2many_binary"
@@ -111,6 +109,19 @@
'刀具')], 'required': True} '刀具')], 'required': True}
</attribute> </attribute>
</xpath> </xpath>
<xpath expr="//sheet//notebook" position="inside">
<page string="2D加工图纸">
<field name='machining_drawings' attrs="{'invisible': [('categ_type', '!=', '成品')]}"
widget="adaptive_viewer"/>
</page>
</xpath>
<xpath expr="//sheet//notebook" position="inside">
<page string="质检标准">
<field name='quality_standard' attrs="{'invisible': [('categ_type', '!=', '成品')]}"
widget="adaptive_viewer"/>
</page>
</xpath>
<!-- <xpath expr="//field[@name='default_code']" position="attributes">--> <!-- <xpath expr="//field[@name='default_code']" position="attributes">-->
<!-- <attribute name="attrs">{'readonly': [('categ_type', '=', '刀具')], 'invisible':--> <!-- <attribute name="attrs">{'readonly': [('categ_type', '=', '刀具')], 'invisible':-->
<!-- [('product_variant_count', '>' , 1)]}--> <!-- [('product_variant_count', '>' , 1)]}-->

View File

@@ -1272,6 +1272,7 @@ class Sf_Dashboard_Connect(http.Controller):
time_threshold = datetime.now() - timedelta(days=1) time_threshold = datetime.now() - timedelta(days=1)
alarm_last_24_time = 0.0 alarm_last_24_time = 0.0
alarm_all_time = 0.0
def fetch_result_as_dict(cursor): def fetch_result_as_dict(cursor):
"""辅助函数:将查询结果转为字典""" """辅助函数:将查询结果转为字典"""
@@ -1332,6 +1333,35 @@ class Sf_Dashboard_Connect(http.Controller):
alarm_last_24_time += float(result[0]) alarm_last_24_time += float(result[0])
else: else:
alarm_last_24_time += 0.0 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] = { res['data'][item] = {
'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0, 'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0,
@@ -1343,6 +1373,9 @@ class Sf_Dashboard_Connect(http.Controller):
'alarm_last_24_nums': len(list(set(alarm_last_24_nums))), 'alarm_last_24_nums': len(list(set(alarm_last_24_nums))),
'idle_count': idle_count, 'idle_count': idle_count,
'first_online_time': first_online_duration, '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() conn.close()

View File

@@ -2,3 +2,4 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details. # Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models from . import models
from . import wizard

View File

@@ -11,12 +11,14 @@
'security/group_security.xml', 'security/group_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'security/ir_rule_data.xml', 'security/ir_rule_data.xml',
'data/scheduled_actions.xml',
'views/maintenance_logs_views.xml', 'views/maintenance_logs_views.xml',
'views/maintenance_equipment_oee_views.xml', 'views/maintenance_equipment_oee_views.xml',
'views/maintenance_views.xml', 'views/maintenance_views.xml',
'views/equipment_maintenance_standards_views.xml', 'views/equipment_maintenance_standards_views.xml',
'views/maintenance_request_views.xml', 'views/maintenance_request_views.xml',
'views/maintenance_equipment_category_views.xml', 'views/maintenance_equipment_category_views.xml',
'wizard/maintenance_request_wizard.xml',
], ],
'installable': True, 'installable': True,
'application': False, 'application': False,

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>

View File

@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import json import json
import base64 import base64
import logging
from datetime import timedelta from datetime import timedelta
import requests import requests
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
from odoo import api, fields, models, _ from odoo import api, fields, models, _
from odoo.exceptions import UserError from odoo.exceptions import UserError, ValidationError
class SfMaintenanceEquipmentCategory(models.Model): class SfMaintenanceEquipmentCategory(models.Model):
@@ -122,6 +123,13 @@ class SfMaintenanceEquipment(models.Model):
'sf_maintenance_equipment_ids', string='设备维保标准') 'sf_maintenance_equipment_ids', string='设备维保标准')
eq_maintenance_id = fields.Many2one('equipment.maintenance.standards', string='设备保养标准', eq_maintenance_id = fields.Many2one('equipment.maintenance.standards', string='设备保养标准',
domain="[('maintenance_type','=','保养')]") domain="[('maintenance_type','=','保养')]")
initial_action_date = fields.Date(string='重置保养日期')
initial_action_date_old = fields.Date(string='重置保养日期(旧)')
next_action_date = fields.Date(string='下次预防保养')
initial_overhaul_date = fields.Date(string='重置维修日期')
initial_overhaul_date_old = fields.Date(string='重置维修日期(旧)')
overhaul_date = fields.Date(string='下次预防检修') overhaul_date = fields.Date(string='下次预防检修')
overhaul_period = fields.Integer(string='预防检修频次') overhaul_period = fields.Integer(string='预防检修频次')
overhaul_duration = fields.Float(string='检修时长') overhaul_duration = fields.Float(string='检修时长')
@@ -129,6 +137,61 @@ class SfMaintenanceEquipment(models.Model):
overhaul_id = fields.Many2one('equipment.maintenance.standards', string='设备检修标准', overhaul_id = fields.Many2one('equipment.maintenance.standards', string='设备检修标准',
domain="[('maintenance_type','=','检修')]") domain="[('maintenance_type','=','检修')]")
def confirm_maintenance(self):
"""
确认保养/检修
"""
context = self.env.context
if context['type'] == '保养':
if not self.initial_action_date:
raise ValidationError('重置保养日期不能为空!!')
elif self.initial_action_date < fields.Date.today():
raise ValidationError('重置保养日期不能小于当前日期!!')
elif context['type'] == '检修':
if not self.initial_overhaul_date:
raise ValidationError('重置检修日期不能为空!!')
elif self.initial_overhaul_date < fields.Date.today():
raise ValidationError('重置检修日期不能小于当前日期!!')
request_ids = self.env['maintenance.request'].search([('stage_id.done', '=', False),
('equipment_id', '=', self.id),
('maintenance_type', '=', 'preventive'),
('sf_maintenance_type', '=', context['type'])])
if not request_ids:
return self.create_maintenance_request(context['type'])
else:
return {
"type": "ir.actions.act_window",
"res_model": "maintenance.request.wizard",
"views": [[False, "form"]],
"target": "new",
'context': {
'equipment_id': self.id
}
}
def create_maintenance_request(self, maintenance_request_type):
"""
根据条件创建维保计划
"""
if maintenance_request_type == '保养':
self._create_new_request(self.initial_action_date + timedelta(days=self.period))
self.initial_action_date_old = self.initial_action_date
elif maintenance_request_type == '检修':
self._create_new_request1(self.initial_overhaul_date + timedelta(days=self.overhaul_period))
self.initial_overhaul_date_old = self.initial_overhaul_date
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': f'创建{maintenance_request_type}计划',
'message': f'{maintenance_request_type}维保计划创建成功',
'type': 'success',
'next': {'type': 'ir.actions.act_window_close'},
}
}
@api.onchange('eq_maintenance_id', 'overhaul_id') @api.onchange('eq_maintenance_id', 'overhaul_id')
def _compute_equipment_maintenance_standards_ids(self): def _compute_equipment_maintenance_standards_ids(self):
for record in self: for record in self:
@@ -591,11 +654,13 @@ class SfMaintenanceEquipment(models.Model):
('equipment_id', '=', equipment.id), ('equipment_id', '=', equipment.id),
('sf_maintenance_type', '=', '保养'), ('sf_maintenance_type', '=', '保养'),
('stage_id.done', '!=', True), ('stage_id.done', '!=', True),
('active', '!=', False),
('close_date', '=', False)], order="request_date asc", limit=1) ('close_date', '=', False)], order="request_date asc", limit=1)
last_maintenance_done = self.env['maintenance.request'].search([ last_maintenance_done = self.env['maintenance.request'].search([
('equipment_id', '=', equipment.id), ('equipment_id', '=', equipment.id),
('sf_maintenance_type', '=', '保养'), ('sf_maintenance_type', '=', '保养'),
('stage_id.done', '=', True), ('stage_id.done', '=', True),
('active', '!=', False),
('close_date', '!=', False)], order="close_date desc", limit=1) ('close_date', '!=', False)], order="close_date desc", limit=1)
if next_maintenance_todo and last_maintenance_done: if next_maintenance_todo and last_maintenance_done:
next_date = next_maintenance_todo.request_date next_date = next_maintenance_todo.request_date
@@ -624,7 +689,7 @@ class SfMaintenanceEquipment(models.Model):
if next_date < date_now: if next_date < date_now:
next_date = date_now next_date = date_now
else: else:
next_date = equipment.effective_date + timedelta(days=equipment.period) next_date = equipment.initial_action_date + timedelta(days=equipment.period)
equipment.next_action_date = next_date equipment.next_action_date = next_date
else: else:
self.next_action_date = False self.next_action_date = False
@@ -635,11 +700,13 @@ class SfMaintenanceEquipment(models.Model):
('equipment_id', '=', equipment.id), ('equipment_id', '=', equipment.id),
('sf_maintenance_type', '=', '检修'), ('sf_maintenance_type', '=', '检修'),
('stage_id.done', '!=', True), ('stage_id.done', '!=', True),
('active', '!=', False),
('close_date', '=', False)], order="request_date asc", limit=1) ('close_date', '=', False)], order="request_date asc", limit=1)
last_maintenance_done = self.env['maintenance.request'].search([ last_maintenance_done = self.env['maintenance.request'].search([
('equipment_id', '=', equipment.id), ('equipment_id', '=', equipment.id),
('sf_maintenance_type', '=', '检修'), ('sf_maintenance_type', '=', '检修'),
('stage_id.done', '=', True), ('stage_id.done', '=', True),
('active', '!=', False),
('close_date', '!=', False)], order="close_date desc", limit=1) ('close_date', '!=', False)], order="close_date desc", limit=1)
if next_maintenance_todo and last_maintenance_done: if next_maintenance_todo and last_maintenance_done:
next_date = next_maintenance_todo.request_date next_date = next_maintenance_todo.request_date
@@ -668,7 +735,7 @@ class SfMaintenanceEquipment(models.Model):
if next_date < date_now: if next_date < date_now:
next_date = date_now next_date = date_now
else: else:
next_date = equipment.effective_date + timedelta(days=equipment.overhaul_period) next_date = equipment.initial_overhaul_date + timedelta(days=equipment.overhaul_period)
equipment.overhaul_date = next_date equipment.overhaul_date = next_date
else: else:
self.overhaul_date = False self.overhaul_date = False
@@ -735,6 +802,7 @@ class SfMaintenanceEquipment(models.Model):
next_requests = self.env['maintenance.request'].search([('stage_id.done', '=', False), next_requests = self.env['maintenance.request'].search([('stage_id.done', '=', False),
('equipment_id', '=', equipment.id), ('equipment_id', '=', equipment.id),
('maintenance_type', '=', 'preventive'), ('maintenance_type', '=', 'preventive'),
('active', '=', True),
('request_date', '=', equipment.next_action_date), ('request_date', '=', equipment.next_action_date),
('sf_maintenance_type', '=', '保养')]) ('sf_maintenance_type', '=', '保养')])
if not next_requests: if not next_requests:
@@ -743,6 +811,7 @@ class SfMaintenanceEquipment(models.Model):
next_requests = self.env['maintenance.request'].search([('stage_id.done', '=', False), next_requests = self.env['maintenance.request'].search([('stage_id.done', '=', False),
('equipment_id', '=', equipment.id), ('equipment_id', '=', equipment.id),
('maintenance_type', '=', 'preventive'), ('maintenance_type', '=', 'preventive'),
('active', '=', True),
('request_date', '=', equipment.overhaul_date), ('request_date', '=', equipment.overhaul_date),
('sf_maintenance_type', '=', '检修')]) ('sf_maintenance_type', '=', '检修')])
if not next_requests: if not next_requests:

View File

@@ -88,6 +88,69 @@ class SfMaintenanceEquipmentOEE(models.Model):
begin_time = fields.Date('开始时间') begin_time = fields.Date('开始时间')
end_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): def get_day_logs(self):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
@@ -150,12 +213,11 @@ class SfMaintenanceEquipmentOEE(models.Model):
self.fault_nums = real_dict['alarm_last_24_nums'] self.fault_nums = real_dict['alarm_last_24_nums']
self.idle_nums = real_dict['idle_count'] self.idle_nums = real_dict['idle_count']
self.work_time = round( self.work_time = round(
(convert_to_seconds(real_dict['cut_time']) - convert_to_seconds(real_dict['cut_24_time'])) / 3600, (convert_to_seconds(real_dict['cut_time']) - convert_to_seconds(
real_dict['cut_24_time'])) / 3600,
2) 2)
self.offline_time = 24 - (float(self.online_time) if self.online_time else 0) self.offline_time = 24 - (float(self.online_time) if self.online_time else 0)
if response.status_code == 200: if response.status_code == 200:
result = response.json() result = response.json()
print('============', result) print('============', result)

View File

@@ -14,6 +14,8 @@ class SfMaintenanceEquipmentCategory(models.Model):
equipment_maintenance_id = fields.Many2one('equipment.maintenance.standards', string='设备维保标准', equipment_maintenance_id = fields.Many2one('equipment.maintenance.standards', string='设备维保标准',
domain="[('maintenance_type','=',sf_maintenance_type)]") domain="[('maintenance_type','=',sf_maintenance_type)]")
active = fields.Boolean('有效', default=True)
@api.onchange('sf_maintenance_type') @api.onchange('sf_maintenance_type')
def _compute_equipment_maintenance_request_id(self): def _compute_equipment_maintenance_request_id(self):
for record in self: for record in self:

View File

@@ -20,7 +20,12 @@ access_maintenance_equipment_agv_log,maintenance_equipment_agv_log,model_mainten
access_maintenance_system_user,equipment.request system user,maintenance.model_maintenance_request,base.group_user,1,0,0,0 access_maintenance_system_user,equipment.request system user,maintenance.model_maintenance_request,base.group_user,1,1,1,0
access_maintenance_wizard_system_user,maintenance.request.wizard system user,model_maintenance_request_wizard,base.group_user,1,1,1,0
access_maintenance_sf_group_equipment_user,equipment.request_sf_group_equipment_user,maintenance.model_maintenance_request,sf_group_equipment_user,1,1,1,0
access_maintenance_wizard_sf_group_equipment_user,maintenance_wizard_sf_group_equipment_user,model_maintenance_request_wizard,sf_group_equipment_user,1,1,1,0
access_maintenance_sf_group_equipment_manager,equipment.request_sf_group_equipment_manager,maintenance.model_maintenance_request,sf_group_equipment_manager,1,1,1,0
access_maintenance_wizard_sf_group_equipment_manager,maintenance_wizard_sf_group_equipment_manager,model_maintenance_request_wizard,sf_group_equipment_manager,1,1,1,0
access_maintenance_equipment_group_plan_dispatch,maintenance.equipment,maintenance.model_maintenance_equipment,sf_base.group_plan_dispatch,1,0,0,0 access_maintenance_equipment_group_plan_dispatch,maintenance.equipment,maintenance.model_maintenance_equipment,sf_base.group_plan_dispatch,1,0,0,0
access_maintenance_equipment_oee_group_plan_dispatch,maintenance_equipment_oee,model_maintenance_equipment_oee,sf_base.group_plan_dispatch,1,0,0,0 access_maintenance_equipment_oee_group_plan_dispatch,maintenance_equipment_oee,model_maintenance_equipment_oee,sf_base.group_plan_dispatch,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
20 access_maintenance_system_user equipment.request system user maintenance.model_maintenance_request base.group_user 1 0 1 0 1 0
21 access_maintenance_equipment_group_plan_dispatch access_maintenance_wizard_system_user maintenance.equipment maintenance.request.wizard system user maintenance.model_maintenance_equipment model_maintenance_request_wizard sf_base.group_plan_dispatch base.group_user 1 0 1 0 1 0
22 access_maintenance_equipment_oee_group_plan_dispatch access_maintenance_sf_group_equipment_user maintenance_equipment_oee equipment.request_sf_group_equipment_user model_maintenance_equipment_oee maintenance.model_maintenance_request sf_base.group_plan_dispatch sf_group_equipment_user 1 0 1 0 1 0
23 access_sf_maintenance_logs_group_plan_dispatch access_maintenance_wizard_sf_group_equipment_user sf_maintenance_logs maintenance_wizard_sf_group_equipment_user model_sf_maintenance_logs model_maintenance_request_wizard sf_base.group_plan_dispatch sf_group_equipment_user 1 0 1 0 1 0
24 access_maintenance_sf_group_equipment_manager equipment.request_sf_group_equipment_manager maintenance.model_maintenance_request sf_group_equipment_manager 1 1 1 0
25 access_maintenance_wizard_sf_group_equipment_manager maintenance_wizard_sf_group_equipment_manager model_maintenance_request_wizard sf_group_equipment_manager 1 1 1 0
26 access_maintenance_equipment_group_plan_dispatch maintenance.equipment maintenance.model_maintenance_equipment sf_base.group_plan_dispatch 1 0 0 0
27 access_maintenance_equipment_oee_group_plan_dispatch maintenance_equipment_oee model_maintenance_equipment_oee sf_base.group_plan_dispatch 1 0 0 0
28 access_sf_maintenance_logs_group_plan_dispatch sf_maintenance_logs model_sf_maintenance_logs sf_base.group_plan_dispatch 1 0 0 0
29 access_maintenance_standard_image_group_plan_dispatch maintenance_standard_image model_maintenance_standard_image sf_base.group_plan_dispatch 1 0 0 0
30 access_equipment_maintenance_standards_group_plan_dispatch equipment_maintenance_standards model_equipment_maintenance_standards sf_base.group_plan_dispatch 1 0 0 0
31 access_maintenance_standards_group_plan_dispatch maintenance_standards model_maintenance_standards sf_base.group_plan_dispatch 1 0 0 0

View File

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

View File

@@ -80,13 +80,19 @@
<field name="user_id" string="维保人"/> <field name="user_id" string="维保人"/>
</xpath> </xpath>
<xpath expr="//field[@name='close_date']" position="replace"> <xpath expr="//field[@name='close_date']" position="replace">
<field name="close_date" attrs="{'invisible': [('done', '!=', True)]}" readonly="True" string="维保日期"/> <field name="close_date" attrs="{'invisible': [('done', '!=', True)]}" readonly="True"
string="维保日期"/>
</xpath>
<xpath expr="//field[@name='request_date']" position="attributes">
<attribute name="string">计划维保日期</attribute>
</xpath> </xpath>
<sheet> <sheet>
<notebook> <notebook>
<page string="维保标准" attrs="{'invisible': [('equipment_maintenance_id', '=', False)]}" context="{'default_standard_id': 'id'}"> <page string="维保标准" attrs="{'invisible': [('equipment_maintenance_id', '=', False)]}"
context="{'default_standard_id': 'id'}">
<field name="maintenance_standards" widget="one2many_list"> <field name="maintenance_standards" widget="one2many_list">
<tree multi_edit="" editable=""> <tree multi_edit="" editable="">
<field name="name" class="table_custom_required"/> <field name="name" class="table_custom_required"/>
@@ -98,11 +104,33 @@
</field> </field>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
</field>
</record>
<record id="maintenance_request_view_tree_sf" model="ir.ui.view">
<field name="name">maintenance.request.view.tree.sf</field>
<field name="model">maintenance.request</field>
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='request_date']" position="replace">
<field name="request_date" string="计划维保日期"/>
</xpath>
<xpath expr="//field[@name='user_id']" position="after">
<field name="sf_maintenance_type"/>
</xpath>
</field>
</record>
<record id="equipment_request_view_search_sf" model="ir.ui.view">
<field name="name">maintenance.request.view.search.sf</field>
<field name="model">maintenance.request</field>
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_search"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='inactive']" position="replace">
<filter string="不活跃的" name="inactive" domain="[('archive', '=', True)]"/>
<filter string="已归档" name="in_active" domain="[('active', '=', False)]"/>
</xpath>
</field> </field>
</record> </record>
@@ -110,7 +138,7 @@
<record id="hr_equipment_request_action1" model="ir.actions.act_window"> <record id="hr_equipment_request_action1" model="ir.actions.act_window">
<field name="name">维保计划</field> <field name="name">维保计划</field>
<field name="res_model">maintenance.request</field> <field name="res_model">maintenance.request</field>
<field name="view_mode">kanban,tree,form,pivot,graph,calendar</field> <field name="view_mode">tree,kanban,form,pivot,graph,calendar</field>
<field name="view_id" ref="maintenance.hr_equipment_request_view_kanban"/> <field name="view_id" ref="maintenance.hr_equipment_request_view_kanban"/>
<field name="context">{'default_user_id': uid}</field> <field name="context">{'default_user_id': uid}</field>
<field name="help" type="html"> <field name="help" type="html">

View File

@@ -60,9 +60,9 @@
<field name="function_type"/> <field name="function_type"/>
<field name="code" readonly="1"/> <field name="code" readonly="1"/>
<field name="equipment_type" invisible="1"/> <field name="equipment_type" invisible="1"/>
<field name="brand_id" force_save="1" /> <field name="brand_id" force_save="1"/>
<field name="type_id" attrs="{'required': [('equipment_type', '=', '机床')]}" <field name="type_id" attrs="{'required': [('equipment_type', '=', '机床')]}"
domain="[('brand_id', '=', brand_id)]" /> domain="[('brand_id', '=', brand_id)]"/>
<field name="machine_tool_category" readonly="1" attrs="{'invisible': [('type_id', '=', False)]}" <field name="machine_tool_category" readonly="1" attrs="{'invisible': [('type_id', '=', False)]}"
force_save="1"/> force_save="1"/>
<field name="run_time" force_save="1"/> <field name="run_time" force_save="1"/>
@@ -73,7 +73,7 @@
<group> <group>
<group string="基础参数"> <group string="基础参数">
<field name="control_system_id" attrs="{'required': [('equipment_type', '=', '机床')]}" <field name="control_system_id" attrs="{'required': [('equipment_type', '=', '机床')]}"
options="{'no_create': True}" /> options="{'no_create': True}"/>
<label for="workbench_L" string="工作台尺寸(mm)"/> <label for="workbench_L" string="工作台尺寸(mm)"/>
<div class="test_model"> <div class="test_model">
<label for="workbench_L" string="长"/> <label for="workbench_L" string="长"/>
@@ -134,7 +134,7 @@
<!-- <field name="guide_rail" required="1"/>--> <!-- <field name="guide_rail" required="1"/>-->
<field name="number_of_axles" attrs="{'required': [('equipment_type', '=', '机床')]}" <field name="number_of_axles" attrs="{'required': [('equipment_type', '=', '机床')]}"
widget="radio" widget="radio"
options="{'horizontal': true}" /> options="{'horizontal': true}"/>
<label for="x_axis" string="加工行程(mm)" <label for="x_axis" string="加工行程(mm)"
attrs="{'invisible': [('number_of_axles', '=', False)]}"/> attrs="{'invisible': [('number_of_axles', '=', False)]}"/>
<div class="test_model" <div class="test_model"
@@ -197,7 +197,7 @@
<field name="C_tool_time"/> <field name="C_tool_time"/>
</group> </group>
<group string="主轴"> <group string="主轴">
<field name="taper_type_id" attrs="{'required': [('equipment_type', '=', '机床')]}" /> <field name="taper_type_id" attrs="{'required': [('equipment_type', '=', '机床')]}"/>
<label for="distance_min" string="主轴端面-工作台距离(mm)"/> <label for="distance_min" string="主轴端面-工作台距离(mm)"/>
<div class="test_model"> <div class="test_model">
<label for="distance_min" string="最小(min)"/> <label for="distance_min" string="最小(min)"/>
@@ -256,14 +256,14 @@
attrs="{'invisible': [('equipment_type', '!=', 'AGV小车')]}"> attrs="{'invisible': [('equipment_type', '!=', 'AGV小车')]}">
<field name="agv_logs"> <field name="agv_logs">
<tree create="1" edit="1" delete="1" editable="bottom"> <tree create="1" edit="1" delete="1" editable="bottom">
<field name = 'run_type'/> <field name='run_type'/>
<field name = 'run_code'/> <field name='run_code'/>
<field name = 'run_first'/> <field name='run_first'/>
<field name = 'run_last'/> <field name='run_last'/>
<field name = 'production_line'/> <field name='production_line'/>
<field name = 'workorder'/> <field name='workorder'/>
<field name = 'time'/> <field name='time'/>
<field name = 'state'/> <field name='state'/>
</tree> </tree>
</field> </field>
</page> </page>
@@ -979,16 +979,32 @@
</group> </group>
</xpath> </xpath>
<xpath expr="//field[@name='next_action_date']" position="before">
<xpath expr="//page[@name='maintenance']" position="replace">
<page string="维保" name="maintenance">
<group>
<group string="保养">
<field name='eq_maintenance_id' force_save="1" widget="many2one"/> <field name='eq_maintenance_id' force_save="1" widget="many2one"/>
<field name="initial_action_date"/>
</xpath> <field name="next_action_date" string="下次预防保养"/>
<label for="period" string="预防保养频次"/>
<xpath expr="//div[hasclass('o_row')][field[@name='maintenance_duration']]" position="after"> <div class="o_row">
<field name="period"/>
days
<field name='overhaul_id' options="{'no_create':True}"/> </div>
<label for="maintenance_duration" string="保养时长"/>
<div class="o_row">
<field name="maintenance_duration"/>
hours
</div>
<div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap">
<button name="confirm_maintenance" string="确认保养" type="object"
class="oe_highlight" context="{'type': '保养'}"/>
</div>
</group>
<group string="检修">
<field name='overhaul_id'/>
<field name="initial_overhaul_date"/>
<field name="overhaul_date" string="下次预防检修"/> <field name="overhaul_date" string="下次预防检修"/>
<label for="overhaul_period" string="预防检修频次"/> <label for="overhaul_period" string="预防检修频次"/>
<div class="o_row"> <div class="o_row">
@@ -1001,9 +1017,20 @@
<field name="overhaul_duration"/> <field name="overhaul_duration"/>
hours hours
</div> </div>
<field name='equipment_maintenance_standards_ids' widget="many2many_tags" invisible="1"/> <field name='equipment_maintenance_standards_ids' widget="many2many_tags"
invisible="1"/>
<div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap">
<button name="confirm_maintenance" string="确认检修" type="object"
class="oe_highlight" context="{'type': '检修'}"/>
</div>
</group>
</group>
</page>
</xpath> </xpath>
<xpath expr="//page[@name='description']" position="attributes"> <xpath expr="//page[@name='description']" position="attributes">
<attribute name="invisible">1</attribute> <attribute name="invisible">1</attribute>
</xpath> </xpath>
@@ -1189,7 +1216,7 @@
<field name="name" readonly="1"/> <field name="name" readonly="1"/>
<field name="type" readonly="1"/> <field name="type" readonly="1"/>
<field name="image" widget="image" readonly="1"/> <field name="image" widget="image" readonly="1"/>
<!-- <field name="equipment_id"/>--> <!-- <field name="equipment_id"/>-->
<field name="active" invisible="1"/> <field name="active" invisible="1"/>
</tree> </tree>
</field> </field>

View File

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

View File

@@ -0,0 +1,26 @@
from odoo import fields, models
class MaintenanceRequestWizard(models.TransientModel):
_name = 'maintenance.request.wizard'
_description = '维保二次确认弹窗'
name = fields.Char('')
def submit(self):
context = self.env.context
equipment_id = self.env['maintenance.equipment'].sudo().search([('id', '=', context['equipment_id'])])
request_ids = self.env['maintenance.request'].search([('stage_id.done', '=', False),
('equipment_id', '=', equipment_id.id),
('maintenance_type', '=', 'preventive'),
('sf_maintenance_type', '=', context['type'])])
request_ids.write({'active': False})
return equipment_id.create_maintenance_request(context['type'])
def cancel(self):
context = self.env.context
equipment_id = self.env['maintenance.equipment'].sudo().search([('id', '=', context['equipment_id'])])
if context['type'] == '保养':
equipment_id.initial_action_date = equipment_id.initial_action_date_old
elif context['type'] == '检修':
equipment_id.initial_overhaul_date = equipment_id.initial_overhaul_date_old

View File

@@ -0,0 +1,29 @@
<openerp>
<data>
<record id="action_maintenance_request_wizard" model="ir.actions.act_window">
<field name="name">维保计划</field>
<field name="res_model">maintenance.request.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record model="ir.ui.view" id="maintenance_request_wizard_form_view">
<field name="name">maintenance.request.wizard.form.view</field>
<field name="model">maintenance.request.wizard</field>
<field name="arch" type="xml">
<form>
<div>
<field name="name" invisible="1"/>
有未执行的历史维保计划,是否创建新维保计划!!
</div>
<footer>
<button string="确认" name="submit" type="object" class="oe_highlight"/>
<button string="取消" name="cancel" type="object" class="oe_highlight"/>
</footer>
</form>
</field>
</record>
</data>
</openerp>

View File

@@ -10,7 +10,7 @@
""", """,
'category': 'sf', 'category': 'sf',
'website': 'https://www.sf.jikimo.com', 'website': 'https://www.sf.jikimo.com',
'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse'], 'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse','jikimo_attachment_viewer'],
'data': [ 'data': [
'data/stock_data.xml', 'data/stock_data.xml',
'data/empty_racks_data.xml', 'data/empty_racks_data.xml',
@@ -45,6 +45,8 @@
'sf_manufacturing/static/src/scss/kanban_change.scss', 'sf_manufacturing/static/src/scss/kanban_change.scss',
'sf_manufacturing/static/src/xml/button_show_on_tree.xml', 'sf_manufacturing/static/src/xml/button_show_on_tree.xml',
'sf_manufacturing/static/src/js/workpiece_delivery_wizard_confirm.js', 'sf_manufacturing/static/src/js/workpiece_delivery_wizard_confirm.js',
'sf_manufacturing/static/src/js/qr.js',
'sf_manufacturing/static/src/xml/qr.xml',
] ]
}, },

View File

@@ -18,7 +18,7 @@ class MrpProduction(models.Model):
_inherit = 'mrp.production' _inherit = 'mrp.production'
_description = "制造订单" _description = "制造订单"
_order = 'create_date desc' _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="托盘") # tray_ids = fields.One2many('sf.tray', 'production_id', string="托盘")
maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests") maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests")
request_ids = fields.One2many('maintenance.request', 'production_id') request_ids = fields.One2many('maintenance.request', 'production_id')
@@ -34,6 +34,29 @@ class MrpProduction(models.Model):
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True) tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=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:
# 确保 procurement_group_id 和相关字段存在
if production.procurement_group_id:
# 获取相关的 sale_id
sale_order_id = production.procurement_group_id.mrp_production_ids.mapped(
'move_dest_ids.group_id.sale_id')
# 确保 sale_order_id 是有效的 ID 列表
if sale_order_id:
# 获取 sale.order 记录
sale_id = self.env['sale.order'].sudo().browse(sale_order_id.ids) # 使用 mapped 返回的 ID 列表
# 处理 sale_id
if sale_id:
# 假设我们只需要第一个 sale_id
production.deadline_of_delivery = sale_id[0].deadline_of_delivery if sale_id else False
else:
production.deadline_of_delivery = False
else:
production.deadline_of_delivery = False
@api.depends('workorder_ids.tool_state_remark') @api.depends('workorder_ids.tool_state_remark')
def _compute_tool_state_remark(self): def _compute_tool_state_remark(self):
for item in self: for item in self:
@@ -118,10 +141,12 @@ class MrpProduction(models.Model):
], string='工序状态', default='待装夹') ], string='工序状态', default='待装夹')
# 零件图号 # 零件图号
part_number = fields.Char('零件图号') part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
# 上传零件图纸 # 上传零件图纸
part_drawing = fields.Binary('零件图纸') part_drawing = fields.Binary('零件图纸', related='product_id.machining_drawings', readonly=True)
quality_standard = fields.Binary('质检标准', related='product_id.quality_standard', readonly=True)
@api.depends('product_id.manual_quotation') @api.depends('product_id.manual_quotation')
def _compute_manual_quotation(self): def _compute_manual_quotation(self):
@@ -948,6 +973,8 @@ class MrpProduction(models.Model):
if production.programming_no in program_to_production_names: if production.programming_no in program_to_production_names:
productions_not_delivered = self.env['mrp.production'].search( productions_not_delivered = self.env['mrp.production'].search(
[('programming_no', '=', production.programming_no), ('programming_state', '=', '已编程未下发')]) [('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') rework_workorder = production.workorder_ids.filtered(lambda m: m.state == 'rework')
if rework_workorder: if rework_workorder:
for rework_item in rework_workorder: for rework_item in rework_workorder:
@@ -963,7 +990,7 @@ class MrpProduction(models.Model):
# 对制造订单所以面的cnc工单的程序用刀进行校验 # 对制造订单所以面的cnc工单的程序用刀进行校验
try: try:
logging.info(f'已更新制造订单:{productions_not_delivered}') logging.info(f'已更新制造订单:{productions_not_delivered}')
productions_not_delivered.production_cnc_tool_checkout() productions.production_cnc_tool_checkout()
except Exception as e: except Exception as e:
logging.info(f'对cnc工单的程序用刀进行校验报错{e}') logging.info(f'对cnc工单的程序用刀进行校验报错{e}')

View File

@@ -59,7 +59,8 @@ class ResMrpWorkOrder(models.Model):
compute='_compute_state', store=True, compute='_compute_state', store=True,
default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True) default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True)
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效') delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
tracking=True)
@api.depends('production_id.manual_quotation') @api.depends('production_id.manual_quotation')
def _compute_manual_quotation(self): def _compute_manual_quotation(self):
@@ -225,6 +226,9 @@ class ResMrpWorkOrder(models.Model):
material_height = fields.Float(string='') material_height = fields.Float(string='')
# 零件图号 # 零件图号
part_number = fields.Char(related='production_id.part_number', 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([ process_state = fields.Selection([
('待装夹', '待装夹'), ('待装夹', '待装夹'),
@@ -1048,6 +1052,17 @@ class ResMrpWorkOrder(models.Model):
if workorder.production_id.tool_state in ['1', '2'] and workorder.state == 'ready': if workorder.production_id.tool_state in ['1', '2'] and workorder.state == 'ready':
workorder.state = 'waiting' workorder.state = 'waiting'
continue continue
if (workorder.production_id.tool_state in ['1', '2']
and not workorder.production_id.workorder_ids.filtered(lambda a: a.sequence == 0)
and workorder.production_id.programming_state == '编程中' and workorder.name == '装夹预调'):
if workorder.state == 'pending' and workorder == self.search(
[('production_id', '=', workorder.production_id.id),
('routing_type', '=', '装夹预调'),
('state', 'not in', ['rework', 'done', 'cancel'])],
limit=1,
order="sequence"):
workorder.state = 'waiting'
continue
# elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'cancel', 'progress', # elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'cancel', 'progress',
# 'rework']: # 'rework']:
@@ -1091,6 +1106,8 @@ class ResMrpWorkOrder(models.Model):
if self.routing_type == '装夹预调': if self.routing_type == '装夹预调':
# 判断是否有坯料的序列号信息 # 判断是否有坯料的序列号信息
boolean = False boolean = False
if self.production_id.move_raw_ids:
if self.production_id.move_raw_ids[0].move_line_ids:
if self.production_id.move_raw_ids[0].move_line_ids: if self.production_id.move_raw_ids[0].move_line_ids:
if self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name: if self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name:
boolean = True boolean = True

View File

@@ -16,6 +16,12 @@ from OCC.Extend.DataExchange import write_stl_file
class ResProductMo(models.Model): class ResProductMo(models.Model):
_inherit = 'product.template' _inherit = 'product.template'
def _get_machining_precision(self):
machinings = self.env['sf.machining.accuracy'].sudo().search([])
list = [(m.sync_id, m.name) for m in machinings]
return list
model_file = fields.Binary('模型文件') model_file = fields.Binary('模型文件')
categ_type = fields.Selection(string='产品的类别', related='categ_id.type', store=True) categ_type = fields.Selection(string='产品的类别', related='categ_id.type', store=True)
model_name = fields.Char('模型名称') model_name = fields.Char('模型名称')
@@ -23,12 +29,7 @@ class ResProductMo(models.Model):
model_width = fields.Float('模型宽(mm)', digits=(16, 3)) model_width = fields.Float('模型宽(mm)', digits=(16, 3))
model_height = fields.Float('模型高(mm)', digits=(16, 3)) model_height = fields.Float('模型高(mm)', digits=(16, 3))
model_volume = fields.Float('模型体积(m³)') model_volume = fields.Float('模型体积(m³)')
model_machining_precision = fields.Selection([ model_machining_precision = fields.Selection(selection=_get_machining_precision, string='加工精度')
('0.10', '±0.10mm'),
('0.05', '±0.05mm'),
('0.03', '±0.03mm'),
('0.02', '±0.02mm'),
('0.01', '±0.01mm')], string='加工精度')
model_processing_panel = fields.Char('模型加工面板') model_processing_panel = fields.Char('模型加工面板')
model_remark = fields.Char('模型备注说明') model_remark = fields.Char('模型备注说明')
length = fields.Float('长(mm)', digits=(16, 3)) length = fields.Float('长(mm)', digits=(16, 3))
@@ -774,8 +775,8 @@ class ResProductMo(models.Model):
# bfm下单 # bfm下单
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
part_number = fields.Char(string='零件图号', readonly=True) part_number = fields.Char(string='零件图号', readonly=True)
# machining_drawings = fields.Binary('2D加工图纸', readonly=True) machining_drawings = fields.Binary('2D加工图纸', readonly=True)
# quality_standard = fields.Binary('质检标准', readonly=True) quality_standard = fields.Binary('质检标准', readonly=True)
@api.constrains('tool_length') @api.constrains('tool_length')
def _check_tool_length_size(self): def _check_tool_length_size(self):
@@ -837,6 +838,11 @@ class ResProductMo(models.Model):
else: else:
return self.env.ref('sf_dlm.product_uom_cubic_millimeter') return self.env.ref('sf_dlm.product_uom_cubic_millimeter')
def attachment_update(self, name, res_id, res_field, mimetype):
attachment_info = self.env['ir.attachment'].sudo().search(
[('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1)
attachment_info.write({'name': name, 'mimetype': mimetype})
# 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品 # 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品
def product_create(self, product_id, item, order_id, order_number, i): def product_create(self, product_id, item, order_id, order_number, i):
copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy() copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy()
@@ -875,8 +881,9 @@ class ResProductMo(models.Model):
'manual_quotation': item['manual_quotation'] or False, 'manual_quotation': item['manual_quotation'] or False,
'part_number': item.get('part_number') or '', 'part_number': item.get('part_number') or '',
'active': True, 'active': True,
# 'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode(item['machining_drawings']), 'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode(
# 'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']), item['machining_drawings']),
'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']),
} }
tax_id = self.env['account.tax'].sudo().search( tax_id = self.env['account.tax'].sudo().search(
[('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')]) [('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')])
@@ -884,6 +891,12 @@ class ResProductMo(models.Model):
vals.update({'taxes_id': [(6, 0, [int(tax_id)])]}) vals.update({'taxes_id': [(6, 0, [int(tax_id)])]})
copy_product_id.sudo().write(vals) copy_product_id.sudo().write(vals)
product_id.product_tmpl_id.active = False product_id.product_tmpl_id.active = False
if item['machining_drawings'] and item['machining_drawings_name'] and item['machining_drawings_mimetype']:
self.attachment_update(item['machining_drawings_name'], copy_product_id.product_tmpl_id.id,
'machining_drawings', item['machining_drawings_mimetype'])
if item['quality_standard'] and item['quality_standard_name'] and item['quality_standard_mimetype']:
self.attachment_update(item['quality_standard_name'], copy_product_id.product_tmpl_id.id,
'quality_standard', item['quality_standard_mimetype'])
return copy_product_id return copy_product_id
def _get_ids(self, param): def _get_ids(self, param):

View File

@@ -182,6 +182,11 @@ class StockRule(models.Model):
moves._action_confirm() moves._action_confirm()
return True return True
def attachment_update(self, name, res_id, res_field):
attachment_info = self.env['ir.attachment'].sudo().search(
[('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1)
attachment_info.write({'name': name})
@api.model @api.model
def _run_manufacture(self, procurements): def _run_manufacture(self, procurements):
productions_values_by_company = defaultdict(list) productions_values_by_company = defaultdict(list)
@@ -267,11 +272,6 @@ class StockRule(models.Model):
workorder_duration += workorder.duration_expected workorder_duration += workorder.duration_expected
sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)]) sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
# 根据销售订单号查询快速订单
quick_easy_order = self.env['quick.easy.order'].sudo().search([('sale_order_id', '=', sale_order.id)])
if quick_easy_order:
production.write({'part_number': quick_easy_order.part_drawing_number,
'part_drawing': quick_easy_order.machining_drawings})
if sale_order: if sale_order:
# sale_order.write({'schedule_status': 'to schedule'}) # sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(company_id).create({ self.env['sf.production.plan'].sudo().with_company(company_id).create({

View File

@@ -0,0 +1,115 @@
/** @odoo-module **/
import { registry } from '@web/core/registry';
import { Component } from '@odoo/owl';
class QRCodeWidget extends Component {
// 初始化组件
setup() {
console.log('QRCodeWidget setup');
this.qrCodeValue = ''; // 初始化为空字符串,用于存储条码
this.inputBuffer = ''; // 存储临时输入的字符
this.inputTimer = null; // 定时器
// 显式绑定上下文
this.onGlobalKeyDown = this.onGlobalKeyDown.bind(this);
window.addEventListener('keydown', this.onGlobalKeyDown);
}
// 清理事件监听器,防止内存泄漏
willUnmount() {
window.removeEventListener('keydown', this.onGlobalKeyDown);
if (this.inputTimer) {
clearTimeout(this.inputTimer);
}
}
// 全局键盘事件监听器
onGlobalKeyDown(event) {
// 如果是Tab键表示扫码输入结束
if (event.key === 'Tab' || event.key === 'Enter') {
this.qrCodeValue = this.inputBuffer; // 完整条码赋值
console.log('完整条码:', this.qrCodeValue);
this.onQRCodeChange(this.qrCodeValue); // 调用父组件的 onQRCodeChange 方法
this.inputBuffer = ''; // 清空临时缓冲区
event.preventDefault(); // 阻止Tab键的默认行为
return;
}
// 只处理可打印字符
if (event.key.length === 1) {
this.inputBuffer += event.key; // 添加到缓冲区
// console.log('当前缓冲区:', this.inputBuffer);
// 清除之前的定时器,重新开始计时
if (this.inputTimer) {
clearTimeout(this.inputTimer);
}
// 启动一个定时器如果500ms内没有新的输入则认为条码输入完成
this.inputTimer = setTimeout(() => {
this.qrCodeValue = this.inputBuffer;
// console.log('定时器触发,完整条码:', this.qrCodeValue);
this.inputBuffer = ''; // 清空缓冲区
}, 500); // 可以根据需要调整时间
}
}
// 处理二维码输入变更
async onQRCodeChange(qrCodeValue) {
console.log('onQRCodeChange二维码输入变更', qrCodeValue); // 检查二维码的输入是否被捕获
if (qrCodeValue) {
// console.log('二维码输入变更');
try {
// 发起 RPC 请求
const result = await this.env.services.rpc('/web/dataset/call_kw', {
model: 'mrp.workorder',
method: 'search_read',
args: [
[['rfid_code', '=', qrCodeValue]], // 查询条件
['id'] // 返回的字段
],
kwargs: {}
});
if (result.length > 0) {
console.log('该二维码对应的工单存在!');
} else {
console.log('未找到对应的工单。');
const routingTypeField = document.querySelector('[name="routing_type"]');
if (routingTypeField) {
let fieldValue = routingTypeField.querySelector('span').getAttribute('raw-value');
console.log('Routing Type Value:', fieldValue);
// 清理多余的引号
fieldValue = fieldValue ? fieldValue.replace(/["]+/g, '') : null;
console.log(fieldValue);
if (fieldValue && fieldValue === '装夹预调') {
// console.log('routing_type 为装夹预调');
// 检查 RFID 值
if (!qrCodeValue || qrCodeValue.length <= 3) return;
// 查找 name="button_start" 按钮并触发点击事件
const startButton = document.querySelector('[name="button_start"]');
if (startButton) {
startButton.click();
}
}
}
}
} catch (error) {
console.error('查询工单时出错:', error);
}
}
}
// 返回模板名称
static template = 'sf_manufacturing.QRCodeWidgetTemplate';
}
// 将自定义字段注册到字段注册表
registry.category('fields').add('qrcode_widget', QRCodeWidget);

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates>
<t t-name="sf_manufacturing.QRCodeWidgetTemplate" owl="1">
<!-- <div> -->
<!-- <input type="text" t-att-value="props.value" placeholder="Scan QR code here" /> -->
<!-- </div> -->
<div t-esc="props.value">
</div>
</t>
</templates>

View File

@@ -98,9 +98,9 @@
<field name="production_line_id" readonly="1"/> <field name="production_line_id" readonly="1"/>
<!-- <field name="production_line_state" readonly="1"/>--> <!-- <field name="production_line_state" readonly="1"/>-->
<field name="part_number" string="成品的零件图号"/> <field name="part_number" string="成品的零件图号"/>
<field name="part_drawing"/>
<field name="tool_state"/> <field name="tool_state"/>
<field name="tool_state_remark" string="备注" attrs="{'invisible': [('tool_state', '!=', '1')]}"/> <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"/> <field name="tool_state_remark2" invisible="1"/>
</xpath> </xpath>
<xpath expr="//header//button[@name='action_cancel']" position="replace"> <xpath expr="//header//button[@name='action_cancel']" position="replace">
@@ -328,6 +328,16 @@
<xpath expr="//field[@name='components_availability']" position="attributes"> <xpath expr="//field[@name='components_availability']" position="attributes">
<attribute name="string">投料状态</attribute> <attribute name="string">投料状态</attribute>
</xpath> </xpath>
<xpath expr="//sheet//notebook" position="inside">
<page string="零件图纸">
<field name="part_drawing" widget="adaptive_viewer"/>
</page>
</xpath>
<xpath expr="//sheet//notebook" position="inside">
<page string="质检标准">
<field name="quality_standard" widget="adaptive_viewer"/>
</page>
</xpath>
</field> </field>
</record> </record>

View File

@@ -125,9 +125,9 @@
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/> <field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//form" position="inside"> <!-- <xpath expr="//form" position="inside"> -->
<script src="sf_manufacturing/static/src/js/customRFID.js"/> <!-- <script src="sf_manufacturing/static/src/js/customRFID.js"/> -->
</xpath> <!-- </xpath> -->
<xpath expr="//header/field[@name='state']" position="replace"> <xpath expr="//header/field[@name='state']" position="replace">
<field name="state" widget="statusbar" <field name="state" widget="statusbar"
statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/> statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/>
@@ -225,6 +225,7 @@
<xpath expr="//label[1]" position="before"> <xpath expr="//label[1]" position="before">
<!-- --> <!-- -->
<field name="production_id" invisible="0"/> <field name="production_id" invisible="0"/>
<field name="routing_type" string="工单类型" readonly="1"/>
<field name="duration_expected" invisible="1"/> <field name="duration_expected" invisible="1"/>
<field name="date_planned_start" invisible="1"/> <field name="date_planned_start" invisible="1"/>
<field name="date_planned_finished" invisible="1"/> <field name="date_planned_finished" invisible="1"/>
@@ -246,8 +247,8 @@
<field name='process_state' invisible="1"/> <field name='process_state' invisible="1"/>
<field name='tag_type' readonly="1" attrs='{"invisible": [("tag_type","=",False)]}' <field name='tag_type' readonly="1" attrs='{"invisible": [("tag_type","=",False)]}'
decoration-danger="tag_type == '重新加工'"/> decoration-danger="tag_type == '重新加工'"/>
<field name="rfid_code" force_save="1" readonly="0" cache="True" <field name="rfid_code" force_save="1" readonly="1" cache="True"
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/> attrs="{'invisible': [('rfid_code_old', '!=', False)]}" widget='qrcode_widget'/>
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/> <field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
</xpath> </xpath>
@@ -466,6 +467,15 @@
<field name='X_deviation_angle' readonly="1"/> <field name='X_deviation_angle' readonly="1"/>
</group> </group>
</page> </page>
<page string="2D加工图纸" attrs="{'invisible': [('routing_type','!=','装夹预调')]}">
<field name="machining_drawings" widget="adaptive_viewer"/>
</page>
<page string="质检标准" attrs="{'invisible': [('routing_type','!=','装夹预调')]}">
<field name="quality_standard" widget="adaptive_viewer"/>
</page>
<page string="工件配送" <page string="工件配送"
attrs="{'invisible': [('routing_type','!=','装夹预调')]}"> attrs="{'invisible': [('routing_type','!=','装夹预调')]}">
<field name="workpiece_delivery_ids"> <field name="workpiece_delivery_ids">
@@ -519,6 +529,13 @@
<!-- attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>--> <!-- attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>-->
<!-- </div>--> <!-- </div>-->
</page> </page>
<page string="2D加工图纸" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<field name="machining_drawings" widget="adaptive_viewer"/>
</page>
<page string="质检标准" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<field name="quality_standard" widget="adaptive_viewer"/>
</page>
</xpath> </xpath>
<xpath expr="//page[1]" position="before"> <xpath expr="//page[1]" position="before">
<page string="CNC程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'> <page string="CNC程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
@@ -589,7 +606,6 @@
mrp.group_mrp_manager,sf_base.group_sf_mrp_manager,sf_base.group_sf_equipment_user,sf_base.group_sf_order_user mrp.group_mrp_manager,sf_base.group_sf_mrp_manager,sf_base.group_sf_equipment_user,sf_base.group_sf_order_user
</attribute> </attribute>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -17,7 +17,7 @@
'data/cron_data.xml', 'data/cron_data.xml',
'data/template_data.xml', 'data/template_data.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'views/mrp_workorder_views.xml',
], ],
'test': [ 'test': [
], ],

View File

@@ -13,6 +13,19 @@
<field name="active" eval="True"/> <field name="active" eval="True"/>
</record> </record>
<record model="ir.cron" id="ir_cron_sale_order_recover_time_warning">
<field name="name">检查销售订单是否完成并恢复正常时效</field>
<field name="model_id" ref="model_sale_order"/>
<field name="state">code</field>
<field name="code">model._recover_sale_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"> <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="model_id" ref="model_mrp_workorder"/>

View File

@@ -97,7 +97,7 @@
<field name="send_type">timing</field> <field name="send_type">timing</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 工单逾期预警 <field name="content">### 工单逾期预警
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field> 事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
</record> </record>
<record id="template_mrp_workorder_pre_overdue" model="jikimo.message.template"> <record id="template_mrp_workorder_pre_overdue" model="jikimo.message.template">
@@ -109,7 +109,7 @@
<field name="send_type">timing</field> <field name="send_type">timing</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 工单已逾期提醒 <field name="content">### 工单已逾期提醒
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field> 事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
</record> </record>
<record id="template_mrp_workorder_cnc_overdue_warning" model="jikimo.message.template"> <record id="template_mrp_workorder_cnc_overdue_warning" model="jikimo.message.template">
@@ -121,7 +121,7 @@
<field name="send_type">timing</field> <field name="send_type">timing</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 工单逾期预警 <field name="content">### 工单逾期预警
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field> 事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
</record> </record>
<record id="template_mrp_workorder_cnc_overdue" model="jikimo.message.template"> <record id="template_mrp_workorder_cnc_overdue" model="jikimo.message.template">
@@ -133,7 +133,7 @@
<field name="send_type">timing</field> <field name="send_type">timing</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 工单已逾期提醒 <field name="content">### 工单已逾期提醒
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field> 事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
</record> </record>
<record id="template_mrp_workorder_unclamp_overdue_warning" model="jikimo.message.template"> <record id="template_mrp_workorder_unclamp_overdue_warning" model="jikimo.message.template">
@@ -145,7 +145,7 @@
<field name="send_type">timing</field> <field name="send_type">timing</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 工单逾期预警 <field name="content">### 工单逾期预警
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field> 事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
</record> </record>
<record id="template_mrp_workorder_unclamp_overdue" model="jikimo.message.template"> <record id="template_mrp_workorder_unclamp_overdue" model="jikimo.message.template">
@@ -157,7 +157,7 @@
<field name="send_type">timing</field> <field name="send_type">timing</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 工单已逾期提醒 <field name="content">### 工单已逾期提醒
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field> 事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
</record> </record>
<record id="template_mrp_workorder_surface_overdue_warning" model="jikimo.message.template"> <record id="template_mrp_workorder_surface_overdue_warning" model="jikimo.message.template">
@@ -169,7 +169,7 @@
<field name="send_type">timing</field> <field name="send_type">timing</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 工单逾期预警 <field name="content">### 工单逾期预警
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field> 事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
</record> </record>
<record id="template_mrp_workorder_surface_overdue" model="jikimo.message.template"> <record id="template_mrp_workorder_surface_overdue" model="jikimo.message.template">
@@ -181,7 +181,7 @@
<field name="send_type">timing</field> <field name="send_type">timing</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 工单已逾期提醒 <field name="content">### 工单已逾期提醒
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field> 事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
</record> </record>

View File

@@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api from odoo import models, fields, api
class SFMessageMaintenanceLogs(models.Model): class SFMessageMaintenanceLogs(models.Model):
_name = 'sf.maintenance.logs' _name = 'sf.maintenance.logs'
_inherit = ['sf.maintenance.logs', 'jikimo.message.dispatch'] _inherit = ['sf.maintenance.logs', 'jikimo.message.dispatch']
@api._model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
res = super(SFMessageMaintenanceLogs, self).create(vals_list) res = super(SFMessageMaintenanceLogs, self).create(vals_list)
for rec in res: for rec in res:
rec.add_queue() rec.add_queue('设备故障')
return res return res
def _get_message(self, message_queue_ids): def _get_message(self, message_queue_ids):

View File

@@ -1,3 +1,4 @@
import logging
import re import re
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from urllib.parse import urlencode from urllib.parse import urlencode
@@ -35,19 +36,20 @@ class SFMessageMrpProduction(models.Model):
[('origin', '=', mrp_production.origin), ('picking_type_id.sequence_code', '=', 'SFP'), [('origin', '=', mrp_production.origin), ('picking_type_id.sequence_code', '=', 'SFP'),
('state', '=', 'assigned')], limit=1) ('state', '=', 'assigned')], limit=1)
if stock_picking_sfp: if stock_picking_sfp:
url = self.request_url() url = self.request_url(stock_picking_sfp.id)
content = content.replace('{{name}}', stock_picking_sfp.name).replace( content = content.replace('{{name}}', stock_picking_sfp.name).replace(
'{{sale_order_name}}', mrp_production.origin).replace('{{request_url}}', url) '{{sale_order_name}}', mrp_production.origin).replace('{{request_url}}', url)
contents.append(content) contents.append(content)
logging.info('生产完工入库提醒: %s' % contents)
return contents return contents
def request_url(self): def request_url(self, id):
url = self.env['ir.config_parameter'].get_param('web.base.url') url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('mrp.mrp_production_action').id action_id = self.env.ref('stock.action_picking_tree_all').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id
# 查询参数 # 查询参数
params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.production', params = {'id': id, 'menu_id': menu_id, 'action': action_id, 'model': 'mrp.production',
'view_type': 'kanban'} 'view_type': 'form'}
# 拼接查询参数 # 拼接查询参数
query_string = urlencode(params) query_string = urlencode(params)
# 拼接URL # 拼接URL

View File

@@ -34,7 +34,7 @@ class SFMessageSale(models.Model):
picking_id.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id).ids picking_id.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id).ids
purchase_order_id.extend(purchase_order_ids) purchase_order_id.extend(purchase_order_ids)
if purchase_order_id: if purchase_order_id:
purchase_order_list = self.env['purchase.order'].search([('id', 'in', purchase_order_id)]) purchase_order_list = self.env['purchase.order'].sudo().search([('id', 'in', purchase_order_id)])
for purchase_order_info in purchase_order_list: for purchase_order_info in purchase_order_list:
purchase_order_info.add_queue('坯料采购提醒') purchase_order_info.add_queue('坯料采购提醒')
except Exception as e: except Exception as e:
@@ -45,7 +45,7 @@ class SFMessageSale(models.Model):
def _get_message(self, message_queue_ids): def _get_message(self, message_queue_ids):
contents = [] contents = []
bussiness_node = None bussiness_node = None
url = self.env['ir.config_parameter'].get_param('web.base.url') url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
current_time_strf = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 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 = 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') current_time_datetime = datetime.strptime(current_time, '%Y-%m-%d %H:%M:%S')
@@ -60,7 +60,7 @@ class SFMessageSale(models.Model):
contents.append(content) contents.append(content)
elif item.message_template_id.bussiness_node_id.name == '确认接单': elif item.message_template_id.bussiness_node_id.name == '确认接单':
content = super(SFMessageSale, self)._get_message(item) content = super(SFMessageSale, self)._get_message(item)
sale_order_line = self.env['sale.order.line'].search([('order_id', '=', int(item.res_id))]) sale_order_line = self.env['sale.order.line'].sudo().search([('order_id', '=', int(item.res_id))])
product = sale_order_line[0].product_id.name if len(sale_order_line) == 1 else '%s...' % \ product = sale_order_line[0].product_id.name if len(sale_order_line) == 1 else '%s...' % \
sale_order_line[ sale_order_line[
0].product_id.name 0].product_id.name
@@ -103,39 +103,70 @@ class SFMessageSale(models.Model):
today = datetime.today().date() today = datetime.today().date()
deadline_check = today + timedelta(days=1) deadline_check = today + timedelta(days=1)
logging.info(f"today: {today}, deadline_check: {deadline_check}") logging.info(f"today: {today}, deadline_check: {deadline_check}")
sale_order = self.sudo().search([('state', 'in', ['sale']), ('deadline_of_delivery', '!=', False)]) sale_order = self.sudo().search(
[('state', 'in', ['sale']), ('deadline_of_delivery', '!=', False), ('delivery_status', '!=', 'full')])
for item in sale_order: for item in sale_order:
production = self.env['mrp.production'].search([('origin', '=', item.name)]) production = self.env['mrp.production'].sudo().search([('origin', '=', item.name)])
production_not_done = production.filtered(lambda p: p.state not in ['done', 'scrap', 'cancel']) 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'])) production_done_count = len(production.filtered(lambda p: p.state in ['done', 'scrap', 'cancel']))
if len(production_not_done) != item.mrp_production_count: if (len(production_not_done) >= 1 and len(production_not_done) != item.mrp_production_count) or len(
if deadline_check == item.deadline_of_delivery: production_not_done) != production_done_count:
# logging.info("-----不等于----")
# logging.info(f"name: {item.name}")
# logging.info(
# f"production_not_done: {len(production_not_done)}, production_done_count: {production_done_count}")
# logging.info(f"deadline_of_delivery: {item.deadline_of_delivery}")
if deadline_check == item.deadline_of_delivery and item.delivery_warning not in ['warning']:
item.delivery_warning = 'warning' item.delivery_warning = 'warning'
elif today == item.deadline_of_delivery: elif today >= item.deadline_of_delivery and item.delivery_warning not in ['overdue']:
item.delivery_warning = 'overdue' item.delivery_warning = 'overdue'
elif production_done_count == item.mrp_production_count: elif production_done_count == item.mrp_production_count:
# logging.info("-----等于----")
# logging.info(f"name: {item.name}")
# logging.info(
# f"production_not_done: {len(production_not_done)}, production_done_count: {production_done_count}")
# logging.info(f"deadline_of_delivery: {item.deadline_of_delivery}")
if item.delivery_status in ['pending', 'partial']: if item.delivery_status in ['pending', 'partial']:
if deadline_check == item.deadline_of_delivery: if deadline_check == item.deadline_of_delivery and item.delivery_warning not in ['warning']:
item.delivery_warning = 'warning' item.delivery_warning = 'warning'
elif today == item.deadline_of_delivery: elif today >= item.deadline_of_delivery and item.delivery_warning not in ['overdue']:
item.delivery_warning = 'overdue' item.delivery_warning = 'overdue'
else: else:
# logging.info("-----1111111----")
# logging.info(f"name: {item.name}")
# logging.info(
# f"production_not_done: {len(production_not_done)}, production_done_count: {production_done_count}")
continue continue
# 获取业务节点
business_node_ids = {
'warning': self.env.ref('sf_message.bussiness_sale_order_overdue_warning').id,
'overdue': self.env.ref('sf_message.bussiness_sale_order_overdue').id
}
overdue_orders = self.sudo().search([('delivery_warning', 'in', ['warning', 'overdue'])]) overdue_orders = self.sudo().search([('delivery_warning', 'in', ['warning', 'overdue'])])
for wo in overdue_orders: for wo in overdue_orders:
message_template = self.env["jikimo.message.template"].search([ business_node_id = business_node_ids.get(wo.delivery_warning)
if business_node_id:
message_template = self.env["jikimo.message.template"].sudo().search([
("model", "=", self._name), ("model", "=", self._name),
("bussiness_node_id", "=", self.env.ref('sf_message.bussiness_sale_order_overdue_warning').id) ("bussiness_node_id", "=", business_node_id)
]) ], limit=1)
sale_order_has = self.env['jikimo.message.queue'].search([ sale_order_has = self.env['jikimo.message.queue'].sudo().search([
('res_id', '=', wo.id), ('res_id', '=', wo.id),
('message_status', '=', 'pending'), ('message_status', '=', 'pending'),
('message_template_id', '=', message_template.id) ('message_template_id', '=', message_template.id)
]) ])
if not sale_order_has: if not sale_order_has:
if wo.delivery_warning == 'warning': message_name = '销售订单逾期预警' if wo.delivery_warning == 'warning' else '销售订单已逾期'
wo.add_queue('销售订单逾期预警') wo.add_queue(message_name)
elif wo.delivery_warning == 'overdue':
wo.add_queue('销售订单已逾期')
def _recover_sale_time_warning_func(self):
sale_order_done = self.sudo().search([('state', 'in', ['sale']), ('delivery_status', '=', 'full')])
sale_order_overdue = sale_order_done.filtered(lambda x: x.delivery_warning in ['overdue', 'warning'])
if sale_order_overdue:
sale_order_overdue.write({'delivery_warning': 'normal'})
message_queue_ids = self.env["jikimo.message.queue"].sudo().search([
("message_status", "=", "pending"),
("res_id", "in", [item.id for item in sale_order_overdue])
])
if message_queue_ids:
message_queue_ids.write({'message_status': 'cancel'})

View File

@@ -1,3 +1,4 @@
import logging
import re import re
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from urllib.parse import urlencode from urllib.parse import urlencode
@@ -28,21 +29,22 @@ class SFMessageStockPicking(models.Model):
[('origin', '=', record.origin), ('state', '!=', 'done'), [('origin', '=', record.origin), ('state', '!=', 'done'),
('picking_type_id.sequence_code', '=', 'SFP')]) ('picking_type_id.sequence_code', '=', 'SFP')])
if not stock_picking_sfp: if not stock_picking_sfp:
stock_picking_send = self.env["jikimo.message.queue"].search([('res_id', '=', record.id)]) stock_picking_send = self.env["jikimo.message.queue"].sudo().search([('res_id', '=', record.id)])
if not stock_picking_send: if not stock_picking_send:
record.add_queue('订单发货提醒') record.add_queue('订单发货提醒')
def deal_stock_picking_sfp(self, message_queue_id): # 处理订单发货提醒 def deal_stock_picking_sfp(self, message_queue_id): # 处理订单发货提醒
content = None content = None
stock_picking = self.env['stock.picking'].search([('id', '=', int(message_queue_id.res_id))]) stock_picking = self.env['stock.picking'].sudo().search([('id', '=', int(message_queue_id.res_id))])
stock_picking_out = self.env['stock.picking'].search( stock_picking_out = self.env['stock.picking'].sudo().search(
[('origin', '=', stock_picking.origin), ('state', '=', 'assigned'), [('origin', '=', stock_picking.origin), ('state', '=', 'assigned'),
('picking_type_id.sequence_code', '=', 'OUT')]) ('picking_type_id.sequence_code', '=', 'OUT')])
if stock_picking_out and len(stock_picking_out) > 0: if stock_picking_out and len(stock_picking_out) > 0:
content = message_queue_id.message_template_id.content content = message_queue_id.message_template_id.content
url = self.request_url() url = self.request_url1(stock_picking_out.id)
content = content.replace('{{name}}', stock_picking_out.name).replace( content = content.replace('{{name}}', stock_picking_out.name).replace(
'{{sale_order_name}}', stock_picking_out.origin).replace('{{request_url}}', url) '{{sale_order_name}}', stock_picking_out.origin).replace('{{request_url}}', url)
logging.info('订单发货提醒: %s' % content)
return content return content
def _get_message(self, message_queue_ids): def _get_message(self, message_queue_ids):
@@ -52,10 +54,10 @@ class SFMessageStockPicking(models.Model):
i = 0 i = 0
if message_queue_id.message_template_id.name == '坯料发料提醒': if message_queue_id.message_template_id.name == '坯料发料提醒':
content = message_queue_id.message_template_id.content content = message_queue_id.message_template_id.content
stock_picking_line = self.env['stock.picking'].search([('id', '=', int(message_queue_id.res_id))]) stock_picking_line = self.env['stock.picking'].sudo().search([('id', '=', int(message_queue_id.res_id))])
mrp_production_info = self.env['mrp.production'].search( mrp_production_info = self.env['mrp.production'].sudo().search(
[('name', '=', stock_picking_line.origin)]) [('name', '=', stock_picking_line.origin)])
mrp_production_list = self.env['mrp.production'].search( mrp_production_list = self.env['mrp.production'].sudo().search(
[('product_id', '=', mrp_production_info.product_id.id)]) [('product_id', '=', mrp_production_info.product_id.id)])
for mrp_production_line in mrp_production_list: for mrp_production_line in mrp_production_list:
picking_ids = mrp_production_line.picking_ids picking_ids = mrp_production_line.picking_ids
@@ -85,9 +87,9 @@ class SFMessageStockPicking(models.Model):
return super(SFMessageStockPicking, self).get_special_url(id, tmplate_name, special_name, model_id) return super(SFMessageStockPicking, self).get_special_url(id, tmplate_name, special_name, model_id)
def request_url(self): def request_url(self):
url = self.env['ir.config_parameter'].get_param('web.base.url') url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
action_id = self.env.ref('stock.stock_picking_type_action').id action_id = self.env.ref('stock.stock_picking_type_action').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id menu_id = self.env['ir.model.data'].sudo().search([('name', '=', 'module_theme_treehouse')]).id
# 查询参数 # 查询参数
params = {'menu_id': menu_id, 'action': action_id, 'model': 'stock.picking', params = {'menu_id': menu_id, 'action': action_id, 'model': 'stock.picking',
'view_type': 'kanban'} 'view_type': 'kanban'}
@@ -96,3 +98,16 @@ class SFMessageStockPicking(models.Model):
# 拼接URL # 拼接URL
full_url = url + "/web#" + query_string full_url = url + "/web#" + query_string
return full_url return full_url
def request_url1(self, id):
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
action_id = self.env.ref('stock.action_picking_tree_all').id
menu_id = self.env['ir.model.data'].sudo().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

@@ -26,7 +26,7 @@ class SFMessageWork(models.Model):
contents = [] contents = []
product_id = [] product_id = []
bussiness_node = None bussiness_node = None
url = self.env['ir.config_parameter'].get_param('web.base.url') url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
current_time_strf = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 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 = 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') current_time_datetime = datetime.strptime(current_time, '%Y-%m-%d %H:%M:%S')
@@ -39,8 +39,8 @@ class SFMessageWork(models.Model):
for message_queue_id in message_queue_ids: for message_queue_id in message_queue_ids:
if message_queue_id.message_template_id.name == '工单已下发通知': if message_queue_id.message_template_id.name == '工单已下发通知':
content = message_queue_id.message_template_id.content content = message_queue_id.message_template_id.content
mrp_workorder_line = self.env['mrp.workorder'].search([('id', '=', int(message_queue_id.res_id))]) mrp_workorder_line = self.env['mrp.workorder'].sudo().search([('id', '=', int(message_queue_id.res_id))])
mrp_workorder_list = self.env['mrp.workorder'].search( mrp_workorder_list = self.env['mrp.workorder'].sudo().search(
[('product_id', '=', mrp_workorder_line.product_id.id), ('state', '=', 'ready'), [('product_id', '=', mrp_workorder_line.product_id.id), ('state', '=', 'ready'),
('routing_type', '=', '装夹预调')]) ('routing_type', '=', '装夹预调')])
if len(mrp_workorder_list) > 0 and mrp_workorder_line.product_id.id not in product_id: if len(mrp_workorder_list) > 0 and mrp_workorder_line.product_id.id not in product_id:
@@ -69,11 +69,11 @@ class SFMessageWork(models.Model):
search_condition = [ search_condition = [
('delivery_warning', '=', 'warning')] if bussiness_node in template_names['预警'] else [ ('delivery_warning', '=', 'warning')] if bussiness_node in template_names['预警'] else [
('delivery_warning', '=', 'overdue')] ('delivery_warning', '=', 'overdue')]
record = self.sudo().search(search_condition + [('id', '=', int(item.res_id))]) record = self.sudo().search(search_condition + [('id', '=', int(message_queue_id.res_id))])
if record: if record:
i += 1 i += 1
if i >= 1: if i >= 1:
action_id = self.env.ref('sf_manufacturing.mrp_workorder_action_tablet').id action_id = self.env.ref('sf_message.mrp_workorder_action_notify').id
url_with_id = f"{url}/web#view_type=list&action={action_id}" url_with_id = f"{url}/web#view_type=list&action={action_id}"
content_template = content.replace('{{url}}', url_with_id) content_template = content.replace('{{url}}', url_with_id)
if bussiness_node in template_names['预警']: if bussiness_node in template_names['预警']:
@@ -84,12 +84,13 @@ class SFMessageWork(models.Model):
return contents return contents
def request_url(self): def request_url(self):
url = self.env['ir.config_parameter'].get_param('web.base.url') url = self.env['ir.config_parameter'].sudo().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_issued_action').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_stock_dropshipping')]).id menu_id = self.env['ir.model.data'].sudo().search([('name', '=', 'module_stock_dropshipping')]).id
active_id = self.env['mrp.workcenter'].sudo().search([('name', '=', '工件装夹中心')]).id
# 查询参数 # 查询参数
params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder', params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder',
'view_type': 'list', 'active_id': 1} 'view_type': 'list', 'active_id': active_id}
# 拼接查询参数 # 拼接查询参数
query_string = urlencode(params) query_string = urlencode(params)
# 拼接URL # 拼接URL
@@ -115,21 +116,26 @@ class SFMessageWork(models.Model):
item.date_planned_finished.strftime("%Y-%m-%d %H:%M:%S")) 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') date_planned_finished = datetime.strptime(date_planned_finished_str, '%Y-%m-%d %H:%M:%S')
twelve_hours_ago = current_time_datetime - timedelta(hours=12) twelve_hours_ago = current_time_datetime - timedelta(hours=12)
if current_time_datetime >= date_planned_finished: if current_time_datetime >= date_planned_finished and item.delivery_warning not in ['overdue']:
logging.info("------overdue-------") logging.info("------overdue-------")
logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, " logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, "
f"Planned Finish: {date_planned_finished}") f"Planned Finish: {date_planned_finished}")
item.delivery_warning = 'overdue' item.delivery_warning = 'overdue'
elif twelve_hours_ago <= current_time_datetime <= date_planned_finished: elif twelve_hours_ago <= current_time_datetime <= date_planned_finished and item.delivery_warning not in [
'warning']:
logging.info("------warning-------") logging.info("------warning-------")
logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, " logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, "
f"Planned Finish: {date_planned_finished}") f"Planned Finish: {date_planned_finished}")
item.delivery_warning = 'warning' item.delivery_warning = 'warning'
business_node_ids = { business_node_ids = {
'装夹预调': self.env.ref('sf_message.bussiness_mrp_workorder_pre_overdue_warning').id, '装夹预调_overdue': self.env.ref('sf_message.bussiness_mrp_workorder_pre_overdue').id,
'CNC加工': self.env.ref('sf_message.bussiness_mrp_workorder_cnc_overdue_warning').id, '装夹预调_warning': self.env.ref('sf_message.bussiness_mrp_workorder_pre_overdue_warning').id,
'解除装夹': self.env.ref('sf_message.bussiness_mrp_workorder_unclamp_overdue_warning').id, 'CNC加工_overdue': self.env.ref('sf_message.bussiness_mrp_workorder_cnc_overdue').id,
'表面工艺': self.env.ref('sf_message.bussiness_mrp_workorder_surface_overdue_warning').id, 'CNC加工_warning': self.env.ref('sf_message.bussiness_mrp_workorder_cnc_overdue_warning').id,
'解除装夹_overdue': self.env.ref('sf_message.bussiness_mrp_workorder_unclamp_overdue').id,
'解除装夹_warning': self.env.ref('sf_message.bussiness_mrp_workorder_unclamp_overdue_warning').id,
'表面工艺_overdue': self.env.ref('sf_message.bussiness_mrp_workorder_surface_overdue').id,
'表面工艺_warning': self.env.ref('sf_message.bussiness_mrp_workorder_surface_overdue_warning').id,
} }
message_templates = {key: self.env["jikimo.message.template"].sudo().search([ message_templates = {key: self.env["jikimo.message.template"].sudo().search([
("model", "=", self._name), ("model", "=", self._name),
@@ -137,13 +143,17 @@ class SFMessageWork(models.Model):
]) for key in business_node_ids} ]) for key in business_node_ids}
for item in orders: for item in orders:
if item.delivery_warning in ['overdue', 'warning']: if item.delivery_warning in ['overdue', 'warning']:
bussiness_node_id = business_node_ids.get(item.routing_type) warning_type = 'warning' if item.delivery_warning == 'warning' else 'overdue'
if bussiness_node_id and message_templates[item.routing_type]: key = f"{item.routing_type}_{warning_type}"
bussiness_node_id = business_node_ids.get(key, None)
if bussiness_node_id:
message_template = message_templates.get(key)
if message_template and message_template.id:
message_queue_ids = self.env["jikimo.message.queue"].sudo().search([ message_queue_ids = self.env["jikimo.message.queue"].sudo().search([
("message_template_id", "=", message_templates[item.routing_type].id), ("message_template_id", "=", message_template.id),
("message_status", "=", "pending"), ("message_status", "=", "pending"),
("res_id", "=", item.id) ("res_id", "=", item.id)
]) ], limit=1)
if not message_queue_ids: if not message_queue_ids:
overdue_message = '工单已逾期' if item.delivery_warning == 'overdue' else '工单逾期预警' overdue_message = '工单已逾期' if item.delivery_warning == 'overdue' else '工单逾期预警'
queue_method_name = f'add_queue' queue_method_name = f'add_queue'
@@ -153,6 +163,13 @@ class SFMessageWork(models.Model):
getattr(item, queue_method_name)(*args) getattr(item, queue_method_name)(*args)
def _recover_time_warning_func(self): def _recover_time_warning_func(self):
workorder_done = self.env['mrp.workorder'].search([("state", "=", "done")]) 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 = workorder_done.filtered(lambda x: x.delivery_warning in ['overdue', 'warning'])
if workorder_overdue:
workorder_overdue.write({'delivery_warning': 'normal'}) workorder_overdue.write({'delivery_warning': 'normal'})
message_queue_ids = self.env["jikimo.message.queue"].sudo().search([
("message_status", "=", "pending"),
("res_id", "in", [item.id for item in workorder_overdue])
])
if message_queue_ids:
message_queue_ids.write({'message_status': 'cancel'})

View File

@@ -0,0 +1,65 @@
<?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>
<record model="ir.actions.act_window" id="mrp_workorder_issued_action">
<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_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

@@ -219,7 +219,7 @@ class sf_production_plan(models.Model):
return num return num
def do_production_schedule(self, count=1): def do_production_schedule(self):
""" """
排程方法 排程方法
""" """
@@ -227,29 +227,26 @@ class sf_production_plan(models.Model):
if not record.production_line_id: if not record.production_line_id:
raise ValidationError("未选择生产线") raise ValidationError("未选择生产线")
else: else:
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
if record.production_id:
if record.production_id.workorder_ids: if record.production_id.workorder_ids:
last_cnc_start = record.date_planned_start if record.date_planned_start else datetime.now()
for item in record.production_id.workorder_ids: for item in record.production_id.workorder_ids:
if item.name == 'CNC加工': if item.name == 'CNC加工':
item.date_planned_finished = datetime.now() + timedelta(days=100) # 将同一个面的所有工单筛选出来
item.date_planned_start = self.date_planned_start if self.date_planned_start else datetime.now() workorder_list = record.production_id.workorder_ids.filtered(lambda x: x.processing_panel == item.processing_panel)
routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search(
[('name', '=', 'CNC加工')], limit=1)
# 设置一个小的开始时间
item.date_planned_start = datetime.now() - timedelta(days=100)
item.date_planned_finished = last_cnc_start + timedelta(
minutes=routing_workcenter.time_cycle)
item.date_planned_start = last_cnc_start
record.sudo().production_id.plan_start_processing_time = item.date_planned_start record.sudo().production_id.plan_start_processing_time = item.date_planned_start
item.date_planned_finished = item.date_planned_start + timedelta( item.duration_expected = routing_workcenter.time_cycle
minutes=record.env['mrp.routing.workcenter'].sudo().search( pre_duration , next_duration = record.calculate_plan_time(item, workorder_list)
[('name', '=', 'CNC加工')]).time_cycle) record.date_planned_finished = item.date_planned_finished
item.duration_expected = record.env['mrp.routing.workcenter'].sudo().search( # 计算下一个cnc工单的开始时间
[('name', '=', 'CNC加工')]).time_cycle last_cnc_start = workorder_list[-1].date_planned_finished + timedelta(minutes=pre_duration)
record.calculate_plan_time_before(item, workorder_id_list)
record.calculate_plan_time_after(item, workorder_id_list)
record.date_planned_start, record.date_planned_finished = \
item.date_planned_start, item.date_planned_finished
record.state = 'done' record.state = 'done'
record.date_planned_finished = record.date_planned_start + timedelta(
minutes=60) if not record.date_planned_finished else record.date_planned_finished
# record.production_id.schedule_state = '已排' # record.production_id.schedule_state = '已排'
record.sudo().production_id.schedule_state = '已排' record.sudo().production_id.schedule_state = '已排'
record.sudo().production_id.process_state = '待装夹' record.sudo().production_id.process_state = '待装夹'
@@ -282,9 +279,9 @@ class sf_production_plan(models.Model):
} }
# 处理是否可排程 # 处理是否可排程
def deal_processing_schedule(self, date_planned_start, count): def deal_processing_schedule(self, date_planned_start,):
for record in self: count = len(self)
workcenter_ids = record.production_line_id.mrp_workcenter_ids workcenter_ids = self.production_line_id.mrp_workcenter_ids
if not workcenter_ids: if not workcenter_ids:
raise UserError('生产线没有配置工作中心') raise UserError('生产线没有配置工作中心')
production_lines = workcenter_ids.filtered(lambda b: "自动生产线" in b.name) production_lines = workcenter_ids.filtered(lambda b: "自动生产线" in b.name)
@@ -301,35 +298,47 @@ class sf_production_plan(models.Model):
raise UserError('当前计划开始时间不能预约排程,生产线该时间段没有可排程的资源') raise UserError('当前计划开始时间不能预约排程,生产线该时间段没有可排程的资源')
return True return True
def calculate_plan_time_before(self, item, workorder_id_list): def calculate_plan_time(self, item, workorder_list):
""" """
根据CNC工单的时间去计算之前的其他工单的开始结束时间 根据CNC工单的时间去计算之前的其他工单的开始结束时间
""" """
sequence = workorder_id_list.index(item.id) - 1 item_position = 0
# 计算CNC加工之前工单的开始结束时间 for index, workorder in enumerate(workorder_list):
for i in range(1 if sequence == 0 else sequence): if workorder.id == item.id:
current_workorder_id = (item.id - (i + 1)) item_position = index
current_workorder_obj = self.env['mrp.workorder'].sudo().search( break
[('id', '=', current_workorder_id)]) routing_workcenters = self.env['mrp.routing.workcenter'].sudo().search([])
old_workorder_obj = self.env['mrp.workorder'].sudo().search( # 记录所有前序工序时长
[('id', '=', (current_workorder_id + 1))]) previous_workorder_duration = 0
work_order = self.env['mrp.workorder'].sudo().search( for i in range(item_position, -1, -1):
[('production_id', '=', self.production_id.id), ('id', '=', current_workorder_id)]) if i < 1:
work_order.date_planned_finished = datetime.now() + timedelta(days=100) break
work_order.date_planned_start = old_workorder_obj.date_planned_start - timedelta( current_workorder = workorder_list[i]
minutes=self.env['mrp.routing.workcenter'].sudo().search( next_workorder = workorder_list[i - 1]
[('name', '=', current_workorder_obj.name)]).time_cycle) routing_workcenter = routing_workcenters.filtered(lambda x: x.name == next_workorder.name)[0]
work_order.date_planned_finished = old_workorder_obj.date_planned_start # 设置一个小的开始时间
work_order.duration_expected = self.env['mrp.routing.workcenter'].sudo().search( next_workorder.date_planned_start = datetime.now() - timedelta(days=100)
[('name', '=', current_workorder_obj.name)]).time_cycle next_workorder.date_planned_finished = current_workorder.date_planned_start
first_workorder = self.env['mrp.workorder'].sudo().search([('id', '=', workorder_id_list[0])]) next_workorder.date_planned_start = next_workorder.date_planned_finished - timedelta(
second_workorder = self.env['mrp.workorder'].sudo().search([('id', '=', workorder_id_list[1])]) minutes=routing_workcenter.time_cycle)
if second_workorder.date_planned_start < first_workorder.date_planned_finished: next_workorder.duration_expected = routing_workcenter.time_cycle
item.date_planned_start += timedelta(minutes=60) previous_workorder_duration += routing_workcenter.time_cycle
item.date_planned_finished += timedelta(minutes=60) # 记录所有后续工序时长
item.duration_expected = self.env['mrp.routing.workcenter'].sudo().search( next_workorder_duration = 0
[('name', '=', 'CNC加工')]).time_cycle for i in range(item_position, len(workorder_list) - 1):
self.calculate_plan_time_before(item, workorder_id_list) if i > len(workorder_list) - 1:
break
current_workorder = workorder_list[i]
next_workorder = workorder_list[i + 1]
routing_workcenter = routing_workcenters.filtered(lambda x: x.name == next_workorder.name)[0]
# 设置一个小的开始时间
next_workorder.date_planned_start = datetime.now() - timedelta(days=100)
next_workorder.date_planned_finished = current_workorder.date_planned_finished + timedelta(
minutes=routing_workcenter.time_cycle)
next_workorder.date_planned_start = current_workorder.date_planned_finished
next_workorder.duration_expected = routing_workcenter.time_cycle
next_workorder_duration += routing_workcenter.time_cycle
return previous_workorder_duration, next_workorder_duration
def calculate_plan_time_after(self, item, workorder_id_list): def calculate_plan_time_after(self, item, workorder_id_list):
""" """

View File

@@ -31,22 +31,24 @@ class Action_Plan_All_Wizard(models.TransientModel):
# 确认排程按钮 # 确认排程按钮
def action_plan_all(self): def action_plan_all(self):
# 使用传递过来的计划ID # 使用传递过来的计划ID
temp_plan_ids = self.plan_ids self.plan_ids.production_line_id = self.production_line_id.id
self.plan_ids.date_planned_start = self.date_planned_start
# 在这里添加您的逻辑来处理这些ID # 在这里添加您的逻辑来处理这些ID
count = len(temp_plan_ids) + 1 # 判断能否排成
for plan in temp_plan_ids: self.plan_ids.deal_processing_schedule(self.date_planned_start)
count = count - 1 self.plan_ids.do_production_schedule()
# 处理每个计划 # for plan in temp_plan_ids:
# 比如更新计划状态、分配资源等 # # 处理每个计划
# 示例plan.state = 'scheduled' # # 比如更新计划状态、分配资源等
print('处理计划:', plan.id) # # 示例plan.state = 'scheduled'
# 拿到计划对象 # print('处理计划:', plan.id)
plan_obj = self.env['sf.production.plan'].browse(plan.id) # # 拿到计划对象
plan_obj.production_line_id = self.production_line_id.id # plan_obj = self.env['sf.production.plan'].browse(plan.id)
plan.date_planned_start = self.date_planned_start # plan_obj.production_line_id = self.production_line_id.id
plan_obj.do_production_schedule(count) # plan.date_planned_start = self.date_planned_start
# plan_obj.do_production_schedule()
# plan_obj.state = 'done' # plan_obj.state = 'done'
print('处理计划:', plan.id, '完成') _logger.info('处理计划: %s 完成', self.plan_ids.ids)
# # 获取当前生产线 # # 获取当前生产线
# production_line_id = self.production_line_id # production_line_id = self.production_line_id
@@ -73,4 +75,14 @@ class Action_Plan_All_Wizard(models.TransientModel):
# if all(production_order_plan_state == '已取消' for production_order_plan_state in production_order_plan_state_list): # if all(production_order_plan_state == '已取消' for production_order_plan_state in production_order_plan_state_list):
# raise UserError('当前生产线的所有生产订单都已取消,请勿重复排程!') # raise UserError('当前生产线的所有生产订单都已取消,请勿重复排程!')
# # 如果当前生产线的所有生产订单的排程状态都是已暂停,则报错 # # 如果当前生产线的所有生产订单的排程状态都是已暂停,则报错
# if all(production_order_plan_state == '已暂停' for production_order_plan_state in production # if all(production_order_plan_state == '已暂停' for production_order_plan_state in production_order_plan_state_list):
# raise UserError('当前生产线的所有生产订单都已暂停,请勿重复排程!')
# # 如果当前生产线的所有生产订单的排程状态都是已完成,则报错
# if all(production_order_plan_state == '已完成' for production_order_plan_state in production_order_plan_state_list):
# raise UserError('当前生产线的所有生产订单都已完成,请勿重复排程!')
# # 如果当前生产线的所有生产订单的排程状态都是已取消,则报错
# if all(production_order_plan_state == '已取消' for production_order_plan_state in production_order_plan_state_list):
# raise UserError('当前生产线的所有生产订单都已取消,请勿重复排程!')
# # 如果当前生产线的所有生产订单的排程状态都是已暂停,则报错
# if all(production_order_plan_state == '已暂停' for production_order_plan_state in production_order_plan_state_list):
# raise UserError('当前生产线的所有生产订单都已暂停,请勿重复排程!')

View File

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

View File

@@ -31,8 +31,8 @@ class SfQualityCncTest(models.Model):
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因") ("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因")
detailed_reason = fields.Text('详细原因') detailed_reason = fields.Text('详细原因')
# machining_drawings = fields.Binary(related='workorder_id.machining_drawings', string='2D加工图纸', readonly=True) machining_drawings = fields.Binary('2D加工图纸', related='workorder_id.machining_drawings', readonly=True)
# quality_standard = fields.Binary(related='workorder_id.quality_standard', string='质检标准', readonly=True) quality_standard = fields.Binary('质检标准', related='workorder_id.quality_standard', readonly=True)
def submit_pass(self): def submit_pass(self):
if self.test_results in ['返工', '报废']: if self.test_results in ['返工', '报废']:

View File

@@ -107,10 +107,10 @@
</group> </group>
</page> </page>
<page string="2D图纸"> <page string="2D图纸">
<!-- <field name="machining_drawings" string="" widget="pdf_viewer"/>--> <field name="machining_drawings" string="" widget="adaptive_viewer"/>
</page> </page>
<page string="客户质量标准"> <page string="客户质量标准">
<!-- <field name="quality_standard" string=""/>--> <field name="quality_standard" string="" widget="adaptive_viewer"/>
</page> </page>
<page string="其他" attrs="{'invisible': [('state','=', 'waiting')]}"> <page string="其他" attrs="{'invisible': [('state','=', 'waiting')]}">
<group> <group>

View File

@@ -20,6 +20,12 @@ class QuickEasyOrder(models.Model):
_description = '简易下单' _description = '简易下单'
_order = 'id desc' _order = 'id desc'
def _get_machining_precision(self):
machinings = self.env['sf.machining.accuracy'].sudo().search([])
list = [(m.sync_id, m.name) for m in machinings]
return list
name = fields.Char('订单编号', default=lambda self: self.env['ir.sequence'].next_by_code('quick.easy.order')) name = fields.Char('订单编号', default=lambda self: self.env['ir.sequence'].next_by_code('quick.easy.order'))
model_length = fields.Float('长(mm)', digits=(16, 3)) model_length = fields.Float('长(mm)', digits=(16, 3))
model_width = fields.Float('宽(mm)', digits=(16, 3)) model_width = fields.Float('宽(mm)', digits=(16, 3))
@@ -27,12 +33,7 @@ class QuickEasyOrder(models.Model):
model_volume = fields.Float('体积(mm³)', digits=(16, 3)) model_volume = fields.Float('体积(mm³)', digits=(16, 3))
model_processing_side = fields.Char('加工面', default='A') model_processing_side = fields.Char('加工面', default='A')
model_feature = fields.Char('特征') model_feature = fields.Char('特征')
machining_precision = fields.Selection([ machining_precision = fields.Selection(selection=_get_machining_precision, string='加工精度')
('0.10', '±0.10mm'),
('0.05', '±0.05mm'),
('0.03', '±0.03mm'),
('0.02', '±0.02mm'),
('0.01', '±0.01mm')], string='加工精度', default='0.10')
material_id = fields.Many2one('sf.production.materials', '材料', tracking=True) material_id = fields.Many2one('sf.production.materials', '材料', tracking=True)
material_model_id = fields.Many2one('sf.materials.model', '型号', domain="[('materials_id', '=', material_id)]", material_model_id = fields.Many2one('sf.materials.model', '型号', domain="[('materials_id', '=', material_id)]",
tracking=True) tracking=True)
@@ -219,7 +220,14 @@ class QuickEasyOrder(models.Model):
'total_amount': item.price, 'total_amount': item.price,
'remark': '', 'remark': '',
'manual_quotation': True, 'manual_quotation': True,
'barcode': barcode 'barcode': barcode,
'part_number': item.part_drawing_number,
'machining_drawings_name': '',
'quality_standard_name': '',
'machining_drawings_mimetype': '',
'quality_standard_mimetype': '',
'machining_drawings': item.machining_drawings,
'quality_standard': '',
}) })
# res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list']) # res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list'])
product_id = self.env.ref('sf_dlm.product_template_sf').sudo() product_id = self.env.ref('sf_dlm.product_template_sf').sudo()

View File

@@ -55,8 +55,8 @@ class ReSaleOrder(models.Model):
store=True, readonly=False, copy=False, precompute=True, store=True, readonly=False, copy=False, precompute=True,
states=READONLY_FIELD_STATES, default=fields.Datetime.now) states=READONLY_FIELD_STATES, default=fields.Datetime.now)
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效') delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
tracking=True)
# 业务平台分配工厂后在智能工厂先创建销售订单 # 业务平台分配工厂后在智能工厂先创建销售订单
def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address, def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address,
@@ -118,17 +118,23 @@ class ReSaleOrder(models.Model):
# 业务平台分配工厂时在创建完产品后再创建销售明细信息 # 业务平台分配工厂时在创建完产品后再创建销售明细信息
def sale_order_create_line(self, product, item): def sale_order_create_line(self, product, item):
machining_accuracy_name = ''
if product.model_machining_precision:
machining_accuracy_name = self.env['sf.machining.accuracy'].sudo().search(
[('sync_id', '=', product.model_machining_precision)]).name
vals = { vals = {
'order_id': self.id, 'order_id': self.id,
'product_id': product.id, 'product_id': product.id,
'name': '%s/%s/%s/%s/±%s/%s' % ( 'name': '%s/%s/%s/%s/%s/%s' % (
product.model_long, product.model_width, product.model_height, product.model_volume, product.model_long, product.model_width, product.model_height, product.model_volume,
product.model_machining_precision, machining_accuracy_name,
product.materials_id.name), product.materials_id.name),
'price_unit': product.list_price, 'price_unit': product.list_price,
'product_uom_qty': item['number'], 'product_uom_qty': item['number'],
'model_glb_file': base64.b64decode(item['model_file']), '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) return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
@@ -169,6 +175,9 @@ class ResaleOrderLine(models.Model):
check_status = fields.Selection(related='order_id.check_status') check_status = fields.Selection(related='order_id.check_status')
remark = fields.Char('备注') remark = fields.Char('备注')
is_incoming_material = fields.Boolean('是否带料', default=False)
incoming_size = fields.Char('带料尺寸')
@api.depends('product_template_id') @api.depends('product_template_id')
def _compute_model_glb_file(self): def _compute_model_glb_file(self):
for line in self: for line in self:

View File

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

View File

@@ -95,7 +95,7 @@
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute> <attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
</field> </field>
<field name="payment_term_id" position="after"> <field name="payment_term_id" position="after">
<field name="deadline_of_delivery" readonly="1"/> <field name="deadline_of_delivery" readonly="0"/>
<field name="payments_way" attrs="{'readonly': [('state', 'in', ('sale','cancel'))]}"/> <field name="payments_way" attrs="{'readonly': [('state', 'in', ('sale','cancel'))]}"/>
<field name="pay_way" attrs="{'readonly': [('state', 'in', ('sale','cancel'))]}"/> <field name="pay_way" attrs="{'readonly': [('state', 'in', ('sale','cancel'))]}"/>
<!-- <field name="schedule_status" readonly="1"/> --> <!-- <field name="schedule_status" readonly="1"/> -->
@@ -118,6 +118,8 @@
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="replace"> <xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="replace">
<field name="name" widget="section_and_note_text" optional="show" <field name="name" widget="section_and_note_text" optional="show"
string="参数说明(长/宽/高/体积/精度/材质)"/> string="参数说明(长/宽/高/体积/精度/材质)"/>
<field name="is_incoming_material" optional="hide"/>
<field name="incoming_size" optional="hide"/>
</xpath> </xpath>
<field name="user_id" position="attributes"> <field name="user_id" position="attributes">
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute> <attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
@@ -162,6 +164,11 @@
<xpath expr="//button[@name='action_cancel']" position="attributes"> <xpath expr="//button[@name='action_cancel']" position="attributes">
<attribute name="string">拒绝接单</attribute> <attribute name="string">拒绝接单</attribute>
</xpath> </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> </field>
</record> </record>
@@ -265,7 +272,6 @@
</field> </field>
</field> </field>
</record> </record>
<record id="sale.product_template_action" model="ir.actions.act_window"> <record id="sale.product_template_action" model="ir.actions.act_window">
<field name="context">{"search_default_categ_id":1, <field name="context">{"search_default_categ_id":1,
"search_default_filter_to_sell":1,"sale_multi_pricelist_product_template": 1} "search_default_filter_to_sell":1,"sale_multi_pricelist_product_template": 1}

View File

@@ -51,6 +51,8 @@ class FunctionalCuttingToolEntity(models.Model):
string='位置', compute='_compute_current_location_id', store=True) string='位置', compute='_compute_current_location_id', store=True)
image = fields.Binary('图片', readonly=True) image = fields.Binary('图片', readonly=True)
stock_num = fields.Integer('库存变更次数', default=0)
safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools', safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools',
string='功能刀具安全库存', readonly=True) string='功能刀具安全库存', readonly=True)
@@ -71,7 +73,7 @@ class FunctionalCuttingToolEntity(models.Model):
}) })
@api.depends('barcode_id.quant_ids', 'barcode_id.quant_ids.location_id', 'functional_tool_status', @api.depends('barcode_id.quant_ids', 'barcode_id.quant_ids.location_id', 'functional_tool_status',
'current_shelf_location_id') 'current_shelf_location_id', 'stock_num')
def _compute_current_location_id(self): def _compute_current_location_id(self):
for record in self: for record in self:
if record.functional_tool_status == '已拆除': if record.functional_tool_status == '已拆除':

View File

@@ -175,7 +175,9 @@ class MrpProduction(models.Model):
cnc_ids = self.env['sf.cnc.processing'].sudo().search( cnc_ids = self.env['sf.cnc.processing'].sudo().search(
[('workorder_id', 'in', workorder_ids.ids), ('cutting_tool_name', 'in', invalid_tool)]) [('workorder_id', 'in', workorder_ids.ids), ('cutting_tool_name', 'in', invalid_tool)])
if cnc_ids: if cnc_ids:
cnc_ids.write({'tool_state': '2'}) for cnc_id in cnc_ids:
cnc_id.tool_state = '2'
# cnc_ids.write({'tool_state': '2'})
# 创建制造订单无效刀检测结果记录 # 创建制造订单无效刀检测结果记录
for production_id in self: for production_id in self:
for processing_panel in list(set(invalid_tool_processing_panel)): for processing_panel in list(set(invalid_tool_processing_panel)):
@@ -204,7 +206,9 @@ class MrpProduction(models.Model):
cnc_ids = self.env['sf.cnc.processing'].sudo().search( cnc_ids = self.env['sf.cnc.processing'].sudo().search(
[('workorder_id', 'in', workorder_ids.ids), ('cutting_tool_name', 'in', missing_tool_1)]) [('workorder_id', 'in', workorder_ids.ids), ('cutting_tool_name', 'in', missing_tool_1)])
if cnc_ids: if cnc_ids:
cnc_ids.write({'tool_state': '1'}) for cnc_id in cnc_ids:
cnc_id.tool_state = '1'
# cnc_ids.write({'tool_state': '1'})
if missing_tool_2 and invalid_tool == []: if missing_tool_2 and invalid_tool == []:
logging.info(f'库存缺刀:{missing_tool_2}') logging.info(f'库存缺刀:{missing_tool_2}')
# 调用CAM工单程序用刀计划创建方法 # 调用CAM工单程序用刀计划创建方法

View File

@@ -53,6 +53,13 @@ class StockMoveLine(models.Model):
[('barcode_id', '=', line_id.lot_id.id), [('barcode_id', '=', line_id.lot_id.id),
('functional_tool_status', '=', '正常')]).cnc_function_tool_use_verify() ('functional_tool_status', '=', '正常')]).cnc_function_tool_use_verify()
for move_line in move_lines:
if move_line.lot_id:
tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('barcode_id', '=', move_line.lot_id.id),
('functional_tool_status', '=', '正常')])
tool_id.stock_num += tool_id.stock_num
class StockPicking(models.Model): class StockPicking(models.Model):
_inherit = 'stock.picking' _inherit = 'stock.picking'