Compare commits
407 Commits
release/re
...
release/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a6cf74bc2 | ||
|
|
c0202330f8 | ||
|
|
1dabdd157e | ||
|
|
36dc8070fa | ||
|
|
d1656278ea | ||
|
|
0675937588 | ||
|
|
c0d006d139 | ||
|
|
2fa47eae27 | ||
|
|
cb2e1ecabe | ||
|
|
9f1233d20e | ||
|
|
a783f7ec7b | ||
|
|
db50253100 | ||
|
|
5f7f905540 | ||
|
|
1c86cc1421 | ||
|
|
1ea6f649f0 | ||
|
|
f0421b873c | ||
|
|
913feea2a9 | ||
|
|
5d36513e59 | ||
|
|
94d6085f92 | ||
|
|
f361106c40 | ||
|
|
a46cd0f515 | ||
|
|
2c6e1a40f5 | ||
|
|
ffb775abb7 | ||
|
|
2c15532c73 | ||
|
|
1980ee2a9a | ||
|
|
bba4e55770 | ||
|
|
a9bbe98e8f | ||
|
|
11e3bbddd8 | ||
|
|
c01dfddfb4 | ||
|
|
50dcc9f7ba | ||
|
|
41a7aea01e | ||
|
|
066b256b0c | ||
|
|
754047bf02 | ||
|
|
f5bf95ab6e | ||
|
|
5ea25fae73 | ||
|
|
c367e39d5f | ||
|
|
dfec70081b | ||
|
|
d0c35695d5 | ||
|
|
95eb6bd18b | ||
|
|
599d2280f5 | ||
|
|
e1397f4b93 | ||
|
|
71c606974c | ||
|
|
a0ed14aed1 | ||
|
|
be3d4979b7 | ||
|
|
373ce89a2c | ||
|
|
56317ab111 | ||
|
|
683d79a4e3 | ||
|
|
362801f527 | ||
|
|
a81ad08740 | ||
|
|
d2d5702125 | ||
|
|
9c47a6bdba | ||
|
|
f0a887887e | ||
|
|
fffe0a230b | ||
|
|
2600d15e2b | ||
|
|
c60b91c315 | ||
|
|
639dd4e78d | ||
|
|
3c4286319f | ||
|
|
55016918eb | ||
|
|
4236600b39 | ||
|
|
e84842d0a3 | ||
|
|
60df55d71e | ||
|
|
6643684e9b | ||
|
|
f77a1f6167 | ||
|
|
a467aef925 | ||
|
|
b1b805959a | ||
|
|
e602095b50 | ||
|
|
ba05827126 | ||
|
|
89bd9533d7 | ||
|
|
fd2228ba59 | ||
|
|
2758817048 | ||
|
|
2e916337e9 | ||
|
|
47b8a0051b | ||
|
|
76e6502afe | ||
|
|
1b96f420ec | ||
|
|
00645364b3 | ||
|
|
fdad5100ae | ||
|
|
8cd03a1040 | ||
|
|
41c2523201 | ||
|
|
22a1ae11a6 | ||
|
|
4939c6d6db | ||
|
|
460670843f | ||
|
|
66caeee1cd | ||
|
|
28041cbef9 | ||
|
|
fddddf1649 | ||
|
|
3e61e31314 | ||
|
|
549a64b012 | ||
|
|
dbaad85670 | ||
|
|
b731ffba33 | ||
|
|
9048b32405 | ||
|
|
98d2aa756a | ||
|
|
3749872780 | ||
|
|
de8bebc1f9 | ||
|
|
b468ac216c | ||
|
|
05f5b10833 | ||
|
|
8686d93651 | ||
|
|
258e24eb05 | ||
|
|
cc4b58b136 | ||
|
|
d36250aa48 | ||
|
|
ad43b43beb | ||
|
|
f9ace6da7c | ||
|
|
12b4b418ea | ||
|
|
60b77e09d6 | ||
|
|
891fe257e1 | ||
|
|
6859458db2 | ||
|
|
ca7c3867cd | ||
|
|
4bcf8236ef | ||
|
|
74d557a0fc | ||
|
|
3686c0e070 | ||
|
|
536d7e9e79 | ||
|
|
67e79c5fb8 | ||
|
|
0c3217824e | ||
|
|
9eddfe36d6 | ||
|
|
9655281b67 | ||
|
|
18b584438a | ||
|
|
709f29185d | ||
|
|
886de3195c | ||
|
|
d9e5ffa68d | ||
|
|
030a900580 | ||
|
|
4370236edf | ||
|
|
e01209f343 | ||
|
|
b4803f03fa | ||
|
|
c9d4f0667a | ||
|
|
30c823189c | ||
|
|
3ed503391e | ||
|
|
befe0c2b00 | ||
|
|
44a9ad340b | ||
|
|
55bac0020f | ||
|
|
d3124bb9fe | ||
|
|
64fd6ef5dc | ||
|
|
001b2ead57 | ||
|
|
d0be097a9b | ||
|
|
0be8d0fbb2 | ||
|
|
71faa8a835 | ||
|
|
12afc1ef83 | ||
|
|
34624e6592 | ||
|
|
a16effd8db | ||
|
|
f59299d4d5 | ||
|
|
c7cef27ad6 | ||
|
|
b88b0fc38a | ||
|
|
4297d41dda | ||
|
|
3f85d058cc | ||
|
|
680bed9944 | ||
|
|
d3e307d195 | ||
|
|
86a011343d | ||
|
|
fe4bd3834e | ||
|
|
d3992c2a2e | ||
|
|
e62ed636e7 | ||
|
|
f0fdeff699 | ||
|
|
dec85dc92f | ||
|
|
f4f9591f35 | ||
|
|
efb7334486 | ||
|
|
b9c1224442 | ||
|
|
ca1a3ff120 | ||
|
|
da8e543819 | ||
|
|
eb236fea11 | ||
|
|
1d271d9167 | ||
|
|
c5cf614645 | ||
|
|
167c280fa4 | ||
|
|
69157a7b1f | ||
|
|
2939e6bf82 | ||
|
|
96bbf3a677 | ||
|
|
e3580d9ac8 | ||
|
|
ded1789813 | ||
|
|
759f947fa7 | ||
|
|
302aed16ec | ||
|
|
7d1db793b1 | ||
|
|
83396f5434 | ||
|
|
fe9baf08f0 | ||
|
|
b47cd0cdfe | ||
|
|
251e289fd1 | ||
|
|
1d4ecb9895 | ||
|
|
f3a7dcc6a4 | ||
|
|
ebd56eb5e0 | ||
|
|
4f99a162b5 | ||
|
|
28843b0733 | ||
|
|
8a0c968b10 | ||
|
|
9d3c4f8163 | ||
|
|
08831812ae | ||
|
|
8b75658787 | ||
|
|
25ac346cb7 | ||
|
|
2d15782228 | ||
|
|
856237c4cb | ||
|
|
a47c751b04 | ||
|
|
9bec39f4e6 | ||
|
|
33bf88968c | ||
|
|
7163e025d2 | ||
|
|
11ec448e81 | ||
|
|
6c2fb043c4 | ||
|
|
1dcecea3d5 | ||
|
|
88f3ac3d4e | ||
|
|
983618d798 | ||
|
|
7a9c0ff163 | ||
|
|
77f7602b23 | ||
|
|
70b8521b90 | ||
|
|
1b89642dae | ||
|
|
1968ee17cb | ||
|
|
5e83fb382f | ||
|
|
974671ee07 | ||
|
|
d8b4797ffe | ||
|
|
b07e7707c7 | ||
|
|
8726f8cac3 | ||
|
|
cb7960387b | ||
|
|
6eaf92b841 | ||
|
|
ec0b5e88b6 | ||
|
|
f1b8ee41bc | ||
|
|
97c0b95e2d | ||
|
|
7ac342bfd4 | ||
|
|
6c820ead44 | ||
|
|
c536dde2cc | ||
|
|
801ff9e076 | ||
|
|
d0e049e881 | ||
|
|
81158e2fb4 | ||
|
|
3404cccdc8 | ||
|
|
45bb78d7e9 | ||
|
|
83334e2915 | ||
|
|
d4c30f645b | ||
|
|
bd642812a9 | ||
|
|
3eca74518a | ||
|
|
37977be862 | ||
|
|
a0bd214118 | ||
|
|
7885794322 | ||
|
|
7152b54017 | ||
|
|
0fef714d61 | ||
|
|
6a2ff72dce | ||
|
|
3094379e86 | ||
|
|
77815c45a0 | ||
|
|
dd7c69ce1b | ||
|
|
e02f792300 | ||
|
|
9aca786522 | ||
|
|
134e23ea2f | ||
|
|
129f8a4d7d | ||
|
|
79e3006cdb | ||
|
|
6b140fe6dd | ||
|
|
7533d23d3e | ||
|
|
e8512b23e4 | ||
|
|
b582bfbafa | ||
|
|
11907d4c5e | ||
|
|
ed4903b6f1 | ||
|
|
b383a6d229 | ||
|
|
27eb959a2a | ||
|
|
1672a3982e | ||
|
|
40f8392bd3 | ||
|
|
1c8644983b | ||
|
|
566d9fce9c | ||
|
|
b071b14bbd | ||
|
|
9d95442720 | ||
|
|
fd225fa0e1 | ||
|
|
52fa229896 | ||
|
|
937efa5f0f | ||
|
|
87153fab3f | ||
|
|
21c33bb662 | ||
|
|
b0da7977f5 | ||
|
|
ae6764495e | ||
|
|
869e3e4b4f | ||
|
|
050e82673a | ||
|
|
1210625cfc | ||
|
|
804b401a87 | ||
|
|
a7a8e73616 | ||
|
|
d60fefb2ec | ||
|
|
4a86871039 | ||
|
|
93c3548b40 | ||
|
|
6c6fe44d45 | ||
|
|
bb33a1d093 | ||
|
|
396084a498 | ||
|
|
73cc244994 | ||
|
|
fa6303bbef | ||
|
|
5ca555c520 | ||
|
|
487f6c2054 | ||
|
|
9ec37f5d5b | ||
|
|
cbc8a41984 | ||
|
|
025ad213d6 | ||
|
|
0b267cc88a | ||
|
|
0bc4072a8f | ||
|
|
957c5583bd | ||
|
|
9c4c2b85dd | ||
|
|
56af286500 | ||
|
|
cc83029c72 | ||
|
|
79ab1cc573 | ||
|
|
bda3df7806 | ||
|
|
150b684354 | ||
|
|
d69dc20fd1 | ||
|
|
e9c9b77112 | ||
|
|
495f92bd80 | ||
|
|
8a97fd08e2 | ||
|
|
1551ea4b12 | ||
|
|
75c5cca9a0 | ||
|
|
6b6be85057 | ||
|
|
7fb3c32d07 | ||
|
|
8203975142 | ||
|
|
449cf5bfb1 | ||
|
|
d7d5ccc142 | ||
|
|
8710df6dc2 | ||
|
|
f5c1457707 | ||
|
|
5155135cb4 | ||
|
|
4421eed1d0 | ||
|
|
5be5e8b3ec | ||
|
|
46e3a23492 | ||
|
|
675b09390b | ||
|
|
34251b4027 | ||
|
|
c4621d36a3 | ||
|
|
7bdc4b463a | ||
|
|
ea88b5418f | ||
|
|
f5a64caf81 | ||
|
|
1e5f26d645 | ||
|
|
ace32d9490 | ||
|
|
5db2f1fc70 | ||
|
|
960c940505 | ||
|
|
ee1629b40a | ||
|
|
06de5f6a2d | ||
|
|
c1eff705c2 | ||
|
|
8e3c7f9732 | ||
|
|
2591e627f0 | ||
|
|
4c66d86ee6 | ||
|
|
d4bc1c13ea | ||
|
|
4c845ee9fd | ||
|
|
726c3aede1 | ||
|
|
871c406c09 | ||
|
|
2ba9695c34 | ||
|
|
e1db34f25d | ||
|
|
e496555ff3 | ||
|
|
404a41294c | ||
|
|
e124560089 | ||
|
|
fd3a363bf6 | ||
|
|
9f6563186c | ||
|
|
1b174c5805 | ||
|
|
849b7be20d | ||
|
|
9d32bf8363 | ||
|
|
998daaa7f7 | ||
|
|
b23cb9af6e | ||
|
|
56adaddefc | ||
|
|
4a648fbd7b | ||
|
|
a3bf451d83 | ||
|
|
2919a3c159 | ||
|
|
8f6e2bc13d | ||
|
|
909230c1cc | ||
|
|
db8c338588 | ||
|
|
f319a9adf4 | ||
|
|
172e420939 | ||
|
|
0c3727540e | ||
|
|
5668722109 | ||
|
|
2d80355559 | ||
|
|
d281026086 | ||
|
|
5c35a8c38d | ||
|
|
3b24f90385 | ||
|
|
14355606c7 | ||
|
|
5997cbcb0e | ||
|
|
f07d7611d0 | ||
|
|
b106d56f3f | ||
|
|
3156052604 | ||
|
|
c8de75ceae | ||
|
|
d4b1f8f1a1 | ||
|
|
5378d62551 | ||
|
|
424f7196f8 | ||
|
|
c2723d9d05 | ||
|
|
7bf001927a | ||
|
|
84d67d285e | ||
|
|
a583b483e3 | ||
|
|
719a96f983 | ||
|
|
08fd0b01d3 | ||
|
|
db7fbed177 | ||
|
|
ad149a58ea | ||
|
|
0d96cd070c | ||
|
|
37f030c2db | ||
|
|
e2a62325f8 | ||
|
|
0db103cfc7 | ||
|
|
05f2cb553d | ||
|
|
c597471949 | ||
|
|
70ffbafac4 | ||
|
|
1cb7af072e | ||
|
|
4f6b1d0342 | ||
|
|
9bdcf0dd92 | ||
|
|
bcb60425b2 | ||
|
|
22643368fa | ||
|
|
aeb100923f | ||
|
|
53c6d6015e | ||
|
|
131e9329de | ||
|
|
dbd5c488f8 | ||
|
|
f8ba414229 | ||
|
|
7fd3647afb | ||
|
|
f5be9c6e65 | ||
|
|
c275a39a15 | ||
|
|
d07ab53aeb | ||
|
|
55accb714a | ||
|
|
5bd3eddfd5 | ||
|
|
c8bcd4d0f5 | ||
|
|
2cbe5ed394 | ||
|
|
1f1cb17a40 | ||
|
|
2ff935f68d | ||
|
|
098745ec50 | ||
|
|
94175f2039 | ||
|
|
1940116a35 | ||
|
|
f4eb378bea | ||
|
|
dcbb60b088 | ||
|
|
88ef9c106d | ||
|
|
0f7f12008f | ||
|
|
f44836705b | ||
|
|
35ac51bc10 | ||
|
|
eb2851391b | ||
|
|
86f67556ce | ||
|
|
e437875a92 | ||
|
|
9e56aeda67 | ||
|
|
b4535e88c9 | ||
|
|
be94cd0d54 | ||
|
|
65e209fe2a | ||
|
|
27ba002b51 | ||
|
|
2cd83c87e2 | ||
|
|
ba87d07af7 |
@@ -5,7 +5,7 @@ import {patch} from '@web/core/utils/patch';
|
||||
import {_t} from "@web/core/l10n/translation";
|
||||
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
|
||||
import {ListRenderer} from "@web/views/list/list_renderer";
|
||||
import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field";
|
||||
// import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field";
|
||||
|
||||
import {Field} from "@web/views/fields/field";
|
||||
|
||||
@@ -153,34 +153,34 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
|
||||
|
||||
|
||||
// 根据进度条设置水印
|
||||
const statusbar_params = {
|
||||
'已完工': 'bg-primary',
|
||||
'完成': 'bg-primary',
|
||||
'采购订单': 'bg-primary',
|
||||
'作废': 'bg-danger',
|
||||
'封存(报废)': 'bg-danger',
|
||||
}
|
||||
patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', {
|
||||
setup() {
|
||||
owl.onMounted(this.ribbons);
|
||||
return this._super(...arguments);
|
||||
},
|
||||
ribbons() {
|
||||
try {
|
||||
const dom = $('.o_form_sheet.position-relative')
|
||||
const status = statusbar_params[this.currentName]
|
||||
if(status && dom.length) {
|
||||
dom.prepend(`<div class="o_widget o_widget_web_ribbon">
|
||||
<div class="ribbon ribbon-top-right">
|
||||
<span class="bg-opacity-75 ${status}" title="">${this.currentName}</span>
|
||||
</div>
|
||||
</div>`)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
})
|
||||
// const statusbar_params = {
|
||||
// '已完工': 'bg-primary',
|
||||
// '完成': 'bg-primary',
|
||||
// '采购订单': 'bg-primary',
|
||||
// '作废': 'bg-danger',
|
||||
// '封存(报废)': 'bg-danger',
|
||||
// }
|
||||
// patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', {
|
||||
// setup() {
|
||||
// owl.onMounted(this.ribbons);
|
||||
// return this._super(...arguments);
|
||||
// },
|
||||
// ribbons() {
|
||||
// try {
|
||||
// const dom = $('.o_form_sheet.position-relative')
|
||||
// const status = statusbar_params[this.currentName]
|
||||
// if(status && dom.length) {
|
||||
// dom.prepend(`<div class="o_widget o_widget_web_ribbon">
|
||||
// <div class="ribbon ribbon-top-right">
|
||||
// <span class="bg-opacity-75 ${status}" title="">${this.currentName}</span>
|
||||
// </div>
|
||||
// </div>`)
|
||||
// }
|
||||
// } catch (e) {
|
||||
// console.log(e)
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
|
||||
$(function () {
|
||||
document.addEventListener('click', function () {
|
||||
|
||||
@@ -526,4 +526,9 @@ div:has(.o_required_modifier) > label::before {
|
||||
// 设置表单页面label文本不换行
|
||||
.o_form_view .o_group .o_wrap_label .o_form_label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
// 修复表格内容覆盖表头bug
|
||||
.o_list_renderer .o_list_table tbody th {
|
||||
position: unset;
|
||||
}
|
||||
|
||||
|
||||
@@ -301,53 +301,27 @@ def unlink(self):
|
||||
# This is used to restrict the access right to unlink a record
|
||||
current_model_id = self.env['ir.model'].sudo().search(
|
||||
[('model', '=', self._name)]).id
|
||||
# access_right_rec = self.env['access.right'].sudo().search_read(
|
||||
# [('model_id', '=', current_model_id)], ['model_id', 'is_delete',
|
||||
# 'groups_id'])
|
||||
# if access_right_rec and not self.env.is_admin():
|
||||
# for rec in access_right_rec:
|
||||
# group_name = self.env['ir.model.data'].sudo().search([
|
||||
# ('model', '=', 'res.groups'),
|
||||
# ('res_id', '=', rec['groups_id'][0])
|
||||
# ]).name
|
||||
# module_name = self.env['ir.model.data'].sudo().search([
|
||||
# ('model', '=', 'res.groups'),
|
||||
# ('res_id', '=', rec['groups_id'][0])
|
||||
# ]).module
|
||||
# group = module_name + "." + group_name
|
||||
# if self.env.user.has_group(group):
|
||||
# if rec['is_delete']:
|
||||
# raise UserError(_('You are restricted from performing this'
|
||||
# ' operation. Please contact the'
|
||||
# ' administrator.'))
|
||||
# 检查 'access.right' 模型是否存在于环境中
|
||||
if 'access.right' in self.env:
|
||||
# current_model_id = self.env['ir.model'].sudo().search([('model', '=', self._name)]).id
|
||||
access_right_rec = self.env['access.right'].sudo().search_read(
|
||||
[('model_id', '=', current_model_id)], ['model_id', 'is_delete', 'groups_id']
|
||||
)
|
||||
|
||||
if access_right_rec and not self.env.is_admin():
|
||||
for rec in access_right_rec:
|
||||
group_data = self.env['ir.model.data'].sudo().search_read(
|
||||
[('model', '=', 'res.groups'), ('res_id', '=', rec['groups_id'][0])],
|
||||
['name', 'module']
|
||||
)
|
||||
|
||||
if group_data:
|
||||
group_name = group_data[0]['name']
|
||||
module_name = group_data[0]['module']
|
||||
group_xml_id = f"{module_name}.{group_name}"
|
||||
|
||||
if self.env.user.has_group(group_xml_id) and rec['is_delete']:
|
||||
raise UserError(
|
||||
_('You are restricted from performing this operation. Please contact the administrator.'))
|
||||
else:
|
||||
# 如果 'access.right' 模型不存在,可以在这里定义备选逻辑
|
||||
pass
|
||||
|
||||
access_right_rec = self.env['access.right'].sudo().search_read(
|
||||
[('model_id', '=', current_model_id)], ['model_id', 'is_delete',
|
||||
'groups_id'])
|
||||
if access_right_rec and not self.env.is_admin():
|
||||
for rec in access_right_rec:
|
||||
group_name = self.env['ir.model.data'].sudo().search([
|
||||
('model', '=', 'res.groups'),
|
||||
('res_id', '=', rec['groups_id'][0])
|
||||
]).name
|
||||
module_name = self.env['ir.model.data'].sudo().search([
|
||||
('model', '=', 'res.groups'),
|
||||
('res_id', '=', rec['groups_id'][0])
|
||||
]).module
|
||||
group = module_name + "." + group_name
|
||||
if self.env.user.has_group(group):
|
||||
if rec['is_delete']:
|
||||
raise UserError(_('You are restricted from performing this'
|
||||
' operation. Please contact the'
|
||||
' administrator.'))
|
||||
return True
|
||||
|
||||
|
||||
BaseModel._create = _create
|
||||
BaseModel.unlink = unlink
|
||||
BaseModel.unlink = unlink
|
||||
5
jikimo_system_order/__init__.py
Normal file
5
jikimo_system_order/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import controllers
|
||||
from . import models
|
||||
from . import wizard
|
||||
39
jikimo_system_order/__manifest__.py
Normal file
39
jikimo_system_order/__manifest__.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': "jikimo_system_order",
|
||||
|
||||
'summary': """
|
||||
系统工单""",
|
||||
|
||||
'description': """
|
||||
用于处理针对系统的工作任务;
|
||||
员工可以通过系统工单发起申请,由维护人员处理以后,填写处理结果。
|
||||
""",
|
||||
|
||||
'author': "机企猫",
|
||||
'website': "http://www.jikimo.com",
|
||||
|
||||
# Categories can be used to filter modules in modules listing
|
||||
# Check https://github.com/odoo/odoo/blob/master/odoo/addons/base/module/module_data.xml
|
||||
# for the full list
|
||||
'category': 'Uncategorized',
|
||||
'version': '0.1',
|
||||
|
||||
# any module necessary for this one to work correctly
|
||||
'depends': ['base','mail'],
|
||||
|
||||
# always loaded
|
||||
'data': [
|
||||
'security/account_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/order_wizard.xml',
|
||||
'views/notice_user_config.xml',
|
||||
'views/yizuo_system_order_view.xml',
|
||||
'views/work_order_number.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
],
|
||||
# only loaded in demonstration mode
|
||||
'demo': [
|
||||
'demo/demo.xml',
|
||||
],
|
||||
}
|
||||
3
jikimo_system_order/controllers/__init__.py
Normal file
3
jikimo_system_order/controllers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import controllers
|
||||
20
jikimo_system_order/controllers/controllers.py
Normal file
20
jikimo_system_order/controllers/controllers.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import http
|
||||
|
||||
# class TopSystemOrder(http.Controller):
|
||||
# @http.route('/jikimo_system_order/jikimo_system_order/', auth='public')
|
||||
# def index(self, **kw):
|
||||
# return "Hello, world"
|
||||
|
||||
# @http.route('/jikimo_system_order/jikimo_system_order/objects/', auth='public')
|
||||
# def list(self, **kw):
|
||||
# return http.request.render('jikimo_system_order.listing', {
|
||||
# 'root': '/jikimo_system_order/jikimo_system_order',
|
||||
# 'objects': http.request.env['jikimo_system_order.jikimo_system_order'].search([]),
|
||||
# })
|
||||
|
||||
# @http.route('/jikimo_system_order/jikimo_system_order/objects/<model("jikimo_system_order.jikimo_system_order"):obj>/', auth='public')
|
||||
# def object(self, obj, **kw):
|
||||
# return http.request.render('jikimo_system_order.object', {
|
||||
# 'object': obj
|
||||
# })
|
||||
30
jikimo_system_order/demo/demo.xml
Normal file
30
jikimo_system_order/demo/demo.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- -->
|
||||
<!-- <record id="object0" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 0</field> -->
|
||||
<!-- <field name="value">0</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
<!-- <record id="object1" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 1</field> -->
|
||||
<!-- <field name="value">10</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
<!-- <record id="object2" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 2</field> -->
|
||||
<!-- <field name="value">20</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
<!-- <record id="object3" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 3</field> -->
|
||||
<!-- <field name="value">30</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
<!-- <record id="object4" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 4</field> -->
|
||||
<!-- <field name="value">40</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
</data>
|
||||
</odoo>
|
||||
7
jikimo_system_order/models/__init__.py
Normal file
7
jikimo_system_order/models/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import constant
|
||||
from . import order_classify
|
||||
from . import system_work_order
|
||||
from . import work_order_template
|
||||
from . import res_config_setting
|
||||
7
jikimo_system_order/models/constant.py
Normal file
7
jikimo_system_order/models/constant.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 工单状态
|
||||
STATE_SELECTION = [('draft', u'草稿'), ('unconfirmed', u'待确认'), ('pending', u'待处理'),
|
||||
('processed', u'已处理待评分'), ('completed', u'已完成'), ('closed', u'已关闭')]
|
||||
|
||||
GRADE = [('1', '1非常不满意'), ('2', '2不满意'), ('3', '3一般'), ('4', '4满意'), ('5', '5非常满意')]
|
||||
25
jikimo_system_order/models/order_classify.py
Normal file
25
jikimo_system_order/models/order_classify.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class OrderClassify(models.Model):
|
||||
_name = 'order.classify'
|
||||
_order = 'sequence, name'
|
||||
|
||||
|
||||
@api.constrains('name')
|
||||
def check_base_name(self):
|
||||
"""类型名称唯一"""
|
||||
name_obj = self.env['order.classify'].search([('name', '=', self.name)])
|
||||
if len(name_obj) >= 2:
|
||||
raise ValidationError(u'该类型已存在')
|
||||
|
||||
# 名称
|
||||
name = fields.Char(string=u'名称', size=20)
|
||||
# 排序
|
||||
sequence = fields.Integer(default=10)
|
||||
# 是否有效
|
||||
state = fields.Boolean(default=True, string='是否有效')
|
||||
|
||||
32
jikimo_system_order/models/res_config_setting.py
Normal file
32
jikimo_system_order/models/res_config_setting.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ResModelWeConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
lost_agent_id = fields.Char('企微通知应用ID')
|
||||
|
||||
@api.model
|
||||
def get_values(self):
|
||||
"""
|
||||
重载获取参数的方法,参数都存在系统参数中
|
||||
:return:
|
||||
"""
|
||||
values = super(ResModelWeConfigSettings, self).get_values()
|
||||
config = self.env['ir.config_parameter'].sudo()
|
||||
lost_agent_id = config.get_param('lost_agent_id', default='')
|
||||
values.update(
|
||||
lost_agent_id=lost_agent_id,
|
||||
)
|
||||
return values
|
||||
|
||||
def set_values(self):
|
||||
super(ResModelWeConfigSettings, self).set_values()
|
||||
ir_config = self.env['ir.config_parameter'].sudo()
|
||||
ir_config.set_param("lost_agent_id", self.lost_agent_id or "")
|
||||
|
||||
183
jikimo_system_order/models/system_work_order.py
Normal file
183
jikimo_system_order/models/system_work_order.py
Normal file
@@ -0,0 +1,183 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo import exceptions
|
||||
from .constant import STATE_SELECTION, GRADE
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
|
||||
class SystemWorkOrder(models.Model):
|
||||
_name = 'system.work.order'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'date desc'
|
||||
_description = u'系统工单'
|
||||
_rec_name = 'order_number'
|
||||
|
||||
def get_is_technicist(self):
|
||||
self._cr.execute(
|
||||
"select u.id from res_users u left join res_groups_users_rel r on r.uid = u.id where r.gid in (select g.id from res_groups g where g.name = '技术员权限') and u.id ='%s'",
|
||||
(self.env.user.id,))
|
||||
hr = self._cr.dictfetchall()
|
||||
if len(hr) > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# def get_user_department_id(self):
|
||||
# """根据用户id系统员工id"""
|
||||
# employee = self.env['hr.employee'].sudo().search([('user_id', '=', self.env.uid)], limit=1)
|
||||
# if employee:
|
||||
# if len(employee) > 0:
|
||||
# if not employee.department_id:
|
||||
# raise exceptions.Warning(u'您当前使用的用户没有所属部门')
|
||||
# return employee.department_id
|
||||
# else:
|
||||
# return False
|
||||
# else:
|
||||
# raise exceptions.Warning(u'您当前使用的用户没有关联员工')
|
||||
|
||||
@api.onchange('order_template_id')
|
||||
def get_title(self):
|
||||
"""选择模板自动填充"""
|
||||
if self.order_template_id:
|
||||
self.title = self.order_template_id.title_template
|
||||
self.text = self.order_template_id.text_template
|
||||
|
||||
# 工单编号
|
||||
order_number = fields.Char(string=u'工单编号', default='/')
|
||||
# 紧急程度
|
||||
urgency_degree = fields.Selection([('0', u'0星'), ('1', u'一星'), ('2', u'二星'), ('3', u'三星'), ('4', u'四星'),
|
||||
('5', u'五星')], string=u'紧急程度', help='五星为最紧急!', default='5')
|
||||
# 工单分类(可以配置,并调整优先级)
|
||||
order_type = fields.Many2one('order.classify', string=u'工单分类', domain=[('state', '=', True)])
|
||||
# 发起人所属公司(res.company)
|
||||
initiator_company_id = fields.Many2one('res.company', string=u'发起人所属公司', default=lambda self: self.env.user.company_id)
|
||||
# 发起人部门(hr.department)
|
||||
# initiator_department_id = fields.Many2one('hr.department', string=u'发起人部门', default=get_user_department_id)
|
||||
# 发起人(hr.employee)
|
||||
initiator_id = fields.Many2one('res.users', string=u'发起人', default=lambda self: self.env.user)
|
||||
# 发起时间
|
||||
date = fields.Datetime(string=u'发起时间', default=lambda self: fields.datetime.now())
|
||||
# 确认人
|
||||
confirm_id = fields.Many2one('res.users', string=u'确认人')
|
||||
# 确认日期
|
||||
confirmation_date = fields.Datetime(string=u'确认时间')
|
||||
# 模板
|
||||
order_template_id = fields.Many2one('work.order.template', string=u'模板', domain=[('state', '=', True)])
|
||||
# 标题
|
||||
title = fields.Char(string=u'标题')
|
||||
# 正文
|
||||
text = fields.Html(string=u'正文')
|
||||
# 状态[草稿\待确认\待处理\已处理\已关闭]
|
||||
state = fields.Selection(STATE_SELECTION, default='draft', string=u'状态')
|
||||
# 关闭原因
|
||||
close_cause = fields.Text(string=u'关闭问题原因')
|
||||
# 关闭时间
|
||||
close_time = fields.Datetime(string=u'关闭问题时间')
|
||||
# 关闭人
|
||||
close_user_id = fields.Many2one('res.users', string=u'关闭人')
|
||||
# 解决人
|
||||
solve_people_id = fields.Many2one('res.users', string=u'解决人')
|
||||
# 用户实际问题
|
||||
users_problem = fields.Text(string=u'用户实际问题')
|
||||
# 最终解决方案
|
||||
solution = fields.Text(string=u'最终解决方案')
|
||||
# 判断是否为技术人员
|
||||
# is_technicist = fields.Boolean(string=u'是否为技术人员', default=get_is_technicist)
|
||||
# 打分
|
||||
grade = fields.Selection(GRADE, string=u'评分')
|
||||
# 评价按钮的显示
|
||||
is_display = fields.Boolean('控制显示评价按钮', compute='compute_is_display')
|
||||
|
||||
def compute_is_display(self):
|
||||
for item in self:
|
||||
if item.state == 'processed' and self.env.user.id == item.initiator_id.id:
|
||||
item.is_display = True
|
||||
else:
|
||||
item.is_display = False
|
||||
|
||||
@api.onchange('order_type')
|
||||
def _onchange_order_type(self):
|
||||
self.order_template_id = None
|
||||
self.title = None
|
||||
self.text = None
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# 创建编号
|
||||
if vals.get('order_number', '/') == '/':
|
||||
vals['order_number'] = self.env['ir.sequence'].get('system.work.order') or '/'
|
||||
return super(SystemWorkOrder, self).create(vals)
|
||||
|
||||
def do_draft(self, order=None):
|
||||
"""状态草稿"""
|
||||
bill = self
|
||||
if order:
|
||||
bill = order
|
||||
if bill.state == 'unconfirmed':
|
||||
state_remark = u'待确认 --> 草稿'
|
||||
# bill.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
bill.state = 'draft'
|
||||
|
||||
def do_unconfirmed(self):
|
||||
"""状态待确认"""
|
||||
if self.state == 'draft':
|
||||
state_remark = u'草稿 --> 待确认'
|
||||
# self.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.state = 'unconfirmed'
|
||||
# 获取通知人
|
||||
objs = self.env['system.order.notice'].search([])
|
||||
user_ids = objs.notice_user_ids.filtered(lambda item: item.we_employee_id not in ['', False])
|
||||
we_employee_ids = user_ids.mapped('we_employee_id')
|
||||
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
|
||||
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
|
||||
# agent_id, user_ids, content
|
||||
content = """您有一张工单<font color=\"warning\">待处理</font>:**工单标题:{2}**
|
||||
>创建人:{1}
|
||||
>提交时间:{3}
|
||||
>紧急程度:{0}星
|
||||
请查看工单消息,并及时处理!
|
||||
""".format(self.urgency_degree,
|
||||
self.initiator_id.name, self.title, (self.date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'))
|
||||
for we_employee_id in we_employee_ids:
|
||||
try:
|
||||
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
|
||||
except Exception as e:
|
||||
logging.error('工单处理发送消息异常%s' % str(e))
|
||||
|
||||
return True
|
||||
|
||||
def do_pending(self):
|
||||
"""状态待处理"""
|
||||
if self.state == 'unconfirmed':
|
||||
state_remark = u'待确认 --> 待处理'
|
||||
# self.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.state = 'pending'
|
||||
self.confirm_id = self.env.user
|
||||
self.confirmation_date = fields.datetime.now()
|
||||
return True
|
||||
|
||||
def urned_off(self):
|
||||
"""状态关闭"""
|
||||
if self.close_cause:
|
||||
self.state = 'closed'
|
||||
self.close_time = fields.datetime.now()
|
||||
else:
|
||||
raise ValidationError(u'请注明关闭原因')
|
||||
return True
|
||||
|
||||
def unlink(self):
|
||||
for item in self:
|
||||
if item.state != "draft":
|
||||
raise ValidationError(u'只能删除状态为【草稿】的工单。')
|
||||
elif item.env.uid != item.initiator_id.id:
|
||||
raise ValidationError(u'非本人不能删除')
|
||||
else:
|
||||
super(SystemWorkOrder, item).unlink()
|
||||
38
jikimo_system_order/models/work_order_template.py
Normal file
38
jikimo_system_order/models/work_order_template.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class WorkOrderTemplate(models.Model):
|
||||
_name = 'work.order.template'
|
||||
_order = 'num'
|
||||
|
||||
# 编号
|
||||
num = fields.Char(string=u'编号', default='/')
|
||||
# 名称
|
||||
name = fields.Char(string=u'模板名称', required="1")
|
||||
# 分类
|
||||
work_order_type = fields.Many2one('order.classify', string=u'系统工单分类', domain=[('state', '=', True)])
|
||||
# 模板标题
|
||||
title_template = fields.Char(string=u'模板标题')
|
||||
# 模板正文
|
||||
text_template = fields.Html(string=u'模板正文')
|
||||
# 模板说明
|
||||
template_explain = fields.Text(string=u'模板说明')
|
||||
# 是否有效
|
||||
state = fields.Boolean(default=True, string=u'是否有效')
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# 创建编号
|
||||
if vals.get('num', '/') == '/':
|
||||
vals['num'] = self.env['ir.sequence'].get('work.order.template') or '/'
|
||||
return super(WorkOrderTemplate, self).create(vals)
|
||||
|
||||
|
||||
class SystemOrderNotice(models.Model):
|
||||
_name = 'system.order.notice'
|
||||
_description = '工单处理人设置'
|
||||
|
||||
notice_user_ids = fields.Many2many('res.users', string='工单处理人')
|
||||
|
||||
24
jikimo_system_order/security/account_security.xml
Normal file
24
jikimo_system_order/security/account_security.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0"> <!-- noupdate表示,当模块升级时是否更新本条数据-->
|
||||
<!--运维权限组-->
|
||||
<record id="group_operations_permissions_rwc" model="res.groups">
|
||||
<field name="name">运维权限</field>
|
||||
</record>
|
||||
|
||||
<record id="system_order_user_rule" model="ir.rule">
|
||||
<field name="name">用户访问工单信息</field>
|
||||
<field name="model_id" ref="model_system_work_order"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
<field name="domain_force">[('initiator_id', '=', user.id)]</field>
|
||||
</record>
|
||||
|
||||
<record id="system_order_group_operations_rule" model="ir.rule">
|
||||
<field name="name">运维访问工单信息</field>
|
||||
<field name="model_id" ref="model_system_work_order"/>
|
||||
<field name="groups" eval="[(4, ref('jikimo_system_order.group_operations_permissions_rwc'))]"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
16
jikimo_system_order/security/ir.model.access.csv
Normal file
16
jikimo_system_order/security/ir.model.access.csv
Normal file
@@ -0,0 +1,16 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
|
||||
inside_system_order_classify_r,jikimo_system_order.order_classify,model_order_classify,,1,1,1,1
|
||||
inside_system_work_order_rc,jikimo_system_order.system_work_order,model_system_work_order,,1,1,1,1
|
||||
inside_work_order_template_r,jikimo_system_order.work_order_template,model_work_order_template,,1,1,1,1
|
||||
|
||||
inside_system_order_classify_rwc,jikimo_system_order.order_classify,model_order_classify,group_operations_permissions_rwc,1,1,1,0
|
||||
inside_system_work_order_rwc,jikimo_system_order.system_work_order,model_system_work_order,group_operations_permissions_rwc,1,1,1,0
|
||||
inside_work_order_template_rwc,jikimo_system_order.work_order_template,model_work_order_template,group_operations_permissions_rwc,1,1,1,0
|
||||
|
||||
order_close_wizard_group_user,jikimo_system_order.order_close_wizard,model_order_close_wizard,base.group_user,1,1,1,1
|
||||
order_other_wizard_group_user,jikimo_system_order.order_other_wizard,model_order_other_wizard,base.group_user,1,1,1,1
|
||||
order_technician_wizard_group_user,jikimo_system_order.order_technician_wizard,model_order_technician_wizard,base.group_user,1,1,1,1
|
||||
system_work_order_wizard_group_user,jikimo_system_order.system_work_order_wizard,model_system_work_order_wizard,base.group_user,1,1,1,1
|
||||
|
||||
system_order_notice_group_user,jikimo_system_order.system_order_notice,model_system_order_notice,base.group_user,1,1,1,1
|
||||
|
BIN
jikimo_system_order/static/description/icon.png
Normal file
BIN
jikimo_system_order/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
58
jikimo_system_order/views/notice_user_config.xml
Normal file
58
jikimo_system_order/views/notice_user_config.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
# ---------- 工单通知处理人设置 ------------
|
||||
|
||||
<record model="ir.ui.view" id="tree_system_order_notice_view">
|
||||
<field name="name">tree.system.order.notice</field>
|
||||
<field name="model">system.order.notice</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="工单处理人设置" editable="top">
|
||||
<field name="notice_user_ids" widget="many2many_tags" required="1" options="{'no_create': True, 'no_edit': True}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.ui.view" id="search_system_order_notice_view">
|
||||
<field name="name">search.system.order.notice</field>
|
||||
<field name="model">system.order.notice</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="工单处理人设置">
|
||||
<field name="notice_user_ids" string="模糊搜索"
|
||||
filter_domain="[('notice_user_ids', 'ilike', self)]"/>
|
||||
<separator></separator>
|
||||
|
||||
<field name="notice_user_ids" string="处理人"/>
|
||||
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_system_order_notice_view">
|
||||
<field name="name">工单处理人</field>
|
||||
<field name="res_model">system.order.notice</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="context">{}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
[工单处理人] 还没有哦!点左上角的[创建]按钮,沙发归你了!
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
28
jikimo_system_order/views/res_config_settings_views.xml
Normal file
28
jikimo_system_order/views/res_config_settings_views.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="res_config_settings_we_view_form_inherit" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.we.view.form.inherit.bpm</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[hasclass('app_settings_block')]/div[6]" position="after">
|
||||
<div>
|
||||
<h2>企微通知应用ID</h2>
|
||||
<div class="row mt16 o_settings_container" id="jd_api">
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane"/>
|
||||
<div class="o_setting_right_pane">
|
||||
<div class="text-muted">
|
||||
<label for="lost_agent_id"/>
|
||||
<field name="lost_agent_id"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
23
jikimo_system_order/views/work_order_number.xml
Normal file
23
jikimo_system_order/views/work_order_number.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<odoo>
|
||||
<data noupdate="True">
|
||||
<!-- 工单流水号 -->
|
||||
<record id="seq_work_order" model="ir.sequence">
|
||||
<field name="name">seq_work_order</field>
|
||||
<field name="company_id"/>
|
||||
<field name="code">system.work.order</field>
|
||||
<field name="prefix">SO%(year)s%(month)s%(day)s</field>
|
||||
<field name="padding">1</field>
|
||||
</record>
|
||||
|
||||
<!-- 模板编号 -->
|
||||
<record id="seq_order_template" model="ir.sequence">
|
||||
<field name="name">seq_order_template</field>
|
||||
<field name="company_id"/>
|
||||
<field name="code">work.order.template</field>
|
||||
<field name="prefix">TL</field>
|
||||
<field name="padding">1</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
243
jikimo_system_order/views/yizuo_system_order_view.xml
Normal file
243
jikimo_system_order/views/yizuo_system_order_view.xml
Normal file
@@ -0,0 +1,243 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<odoo>
|
||||
<data>
|
||||
<!--工单信息-->
|
||||
<record model="ir.ui.view" id="work_order_tree">
|
||||
<field name="name">工单信息</field>
|
||||
<field name="model">system.work.order</field><!--对应表单名称-->
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="state" widget="badge" decoration-primary="state == 'draft'"
|
||||
decoration-success="state in ('processed', 'completed')"
|
||||
decoration-danger="state == 'pending'" decoration-warning="state in ('unconfirmed')"/>
|
||||
<field name="order_number"/>
|
||||
<field name="title"/>
|
||||
<field name="initiator_id"/>
|
||||
<field name="date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--新建系统工单-->
|
||||
<record model="ir.ui.view" id="ork_order_form">
|
||||
<field name="name">新建系统工单</field>
|
||||
<field name="model">system.work.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<field name="is_display" invisible="1"/>
|
||||
<button string='提交' class="oe_highlight" states="draft"
|
||||
type="object" name="do_unconfirmed"
|
||||
attrs="{'invisible': [('state', '!=', 'draft')]}"/>
|
||||
<button string='追回编辑' states="unconfirmed"
|
||||
type="action" name="%(system_work_order_wizard_view_act_window)d"
|
||||
context="{'explain':'确认要执行此操作吗?','object_name':'system.work.order','function_name':'do_draft','object_id':id}"/>
|
||||
|
||||
<button name="do_pending" states="unconfirmed"
|
||||
string="确认可处理" type="object" class="oe_highlight"
|
||||
groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
|
||||
<button string='处理工单' class="oe_highlight" states="pending"
|
||||
type="action" name="%(launch_order_technician_wizard)d"
|
||||
groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
<button string='评价' class="oe_highlight" attrs="{'invisible': [('is_display', '=', False)]}"
|
||||
type="action" name="%(launch_order_other_wizard)d" context="{'active_id':id}"/>
|
||||
<button name="%(launch_order_close_wizard)d" string="关闭该工单"
|
||||
attrs="{'invisible': ['|',('state', '=', 'draft'),'|',('state','=','completed'),('state','=','closed')]}"
|
||||
type="action" context="{'active_id':id}"/>
|
||||
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<!-- <label for="order_number" class="oe_edit_only"/>-->
|
||||
<group>
|
||||
<field name="order_number" required="True" readonly="1"/>
|
||||
<field name="order_type" required="True" attrs="{'readonly': [('state', '!=', 'draft')]}" options="{'no_create': True}"/>
|
||||
<field name="date" required="True" readonly="True"/>
|
||||
<field name="order_template_id" attrs="{'readonly': [('state', '!=', 'draft')]}"
|
||||
domain="[('work_order_type','=',order_type),('state','=',True)]" options="{'no_create': True}"/>
|
||||
<field name="confirmation_date" readonly="True"/>
|
||||
<field name="urgency_degree" required="True" attrs="{'readonly': [('state','!=','draft')]}" widget="priority"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="initiator_company_id" required="True" readonly="True"/>
|
||||
<!-- <field name="initiator_department_id" required="True" readonly="True"/>-->
|
||||
<field name="initiator_id" required="True" readonly="True"/>
|
||||
<field name="confirm_id" readonly="True"/>
|
||||
<field name="solve_people_id" readonly="True"/>
|
||||
<field name="close_user_id" readonly="True"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="title" attrs="{'readonly': [('state', '!=', 'draft')]}" required="True"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="工单内容">
|
||||
<field name="text" attrs="{'readonly': [('state','!=','draft')]}" required="True"/>
|
||||
</page>
|
||||
<page string="解决方案">
|
||||
<group>
|
||||
<field name="users_problem" readonly="True"/>
|
||||
<field name="solution" readonly="True"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="其他">
|
||||
<group>
|
||||
<field name="close_cause" readonly="True"/>
|
||||
<field name="close_time" readonly="True"/>
|
||||
<field name="grade" readonly="True"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<!-- <div class="oe_chatter">-->
|
||||
<!-- <field name="message_follower_ids" widget="mail_followers"/>-->
|
||||
<!-- <field name="message_ids" widget="mail_thread"/>-->
|
||||
<!-- </div>-->
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 搜索工单 -->
|
||||
<record model="ir.ui.view" id="restaurant_search">
|
||||
<field name="name">搜索工单</field>
|
||||
<field name="model">system.work.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field string='发起人' name="initiator_id" widget="char" required="True"/>
|
||||
<field string='标题' name="title" widget="char"/>
|
||||
<field string='正文' name="text" widget="html"/>
|
||||
<field string='实际问题' name="users_problem" widget="text"/>
|
||||
<field string='解决方案' name="solution" widget="text"/>
|
||||
<filter name="today" string="今日工单" domain="[('date','=',time.strftime('%%Y-%%m-%%d'))]"/>
|
||||
<filter name="yesterday" string="昨日工单"
|
||||
domain="[('date', '=', (context_today() - relativedelta(days=1)).strftime('%Y-%m-%d'))]"/>
|
||||
<filter name="month" string="本月工单"
|
||||
domain="[('date','>=', time.strftime('%Y-%m-01')),('date','<', (context_today() + relativedelta(months=1)).strftime('%Y-%m-01'))]"/>
|
||||
<filter name="last_month" string="上月工单"
|
||||
domain="[('date','<', time.strftime('%Y-%m-01')),('date','>=', (context_today() - relativedelta(months=1)).strftime('%Y-%m-01'))]"/>
|
||||
<filter name="unconfirmed" string="待确认" domain="[('state','=','unconfirmed')]"/>
|
||||
<filter name="pending" string="待处理" domain="[('state','=','pending')]"/>
|
||||
<filter name="processed" string="已处理"
|
||||
domain="['|', ('state','=','processed'), ('state','=','closed')]"/>
|
||||
<group>
|
||||
<filter string='发起人' name="initiator_id" context='{"group_by":"initiator_id"}'/>
|
||||
<filter string='工单分类' name="order_type" context='{"group_by":"order_type"}'/>
|
||||
<filter string='模板' name="order_template_id" context='{"group_by":"order_template_id"}'/>
|
||||
<filter string='状态' name="state" context='{"group_by":"state"}'/>
|
||||
<filter string='紧急情况' name="state" context='{"group_by":"urgency_degree"}'/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="graph_tree">
|
||||
<field name="name">工单图表</field>
|
||||
<field name="model">system.work.order</field><!--对应表单名称-->
|
||||
<field name="arch" type="xml">
|
||||
<pivot>
|
||||
<field name="date" type="row" interval="day"/>
|
||||
<field name="order_type" type="col"/>
|
||||
<field name="state" type="row"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 工单 -->
|
||||
<record model="ir.actions.act_window" id="system_order">
|
||||
<field name="name">工单</field>
|
||||
<field name="res_model">system.work.order</field>
|
||||
<field name="view_mode">tree,form,search,graph,pivot</field>
|
||||
</record>
|
||||
|
||||
<!--工单模板信息-->
|
||||
<record model="ir.ui.view" id="order_template_tree">
|
||||
<field name="name">工单模板信息</field>
|
||||
<field name="model">work.order.template</field><!--对应表单名称-->
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="num"/>
|
||||
<field name="name"/>
|
||||
<field name="work_order_type"/>
|
||||
<field name="title_template"/>
|
||||
<field name="template_explain"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--新建系统工单模板-->
|
||||
<record model="ir.ui.view" id="order_template_form">
|
||||
<field name="name">新建系统工单模板</field>
|
||||
<field name="model">work.order.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="num" required="True" readonly="True"/>
|
||||
<field name="name" required="True"/>
|
||||
<field name="work_order_type" required="True"/>
|
||||
<field name="template_explain" required="True" style="height: 50px;"/>
|
||||
<field name="title_template" required="True"/>
|
||||
<field name="state"/>
|
||||
<field name="text_template" required="True"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 工单模板 -->
|
||||
<record model="ir.actions.act_window" id="work_template">
|
||||
<field name="name">工单模板</field>
|
||||
<field name="res_model">work.order.template</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<!--工单分类信息-->
|
||||
<record model="ir.ui.view" id="order_type_tree">
|
||||
<field name="name">工单分类信息</field>
|
||||
<field name="model">order.classify</field><!--对应表单名称-->
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--新建系统分类信息-->
|
||||
<record model="ir.ui.view" id="order_type_form">
|
||||
<field name="name">新建系统分类信息</field>
|
||||
<field name="model">order.classify</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" required="True"/>
|
||||
<field name="sequence" invisible="True"/>
|
||||
<field name="state"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 工单分类 -->
|
||||
<record model="ir.actions.act_window" id="classify">
|
||||
<field name="name">工单分类</field>
|
||||
<field name="res_model">order.classify</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem name="系统工单" id="work_order_1_list" web_icon="jikimo_system_order,static/description/icon.png"/>
|
||||
<menuitem name="工单" id="work_order" parent="work_order_1_list" action="system_order"/>
|
||||
<menuitem name="工单模板" id="work_order_template" parent="work_order_1_list" action="work_template" groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
<menuitem name="工单分类" id="work_order_type" parent="work_order_1_list" action="classify" groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
<menuitem name="工单设置" id="system_order_notice_user_config" parent="work_order_1_list" action="action_system_order_notice_view" groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
</data>
|
||||
</odoo>
|
||||
6
jikimo_system_order/wizard/__init__.py
Normal file
6
jikimo_system_order/wizard/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import order_other_wizard
|
||||
from . import order_technician_wizard
|
||||
from . import order_close_wizard
|
||||
from . import system_work_order_wizard
|
||||
79
jikimo_system_order/wizard/order_close_wizard.py
Normal file
79
jikimo_system_order/wizard/order_close_wizard.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION
|
||||
from odoo.exceptions import ValidationError
|
||||
import datetime, logging
|
||||
|
||||
|
||||
class OrderCloseWizard(models.TransientModel):
|
||||
_name = 'order.close.wizard'
|
||||
|
||||
|
||||
def get_context(self):
|
||||
if self._context.get('active_id'):
|
||||
obj = self.env['system.work.order'].browse(self._context.get('active_id'))
|
||||
if obj.initiator_id.id != self.env.user.id:
|
||||
raise ValidationError(u'非本人无法操作')
|
||||
return obj
|
||||
|
||||
order_id = fields.Many2one('system.work.order', string=u'工单ID',
|
||||
default=lambda self: self.get_context().id)
|
||||
# 关闭原因
|
||||
close_cause = fields.Text(string=u'关闭问题原因', default=lambda self: self.get_context().close_cause)
|
||||
# 关闭时间
|
||||
close_time = fields.Datetime(string=u'关闭问题时间', default=fields.datetime.now())
|
||||
# 状态
|
||||
state = fields.Selection(STATE_SELECTION, default='closed', string=u'状态')
|
||||
# 关闭人
|
||||
close_user_id = fields.Many2one('res.users', string=u'关闭人', default=lambda self: self.env.user)
|
||||
|
||||
|
||||
def sure(self):
|
||||
self.order_id.close_cause = self.close_cause
|
||||
self.order_id.close_time = self.close_time
|
||||
if self.order_id.state == 'unconfirmed':
|
||||
state_remark = u'待确认 --> 已关闭'
|
||||
if self.order_id.state == 'pending':
|
||||
state_remark = u'待处理 --> 已关闭'
|
||||
if self.order_id.state == 'processed':
|
||||
state_remark = u'已处理待评分 --> 已关闭'
|
||||
# self.order_id.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.order_id.state = self.state
|
||||
self.order_id.close_user_id = self.close_user_id
|
||||
we_employee_ids = []
|
||||
if self.order_id.initiator_id.we_employee_id:
|
||||
we_employee_ids.append(self.order_id.initiator_id.we_employee_id)
|
||||
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
|
||||
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
|
||||
# agent_id, user_ids, content
|
||||
content = """您提交的工单-**工单标题:{0}**-<font color=\"#FF0000\">**已关闭**</font>
|
||||
>提交时间:{1}
|
||||
>处理时间:{2}
|
||||
>处理人:{3}
|
||||
如有问题,请联系系统管理员!
|
||||
""".format(self.order_id.title,
|
||||
(self.order_id.date + datetime.timedelta(hours=8)).strftime(
|
||||
'%Y-%m-%d %H:%M'), (datetime.datetime.now() + datetime.timedelta(
|
||||
hours=8)).strftime('%Y-%m-%d %H:%M'), self.env.user.name or '')
|
||||
# wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_ids, content=content)
|
||||
for we_employee_id in we_employee_ids:
|
||||
try:
|
||||
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
|
||||
except Exception as e:
|
||||
logging.error('工单关闭发送消息异常%s' % str(e))
|
||||
return {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
42
jikimo_system_order/wizard/order_other_wizard.py
Normal file
42
jikimo_system_order/wizard/order_other_wizard.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION, GRADE
|
||||
import datetime
|
||||
|
||||
|
||||
class OrderOtherWizard(models.TransientModel):
|
||||
_name = 'order.other.wizard'
|
||||
|
||||
|
||||
def get_context(self):
|
||||
if self._context.get('active_id'):
|
||||
obj = self.env['system.work.order'].browse(self._context.get('active_id'))
|
||||
if obj.initiator_id.id != self.env.user.id:
|
||||
raise ValidationError(u'非本人无法操作')
|
||||
return obj
|
||||
|
||||
order_id = fields.Many2one('system.work.order', string=u'工单ID',
|
||||
default=lambda self: self.get_context().id)
|
||||
# 关闭时间
|
||||
close_time = fields.Datetime(string=u'关闭时间', default=fields.datetime.now())
|
||||
# 状态
|
||||
state = fields.Selection(STATE_SELECTION, default='completed', string=u'状态')
|
||||
# 打分
|
||||
grade = fields.Selection(GRADE, string=u'评分')
|
||||
# 关闭人
|
||||
close_user_id = fields.Many2one('res.users', string=u'关闭人', default=lambda self: self.env.user)
|
||||
|
||||
|
||||
def sure(self):
|
||||
self.order_id.close_time = self.close_time
|
||||
self.order_id.grade = self.grade
|
||||
if self.order_id.state == 'processed':
|
||||
state_remark = u'已处理待评分 --> 已完成'
|
||||
# self.order_id.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.order_id.state = self.state
|
||||
self.order_id.close_user_id = self.close_user_id
|
||||
return {}
|
||||
59
jikimo_system_order/wizard/order_technician_wizard.py
Normal file
59
jikimo_system_order/wizard/order_technician_wizard.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
|
||||
class OrderTechnicianWizard(models.TransientModel):
|
||||
_name = 'order.technician.wizard'
|
||||
|
||||
order_id = fields.Many2one('system.work.order', string=u'工单ID',
|
||||
default=lambda self: self.env.context.get('active_id'))
|
||||
# 解决人
|
||||
solve_people_id = fields.Many2one('res.users', string=u'解决人', default=lambda self: self.env.user)
|
||||
# 用户实际问题
|
||||
users_problem = fields.Text(string=u'用户实际问题')
|
||||
# 最终解决方案
|
||||
solution = fields.Text(string=u'最终解决方案')
|
||||
# 状态
|
||||
state = fields.Selection(STATE_SELECTION, default='processed', string=u'状态')
|
||||
|
||||
def sure(self):
|
||||
self.order_id.solve_people_id = self.solve_people_id
|
||||
self.order_id.users_problem = self.users_problem
|
||||
self.order_id.solution = self.solution
|
||||
if self.order_id.state == 'pending':
|
||||
state_remark = u'待处理 --> 已处理待评分'
|
||||
# self.order_id.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.order_id.state = self.state
|
||||
# 获取通知人
|
||||
# objs = self.env['system.order.notice'].search([])
|
||||
# user_ids = objs.notice_user_ids.filtered(lambda item: item.we_employee_id not in ['', False])
|
||||
# we_employee_ids = user_ids.mapped('we_employee_id')
|
||||
we_employee_ids = []
|
||||
if self.order_id.initiator_id.we_employee_id:
|
||||
we_employee_ids.append(self.order_id.initiator_id.we_employee_id)
|
||||
print(we_employee_ids)
|
||||
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
|
||||
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
|
||||
# agent_id, user_ids, content
|
||||
content = """您提交的工单-**工单标题:{0}**-<font color=\"info\">**已处理**</font>
|
||||
>提交时间:{1}
|
||||
>处理反馈:{4}
|
||||
>处理时间:{2}
|
||||
>处理人:{3}
|
||||
如有问题,请联系系统管理员!
|
||||
""".format(self.order_id.title,
|
||||
(self.order_id.date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'), (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'), self.env.user.name or '', self.solution or '')
|
||||
# wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_ids, content=content)
|
||||
for we_employee_id in we_employee_ids:
|
||||
try:
|
||||
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
|
||||
except Exception as e:
|
||||
logging.error('工单处理发送消息异常%s' % str(e))
|
||||
|
||||
return {}
|
||||
122
jikimo_system_order/wizard/order_wizard.xml
Normal file
122
jikimo_system_order/wizard/order_wizard.xml
Normal file
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- 技术员向导form-->
|
||||
<record model="ir.ui.view" id="wizard_technician_form_view">
|
||||
<field name="name">技术员向导</field>
|
||||
<field name="model">order.technician.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="技术员编辑">
|
||||
<group>
|
||||
<field name="order_id" required="1" readonly="1"/>
|
||||
<field name="solve_people_id" required="1"/>
|
||||
<field name="users_problem" required="1" style="height: 50px;"/>
|
||||
<field name="solution" required="1" style="height: 50px;"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="取消" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="launch_order_technician_wizard">
|
||||
<field name="name">技术员编辑</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">order.technician.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="wizard_technician_form_view"/>
|
||||
<field name="context">{'display_default_code':False}</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<!-- 其它向导form-->
|
||||
<record model="ir.ui.view" id="wizard_other_form_view">
|
||||
<field name="name">其它向导</field>
|
||||
<field name="model">order.other.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="其它编辑">
|
||||
<group>
|
||||
<field name="order_id" required="1" readonly="1"/>
|
||||
<field name="close_time" required="1" readonly="1"/>
|
||||
<field name="grade" required="1"/>
|
||||
<field name="close_user_id" required="1" readonly="1"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="取消" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="launch_order_other_wizard">
|
||||
<field name="name">其它编辑</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">order.other.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="wizard_other_form_view"/>
|
||||
<field name="context">{'display_default_code':False}</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<!--关闭向导form-->
|
||||
<record model="ir.ui.view" id="wizard_close_form_view">
|
||||
<field name="name">关闭向导</field>
|
||||
<field name="model">order.close.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="关闭工单">
|
||||
<group>
|
||||
<field name="order_id" required="1" readonly="1"/>
|
||||
<field name="close_cause" required="1" style="height: 50px;"/>
|
||||
<field name="close_time" required="1" readonly="1"/>
|
||||
<field name="close_user_id" required="1" readonly="1"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="取消" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="launch_order_close_wizard">
|
||||
<field name="name">关闭工单</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">order.close.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="wizard_close_form_view"/>
|
||||
<field name="context">{'display_default_code':False}</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<record id="system_work_order_wizard_view" model="ir.ui.view">
|
||||
<field name="name">system_work_order_wizard_view</field>
|
||||
<field name="model">system.work.order.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="二次确认">
|
||||
<field name="explain" readonly="1"/>
|
||||
<footer>
|
||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="取消" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="system_work_order_wizard_view_act_window">
|
||||
<field name="name">二次确认</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">system.work.order.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
42
jikimo_system_order/wizard/system_work_order_wizard.py
Normal file
42
jikimo_system_order/wizard/system_work_order_wizard.py
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2017/12/12 9:46
|
||||
# @Author : GuoXiang
|
||||
# @Site :
|
||||
# @File : system_work_order_wizard.py
|
||||
# @Software: PyCharm
|
||||
# @Desc :
|
||||
# @license : Copyright©2018 www.dasmaster.com All Rights Reserved.
|
||||
# @Contact : xg1230205321@163.com
|
||||
from odoo import models, api, fields
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class SystemWorkOrderWizard(models.TransientModel):
|
||||
_name = "system.work.order.wizard"
|
||||
_description = u"追回确认"
|
||||
|
||||
|
||||
def _get_explain(self):
|
||||
if self._context.get('object_id'):
|
||||
obj = self.env['system.work.order'].browse(self._context.get('object_id'))
|
||||
if obj.initiator_id.id != self.env.user.id:
|
||||
raise ValidationError(u'非本人无法操作')
|
||||
if self._context.get('explain'):
|
||||
return self._context["explain"]
|
||||
|
||||
explain = fields.Char(default=_get_explain)
|
||||
|
||||
|
||||
def sure(self):
|
||||
"""
|
||||
确认
|
||||
:return:
|
||||
"""
|
||||
if self._context.get('object_id') and self._context.get('object_name') and self._context.get(
|
||||
'explain') and self._context.get('function_name'):
|
||||
work_sheet_obj = self.env[self._context["object_name"]].search([('id', '=', int(self._context["object_id"]))])
|
||||
class_name = self._context.get('object_name') # 获得对象类名
|
||||
method_name = self._context.get('function_name') # 获得对象的方法
|
||||
obj_function = getattr(self.env[class_name], method_name)
|
||||
obj_function(work_sheet_obj)
|
||||
@@ -61,12 +61,10 @@ class MrsMaterialModel(models.Model):
|
||||
supplier_ids = fields.One2many('sf.supplier.sort', 'materials_model_id', string='供应商')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
|
||||
@api.onchange('gain_way')
|
||||
def _check_gain_way(self):
|
||||
if not self.gain_way:
|
||||
raise UserError("请选择获取方式")
|
||||
if self.gain_way in ['外协', '采购']:
|
||||
if not self.supplier_ids:
|
||||
@api.constrains("gain_way")
|
||||
def _check_supplier_ids(self):
|
||||
for item in self:
|
||||
if item.gain_way in ('外协', '采购') and not item.supplier_ids:
|
||||
raise UserError("请添加供应商")
|
||||
|
||||
|
||||
@@ -94,8 +92,10 @@ class MrsProductionProcess(models.Model):
|
||||
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数')
|
||||
category_id = fields.Many2one('sf.production.process.category')
|
||||
category_id = fields.Many2one('sf.production.process.category', string='表面工艺类别')
|
||||
# workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True)
|
||||
processing_day = fields.Float('加工天数/d')
|
||||
travel_day = fields.Float('路途天数/d')
|
||||
|
||||
|
||||
# class MrsProcessingTechnology(models.Model):
|
||||
@@ -143,7 +143,10 @@ class MrsProductionProcessParameter(models.Model):
|
||||
is_check = fields.Boolean(default=False)
|
||||
# price = fields.Float('单价')
|
||||
process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||
process_description = fields.Char(string='工艺描述')
|
||||
materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料')
|
||||
processing_day = fields.Float('加工天数/d')
|
||||
travel_day = fields.Float('路途天数/d')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
|
||||
def name_get(self):
|
||||
|
||||
@@ -11,8 +11,8 @@ access_sf_machine_control_system,sf_machine_control_system,model_sf_machine_cont
|
||||
access_sf_machine_control_system_admin,sf_machine_control_system_admin,model_sf_machine_control_system,base.group_system,1,1,1,0
|
||||
access_sf_production_process_group_sale_director,sf_production_process_group_sale_director,model_sf_production_process,sf_base.group_sale_director,1,0,0,0
|
||||
access_sf_production_process_group_sale_salemanager,sf_production_process_group_sale_salemanager,model_sf_production_process,sf_base.group_sale_salemanager,1,0,0,0
|
||||
access_res_partner_category_group_sale_salemanager,res_partner_category_group_sale_salemanager,base.model_res_partner_category,sf_base.group_sale_salemanager,1,0,1,0
|
||||
access_res_partner_category_group_sale_director,res_partner_category_group_sale_director,base.model_res_partner_category,sf_base.group_sale_director,1,0,1,0
|
||||
access_res_partner_category_group_sale_salemanager,res_partner_category_group_sale_salemanager,base.model_res_partner_category,sf_base.group_sale_salemanager,1,1,1,0
|
||||
access_res_partner_category_group_sale_director,res_partner_category_group_sale_director,base.model_res_partner_category,sf_base.group_sale_director,1,1,1,0
|
||||
access_sf_production_process,sf_production_process,model_sf_production_process,base.group_user,1,1,1,0
|
||||
access_sf_production_process_admin,sf_production_process_admin,model_sf_production_process,base.group_system,1,1,1,0
|
||||
access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0
|
||||
|
||||
|
@@ -27,9 +27,13 @@
|
||||
<group>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="process_id" readonly="1"/>
|
||||
<field name="process_description" readonly="1"/>
|
||||
<field name="gain_way"/>
|
||||
</group>
|
||||
|
||||
<group>
|
||||
<field name="processing_day" readonly="1"/>
|
||||
<field name="travel_day" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="适用材料">
|
||||
@@ -179,41 +183,46 @@
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="code"/>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="category_id" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="processing_day" readonly="1"/>
|
||||
<field name="travel_day" readonly="1"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="可选参数">
|
||||
<field name="parameter_ids">
|
||||
<tree force_save="1">
|
||||
<field name="code" readonly="1" force_save="1"/>
|
||||
<field name="name"/>
|
||||
<field name="gain_way"/>
|
||||
<field name='process_id' default="default"/>
|
||||
</tree>
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="code"/>
|
||||
<field name="name" string="参数名"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name='process_id'/>
|
||||
<field name="gain_way"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="适用材料">
|
||||
<field name="materials_model_ids"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
</notebook>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="可选参数">
|
||||
<field name="parameter_ids">
|
||||
<tree force_save="1">
|
||||
<field name="code" readonly="1" force_save="1"/>
|
||||
<field name="name"/>
|
||||
<field name="gain_way"/>
|
||||
<field name='process_id' default="default"/>
|
||||
</tree>
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="code"/>
|
||||
<field name="name" string="参数名"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name='process_id'/>
|
||||
<field name="gain_way"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="适用材料">
|
||||
<field name="materials_model_ids"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
</notebook>
|
||||
<group>
|
||||
<group>
|
||||
<field name="remark"/>
|
||||
@@ -251,7 +260,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="materials_no" readonly="1" force_save="1"/>
|
||||
<field name="gain_way" required="1"/>
|
||||
<field name="gain_way" required="0"/>
|
||||
<field name="tensile_strength" required="1"/>
|
||||
<field name="hardness" required="1"/>
|
||||
<field name="density" readonly="1"/>
|
||||
@@ -270,9 +279,9 @@
|
||||
<notebook>
|
||||
<page string="供应商">
|
||||
<field name='supplier_ids' class="supplier_ids_set_css">
|
||||
<tree editable='bottom'>
|
||||
<tree editable='bottom' delete="1">
|
||||
<field name="sequence" widget="handle" string="序号"/>
|
||||
<field name="partner_id" string="名称"/>
|
||||
<field name="partner_id" string="名称" options="{'no_create': True}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
@@ -21,6 +21,7 @@ class Http(models.AbstractModel):
|
||||
def _auth_method_sf_token(cls):
|
||||
# 从headers.environ中获取对方传过来的token,timestamp,加密的校验字符串
|
||||
datas = request.httprequest.headers.environ
|
||||
_logger.info('datas:%s' % datas)
|
||||
if 'HTTP_TOKEN' in datas:
|
||||
_logger.info('token:%s' % datas['HTTP_TOKEN'])
|
||||
# 查询密钥
|
||||
|
||||
@@ -5,7 +5,7 @@ import requests
|
||||
import cpca
|
||||
# from odoo.exceptions import UserError
|
||||
# from odoo.exceptions import ValidationError
|
||||
from odoo import api, fields, models
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -149,7 +149,7 @@ class JdEclp(models.Model):
|
||||
},
|
||||
}
|
||||
_logger.info('准备调接口1')
|
||||
url1 = config['bfm_url'] + '/api/create/jd/order'
|
||||
url1 = config['bfm_url_new'] + '/api/create/jd/order'
|
||||
requests.post(url1, json=json1, data=None)
|
||||
_logger.info('调用成功1')
|
||||
_logger.info('准备调接口2')
|
||||
@@ -158,18 +158,31 @@ class JdEclp(models.Model):
|
||||
'orderNo': self.origin,
|
||||
},
|
||||
}
|
||||
url2 = config['bfm_url'] + '/api/get/jd/no'
|
||||
url2 = config['bfm_url_new'] + '/api/get/jd/no'
|
||||
response = requests.post(url2, json=json2, data=None)
|
||||
# _logger.info('调用成功2', response.json()['result']['wbNo'])
|
||||
self.carrier_tracking_ref = response.json()['result']['wbNo']
|
||||
tem_ret = response.json().get('result')
|
||||
if not tem_ret:
|
||||
raise ValidationError('京东物流返回异常,请联系管理员')
|
||||
self.carrier_tracking_ref = response.json()['result'].get('wbNo')
|
||||
if not self.carrier_tracking_ref:
|
||||
raise ValidationError('物流下单未成功,请联系管理员')
|
||||
self.is_bill = True
|
||||
self.logistics_status = '1'
|
||||
|
||||
# # 京东物流下单后,销售订单状态改为待收货
|
||||
# self.env['sale.order'].search([('name', '=', self.origin)]).write({'scheduled_status': 'to receive'})
|
||||
notification = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('成功'),
|
||||
'type': 'success',
|
||||
'message': '物流下单成功',
|
||||
'sticky': False,
|
||||
'next': {'type': 'ir.actions.client', 'tag': 'reload'}
|
||||
}
|
||||
}
|
||||
|
||||
# else:
|
||||
# raise UserError("选择京东物流才能下单呦")
|
||||
return notification
|
||||
|
||||
def get_bill(self):
|
||||
"""
|
||||
@@ -183,7 +196,7 @@ class JdEclp(models.Model):
|
||||
'no': self.origin,
|
||||
},
|
||||
}
|
||||
url1 = config['bfm_url'] + '/api/create/jd/bill'
|
||||
url1 = config['bfm_url_new'] + '/api/create/jd/bill'
|
||||
response = requests.post(url1, json=json1, data=None)
|
||||
# _logger.info('调用成功2', response.json())
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class StatusChange(models.Model):
|
||||
'process_start_time': process_start_time,
|
||||
},
|
||||
}
|
||||
url1 = config['bfm_url'] + '/api/get/state/get_order'
|
||||
url1 = config['bfm_url_new'] + '/api/get/state/get_order'
|
||||
requests.post(url1, json=json1, data=None)
|
||||
logging.info('接口已经执行=============')
|
||||
|
||||
@@ -54,7 +54,7 @@ class StatusChange(models.Model):
|
||||
'state': '待派单',
|
||||
},
|
||||
}
|
||||
url1 = config['bfm_url'] + '/api/get/state/cancel_order'
|
||||
url1 = config['bfm_url_new'] + '/api/get/state/cancel_order'
|
||||
requests.post(url1, json=json1, data=None)
|
||||
|
||||
return res
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<field name="is_bill" invisible="True"/>
|
||||
<field name="logistics_status" invisible="True"/>
|
||||
<field name="logistics_way" invisible="True"/>
|
||||
<button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"
|
||||
<button string="物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"
|
||||
attrs="{'invisible': ['|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('is_bill', '=', True), ('logistics_way', '=', '自提')]}"/>
|
||||
<button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"
|
||||
attrs="{'invisible': ['|', '|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('logistics_status', '=', '2'), ('is_bill', '=', False), ('logistics_way', '=', '自提')]}"/>
|
||||
@@ -45,42 +45,50 @@
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<field name="location_id" position="after">
|
||||
<field name="logistics_status" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="logistics_way" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<xpath expr="//group//field[@name='carrier_id']" position="after">
|
||||
<!-- <field name="senderNickName" domain="[('self.name', 'like', '%OUT%')]"/> -->
|
||||
<field name="senderNickName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="expressItemName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="deliveryType" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverMobile" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverProvinceName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverCityName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverCountyName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverTownName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverCompany" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="remark" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="grossWeight" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="grossVolume" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="pickupBeginTime" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="bill_show" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="logistics_status"/>
|
||||
<record id="tracking_only_view" model="ir.ui.view">
|
||||
<field name="name">tracking only</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form//sheet//notebook//page[@name='operations']" position="after">
|
||||
<page string="发货信息" name="tracking">
|
||||
<group>
|
||||
<group>
|
||||
<field name="senderNickName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="expressItemName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="grossWeight" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="grossVolume" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="deliveryType" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverMobile" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverProvinceName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverCityName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverCountyName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverTownName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="receiverCompany" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
<field name="remark" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
|
||||
<field name="pickupBeginTime" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="logistics_status"/>
|
||||
<field name="carrier_id"/>
|
||||
<field name="carrier_tracking_ref"/>
|
||||
|
||||
<field name="bill_show" attrs="{'invisible': [('check_out', '!=', 'OUT')]}" string='面单下载'/>
|
||||
<field name="bill_show" widget="pdf_viewer" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="//group//field[@name='group_id']" position="after">
|
||||
<field name="bill_show" widget="pdf_viewer" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||
</xpath>
|
||||
<!-- <xpath expr="//group[@name='other_infos']" position="after"> -->
|
||||
<!-- <div> -->
|
||||
<!-- <button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- <div> -->
|
||||
<!-- <button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- </xpath> -->
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -22,6 +22,16 @@
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
</record>
|
||||
|
||||
<record id="stock_location_tool_dismantle" model="stock.location">
|
||||
<field name="name">拆解</field>
|
||||
<field name="location_id" ref="stock.stock_location_locations_virtual"/>
|
||||
<field name="usage">internal</field>
|
||||
<field name="barcode">DJCJ</field>
|
||||
<field name="scrap_location">true</field>
|
||||
<field name="active">true</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="after_assembly_picking_in" model="stock.picking.type">
|
||||
<field name="name">刀具组装入库</field>
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
</div>
|
||||
<field name="model_volume" string="体积[mm³]"/>
|
||||
<field name="product_model_type_id" string="模型类型"/>
|
||||
<field name="model_processing_panel" placeholder="例如R,U" string="加工面板"/>
|
||||
<field name="model_processing_panel" placeholder="例如R,U" string="加工面板" readonly="1"/>
|
||||
<field name="model_machining_precision"/>
|
||||
<field name="model_process_parameters_ids" string="表面工艺参数"
|
||||
widget="many2many_tags"
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from . import models
|
||||
from . import wizard
|
||||
from . import controllers
|
||||
|
||||
1
sf_machine_connect/controllers/__init__.py
Normal file
1
sf_machine_connect/controllers/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import controllers
|
||||
98
sf_machine_connect/controllers/controllers.py
Normal file
98
sf_machine_connect/controllers/controllers.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import ast
|
||||
import json
|
||||
import logging
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class Sf_Dashboard_Connect(http.Controller):
|
||||
|
||||
@http.route('/api/get_machine_datas/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def get_machine_datas_list(self, **kw):
|
||||
"""
|
||||
拿到机床数据返回给大屏展示
|
||||
:param kw:
|
||||
:return:
|
||||
"""
|
||||
res = {'status': 1, 'message': '成功', 'data': []}
|
||||
logging.info('前端请求机床数据的参数为:%s' % kw)
|
||||
# tem_list = [
|
||||
# "XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-1", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-3",
|
||||
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-4", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-5",
|
||||
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-6", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-7",
|
||||
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-8", "XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-2",
|
||||
# "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-9", "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-10",
|
||||
# "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-11", "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-12",
|
||||
# "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-13", "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-14"
|
||||
# ]
|
||||
try:
|
||||
equipment_obj = request.env['maintenance.equipment'].sudo()
|
||||
# 获取请求的机床数据
|
||||
machine_list = ast.literal_eval(kw['machine_list'])
|
||||
for item in machine_list:
|
||||
machine_data = equipment_obj.search([('code', '=', item)])
|
||||
if machine_data:
|
||||
res['data'].append({
|
||||
'id': machine_data.id,
|
||||
'name': machine_data.name,
|
||||
'code': machine_data.code,
|
||||
'status': machine_data.status,
|
||||
'run_status': machine_data.run_status,
|
||||
'run_time': machine_data.run_time,
|
||||
'system_date': machine_data.system_date,
|
||||
'system_time': machine_data.system_time,
|
||||
'cut_time': machine_data.cut_time,
|
||||
'cut_status': machine_data.cut_status,
|
||||
'program': machine_data.program,
|
||||
'program_name': machine_data.program_name,
|
||||
'program_status': machine_data.program_status,
|
||||
'tool_num': machine_data.tool_num,
|
||||
'machine_power_on_time': machine_data.machine_power_on_time,
|
||||
'product_counts': machine_data.product_counts,
|
||||
'mode': machine_data.mode,
|
||||
'start_time': machine_data.start_time,
|
||||
'end_time': machine_data.end_time,
|
||||
'program_start_time': machine_data.program_start_time,
|
||||
'program_end_time': machine_data.program_end_time,
|
||||
'standby_start_time': machine_data.standby_start_time,
|
||||
'standby_end_time': machine_data.standby_end_time,
|
||||
'offline_start_time': machine_data.offline_start_time,
|
||||
'offline_end_time': machine_data.offline_end_time,
|
||||
'emg_status': machine_data.emg_status,
|
||||
'current_program': machine_data.current_program,
|
||||
'current_program_seq': machine_data.current_program_seq,
|
||||
'x_abs_pos': machine_data.x_abs_pos,
|
||||
'y_abs_pos': machine_data.y_abs_pos,
|
||||
'z_abs_pos': machine_data.z_abs_pos,
|
||||
'feed_speed_set': machine_data.feed_speed_set,
|
||||
'act_feed_speed': machine_data.act_feed_speed,
|
||||
'spindle_speed_set': machine_data.spindle_speed_set,
|
||||
'act_spindle_speed': machine_data.act_spindle_speed,
|
||||
'spindle_load': machine_data.spindle_load,
|
||||
'x_axis_load': machine_data.x_axis_load,
|
||||
'y_axis_load': machine_data.y_axis_load,
|
||||
'z_axis_load': machine_data.z_axis_load,
|
||||
'rapid_feed': machine_data.rapid_feed,
|
||||
'feed_rate': machine_data.feed_rate,
|
||||
'x_mach_coord': machine_data.x_mach_coord,
|
||||
'y_mach_coord': machine_data.y_mach_coord,
|
||||
'z_mach_coord': machine_data.z_mach_coord,
|
||||
'x_rel_coord': machine_data.x_rel_coord,
|
||||
'y_rel_coord': machine_data.y_rel_coord,
|
||||
'z_rel_coord': machine_data.z_rel_coord,
|
||||
'x_dis_coord': machine_data.x_dis_coord,
|
||||
'y_dis_coord': machine_data.y_dis_coord,
|
||||
'z_dis_coord': machine_data.z_dis_coord,
|
||||
'alarm_time': machine_data.alarm_time,
|
||||
'alarm_msg': machine_data.alarm_msg,
|
||||
'clear_time': machine_data.clear_time,
|
||||
})
|
||||
|
||||
return json.JSONEncoder().encode(res)
|
||||
except Exception as e:
|
||||
logging.info('前端请求机床数据失败,原因:%s' % e)
|
||||
res['status'] = -1
|
||||
res['message'] = '前端请求机床数据失败,原因:%s' % e
|
||||
return json.JSONEncoder().encode(res)
|
||||
@@ -123,128 +123,159 @@ class Machine_ftp(models.Model):
|
||||
|
||||
# workorder_ids = fields.One2many('mrp.workorder', 'machine_tool_id', string='工单')
|
||||
|
||||
# 机床配置项目
|
||||
# ftp相关
|
||||
ftp_num = fields.Char('ftp账号')
|
||||
ftp_pwd = fields.Char('ftp密码')
|
||||
ftp_host = fields.Char('ftp地址')
|
||||
ftp_port = fields.Integer('ftp端口')
|
||||
ftp_remote_path = fields.Char('机床ftp路径')
|
||||
# 补偿值写入相关
|
||||
x_compensation_node = fields.Char('x补偿值节点')
|
||||
y_compensation_node = fields.Char('y补偿值节点')
|
||||
# 数采配置相关
|
||||
machine_ip = fields.Char('机床IP')
|
||||
machine_signed = fields.Char('机床刷新间隔')
|
||||
machine_status = fields.Char('机床在线状态')
|
||||
machine_cnc_type = fields.Char('机床CNC型号')
|
||||
machine_axis_count = fields.Char('机床轴总数')
|
||||
machine_run_status = fields.Char('机床运行状态')
|
||||
machine_emg_status = fields.Char('机床急停状态')
|
||||
machine_cut_status = fields.Char('机床当前切削状态')
|
||||
machine_mode = fields.Char('机床当前操作模式')
|
||||
machine_spindle_load = fields.Char('机床主轴负载')
|
||||
machine_x_mach = fields.Char('机床X轴机械坐标')
|
||||
machine_x_abs_mach = fields.Char('机床X轴当前位置')
|
||||
machine_x_rel_mach = fields.Char('机床X轴相对工件坐标')
|
||||
machine_x_dis_mach = fields.Char('机床X轴目标距离')
|
||||
machine_x_axis_load = fields.Char('机床X轴伺服轴负载')
|
||||
machine_y_mach = fields.Char('机床Y轴机械坐标')
|
||||
machine_y_abs_mach = fields.Char('机床Y轴当前位置')
|
||||
machine_y_rel_mach = fields.Char('机床Y轴相对工件坐标')
|
||||
machine_y_dis_mach = fields.Char('机床Y轴目标距离')
|
||||
machine_y_axis_load = fields.Char('机床Y轴伺服轴负载')
|
||||
machine_z_mach = fields.Char('机床Z轴机械坐标')
|
||||
machine_z_abs_mach = fields.Char('机床Z轴当前位置')
|
||||
machine_z_rel_mach = fields.Char('机床Z轴相对工件坐标')
|
||||
machine_z_dis_mach = fields.Char('机床Z轴目标距离')
|
||||
machine_z_axis_load = fields.Char('机床Z轴伺服轴负载')
|
||||
machine_tool_num = fields.Char('机床当前刀位号')
|
||||
machine_program = fields.Char('机床主程序名称')
|
||||
machine_current_prg = fields.Char('机床当前执行指令')
|
||||
machine_prg_seq = fields.Char('机床当前执行语句号')
|
||||
machine_spindle_speed_set = fields.Char('机床设定主轴速度')
|
||||
machine_act_spindle_speed = fields.Char('机床实际主轴转速')
|
||||
machine_feed_speed_set = fields.Char('机床设定进给速度')
|
||||
machine_act_feed_speed = fields.Char('机床实际进给速度')
|
||||
machine_spindle_feed = fields.Char('机床主轴倍率')
|
||||
machine_feed_rate = fields.Char('机床进给倍率')
|
||||
machine_rapid_feed = fields.Char('机床快速移动倍率')
|
||||
machine_run_time = fields.Char('机床运行时间')
|
||||
machine_cut_time = fields.Char('机床切削时间')
|
||||
machine_keep_alive_time = fields.Char('机床上电时间')
|
||||
machine_circle_time = fields.Char('机床循环时间')
|
||||
machine_product_counts = fields.Char('机床加工件数')
|
||||
machine_system_date = fields.Char('机床系统日期')
|
||||
machine_system_time = fields.Char('机床系统时间')
|
||||
machine_alarm_msg = fields.Char('机床系统报警')
|
||||
# # 机床配置项目
|
||||
# # ftp相关
|
||||
# ftp_num = fields.Char('ftp账号')
|
||||
# ftp_pwd = fields.Char('ftp密码')
|
||||
# ftp_host = fields.Char('ftp地址')
|
||||
# ftp_port = fields.Integer('ftp端口')
|
||||
# ftp_remote_path = fields.Char('机床ftp路径')
|
||||
# # 补偿值写入相关
|
||||
# x_compensation_node = fields.Char('x补偿值节点')
|
||||
# y_compensation_node = fields.Char('y补偿值节点')
|
||||
# # 数采配置相关
|
||||
# machine_ip = fields.Char('机床IP')
|
||||
# machine_signed = fields.Char('机床刷新间隔')
|
||||
# machine_status = fields.Char('机床在线状态')
|
||||
# machine_cnc_type = fields.Char('机床CNC型号')
|
||||
# machine_axis_count = fields.Char('机床轴总数')
|
||||
# machine_run_status = fields.Char('机床运行状态')
|
||||
# machine_emg_status = fields.Char('机床急停状态')
|
||||
# machine_cut_status = fields.Char('机床当前切削状态')
|
||||
# machine_mode = fields.Char('机床当前操作模式')
|
||||
# machine_spindle_load = fields.Char('机床主轴负载')
|
||||
# machine_x_mach = fields.Char('机床X轴机械坐标')
|
||||
# machine_x_abs_mach = fields.Char('机床X轴当前位置')
|
||||
# machine_x_rel_mach = fields.Char('机床X轴相对工件坐标')
|
||||
# machine_x_dis_mach = fields.Char('机床X轴目标距离')
|
||||
# machine_x_axis_load = fields.Char('机床X轴伺服轴负载')
|
||||
# machine_y_mach = fields.Char('机床Y轴机械坐标')
|
||||
# machine_y_abs_mach = fields.Char('机床Y轴当前位置')
|
||||
# machine_y_rel_mach = fields.Char('机床Y轴相对工件坐标')
|
||||
# machine_y_dis_mach = fields.Char('机床Y轴目标距离')
|
||||
# machine_y_axis_load = fields.Char('机床Y轴伺服轴负载')
|
||||
# machine_z_mach = fields.Char('机床Z轴机械坐标')
|
||||
# machine_z_abs_mach = fields.Char('机床Z轴当前位置')
|
||||
# machine_z_rel_mach = fields.Char('机床Z轴相对工件坐标')
|
||||
# machine_z_dis_mach = fields.Char('机床Z轴目标距离')
|
||||
# machine_z_axis_load = fields.Char('机床Z轴伺服轴负载')
|
||||
# machine_tool_num = fields.Char('机床当前刀位号')
|
||||
# machine_program = fields.Char('机床主程序名称')
|
||||
# machine_current_prg = fields.Char('机床当前执行指令')
|
||||
# machine_prg_seq = fields.Char('机床当前执行语句号')
|
||||
# machine_spindle_speed_set = fields.Char('机床设定主轴速度')
|
||||
# machine_act_spindle_speed = fields.Char('机床实际主轴转速')
|
||||
# machine_feed_speed_set = fields.Char('机床设定进给速度')
|
||||
# machine_act_feed_speed = fields.Char('机床实际进给速度')
|
||||
# machine_spindle_feed = fields.Char('机床主轴倍率')
|
||||
# machine_feed_rate = fields.Char('机床进给倍率')
|
||||
# machine_rapid_feed = fields.Char('机床快速移动倍率')
|
||||
# machine_run_time = fields.Char('机床运行时间')
|
||||
# machine_cut_time = fields.Char('机床切削时间')
|
||||
# machine_keep_alive_time = fields.Char('机床上电时间')
|
||||
# machine_circle_time = fields.Char('机床循环时间')
|
||||
# machine_product_counts = fields.Char('机床加工件数')
|
||||
# machine_system_date = fields.Char('机床系统日期')
|
||||
# machine_system_time = fields.Char('机床系统时间')
|
||||
# machine_alarm_msg = fields.Char('机床系统报警')
|
||||
|
||||
# 刀位配置
|
||||
tool_num1 = fields.Char('刀位1')
|
||||
tool_num2 = fields.Char('刀位2')
|
||||
tool_num3 = fields.Char('刀位3')
|
||||
tool_num4 = fields.Char('刀位4')
|
||||
tool_num5 = fields.Char('刀位5')
|
||||
tool_num6 = fields.Char('刀位6')
|
||||
tool_num7 = fields.Char('刀位7')
|
||||
tool_num8 = fields.Char('刀位8')
|
||||
tool_num9 = fields.Char('刀位9')
|
||||
tool_num10 = fields.Char('刀位10')
|
||||
tool_num11 = fields.Char('刀位11')
|
||||
tool_num12 = fields.Char('刀位12')
|
||||
tool_num13 = fields.Char('刀位13')
|
||||
tool_num14 = fields.Char('刀位14')
|
||||
tool_num15 = fields.Char('刀位15')
|
||||
tool_num16 = fields.Char('刀位16')
|
||||
tool_num17 = fields.Char('刀位17')
|
||||
tool_num18 = fields.Char('刀位18')
|
||||
tool_num19 = fields.Char('刀位19')
|
||||
tool_num20 = fields.Char('刀位20')
|
||||
tool_num21 = fields.Char('刀位21')
|
||||
tool_num22 = fields.Char('刀位22')
|
||||
tool_num23 = fields.Char('刀位23')
|
||||
tool_num24 = fields.Char('刀位24')
|
||||
# # 刀位配置
|
||||
# tool_num1 = fields.Char('刀位1')
|
||||
# tool_num2 = fields.Char('刀位2')
|
||||
# tool_num3 = fields.Char('刀位3')
|
||||
# tool_num4 = fields.Char('刀位4')
|
||||
# tool_num5 = fields.Char('刀位5')
|
||||
# tool_num6 = fields.Char('刀位6')
|
||||
# tool_num7 = fields.Char('刀位7')
|
||||
# tool_num8 = fields.Char('刀位8')
|
||||
# tool_num9 = fields.Char('刀位9')
|
||||
# tool_num10 = fields.Char('刀位10')
|
||||
# tool_num11 = fields.Char('刀位11')
|
||||
# tool_num12 = fields.Char('刀位12')
|
||||
# tool_num13 = fields.Char('刀位13')
|
||||
# tool_num14 = fields.Char('刀位14')
|
||||
# tool_num15 = fields.Char('刀位15')
|
||||
# tool_num16 = fields.Char('刀位16')
|
||||
# tool_num17 = fields.Char('刀位17')
|
||||
# tool_num18 = fields.Char('刀位18')
|
||||
# tool_num19 = fields.Char('刀位19')
|
||||
# tool_num20 = fields.Char('刀位20')
|
||||
# tool_num21 = fields.Char('刀位21')
|
||||
# tool_num22 = fields.Char('刀位22')
|
||||
# tool_num23 = fields.Char('刀位23')
|
||||
# tool_num24 = fields.Char('刀位24')
|
||||
|
||||
# 机床采集项目
|
||||
timestamp = fields.Datetime('时间戳', readonly=True)
|
||||
signed = fields.Integer('刷新间隔', readonly=True)
|
||||
status = fields.Boolean('在线状态', readonly=True)
|
||||
time_on = fields.Char('总在线时长', readonly=True)
|
||||
time_on_now = fields.Char('本次在线时长', readonly=True)
|
||||
tool_num = fields.Integer('当前刀具', readonly=True)
|
||||
program = fields.Char('当前程序', readonly=True)
|
||||
run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], string='运行状态',
|
||||
readonly=True, default='0')
|
||||
run_time = fields.Char('总运行时长', readonly=True)
|
||||
cut_time = fields.Char('总切削时长', readonly=True)
|
||||
cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], string='切削状态',
|
||||
readonly=True, default='0')
|
||||
spindle_speed = fields.Char('主轴转速', readonly=True)
|
||||
status = fields.Boolean('机床在线状态', readonly=True)
|
||||
# run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], string='机床运行状态',
|
||||
# readonly=True, default='0')
|
||||
run_status = fields.Char('机床运行状态', readonly=True)
|
||||
run_time = fields.Char('机床累计运行时长', readonly=True)
|
||||
# 机床系统日期
|
||||
system_date = fields.Char('机床系统日期', readonly=True)
|
||||
# 机床系统时间
|
||||
system_time = fields.Char('机床系统时间', readonly=True)
|
||||
cut_time = fields.Char('机床累计切削时间', readonly=True)
|
||||
# cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], string='机床当前切削状态',
|
||||
# readonly=True, default='0')
|
||||
cut_status = fields.Char('机床当前切削状态', readonly=True)
|
||||
# 当前程序名
|
||||
program = fields.Char('机床当前程序', readonly=True)
|
||||
# 当前刀具号
|
||||
tool_num = fields.Integer('机床当前刀具号', readonly=True)
|
||||
# 机床通电开机时间, 机床加工件数, 机床当前操作模式, 开始加工时间, 结束加工时间, 加工程序开始时间, 加工程序结束时间, 待机开始时间,
|
||||
# 待机结束时间, 机床离线开始时间, 机床离线结束时间, 机床急停状态, 机床主程序名称, 程序运行的状态, 机床当前执行指令, 机床当前执行语句号
|
||||
# 机床X轴当前位置, 机床Y轴当前位置, 机床Z轴当前位置
|
||||
machine_power_on_time = fields.Char('机床通电开机时间', readonly=True)
|
||||
product_counts = fields.Char('机床加工件数', readonly=True)
|
||||
mode = fields.Char('机床当前操作模式', readonly=True)
|
||||
start_time = fields.Char('开始加工时间', readonly=True)
|
||||
end_time = fields.Char('结束加工时间', readonly=True)
|
||||
program_start_time = fields.Char('加工程序开始时间', readonly=True)
|
||||
program_end_time = fields.Char('加工程序结束时间', readonly=True)
|
||||
standby_start_time = fields.Char('待机开始时间', readonly=True)
|
||||
standby_end_time = fields.Char('待机结束时间', readonly=True)
|
||||
offline_start_time = fields.Char('机床离线开始时间', readonly=True)
|
||||
offline_end_time = fields.Char('机床离线结束时间', readonly=True)
|
||||
emg_status = fields.Char('机床急停状态', readonly=True)
|
||||
program_name = fields.Char('机床主程序名称', readonly=True)
|
||||
program_status = fields.Char('程序运行状态', readonly=True)
|
||||
current_program = fields.Char('机床当前执行指令', readonly=True)
|
||||
current_program_seq = fields.Char('机床当前执行语句号', readonly=True)
|
||||
x_abs_pos = fields.Char('机床X轴当前位置(mm)', readonly=True)
|
||||
y_abs_pos = fields.Char('机床Y轴当前位置(mm)', readonly=True)
|
||||
z_abs_pos = fields.Char('机床Z轴当前位置(mm)', readonly=True)
|
||||
|
||||
tool_num_process_time1 = fields.Char('刀位1', readonly=True, default='0')
|
||||
tool_num_process_time2 = fields.Char('刀位2', readonly=True, default='0')
|
||||
tool_num_process_time3 = fields.Char('刀位3', readonly=True, default='0')
|
||||
tool_num_process_time4 = fields.Char('刀位4', readonly=True, default='0')
|
||||
tool_num_process_time5 = fields.Char('刀位5', readonly=True, default='0')
|
||||
tool_num_process_time6 = fields.Char('刀位6', readonly=True, default='0')
|
||||
tool_num_process_time7 = fields.Char('刀位7', readonly=True, default='0')
|
||||
tool_num_process_time8 = fields.Char('刀位8', readonly=True, default='0')
|
||||
tool_num_process_time9 = fields.Char('刀位9', readonly=True, default='0')
|
||||
tool_num_process_time10 = fields.Char('刀位10', readonly=True, default='0')
|
||||
tool_num_process_time11 = fields.Char('刀位11', readonly=True, default='0')
|
||||
tool_num_process_time12 = fields.Char('刀位12', readonly=True, default='0')
|
||||
tool_num_process_time13 = fields.Char('刀位13', readonly=True, default='0')
|
||||
tool_num_process_time14 = fields.Char('刀位14', readonly=True, default='0')
|
||||
tool_num_process_time15 = fields.Char('刀位15', readonly=True, default='0')
|
||||
tool_num_process_time16 = fields.Char('刀位16', readonly=True, default='0')
|
||||
tool_num_process_time17 = fields.Char('刀位17', readonly=True, default='0')
|
||||
tool_num_process_time18 = fields.Char('刀位18', readonly=True, default='0')
|
||||
tool_num_process_time19 = fields.Char('刀位19', readonly=True, default='0')
|
||||
tool_num_process_time20 = fields.Char('刀位20', readonly=True, default='0')
|
||||
tool_num_process_time21 = fields.Char('刀位21', readonly=True, default='0')
|
||||
tool_num_process_time22 = fields.Char('刀位22', readonly=True, default='0')
|
||||
tool_num_process_time23 = fields.Char('刀位23', readonly=True, default='0')
|
||||
tool_num_process_time24 = fields.Char('刀位24', readonly=True, default='0')
|
||||
# 机床设定进给速度, 机床实际进给速度, 机床设定主轴转速, 机床实际主轴转速, 机床主轴负载, 机床X轴伺服轴负载, 机床Y轴伺服轴负载
|
||||
# 机床Z轴伺服轴负载, 机床快速移动倍率, 机床进给倍率, 机床X轴机械坐标, 机床Y轴机械坐标, 机床Z轴机械坐标, 机床X轴相对工件坐标
|
||||
# 机床Y轴相对工件坐标, 机床Z轴相对工件坐标, 机床X轴目标距离, 机床Y轴目标距离, 机床Z轴目标距离
|
||||
feed_speed_set = fields.Char('机床设定进给速度(mm/min)', readonly=True)
|
||||
act_feed_speed = fields.Char('机床实际进给速度(mm/min)', readonly=True)
|
||||
spindle_speed_set = fields.Char('机床设定主轴转速(r/min)', readonly=True)
|
||||
act_spindle_speed = fields.Char('机床实际主轴转速(r/min)', readonly=True)
|
||||
spindle_load = fields.Char('机床主轴负载(%)', readonly=True)
|
||||
x_axis_load = fields.Char('机床X轴伺服轴负载(%)', readonly=True)
|
||||
y_axis_load = fields.Char('机床Y轴伺服轴负载(%)', readonly=True)
|
||||
z_axis_load = fields.Char('机床Z轴伺服轴负载(%)', readonly=True)
|
||||
rapid_feed = fields.Char('机床快速移动倍率(%)', readonly=True)
|
||||
feed_rate = fields.Char('机床进给倍率(%)', readonly=True)
|
||||
x_mach_coord = fields.Char('机床X轴机械坐标(mm)', readonly=True)
|
||||
y_mach_coord = fields.Char('机床Y轴机械坐标(mm)', readonly=True)
|
||||
z_mach_coord = fields.Char('机床Z轴机械坐标(mm)', readonly=True)
|
||||
x_rel_coord = fields.Char('机床X轴相对工件坐标(mm)', readonly=True)
|
||||
y_rel_coord = fields.Char('机床Y轴相对工件坐标(mm)', readonly=True)
|
||||
z_rel_coord = fields.Char('机床Z轴相对工件坐标(mm)', readonly=True)
|
||||
x_dis_coord = fields.Char('机床X轴目标距离(mm)', readonly=True)
|
||||
y_dis_coord = fields.Char('机床Y轴目标距离(mm)', readonly=True)
|
||||
z_dis_coord = fields.Char('机床Z轴目标距离(mm)', readonly=True)
|
||||
|
||||
# 故障报警时间, 故障报警信息, 故障消除时间(复原时间)
|
||||
alarm_time = fields.Char('故障报警时间', readonly=True)
|
||||
alarm_msg = fields.Char('故障报警信息', readonly=True)
|
||||
clear_time = fields.Char('故障消除时间(复原时间)', readonly=True)
|
||||
|
||||
# 当前程序名, 机床累计运行时间, 机床系统日期, 机床系统时间, 当前刀具号, 机床循环时间
|
||||
|
||||
|
||||
class WorkCenterBarcode(models.Model):
|
||||
@@ -259,39 +290,59 @@ class WorkCenterBarcode(models.Model):
|
||||
button_compensation_state = fields.Boolean(string='是否已经补偿', readonly=True)
|
||||
button_up_all_state = fields.Boolean(string='是否已经全部下发', readonly=True)
|
||||
machine_tool_id = fields.Many2one('sf.machine_tool.type', string='机床')
|
||||
machine_tool_name = fields.Char(string='机床名称', default='未知机床', compute='_run_info', readonly=True)
|
||||
machine_tool_type_id = fields.Char(string='机床型号', default='未知型号', compute='_run_info', readonly=True)
|
||||
machine_tool_status = fields.Boolean(string='在线状态', compute='_run_info', readonly=True)
|
||||
# machine_tool_name = fields.Char(string='机床名称', default='未知机床', compute='_run_info', readonly=True)
|
||||
# machine_tool_type_id = fields.Char(string='机床型号', default='未知型号', compute='_run_info', readonly=True)
|
||||
# machine_tool_status = fields.Boolean(string='在线状态', compute='_run_info', readonly=True)
|
||||
# machine_tool_run_status = fields.Selection([('0', '关机中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')],
|
||||
# string='运行状态', compute='_run_info', readonly=True, default='0')
|
||||
# machine_tool_timestamp = fields.Datetime('时间戳', compute='_run_info', readonly=True)
|
||||
# machine_tool_time_on = fields.Char('总在线时长', compute='_run_info', readonly=True)
|
||||
# machine_tool_time_on_now = fields.Char('本次在线时长', compute='_run_info', readonly=True)
|
||||
# machine_tool_tool_num = fields.Integer('当前刀具', compute='_run_info', readonly=True)
|
||||
# machine_tool_program = fields.Char('当前程序', compute='_run_info', readonly=True)
|
||||
# machine_tool_machine_ip = fields.Char('机床IP', compute='_run_info', readonly=True)
|
||||
# machine_tool_cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')],
|
||||
# string='切削状态', compute='_run_info', readonly=True, default='0')
|
||||
# machine_tool_compensation_value_x = fields.Char('x补偿值', compute='_run_info', readonly=True)
|
||||
# machine_tool_compensation_value_y = fields.Char('y补偿值', compute='_run_info', readonly=True)
|
||||
|
||||
machine_tool_name = fields.Char(string='机床名称', default='未知机床', readonly=True)
|
||||
machine_tool_type_id = fields.Char(string='机床型号', default='未知型号', readonly=True)
|
||||
machine_tool_status = fields.Boolean(string='在线状态', readonly=True)
|
||||
machine_tool_run_status = fields.Selection([('0', '关机中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')],
|
||||
string='运行状态', compute='_run_info', readonly=True, default='0')
|
||||
machine_tool_timestamp = fields.Datetime('时间戳', compute='_run_info', readonly=True)
|
||||
machine_tool_time_on = fields.Char('总在线时长', compute='_run_info', readonly=True)
|
||||
machine_tool_time_on_now = fields.Char('本次在线时长', compute='_run_info', readonly=True)
|
||||
machine_tool_tool_num = fields.Integer('当前刀具', compute='_run_info', readonly=True)
|
||||
machine_tool_program = fields.Char('当前程序', compute='_run_info', readonly=True)
|
||||
machine_tool_machine_ip = fields.Char('机床IP', compute='_run_info', readonly=True)
|
||||
string='运行状态', readonly=True, default='0')
|
||||
machine_tool_timestamp = fields.Datetime('时间戳', readonly=True)
|
||||
machine_tool_time_on = fields.Char('总在线时长', readonly=True)
|
||||
machine_tool_time_on_now = fields.Char('本次在线时长', readonly=True)
|
||||
machine_tool_tool_num = fields.Integer('当前刀具', readonly=True)
|
||||
machine_tool_program = fields.Char('当前程序', readonly=True)
|
||||
machine_tool_machine_ip = fields.Char('机床IP', readonly=True)
|
||||
machine_tool_cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')],
|
||||
string='切削状态', compute='_run_info', readonly=True, default='0')
|
||||
machine_tool_compensation_value_x = fields.Char('x补偿值', compute='_run_info', readonly=True)
|
||||
machine_tool_compensation_value_y = fields.Char('y补偿值', compute='_run_info', readonly=True)
|
||||
string='切削状态', readonly=True, default='0')
|
||||
machine_tool_compensation_value_x = fields.Char('x补偿值', readonly=True)
|
||||
machine_tool_compensation_value_y = fields.Char('y补偿值', readonly=True)
|
||||
|
||||
# 工单状态
|
||||
|
||||
delivery_records = fields.One2many('delivery.record', 'workorder_id', string="下发记录")
|
||||
|
||||
@api.depends('equipment_id.timestamp')
|
||||
def _run_info(self):
|
||||
# self.machine_tool_name = '1号机床'
|
||||
self.machine_tool_name = self.equipment_id.name
|
||||
self.machine_tool_type_id = self.equipment_id.type_id.name
|
||||
self.machine_tool_status = self.equipment_id.status
|
||||
self.machine_tool_run_status = self.equipment_id.run_status
|
||||
self.machine_tool_timestamp = self.equipment_id.timestamp
|
||||
self.machine_tool_time_on = self.equipment_id.time_on
|
||||
self.machine_tool_time_on_now = self.equipment_id.time_on_now
|
||||
self.machine_tool_tool_num = self.equipment_id.tool_num
|
||||
self.machine_tool_program = self.equipment_id.program
|
||||
self.machine_tool_machine_ip = self.equipment_id.machine_ip
|
||||
self.machine_tool_cut_status = self.equipment_id.cut_status
|
||||
self.machine_tool_compensation_value_x = self.compensation_value_x
|
||||
self.machine_tool_compensation_value_y = self.compensation_value_y
|
||||
# self.machine_tool_name = self.equipment_id.name
|
||||
# self.machine_tool_type_id = self.equipment_id.type_id.name
|
||||
# self.machine_tool_status = self.equipment_id.status
|
||||
# self.machine_tool_run_status = self.equipment_id.run_status
|
||||
# self.machine_tool_timestamp = self.equipment_id.timestamp
|
||||
# self.machine_tool_time_on = self.equipment_id.time_on
|
||||
# self.machine_tool_time_on_now = self.equipment_id.time_on_now
|
||||
# self.machine_tool_tool_num = self.equipment_id.tool_num
|
||||
# self.machine_tool_program = self.equipment_id.program
|
||||
# self.machine_tool_machine_ip = self.equipment_id.machine_ip
|
||||
# self.machine_tool_cut_status = self.equipment_id.cut_status
|
||||
# self.machine_tool_compensation_value_x = self.compensation_value_x
|
||||
# self.machine_tool_compensation_value_y = self.compensation_value_y
|
||||
pass
|
||||
|
||||
def compensation(self):
|
||||
|
||||
|
||||
@@ -8,11 +8,14 @@ _logger = logging.getLogger(__name__)
|
||||
class ResBFMConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
bfm_url = fields.Selection(
|
||||
[("https://bfm.cs.jikimo.com", "开发环境(https://bfm.cs.jikimo.com)"),
|
||||
("https://bfm.t.jikimo.com", "测试环境(https://bfm.t.jikimo.com)"),
|
||||
# ("正式环境", "https://bfm.jikimo.com")], string='bfm环境', store=True)
|
||||
("https://bfm.jikimo.com", "正式环境(https://bfm.jikimo.com)")], string='bfm环境', store=True)
|
||||
# bfm_url = fields.Selection(
|
||||
# [("https://bfm.cs.jikimo.com", "开发环境(https://bfm.cs.jikimo.com)"),
|
||||
# ("https://bfm.t.jikimo.com", "测试环境(https://bfm.t.jikimo.com)"),
|
||||
# ("https://bfm.r.jikimo.com", "预发布环境(https://bfm.r.jikimo.com)"),
|
||||
# # ("正式环境", "https://bfm.jikimo.com")], string='bfm环境', store=True)
|
||||
# ("https://bfm.jikimo.com", "正式环境(https://bfm.jikimo.com)")], string='bfm环境', store=True)
|
||||
|
||||
bfm_url_new = fields.Char('业务平台环境路径', placeholder='请输入当前对应的业务平台环境路径')
|
||||
|
||||
@api.model
|
||||
def get_values(self):
|
||||
@@ -22,14 +25,14 @@ class ResBFMConfigSettings(models.TransientModel):
|
||||
"""
|
||||
values = super(ResBFMConfigSettings, self).get_values()
|
||||
config = self.env['ir.config_parameter'].sudo()
|
||||
bfm_url = config.get_param('bfm_url', default='')
|
||||
bfm_url_new = config.get_param('bfm_url_new', default='')
|
||||
|
||||
values.update(
|
||||
bfm_url=bfm_url,
|
||||
bfm_url_new=bfm_url_new,
|
||||
)
|
||||
return values
|
||||
|
||||
def set_values(self):
|
||||
super(ResBFMConfigSettings, self).set_values()
|
||||
ir_config = self.env['ir.config_parameter'].sudo()
|
||||
ir_config.set_param("bfm_url", self.bfm_url or "")
|
||||
ir_config.set_param("bfm_url_new", self.bfm_url_new or "")
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='production_id']" position="before">
|
||||
<field name="product_tmpl_name"/>
|
||||
<field name="rfid_code"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<field name="model">mrp.workorder</field>
|
||||
<field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- <xpath expr="//header" position="inside">-->
|
||||
<!-- <button string="程序下载" name="cnc_file_download" type="object" class="oe_highlight" attrs='{"invisible": ["|",-->
|
||||
<!-- ("user_permissions","=",False),("routing_type","!=","CNC加工")]}'/>-->
|
||||
<!-- </xpath>-->
|
||||
<!-- <xpath expr="//header" position="inside">–>-->
|
||||
<!-- <button string="程序下载" name="cnc_file_download" type="object" class="oe_highlight" attrs='{"invisible": ["|",-->
|
||||
<!-- ("user_permissions","=",False),("routing_type","!=","CNC加工")]}'/>-->
|
||||
<!-- </xpath>-->
|
||||
<xpath expr="//page//field[@name='cnc_ids']" position="before">
|
||||
<group>
|
||||
<group>
|
||||
@@ -17,15 +17,15 @@
|
||||
</group>
|
||||
<div>
|
||||
<div>
|
||||
<field name="button_compensation_state" attrs='{"invisible": ["|",
|
||||
("state","!=","progress"),("user_permissions","=",False)]}'/>
|
||||
<!-- <field name="button_compensation_state" attrs='{"invisible": ["|",-->
|
||||
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>-->
|
||||
<!-- <span> </span>-->
|
||||
<button name="button_send_program_again" type="object" string="重新下发NC程序"
|
||||
class="btn-primary"
|
||||
confirm="是否确认重新下发NC程序?"
|
||||
groups="sf_base.group_sf_order_user,sf_base.group_sf_equipment_user"
|
||||
attrs="{'invisible': ['|', '|', '|',('routing_type','!=','装夹预调'),('state','in',['done', 'cancel',
|
||||
'progress']),('processing_drawing','=',False),('is_send_program_again','=',True)]}"/>
|
||||
<!-- <button name="button_send_program_again" type="object" string="重新下发NC程序"-->
|
||||
<!-- class="btn-primary"-->
|
||||
<!-- confirm="是否确认重新下发NC程序?"-->
|
||||
<!-- groups="sf_base.group_sf_order_user,sf_base.group_sf_equipment_user"-->
|
||||
<!-- attrs="{'invisible': ['|', '|', '|',('routing_type','!=','装夹预调'),('state','in',['done', 'cancel',-->
|
||||
<!-- 'progress']),('processing_drawing','=',False),('is_send_program_again','=',True)]}"/>-->
|
||||
<!-- <button string="一键补偿" name="compensation" type="object" confirm="是否确认下发补偿"-->
|
||||
<!-- class="btn-primary" attrs='{"invisible": ["|",-->
|
||||
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>-->
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<field name="program_name"/>
|
||||
<field name="functional_tool_type_id"/>
|
||||
<field name="cutting_tool_name"/>
|
||||
<field name="tool_state"/>
|
||||
<field name="cutting_tool_no"/>
|
||||
<field name="processing_type"/>
|
||||
<field name="margin_x_y"/>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<!-- attrs='{"invisible": ["|",("state","!=","progress"), -->
|
||||
<!-- ("user_permissions","!=",True)]}'/> -->
|
||||
<!-- <button string="下发" name="up" type="object" class="btn-primary" confirm="是否确认下发此程序" context="{'default_cnc_ids': cnc_ids}"/> -->
|
||||
<button string="下发" name="up" type="object" class="btn-primary" confirm="是否确认下发此程序"
|
||||
<!-- <button string="下发" name="up" type="object" class="btn-primary" confirm="是否确认下发此程序"-->
|
||||
context="{'default_sf_cnc_processing_id': id}" attrs='{"invisible": ["|",("state","!=","progress"),
|
||||
("user_permissions","!=",True)]}'/>
|
||||
<!-- <button string="下发" name="up" type="object" class="btn-primary" confirm="是否确认下发此程序"-->
|
||||
|
||||
@@ -13,294 +13,138 @@
|
||||
<page string="机床运行状态" attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
|
||||
<group string='状态监控'>
|
||||
<group>
|
||||
<field name="timestamp"/>
|
||||
<field name="signed"/>
|
||||
<!-- <field name="timestamp"/> -->
|
||||
<field name="status"/>
|
||||
<field name="time_on"/>
|
||||
<field name="time_on_now"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="run_status"/>
|
||||
<field name="run_time"/>
|
||||
<field name="system_date"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cut_status"/>
|
||||
<field name="cut_time"/>
|
||||
<!-- <field name="cut_time"/> -->
|
||||
<field name="program"/>
|
||||
<field name="tool_num"/>
|
||||
<field name="spindle_speed"/>
|
||||
</group>
|
||||
</group>
|
||||
<!-- <group string='刀位统计'> -->
|
||||
<!-- <group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="tool_num_process_time1"/> -->
|
||||
<!-- <field name="tool_num_process_time5"/> -->
|
||||
<!-- <field name="tool_num_process_time9"/> -->
|
||||
<!-- <field name="tool_num_process_time13"/> -->
|
||||
<!-- <field name="tool_num_process_time17"/> -->
|
||||
<!-- <field name="tool_num_process_time21"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="tool_num_process_time2"/> -->
|
||||
<!-- <field name="tool_num_process_time6"/> -->
|
||||
<!-- <field name="tool_num_process_time10"/> -->
|
||||
<!-- <field name="tool_num_process_time14"/> -->
|
||||
<!-- <field name="tool_num_process_time18"/> -->
|
||||
<!-- <field name="tool_num_process_time22"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="tool_num_process_time3"/> -->
|
||||
<!-- <field name="tool_num_process_time7"/> -->
|
||||
<!-- <field name="tool_num_process_time11"/> -->
|
||||
<!-- <field name="tool_num_process_time15"/> -->
|
||||
<!-- <field name="tool_num_process_time19"/> -->
|
||||
<!-- <field name="tool_num_process_time23"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="tool_num_process_time4"/> -->
|
||||
<!-- <field name="tool_num_process_time8"/> -->
|
||||
<!-- <field name="tool_num_process_time12"/> -->
|
||||
<!-- <field name="tool_num_process_time16"/> -->
|
||||
<!-- <field name="tool_num_process_time20"/> -->
|
||||
<!-- <field name="tool_num_process_time24"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- </group> -->
|
||||
<!-- </group> -->
|
||||
|
||||
<!-- <div class="o_address_format"> -->
|
||||
<!-- <label for="tool_num_process_time1" string="刀位1"/> -->
|
||||
<!-- <field name="tool_num_process_time1" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time2" string="刀位2"/> -->
|
||||
<!-- <field name="tool_num_process_time2" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time3" string="刀位3"/> -->
|
||||
<!-- <field name="tool_num_process_time3" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time4" string="刀位4"/> -->
|
||||
<!-- <field name="tool_num_process_time4" class="o_form_label"/> -->
|
||||
<!-- <div></div> -->
|
||||
<!-- <label for="tool_num_process_time5" string="刀位5"/> -->
|
||||
<!-- <field name="tool_num_process_time5" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time6" string="刀位6"/> -->
|
||||
<!-- <field name="tool_num_process_time6" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time7" string="刀位7"/> -->
|
||||
<!-- <field name="tool_num_process_time7" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time8" string="刀位8"/> -->
|
||||
<!-- <field name="tool_num_process_time8" class="o_form_label"/> -->
|
||||
<!-- <div></div> -->
|
||||
<!-- <label for="tool_num_process_time9" string="刀位9"/> -->
|
||||
<!-- <field name="tool_num_process_time9" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time10" string="刀位10"/> -->
|
||||
<!-- <field name="tool_num_process_time10" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time11" string="刀位11"/> -->
|
||||
<!-- <field name="tool_num_process_time11" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time12" string="刀位12"/> -->
|
||||
<!-- <field name="tool_num_process_time12" class="o_form_label"/> -->
|
||||
<!-- <div></div> -->
|
||||
<!-- <label for="tool_num_process_time13" string="刀位13"/> -->
|
||||
<!-- <field name="tool_num_process_time13" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time14" string="刀位14"/> -->
|
||||
<!-- <field name="tool_num_process_time14" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time15" string="刀位15"/> -->
|
||||
<!-- <field name="tool_num_process_time15" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time16" string="刀位16"/> -->
|
||||
<!-- <field name="tool_num_process_time16" class="o_form_label"/> -->
|
||||
<!-- <div></div> -->
|
||||
<!-- <label for="tool_num_process_time17" string="刀位17"/> -->
|
||||
<!-- <field name="tool_num_process_time17" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time18" string="刀位18"/> -->
|
||||
<!-- <field name="tool_num_process_time18" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time19" string="刀位19"/> -->
|
||||
<!-- <field name="tool_num_process_time19" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time20" string="刀位20"/> -->
|
||||
<!-- <field name="tool_num_process_time20" class="o_form_label"/> -->
|
||||
<!-- <div></div> -->
|
||||
<!-- <label for="tool_num_process_time21" string="刀位21"/> -->
|
||||
<!-- <field name="tool_num_process_time21" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time22" string="刀位22"/> -->
|
||||
<!-- <field name="tool_num_process_time22" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time23" string="刀位23"/> -->
|
||||
<!-- <field name="tool_num_process_time23" class="o_form_label"/> -->
|
||||
<!-- <span>&nbsp;</span> -->
|
||||
<!-- <label for="tool_num_process_time24" string="刀位24"/> -->
|
||||
<!-- <field name="tool_num_process_time24" class="o_form_label"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- </group> -->
|
||||
</page>
|
||||
<page string="机床运行数据" attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
|
||||
<!-- <group string="机床配置">--> -->
|
||||
<group string="ftp相关">
|
||||
<group>
|
||||
<field name="ftp_num"/>
|
||||
<field name="ftp_pwd"/>
|
||||
<field name="ftp_host"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="ftp_port"/>
|
||||
<field name="ftp_remote_path"/>
|
||||
</group>
|
||||
<group string="运行数据">
|
||||
<group>
|
||||
<field name="machine_power_on_time"/>
|
||||
<field name="product_counts"/>
|
||||
<field name="mode"/>
|
||||
<field name="start_time"/>
|
||||
<field name="end_time"/>
|
||||
<field name="program_start_time"/>
|
||||
<field name="program_end_time"/>
|
||||
<field name="standby_start_time"/>
|
||||
<field name="standby_end_time"/>
|
||||
<field name="offline_start_time"/>
|
||||
<field name="offline_end_time"/>
|
||||
<field name="emg_status"/>
|
||||
<field name="program_name"/>
|
||||
<field name="program_status"/>
|
||||
<field name="current_program"/>
|
||||
<field name="current_program_seq"/>
|
||||
<field name="x_abs_pos"/>
|
||||
<field name="y_abs_pos"/>
|
||||
<field name="z_abs_pos"/>
|
||||
</group>
|
||||
<group string="补偿值相关">
|
||||
<group>
|
||||
<field name="x_compensation_node"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="y_compensation_node"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="feed_speed_set"/>
|
||||
<field name="act_feed_speed"/>
|
||||
<field name="spindle_speed_set"/>
|
||||
<field name="act_spindle_speed"/>
|
||||
<field name="spindle_load"/>
|
||||
<field name="x_axis_load"/>
|
||||
<field name="y_axis_load"/>
|
||||
<field name="z_axis_load"/>
|
||||
<field name="rapid_feed"/>
|
||||
<field name="feed_rate"/>
|
||||
<field name="x_mach_coord"/>
|
||||
<field name="y_mach_coord"/>
|
||||
<field name="z_mach_coord"/>
|
||||
<field name="x_rel_coord"/>
|
||||
<field name="y_rel_coord"/>
|
||||
<field name="z_rel_coord"/>
|
||||
<field name="x_dis_coord"/>
|
||||
<field name="y_dis_coord"/>
|
||||
<field name="z_dis_coord"/>
|
||||
</group>
|
||||
<group string="数采相关">
|
||||
<group>
|
||||
<field name="machine_ip"/>
|
||||
<field name="machine_signed"/>
|
||||
<field name="machine_status"/>
|
||||
<field name="machine_cnc_type"/>
|
||||
<field name="machine_axis_count"/>
|
||||
<field name="machine_run_status"/>
|
||||
<field name="machine_emg_status"/>
|
||||
<field name="machine_cut_status"/>
|
||||
<field name="machine_mode"/>
|
||||
<field name="machine_spindle_load"/>
|
||||
<field name="machine_x_mach"/>
|
||||
<field name="machine_x_abs_mach"/>
|
||||
<field name="machine_x_rel_mach"/>
|
||||
<field name="machine_x_dis_mach"/>
|
||||
<field name="machine_x_axis_load"/>
|
||||
<field name="machine_y_mach"/>
|
||||
<field name="machine_y_abs_mach"/>
|
||||
<field name="machine_y_rel_mach"/>
|
||||
<field name="machine_y_dis_mach"/>
|
||||
<field name="machine_y_axis_load"/>
|
||||
<field name="machine_z_mach"/>
|
||||
<field name="machine_z_abs_mach"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="machine_z_rel_mach"/>
|
||||
<field name="machine_z_dis_mach"/>
|
||||
<field name="machine_z_axis_load"/>
|
||||
<field name="machine_tool_num"/>
|
||||
<field name="machine_program"/>
|
||||
<field name="machine_current_prg"/>
|
||||
<field name="machine_prg_seq"/>
|
||||
<field name="machine_spindle_speed_set"/>
|
||||
<field name="machine_act_spindle_speed"/>
|
||||
<field name="machine_feed_speed_set"/>
|
||||
<field name="machine_act_feed_speed"/>
|
||||
<field name="machine_spindle_feed"/>
|
||||
<field name="machine_feed_rate"/>
|
||||
<field name="machine_rapid_feed"/>
|
||||
<field name="machine_run_time"/>
|
||||
<field name="machine_cut_time"/>
|
||||
<field name="machine_keep_alive_time"/>
|
||||
<field name="machine_circle_time"/>
|
||||
<field name="machine_product_counts"/>
|
||||
<field name="machine_system_date"/>
|
||||
<field name="machine_system_time"/>
|
||||
<field name="machine_alarm_msg"/>
|
||||
</group>
|
||||
</group>
|
||||
<!-- </group> -->
|
||||
</page>
|
||||
<!-- <page string="刀位配置"> -->
|
||||
<!-- <group string="刀位配置"> -->
|
||||
</group>
|
||||
<!-- <group string="ftp相关"> -->
|
||||
<!-- <group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="tool_num1"/> -->
|
||||
<!-- <field name="tool_num5"/> -->
|
||||
<!-- <field name="tool_num9"/> -->
|
||||
<!-- <field name="tool_num13"/> -->
|
||||
<!-- <field name="tool_num17"/> -->
|
||||
<!-- <field name="tool_num21"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="tool_num2"/> -->
|
||||
<!-- <field name="tool_num6"/> -->
|
||||
<!-- <field name="tool_num10"/> -->
|
||||
<!-- <field name="tool_num14"/> -->
|
||||
<!-- <field name="tool_num18"/> -->
|
||||
<!-- <field name="tool_num22"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <field name="ftp_num"/> -->
|
||||
<!-- <field name="ftp_pwd"/> -->
|
||||
<!-- <field name="ftp_host"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="tool_num3"/> -->
|
||||
<!-- <field name="tool_num7"/> -->
|
||||
<!-- <field name="tool_num11"/> -->
|
||||
<!-- <field name="tool_num15"/> -->
|
||||
<!-- <field name="tool_num19"/> -->
|
||||
<!-- <field name="tool_num23"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="tool_num4"/> -->
|
||||
<!-- <field name="tool_num8"/> -->
|
||||
<!-- <field name="tool_num12"/> -->
|
||||
<!-- <field name="tool_num16"/> -->
|
||||
<!-- <field name="tool_num20"/> -->
|
||||
<!-- <field name="tool_num24"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <field name="ftp_port"/> -->
|
||||
<!-- <field name="ftp_remote_path"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- </group> -->
|
||||
<!-- </page> -->
|
||||
<!-- </notebook> -->
|
||||
<!-- <group string="补偿值相关"> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="x_compensation_node"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="y_compensation_node"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group string="数采相关"> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="machine_ip"/> -->
|
||||
<!-- <field name="machine_signed"/> -->
|
||||
<!-- <field name="machine_status"/> -->
|
||||
<!-- <field name="machine_cnc_type"/> -->
|
||||
<!-- <field name="machine_axis_count"/> -->
|
||||
<!-- <field name="machine_run_status"/> -->
|
||||
<!-- <field name="machine_emg_status"/> -->
|
||||
<!-- <field name="machine_cut_status"/> -->
|
||||
<!-- <field name="machine_mode"/> -->
|
||||
<!-- <field name="machine_spindle_load"/> -->
|
||||
<!-- <field name="machine_x_mach"/> -->
|
||||
<!-- <field name="machine_x_abs_mach"/> -->
|
||||
<!-- <field name="machine_x_rel_mach"/> -->
|
||||
<!-- <field name="machine_x_dis_mach"/> -->
|
||||
<!-- <field name="machine_x_axis_load"/> -->
|
||||
<!-- <field name="machine_y_mach"/> -->
|
||||
<!-- <field name="machine_y_abs_mach"/> -->
|
||||
<!-- <field name="machine_y_rel_mach"/> -->
|
||||
<!-- <field name="machine_y_dis_mach"/> -->
|
||||
<!-- <field name="machine_y_axis_load"/> -->
|
||||
<!-- <field name="machine_z_mach"/> -->
|
||||
<!-- <field name="machine_z_abs_mach"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="machine_z_rel_mach"/> -->
|
||||
<!-- <field name="machine_z_dis_mach"/> -->
|
||||
<!-- <field name="machine_z_axis_load"/> -->
|
||||
<!-- <field name="machine_tool_num"/> -->
|
||||
<!-- <field name="machine_program"/> -->
|
||||
<!-- <field name="machine_current_prg"/> -->
|
||||
<!-- <field name="machine_prg_seq"/> -->
|
||||
<!-- <field name="machine_spindle_speed_set"/> -->
|
||||
<!-- <field name="machine_act_spindle_speed"/> -->
|
||||
<!-- <field name="machine_feed_speed_set"/> -->
|
||||
<!-- <field name="machine_act_feed_speed"/> -->
|
||||
<!-- <field name="machine_spindle_feed"/> -->
|
||||
<!-- <field name="machine_feed_rate"/> -->
|
||||
<!-- <field name="machine_rapid_feed"/> -->
|
||||
<!-- <field name="machine_run_time"/> -->
|
||||
<!-- <field name="machine_cut_time"/> -->
|
||||
<!-- <field name="machine_keep_alive_time"/> -->
|
||||
<!-- <field name="machine_circle_time"/> -->
|
||||
<!-- <field name="machine_product_counts"/> -->
|
||||
<!-- <field name="machine_system_date"/> -->
|
||||
<!-- <field name="machine_system_time"/> -->
|
||||
<!-- <field name="machine_alarm_msg"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- </group> -->
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 刀具寿命 -->
|
||||
<!-- <record id="view_cutting_tool_inherited" model="ir.ui.view"> -->
|
||||
<!-- <field name="name">sf_cutting_tool_extension</field> -->
|
||||
<!-- <field name="model">sf.cutting_tool.type</field> -->
|
||||
<!-- <field name="inherit_id" ref="sf_base.form_sf_machine_tool_type"/> -->
|
||||
<!-- <field name="arch" type="xml"> -->
|
||||
<!-- <xpath expr="//form//group" position="after"> -->
|
||||
<!-- <group string='刀具寿命'> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="total_cut_time"/> -->
|
||||
<!-- <field name="tool_position"/> -->
|
||||
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="predict_life_time"/> -->
|
||||
|
||||
<!-- </group> -->
|
||||
|
||||
<!-- <div> -->
|
||||
|
||||
<!-- <div> -->
|
||||
<!-- <field name='is_connect_tool_position' invisible='1'/> -->
|
||||
<!-- <button string="绑定刀位" name="tool_connect_machine" type="object" confirm="是否确认绑定此刀位" -->
|
||||
<!-- class="btn-primary"/> -->
|
||||
<!-- attrs='{"invisible": [("is_connect_tool_position","!=", -->
|
||||
<!-- "False")]}' -->
|
||||
<!-- <span> </span> -->
|
||||
<!-- <button string="解绑刀位" name="tool_unconnect_machine" type="object" confirm="是否解绑此刀位" -->
|
||||
<!-- class="btn-primary"/> -->
|
||||
<!-- attrs='{"invisible": [("is_connect_tool_position","!=", -->
|
||||
<!-- "False")]}' -->
|
||||
|
||||
<!-- </div> -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- </div> -->
|
||||
<!-- </group> -->
|
||||
<!-- </xpath> -->
|
||||
<!-- </field> -->
|
||||
<!-- </record> -->
|
||||
</odoo>
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<div class="o_setting_left_pane"/>
|
||||
<div class="o_setting_right_pane">
|
||||
<div class="text-muted">
|
||||
<label for="bfm_url" />
|
||||
<field name="bfm_url" string="访问地址"/>
|
||||
<label for="bfm_url_new" />
|
||||
<field name="bfm_url_new" string="业务平台访问地址"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<!-- <field name="program_ids" domain="[('workorder_id', '=', workorder_id)]"/>-->
|
||||
</group>
|
||||
<footer>
|
||||
<button string="合并下发" name="confirm_up" type="object" class="btn-primary" confirm="是否确认合并下发"/>
|
||||
<!-- <button string="合并下发" name="confirm_up" type="object" class="btn-primary" confirm="是否确认合并下发"/>-->
|
||||
<button string="取消" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
@@ -10,21 +10,21 @@ class SfMaintenanceLogs(models.Model):
|
||||
name = fields.Char(string='名称')
|
||||
type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型')
|
||||
brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌')
|
||||
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='设备')
|
||||
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='机台号')
|
||||
maintenance_equipment_oee_id = fields.Many2one('maintenance.equipment.oee', string='设备oee')
|
||||
code_location = fields.Char(string='编码位置')
|
||||
fault_type = fields.Selection(
|
||||
[('电气类', '电气类'), ('机械类', '机械类'), ('程序类', '程序类'), ('系统类', '系统类')], string='故障类型')
|
||||
fault_code = fields.Char(string='故障代码')
|
||||
fault_alarm_info = fields.Char(string='故障报警信息')
|
||||
fault_alarm_info = fields.Text(string='故障报警信息')
|
||||
alarm_level = fields.Selection([('一级', '一级(严重)'), ('二级', '二级(中等)'), ('三级', '三级(轻微)')],
|
||||
string='报警级别')
|
||||
alarm_time = fields.Datetime(string='报警时间')
|
||||
alarm_time = fields.Datetime(string='故障报警时间')
|
||||
alarm_way = fields.Selection([('文本提示报警', '文本提示报警'), ('声光报警', '声光报警'), ('图文报警', '图文报警')],
|
||||
string='报警方式')
|
||||
fault_process = fields.Text(string='故障处理方法')
|
||||
operator = fields.Many2one('res.users', string='处理人')
|
||||
recovery_time = fields.Datetime(string='复原时间')
|
||||
recovery_time = fields.Datetime(string='故障消除时间')
|
||||
fault_duration = fields.Float(string='故障时长')
|
||||
note = fields.Text(string='备注')
|
||||
active = fields.Boolean('Active', default=True)
|
||||
|
||||
@@ -7,20 +7,23 @@ class SfMaintenanceEquipmentOEE(models.Model):
|
||||
_description = '设备OEE'
|
||||
|
||||
name = fields.Char('设备oee')
|
||||
equipment_id = fields.Many2one('maintenance.equipment', '设备',
|
||||
equipment_id = fields.Many2one('maintenance.equipment', '机台号',
|
||||
domain="[('category_id.equipment_type', '=', '机床'),('state_zc', '=', '已注册')]")
|
||||
type_id = fields.Many2one('sf.machine_tool.type', '型号', related='equipment_id.type_id')
|
||||
machine_tool_picture = fields.Binary('设备图片', related='equipment_id.machine_tool_picture')
|
||||
machine_tool_picture = fields.Binary('设备图片', related='equipment_id.machine_tool_picture')
|
||||
state = fields.Selection(
|
||||
[("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"),
|
||||
("封存(报废)", "封存(报废)")],
|
||||
default='正常', string="机床状态", related='equipment_id.state')
|
||||
run_time = fields.Float('正常运行总时长(h)')
|
||||
equipment_time = fields.Float('总时长(h)')
|
||||
done_nums = fields.Integer('累计加工总件数')
|
||||
utilization_rate = fields.Char('开动率')
|
||||
fault_time = fields.Float('故障停机总时长(h)')
|
||||
run_time = fields.Float('加工时长(h)')
|
||||
equipment_time = fields.Float('开机时长(h)')
|
||||
done_nums = fields.Integer('加工件数')
|
||||
utilization_rate = fields.Char('可用率')
|
||||
fault_time = fields.Float('故障时长')
|
||||
fault_nums = fields.Integer('故障次数')
|
||||
# 故障率
|
||||
fault_rate = fields.Char('故障率')
|
||||
# 设备故障日志
|
||||
sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志',
|
||||
related='equipment_id.sf_maintenance_logs_ids')
|
||||
oee_logs = fields.One2many('maintenance.equipment.oee.logs', 'equipment_oee_id', string='运行日志')
|
||||
@@ -38,12 +41,52 @@ class SfMaintenanceEquipmentOEELog(models.Model):
|
||||
_name = 'maintenance.equipment.oee.logs'
|
||||
_description = '设备运行日志'
|
||||
|
||||
name = fields.Char('运行日志')
|
||||
run_time = fields.Datetime('时间')
|
||||
state = fields.Selection([("开机", "开机"), ("关机", "关机"), ("等待", "等待"), ("开始加工", "开始加工"),
|
||||
("结束加工", "结束加工"), ("故障", "故障"),
|
||||
("检修", "检修"), ("保养", "保养")], default="", string="事件/状态")
|
||||
workorder_id = fields.Char('加工订单')
|
||||
time = fields.Char('持续时长')
|
||||
color = fields.Char('颜色', default=1)
|
||||
equipment_id = fields.Many2one('maintenance.equipment', '机台号')
|
||||
equipment_code = fields.Char('设备编码')
|
||||
name = fields.Char('设备名称', readonly='True')
|
||||
machine_tool_picture = fields.Binary('设备图片')
|
||||
type_id = fields.Many2one('sf.machine_tool.type', '品牌型号')
|
||||
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
|
||||
("检修", "检修"), ("保养", "保养")], default="", string="实时状态")
|
||||
online_time = fields.Char('开机时长')
|
||||
|
||||
offline_time = fields.Char('关机时长')
|
||||
offline_nums = fields.Integer('关机次数')
|
||||
# 待机时长
|
||||
|
||||
idle_time = fields.Char('待机时长')
|
||||
|
||||
# 待机率
|
||||
idle_rate = fields.Char('待机率')
|
||||
|
||||
work_time = fields.Char('加工时长')
|
||||
work_rate = fields.Char('可用率')
|
||||
fault_time = fields.Char('故障时长')
|
||||
fault_rate = fields.Char('故障率')
|
||||
fault_nums = fields.Integer('故障次数')
|
||||
|
||||
detail_ids = fields.One2many('maintenance.equipment.oee.log.detail', 'log_id', string='日志详情')
|
||||
|
||||
# maintenance_time = fields.Char('维保时长')
|
||||
# work_nums = fields.Integer('加工件数')
|
||||
equipment_oee_id = fields.Many2one('maintenance.equipment.oee', '设备OEE')
|
||||
|
||||
@api.onchange('equipment_id')
|
||||
def get_name(self):
|
||||
self.name = self.equipment_id.name
|
||||
self.equipment_code = self.equipment_id.code
|
||||
|
||||
|
||||
# 设备运行日志详情
|
||||
class SfMaintenanceEquipmentOEELogDetail(models.Model):
|
||||
_name = 'maintenance.equipment.oee.log.detail'
|
||||
_description = '设备运行日志详情'
|
||||
|
||||
sequence = fields.Integer('序号')
|
||||
time = fields.Datetime('时间')
|
||||
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
|
||||
("检修", "检修"), ("保养", "保养")], default="", string="事件/状态")
|
||||
production_id = fields.Many2one('mrp.production', '加工工单')
|
||||
|
||||
log_id = fields.Many2one('maintenance.equipment.oee.logs', '日志')
|
||||
|
||||
|
||||
@@ -67,3 +67,6 @@ access_sf_cutting_tool_type_admin_sf_group_equipment_user,sf_cutting_tool_type_a
|
||||
access_sf_cutting_tool_type_group_purchase_director_sf_group_equipment_user,sf_cutting_tool_type_group_purchase_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
|
||||
access_sf_cutting_tool_type_group_sale_director_sf_group_equipment_user,sf_cutting_tool_type_group_sale_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
|
||||
access_sf_cutting_tool_type_group_plan_director_sf_group_equipment_user,sf_cutting_tool_type_group_plan_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
|
||||
|
||||
access_maintenance_equipment_oee_logs,maintenance_equipment_oee_logs,model_maintenance_equipment_oee_logs,sf_maintenance.sf_group_equipment_manager,1,1,1,1
|
||||
access_maintenance_equipment_oee_log_detail,maintenance_equipment_oee_log_detail,model_maintenance_equipment_oee_log_detail,sf_maintenance.sf_group_equipment_manager,1,1,1,1
|
||||
|
@@ -14,6 +14,7 @@
|
||||
<field name="utilization_rate"/>
|
||||
<field name="fault_time"/>
|
||||
<field name="fault_nums"/>
|
||||
<field name="fault_rate"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -49,19 +50,19 @@
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="运行日志">
|
||||
<field name="oee_logs">
|
||||
<tree create="1" edit="1" delete="1" editable="bottom">
|
||||
<field name = 'run_time'/>
|
||||
<field name = 'state'/>
|
||||
<field name = 'workorder_id'/>
|
||||
<field name = 'time'/>
|
||||
<field name = 'color' widget="color"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
<!-- <notebook> -->
|
||||
<!-- <page string="运行日志"> -->
|
||||
<!-- <field name="oee_logs"> -->
|
||||
<!-- <tree create="1" edit="1" delete="1" editable="bottom"> -->
|
||||
<!-- <field name = 'run_time'/> -->
|
||||
<!-- <field name = 'state'/> -->
|
||||
<!-- <field name = 'workorder_id'/> -->
|
||||
<!-- <field name = 'time'/> -->
|
||||
<!-- <field name = 'color' widget="color"/> -->
|
||||
<!-- </tree> -->
|
||||
<!-- </field> -->
|
||||
<!-- </page> -->
|
||||
<!-- </notebook> -->
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
@@ -7,22 +7,20 @@
|
||||
<field name="model">sf.maintenance.logs</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="code"/>
|
||||
<field name="type" optional="hide"/>
|
||||
<field name="brand"/>
|
||||
<field name="maintenance_equipment_id"/>
|
||||
<field name="code_location" optional="hide"/>
|
||||
<field name="fault_type"/>
|
||||
<field name="fault_code" optional="hide"/>
|
||||
<field name="alarm_time"/>
|
||||
<field name="fault_alarm_info"/>
|
||||
<field name="alarm_level" optional="hide"/>
|
||||
<field name="alarm_time"/>
|
||||
<field name="alarm_way" optional="hide"/>
|
||||
<field name="fault_process"/>
|
||||
<field name="operator"/>
|
||||
<field name="fault_process" optional="hide"/>
|
||||
<field name="operator" optional="hide"/>
|
||||
<field name="recovery_time"/>
|
||||
<field name="fault_duration"/>
|
||||
<field name="note"/>
|
||||
<field name="note" optional="hide"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -45,25 +43,32 @@
|
||||
<group>
|
||||
<group>
|
||||
|
||||
<field name="name"/>
|
||||
<field name="type" required="1" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="brand"/>
|
||||
<!-- <field name="name"/> -->
|
||||
<!-- <field name="type" required="1" widget="radio" options="{'horizontal': true}"/> -->
|
||||
<field name="maintenance_equipment_id"/>
|
||||
<field name="code_location"/>
|
||||
<field name="fault_type" required="1" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="fault_code"/>
|
||||
<field name="fault_process"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="fault_alarm_info"/>
|
||||
<field name="brand"/>
|
||||
<field name="alarm_time"/>
|
||||
<field name="alarm_way" required="1" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="operator"/>
|
||||
<field name="recovery_time"/>
|
||||
<field name="fault_duration"/>
|
||||
<field name="note"/>
|
||||
<field name="fault_alarm_info"/>
|
||||
|
||||
<!-- <field name="code_location"/> -->
|
||||
<!-- <field name="fault_type" required="1" widget="radio" options="{'horizontal': true}"/> -->
|
||||
<!-- <field name="fault_code"/> -->
|
||||
|
||||
</group>
|
||||
<group>
|
||||
<field name="operator"/>
|
||||
|
||||
<field name="fault_process"/>
|
||||
<!-- <field name="alarm_way" required="1" widget="radio" options="{'horizontal': true}"/> -->
|
||||
<field name="recovery_time"/>
|
||||
<field name="fault_duration"/>
|
||||
|
||||
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<group>
|
||||
<field name="note"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
@@ -100,6 +105,246 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 设备运行日志 -->
|
||||
<record id="view_maintenance_logs_run_tree" model="ir.ui.view">
|
||||
<field name="name">maintenance.logs.run.tree</field>
|
||||
<field name="model">maintenance.equipment.oee.logs</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="equipment_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_maintenance_logs_run_form" model="ir.ui.view">
|
||||
<field name="name">maintenance.logs.run.form</field>
|
||||
<field name="model">maintenance.equipment.oee.logs</field>
|
||||
<field name="arch" type="xml">
|
||||
<!-- <form string="设备运行日志"> -->
|
||||
<!-- <header> -->
|
||||
<!-- <field name="equipment_id" readonly="1"/> -->
|
||||
<!-- </header> -->
|
||||
<!-- <sheet> -->
|
||||
<!-- <div class="oe_title"> -->
|
||||
<!-- <h1> -->
|
||||
<!-- <field name="start_time" readonly="1"/> -->
|
||||
<!-- </h1> -->
|
||||
<!-- </div> -->
|
||||
<!-- <group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="stop_time" readonly="1"/> -->
|
||||
<!-- <field name="duration" readonly="1"/> -->
|
||||
<!-- <field name="oee" readonly="1"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="note"/> -->
|
||||
<!-- </group> -->
|
||||
|
||||
<!-- </group> -->
|
||||
<!-- </sheet> -->
|
||||
<!-- </form> -->
|
||||
<form string="设备运行日志">
|
||||
<!-- <header> -->
|
||||
<!-- <field name="name" readonly="1"/> -->
|
||||
<!-- </header> -->
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
|
||||
<field name="type_id"/>
|
||||
<field name="state"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<!-- <field name="state" nolabel="1"/> -->
|
||||
<field name="state" string=""/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="machine_tool_picture" widget="image" nolabel="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="online_time" readonly="1"/>
|
||||
<field name="offline_time" readonly="1"/>
|
||||
<field name="fault_rate" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="offline_nums" readonly="1"/>
|
||||
<field name="fault_time" readonly="1"/>
|
||||
<field name="fault_nums" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="idle_time"/>
|
||||
<field name="idle_rate"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="work_time"/>
|
||||
<field name="work_rate"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="24H日志详情">
|
||||
<!-- 筛选出24小时内的日志 -->
|
||||
<!-- <field name="detail_ids" domain="[('time','<',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> -->
|
||||
<field name="detail_ids" domain="[('state','ilike','加工')]">
|
||||
<tree>
|
||||
<field name="sequence"/>
|
||||
<field name="time"/>
|
||||
<field name="state"/>
|
||||
<field name="production_id"/>
|
||||
</tree>
|
||||
<!-- <form> -->
|
||||
<!-- <field name="sequence"/> -->
|
||||
<!-- <field name="time"/> -->
|
||||
<!-- <field name="state"/> -->
|
||||
<!-- <field name="production_id"/> -->
|
||||
<!-- </form> -->
|
||||
|
||||
</field>
|
||||
</page>
|
||||
<page string="历史日志详情">
|
||||
<field name="detail_ids">
|
||||
<tree>
|
||||
<field name="sequence"/>
|
||||
<field name="time"/>
|
||||
<field name="state"/>
|
||||
<field name="production_id"/>
|
||||
</tree>
|
||||
<!-- <form> -->
|
||||
<!-- <field name="sequence"/> -->
|
||||
<!-- <field name="time"/> -->
|
||||
<!-- <field name="state"/> -->
|
||||
<!-- <field name="production_id"/> -->
|
||||
<!-- </form> -->
|
||||
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- <record id="view_maintenance_logs_run_search" model="ir.ui.view"> -->
|
||||
<!-- <field name="name">maintenance.logs.run.search</field> -->
|
||||
<!-- <field name="model">maintenance.equipment.oee.logs</field> -->
|
||||
<!-- <field name="arch" type="xml"> -->
|
||||
<!-- <search> -->
|
||||
<!-- <field name="equipment_id"/> -->
|
||||
<!-- <field name="start_time"/> -->
|
||||
<!-- <field name="stop_time"/> -->
|
||||
<!-- <field name="duration"/> -->
|
||||
<!-- <field name="oee"/> -->
|
||||
<!-- <field name="note"/> -->
|
||||
<!-- </search> -->
|
||||
|
||||
<!-- </field> -->
|
||||
<!-- </record> -->
|
||||
|
||||
<!-- 设备运行日志详情 -->
|
||||
<record id="view_maintenance_logs_run_detail_tree" model="ir.ui.view">
|
||||
<field name="name">maintenance.logs.run.detail.tree</field>
|
||||
<field name="model">maintenance.equipment.oee.log.detail</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="sequence"/>
|
||||
<field name="time"/>
|
||||
<field name="state"/>
|
||||
<field name="production_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_maintenance_logs_run_detail_form" model="ir.ui.view">
|
||||
<field name="name">maintenance.logs.run.detail.form</field>
|
||||
<field name="model">maintenance.equipment.oee.log.detail</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="设备运行日志详情">
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="state"/>
|
||||
<field name="production_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="sequence"/>
|
||||
<field name="time"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- <record id="view_maintenance_logs_run_detail_search" model="ir.ui.view"> -->
|
||||
<!-- <field name="name">maintenance.logs.run.detail.search</field> -->
|
||||
<!-- <field name="model">maintenance.equipment.oee.logs.detail</field> -->
|
||||
<!-- <field name="arch" type="xml"> -->
|
||||
<!-- <search> -->
|
||||
<!-- <field name="equipment_id"/> -->
|
||||
<!-- <field name="start_time"/> -->
|
||||
<!-- <field name="stop_time"/> -->
|
||||
<!-- <field name="duration"/> -->
|
||||
<!-- <field name="oee"/> -->
|
||||
<!-- <field name="note"/> -->
|
||||
<!-- </search> -->
|
||||
<!-- </field> -->
|
||||
<!-- </record> -->
|
||||
|
||||
<!-- 设备运行日志详情action -->
|
||||
<!-- <record id="action_maintenance_logs_run_detail" model="ir.actions.act_window"> -->
|
||||
<!-- <field name="name">设备运行日志详情</field> -->
|
||||
<!-- <field name="type">ir.actions.act_window</field> -->
|
||||
<!-- <field name="res_model">maintenance.equipment.oee.logs.detail</field> -->
|
||||
<!-- <field name="view_mode">tree,form</field> -->
|
||||
<!-- <field name="view_id" ref="view_maintenance_logs_run_detail_tree"/> -->
|
||||
<!-- <field name="help" type="html"> -->
|
||||
<!-- <p class="oe_view_nocontent_create"> -->
|
||||
<!-- 设备运行日志详情 -->
|
||||
<!-- </p> -->
|
||||
<!-- </field> -->
|
||||
<!-- -->
|
||||
<!-- </record> -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<record id="action_maintenance_logs_run" model="ir.actions.act_window">
|
||||
<field name="name">设备运行日志</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">maintenance.equipment.oee.logs</field>
|
||||
<!-- <field name="search_view_id" ref="view_maintenance_logs_run_search"/> -->
|
||||
<field name="view_mode">tree,form</field>
|
||||
<!-- <field name="view_mode">form</field> -->
|
||||
<field name="view_id" ref="view_maintenance_logs_run_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
设备运行日志
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem name="设备运行日志" id="menu_maintenance_logs_run" parent="maintenance.menu_m_request"
|
||||
sequence="10" action="action_maintenance_logs_run"/>
|
||||
|
||||
|
||||
<!-- Action -->
|
||||
|
||||
|
||||
@@ -14,9 +14,12 @@
|
||||
'data': [
|
||||
'data/stock_data.xml',
|
||||
'data/empty_racks_data.xml',
|
||||
'data/panel_data.xml',
|
||||
'security/group_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/workpiece_delivery_views.xml',
|
||||
'wizard/rework_wizard_views.xml',
|
||||
'wizard/production_wizard_views.xml',
|
||||
'views/mrp_views_menus.xml',
|
||||
'views/stock_lot_views.xml',
|
||||
'views/mrp_production_addional_change.xml',
|
||||
|
||||
@@ -25,7 +25,8 @@ class Manufacturing_Connect(http.Controller):
|
||||
{'content': ret, 'name': 'AutoDeviceApi/GetWoInfo'})
|
||||
logging.info('RfidCode:%s' % ret['RfidCode'])
|
||||
if 'RfidCode' in ret:
|
||||
workorder = request.env['mrp.workorder'].sudo().search([('rfid_code', '=', ret['RfidCode'])])
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('rfid_code', '=', ret['RfidCode']), ('state', '!=', 'rework')])
|
||||
if workorder:
|
||||
for item in workorder:
|
||||
res['Datas'].append({
|
||||
@@ -122,7 +123,8 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('RfidCode:%s' % ret['RfidCode'])
|
||||
if 'RfidCode' in ret:
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('routing_type', '=', '装夹预调'), ('rfid_code', '=', ret['RfidCode'])], limit=1, order='id asc')
|
||||
[('routing_type', '=', '装夹预调'), ('rfid_code', '=', ret['RfidCode']), ('state', '!=', 'rework')],
|
||||
limit=1, order='id asc')
|
||||
if workorder:
|
||||
for item in workorder:
|
||||
if item.material_center_point:
|
||||
@@ -162,7 +164,8 @@ class Manufacturing_Connect(http.Controller):
|
||||
routing_type = ret['CraftId']
|
||||
equipment_id = ret["DeviceId"]
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
|
||||
[('production_id', '=', production_id), ('routing_type', '=', routing_type),
|
||||
('rfid_code', '!=', False), ('state', '!=', 'rework')], limit=1)
|
||||
if not workorder:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单不存在'}
|
||||
return json.JSONEncoder().encode(res)
|
||||
@@ -203,12 +206,14 @@ class Manufacturing_Connect(http.Controller):
|
||||
res = {'Succeed': True, 'Datas': ['工单已结束']}
|
||||
datas = request.httprequest.data
|
||||
ret = json.loads(datas)
|
||||
logging.info('button_Work_End:%s' % ret)
|
||||
request.env['center_control.interface.log'].sudo().create(
|
||||
{'content': ret, 'name': 'AutoDeviceApi/FeedBackEnd'})
|
||||
production_id = ret['BillId']
|
||||
routing_type = ret['CraftId']
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
|
||||
[('production_id', '=', production_id), ('routing_type', '=', routing_type),
|
||||
('rfid_code', '!=', False), ('state', '!=', 'rework')], limit=1)
|
||||
if not workorder:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单不存在'}
|
||||
return json.JSONEncoder().encode(res)
|
||||
@@ -217,21 +222,22 @@ class Manufacturing_Connect(http.Controller):
|
||||
return json.JSONEncoder().encode(res)
|
||||
# workorder.write({'date_finished': datetime.now()})
|
||||
if ret['IsComplete'] is True:
|
||||
workorder.button_finish()
|
||||
# workorder.process_state = '待解除装夹'
|
||||
# workorder.sudo().production_id.process_state = '待解除装夹'
|
||||
workorder.write({'date_finished': datetime.now()})
|
||||
|
||||
# 根据工单的实际结束时间修改排程单的结束时间、状态,同时修改销售订单的状态
|
||||
if workorder.date_finished:
|
||||
request.env['sf.production.plan'].sudo().search([('production_id', '=', production_id)]).write(
|
||||
{'actual_end_time': workorder.date_finished,
|
||||
'state': 'finished'})
|
||||
production_obj = request.env['mrp.production'].sudo().search([('name', '=', production_id)])
|
||||
if production_obj:
|
||||
production_obj.sudo().work_order_state = '已完成'
|
||||
production_obj.write({'state': 'completed'})
|
||||
# request.env['sale.order'].sudo().search(
|
||||
# [('name', '=', production_obj.origin)]).write({'schedule_status': 'to deliver'})
|
||||
# workorder.process_state = '待解除装夹'
|
||||
# workorder.sudo().production_id.process_state = '待解除装夹'
|
||||
|
||||
# 根据工单的实际结束时间修改排程单的结束时间、状态,同时修改销售订单的状态
|
||||
# if workorder.date_finished:
|
||||
# request.env['sf.production.plan'].sudo().search([('production_id', '=', production_id)]).write(
|
||||
# {'actual_end_time': workorder.date_finished,
|
||||
# 'state': 'finished'})
|
||||
# production_obj = request.env['mrp.production'].sudo().search([('name', '=', production_id)])
|
||||
# if production_obj:
|
||||
# production_obj.sudo().work_order_state = '已完成'
|
||||
# production_obj.write({'state': 'done'})
|
||||
# request.env['sale.order'].sudo().search(
|
||||
# [('name', '=', production_obj.origin)]).write({'schedule_status': 'to deliver'})
|
||||
|
||||
except Exception as e:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
||||
@@ -254,39 +260,27 @@ class Manufacturing_Connect(http.Controller):
|
||||
request.env['center_control.interface.log'].sudo().create(
|
||||
{'content': ret, 'name': 'AutoDeviceApi/PartQualityInspect'})
|
||||
production_id = ret['BillId']
|
||||
routing_type = ret['CraftId']
|
||||
# routing_type = ret['CraftId']
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
|
||||
[('production_id', '=', production_id), ('routing_type', '=', 'CNC加工'),
|
||||
('state', 'not in', ['rework', 'done', 'cancel'])], order='sequence asc',
|
||||
limit=1)
|
||||
if workorder:
|
||||
# workorder.test_results = ret['Quality']
|
||||
logging.info('制造订单:%s' % workorder.production_id.name)
|
||||
if 'ReportPaht' in ret:
|
||||
download_state = request.env['mrp.workorder'].with_user(
|
||||
request.env.ref("base.user_admin")).download_reportfile_tmp(workorder,
|
||||
ret['ReportPaht'])
|
||||
if download_state == 1:
|
||||
detection_ret = request.env['mrp.workorder'].with_user(
|
||||
request.env.ref("base.user_admin")).get_detection_file(workorder, ret['ReportPaht'])
|
||||
if detection_ret is True:
|
||||
stock_picking_type = request.env['stock.picking.type'].sudo().search(
|
||||
[('sequence_code', '=', 'SFP')])
|
||||
if stock_picking_type:
|
||||
stock_picking = request.env['stock.picking'].sudo().search(
|
||||
[('product_id', '=', workorder.product_id.id),
|
||||
('origin', '=', workorder.production_id.origin),
|
||||
('picking_type_id', '=', stock_picking_type.id)])
|
||||
if stock_picking:
|
||||
quality_check = request.env['quality.check'].sudo().search(
|
||||
[('product_id', '=', workorder.product_id.id),
|
||||
('picking_id', '=', stock_picking.id)])
|
||||
if quality_check:
|
||||
logging.info('质检单:%s' % quality_check.name)
|
||||
quality_check.write({'report_pdf': workorder.detection_report})
|
||||
elif download_state == 2:
|
||||
res = {'Succeed': False, 'ErrorCode': 205,
|
||||
'Error': 'ReportPaht中的工件号与制造订单%s不匹配,请检查ReportPaht是否正确' % workorder.production_id.name}
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 204, 'Error': '检测报告文件从FTP拉取失败'}
|
||||
if ret['ReportPaht'].find('.pdf') != -1:
|
||||
download_state = request.env['mrp.workorder'].with_user(
|
||||
request.env.ref("base.user_admin")).download_reportfile_tmp(workorder,
|
||||
ret['ReportPaht'])
|
||||
if download_state is True:
|
||||
detection_ret = request.env['mrp.workorder'].with_user(
|
||||
request.env.ref("base.user_admin")).get_detection_file(workorder, ret['ReportPaht'])
|
||||
logging.info('detection_ret:%s' % detection_ret)
|
||||
if detection_ret is False:
|
||||
res = {'Succeed': False, 'ErrorCode': 205, 'Error': '检测报告文件读取失败'}
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 204, 'Error': '检测报告文件从FTP拉取失败'}
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传ReportPaht字段'}
|
||||
else:
|
||||
@@ -314,18 +308,18 @@ class Manufacturing_Connect(http.Controller):
|
||||
if 'RfidCode' in ret:
|
||||
logging.info('RfidCode:%s' % ret['RfidCode'])
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', 'CNC加工')])
|
||||
[('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', 'CNC加工'), ('state', '!=', 'rework')])
|
||||
if workorder:
|
||||
for item in workorder.cmm_ids:
|
||||
if item.program_date is not False:
|
||||
program_date = item.program_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
program_date_str = request.env['sf.sync.common'].sudo().get_add_time(program_date)
|
||||
if item.program_create_date is not False:
|
||||
program_create_date = item.program_create_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
program_date_str = request.env['sf.sync.common'].sudo().get_add_time(program_create_date)
|
||||
res['Datas'].append({
|
||||
'CraftId': workorder.id,
|
||||
'CraftKey': workorder.name,
|
||||
'ProgramDate': '' if not item.program_date else program_date_str,
|
||||
'ProgramDate': '' if not item.program_create_date else program_date_str,
|
||||
'ProgramPath': item.program_path,
|
||||
'PostProcessing': item.post_processing_name,
|
||||
'PostProcessing': item.program_name,
|
||||
})
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '暂无工单及对应的CNC程序数据'}
|
||||
@@ -354,7 +348,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
if 'RfidCode' in ret:
|
||||
logging.info('RfidCode:%s' % ret['RfidCode'])
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', 'CNC加工')])
|
||||
[('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', 'CNC加工'), ('state', '!=', 'rework')])
|
||||
if workorder:
|
||||
for item in workorder.cnc_ids:
|
||||
res['Datas'].append({
|
||||
@@ -463,19 +457,25 @@ class Manufacturing_Connect(http.Controller):
|
||||
if rfid_code is not None:
|
||||
domain = [
|
||||
('rfid_code', '=', rfid_code),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
('routing_type', '=', 'CNC加工'), ('state', '!=', 'rework')
|
||||
]
|
||||
workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc')
|
||||
if workorder:
|
||||
for order in workorder:
|
||||
if order.production_id.production_line_state == '待上产线':
|
||||
if order.production_line_state == '待上产线':
|
||||
logging.info(
|
||||
'制造订单产线状态:%s' % order.production_id.production_line_state)
|
||||
order.production_id.write({'production_line_state': '已上产线'})
|
||||
'工单产线状态:%s' % order.production_line_state)
|
||||
panel_workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('rfid_code', '=', rfid_code), ('state', '!=', 'rework'),
|
||||
('processing_panel', '=', order.processing_panel)])
|
||||
if panel_workorder:
|
||||
panel_workorder.write({'production_line_state': '已上产线'})
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[
|
||||
('rfid_code', '=', rfid_code), ('type', '=', '上产线'),
|
||||
('production_id', '=', order.production_id.id)])
|
||||
('production_id', '=', order.production_id.id),
|
||||
('workorder_id', '=', order.id),
|
||||
('workorder_state', '=', 'done')])
|
||||
if workpiece_delivery.status == '待下发':
|
||||
workpiece_delivery.write({'is_manual_work': True})
|
||||
else:
|
||||
@@ -520,20 +520,28 @@ class Manufacturing_Connect(http.Controller):
|
||||
if rfid_code is not None:
|
||||
domain = [
|
||||
('rfid_code', '=', rfid_code),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
('routing_type', '=', 'CNC加工'), ('state', '!=', 'rework')
|
||||
]
|
||||
workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc')
|
||||
if workorder:
|
||||
for order in workorder:
|
||||
if order.production_id.production_line_state == '已上产线':
|
||||
if order.production_line_state == '已上产线':
|
||||
logging.info(
|
||||
'制造订单产线状态:%s' % order.production_id.production_line_state)
|
||||
order.production_id.write({'production_line_state': '已下产线'})
|
||||
'工单产线状态:%s' % order.production_line_state)
|
||||
panel_workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('rfid_code', '=', rfid_code), ('state', '!=', 'rework'),
|
||||
('processing_panel', '=', order.processing_panel)])
|
||||
if panel_workorder:
|
||||
panel_workorder.write({'production_line_state': '已下产线'})
|
||||
workorder.write({'state': 'to be detected'})
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[
|
||||
('rfid_code', '=', rfid_code), ('type', '=', '下产线'),
|
||||
('production_id', '=', order.production_id.id)])
|
||||
delivery_Arr.append(workpiece_delivery.id)
|
||||
('production_id', '=', order.production_id.id),
|
||||
('workorder_id', '=', order.id),
|
||||
('workorder_state', '=', 'done')])
|
||||
if workpiece_delivery:
|
||||
delivery_Arr.append(workpiece_delivery.id)
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 204,
|
||||
'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
|
||||
|
||||
24
sf_manufacturing/data/panel_data.xml
Normal file
24
sf_manufacturing/data/panel_data.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="panel_zm" model="sf.processing.panel">
|
||||
<field name="name">ZM</field>
|
||||
</record>
|
||||
|
||||
<record id="panel_fm" model="sf.processing.panel">
|
||||
<field name="name">FM</field>
|
||||
</record>
|
||||
<record id="panel_yc" model="sf.processing.panel">
|
||||
<field name="name">YC</field>
|
||||
</record>
|
||||
<record id="panel_zc" model="sf.processing.panel">
|
||||
<field name="name">ZC</field>
|
||||
</record>
|
||||
<record id="panel_qc" model="sf.processing.panel">
|
||||
<field name="name">QC</field>
|
||||
</record>
|
||||
<record id="panel_hc" model="sf.processing.panel">
|
||||
<field name="name">HC</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,6 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record model="ir.cron" id="ir_cron_mrp_production">
|
||||
<field name="name">返工且编程中的制造订单定时获取Cloud编程单状态</field>
|
||||
<field name="model_id" ref="model_mrp_production"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._cron_get_programming_state()</field>
|
||||
<field name="interval_number">3</field>
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
</record>
|
||||
|
||||
<record id="sequence_routing_workcenter" model="ir.sequence">
|
||||
<field name="name">工序编码规则</field>
|
||||
<field name="code">mrp.routing.workcenter</field>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import requests
|
||||
from itertools import groupby
|
||||
@@ -24,22 +26,60 @@ class MrpProduction(models.Model):
|
||||
work_order_state = fields.Selection([('未排', '未排'), ('已排', '已排'), ('已完成', '已完成')],
|
||||
string='工单状态', default='未排')
|
||||
|
||||
detection_result_ids = fields.One2many('sf.detection.result', 'production_id', '检测报告')
|
||||
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
|
||||
store=True, compute='_compute_tool_state')
|
||||
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
|
||||
tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True)
|
||||
|
||||
@api.depends('workorder_ids.tool_state_remark')
|
||||
def _compute_tool_state_remark(self):
|
||||
for item in self:
|
||||
if item.workorder_ids:
|
||||
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ['rework', 'done', 'cancel'])
|
||||
if workorder_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
work_ids = workorder_ids.filtered(lambda a: a.tool_state == '1')
|
||||
tool_state_remark = ''
|
||||
for work_id in work_ids:
|
||||
if tool_state_remark == '':
|
||||
tool_state_remark = f'{work_id.tool_state_remark}'
|
||||
else:
|
||||
tool_state_remark = f"{tool_state_remark}\n{work_id.tool_state_remark}"
|
||||
item.tool_state_remark = tool_state_remark
|
||||
else:
|
||||
item.tool_state_remark = False
|
||||
|
||||
@api.depends('workorder_ids.tool_state')
|
||||
def _compute_tool_state(self):
|
||||
for item in self:
|
||||
if item.workorder_ids:
|
||||
tool_state = item.tool_state
|
||||
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ['rework', 'done', 'cancel'])
|
||||
if workorder_ids.filtered(lambda a: a.tool_state == '2'):
|
||||
item.tool_state = '2'
|
||||
elif workorder_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
item.tool_state = '1'
|
||||
else:
|
||||
item.tool_state = '0'
|
||||
if tool_state == '2' and item.tool_state != '2':
|
||||
item.detection_result_ids.filtered(
|
||||
lambda a: a.detailed_reason == '无效功能刀具' and a.handle_result == '待处理').write(
|
||||
{'handle_result': '已处理'})
|
||||
|
||||
# state = fields.Selection(selection_add=[
|
||||
# ('pending_scheduling', '待排程'),
|
||||
# ('pending_processing', '待加工'),
|
||||
# ('completed', '已完工')
|
||||
# ])
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('confirmed', 'Confirmed'),
|
||||
('progress', '待排程'),
|
||||
('pending_cam', '待装夹'),
|
||||
('pending_processing', '待加工'),
|
||||
('pending_era_cam', '待解除装夹'),
|
||||
('completed', '已完工'),
|
||||
('draft', '草稿'),
|
||||
('confirmed', '待排程'),
|
||||
('pending_cam', '待加工'),
|
||||
('progress', '加工中'),
|
||||
('rework', '返工'),
|
||||
('to_close', 'To Close'),
|
||||
('done', 'Done'),
|
||||
('cancel', 'Cancelled')], string='State',
|
||||
('cancel', '报废')], string='State',
|
||||
compute='_compute_state', copy=False, index=True, readonly=True,
|
||||
store=True, tracking=True,
|
||||
help=" * Draft: The MO is not confirmed yet.\n"
|
||||
@@ -53,13 +93,17 @@ class MrpProduction(models.Model):
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
programming_no = fields.Char('编程单号')
|
||||
work_state = fields.Char('业务状态')
|
||||
programming_state = fields.Char('编程状态', tracking=True)
|
||||
programming_state = fields.Selection(
|
||||
[('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'), ('已下发', '已下发')],
|
||||
string='编程状态',
|
||||
tracking=True)
|
||||
glb_file = fields.Binary("glb模型文件")
|
||||
production_line_id = fields.Many2one('sf.production.line', string='生产线', tracking=True)
|
||||
plan_start_processing_time = fields.Datetime('计划开始加工时间')
|
||||
production_line_state = fields.Selection(
|
||||
[('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
|
||||
string='上/下产线', default='待上产线', tracking=True)
|
||||
is_rework = fields.Boolean(string='是否返工', default=False)
|
||||
# production_line_state = fields.Selection(
|
||||
# [('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
|
||||
# string='上/下产线', default='待上产线', tracking=True)
|
||||
# 工序状态
|
||||
# Todo 研究下用法
|
||||
process_state = fields.Selection([
|
||||
@@ -77,11 +121,11 @@ class MrpProduction(models.Model):
|
||||
part_drawing = fields.Binary('零件图纸')
|
||||
|
||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
||||
rework_production = fields.Many2one('mrp.production', string='返工的制造订单')
|
||||
is_scrap = fields.Boolean('是否报废', default=False)
|
||||
|
||||
@api.depends(
|
||||
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
|
||||
'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state', 'process_state')
|
||||
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'tool_state',
|
||||
'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state')
|
||||
def _compute_state(self):
|
||||
for production in self:
|
||||
if not production.state or not production.product_uom_id:
|
||||
@@ -109,22 +153,40 @@ class MrpProduction(models.Model):
|
||||
production.state = 'progress'
|
||||
elif any(not float_is_zero(move.quantity_done,
|
||||
precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding)
|
||||
for move in production.move_raw_ids):
|
||||
for move in production.move_raw_ids if move.product_id):
|
||||
production.state = 'progress'
|
||||
|
||||
# 新添加的状态逻辑
|
||||
if production.state == 'progress' and production.schedule_state == '已排' and production.process_state == '待装夹':
|
||||
# production.state = 'pending_processing'
|
||||
# # 新添加的状态逻辑
|
||||
if (
|
||||
production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排':
|
||||
production.state = 'confirmed'
|
||||
elif production.state == 'pending_cam' and production.schedule_state == '未排':
|
||||
production.state = 'confirmed'
|
||||
elif production.state == 'to_close' and production.schedule_state == '已排':
|
||||
production.state = 'pending_cam'
|
||||
if production.state == 'progress' and production.schedule_state == '已排' and production.process_state == '待加工':
|
||||
# if production.state == 'pending_cam' and production.process_state == '待加工':
|
||||
production.state = 'pending_processing'
|
||||
elif production.state == 'progress' and production.process_state == '待解除装夹':
|
||||
production.state = 'pending_era_cam'
|
||||
elif production.state == 'progress' and production.process_state == '已完工':
|
||||
production.state = 'completed'
|
||||
elif production.state == 'progress' and production.work_order_state == '已完成':
|
||||
production.state = 'completed'
|
||||
|
||||
if production.state == 'progress':
|
||||
if all(wo_state not in ('progress', 'done', 'rework') for wo_state in
|
||||
production.workorder_ids.mapped('state')):
|
||||
production.state = 'pending_cam'
|
||||
if production.is_rework is True:
|
||||
production.state = 'rework'
|
||||
# if production.state == 'pending_cam':
|
||||
# if all(wo_state in 'done' for wo_state in production.workorder_ids.mapped('state')):
|
||||
# production.state = 'done'
|
||||
if any(
|
||||
(
|
||||
wo.test_results == '返工' and wo.state == 'done' and production.programming_state in [
|
||||
'已编程']) or (
|
||||
wo.state == 'rework' and production.programming_state == '编程中') or (
|
||||
wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中',
|
||||
'已编程'])
|
||||
for wo in
|
||||
production.workorder_ids):
|
||||
production.state = 'rework'
|
||||
# 如果制造订单的功能刀具为【无效刀】则制造订单状态改为返工
|
||||
if production.tool_state == '2':
|
||||
production.state = 'rework'
|
||||
|
||||
def action_check(self):
|
||||
"""
|
||||
@@ -155,27 +217,64 @@ class MrpProduction(models.Model):
|
||||
for production in self:
|
||||
production.maintenance_count = len(production.request_ids)
|
||||
|
||||
# 制造订单报废:编程单更新
|
||||
def updateCNC(self):
|
||||
# 获取cloud编程单的状态
|
||||
def _cron_get_programming_state(self):
|
||||
try:
|
||||
res = {'production_no': self.name, 'programming_no': self.programming_no,
|
||||
'order_no': self.origin}
|
||||
if not self:
|
||||
reproduction = self.env['mrp.production'].search(
|
||||
[('state', '=', 'rework'), ('programming_state', '=', '编程中'), ('is_rework', '=', True)])
|
||||
else:
|
||||
reproduction = self
|
||||
if reproduction:
|
||||
programming_no_set = set([str(item.programming_no) for item in reproduction])
|
||||
programming_no = list(programming_no_set)
|
||||
programming_no_str = ','.join(programming_no)
|
||||
res = {'programming_no': programming_no_str}
|
||||
logging.info('res=%s:' % res)
|
||||
configsettings = self.env['res.config.settings'].get_values()
|
||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
||||
url = '/api/intelligent_programming/get_state'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
ret = requests.post(config_url, json=res, data=None, headers=config_header)
|
||||
ret = ret.json()
|
||||
result = json.loads(ret['result'])
|
||||
if result['status'] == 1:
|
||||
for item in result['programming_list']:
|
||||
if not self:
|
||||
for rp in reproduction:
|
||||
if rp.programming_no == item['programming_no']:
|
||||
rp.write({'programming_state': '已编程未下发' if item[
|
||||
'programming_state'] == '已编程' else '编程中'})
|
||||
|
||||
else:
|
||||
return item
|
||||
|
||||
else:
|
||||
raise UserError(ret['message'])
|
||||
except Exception as e:
|
||||
logging.info('cron_get_programming_state error:%s' % e)
|
||||
|
||||
# 编程单更新
|
||||
def update_programming_state(self):
|
||||
try:
|
||||
res = {'programming_no': self.programming_no,
|
||||
'manufacturing_type': 'rework' if self.is_scrap is False else 'scrap'}
|
||||
logging.info('res=%s:' % res)
|
||||
configsettings = self.env['res.config.settings'].get_values()
|
||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
||||
url = '/api/intelligent_programming/update_intelligent_programmings'
|
||||
url = '/api/intelligent_programming/reset_state_again'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
res['token'] = configsettings['token']
|
||||
ret = requests.post(config_url, json={}, data=res, headers=config_header)
|
||||
ret = requests.post(config_url, json=res, data=None, headers=config_header)
|
||||
ret = ret.json()
|
||||
logging.info('updateCNC-ret:%s' % ret)
|
||||
if ret['status'] == 1:
|
||||
self.write({'work_state': '已编程'})
|
||||
result = json.loads(ret['result'])
|
||||
logging.info('update_programming_state-ret:%s' % result)
|
||||
if result['status'] == 1:
|
||||
self.write({'is_rework': True})
|
||||
else:
|
||||
raise UserError(ret['message'])
|
||||
except Exception as e:
|
||||
logging.info('updateCNC error:%s' % e)
|
||||
raise UserError("更新程单失败,请联系管理员")
|
||||
logging.info('update_programming_state error:%s' % e)
|
||||
raise UserError("更新编程单状态失败,请联系管理员")
|
||||
|
||||
# cnc程序获取
|
||||
def fetchCNC(self, production_names):
|
||||
@@ -201,7 +300,7 @@ class MrpProduction(models.Model):
|
||||
'material_type_code': self.env['sf.materials.model'].search(
|
||||
[('id', '=', cnc.product_id.materials_type_id.id)]).materials_no,
|
||||
'machining_processing_panel': cnc.product_id.model_processing_panel,
|
||||
'machining_precision': cnc.product_id.model_machining_precision,
|
||||
'machining_precision': '',
|
||||
'embryo_long': cnc.product_id.bom_ids.bom_line_ids.product_id.length,
|
||||
'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height,
|
||||
'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
|
||||
@@ -293,14 +392,6 @@ class MrpProduction(models.Model):
|
||||
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
|
||||
|
||||
def _create_workorder3(self, item):
|
||||
# 根据product_id对self进行分组
|
||||
grouped_product_ids = {k: list(g) for k, g in groupby(self, key=lambda x: x.product_id.id)}
|
||||
# 初始化一个字典来存储每个product_id对应的生产订单名称列表
|
||||
product_id_to_production_names = {}
|
||||
# 对于每个product_id,获取其所有生产订单的名称
|
||||
for product_id, productions in grouped_product_ids.items():
|
||||
# 为同一个product_id创建一个生产订单名称列表
|
||||
product_id_to_production_names[product_id] = [production.name for production in productions]
|
||||
for production in self:
|
||||
if not production.bom_id or not production.product_id:
|
||||
continue
|
||||
@@ -347,6 +438,7 @@ class MrpProduction(models.Model):
|
||||
# 表面工艺工序
|
||||
# 获取表面工艺id
|
||||
if production.product_id.model_process_parameters_ids:
|
||||
logging.info('model_process_parameters_ids:%s' % production.product_id.model_process_parameters_ids)
|
||||
surface_technics_arr = []
|
||||
# 工序id
|
||||
route_workcenter_arr = []
|
||||
@@ -361,6 +453,7 @@ class MrpProduction(models.Model):
|
||||
# 用filter刷选表面工艺id'是否存在工艺类别对象里
|
||||
if production_process_category:
|
||||
for p in production_process_category:
|
||||
logging.info('production_process_category:%s' % p.name)
|
||||
production_process = p.production_process_ids.filtered(
|
||||
lambda pp: pp.id in surface_technics_arr)
|
||||
if production_process:
|
||||
@@ -414,7 +507,7 @@ class MrpProduction(models.Model):
|
||||
else:
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
|
||||
production_item)
|
||||
production)
|
||||
if sorted_workorders[i] in consecutive_workorders:
|
||||
is_pick = True
|
||||
consecutive_workorders = []
|
||||
@@ -422,46 +515,24 @@ class MrpProduction(models.Model):
|
||||
# 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单
|
||||
if is_pick is False:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i],
|
||||
production_item)
|
||||
production)
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
|
||||
production_item)
|
||||
production)
|
||||
if sorted_workorders[i] in consecutive_workorders:
|
||||
is_pick = True
|
||||
consecutive_workorders = []
|
||||
m = 0
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production_item)
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production)
|
||||
if is_pick is False and m == 0:
|
||||
if len(sorted_workorders) == 1:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production_item)
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production)
|
||||
else:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production_item)
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production)
|
||||
for workorder in production.workorder_ids:
|
||||
workorder.duration_expected = workorder._get_duration_expected()
|
||||
|
||||
# 在之前的销售单上重新生成制造订单
|
||||
def create_production1_values(self, production):
|
||||
production_values_str = {'origin': production.origin,
|
||||
'product_id': production.product_id.id,
|
||||
'product_description_variants': production.product_description_variants,
|
||||
'product_qty': production.product_qty,
|
||||
'product_uom_id': production.product_uom_id.id,
|
||||
'location_src_id': production.location_src_id.id,
|
||||
'location_dest_id': production.location_dest_id.id,
|
||||
'bom_id': production.bom_id.id,
|
||||
'date_deadline': production.date_deadline,
|
||||
'date_planned_start': production.date_planned_start,
|
||||
'date_planned_finished': production.date_planned_finished,
|
||||
'procurement_group_id': False,
|
||||
'propagate_cancel': production.propagate_cancel,
|
||||
'orderpoint_id': production.orderpoint_id.id,
|
||||
'picking_type_id': production.picking_type_id.id,
|
||||
'company_id': production.company_id.id,
|
||||
'move_dest_ids': production.move_dest_ids.ids,
|
||||
'user_id': production.user_id.id}
|
||||
return production_values_str
|
||||
|
||||
# 工单排序
|
||||
def _reset_work_order_sequence1(self, k):
|
||||
for rec in self:
|
||||
@@ -530,70 +601,90 @@ class MrpProduction(models.Model):
|
||||
|
||||
def _reset_work_order_sequence(self):
|
||||
for rec in self:
|
||||
sequence_list = {}
|
||||
workorder_ids = rec.workorder_ids.filtered(lambda item: item.state in ('返工', 'rework'))
|
||||
# 产品模型类型
|
||||
model_type_id = rec.product_id.product_model_type_id
|
||||
# 产品加工面板
|
||||
model_processing_panel = rec.product_id.model_processing_panel
|
||||
if model_type_id:
|
||||
if model_processing_panel:
|
||||
tmpl_num = 1
|
||||
panel_list = model_processing_panel.split(',')
|
||||
for panel in panel_list:
|
||||
panel_sequence_list = {}
|
||||
# 成品工序
|
||||
product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids
|
||||
if product_routing_tmpl_ids:
|
||||
for tmpl_id in product_routing_tmpl_ids:
|
||||
panel_sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
|
||||
tmpl_num += 1
|
||||
sequence_list.update({panel: panel_sequence_list})
|
||||
# 表面工艺工序
|
||||
# 模型类型的表面工艺工序模版
|
||||
surface_tmpl_ids = model_type_id.surface_technics_routing_tmpl_ids
|
||||
# 产品选择的表面工艺
|
||||
model_process_parameters_ids = rec.product_id.model_process_parameters_ids
|
||||
process_dict = {}
|
||||
if model_process_parameters_ids:
|
||||
for process_parameters_id in model_process_parameters_ids:
|
||||
process_id = process_parameters_id.process_id
|
||||
for surface_tmpl_id in surface_tmpl_ids:
|
||||
if process_id == surface_tmpl_id.route_workcenter_id.surface_technics_id:
|
||||
surface_tmpl_name = surface_tmpl_id.route_workcenter_id.name
|
||||
process_dict.update({int(process_id.category_id.code): '%s-%s' % (
|
||||
surface_tmpl_name, process_parameters_id.name)})
|
||||
process_list = sorted(process_dict.keys())
|
||||
for process_num in process_list:
|
||||
sequence_list.update({process_dict.get(process_num): tmpl_num})
|
||||
tmpl_num += 1
|
||||
# 坯料工序
|
||||
tmpl_num = 1
|
||||
embryo_routing_tmpl_ids = model_type_id.embryo_routing_tmpl_ids
|
||||
if embryo_routing_tmpl_ids:
|
||||
for tmpl_id in embryo_routing_tmpl_ids:
|
||||
sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
|
||||
if not workorder_ids:
|
||||
sequence_list = {}
|
||||
if model_type_id:
|
||||
if model_processing_panel:
|
||||
tmpl_num = 1
|
||||
panel_list = model_processing_panel.split(',')
|
||||
for panel in panel_list:
|
||||
panel_sequence_list = {}
|
||||
# 成品工序
|
||||
product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids
|
||||
if product_routing_tmpl_ids:
|
||||
for tmpl_id in product_routing_tmpl_ids:
|
||||
panel_sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
|
||||
tmpl_num += 1
|
||||
sequence_list.update({panel: panel_sequence_list})
|
||||
# 表面工艺工序
|
||||
# 模型类型的表面工艺工序模版
|
||||
surface_tmpl_ids = model_type_id.surface_technics_routing_tmpl_ids
|
||||
# 产品选择的表面工艺
|
||||
model_process_parameters_ids = rec.product_id.model_process_parameters_ids
|
||||
process_dict = {}
|
||||
if model_process_parameters_ids:
|
||||
for process_parameters_id in model_process_parameters_ids:
|
||||
process_id = process_parameters_id.process_id
|
||||
for surface_tmpl_id in surface_tmpl_ids:
|
||||
if process_id == surface_tmpl_id.route_workcenter_id.surface_technics_id:
|
||||
surface_tmpl_name = surface_tmpl_id.route_workcenter_id.name
|
||||
process_dict.update({int(process_id.category_id.code): '%s-%s' % (
|
||||
surface_tmpl_name, process_parameters_id.name)})
|
||||
process_list = sorted(process_dict.keys())
|
||||
for process_num in process_list:
|
||||
sequence_list.update({process_dict.get(process_num): tmpl_num})
|
||||
tmpl_num += 1
|
||||
# 坯料工序
|
||||
tmpl_num = 1
|
||||
embryo_routing_tmpl_ids = model_type_id.embryo_routing_tmpl_ids
|
||||
if embryo_routing_tmpl_ids:
|
||||
for tmpl_id in embryo_routing_tmpl_ids:
|
||||
sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
|
||||
tmpl_num += 1
|
||||
else:
|
||||
raise ValidationError('该产品【加工面板】为空!')
|
||||
else:
|
||||
raise ValidationError('该产品【加工面板】为空!')
|
||||
raise ValidationError('该产品没有选择【模版类型】!')
|
||||
|
||||
else:
|
||||
raise ValidationError('该产品没有选择【模版类型】!')
|
||||
|
||||
for work in rec.workorder_ids:
|
||||
if sequence_list.get(work.name):
|
||||
work.sequence = sequence_list[work.name]
|
||||
elif sequence_list.get(work.processing_panel):
|
||||
processing_panel = sequence_list.get(work.processing_panel)
|
||||
if processing_panel.get(work.name):
|
||||
work.sequence = processing_panel[work.name]
|
||||
for work in rec.workorder_ids:
|
||||
if sequence_list.get(work.name):
|
||||
work.sequence = sequence_list[work.name]
|
||||
elif sequence_list.get(work.processing_panel):
|
||||
processing_panel = sequence_list.get(work.processing_panel)
|
||||
if processing_panel.get(work.name):
|
||||
work.sequence = processing_panel[work.name]
|
||||
else:
|
||||
raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name)
|
||||
else:
|
||||
raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name)
|
||||
else:
|
||||
raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name)
|
||||
# if work.name == '获取CNC加工程序':
|
||||
# work.button_start()
|
||||
# #work.fetchCNC()
|
||||
# work.button_finish()
|
||||
# 当单个面触发返工时,将新生成的工单插入到返工工单下方,并且后面的所以工单工序重排
|
||||
elif rec.workorder_ids.filtered(lambda item: item.sequence == 0):
|
||||
# 获取新增的返工工单
|
||||
work_ids = rec.workorder_ids.filtered(lambda item: item.sequence == 0)
|
||||
# 获取当前返工面最后一个工单工序
|
||||
sequence_max = sorted(
|
||||
rec.workorder_ids.filtered(lambda item: item.processing_panel == work_ids[0].processing_panel),
|
||||
key=lambda item: item.sequence, reverse=True)[0].sequence
|
||||
# 对当前返工工单之后的工单工序进行重排
|
||||
work_order_ids = rec.workorder_ids.filtered(lambda item: item.sequence > sequence_max)
|
||||
for work_id in work_order_ids:
|
||||
work_id.sequence = work_id.sequence + 3
|
||||
# 生成新增的返工工单的工序
|
||||
# 成品工序
|
||||
panel_sequence_list = {}
|
||||
product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids
|
||||
if product_routing_tmpl_ids:
|
||||
for tmpl_id in product_routing_tmpl_ids:
|
||||
sequence_max += 1
|
||||
panel_sequence_list.update({tmpl_id.route_workcenter_id.name: sequence_max})
|
||||
for work_id in work_ids:
|
||||
if panel_sequence_list.get(work_id.name):
|
||||
work_id.sequence = panel_sequence_list[work_id.name]
|
||||
|
||||
# 创建工单并进行排序
|
||||
def _create_workorder(self, item):
|
||||
@@ -641,6 +732,9 @@ class MrpProduction(models.Model):
|
||||
})
|
||||
|
||||
for production in self:
|
||||
logging.info('qty_produced:%s' % production.qty_produced)
|
||||
if production.qty_produced == 0.0:
|
||||
production.qty_produced = 1.0
|
||||
production.write({
|
||||
'date_finished': fields.Datetime.now(),
|
||||
'product_qty': production.qty_produced,
|
||||
@@ -669,6 +763,7 @@ class MrpProduction(models.Model):
|
||||
if any(mo.show_allocation for mo in self):
|
||||
action = self.action_view_reception_report()
|
||||
return action
|
||||
logging.info('last-product_qty:%s' % production.product_qty)
|
||||
return True
|
||||
context = self.env.context.copy()
|
||||
context = {k: v for k, v in context.items() if not k.startswith('default_')}
|
||||
@@ -692,3 +787,300 @@ class MrpProduction(models.Model):
|
||||
'view_mode': 'tree,form',
|
||||
})
|
||||
return action
|
||||
|
||||
# 返工
|
||||
def button_rework(self):
|
||||
cloud_programming = None
|
||||
if self.programming_state in ['已编程']:
|
||||
cloud_programming = self._cron_get_programming_state()
|
||||
return {
|
||||
'name': _('返工'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'sf.rework.wizard',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_production_id': self.id,
|
||||
'default_reprogramming_num': cloud_programming['reprogramming_num'],
|
||||
'default_programming_state': cloud_programming['programming_state'],
|
||||
'default_is_reprogramming': True if cloud_programming['programming_state'] in ['已下发'] else False
|
||||
}
|
||||
}
|
||||
|
||||
# 更新程序
|
||||
def do_update_program(self):
|
||||
program_production = self
|
||||
if len(program_production) >= 1:
|
||||
# same_product_id = None
|
||||
# is_not_same_product = 0
|
||||
for item in program_production:
|
||||
# if same_product_id is None:
|
||||
# same_product_id = item.product_id
|
||||
# if item.product_id != same_product_id:
|
||||
# is_not_same_product += 1
|
||||
if item.state != "rework" and item.programming_state != "已编程未下发":
|
||||
raise UserError("请选择状态为返工且已编程未下发的制造订单")
|
||||
# if is_not_same_product >= 1:
|
||||
# raise UserError("您选择的记录中含有其他产品的制造订单,请选择同一产品的制造订单")
|
||||
grouped_program_ids = {k: list(g) for k, g in groupby(program_production, key=lambda x: x.programming_no)}
|
||||
program_to_production_names = {}
|
||||
for programming_no, program_production in grouped_program_ids.items():
|
||||
program_to_production_names[programming_no] = [production.name for production in program_production]
|
||||
for production in self:
|
||||
if production.programming_no in program_to_production_names:
|
||||
productions_not_delivered = self.env['mrp.production'].search(
|
||||
[('programming_no', '=', production.programming_no), ('programming_state', '=', '已编程未下发')])
|
||||
rework_workorder = production.workorder_ids.filtered(lambda m: m.state == 'rework')
|
||||
if rework_workorder:
|
||||
for rework_item in rework_workorder:
|
||||
pending_workorder = production.workorder_ids.filtered(
|
||||
lambda m1: m1.state in [
|
||||
'pending'] and m1.processing_panel == rework_item.processing_panel and m1.routing_type == 'CNC加工')
|
||||
if not pending_workorder.cnc_ids:
|
||||
production.get_new_program(rework_item.processing_panel)
|
||||
# production.write({'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
|
||||
productions_not_delivered.write(
|
||||
{'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
|
||||
|
||||
# 从cloud获取重新编程过的最新程序
|
||||
def get_new_program(self, processing_panel):
|
||||
try:
|
||||
res = {'programming_no': self.programming_no, 'processing_panel': processing_panel}
|
||||
configsettings = self.env['res.config.settings'].get_values()
|
||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
||||
url = '/api/intelligent_programming/get_new_program'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
r = requests.post(config_url, json=res, data=None, headers=config_header)
|
||||
r = r.json()
|
||||
result = json.loads(r['result'])
|
||||
if result['status'] == 1:
|
||||
program_path_tmp_panel = os.path.join('/tmp', result['folder_name'], 'return', processing_panel)
|
||||
if os.path.exists(program_path_tmp_panel):
|
||||
files_r = os.listdir(program_path_tmp_panel)
|
||||
if files_r:
|
||||
for file_name in files_r:
|
||||
file_path = os.path.join(program_path_tmp_panel, file_name)
|
||||
os.remove(file_path)
|
||||
download_state = self.env['sf.cnc.processing'].download_file_tmp(result['folder_name'],
|
||||
processing_panel)
|
||||
if download_state is False:
|
||||
raise UserError('编程单号为%s的CNC程序文件从FTP拉取失败' % (self.programming_no))
|
||||
productions = self.env['mrp.production'].search(
|
||||
[('programming_no', '=', self.programming_no), ('state', 'not in', ('cancel', 'done'))])
|
||||
if productions:
|
||||
for production in productions:
|
||||
panel_workorder = production.workorder_ids.filtered(lambda
|
||||
pw: pw.processing_panel == processing_panel and pw.routing_type == 'CNC加工' and pw.state not in (
|
||||
'rework', 'done'))
|
||||
if panel_workorder:
|
||||
if panel_workorder.cmm_ids:
|
||||
panel_workorder.cmm_ids.sudo().unlink()
|
||||
if panel_workorder.cnc_ids:
|
||||
panel_workorder.cnc_ids.sudo().unlink()
|
||||
self.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
|
||||
production)
|
||||
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
|
||||
# processing_panel)
|
||||
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)
|
||||
files_panel = os.listdir(program_path_tmp_panel)
|
||||
if files_panel:
|
||||
for file in files_panel:
|
||||
file_extension = os.path.splitext(file)[1]
|
||||
if file_extension.lower() == '.pdf':
|
||||
panel_file_path = os.path.join(program_path_tmp_panel, file)
|
||||
logging.info('panel_file_path:%s' % panel_file_path)
|
||||
panel_workorder.write(
|
||||
{'cnc_ids': panel_workorder.cnc_ids.sudo()._json_cnc_processing(processing_panel,
|
||||
result),
|
||||
'cmm_ids': panel_workorder.cmm_ids.sudo()._json_cmm_program(processing_panel, result),
|
||||
'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
logging.info('len(cnc_worksheet):%s' % len(panel_workorder.cnc_worksheet))
|
||||
pre_workorder = production.workorder_ids.filtered(lambda
|
||||
ap: ap.routing_type == '装夹预调' and ap.processing_panel == processing_panel and ap.state not in (
|
||||
'rework', 'done'))
|
||||
if pre_workorder:
|
||||
pre_workorder.write(
|
||||
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
# if production.state == 'rework' and production.programming_state == '已编程未下发':
|
||||
# production.write(
|
||||
# {'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
|
||||
# logging.info('返工含有已编程未下发的程序更新完成:%s' % production.name)
|
||||
logging.info('更新程序完成:%s' % production.name)
|
||||
|
||||
else:
|
||||
raise UserError(result['message'])
|
||||
except Exception as e:
|
||||
logging.info('get_new_program error:%s' % e)
|
||||
raise UserError("从云平台获取最新程序失败,请联系管理员")
|
||||
|
||||
def recreateManufacturing(self):
|
||||
"""
|
||||
重新生成制造订单
|
||||
"""
|
||||
if self.is_scrap is True:
|
||||
sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)])
|
||||
values = self.env['mrp.production'].create_production1_values(self.production_id)
|
||||
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
|
||||
self.production_id.company_id).create(
|
||||
values)
|
||||
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
||||
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||
productions._create_workorder()
|
||||
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
|
||||
(
|
||||
p.move_dest_ids.procure_method != 'make_to_order' and
|
||||
not p.move_raw_ids and not p.workorder_ids)).action_confirm()
|
||||
for production_item in productions:
|
||||
process_parameter_workorder = self.env['mrp.workorder'].search(
|
||||
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_item.id),
|
||||
('is_subcontract', '=', True)])
|
||||
if process_parameter_workorder:
|
||||
is_pick = False
|
||||
consecutive_workorders = []
|
||||
m = 0
|
||||
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id)
|
||||
for i in range(len(sorted_workorders) - 1):
|
||||
if m == 0:
|
||||
is_pick = False
|
||||
if sorted_workorders[i].supplier_id.id == sorted_workorders[i + 1].supplier_id.id and \
|
||||
sorted_workorders[i].is_subcontract == sorted_workorders[i + 1].is_subcontract and \
|
||||
sorted_workorders[i].id == sorted_workorders[i + 1].id - 1:
|
||||
if sorted_workorders[i] not in consecutive_workorders:
|
||||
consecutive_workorders.append(sorted_workorders[i])
|
||||
consecutive_workorders.append(sorted_workorders[i + 1])
|
||||
m += 1
|
||||
continue
|
||||
else:
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
|
||||
production_item)
|
||||
if sorted_workorders[i] in consecutive_workorders:
|
||||
is_pick = True
|
||||
consecutive_workorders = []
|
||||
m = 0
|
||||
# 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单
|
||||
if is_pick is False:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i],
|
||||
production_item)
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
|
||||
production_item)
|
||||
if sorted_workorders[i] in consecutive_workorders:
|
||||
is_pick = True
|
||||
consecutive_workorders = []
|
||||
m = 0
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production_item)
|
||||
if is_pick is False and m == 0:
|
||||
if len(sorted_workorders) == 1:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production_item)
|
||||
else:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production_item)
|
||||
|
||||
for production in productions:
|
||||
origin_production = production.move_dest_ids and production.move_dest_ids[
|
||||
0].raw_material_production_id or False
|
||||
orderpoint = production.orderpoint_id
|
||||
if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual':
|
||||
production.message_post(
|
||||
body=_('This production order has been created from Replenishment Report.'),
|
||||
message_type='comment',
|
||||
subtype_xmlid='mail.mt_note')
|
||||
elif orderpoint:
|
||||
production.message_post_with_view(
|
||||
'mail.message_origin_link',
|
||||
values={'self': production, 'origin': orderpoint},
|
||||
subtype_id=self.env.ref('mail.mt_note').id)
|
||||
elif origin_production:
|
||||
production.message_post_with_view(
|
||||
'mail.message_origin_link',
|
||||
values={'self': production, 'origin': origin_production},
|
||||
subtype_id=self.env.ref('mail.mt_note').id)
|
||||
|
||||
'''
|
||||
创建生产计划
|
||||
'''
|
||||
# 工单耗时
|
||||
workorder_duration = 0
|
||||
for workorder in productions.workorder_ids:
|
||||
workorder_duration += workorder.duration_expected
|
||||
|
||||
if sale_order:
|
||||
sale_order.mrp_production_ids |= productions
|
||||
# sale_order.write({'schedule_status': 'to schedule'})
|
||||
self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({
|
||||
'name': productions.name,
|
||||
'order_deadline': sale_order.deadline_of_delivery,
|
||||
'production_id': productions.id,
|
||||
'date_planned_start': productions.date_planned_start,
|
||||
'origin': productions.origin,
|
||||
'product_qty': productions.product_qty,
|
||||
'product_id': productions.product_id.id,
|
||||
'state': 'draft',
|
||||
})
|
||||
|
||||
# 在之前的销售单上重新生成制造订单
|
||||
def create_production1_values(self, production, sale_order):
|
||||
production_values_str = {'origin': production.origin,
|
||||
'product_id': production.product_id.id,
|
||||
'product_description_variants': production.product_description_variants,
|
||||
'product_qty': production.product_qty,
|
||||
'product_uom_id': production.product_uom_id.id,
|
||||
'location_src_id': production.location_src_id.id,
|
||||
'location_dest_id': production.location_dest_id.id,
|
||||
'bom_id': production.bom_id.id,
|
||||
'date_deadline': production.date_deadline,
|
||||
'date_planned_start': production.date_planned_start,
|
||||
'date_planned_finished': production.date_planned_finished,
|
||||
'procurement_group_id': sale_order.id,
|
||||
'propagate_cancel': production.propagate_cancel,
|
||||
'orderpoint_id': production.orderpoint_id.id,
|
||||
'picking_type_id': production.picking_type_id.id,
|
||||
'company_id': production.company_id.id,
|
||||
'move_dest_ids': production.move_dest_ids.ids,
|
||||
'user_id': production.user_id.id}
|
||||
return production_values_str
|
||||
|
||||
|
||||
class sf_detection_result(models.Model):
|
||||
_name = 'sf.detection.result'
|
||||
_description = "检测结果"
|
||||
|
||||
production_id = fields.Many2one('mrp.production')
|
||||
processing_panel = fields.Char('加工面')
|
||||
routing_type = fields.Selection([
|
||||
('装夹预调', '装夹预调'),
|
||||
('CNC加工', 'CNC加工')], string="工序类型")
|
||||
|
||||
rework_reason = fields.Selection(
|
||||
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"),
|
||||
("operate computer", "操机"),
|
||||
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因", tracking=True)
|
||||
detailed_reason = fields.Text('详细原因')
|
||||
test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")],
|
||||
string="检测结果", tracking=True)
|
||||
test_report = fields.Binary('检测报告', readonly=True)
|
||||
handle_result = fields.Selection([("待处理", "待处理"), ("已处理", "已处理")], default='', string="处理结果",
|
||||
tracking=True)
|
||||
|
||||
# 查看检测报告
|
||||
def button_look_test_report(self):
|
||||
return {
|
||||
'res_model': 'sf.detection.result',
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_id': self.id,
|
||||
'views': [(self.env.ref('sf_manufacturing.sf_test_report_form').id, 'form')],
|
||||
# 'view_mode': 'form',
|
||||
# 'context': {
|
||||
# 'default_id': self.id
|
||||
# },
|
||||
'target': 'new'
|
||||
}
|
||||
|
||||
|
||||
class sf_processing_panel(models.Model):
|
||||
_name = 'sf.processing.panel'
|
||||
_description = "加工面"
|
||||
|
||||
name = fields.Char('加工面')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
|
||||
@@ -5,24 +5,49 @@ from odoo.addons.resource.models.resource import Intervals
|
||||
|
||||
|
||||
class ResWorkcenter(models.Model):
|
||||
_inherit = "mrp.workcenter"
|
||||
_name = "mrp.workcenter"
|
||||
_inherit = ['mrp.workcenter', 'mail.thread']
|
||||
|
||||
# 生产线显示
|
||||
production_line_show = fields.Char(string='生产线名称')
|
||||
equipment_id = fields.Many2one(
|
||||
'maintenance.equipment', string="设备",
|
||||
)
|
||||
equipment_id = fields.Many2one('maintenance.equipment', string="设备", tracking=True)
|
||||
production_line_id = fields.Many2one('sf.production.line', string='生产线',
|
||||
related='equipment_id.production_line_id', store=True)
|
||||
|
||||
is_process_outsourcing = fields.Boolean('工艺外协')
|
||||
users_ids = fields.Many2many("res.users", 'users_workcenter')
|
||||
users_ids = fields.Many2many("res.users", 'users_workcenter', tracking=True)
|
||||
|
||||
def write(self, vals):
|
||||
if 'users_ids' in vals:
|
||||
old_users = self.users_ids
|
||||
res = super(ResWorkcenter, self).write(vals)
|
||||
new_users = self.users_ids
|
||||
added_users = new_users - old_users
|
||||
removed_users = old_users - new_users
|
||||
if added_users or removed_users:
|
||||
message = "增加 → %s ; 移除 → %s (可操作用户)" % (
|
||||
# ','.join(added_users.mapped('name')), ','.join(removed_users.mapped('name')))
|
||||
added_users.mapped('name'), removed_users.mapped('name'))
|
||||
self.message_post(body=message)
|
||||
return res
|
||||
return super(ResWorkcenter, self).write(vals)
|
||||
|
||||
name = fields.Char('Work Center', related='resource_id.name', store=True, readonly=False, tracking=True)
|
||||
time_efficiency = fields.Float('Time Efficiency', related='resource_id.time_efficiency', default=100, store=True,
|
||||
readonly=False, tracking=True)
|
||||
default_capacity = fields.Float(
|
||||
'Capacity', default=1.0,
|
||||
help="Default number of pieces (in product UoM) that can be produced in parallel (at the same time) at this work center. For example: the capacity is 5 and you need to produce 10 units, then the operation time listed on the BOM will be multiplied by two. However, note that both time before and after production will only be counted once.",
|
||||
tracking=True)
|
||||
|
||||
oee_target = fields.Float(
|
||||
string='OEE Target', help="Overall Effective Efficiency Target in percentage", default=90, tracking=True)
|
||||
|
||||
time_start = fields.Float('Setup Time', tracking=True)
|
||||
time_stop = fields.Float('Cleanup Time', tracking=True)
|
||||
costs_hour = fields.Float(string='Cost per hour', help='Hourly processing cost.', default=0.0, tracking=True)
|
||||
|
||||
equipment_status = fields.Selection(
|
||||
[("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"),("空闲", "空闲"),("封存(报废)", "封存(报废)")],
|
||||
[("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"), ("封存(报废)", "封存(报废)")],
|
||||
string="设备状态", related='equipment_id.state')
|
||||
|
||||
# @api.depends('equipment_id')
|
||||
|
||||
@@ -13,13 +13,13 @@ from dateutil.relativedelta import relativedelta
|
||||
# import subprocess
|
||||
from odoo import api, fields, models, SUPERUSER_ID, _
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.addons.sf_mrs_connect.models.ftp_operate import FtpController
|
||||
|
||||
|
||||
class ResMrpWorkOrder(models.Model):
|
||||
_inherit = 'mrp.workorder'
|
||||
_order = 'sequence asc,create_date desc'
|
||||
_order = 'sequence asc'
|
||||
|
||||
product_tmpl_name = fields.Char('坯料产品名称', related='production_bom_id.bom_line_ids.product_id.name')
|
||||
|
||||
@@ -47,9 +47,28 @@ class ResMrpWorkOrder(models.Model):
|
||||
('切割', '切割'), ('表面工艺', '表面工艺')
|
||||
], string="工序类型")
|
||||
results = fields.Char('结果')
|
||||
state = fields.Selection([
|
||||
('pending', '等待其他工单'),
|
||||
('waiting', '等待组件'),
|
||||
('ready', '就绪'),
|
||||
('progress', '进行中'),
|
||||
('to be detected', "待检测"),
|
||||
('done', '已完工'),
|
||||
('rework', '返工'),
|
||||
('cancel', '取消')], string='Status',
|
||||
compute='_compute_state', store=True,
|
||||
default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True)
|
||||
# state = fields.Selection(selection_add=[('to be detected', "待检测"), ('rework', '返工')], tracking=True)
|
||||
|
||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
||||
|
||||
def _compute_working_users(self):
|
||||
super()._compute_working_users()
|
||||
for item in self:
|
||||
if item.state == 'to be detected':
|
||||
if self.env.user.has_group('sf_base.group_sf_equipment_user'):
|
||||
item.is_user_working = True
|
||||
|
||||
@api.onchange('users_ids')
|
||||
def get_user_permissions(self):
|
||||
uid = self.env.uid
|
||||
@@ -136,11 +155,6 @@ class ResMrpWorkOrder(models.Model):
|
||||
|
||||
supplier_id = fields.Many2one('res.partner', string='外协供应商')
|
||||
equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True)
|
||||
is_ok = fields.Boolean(string='是否合格')
|
||||
# 加工人
|
||||
processing_user_id = fields.Many2one('res.users', string='加工人')
|
||||
# 检测人
|
||||
inspection_user_id = fields.Many2one('res.users', string='检测人')
|
||||
# 保存名称
|
||||
save_name = fields.Char(string='检测文件保存名称', compute='_compute_save_name')
|
||||
# 获取数据状态
|
||||
@@ -163,13 +177,46 @@ class ResMrpWorkOrder(models.Model):
|
||||
# 加工图纸
|
||||
processing_drawing = fields.Binary(string='加工图纸')
|
||||
|
||||
# 功能刀具状态
|
||||
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
|
||||
store=True, compute='_compute_tool_state')
|
||||
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
|
||||
|
||||
@api.depends('cnc_ids.tool_state')
|
||||
def _compute_tool_state_remark(self):
|
||||
for item in self:
|
||||
if item.cnc_ids:
|
||||
if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
|
||||
item.tool_state_remark = None
|
||||
elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
tool_state_remark = []
|
||||
cnc_ids = item.cnc_ids.filtered(lambda a: a.tool_state == '1')
|
||||
for cnc_id in cnc_ids:
|
||||
if cnc_id.cutting_tool_name not in tool_state_remark:
|
||||
tool_state_remark.append(cnc_id.cutting_tool_name)
|
||||
item.tool_state_remark = f"{item.processing_panel}缺刀:{tool_state_remark}"
|
||||
else:
|
||||
item.tool_state_remark = None
|
||||
|
||||
@api.depends('cnc_ids.tool_state')
|
||||
def _compute_tool_state(self):
|
||||
for item in self:
|
||||
if item.cnc_ids:
|
||||
if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
|
||||
item.tool_state = '2'
|
||||
elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
item.tool_state = '1'
|
||||
else:
|
||||
item.tool_state = '0'
|
||||
|
||||
@api.depends('production_id')
|
||||
def _compute_save_name(self):
|
||||
"""
|
||||
保存名称
|
||||
"""
|
||||
for record in self:
|
||||
record.save_name = record.production_id.name.replace('/', '_')
|
||||
tem_name = record.production_id.name.replace('/', '_')
|
||||
record.save_name = tem_name + '_' + record.processing_panel
|
||||
|
||||
schedule_state = fields.Selection(related='production_id.schedule_state', store=True)
|
||||
# 工件装夹信息
|
||||
@@ -198,16 +245,78 @@ class ResMrpWorkOrder(models.Model):
|
||||
|
||||
production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id',
|
||||
string='生产线', store=True, tracking=True)
|
||||
production_line_state = fields.Selection(related='production_id.production_line_state',
|
||||
string='上/下产线', store=True, tracking=True)
|
||||
detection_report = fields.Binary('检测报告', readonly=True)
|
||||
production_line_state = fields.Selection(
|
||||
[('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
|
||||
string='上/下产线', default='待上产线', tracking=True)
|
||||
detection_report = fields.Binary('检测报告', readonly=False)
|
||||
is_remanufacture = fields.Boolean(string='重新生成制造订单', default=False)
|
||||
is_fetchcnc = fields.Boolean(string='重新获取NC程序', default=False)
|
||||
reason = fields.Selection(
|
||||
[("programming", "编程"), ("clamping", "返工"), ("cutter", "刀具"), ("operate computer", "操机"),
|
||||
("technology", "工艺"), ("customer redrawing", "客户改图"), ("other", "其他"), ], string="原因", tracking=True)
|
||||
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"), ("operate computer", "操机"),
|
||||
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因", tracking=True)
|
||||
detailed_reason = fields.Text('详细原因')
|
||||
is_send_program_again = fields.Boolean(string='是否重新下发NC程序', default=False)
|
||||
is_rework = fields.Boolean(string='是否返工', default=False)
|
||||
|
||||
@api.constrains('blocked_by_workorder_ids')
|
||||
def _check_no_cyclic_dependencies(self):
|
||||
if self.production_id.state not in ['rework'] and self.state not in ['rework']:
|
||||
if not self._check_m2m_recursion('blocked_by_workorder_ids'):
|
||||
raise ValidationError(_("您不能创建周期性的依赖关系."))
|
||||
|
||||
def _plan_workorder(self, replan=False):
|
||||
self.ensure_one()
|
||||
# Plan workorder after its predecessors
|
||||
start_date = max(self.production_id.date_planned_start, datetime.now())
|
||||
for workorder in self.blocked_by_workorder_ids:
|
||||
if workorder.state in ['done', 'cancel', 'rework']:
|
||||
continue
|
||||
workorder._plan_workorder(replan)
|
||||
start_date = max(start_date, workorder.date_planned_finished)
|
||||
# Plan only suitable workorders
|
||||
if self.state not in ['pending', 'waiting', 'ready']:
|
||||
return
|
||||
if self.leave_id:
|
||||
if replan:
|
||||
self.leave_id.unlink()
|
||||
else:
|
||||
return
|
||||
# Consider workcenter and alternatives
|
||||
workcenters = self.workcenter_id | self.workcenter_id.alternative_workcenter_ids
|
||||
best_finished_date = datetime.max
|
||||
vals = {}
|
||||
for workcenter in workcenters:
|
||||
# Compute theoretical duration
|
||||
if self.workcenter_id == workcenter:
|
||||
duration_expected = self.duration_expected
|
||||
else:
|
||||
duration_expected = self._get_duration_expected(alternative_workcenter=workcenter)
|
||||
from_date, to_date = workcenter._get_first_available_slot(start_date, duration_expected)
|
||||
# If the workcenter is unavailable, try planning on the next one
|
||||
if not from_date:
|
||||
continue
|
||||
# Check if this workcenter is better than the previous ones
|
||||
if to_date and to_date < best_finished_date:
|
||||
best_start_date = from_date
|
||||
best_finished_date = to_date
|
||||
best_workcenter = workcenter
|
||||
vals = {
|
||||
'workcenter_id': workcenter.id,
|
||||
'duration_expected': duration_expected,
|
||||
}
|
||||
# If none of the workcenter are available, raise
|
||||
if best_finished_date == datetime.max:
|
||||
raise UserError(_('Impossible to plan the workorder. Please check the workcenter availabilities.'))
|
||||
# Create leave on chosen workcenter calendar
|
||||
leave = self.env['resource.calendar.leaves'].create({
|
||||
'name': self.display_name,
|
||||
'calendar_id': best_workcenter.resource_calendar_id.id,
|
||||
'date_from': best_start_date,
|
||||
'date_to': best_finished_date,
|
||||
'resource_id': best_workcenter.resource_id.id,
|
||||
'time_type': 'other'
|
||||
})
|
||||
vals['leave_id'] = leave.id
|
||||
self.write(vals)
|
||||
|
||||
@api.onchange('rfid_code')
|
||||
def _onchange(self):
|
||||
@@ -222,7 +331,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
sql = """
|
||||
SELECT *
|
||||
FROM mrp_workorder
|
||||
WHERE
|
||||
WHERE state!='rework'
|
||||
to_char(date_planned_start::timestamp + '8 hour','YYYY-MM-DD HH:mm:SS')>= %s
|
||||
AND to_char(date_planned_finished::timestamp + '8 hour','YYYY-MM-DD HH:mm:SS')<= %s
|
||||
"""
|
||||
@@ -234,16 +343,6 @@ class ResMrpWorkOrder(models.Model):
|
||||
ids = [t[0] for t in self.env.cr.fetchall()]
|
||||
return [('id', 'in', ids)]
|
||||
|
||||
@api.onchange('is_ok')
|
||||
def _onchange_inspection_user_id(self):
|
||||
"""
|
||||
检测is_ok(是否合格)被修改的话,就将当前用户赋值给inspection_user_id
|
||||
"""
|
||||
if not self.inspection_user_id:
|
||||
self.inspection_user_id = self.env.user.id
|
||||
else:
|
||||
self.inspection_user_id = False
|
||||
|
||||
@api.onchange('functional_fixture_id')
|
||||
def _onchange_functional_fixture_id(self):
|
||||
if self.functional_fixture_id:
|
||||
@@ -443,6 +542,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
work.compensation_value_y = eval(self.material_center_point)[1]
|
||||
# work.process_state = '待加工'
|
||||
# self.sudo().production_id.process_state = '待加工'
|
||||
# self.sudo().production_id.process_state = '待加工'
|
||||
self.date_finished = datetime.now()
|
||||
workorder.button_finish()
|
||||
|
||||
@@ -473,6 +573,20 @@ class ResMrpWorkOrder(models.Model):
|
||||
else:
|
||||
raise UserError(_("该工单暂未完成,无法进行工件配送"))
|
||||
|
||||
def button_rework_pre(self):
|
||||
return {
|
||||
'name': _('返工'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'sf.rework.wizard',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_workorder_id': self.id,
|
||||
'default_production_id': self.production_id.id,
|
||||
# 'default_programming_state': self.production_id.programming_state,
|
||||
'default_routing_type': self.routing_type
|
||||
}}
|
||||
|
||||
# 拼接工单对象属性值
|
||||
def json_workorder_str(self, k, production, route, item):
|
||||
# 计算预计时长duration_expected
|
||||
@@ -529,12 +643,16 @@ class ResMrpWorkOrder(models.Model):
|
||||
up_route = self.env['sf.agv.task.route'].search([('route_type', '=', '上产线')], limit=1, order='id asc')
|
||||
down_route = self.env['sf.agv.task.route'].search([('route_type', '=', '下产线')], limit=1, order='id asc')
|
||||
return [
|
||||
[0, '', {'production_id': production.id, 'type': '上产线', 'route_id': up_route.id,
|
||||
'feeder_station_start_id': up_route.start_site_id.id,
|
||||
'feeder_station_destination_id': up_route.end_site_id.id}],
|
||||
[0, '', {'production_id': production.id, 'type': '下产线', 'route_id': down_route.id,
|
||||
'feeder_station_start_id': down_route.start_site_id.id,
|
||||
'feeder_station_destination_id': down_route.end_site_id.id}]]
|
||||
[0, '',
|
||||
{'production_id': production.id, 'production_line_id': production.production_line_id.id, 'type': '上产线',
|
||||
'route_id': up_route.id,
|
||||
'feeder_station_start_id': up_route.start_site_id.id,
|
||||
'feeder_station_destination_id': up_route.end_site_id.id}],
|
||||
[0, '',
|
||||
{'production_id': production.id, 'production_line_id': production.production_line_id.id, 'type': '下产线',
|
||||
'route_id': down_route.id,
|
||||
'feeder_station_start_id': down_route.start_site_id.id,
|
||||
'feeder_station_destination_id': down_route.end_site_id.id}]]
|
||||
|
||||
# 拼接工单对象属性值(表面工艺)
|
||||
def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id):
|
||||
@@ -680,119 +798,6 @@ class ResMrpWorkOrder(models.Model):
|
||||
# 'target':'new'
|
||||
# }
|
||||
|
||||
def recreateManufacturingOrWorkerOrder(self):
|
||||
"""
|
||||
重新生成制造订单或者重新生成工单
|
||||
"""
|
||||
if self.test_results in ['返工', '报废']:
|
||||
values = self.env['mrp.production'].create_production1_values(self.production_id)
|
||||
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
|
||||
self.production_id.company_id).create(
|
||||
values)
|
||||
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
||||
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||
productions._create_workorder()
|
||||
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
|
||||
(
|
||||
p.move_dest_ids.procure_method != 'make_to_order' and
|
||||
not p.move_raw_ids and not p.workorder_ids)).action_confirm()
|
||||
for production_item in productions:
|
||||
process_parameter_workorder = self.env['mrp.workorder'].search(
|
||||
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_item.id),
|
||||
('is_subcontract', '=', True)])
|
||||
if process_parameter_workorder:
|
||||
is_pick = False
|
||||
consecutive_workorders = []
|
||||
m = 0
|
||||
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id)
|
||||
for i in range(len(sorted_workorders) - 1):
|
||||
if m == 0:
|
||||
is_pick = False
|
||||
if sorted_workorders[i].supplier_id.id == sorted_workorders[i + 1].supplier_id.id and \
|
||||
sorted_workorders[i].is_subcontract == sorted_workorders[i + 1].is_subcontract and \
|
||||
sorted_workorders[i].id == sorted_workorders[i + 1].id - 1:
|
||||
if sorted_workorders[i] not in consecutive_workorders:
|
||||
consecutive_workorders.append(sorted_workorders[i])
|
||||
consecutive_workorders.append(sorted_workorders[i + 1])
|
||||
m += 1
|
||||
continue
|
||||
else:
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
|
||||
production_item)
|
||||
if sorted_workorders[i] in consecutive_workorders:
|
||||
is_pick = True
|
||||
consecutive_workorders = []
|
||||
m = 0
|
||||
# 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单
|
||||
if is_pick is False:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i],
|
||||
production_item)
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
|
||||
production_item)
|
||||
if sorted_workorders[i] in consecutive_workorders:
|
||||
is_pick = True
|
||||
consecutive_workorders = []
|
||||
m = 0
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production_item)
|
||||
if is_pick is False and m == 0:
|
||||
if len(sorted_workorders) == 1:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production_item)
|
||||
else:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production_item)
|
||||
|
||||
for production in productions:
|
||||
origin_production = production.move_dest_ids and production.move_dest_ids[
|
||||
0].raw_material_production_id or False
|
||||
orderpoint = production.orderpoint_id
|
||||
if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual':
|
||||
production.message_post(
|
||||
body=_('This production order has been created from Replenishment Report.'),
|
||||
message_type='comment',
|
||||
subtype_xmlid='mail.mt_note')
|
||||
elif orderpoint:
|
||||
production.message_post_with_view(
|
||||
'mail.message_origin_link',
|
||||
values={'self': production, 'origin': orderpoint},
|
||||
subtype_id=self.env.ref('mail.mt_note').id)
|
||||
elif origin_production:
|
||||
production.message_post_with_view(
|
||||
'mail.message_origin_link',
|
||||
values={'self': production, 'origin': origin_production},
|
||||
subtype_id=self.env.ref('mail.mt_note').id)
|
||||
|
||||
'''
|
||||
创建生产计划
|
||||
'''
|
||||
# 工单耗时
|
||||
workorder_duration = 0
|
||||
for workorder in productions.workorder_ids:
|
||||
workorder_duration += workorder.duration_expected
|
||||
|
||||
sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)])
|
||||
if sale_order:
|
||||
sale_order.mrp_production_ids |= productions
|
||||
# sale_order.write({'schedule_status': 'to schedule'})
|
||||
self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({
|
||||
'name': productions.name,
|
||||
'order_deadline': sale_order.deadline_of_delivery,
|
||||
'production_id': productions.id,
|
||||
'date_planned_start': productions.date_planned_start,
|
||||
'origin': productions.origin,
|
||||
'product_qty': productions.product_qty,
|
||||
'product_id': productions.product_id.id,
|
||||
'state': 'draft',
|
||||
})
|
||||
# if self.test_results == '返工':
|
||||
# productions = self.production_id
|
||||
# # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
||||
# # self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||
# productions._create_workorder2(self.processing_panel)
|
||||
# else:
|
||||
# self.results = '合格'
|
||||
|
||||
def json_workorder_str1(self, k, production, route):
|
||||
workorders_values_str = [0, '', {
|
||||
'product_uom_id': production.product_uom_id.id,
|
||||
@@ -816,28 +821,152 @@ class ResMrpWorkOrder(models.Model):
|
||||
}]
|
||||
return workorders_values_str
|
||||
|
||||
# @api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state')
|
||||
# def _compute_state(self):
|
||||
# super(ResMrpWorkOrder, self)._compute_state()
|
||||
# for item in self:
|
||||
# print(item.name)
|
||||
# print(item.state)
|
||||
# print(item.is_remanufacture)
|
||||
# scrap_workorder = self.env['mrp.workorder'].search(
|
||||
# [('production_id', '=', item.production_id.id), ('routing_type', '=', 'CNC加工'),
|
||||
# ('state', '=', 'done'), ('test_results', 'in', ['返工', '报废'])])
|
||||
# print(scrap_workorder)
|
||||
# # if item.routing_type == 'CNC加工' and item.state in ['done'] and item.test_results in ['返工', '报废']:
|
||||
# if item.routing_type == '解除装夹':
|
||||
# if scrap_workorder and item.state not in ['cancel']:
|
||||
# item.state = 'cancel'
|
||||
# elif item.routing_type == '表面工艺':
|
||||
# if scrap_workorder:
|
||||
# stock_move = self.env['stock.move'].search(
|
||||
# [('origin', '=', item.production_id.name)])
|
||||
# stock_move.write({'state': 'cancel'})
|
||||
# item.picking_ids.write({'state': 'cancel'})
|
||||
# item.state = 'cancel'
|
||||
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state',
|
||||
'production_id.tool_state')
|
||||
def _compute_state(self):
|
||||
super()._compute_state()
|
||||
for workorder in self:
|
||||
re_work = self.env['mrp.workorder'].search([('production_id', '=', workorder.production_id.id),
|
||||
('processing_panel', '=', workorder.processing_panel),
|
||||
('is_rework', '=', True), ('state', 'in', ['done', 'rework'])])
|
||||
cnc_workorder = self.env['mrp.workorder'].search(
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('processing_panel', '=', workorder.processing_panel),
|
||||
('routing_type', '=', 'CNC加工'), ('state', 'in', ['done', 'rework']),
|
||||
('test_results', '=', '返工')])
|
||||
cnc_workorder_pending = self.env['mrp.workorder'].search(
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('processing_panel', '=', workorder.processing_panel),
|
||||
('routing_type', '=', 'CNC加工'), ('state', 'in', ['pending'])])
|
||||
unclamp_workorder = self.env['mrp.workorder'].search(
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('sequence', '=', workorder.sequence - 1),
|
||||
('state', 'in', ['done'])])
|
||||
if workorder.state not in ['cancel', 'progress', 'rework']:
|
||||
if workorder.production_id.state == 'rework':
|
||||
if workorder.routing_type == '装夹预调' and workorder.state not in ['done', 'rework',
|
||||
'cancel']:
|
||||
# # 有返工工单
|
||||
# if re_work:
|
||||
# 新工单
|
||||
if workorder.is_rework is False:
|
||||
if workorder.production_id.programming_state == '已编程' and workorder.production_id.is_rework is False:
|
||||
if re_work or cnc_workorder:
|
||||
workorder.state = 'ready'
|
||||
else:
|
||||
if workorder.production_id.is_rework is True:
|
||||
if re_work or cnc_workorder:
|
||||
workorder.state = 'waiting'
|
||||
|
||||
elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'rework', 'cancel']:
|
||||
pre_workorder = self.env['mrp.workorder'].search(
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('processing_panel', '=', workorder.processing_panel),
|
||||
('routing_type', '=', '装夹预调'), ('state', '=', 'done')])
|
||||
if pre_workorder:
|
||||
if re_work:
|
||||
workorder.state = 'waiting'
|
||||
elif workorder.routing_type == '解除装夹' and workorder.state not in ['done', 'rework', 'cancel']:
|
||||
if cnc_workorder:
|
||||
if not cnc_workorder_pending:
|
||||
workorder.state = 'waiting'
|
||||
# else:
|
||||
# if workorder.production_id.is_rework is True:
|
||||
# workorder.state = 'waiting'
|
||||
elif workorder.production_id.state == 'progress':
|
||||
if workorder.routing_type == '装夹预调' and workorder.production_id.programming_state == '已编程' and \
|
||||
workorder.is_rework is False and workorder.state not in [
|
||||
'done', 'rework',
|
||||
'cancel']:
|
||||
if workorder.production_id.is_rework is False:
|
||||
if re_work or cnc_workorder or unclamp_workorder:
|
||||
workorder.state = 'ready'
|
||||
# if (re_work or cnc_workorder) and workorder.production_id.is_rework is False:
|
||||
# workorder.state = 'ready'
|
||||
if workorder.routing_type == '表面工艺' and workorder.state not in ['done', 'progress']:
|
||||
if unclamp_workorder:
|
||||
workorder.state = 'ready'
|
||||
# else:
|
||||
# if workorder.state not in ['cancel', 'rework']:
|
||||
# workorder.state = 'rework'
|
||||
if workorder.routing_type == '装夹预调' and workorder.state in ['waiting', 'ready', 'pending']:
|
||||
workorder_ids = workorder.production_id.workorder_ids
|
||||
work_bo = True
|
||||
for wo in workorder_ids.filtered(lambda a: a.routing_type == '装夹预调' and a.state == 'rework'):
|
||||
if not workorder_ids.filtered(
|
||||
lambda a: (a.routing_type == '装夹预调' and a.state not in ['rework', 'cancel']
|
||||
and a.processing_panel == wo.processing_panel)):
|
||||
work_bo = False
|
||||
break
|
||||
if (workorder.production_id.programming_state == '已编程' and work_bo
|
||||
and not workorder_ids.filtered(lambda a: a.sequence == 0)):
|
||||
# 当工单对应制造订单的功能刀具状态为 【无效刀】时,先对的第一个装夹预调工单状态设置为 【等待组件】
|
||||
if workorder.production_id.tool_state in ['1', '2']:
|
||||
if workorder.state in ['ready']:
|
||||
workorder.state = 'waiting'
|
||||
continue
|
||||
elif workorder.state in ['waiting']:
|
||||
continue
|
||||
elif 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.production_id.tool_state in ['0']:
|
||||
if workorder_ids.filtered(lambda a: a.state == 'rework'):
|
||||
if not workorder_ids.filtered(
|
||||
lambda a: (a.routing_type not in ['装夹预调'] and
|
||||
a.state not in ['pending', 'done', 'rework', 'cancel'])):
|
||||
# 查询工序最小的非完工、非返工的装夹预调工单
|
||||
work_id = self.search(
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('routing_type', '=', '装夹预调'),
|
||||
('state', 'not in', ['rework', 'done', 'cancel'])],
|
||||
limit=1,
|
||||
order="sequence")
|
||||
if workorder == work_id:
|
||||
if workorder.production_id.reservation_state == 'assigned':
|
||||
workorder.state = 'ready'
|
||||
elif workorder.production_id.reservation_state != 'assigned':
|
||||
workorder.state = 'waiting'
|
||||
continue
|
||||
if workorder.production_id.tool_state in ['1', '2'] and workorder.state == 'ready':
|
||||
workorder.state = 'waiting'
|
||||
continue
|
||||
|
||||
# elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'cancel', 'progress',
|
||||
# 'rework']:
|
||||
# per_work = self.env['mrp.workorder'].search(
|
||||
# [('routing_type', '=', '装夹预调'), ('production_id', '=', workorder.production_id.id),
|
||||
# ('processing_panel', '=', workorder.processing_panel), ('is_rework', '=', True)])
|
||||
# if per_work:
|
||||
# workorder.state = 'waiting'
|
||||
# if workorder.routing_type == 'CNC加工' and workorder.state == 'progress':
|
||||
# workorder.state = 'to be detected'
|
||||
|
||||
# for workorder in self:
|
||||
# if workorder.is_rework is True and workorder.state == 'done':
|
||||
# cnc_work = self.env['mrp.workorder'].search([('routing_type','=','CNC加工'),('production_id','=',workorder.production_id.id)])
|
||||
# if cnc_work:
|
||||
# cnc_work.state = 'waiting'
|
||||
# if workorder.state == 'pending':
|
||||
# if all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
|
||||
# workorder.state = 'ready' if workorder.production_id.reservation_state == 'assigned' else 'waiting'
|
||||
# continue
|
||||
# if workorder.state not in ('waiting', 'ready'):
|
||||
# continue
|
||||
# if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
|
||||
# workorder.state = 'pending'
|
||||
# continue
|
||||
# if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'):
|
||||
# continue
|
||||
# if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting':
|
||||
# workorder.state = 'ready'
|
||||
# elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready':
|
||||
# workorder.state = 'waiting'
|
||||
|
||||
# 重写工单开始按钮方法
|
||||
def button_start(self):
|
||||
@@ -856,12 +985,14 @@ class ResMrpWorkOrder(models.Model):
|
||||
limit=1, order='id asc')
|
||||
if not cnc_workorder.cnc_ids:
|
||||
raise UserError(_('该制造订单还未下发CNC程序,请稍后再试'))
|
||||
# else:
|
||||
# for item in cnc_workorder.cnc_ids:
|
||||
# functional_cutting_tool = self.env['sf.functional.cutting.tool.entity'].search(
|
||||
# [('tool_name_id.name', '=', item.cutting_tool_name)])
|
||||
# if not functional_cutting_tool:
|
||||
# raise UserError(_('该制造订单的CNC程序为%s没有对应的功能刀具' % item.cutting_tool_name))
|
||||
else:
|
||||
if self.production_id.tool_state in ['1', '2']:
|
||||
if self.production_id.tool_state == '1':
|
||||
state = '缺刀'
|
||||
else:
|
||||
state = '无效刀'
|
||||
raise UserError(
|
||||
f'制造订单【{self.production_id.name}】功能刀具状态为【{state}】!')
|
||||
if self.routing_type == '解除装夹':
|
||||
'''
|
||||
记录开始时间
|
||||
@@ -876,10 +1007,9 @@ class ResMrpWorkOrder(models.Model):
|
||||
('location_dest_id', '=', self.env['stock.location'].search(
|
||||
[('barcode', 'ilike', 'VL-SPOC')]).id),
|
||||
('origin', '=', self.production_id.name)])
|
||||
purchase = self.env['purchase.order'].search([('origin', '=', self.production_id.name)])
|
||||
if purchase and move_out:
|
||||
if move_out:
|
||||
move_out.write({'state': 'assigned'})
|
||||
self.env['stock.move.line'].create(move_out.get_move_line(purchase, self))
|
||||
self.env['stock.move.line'].create(move_out.get_move_line(self.production_id, self))
|
||||
|
||||
# move_out._action_assign()
|
||||
if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress':
|
||||
@@ -946,7 +1076,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
if record.routing_type == '装夹预调':
|
||||
if not record.material_center_point and record.X_deviation_angle > 0:
|
||||
raise UserError("请对前置三元检测定位参数进行计算定位")
|
||||
if not record.rfid_code:
|
||||
if not record.rfid_code and record.is_rework is False:
|
||||
raise UserError("请扫RFID码进行绑定")
|
||||
record.process_state = '待加工'
|
||||
# record.write({'process_state': '待加工'})
|
||||
@@ -955,6 +1085,15 @@ class ResMrpWorkOrder(models.Model):
|
||||
record.process_state = '待解除装夹'
|
||||
# record.write({'process_state': '待加工'})
|
||||
record.production_id.process_state = '待解除装夹'
|
||||
record.production_id.write({'detection_result_ids': [(0, 0, {
|
||||
'rework_reason': record.reason,
|
||||
'detailed_reason': record.detailed_reason,
|
||||
'processing_panel': record.processing_panel,
|
||||
'routing_type': record.routing_type,
|
||||
'handle_result': '待处理' if record.test_results == '返工' or record.is_rework is True else '',
|
||||
'test_results': record.test_results,
|
||||
'test_report': record.detection_report})],
|
||||
'is_scrap': True if record.test_results == '报废' else False})
|
||||
if record.routing_type == '解除装夹':
|
||||
'''
|
||||
记录结束时间
|
||||
@@ -1003,107 +1142,85 @@ class ResMrpWorkOrder(models.Model):
|
||||
record.write({
|
||||
'date_planned_finished': tem_date_planned_finished # 保持原值
|
||||
})
|
||||
# if record.routing_type == 'CNC加工':
|
||||
# record.write({
|
||||
# 'date_finished': tem_date_finished # 保持原值
|
||||
# })
|
||||
|
||||
# if record.routing_type == 'CNC加工' and record.test_results in ['返工', '报废']:
|
||||
# record.production_id.action_cancel()
|
||||
# record.production_id.workorder_ids.write({'rfid_code': False, 'rfid_code_old': record.rfid_code})
|
||||
# if record.is_remanufacture is True:
|
||||
# record.recreateManufacturingOrWorkerOrder()
|
||||
is_production_id = True
|
||||
for workorder in record.production_id.workorder_ids:
|
||||
if workorder.state != 'done':
|
||||
is_production_id = False
|
||||
if record.routing_type == '解除装夹':
|
||||
is_production_id = False
|
||||
rework_workorder = record.production_id.workorder_ids.filtered(lambda p: p.state == 'rework')
|
||||
done_workorder = record.production_id.workorder_ids.filtered(lambda p1: p1.state == 'done')
|
||||
if (len(rework_workorder) + len(done_workorder) == len(record.production_id.workorder_ids)) or (
|
||||
len(done_workorder) == len(record.production_id.workorder_ids)):
|
||||
is_production_id = True
|
||||
if record.routing_type in ['解除装夹'] or (
|
||||
record.is_rework is True and record.routing_type in ['装夹预调']) or (
|
||||
record.test_results in ['返工', '报废'] and record.routing_type in ['CNC加工']):
|
||||
for workorder in record.production_id.workorder_ids:
|
||||
if workorder.processing_panel == record.processing_panel:
|
||||
rfid_code = workorder.rfid_code
|
||||
workorder.write({'rfid_code_old': rfid_code,
|
||||
'rfid_code': ''})
|
||||
workorder.rfid_code_old = rfid_code
|
||||
workorder.rfid_code = ''
|
||||
'rfid_code': False})
|
||||
if workorder.rfid_code:
|
||||
raise ValidationError(f'【{workorder.name}】工单解绑失败,请重新点击完成按钮!!!')
|
||||
# workorder.rfid_code_old = rfid_code
|
||||
# workorder.rfid_code = False
|
||||
logging.info('workorder.rfid_code:%s' % workorder.rfid_code)
|
||||
if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺']:
|
||||
logging.info('product_qty:%s' % record.production_id.product_qty)
|
||||
for move_raw_id in record.production_id.move_raw_ids:
|
||||
move_raw_id.quantity_done = move_raw_id.product_uom_qty
|
||||
record.process_state = '已完工'
|
||||
record.production_id.process_state = '已完工'
|
||||
if record.routing_type in ['表面工艺']:
|
||||
raw_move = self.env['stock.move'].sudo().search(
|
||||
[('origin', '=', record.production_id.name), ('procure_method', '=', 'make_to_order'),
|
||||
[('origin', '=', record.production_id.name),
|
||||
('procure_method', 'in', ['make_to_order', 'make_to_stock']),
|
||||
('state', '!=', 'done')])
|
||||
if raw_move:
|
||||
raw_move.write({'state': 'done'})
|
||||
record.production_id.button_mark_done1()
|
||||
# self.production_id.state = 'done'
|
||||
# record.production_id.state = 'done'
|
||||
|
||||
# 将FTP的检测报告文件下载到临时目录
|
||||
def download_reportfile_tmp(self, workorder, reportpath):
|
||||
logging.info('reportpath:%s' % reportpath)
|
||||
production_no_ftp = reportpath.split('/')
|
||||
production_no = workorder.production_id.name.replace('/', '_')
|
||||
# ftp地址
|
||||
remotepath = os.path.join('/NC', production_no_ftp[1], 'detection')
|
||||
logging.info('ftp地址:%s' % remotepath)
|
||||
if reportpath.find(production_no) != -1:
|
||||
# 服务器内临时地址
|
||||
serverdir = os.path.join('/tmp', production_no_ftp[1], 'detection')
|
||||
ftp_resconfig = self.env['res.config.settings'].get_values()
|
||||
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']),
|
||||
ftp_resconfig['ftp_user'],
|
||||
ftp_resconfig['ftp_password'])
|
||||
download_state = ftp.download_reportfile_tree(remotepath, serverdir, reportpath)
|
||||
logging.info('download_state:%s' % download_state)
|
||||
else:
|
||||
download_state = 2
|
||||
logging.info('reportpath/ftp地址:%s' % reportpath)
|
||||
logging.info('processing_panel:%s' % workorder.processing_panel)
|
||||
serverdir = os.path.join('/tmp', workorder.production_id.name.replace('/', '_'), 'detection',
|
||||
workorder.processing_panel)
|
||||
ftp_resconfig = self.env['res.config.settings'].get_values()
|
||||
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']),
|
||||
ftp_resconfig['ftp_user'],
|
||||
ftp_resconfig['ftp_password'])
|
||||
if not ftp.file_exists_1(reportpath):
|
||||
logging.info('文件不存在:%s' % reportpath)
|
||||
download_state = ftp.download_program_file(reportpath, serverdir)
|
||||
logging.info('download_state:%s' % download_state)
|
||||
return download_state
|
||||
|
||||
# 根据中控系统提供的检测文件地址去ftp里对应的制造订单里获取
|
||||
def get_detection_file(self, workorder, reportPath):
|
||||
# if reportPath.startswith('/'):
|
||||
# reportPath = reportPath[4:]
|
||||
# serverdir = os.path.join('/tmp', reportPath)
|
||||
serverdir = '/tmp' + reportPath
|
||||
serverdir = os.path.join('/tmp', workorder.production_id.name.replace('/', '_'), 'detection',
|
||||
workorder.processing_panel)
|
||||
logging.info('get_detection_file-serverdir:%s' % serverdir)
|
||||
serverdir_prefix = os.path.dirname(serverdir)
|
||||
logging.info('serverdir_prefix-serverdir:%s' % serverdir_prefix)
|
||||
for root, dirs, files in os.walk(serverdir_prefix):
|
||||
for root, dirs, files in os.walk(serverdir):
|
||||
for filename in files:
|
||||
logging.info('filename:%s' % filename)
|
||||
logging.info('reportPath:%s' % os.path.basename(reportPath))
|
||||
if filename == os.path.basename(reportPath):
|
||||
report_file_path = os.path.join(root, filename)
|
||||
logging.info('get_detection_file-report_file_path:%s' % report_file_path)
|
||||
workorder.detection_report = base64.b64encode(open(report_file_path, 'rb').read())
|
||||
return True
|
||||
|
||||
# 重新下发nc程序
|
||||
def button_send_program_again(self):
|
||||
try:
|
||||
res = {'programming_no': self.production_id.programming_no}
|
||||
configsettings = self.env['res.config.settings'].get_values()
|
||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
||||
url = '/api/intelligent_programming/reset_state_again'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
r = requests.post(config_url, json=res, data=None, headers=config_header)
|
||||
r = r.json()
|
||||
result = json.loads(r['result'])
|
||||
if result['status'] == 1:
|
||||
productions = self.env['mrp.production'].search(
|
||||
[('programming_no', '=', self.production_id.programming_no), ('programming_state', '=', '已编程')])
|
||||
if productions:
|
||||
workorder = productions.workorder_ids.filtered(
|
||||
lambda ap: ap.routing_type in ['装夹预调', 'CNC加工'] and ap.state not in ['done', 'cancel',
|
||||
'progress'])
|
||||
if workorder:
|
||||
workorder.write({'is_send_program_again': True})
|
||||
productions.write({'work_state': '编程中', 'programming_state': '编程中'})
|
||||
else:
|
||||
raise UserError(result['message'])
|
||||
except Exception as e:
|
||||
logging.info('button_send_program_again error:%s' % e)
|
||||
raise UserError("重新下发nc程序失败,请联系管理员")
|
||||
def print_method(self):
|
||||
"""
|
||||
解除装夹处调用关联制造订单的关联序列号的打印方法
|
||||
"""
|
||||
if self.production_id:
|
||||
if self.production_id.lot_producing_id:
|
||||
self.production_id.lot_producing_id.print_single_method()
|
||||
else:
|
||||
raise UserError("无关联制造订单或关联序列号,无法打印。请检查!")
|
||||
|
||||
|
||||
class CNCprocessing(models.Model):
|
||||
@@ -1132,6 +1249,8 @@ class CNCprocessing(models.Model):
|
||||
program_path = fields.Char('程序文件路径')
|
||||
program_create_date = fields.Datetime('程序创建日期')
|
||||
|
||||
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='刀具状态', default='0')
|
||||
|
||||
# mrs下发编程单创建CNC加工
|
||||
def cnc_processing_create(self, cnc_workorder, ret, program_path, program_path_tmp):
|
||||
cnc_processing = None
|
||||
@@ -1165,24 +1284,25 @@ class CNCprocessing(models.Model):
|
||||
|
||||
def _json_cnc_processing(self, panel, ret):
|
||||
cnc_processing = []
|
||||
for item in ret['programming_list']:
|
||||
if item['processing_panel'] == panel and item['ftp_path'].find('.dmi') == -1:
|
||||
cnc_processing.append((0, 0, {
|
||||
'sequence_number': item['sequence_number'],
|
||||
'program_name': item['program_name'],
|
||||
'cutting_tool_name': item['cutting_tool_name'],
|
||||
'cutting_tool_no': item['cutting_tool_no'],
|
||||
'processing_type': item['processing_type'],
|
||||
'margin_x_y': item['margin_x_y'],
|
||||
'margin_z': item['margin_z'],
|
||||
'depth_of_processing_z': item['depth_of_processing_z'],
|
||||
'cutting_tool_extension_length': item['cutting_tool_extension_length'],
|
||||
'cutting_tool_handle_type': item['cutting_tool_handle_type'],
|
||||
'estimated_processing_time': item['estimated_processing_time'],
|
||||
'program_path': item['ftp_path'],
|
||||
'program_create_date': datetime.strptime(item['program_create_date'], '%Y-%m-%d %H:%M:%S'),
|
||||
'remark': item['remark']
|
||||
}))
|
||||
if ret is not False:
|
||||
for item in ret['programming_list']:
|
||||
if item['processing_panel'] == panel and item['ftp_path'].find('.dmi') == -1:
|
||||
cnc_processing.append((0, 0, {
|
||||
'sequence_number': item['sequence_number'],
|
||||
'program_name': item['program_name'],
|
||||
'cutting_tool_name': item['cutting_tool_name'],
|
||||
'cutting_tool_no': item['cutting_tool_no'],
|
||||
'processing_type': item['processing_type'],
|
||||
'margin_x_y': item['margin_x_y'],
|
||||
'margin_z': item['margin_z'],
|
||||
'depth_of_processing_z': item['depth_of_processing_z'],
|
||||
'cutting_tool_extension_length': item['cutting_tool_extension_length'],
|
||||
'cutting_tool_handle_type': item['cutting_tool_handle_type'],
|
||||
'estimated_processing_time': item['estimated_processing_time'],
|
||||
'program_path': item['ftp_path'],
|
||||
'program_create_date': datetime.strptime(item['program_create_date'], '%Y-%m-%d %H:%M:%S'),
|
||||
'remark': item['remark']
|
||||
}))
|
||||
return cnc_processing
|
||||
|
||||
# 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配
|
||||
@@ -1215,11 +1335,13 @@ class CNCprocessing(models.Model):
|
||||
|
||||
# 将FTP的多面的程序单文件下载到临时目录
|
||||
def download_file_tmp(self, production_no, processing_panel):
|
||||
remotepath = os.path.join('/NC', production_no, 'return', processing_panel)
|
||||
remotepath = os.path.join('/home/ftp/ftp_root/NC', production_no, 'return', processing_panel)
|
||||
serverdir = os.path.join('/tmp', production_no, 'return', processing_panel)
|
||||
ftp_resconfig = self.env['res.config.settings'].get_values()
|
||||
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],
|
||||
ftp_resconfig['ftp_password'])
|
||||
if not ftp.file_exists_1(remotepath):
|
||||
logging.info('目录不存在:%s' % remotepath)
|
||||
download_state = ftp.download_program_file(remotepath, serverdir)
|
||||
logging.info('download_state:%s' % download_state)
|
||||
return download_state
|
||||
@@ -1265,6 +1387,7 @@ class SfWorkOrderBarcodes(models.Model):
|
||||
_inherit = ["mrp.workorder", "barcodes.barcode_events_mixin"]
|
||||
|
||||
def on_barcode_scanned(self, barcode):
|
||||
logging.info('Rfid:%s' % barcode)
|
||||
workorder = self.env['mrp.workorder'].browse(self.ids)
|
||||
# workorder_preset = self.env['mrp.workorder'].search(
|
||||
# [('routing_type', '=', '装夹预调'), ('rfid_code', '=', barcode)])
|
||||
@@ -1308,7 +1431,7 @@ class SfWorkOrderBarcodes(models.Model):
|
||||
self.process_state = '待检测'
|
||||
self.date_start = datetime.now()
|
||||
else:
|
||||
raise UserError('该托盘信息不存在!!!')
|
||||
raise UserError('没有找到Rfid为【%s】的托盘信息!!!' % barcode)
|
||||
# stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)])
|
||||
# if stock_move_line.product_id.categ_type == '夹具':
|
||||
# workorder.write({
|
||||
@@ -1382,7 +1505,8 @@ class WorkPieceDelivery(models.Model):
|
||||
[('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型')
|
||||
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
|
||||
status = fields.Selection(
|
||||
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', default='待下发',
|
||||
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送'), ('已取消', '已取消')], string='状态',
|
||||
default='待下发',
|
||||
tracking=True)
|
||||
is_cnc_program_down = fields.Boolean('程序是否下发', default=False, tracking=True)
|
||||
is_manual_work = fields.Boolean('人工操作', default=False)
|
||||
@@ -1635,12 +1759,13 @@ class CMMprogram(models.Model):
|
||||
|
||||
def _json_cmm_program(self, panel, ret):
|
||||
cmm_program = []
|
||||
for item in ret['programming_list']:
|
||||
if item['processing_panel'] == panel and item['ftp_path'].find('.dmi') != -1:
|
||||
cmm_program.append((0, 0, {
|
||||
'sequence_number': 1,
|
||||
'program_name': item['program_name'],
|
||||
'program_path': item['ftp_path'],
|
||||
'program_create_date': datetime.strptime(item['program_create_date'], '%Y-%m-%d %H:%M:%S'),
|
||||
}))
|
||||
if ret is not False:
|
||||
for item in ret['programming_list']:
|
||||
if item['processing_panel'] == panel and item['ftp_path'].find('.dmi') != -1:
|
||||
cmm_program.append((0, 0, {
|
||||
'sequence_number': 1,
|
||||
'program_name': item['program_name'],
|
||||
'program_path': item['ftp_path'],
|
||||
'program_create_date': datetime.strptime(item['program_create_date'], '%Y-%m-%d %H:%M:%S'),
|
||||
}))
|
||||
return cmm_program
|
||||
|
||||
@@ -616,7 +616,7 @@ class ResProductMo(models.Model):
|
||||
item['model_width'] + model_type.embryo_tolerance) * (
|
||||
item['model_height'] + model_type.embryo_tolerance),
|
||||
'product_model_type_id': model_type.id,
|
||||
'model_processing_panel': 'R',
|
||||
# 'model_processing_panel': 'R',
|
||||
'model_machining_precision': item['model_machining_precision'],
|
||||
'model_code': item['barcode'],
|
||||
'length': item['model_long'],
|
||||
@@ -634,6 +634,7 @@ class ResProductMo(models.Model):
|
||||
'model_process_parameters_ids': [(6, 0, [])] if not item.get(
|
||||
'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']),
|
||||
'model_remark': item['remark'],
|
||||
'single_manufacturing': True,
|
||||
'default_code': '%s-%s' % (order_number, i),
|
||||
'manual_quotation': item['manual_quotation'] or False,
|
||||
'part_number': item.get('part_number') or '',
|
||||
|
||||
@@ -205,39 +205,18 @@ class StockRule(models.Model):
|
||||
productions_values)
|
||||
|
||||
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
||||
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
|
||||
(
|
||||
p.move_dest_ids.procure_method != 'make_to_order' and not
|
||||
p.move_raw_ids and not p.workorder_ids)).action_confirm()
|
||||
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||
|
||||
'''
|
||||
创建工单
|
||||
'''
|
||||
# productions._create_workorder()
|
||||
#
|
||||
grouped_product_ids = {k: list(g) for k, g in groupby(productions, key=lambda x: x.product_id.id)}
|
||||
# 初始化一个字典来存储每个product_id对应的生产订单名称列表
|
||||
product_id_to_production_names = {}
|
||||
# 对于每个product_id,获取其所有生产订单的名称
|
||||
for product_id, productions in grouped_product_ids.items():
|
||||
# 为同一个product_id创建一个生产订单名称列表
|
||||
product_id_to_production_names[product_id] = [production.name for production in productions]
|
||||
for production_item in productions:
|
||||
if production_item.product_id.id in product_id_to_production_names:
|
||||
# # 同一个产品多个制造订单对应一个编程单和模型库
|
||||
# # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递
|
||||
if not production_item.programming_no:
|
||||
production_programming = self.env['mrp.production'].search(
|
||||
[('product_id.id', '=', production_item.product_id.id),
|
||||
('origin', '=', production_item.origin)],
|
||||
limit=1, order='id asc')
|
||||
if not production_programming.programming_no:
|
||||
production_item.fetchCNC(
|
||||
', '.join(product_id_to_production_names[production_item.product_id.id]))
|
||||
else:
|
||||
production_item.write({'programming_no': production_programming.programming_no,
|
||||
'programming_state': '编程中'})
|
||||
|
||||
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
|
||||
(
|
||||
p.move_dest_ids.procure_method != 'make_to_order' and not
|
||||
p.move_raw_ids and not p.workorder_ids)).action_confirm()
|
||||
for production in productions:
|
||||
'''
|
||||
创建制造订单时生成序列号
|
||||
@@ -283,6 +262,29 @@ class StockRule(models.Model):
|
||||
'product_id': production.product_id.id,
|
||||
'state': 'draft',
|
||||
})
|
||||
all_production = productions
|
||||
grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)}
|
||||
# 初始化一个字典来存储每个product_id对应的生产订单名称列表
|
||||
product_id_to_production_names = {}
|
||||
# 对于每个product_id,获取其所有生产订单的名称
|
||||
for product_id, all_production in grouped_product_ids.items():
|
||||
# 为同一个product_id创建一个生产订单名称列表
|
||||
product_id_to_production_names[product_id] = [production.name for production in all_production]
|
||||
for production_item in productions:
|
||||
if production_item.product_id.id in product_id_to_production_names:
|
||||
# # 同一个产品多个制造订单对应一个编程单和模型库
|
||||
# # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递
|
||||
if not production_item.programming_no:
|
||||
production_programming = self.env['mrp.production'].search(
|
||||
[('product_id.id', '=', production_item.product_id.id),
|
||||
('origin', '=', production_item.origin)],
|
||||
limit=1, order='id asc')
|
||||
if not production_programming.programming_no:
|
||||
production_item.fetchCNC(
|
||||
', '.join(product_id_to_production_names[production_item.product_id.id]))
|
||||
else:
|
||||
production_item.write({'programming_no': production_programming.programming_no,
|
||||
'programming_state': '编程中'})
|
||||
return True
|
||||
|
||||
|
||||
@@ -403,6 +405,7 @@ class ProductionLot(models.Model):
|
||||
|
||||
def print_single_method(self):
|
||||
|
||||
print('self.name========== %s' % self.name)
|
||||
self.ensure_one()
|
||||
qr_code_data = self.qr_code_image
|
||||
if not qr_code_data:
|
||||
@@ -486,10 +489,10 @@ class StockPicking(models.Model):
|
||||
('location_dest_id', '=', self.env['stock.location'].search(
|
||||
[('barcode', 'ilike', 'VL-SPOC')]).id),
|
||||
('origin', '=', self.origin)])
|
||||
if self.id == move_out.picking_id.id:
|
||||
if move_out.move_line_ids.workorder_id.state not in ['progress']:
|
||||
raise UserError(
|
||||
_('该出库单里源单据内的单号为%s的工单还未开始,不能进行验证操作!' % move_out.move_line_ids.workorder_id.name))
|
||||
# if self.id == move_out.picking_id.id:
|
||||
# if move_out.move_line_ids.workorder_id.state not in ['progress']:
|
||||
# raise UserError(
|
||||
# _('该出库单里源单据内的单号为%s的工单还未开始,不能进行验证操作!' % move_out.move_line_ids.workorder_id.name))
|
||||
# 入库单验证
|
||||
move_in = self.env['stock.move'].search(
|
||||
[('location_dest_id', '=', self.env['stock.location'].search(
|
||||
@@ -505,18 +508,17 @@ class StockPicking(models.Model):
|
||||
res = super().button_validate()
|
||||
if res is True:
|
||||
if self.id == move_out.picking_id.id:
|
||||
if move_out.move_line_ids.workorder_id.state == 'progress':
|
||||
move_in = self.env['stock.move'].search(
|
||||
[('location_dest_id', '=', self.env['stock.location'].search(
|
||||
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
|
||||
('location_id', '=', self.env['stock.location'].search(
|
||||
[('barcode', 'ilike', 'VL-SPOC')]).id),
|
||||
('origin', '=', self.origin)])
|
||||
# purchase = self.env['purchase.order'].search([('origin', '=', self.origin)])
|
||||
if move_in:
|
||||
move_in.write({'state': 'assigned'})
|
||||
purchase = self.env['purchase.order'].search([('origin', '=', self.origin)])
|
||||
self.env['stock.move.line'].create(move_in.get_move_line(purchase, None))
|
||||
# if move_out.move_line_ids.workorder_id.state == 'progress':
|
||||
move_in = self.env['stock.move'].search(
|
||||
[('location_dest_id', '=', self.env['stock.location'].search(
|
||||
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
|
||||
('location_id', '=', self.env['stock.location'].search(
|
||||
[('barcode', 'ilike', 'VL-SPOC')]).id),
|
||||
('origin', '=', self.origin)])
|
||||
production = self.env['mrp.production'].search([('name', '=', self.origin)])
|
||||
if move_in:
|
||||
move_in.write({'state': 'assigned'})
|
||||
self.env['stock.move.line'].create(move_in.get_move_line(production, None))
|
||||
|
||||
return res
|
||||
|
||||
@@ -598,7 +600,7 @@ class ReStockMove(models.Model):
|
||||
'state': 'confirmed',
|
||||
}
|
||||
|
||||
def get_move_line(self, purchase, sorted_workorders):
|
||||
def get_move_line(self, production_id, sorted_workorders):
|
||||
return {
|
||||
'move_id': self.id,
|
||||
'product_id': self.product_id.id,
|
||||
@@ -607,7 +609,7 @@ class ReStockMove(models.Model):
|
||||
'location_dest_id': self.picking_id.location_dest_id.id,
|
||||
'picking_id': self.picking_id.id,
|
||||
'reserved_uom_qty': 1.0,
|
||||
'lot_id': purchase.picking_ids.move_line_ids.lot_id.id,
|
||||
'lot_id': production_id.move_line_raw_ids.lot_id.id,
|
||||
'company_id': self.company_id.id,
|
||||
# 'workorder_id': '' if not sorted_workorders else sorted_workorders.id,
|
||||
# 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id,
|
||||
|
||||
@@ -29,7 +29,7 @@ access_mrp_workorder_group_sf_mrp_user,mrp_workorder,model_mrp_workorder,sf_base
|
||||
access_mrp_workorder_manager,mrp_workorder,model_mrp_workorder,sf_base.group_sf_mrp_manager,1,1,1,0
|
||||
access_mrp_workcenter_group_sf_mrp_user,mrp_workcenter,model_mrp_workcenter,sf_base.group_sf_mrp_user,1,0,0,0
|
||||
access_mrp_workcenter_manager,mrp_workcenter,model_mrp_workcenter,sf_base.group_sf_mrp_manager,1,1,1,0
|
||||
access_mrp_workcenter_productivity_group_sf_mrp_user,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_mrp_user,1,0,0,0
|
||||
access_mrp_workcenter_productivity_group_sf_equipment_user,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_equipment_user,1,1,1,0
|
||||
access_mrp_workcenter_productivity_manager,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_mrp_manager,1,1,1,0
|
||||
access_sf_workpiece_delivery_group_sf_order_user,sf_workpiece_delivery_group_sf_order_user,model_sf_workpiece_delivery,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_sf_workpiece_delivery_group_sf_equipment_user,sf_workpiece_delivery_group_sf_equipment_user,model_sf_workpiece_delivery,sf_base.group_sf_equipment_user,1,1,0,0
|
||||
@@ -141,3 +141,14 @@ access_sf_model_type_group_sf_stock_manager,sf_model_type_group_sf_mrp_manager,m
|
||||
access_mrp_bom_byproduct_group_sf_stock_user,mrp_bom_byproduct_group_sf_stock_user,mrp.model_mrp_bom_byproduct,sf_base.group_sf_stock_user,1,0,0,0
|
||||
access_mrp_bom_byproduct_group_sf_stock_manager,mrp_bom_byproduct_group_sf_mrp_manager,mrp.model_mrp_bom_byproduct,sf_base.group_sf_stock_manager,1,0,0,0
|
||||
|
||||
access_sf_rework_wizard_group_sf_order_user,sf_rework_wizard_group_sf_order_user,model_sf_rework_wizard,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_sf_rework_wizard_group_plan_dispatch,sf_rework_wizard_group_plan_dispatch,model_sf_rework_wizard,sf_base.group_plan_dispatch,1,1,1,0
|
||||
access_sf_detection_result_group_sf_order_user,sf_detection_result_group_sf_order_user,model_sf_detection_result,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_sf_detection_result_group_plan_dispatch,sf_detection_result_group_plan_dispatch,model_sf_detection_result,sf_base.group_plan_dispatch,1,1,1,0
|
||||
access_sf_detection_result_group_sf_equipment_user,sf_detection_result_group_sf_equipment_user,model_sf_detection_result,sf_base.group_sf_equipment_user,1,1,1,0
|
||||
access_sf_processing_panel_group_sf_order_user,sf_processing_panel_group_sf_order_user,model_sf_processing_panel,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_sf_production_wizard_group_sf_order_user,sf_production_wizard_group_sf_order_user,model_sf_production_wizard,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_sf_processing_panel_group_plan_dispatch,sf_processing_panel_group_plan_dispatch,model_sf_processing_panel,sf_base.group_plan_dispatch,1,1,1,0
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1,11 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="custom_mrp_production_tree_view" model="ir.ui.view">
|
||||
<field name="name">custom.mrp.production.tree</field>
|
||||
<field name="model">mrp.production</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_production_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- <xpath expr="//button[@name='do_unreserve']" position="after">-->
|
||||
<!-- <button name="do_update_program" type="object" string="更新程序"-->
|
||||
<!-- groups="sf_base.group_sf_mrp_user"/>-->
|
||||
<!-- </xpath>-->
|
||||
<xpath expr="//field[@name='product_id']" position="replace"/>
|
||||
<xpath expr="//field[@name='product_qty']" position="replace"/>
|
||||
<xpath expr="//field[@name='product_uom_id']" position="replace"/>
|
||||
@@ -65,31 +70,38 @@
|
||||
<!-- <attribute name="statusbar_visible">draft,confirmed,progress,pending_processing,completed,done -->
|
||||
<!-- </attribute> -->
|
||||
<attribute name="statusbar_visible">
|
||||
progress,pending_cam,pending_processing,pending_era_cam,completed,done
|
||||
confirmed,pending_cam,progress,done
|
||||
</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet//group//group[2]//label" position="before">
|
||||
<!-- <field name="process_state"/> -->
|
||||
<field name="state"/>
|
||||
<field name="state" readonly="1"/>
|
||||
<!-- <field name="process_state"/> -->
|
||||
|
||||
</xpath>
|
||||
<xpath expr="//sheet//group//group//div[3]" position="after">
|
||||
<field name="manual_quotation" readonly="1"/>
|
||||
<field name="programming_no" readonly="1"/>
|
||||
<field name="programming_state" readonly="1"
|
||||
decoration-success="programming_state == '已编程'"
|
||||
decoration-warning="programming_state =='编程中'"
|
||||
decoration-danger="programming_state =='已编程未下发'"/>
|
||||
<field name="work_state" invisible="1"/>
|
||||
<field name="schedule_state" invisible='1'/>
|
||||
<field name="manual_quotation" readonly="1"/>
|
||||
<field name="programming_state" readonly="1"/>
|
||||
<field name="is_scrap" invisible='1'/>
|
||||
<field name="is_rework" invisible='1'/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='user_id']" position="before">
|
||||
<field name="plan_start_processing_time" readonly="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='user_id']" position="after">
|
||||
<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_drawing"/>
|
||||
<field name="tool_state"/>
|
||||
<field name="tool_state_remark" string="备注" attrs="{'invisible': [('tool_state', '!=', '1')]}"/>
|
||||
<field name="tool_state_remark2" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//header//button[@name='action_cancel']" position="replace">
|
||||
<button name="action_cancel" type="object" string="取消" data-hotkey="z"
|
||||
@@ -106,9 +118,20 @@
|
||||
<xpath expr="(//header//button[@name='button_mark_done'])[2]" position="replace">
|
||||
<button name="button_mark_done"
|
||||
attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}"
|
||||
string="验证" type="object" class="oe_highlight" data-hotkey="g"
|
||||
string="验证" type="object" data-hotkey="g"
|
||||
groups="sf_base.group_sf_mrp_user"/>
|
||||
</xpath>
|
||||
<xpath expr="(//header//button[@name='button_scrap'])" position="replace">
|
||||
<button name="button_scrap" invisible="1"/>
|
||||
<button name="do_update_program" string="更新程序" type="object" groups="sf_base.group_sf_mrp_user"
|
||||
confirm="是否确认更新程序"
|
||||
attrs="{'invisible': ['|',('state', '!=', 'rework'),('programming_state', '!=', '已编程未下发')]}"/>
|
||||
<button name="button_rework" string="返工" type="object" groups="sf_base.group_sf_mrp_user"
|
||||
attrs="{'invisible': ['|',('state', '!=', 'rework') ,('programming_state', '!=', '已编程')]}"/>
|
||||
<!-- <button name="%(sf_manufacturing.action_sf_production_wizard)d" string="报废" type="action"-->
|
||||
<!-- groups="sf_base.group_sf_mrp_user"-->
|
||||
<!-- attrs="{'invisible': [('is_scrap', '=', False)]}"/>-->
|
||||
</xpath>
|
||||
<xpath expr="(//header//button[@name='button_mark_done'])[3]" position="replace">
|
||||
<button name="button_mark_done" attrs="{'invisible': [
|
||||
'|',
|
||||
@@ -138,11 +161,11 @@
|
||||
attrs="{'invisible': ['|', ('is_planned', '=', False), ('state', '=', 'cancel')]}"
|
||||
data-hotkey="x" groups="sf_base.group_sf_mrp_user"/>
|
||||
</xpath>
|
||||
<xpath expr="//header//button[@name='button_scrap']" position="replace">
|
||||
<button name="button_scrap" type="object" string="报废"
|
||||
attrs="{'invisible': [('state', 'in', ('cancel', 'draft'))]}" data-hotkey="y"
|
||||
groups="sf_base.group_sf_mrp_user"/>
|
||||
</xpath>
|
||||
<!-- <xpath expr="//header//button[@name='button_scrap']" position="replace">-->
|
||||
<!-- <button name="button_scrap" type="object" string="报废"-->
|
||||
<!-- attrs="{'invisible': [('state', 'in', ('cancel', 'draft'))]}" data-hotkey="y"-->
|
||||
<!-- groups="sf_base.group_sf_mrp_user"/>-->
|
||||
<!-- </xpath>-->
|
||||
|
||||
|
||||
<xpath expr="//header//button[@name='action_confirm']" position="replace">
|
||||
@@ -255,7 +278,35 @@
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet//notebook//page[@name='operations']" position="attributes">
|
||||
<attribute name="attrs">{'invisible': [('schedule_state', '=', '未排')]}</attribute>
|
||||
<attribute name="attrs">{'invisible': ['|',('schedule_state', '=', '未排'),('workorder_ids', '=',
|
||||
[])]}
|
||||
</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet//notebook//page[@name='operations']" position="after">
|
||||
<page string="检测结果" attrs="{'invisible': [('detection_result_ids', '=', [])]}">
|
||||
<field name="detection_result_ids" string="" readonly="1">
|
||||
<tree sample="1">
|
||||
<field name="production_id" invisible="1"/>
|
||||
<field name="processing_panel"/>
|
||||
<field name="routing_type"/>
|
||||
<field name="rework_reason"/>
|
||||
<field name="detailed_reason"/>
|
||||
<field name="test_results"/>
|
||||
<field name="handle_result"/>
|
||||
<field name="test_report" invisible="1"/>
|
||||
<button name="button_look_test_report" string="查看测试报告" type="object"
|
||||
attrs="{'invisible': [('test_report', '=', False)]}"
|
||||
class="btn btn-primary me-1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="//sheet//notebook//page[@name='components']" position="attributes">
|
||||
<attribute name="string">投料</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='components_availability']" position="attributes">
|
||||
<attribute name="string">投料状态</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
@@ -278,11 +329,23 @@
|
||||
<field name="model">mrp.workorder</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_production_workorder_tree_editable_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//tree" position="attributes">
|
||||
<attribute name="default_order">sequence</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='state']" position="replace">
|
||||
<field name="state" widget="badge" decoration-warning="state == 'progress'"
|
||||
decoration-success="state == 'done'" decoration-danger="state in ('cancel','rework')"
|
||||
decoration-muted="state == 'to be detected'"
|
||||
decoration-info="state not in ('progress', 'done', 'cancel','rework','to be detected')"
|
||||
attrs="{'invisible': [('production_state', '=', 'draft')], 'column_invisible': [('parent.state', '=', 'draft')]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//tree//button[@name='button_start']" position="replace">
|
||||
<field name="routing_type" invisible="True"/>
|
||||
<button name="button_start" type="object" string="开始" class="btn-success"
|
||||
attrs="{'invisible': ['|', '|', '|','|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False), ('routing_type', '=', 'CNC加工')]}"
|
||||
groups="sf_base.group_sf_mrp_user" confirm="是否确认开始?"/>
|
||||
<button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始?"
|
||||
attrs="{'invisible': ['|', '|', '|','|', ('production_state','in', ('draft', 'done', 'cancel')),
|
||||
('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=',
|
||||
False), ('routing_type', '=', 'CNC加工')]}"
|
||||
groups="sf_base.group_sf_mrp_user"/>
|
||||
</xpath>
|
||||
<xpath expr="//tree//button[@name='button_pending']" position="replace">
|
||||
<button name="button_pending" type="object" string="Pause" class="btn-warning"
|
||||
@@ -291,7 +354,7 @@
|
||||
</xpath>
|
||||
<xpath expr="//tree//button[@name='button_finish']" position="replace">
|
||||
<button name="button_finish" type="object" string="Done" class="btn-success"
|
||||
attrs="{'invisible': ['|', '|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"
|
||||
attrs="{'invisible': ['|', '|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"
|
||||
groups="sf_base.group_sf_mrp_user"
|
||||
confirm="是否确认完成?"/>
|
||||
</xpath>
|
||||
@@ -361,7 +424,9 @@
|
||||
<xpath expr="//header//button[@name='action_cancel']" position="replace">
|
||||
<button name="action_cancel" type="object" string="取消" groups="sf_base.group_sf_mrp_user"/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='state']" position="after">
|
||||
<field name="tool_state" invisible="1"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -393,6 +458,24 @@
|
||||
<field name="model">mrp.production</field>
|
||||
<field name="inherit_id" ref="mrp.view_mrp_production_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//filter[@name='filter_in_progress']" position="before">
|
||||
<filter string="返工" name="filter_rework" domain="[('state', '=', 'rework')]"/>
|
||||
</xpath>
|
||||
<xpath expr="//filter[@name='planning_issues']" position="before">
|
||||
<separator/>
|
||||
<filter string="返工且已编程" name="filter_rework_programmed"
|
||||
domain="[('state', '=', 'rework'),('programming_state', '=', '已编程')]"/>
|
||||
<filter string="返工且已编程未下发" name="filter_rework_programmed_not_delivered"
|
||||
domain="[('state', '=', 'rework'),('programming_state', '=', '已编程未下发')]"/>
|
||||
<separator/>
|
||||
<filter name="filter_programming" string="编程中"
|
||||
domain="[('programming_state', '=', '编程中')]"/>
|
||||
<filter name="filter_programmed" string="已编程"
|
||||
domain="[('programming_state', '=', '已编程')]"/>
|
||||
<filter name="filter_programmed_not_delivered" string="已编程未下发"
|
||||
domain="[('programming_state', '=', '已编程未下发')]"/>
|
||||
<separator/>
|
||||
</xpath>
|
||||
<xpath expr="//search" position="inside">
|
||||
<searchpanel class="account_root">
|
||||
<field name="state" icon="fa-filter" enable_counters="1"/>
|
||||
@@ -478,5 +561,72 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.ui.view" id="sf_test_report_form">
|
||||
<field name="name">sf.detection.result</field>
|
||||
<field name="model">sf.detection.result</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group>
|
||||
<!-- <field name="handle_result"/>-->
|
||||
<field name="test_report" readonly="1" widget="pdf_viewer"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_test_report_form" model="ir.actions.act_window">
|
||||
<field name="name">检测报告</field>
|
||||
<field name="res_model">sf.detection.result</field>
|
||||
<field name="view_mode">form</field>
|
||||
</record>
|
||||
<!-- <menuitem action="mrp.mrp_production_action"-->
|
||||
<!-- id="mrp_production_action"-->
|
||||
<!-- sequence="1" active="False"/>-->
|
||||
|
||||
<!-- <!– <record id="mrp_production_action_sf" model="ir.actions.act_window">–>-->
|
||||
<!-- <!– <field name="name">Manufacturing Orders</field>–>-->
|
||||
<!-- <!– <field name="type">ir.actions.act_window</field>–>-->
|
||||
<!-- <!– <field name="res_model">mrp.production</field>–>-->
|
||||
<!-- <!– <field name="view_mode">tree,kanban,form,calendar,pivot,graph</field>–>-->
|
||||
<!-- <!– <field name="search_view_id" ref="mrp.view_mrp_production_filter"/>–>-->
|
||||
<!-- <!– <!– <field name="context">{'search_default_todo': True, 'default_company_id': allowed_company_ids[0]}</field>–>–>-->
|
||||
<!-- <!– <field name="domain">[('picking_type_id.active', '=', True)]</field>–>-->
|
||||
<!-- <!– </record>–>-->
|
||||
<!-- <!– <menuitem action="mrp_production_action_sf"–>-->
|
||||
<!-- <!– id="menu_mrp_production_action_sf"–>-->
|
||||
<!-- <!– parent="mrp.menu_mrp_manufacturing"–>-->
|
||||
<!-- <!– sequence="2"–>-->
|
||||
<!-- <!– string="制造订单"/>–>-->
|
||||
<!-- <record id="mrp_production_action_sf" model="ir.actions.act_window">-->
|
||||
<!-- <field name="name">Manufacturing Orders</field>-->
|
||||
<!-- <field name="type">ir.actions.act_window</field>-->
|
||||
<!-- <field name="res_model">mrp.production</field>-->
|
||||
<!-- <field name="view_mode">tree,kanban,form,calendar,pivot,graph</field>-->
|
||||
<!-- <field name="view_id" eval="False"/>-->
|
||||
<!-- <field name="search_view_id" ref="mrp.view_mrp_production_filter"/>-->
|
||||
<!-- <field name="context">{'search_default_todo': True, 'default_company_id':-->
|
||||
<!-- allowed_company_ids[0],'search_default_filter_rework':1,'search_default_filter_programmed':1}-->
|
||||
<!-- </field>-->
|
||||
<!-- <field name="domain">[('picking_type_id.active', '=', True)]</field>-->
|
||||
<!-- <!– <!– <field name="help" type="html">–>,'search_default_filter_rework': 1,–>-->
|
||||
<!-- <!– 'search_default_filter_programming': 1–>-->
|
||||
<!-- <!– <p class="o_view_nocontent_smiling_face">–>-->
|
||||
<!-- <!– No manufacturing order found. Let's create one.–>-->
|
||||
<!-- <!– </p>–>-->
|
||||
<!-- <!– <p>–>-->
|
||||
<!-- <!– Consume <a name="%(product.product_template_action)d" type='action' tabindex="-1">components</a> and–>-->
|
||||
<!-- <!– build finished products using–>-->
|
||||
<!-- <!– <a name="%(mrp_bom_form_action)d" type='action' tabindex="-1">bills of materials</a>–>-->
|
||||
<!-- <!– </p>–>-->
|
||||
<!-- <!– </field>–>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<!-- <menuitem action="sf_manufacturing.mrp_production_action_sf"-->
|
||||
<!-- id="mrp_production_action"-->
|
||||
<!-- parent="mrp.menu_mrp_manufacturing"-->
|
||||
<!-- sequence="1"/>-->
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -24,6 +24,20 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="custom_model_form_view_inherit" model="ir.ui.view">
|
||||
<field name="name">custom.model.form.view.inherit</field>
|
||||
<field name="model">mrp.workcenter</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_workcenter_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//form//sheet' position="after">
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="message_ids"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="mrp_workcenter_view_kanban_inherit_workorder" model="ir.ui.view">
|
||||
<field name="name">mrp.workcenter.view.kanban.inherit.mrp.workorder</field>
|
||||
<field name="model">mrp.workcenter</field>
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="replace">
|
||||
<field name="is_subcontract" invisible="1"/>
|
||||
|
||||
<field name="name" decoration-success="is_subcontract" decoration-bf="is_subcontract"/>
|
||||
</field>
|
||||
<field name="name" position="before">
|
||||
<field name="sequence" optional="hide"/>
|
||||
<field name="sequence"/>
|
||||
<field name='user_permissions' invisible="1"/>
|
||||
</field>
|
||||
<field name="name" position="after">
|
||||
@@ -19,6 +18,7 @@
|
||||
</field>
|
||||
<field name="state" position="after">
|
||||
<field name="work_state" optional="hide"/>
|
||||
<field name="tool_state" invisible="1"/>
|
||||
<field name="product_tmpl_name" invisible="1"/>
|
||||
</field>
|
||||
<field name="duration" position="replace">
|
||||
@@ -43,7 +43,7 @@
|
||||
<attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',
|
||||
'done',
|
||||
'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')),
|
||||
('is_user_working', '!=', False),("user_permissions","=",False),("name","=","获取CNC加工程序")]}
|
||||
('is_user_working', '!=', False),("user_permissions","=",False),("name","=","CNC加工")]}
|
||||
</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="attributes">
|
||||
@@ -91,7 +91,7 @@
|
||||
<!-- <field name="target">fullscreen</field>-->
|
||||
<field name="target">current</field>
|
||||
<field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>
|
||||
<field name="context">{'search_default_workcenter_id': active_id}</field>
|
||||
<field name="context">{'search_default_product': 1, 'search_default_workcenter_id': active_id}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_workorder">
|
||||
没有工单要做!
|
||||
@@ -113,6 +113,10 @@
|
||||
<field name="model">mrp.workorder</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header/field[@name='state']" position="replace">
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button type="object" name="action_view_surface_technics_picking" class="oe_stat_button" icon="fa-truck"
|
||||
groups="base.group_user,sf_base.group_sf_order_user"
|
||||
@@ -121,10 +125,12 @@
|
||||
</button>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='state']" position="before">
|
||||
<field name='tool_state' invisible="1"/>
|
||||
<field name='user_permissions' invisible="1"/>
|
||||
<field name='name' invisible="1"/>
|
||||
<field name='is_rework' invisible="1"/>
|
||||
<field name='is_delivery' invisible="1"/>
|
||||
<field name='is_send_program_again' invisible="1"/>
|
||||
<!-- <field name='is_send_program_again' invisible="1"/>-->
|
||||
<!-- 工单form页面的开始停工按钮等 -->
|
||||
<!-- <button name="button_start" type="object" string="开始" class="btn-success" -->
|
||||
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','ready'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" -->
|
||||
@@ -136,8 +142,8 @@
|
||||
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','progress'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" -->
|
||||
<!-- groups="sf_base.group_sf_mrp_user" confirm="是否确认完工"/> -->
|
||||
|
||||
<button name="button_start" type="object" string="开始" class="btn-success"
|
||||
attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False)]}"/>
|
||||
<button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"
|
||||
attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>
|
||||
<button name="button_pending" type="object" string="暂停" class="btn-warning"
|
||||
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
|
||||
<button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工"
|
||||
@@ -159,12 +165,12 @@
|
||||
<!-- groups="sf_base.group_sf_mrp_user" -->
|
||||
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> -->
|
||||
<button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary"
|
||||
attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('is_delivery','=',True),('state','!=','done')]}"/>
|
||||
<button name="button_send_program_again" type="object" string="重新下发NC程序" class="btn-primary"
|
||||
confirm="是否确认重新下发NC程序?"
|
||||
groups="sf_base.group_sf_order_user,sf_base.group_sf_equipment_user"
|
||||
attrs="{'invisible': ['|', '|', '|',('routing_type','!=','装夹预调'),('state','in',['done', 'cancel',
|
||||
'progress']),('cnc_worksheet','=',False),('is_send_program_again','=',True)]}"/>
|
||||
attrs="{'invisible': ['|','|','|','|',('routing_type','!=','装夹预调'),('is_delivery','=',True),('state','!=','done'),('is_rework','=',True),'&',('rfid_code','in',['',False]),('state','=','done')]}"/>
|
||||
<button name="button_rework_pre" type="object" string="返工"
|
||||
class="btn-primary"
|
||||
attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('state','!=','progress'),('is_rework','=',True)]}"/>
|
||||
<button name="print_method" type="object" string="打印二维码" class="btn-primary"
|
||||
attrs="{'invisible': ['|',('routing_type','!=','解除装夹'),('state','!=','done')]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//page[1]" position="before">
|
||||
<page string="开料要求" attrs='{"invisible": [("routing_type","!=","切割")]}'>
|
||||
@@ -183,8 +189,11 @@
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="//label[1]" position="before">
|
||||
<field name='routing_type'/>
|
||||
<field name='routing_type' readonly="1"/>
|
||||
<field name='process_state' attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
||||
<field name="rfid_code" force_save="1" readonly="1" cache="True"
|
||||
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
|
||||
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//label[1]" position="attributes">
|
||||
<attribute name="string">计划加工时间</attribute>
|
||||
@@ -215,11 +224,11 @@
|
||||
attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
|
||||
<field name="processing_panel" readonly="1"
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
|
||||
<field name="equipment_id"
|
||||
<field name="equipment_id" readonly="1"
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/>
|
||||
<field name="production_line_id"
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
|
||||
<field name="production_line_state"
|
||||
<field name="production_line_state" readonly="1"
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/>
|
||||
<!-- <field name="functional_fixture_id" -->
|
||||
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> -->
|
||||
@@ -227,9 +236,6 @@
|
||||
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> -->
|
||||
<!-- <field name="functional_fixture_type_id" -->
|
||||
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> -->
|
||||
<field name="rfid_code" force_save="1" readonly="1" cache="True"
|
||||
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
|
||||
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
|
||||
</group>
|
||||
<!-- <group>-->
|
||||
<!-- <div>-->
|
||||
@@ -242,23 +248,6 @@
|
||||
<!-- <field name="processing_panel" readonly="1" attrs="{'invisible': [('routing_type', 'in', ('获取CNC加工程序','装夹','解除装夹',-->
|
||||
<!-- '前置三元定位检测','后置三元质量检测','解除装夹'))]}"/>-->
|
||||
</field>
|
||||
|
||||
<xpath expr="//page[1]" position="before">
|
||||
<page string="获取CNC加工程序" attrs='{"invisible": [("routing_type","!=","获取CNC加工程序")]}'>
|
||||
<group>
|
||||
<field name="programming_no" readonly="1"
|
||||
attrs='{"invisible": [("programming_no","=",False)]}'/>
|
||||
<field name="programming_state" readonly="1"
|
||||
attrs='{"invisible": [("programming_no","=",False)]}'/>
|
||||
</group>
|
||||
<!-- <group>-->
|
||||
<!-- <div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap">-->
|
||||
<!-- <button type="object" class="oe_highlight" name="fetchCNC" string="获取CNC程序代码"-->
|
||||
<!-- />-->
|
||||
<!-- </div>-->
|
||||
<!-- </group>-->
|
||||
</page>
|
||||
</xpath>
|
||||
<!-- <page string="Components" name="components">-->
|
||||
<xpath expr="//page[1]" position="before">
|
||||
<!-- <page string="装夹托盘" attrs='{"invisible": [("routing_type","!=","装夹")]}'>-->
|
||||
@@ -483,7 +472,11 @@
|
||||
<field name="production_line_id" readonly="1"/>
|
||||
<field name="task_delivery_time" readonly="1"/>
|
||||
<field name="task_completion_time" readonly="1"/>
|
||||
<field name="status" readonly="1"/>
|
||||
<field name="status" readonly="1" widget="badge"
|
||||
decoration-success="status == '已配送'"
|
||||
decoration-warning="status == '待下发'"
|
||||
decoration-danger="status == '待配送'"
|
||||
decoration-info="status== '已取消'"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
@@ -495,16 +488,18 @@
|
||||
<field name="results" invisible="1"/>
|
||||
<page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||
<group>
|
||||
<field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/>
|
||||
<field name="test_results"
|
||||
attrs='{"readonly":[("state","!=","to be detected")],"invisible":[("results","!=",False)]}'/>
|
||||
<!-- <field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/>-->
|
||||
<!-- <field name="is_fetchcnc"-->
|
||||
<!-- attrs='{"invisible":["|",("test_results","=","合格"),("is_remanufacture","=",False)]}'/>-->
|
||||
<!-- <field name="reason"-->
|
||||
<!-- attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/>-->
|
||||
<!-- <field name="detailed_reason" attrs='{"invisible":[("test_results","=","合格")]}'/>-->
|
||||
<!-- <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>-->
|
||||
<field name="reason"
|
||||
attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/>
|
||||
<field name="detailed_reason"
|
||||
attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/>
|
||||
<!-- <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>-->
|
||||
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
|
||||
widget="pdf_viewer"/>
|
||||
widget="pdf_viewer" readonly="1"/>
|
||||
</group>
|
||||
<!-- <div class="col-12 col-lg-6 o_setting_box">-->
|
||||
<!-- <button type="object" class="oe_highlight" name="recreateManufacturingOrWorkerOrder"-->
|
||||
@@ -521,6 +516,7 @@
|
||||
<field name="sequence_number"/>
|
||||
<field name="program_name"/>
|
||||
<field name="cutting_tool_name"/>
|
||||
<field name="tool_state"/>
|
||||
<field name="cutting_tool_no"/>
|
||||
<field name="processing_type"/>
|
||||
<field name="margin_x_y"/>
|
||||
@@ -575,9 +571,6 @@
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//form//sheet//group//group//div[3]" position="after">
|
||||
<field name="is_ok" attrs='{"invisible": [("routing_type","=","装夹预调")]}'/>
|
||||
<field name="processing_user_id" attrs='{"invisible": [("routing_type","=","装夹预调")]}'/>
|
||||
<field name="inspection_user_id" attrs='{"invisible": [("routing_type","=","装夹预调")]}'/>
|
||||
<field name="save_name" widget="CopyClipboardChar"
|
||||
attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/>
|
||||
<label for="material_length" string="物料尺寸"/>
|
||||
@@ -592,9 +585,6 @@
|
||||
<field name="material_height" class="o_address_zip"/>
|
||||
</div>
|
||||
<field name="part_number" string="成品的零件图号"/>
|
||||
<field name="rfid_code" force_save="1" readonly="1" cache="True"
|
||||
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
|
||||
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
@@ -607,6 +597,9 @@
|
||||
<field name="product_id" position="after">
|
||||
<field name="part_number" string="成品零件图号"/>
|
||||
</field>
|
||||
<xpath expr="//filter[@name='progress']" position="after">
|
||||
<filter string="待检测" name="state" domain="[('state','=','to be detected')]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -643,7 +636,9 @@
|
||||
<field name="status" widget="badge"
|
||||
decoration-success="status == '已配送'"
|
||||
decoration-warning="status == '待下发'"
|
||||
decoration-danger="status == '待配送'"/>
|
||||
decoration-danger="status == '待配送'"
|
||||
decoration-info="status == '已取消'"
|
||||
/>
|
||||
<field name="name"/>
|
||||
<field name="production_id"/>
|
||||
<field name="type" readonly="1"/>
|
||||
@@ -729,7 +724,7 @@
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
、
|
||||
<record id="sf_workpiece_delivery_act" model="ir.actions.act_window">
|
||||
<field name="name">工件配送</field>
|
||||
<field name="res_model">sf.workpiece.delivery</field>
|
||||
@@ -739,7 +734,7 @@
|
||||
</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">
|
||||
[('type','in',['上产线','下产线']),('workorder_state','=','done'),('is_manual_work','=',false)]
|
||||
[('type','in',['上产线','下产线']),('workorder_state','in',['done','rework']),('is_manual_work','=',false)]
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<field name="model">sf.maintenance.logs</field>
|
||||
<field name="inherit_id" ref="sf_maintenance.view_maintenance_logs_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='code']" position="after">
|
||||
<xpath expr="//field[@name='type']" position="after">
|
||||
<field name="production_line_id" optional="hide"/>
|
||||
</xpath>
|
||||
</field>
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
from . import workpiece_delivery_wizard
|
||||
from . import rework_wizard
|
||||
from . import production_wizard
|
||||
|
||||
21
sf_manufacturing/wizard/production_wizard.py
Normal file
21
sf_manufacturing/wizard/production_wizard.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
|
||||
import logging
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from datetime import datetime
|
||||
from odoo import models, api, fields, _
|
||||
|
||||
|
||||
class ProductionWizard(models.TransientModel):
|
||||
_name = 'sf.production.wizard'
|
||||
_description = '制造订单向导'
|
||||
|
||||
production_id = fields.Many2one('mrp.production', string='制造订单号')
|
||||
is_reprogramming = fields.Boolean(string='申请重新编程', default=True)
|
||||
is_remanufacture = fields.Boolean(string='重新生成制造订单', default=True)
|
||||
|
||||
def confirm(self):
|
||||
if self.is_reprogramming is True:
|
||||
self.production_id.update_programming_state()
|
||||
self.production_id.action_cancel()
|
||||
|
||||
34
sf_manufacturing/wizard/production_wizard_views.xml
Normal file
34
sf_manufacturing/wizard/production_wizard_views.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="sf_production_wizard_form_view">
|
||||
<field name="name">sf.production.wizard.form.view</field>
|
||||
<field name="model">sf.production.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<field name="production_id" invisible="True"/>
|
||||
<div>
|
||||
重新生成制造订单
|
||||
<field name="is_remanufacture"/>
|
||||
</div>
|
||||
<div>
|
||||
申请重新编程
|
||||
<field name="is_reprogramming" attrs='{"invisible": [("is_remanufacture","=",False)]}'/>
|
||||
</div>
|
||||
<footer>
|
||||
<button string="确认" name="confirm" type="object" class="oe_highlight" confirm="是否确认报废"/>
|
||||
<button string="取消" class="btn btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_sf_production_wizard" model="ir.actions.act_window">
|
||||
<field name="name">报废</field>
|
||||
<field name="res_model">sf.production.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
200
sf_manufacturing/wizard/rework_wizard.py
Normal file
200
sf_manufacturing/wizard/rework_wizard.py
Normal file
@@ -0,0 +1,200 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
|
||||
import logging
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from datetime import datetime
|
||||
from odoo import models, api, fields, _
|
||||
|
||||
|
||||
class ReworkWizard(models.TransientModel):
|
||||
_name = 'sf.rework.wizard'
|
||||
_description = '返工向导'
|
||||
|
||||
workorder_id = fields.Many2one('mrp.workorder', string='工单')
|
||||
product_id = fields.Many2one('product.product')
|
||||
production_id = fields.Many2one('mrp.production', string='制造订单号')
|
||||
rework_reason = fields.Selection(
|
||||
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"),
|
||||
("operate computer", "操机"),
|
||||
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因")
|
||||
detailed_reason = fields.Text('详细原因')
|
||||
routing_type = fields.Selection([
|
||||
('装夹预调', '装夹预调'),
|
||||
('CNC加工', 'CNC加工')], string="工序类型")
|
||||
# 根据工单的加工面来显示
|
||||
processing_panel_id = fields.Many2many('sf.processing.panel', string="加工面")
|
||||
is_reprogramming = fields.Boolean(string='申请重新编程', default=False)
|
||||
is_reprogramming_readonly = fields.Boolean(string='申请重新编程(只读)', default=False)
|
||||
reprogramming_num = fields.Integer('重新编程次数', default=0)
|
||||
programming_state = fields.Selection(
|
||||
[('待编程', '待编程'), ('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'),
|
||||
('已下发', '已下发')],
|
||||
string='编程状态')
|
||||
|
||||
tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state')
|
||||
|
||||
def confirm(self):
|
||||
if self.routing_type in ['装夹预调', 'CNC加工']:
|
||||
self.workorder_id.is_rework = True
|
||||
self.production_id.write({'detection_result_ids': [(0, 0, {
|
||||
'rework_reason': self.rework_reason,
|
||||
'detailed_reason': self.detailed_reason,
|
||||
'processing_panel': self.workorder_id.processing_panel,
|
||||
'routing_type': self.workorder_id.routing_type,
|
||||
'handle_result': '待处理' if self.workorder_id.test_results == '返工' or self.workorder_id.is_rework is True else '',
|
||||
'test_results': '返工' if not self.routing_type == 'CNC加工' else self.workorder_id.test_results,
|
||||
'test_report': self.workorder_id.detection_report})]})
|
||||
self.workorder_id.button_finish()
|
||||
else:
|
||||
if self.production_id.workorder_ids:
|
||||
handle_result = self.production_id.detection_result_ids.filtered(
|
||||
lambda dr: dr.handle_result == '待处理')
|
||||
if handle_result:
|
||||
processing_panels_to_handle = set(handle_item.processing_panel for handle_item in handle_result)
|
||||
processing_panels_choice = set(dr_panel.name for dr_panel in self.processing_panel_id)
|
||||
# 使用集合的差集操作找出那些待处理结果中有但实际可用加工面中没有的加工面
|
||||
processing_panels_missing = processing_panels_to_handle - processing_panels_choice
|
||||
# 存在不一致的加工面
|
||||
if processing_panels_missing:
|
||||
processing_panels_str = ','.join(processing_panels_missing)
|
||||
raise UserError('您还有待处理的检测结果中为%s的加工面未选择' % processing_panels_str)
|
||||
# processing_panels = set()
|
||||
# for handle_item in handle_result:
|
||||
# for dr_panel in self.processing_panel_id:
|
||||
# if dr_panel.name == handle_item.processing_panel:
|
||||
# processing_panels.add(dr_panel.name)
|
||||
# if len(processing_panels) != len(handle_result):
|
||||
# processing_panels_str = ','.join(processing_panels)
|
||||
# return UserError(f'您还有待处理的检测结果中为{processing_panels_str}的加工面未选择')
|
||||
for panel in self.processing_panel_id:
|
||||
panel_workorder = self.production_id.workorder_ids.filtered(
|
||||
lambda ap: ap.processing_panel == panel.name and ap.state != 'rework')
|
||||
if panel_workorder:
|
||||
panel_workorder.write({'state': 'rework'})
|
||||
panel_workorder.filtered(
|
||||
lambda wo: wo.routing_type == '装夹预调').workpiece_delivery_ids.filtered(
|
||||
lambda wd: wd.status == '待下发').write({'status': '已取消'})
|
||||
# workpiece = self.env['sf.workpiece.delivery'].search([('status', '=', '待下发'), (
|
||||
# 'workorder_id', '=',
|
||||
# panel_workorder.filtered(lambda wd: wd.routing_type == '装夹预调').id)])
|
||||
product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search(
|
||||
[('product_model_type_id', '=', self.production_id.product_id.product_model_type_id.id)],
|
||||
order='sequence asc'
|
||||
)
|
||||
workorders_values = []
|
||||
for route in product_routing_workcenter:
|
||||
if route.is_repeat is True:
|
||||
workorders_values.append(
|
||||
self.env['mrp.workorder'].json_workorder_str(panel.name,
|
||||
self.production_id, route, False))
|
||||
if workorders_values:
|
||||
self.production_id.write({'workorder_ids': workorders_values, 'is_rework': True})
|
||||
self.production_id._reset_work_order_sequence()
|
||||
self.production_id.detection_result_ids.filtered(
|
||||
lambda ap1: ap1.processing_panel == panel.name and ap1.handle_result == '待处理').write(
|
||||
{'handle_result': '已处理'})
|
||||
if self.is_reprogramming is False:
|
||||
if self.programming_state in ['已编程', '已下发']:
|
||||
if self.reprogramming_num >= 1 and self.programming_state == '已编程':
|
||||
self.production_id.get_new_program(panel.name)
|
||||
if self.reprogramming_num >= 0 and self.programming_state == '已下发':
|
||||
ret = {'programming_list': []}
|
||||
cnc_rework = max(
|
||||
self.production_id.workorder_ids.filtered(
|
||||
lambda
|
||||
crw: crw.processing_panel == panel.name and crw.state == 'rework' and crw.routing_type == 'CNC加工'),
|
||||
key=lambda w: w.create_date
|
||||
)
|
||||
if cnc_rework.cnc_ids:
|
||||
for item_line in cnc_rework.cnc_ids:
|
||||
vals = {
|
||||
'sequence_number': item_line.sequence_number,
|
||||
'program_name': item_line.program_name,
|
||||
'cutting_tool_name': item_line.cutting_tool_name,
|
||||
'cutting_tool_no': item_line.cutting_tool_no,
|
||||
'processing_type': item_line.processing_type,
|
||||
'margin_x_y': item_line.margin_x_y,
|
||||
'margin_z': item_line.margin_z,
|
||||
'depth_of_processing_z': item_line.depth_of_processing_z,
|
||||
'cutting_tool_extension_length': item_line.cutting_tool_extension_length,
|
||||
'estimated_processing_time': item_line.estimated_processing_time,
|
||||
'cutting_tool_handle_type': item_line.cutting_tool_handle_type,
|
||||
'program_path': item_line.program_path,
|
||||
'ftp_path': item_line.program_path,
|
||||
'processing_panel': panel.name,
|
||||
'program_create_date': datetime.strftime(item_line.program_create_date,
|
||||
'%Y-%m-%d %H:%M:%S'),
|
||||
'remark': item_line.remark
|
||||
}
|
||||
ret['programming_list'].append(vals)
|
||||
for cmm_line in cnc_rework.cmm_ids:
|
||||
vals = {
|
||||
'sequence_number': cmm_line.sequence_number,
|
||||
'program_name': cmm_line.program_name,
|
||||
'program_path': cmm_line.program_path,
|
||||
'ftp_path': cmm_line.program_path,
|
||||
'processing_panel': panel.name,
|
||||
'program_create_date': datetime.strftime(
|
||||
cmm_line.program_create_date,
|
||||
'%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
ret['programming_list'].append(vals)
|
||||
new_cnc_workorder = self.production_id.workorder_ids.filtered(
|
||||
lambda ap1: ap1.processing_panel == panel.name and ap1.state not in (
|
||||
'rework', 'done') and ap1.routing_type == 'CNC加工')
|
||||
if not new_cnc_workorder.cnc_ids:
|
||||
new_cnc_workorder.write({
|
||||
'cnc_ids': new_cnc_workorder.cnc_ids.sudo()._json_cnc_processing(panel.name,
|
||||
ret),
|
||||
'cmm_ids': new_cnc_workorder.cmm_ids.sudo()._json_cmm_program(panel.name,
|
||||
ret),
|
||||
'cnc_worksheet': cnc_rework.cnc_worksheet})
|
||||
new_pre_workorder = self.production_id.workorder_ids.filtered(lambda
|
||||
p: p.routing_type == '装夹预调' and p.processing_panel == panel.name and p.state not in (
|
||||
'rework', 'done'))
|
||||
if new_pre_workorder:
|
||||
pre_rework = max(self.production_id.workorder_ids.filtered(
|
||||
lambda pr: pr.processing_panel == panel.name and pr.state in (
|
||||
'rework') and pr.routing_type == '装夹预调'),
|
||||
key=lambda w1: w1.create_date)
|
||||
new_pre_workorder.write(
|
||||
{'processing_drawing': pre_rework.processing_drawing})
|
||||
self.production_id.write({'state': 'progress', 'is_rework': False})
|
||||
elif self.programming_state in ['待编程', '编程中']:
|
||||
self.production_id.write(
|
||||
{'programming_state': '编程中', 'work_state': '编程中', 'is_rework': True})
|
||||
if self.is_reprogramming is True:
|
||||
self.production_id.update_programming_state()
|
||||
self.production_id.write(
|
||||
{'programming_state': '编程中', 'work_state': '编程中'})
|
||||
if self.production_id.state == 'progress':
|
||||
self.production_id.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||||
if self.reprogramming_num >= 1 and self.programming_state == '已编程':
|
||||
productions_not_delivered = self.env['mrp.production'].search(
|
||||
[('programming_no', '=', self.production_id.programming_no),
|
||||
('programming_state', '=', '已编程未下发')])
|
||||
if productions_not_delivered:
|
||||
productions_not_delivered.write(
|
||||
{'state': 'progress', 'programming_state': '已编程', 'work_state': '已编程',
|
||||
'is_rework': False})
|
||||
|
||||
@api.onchange('production_id')
|
||||
def onchange_processing_panel_id(self):
|
||||
for item in self:
|
||||
domain = [('id', '=', False)]
|
||||
production_id = item.production_id
|
||||
if production_id:
|
||||
if self.env.user.has_group('sf_base.group_sf_order_user'):
|
||||
panel_ids = []
|
||||
panel_arr = production_id.product_id.model_processing_panel
|
||||
for p in production_id.detection_result_ids.filtered(
|
||||
lambda ap1: ap1.handle_result == '待处理'):
|
||||
if p.processing_panel not in panel_arr:
|
||||
panel_arr += ','.join(p.processing_panel)
|
||||
for item in panel_arr.split(','):
|
||||
panel = self.env['sf.processing.panel'].search(
|
||||
[('name', 'ilike', item)])
|
||||
if panel:
|
||||
panel_ids.append(panel.id)
|
||||
domain = {'processing_panel_id': [('id', 'in', panel_ids)]}
|
||||
return {'domain': domain}
|
||||
67
sf_manufacturing/wizard/rework_wizard_views.xml
Normal file
67
sf_manufacturing/wizard/rework_wizard_views.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="sf_rework_wizard_form_view">
|
||||
<field name="name">sf.rework.wizard.form.view</field>
|
||||
<field name="model">sf.rework.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<field name="production_id" invisible="True"/>
|
||||
<field name="workorder_id" invisible="True"/>
|
||||
<field name="product_id" invisible="True"/>
|
||||
<field name="tool_state" invisible="True"/>
|
||||
<field name="routing_type" invisible="True"/>
|
||||
<group>
|
||||
<field name="processing_panel_id" options="{'no_create': True}"
|
||||
attrs='{"invisible": [("routing_type","=","装夹预调")]}' widget="many2many_tags"/>
|
||||
</group>
|
||||
<div attrs='{"invisible": [("reprogramming_num","=",0)]}'>
|
||||
注意: 该制造订单的产品已重复编程过<field
|
||||
name="reprogramming_num" string=""
|
||||
readonly="1"
|
||||
style='color:red;'/>次,且当前编程状态为
|
||||
<field name="programming_state" string=""
|
||||
decoration-info="programming_state == '待编程'"
|
||||
decoration-success="programming_state == '已下发'"
|
||||
decoration-warning="programming_state =='编程中'"
|
||||
decoration-danger="programming_state =='已编程'" readonly="1"/>
|
||||
</div>
|
||||
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","not in",["已下发"])],"readonly": [("tool_state", "=", "2")]}'>
|
||||
<span style='font-weight:bold;'>申请重新编程
|
||||
<field name="is_reprogramming" force_save="1"
|
||||
attrs='{"readonly": [("tool_state", "=", "2")]}'/>
|
||||
</span>
|
||||
</div>
|
||||
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","in",["已下发"])],"readonly": ["|",("is_reprogramming_readonly","=",False),("tool_state", "=", "2")]}'>
|
||||
<span style='font-weight:bold;'>申请重新编程
|
||||
<field name="is_reprogramming_readonly"
|
||||
attrs='{"readonly": ["|",("is_reprogramming_readonly","=",False),("tool_state", "=", "2")]}'/>
|
||||
</span>
|
||||
</div>
|
||||
<group>
|
||||
<!-- <field name="is_reprogramming" force_save="1"-->
|
||||
<!-- attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","not in",["已下发"])]}'/>-->
|
||||
<!-- <field name="is_reprogramming_readonly" string="申请重新编程"-->
|
||||
<!-- attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","in",["已下发"])],"readonly": [("is_reprogramming_readonly","=",False)]}'/>-->
|
||||
<field name="rework_reason"
|
||||
attrs='{"invisible": [("routing_type","not in",["装夹预调","CNC加工"])],"required": [("routing_type","in",["装夹预调"])]}'/>
|
||||
<field name="detailed_reason"
|
||||
attrs='{"invisible": [("routing_type","not in",["装夹预调","CNC加工"])],"required": [("routing_type","in",["装夹预调"])]}'/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="确认" name="confirm" type="object" class="oe_highlight" confirm="是否确认返工"/>
|
||||
<button string="取消" class="btn btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_sf_rework_wizard" model="ir.actions.act_window">
|
||||
<field name="name">返工</field>
|
||||
<field name="res_model">sf.rework.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -28,67 +28,92 @@ class Sf_Mrs_Connect(http.Controller):
|
||||
request.env.ref("base.user_admin")).search(
|
||||
[('programming_no', '=', ret['programming_no'])])
|
||||
if productions:
|
||||
# 拉取所有加工面的程序文件
|
||||
# # 拉取所有加工面的程序文件
|
||||
for r in ret['processing_panel'].split(','):
|
||||
program_path_tmp_r = os.path.join('/tmp', ret['folder_name'], 'return', r)
|
||||
files_r = os.listdir(program_path_tmp_r)
|
||||
if files_r:
|
||||
for file_name in files_r:
|
||||
file_path = os.path.join(program_path_tmp_r, file_name)
|
||||
os.remove(file_path)
|
||||
download_state = request.env['sf.cnc.processing'].with_user(
|
||||
request.env.ref("base.user_admin")).download_file_tmp(
|
||||
ret['folder_name'], r)
|
||||
if download_state == 0:
|
||||
res['status'] = -2
|
||||
res['message'] = '制造订单号为%s的CNC程序文件从FTP拉取失败' % (cnc_production.name)
|
||||
return json.JSONEncoder().encode(res)
|
||||
if os.path.exists(program_path_tmp_r):
|
||||
files_r = os.listdir(program_path_tmp_r)
|
||||
if files_r:
|
||||
for file_name in files_r:
|
||||
file_path = os.path.join(program_path_tmp_r, file_name)
|
||||
os.remove(file_path)
|
||||
download_state = request.env['sf.cnc.processing'].with_user(
|
||||
request.env.ref("base.user_admin")).download_file_tmp(
|
||||
ret['folder_name'], r)
|
||||
if download_state is False:
|
||||
res['status'] = -2
|
||||
res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no'])
|
||||
return json.JSONEncoder().encode(res)
|
||||
for production in productions:
|
||||
if not production.workorder_ids:
|
||||
production.product_id.model_processing_panel = ret['processing_panel']
|
||||
production._create_workorder(ret)
|
||||
else:
|
||||
for panel in ret['processing_panel'].split(','):
|
||||
# 查询状态为进行中且工序类型为CNC加工的工单
|
||||
cnc_workorder = production.workorder_ids.filtered(
|
||||
lambda ac: ac.routing_type == 'CNC加工' and ac.state not in ['progress', 'done',
|
||||
'cancel'] and ac.processing_panel == panel)
|
||||
if cnc_workorder:
|
||||
if cnc_workorder.cnc_ids:
|
||||
cnc_workorder.cmm_ids.sudo().unlink()
|
||||
cnc_workorder.cnc_ids.sudo().unlink()
|
||||
request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
|
||||
production)
|
||||
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
|
||||
# panel)
|
||||
program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel)
|
||||
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)
|
||||
files_panel = os.listdir(program_path_tmp_panel)
|
||||
if files_panel:
|
||||
for file in files_panel:
|
||||
file_extension = os.path.splitext(file)[1]
|
||||
logging.info('file_extension:%s' % file_extension)
|
||||
if file_extension.lower() == '.pdf':
|
||||
panel_file_path = os.path.join(program_path_tmp_panel, file)
|
||||
logging.info('panel_file_path:%s' % panel_file_path)
|
||||
cnc_workorder.write(
|
||||
{'is_send_program_again': False,
|
||||
'cnc_ids': cnc_workorder.cnc_ids.sudo()._json_cnc_processing(panel, ret),
|
||||
'cmm_ids': cnc_workorder.cmm_ids.sudo()._json_cmm_program(panel, ret),
|
||||
'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
pre_workorder = production.workorder_ids.filtered(
|
||||
lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done',
|
||||
'cancel'] and ap.processing_panel == panel)
|
||||
if pre_workorder:
|
||||
pre_workorder.write(
|
||||
{'is_send_program_again': False,
|
||||
'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
# else:
|
||||
# for panel in ret['processing_panel'].split(','):
|
||||
# # 查询状态为进行中且工序类型为CNC加工的工单
|
||||
# cnc_workorder = production.workorder_ids.filtered(
|
||||
# lambda ac: ac.routing_type == 'CNC加工' and ac.state not in ['progress', 'done',
|
||||
# 'cancel'] and ac.processing_panel == panel)
|
||||
# if cnc_workorder:
|
||||
# if cnc_workorder.cnc_ids:
|
||||
# cnc_workorder.cmm_ids.sudo().unlink()
|
||||
# cnc_workorder.cnc_ids.sudo().unlink()
|
||||
# request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
|
||||
# production)
|
||||
# # program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
|
||||
# # panel)
|
||||
# program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel)
|
||||
# logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)
|
||||
# files_panel = os.listdir(program_path_tmp_panel)
|
||||
# if files_panel:
|
||||
# for file in files_panel:
|
||||
# file_extension = os.path.splitext(file)[1]
|
||||
# logging.info('file_extension:%s' % file_extension)
|
||||
# if file_extension.lower() == '.pdf':
|
||||
# panel_file_path = os.path.join(program_path_tmp_panel, file)
|
||||
# logging.info('panel_file_path:%s' % panel_file_path)
|
||||
# cnc_workorder.write(
|
||||
# {'cnc_ids': cnc_workorder.cnc_ids.sudo()._json_cnc_processing(panel, ret),
|
||||
# 'cmm_ids': cnc_workorder.cmm_ids.sudo()._json_cmm_program(panel, ret),
|
||||
# 'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
# pre_workorder = production.workorder_ids.filtered(
|
||||
# lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done',
|
||||
# 'cancel'] and ap.processing_panel == panel)
|
||||
# if pre_workorder:
|
||||
# pre_workorder.write(
|
||||
# {'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
for panel in ret['processing_panel'].split(','):
|
||||
# 查询状态为进行中且工序类型为CNC加工的工单
|
||||
cnc_workorder = productions.workorder_ids.filtered(
|
||||
lambda ac: ac.routing_type == 'CNC加工' and ac.state not in ['progress', 'done',
|
||||
'cancel'] and ac.processing_panel == panel)
|
||||
if cnc_workorder:
|
||||
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
|
||||
# panel)
|
||||
program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel)
|
||||
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)
|
||||
files_panel = os.listdir(program_path_tmp_panel)
|
||||
if files_panel:
|
||||
for file in files_panel:
|
||||
file_extension = os.path.splitext(file)[1]
|
||||
logging.info('file_extension:%s' % file_extension)
|
||||
if file_extension.lower() == '.pdf':
|
||||
panel_file_path = os.path.join(program_path_tmp_panel, file)
|
||||
logging.info('panel_file_path:%s' % panel_file_path)
|
||||
cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
pre_workorder = productions.workorder_ids.filtered(
|
||||
lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done',
|
||||
'cancel'] and ap.processing_panel == panel)
|
||||
if pre_workorder:
|
||||
pre_workorder.write(
|
||||
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||||
cnc_program_ids = [item.id for item in productions]
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[('production_id', 'in', cnc_program_ids)])
|
||||
if workpiece_delivery:
|
||||
workpiece_delivery.write({'is_cnc_program_down': True})
|
||||
workpiece_delivery.write(
|
||||
{'is_cnc_program_down': True, 'production_line_id': productions.production_line_id.id})
|
||||
return json.JSONEncoder().encode(res)
|
||||
else:
|
||||
res = {'status': 0, 'message': '该制造订单暂未开始'}
|
||||
|
||||
@@ -21,6 +21,23 @@ class FtpController():
|
||||
except Exception:
|
||||
logging.info("ftp连接失败")
|
||||
|
||||
def file_exists_1(self, path):
|
||||
# 检查文件是否存在于FTP服务器上
|
||||
try:
|
||||
logging.info("path:%s" % path)
|
||||
logging.info("dirname:%s" % os.path.dirname(path))
|
||||
directories = os.path.normpath(path).split(os.path.sep)
|
||||
# 切换到上级目录
|
||||
for directory in directories:
|
||||
if directory:
|
||||
# 检查目录是否存在
|
||||
if (directory in ['NC']) or (directory not in ['home', 'ftp', 'ftp_root', 'NC']):
|
||||
self.ftp.cwd(directory)
|
||||
return os.path.basename(path)
|
||||
except Exception as e:
|
||||
logging.error(f"Error checking file: {e}")
|
||||
return False
|
||||
|
||||
def file_exists(self, path):
|
||||
# 检查文件是否存在于FTP服务器上
|
||||
try:
|
||||
@@ -32,8 +49,25 @@ class FtpController():
|
||||
logging.error(f"Error checking file: {e}")
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# 下载目录下的pdf文件(程序单/检测文件)
|
||||
def download_program_file(self, target_dir, serverdir):
|
||||
if not os.path.exists(serverdir):
|
||||
os.makedirs(serverdir)
|
||||
try:
|
||||
logging.info('FTP目录:%s' % target_dir)
|
||||
logging.info("进入FTP目录 ")
|
||||
remotenames = self.ftp.nlst()
|
||||
logging.info('FTP目录文件:%s' % remotenames)
|
||||
for file in remotenames:
|
||||
server = os.path.join(serverdir, file)
|
||||
if file.find(".pdf") != -1:
|
||||
self.download_file(server, file)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
finally:
|
||||
self.ftp.quit()
|
||||
logging.info("ftp已关闭")
|
||||
|
||||
# # 检测字符串的编码
|
||||
# def detect_encoding(self, s):
|
||||
|
||||
@@ -326,6 +326,8 @@ class sfProductionProcess(models.Model):
|
||||
production_process.name = item['name']
|
||||
production_process.category_id = category.id
|
||||
production_process.remark = item['remark']
|
||||
production_process.processing_day = item['processing_day']
|
||||
production_process.travel_day = item['travel_day']
|
||||
production_process.active = item['active']
|
||||
else:
|
||||
self.create({
|
||||
@@ -333,6 +335,8 @@ class sfProductionProcess(models.Model):
|
||||
"category_id": category.id,
|
||||
"code": item['code'],
|
||||
"remark": item['remark'],
|
||||
"processing_day": item['processing_day'],
|
||||
"travel_day": item['travel_day'],
|
||||
"active": item['active'],
|
||||
})
|
||||
else:
|
||||
@@ -358,12 +362,16 @@ class sfProductionProcess(models.Model):
|
||||
"category_id": category.id,
|
||||
"code": item['code'],
|
||||
"remark": item['remark'],
|
||||
"processing_day": item['processing_day'],
|
||||
"travel_day": item['travel_day'],
|
||||
"active": item['active'],
|
||||
})
|
||||
else:
|
||||
production_process.name = item['name']
|
||||
production_process.category_id = category.id
|
||||
production_process.remark = item['remark']
|
||||
production_process.processing_day = item['processing_day']
|
||||
production_process.travel_day = item['travel_day']
|
||||
production_process.active = item['active']
|
||||
else:
|
||||
raise ValidationError("表面工艺认证未通过")
|
||||
@@ -1073,6 +1081,9 @@ class sfProductionProcessParameter(models.Model):
|
||||
[('code', '=', item['process_id_code'])])
|
||||
if production_process_parameter:
|
||||
production_process_parameter.name = item['name']
|
||||
production_process_parameter.process_description = item['process_description']
|
||||
production_process_parameter.processing_day = item['processing_day']
|
||||
production_process_parameter.travel_day = item['travel_day']
|
||||
production_process_parameter.active = item['active']
|
||||
production_process_parameter.process_id = process.id
|
||||
production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search(
|
||||
@@ -1080,6 +1091,9 @@ class sfProductionProcessParameter(models.Model):
|
||||
else:
|
||||
self.create({
|
||||
"name": item['name'],
|
||||
"process_description": item['process_description'],
|
||||
"processing_day": item['processing_day'],
|
||||
"travel_day": item['travel_day'],
|
||||
"code": item['code'],
|
||||
"active": item['active'],
|
||||
"process_id": process.id,
|
||||
@@ -1107,6 +1121,9 @@ class sfProductionProcessParameter(models.Model):
|
||||
if not production_process_parameter:
|
||||
self.create({
|
||||
"name": item['name'],
|
||||
"process_description": item['process_description'],
|
||||
"processing_day": item['processing_day'],
|
||||
"travel_day": item['travel_day'],
|
||||
"code": item['code'],
|
||||
"active": item['active'],
|
||||
"process_id": process.id,
|
||||
@@ -1115,6 +1132,9 @@ class sfProductionProcessParameter(models.Model):
|
||||
})
|
||||
else:
|
||||
production_process_parameter.name = item['name']
|
||||
production_process_parameter.process_description = item['process_description']
|
||||
production_process_parameter.processing_day = item['processing_day']
|
||||
production_process_parameter.travel_day = item['travel_day']
|
||||
production_process_parameter.process_id = process.id
|
||||
production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search(
|
||||
[('materials_no', 'in', item['materials_model_ids_codes'])])
|
||||
|
||||
@@ -37,7 +37,7 @@ class sf_production_plan(models.Model):
|
||||
_order = 'state_order asc, write_date desc'
|
||||
|
||||
name = fields.Char(string='制造订单')
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
# active = fields.Boolean(string='已归档', default=True)
|
||||
# selected = fields.Boolean(default=False)
|
||||
# order_number = fields.Char(string='订单号')
|
||||
order_deadline = fields.Datetime(string='订单交期')
|
||||
@@ -101,17 +101,17 @@ class sf_production_plan(models.Model):
|
||||
# return super(sf_production_plan, self.with_context(active_test=False))._search(
|
||||
# args, offset, limit, order, count, access_rights_uid)
|
||||
|
||||
def archive(self):
|
||||
"""
|
||||
归档
|
||||
"""
|
||||
self.write({'active': False})
|
||||
|
||||
def unarchive(self):
|
||||
"""
|
||||
取消归档
|
||||
"""
|
||||
self.write({'active': True})
|
||||
# def archive(self):
|
||||
# """
|
||||
# 归档
|
||||
# """
|
||||
# self.write({'active': False})
|
||||
#
|
||||
# def unarchive(self):
|
||||
# """
|
||||
# 取消归档
|
||||
# """
|
||||
# self.write({'active': True})
|
||||
|
||||
@api.model
|
||||
def get_import_templates(self):
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
<group>
|
||||
<group string="基本信息">
|
||||
<field name="active" invisible="1"/>
|
||||
<!-- <field name="active" invisible="1"/> -->
|
||||
<field name="production_id" widget="many2one_button"/>
|
||||
<field name="product_id"/>
|
||||
<field name="origin"/>
|
||||
@@ -217,11 +217,11 @@
|
||||
</li>
|
||||
<li>
|
||||
<strong>订单交期:</strong>
|
||||
<t t-out="order_deadline"/>
|
||||
<t t-out="order_deadline.format('L LTS')"/>
|
||||
</li>
|
||||
<li>
|
||||
<strong>产品名称:</strong>
|
||||
<t t-out="product_id"/>
|
||||
<t t-out="product_id[1]"/>
|
||||
</li>
|
||||
<li>
|
||||
<strong>数量:</strong>
|
||||
@@ -268,7 +268,8 @@
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.production.plan</field>
|
||||
<field name="view_mode">tree,gantt,form</field>
|
||||
<field name="context">{'search_default_group_by_state': 1, 'search_default_draft': 1, 'display_complete': True}</field>
|
||||
<!-- <field name="context">{'search_default_group_by_state': 1, 'search_default_draft': 1, 'display_complete': True}</field> -->
|
||||
<field name="context">{'search_default_draft': 1, 'display_complete': True}</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -158,7 +158,7 @@ class QuickEasyOrder(models.Model):
|
||||
payload = {
|
||||
'file_path': new_file_path,
|
||||
'dest_path': new_folder_path,
|
||||
'back_url': config['bfm_url']
|
||||
'back_url': config['bfm_url_new']
|
||||
}
|
||||
response = requests.post(url, json=payload, headers=headers)
|
||||
if response.status_code == 200:
|
||||
|
||||
@@ -44,7 +44,6 @@ class ReSaleOrder(models.Model):
|
||||
store=True, readonly=False, precompute=True, check_company=True, tracking=True,
|
||||
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
|
||||
remark = fields.Text('备注')
|
||||
|
||||
validity_date = fields.Date(
|
||||
string="Expiration",
|
||||
compute='_compute_validity_date',
|
||||
@@ -113,6 +112,7 @@ class ReSaleOrder(models.Model):
|
||||
'price_unit': product.list_price,
|
||||
'product_uom_qty': item['number'],
|
||||
'model_glb_file': base64.b64decode(item['model_file']),
|
||||
'remark': item.get('remark')
|
||||
}
|
||||
return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
|
||||
|
||||
@@ -151,6 +151,7 @@ class ResaleOrderLine(models.Model):
|
||||
# # without modifying the related product_id when updated.
|
||||
# domain=[('sale_ok', '=', True), ('categ_type', '=', '成品')])
|
||||
check_status = fields.Selection(related='order_id.check_status')
|
||||
remark = fields.Char('备注')
|
||||
|
||||
@api.depends('product_template_id')
|
||||
def _compute_model_glb_file(self):
|
||||
@@ -171,6 +172,11 @@ class ProductTemplate(models.Model):
|
||||
class RePurchaseOrder(models.Model):
|
||||
_inherit = 'purchase.order'
|
||||
|
||||
mrp_production_count = fields.Integer(
|
||||
"Count of MO Source",
|
||||
compute='_compute_mrp_production_count',
|
||||
groups='mrp.group_mrp_user,sf_base.group_purchase,sf_base.group_purchase_director')
|
||||
|
||||
remark = fields.Text('备注')
|
||||
user_id = fields.Many2one(
|
||||
'res.users', string='买家', index=True, tracking=True,
|
||||
@@ -251,33 +257,33 @@ class ResPartnerToSale(models.Model):
|
||||
# if obj:
|
||||
# raise UserError('该邮箱已存在,请重新输入')
|
||||
|
||||
@api.model
|
||||
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
|
||||
if self._context.get('is_customer'):
|
||||
if self.env.user.has_group('sf_base.group_sale_director'):
|
||||
domain = [('customer_rank', '>', 0)]
|
||||
elif self.env.user.has_group('sf_base.group_sale_salemanager'):
|
||||
customer = self.env['res.partner'].search(
|
||||
[('customer_rank', '>', 0), ('user_id', '=', self.env.user.id)])
|
||||
if customer:
|
||||
ids = [t.id for t in customer]
|
||||
domain = [('id', 'in', ids)]
|
||||
else:
|
||||
domain = [('id', '=', False)]
|
||||
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
||||
elif self._context.get('is_supplier') or self.env.user.has_group('sf_base.group_purchase_director'):
|
||||
if self.env.user.has_group('sf_base.group_purchase_director'):
|
||||
domain = [('supplier_rank', '>', 0)]
|
||||
elif self.env.user.has_group('sf_base.group_purchase'):
|
||||
supplier = self.env['res.partner'].search(
|
||||
[('supplier_rank', '>', 0), ('purchase_user_id', '=', self.env.user.id)])
|
||||
if supplier:
|
||||
ids = [t.id for t in supplier]
|
||||
domain = [('id', 'in', ids)]
|
||||
else:
|
||||
domain = [('id', '=', False)]
|
||||
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
||||
return super()._name_search(name, args, operator, limit, name_get_uid)
|
||||
# @api.model
|
||||
# def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
|
||||
# if self._context.get('is_customer'):
|
||||
# if self.env.user.has_group('sf_base.group_sale_director'):
|
||||
# domain = [('customer_rank', '>', 0)]
|
||||
# elif self.env.user.has_group('sf_base.group_sale_salemanager'):
|
||||
# customer = self.env['res.partner'].search(
|
||||
# [('customer_rank', '>', 0), ('user_id', '=', self.env.user.id)])
|
||||
# if customer:
|
||||
# ids = [t.id for t in customer]
|
||||
# domain = [('id', 'in', ids)]
|
||||
# else:
|
||||
# domain = [('id', '=', False)]
|
||||
# return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
||||
# elif self._context.get('is_supplier') or self.env.user.has_group('sf_base.group_purchase_director'):
|
||||
# if self.env.user.has_group('sf_base.group_purchase_director'):
|
||||
# domain = [('supplier_rank', '>', 0)]
|
||||
# elif self.env.user.has_group('sf_base.group_purchase'):
|
||||
# supplier = self.env['res.partner'].search(
|
||||
# [('supplier_rank', '>', 0), ('purchase_user_id', '=', self.env.user.id)])
|
||||
# if supplier:
|
||||
# ids = [t.id for t in supplier]
|
||||
# domain = [('id', 'in', ids)]
|
||||
# else:
|
||||
# domain = [('id', '=', False)]
|
||||
# return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
||||
# return super()._name_search(name, args, operator, limit, name_get_uid)
|
||||
|
||||
@api.onchange('user_id')
|
||||
def _get_salesman(self):
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<record model="ir.rule" id="sale_order_rule_my">
|
||||
<field name="name">销售经理查看自己的订单</field>
|
||||
<field name="model_id" ref="model_sale_order"/>
|
||||
<field name="domain_force">['|',('user_id','=',user.id),('create_uid', '=',user.id)]</field>
|
||||
<field name="domain_force">['|','|',('user_id','=',user.id),('user_id', '=', False),('create_uid', '=',user.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('sf_base.group_sale_salemanager'))]"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
@@ -74,7 +74,7 @@
|
||||
<record model="ir.rule" id="inventory_purchase_order_rule_my">
|
||||
<field name="name">采购岗查看自己的订单</field>
|
||||
<field name="model_id" ref="purchase.model_purchase_order"/>
|
||||
<field name="domain_force">['|',('user_id','=',user.id),('create_uid', '=',user.id)]</field>
|
||||
<field name="domain_force">['|','|',('user_id','=',user.id),('user_id', '=', False),('create_uid', '=',user.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('sf_base.group_purchase'))]"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="0"/>
|
||||
|
||||
@@ -79,6 +79,13 @@
|
||||
<xpath expr="//form/header/button[@name='button_done']" position="attributes">
|
||||
<attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//form/sheet/div[@name='button_box']/button[@name='action_view_mrp_productions']"
|
||||
position="attributes">
|
||||
<attribute name="groups">mrp.group_mrp_user,sf_base.group_purchase,sf_base.group_purchase_director
|
||||
</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='order_line']" position="attributes">
|
||||
<attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
|
||||
</attribute>
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
<field name="model_glb_file" widget="Viewer3D" optional="show"
|
||||
string="模型文件" attrs="{'readonly': [('state', 'in', ['draft'])]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after">
|
||||
<field name="remark"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="attributes">
|
||||
<attribute name="options">{'no_create': True}</attribute>
|
||||
<attribute name="context">{'is_sale_order_line': True }</attribute>
|
||||
|
||||
@@ -313,42 +313,27 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
|
||||
'applicant': None,
|
||||
'sf_functional_tool_assembly_id': None})
|
||||
|
||||
def create_cam_work_plan(self, cnc_processing_ids):
|
||||
def create_cam_work_plan(self, cnc_processing):
|
||||
"""
|
||||
根据传入的工单信息,查询是否有需要的功能刀具,如果没有则生成CAM工单程序用刀计划
|
||||
"""
|
||||
for cnc_processing in cnc_processing_ids:
|
||||
status = False
|
||||
if cnc_processing.cutting_tool_name:
|
||||
functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search(
|
||||
[('name', '=', cnc_processing.cutting_tool_name)])
|
||||
if functional_tools:
|
||||
for functional_tool in functional_tools:
|
||||
if functional_tool.on_tool_stock_num == 0:
|
||||
if functional_tool.tool_stock_num == 0 and functional_tool.side_shelf_num == 0:
|
||||
status = True
|
||||
else:
|
||||
status = True
|
||||
if status:
|
||||
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
|
||||
'name': cnc_processing.workorder_id.production_id.name,
|
||||
'cam_procedure_code': cnc_processing.program_name,
|
||||
'filename': cnc_processing.cnc_id.name,
|
||||
'functional_tool_name': cnc_processing.cutting_tool_name,
|
||||
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
|
||||
'process_type': cnc_processing.processing_type,
|
||||
'margin_x_y': float(cnc_processing.margin_x_y),
|
||||
'margin_z': float(cnc_processing.margin_z),
|
||||
'finish_depth': float(cnc_processing.depth_of_processing_z),
|
||||
'extension_length': float(cnc_processing.cutting_tool_extension_length),
|
||||
'shank_model': cnc_processing.cutting_tool_handle_type,
|
||||
'estimated_processing_time': cnc_processing.estimated_processing_time,
|
||||
})
|
||||
logging.info('CAM工单程序用刀计划创建成功!!!')
|
||||
# 创建装刀请求
|
||||
knife_plan.apply_for_tooling()
|
||||
else:
|
||||
logging.info('功能刀具【%s】满足CNC用刀需求!!!' % cnc_processing.cutting_tool_name)
|
||||
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
|
||||
'name': cnc_processing.workorder_id.production_id.name,
|
||||
'cam_procedure_code': cnc_processing.program_name,
|
||||
'filename': cnc_processing.cnc_id.name,
|
||||
'functional_tool_name': cnc_processing.cutting_tool_name,
|
||||
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
|
||||
'process_type': cnc_processing.processing_type,
|
||||
'margin_x_y': float(cnc_processing.margin_x_y),
|
||||
'margin_z': float(cnc_processing.margin_z),
|
||||
'finish_depth': float(cnc_processing.depth_of_processing_z),
|
||||
'extension_length': float(cnc_processing.cutting_tool_extension_length),
|
||||
'shank_model': cnc_processing.cutting_tool_handle_type,
|
||||
'estimated_processing_time': cnc_processing.estimated_processing_time,
|
||||
})
|
||||
logging.info('CAM工单程序用刀计划创建成功!!!')
|
||||
# 创建装刀请求
|
||||
knife_plan.apply_for_tooling()
|
||||
|
||||
def unlink_cam_plan(self, production):
|
||||
for item in production:
|
||||
@@ -669,6 +654,20 @@ class FunctionalToolAssembly(models.Model):
|
||||
:return:
|
||||
"""
|
||||
|
||||
picking_num = fields.Integer('调拨单数量', compute='compute_picking_num', store=True)
|
||||
|
||||
@api.depends('assemble_status')
|
||||
def compute_picking_num(self):
|
||||
for item in self:
|
||||
picking_ids = self.env['stock.picking'].sudo().search([('origin', '=', item.assembly_order_code)])
|
||||
item.picking_num = len(picking_ids)
|
||||
|
||||
def open_tool_stock_picking(self):
|
||||
action = self.env.ref('stock.action_picking_tree_all')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('origin', '=', self.assembly_order_code)]
|
||||
return result
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals):
|
||||
obj = super(FunctionalToolAssembly, self).create(vals)
|
||||
@@ -758,7 +757,7 @@ class FunctionalToolDismantle(models.Model):
|
||||
num = "%03d" % m
|
||||
return 'GNDJ-CJD-%s-%s' % (datetime, num)
|
||||
|
||||
functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True,
|
||||
functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True, tracking=True,
|
||||
domain=[('functional_tool_status', '!=', '已拆除'),
|
||||
('current_location', '=', '刀具房')])
|
||||
tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
|
||||
@@ -776,8 +775,18 @@ class FunctionalToolDismantle(models.Model):
|
||||
dismantle_person = fields.Char('拆解人', readonly=True)
|
||||
image = fields.Binary('图片', readonly=True)
|
||||
|
||||
scrap_id = fields.Char('报废单号', readonly=True)
|
||||
scrap_ids = fields.One2many('stock.scrap', 'functional_tool_dismantle_id', string='报废单号', readonly=True)
|
||||
grinding_id = fields.Char('磨削单号', readonly=True)
|
||||
picking_id = fields.Many2one('stock.picking', string='刀具物料调拨单')
|
||||
picking_num = fields.Integer('调拨单数量', default=0, compute='compute_picking_num', store=True)
|
||||
|
||||
@api.depends('picking_id')
|
||||
def compute_picking_num(self):
|
||||
for item in self:
|
||||
if item.picking_id:
|
||||
item.picking_num = 1
|
||||
else:
|
||||
item.picking_num = 0
|
||||
|
||||
state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解', tracking=True)
|
||||
active = fields.Boolean('有效', default=True)
|
||||
@@ -791,7 +800,14 @@ class FunctionalToolDismantle(models.Model):
|
||||
handle_rfid = fields.Char(string='刀柄Rfid', compute='_compute_functional_tool_num', store=True)
|
||||
handle_lot_id = fields.Many2one('stock.lot', string='刀柄序列号', compute='_compute_functional_tool_num',
|
||||
store=True)
|
||||
scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False, tracking=True)
|
||||
scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False, tracking=True, compute='compute_scrap_boolean',
|
||||
store=True)
|
||||
|
||||
@api.depends('dismantle_cause')
|
||||
def compute_scrap_boolean(self):
|
||||
for item in self:
|
||||
if item.dismantle_cause not in ['寿命到期报废', '崩刀报废']:
|
||||
item.scrap_boolean = False
|
||||
|
||||
# 整体式
|
||||
integral_product_id = fields.Many2one('product.product', string='整体式刀具',
|
||||
@@ -803,7 +819,7 @@ class FunctionalToolDismantle(models.Model):
|
||||
integral_lot_id = fields.Many2one('stock.lot', string='整体式刀具批次', compute='_compute_functional_tool_num',
|
||||
store=True)
|
||||
integral_freight_id = fields.Many2one('sf.shelf.location', '整体式刀具目标货位',
|
||||
domain="[('product_id', 'in', (integral_product_id, False))]")
|
||||
domain="[('product_id', 'in', (integral_product_id, False)),('rotative_Boolean', '=', True)]")
|
||||
|
||||
# 刀片
|
||||
blade_product_id = fields.Many2one('product.product', string='刀片', compute='_compute_functional_tool_num',
|
||||
@@ -813,7 +829,7 @@ class FunctionalToolDismantle(models.Model):
|
||||
blade_brand_id = fields.Many2one('sf.machine.brand', string='刀片品牌', related='blade_product_id.brand_id')
|
||||
blade_lot_id = fields.Many2one('stock.lot', string='刀片批次', compute='_compute_functional_tool_num', store=True)
|
||||
blade_freight_id = fields.Many2one('sf.shelf.location', '刀片目标货位',
|
||||
domain="[('product_id', 'in', (blade_product_id, False))]")
|
||||
domain="[('product_id', 'in', (blade_product_id, False)),('rotative_Boolean', '=', True)]")
|
||||
|
||||
# 刀杆
|
||||
bar_product_id = fields.Many2one('product.product', string='刀杆', compute='_compute_functional_tool_num',
|
||||
@@ -823,7 +839,7 @@ class FunctionalToolDismantle(models.Model):
|
||||
bar_brand_id = fields.Many2one('sf.machine.brand', string='刀杆品牌', related='bar_product_id.brand_id')
|
||||
bar_lot_id = fields.Many2one('stock.lot', string='刀杆批次', compute='_compute_functional_tool_num', store=True)
|
||||
bar_freight_id = fields.Many2one('sf.shelf.location', '刀杆目标货位',
|
||||
domain="[('product_id', 'in', (bar_product_id, False))]")
|
||||
domain="[('product_id', 'in', (bar_product_id, False)),('rotative_Boolean', '=', True)]")
|
||||
|
||||
# 刀盘
|
||||
pad_product_id = fields.Many2one('product.product', string='刀盘', compute='_compute_functional_tool_num',
|
||||
@@ -833,7 +849,7 @@ class FunctionalToolDismantle(models.Model):
|
||||
pad_brand_id = fields.Many2one('sf.machine.brand', string='刀盘品牌', related='pad_product_id.brand_id')
|
||||
pad_lot_id = fields.Many2one('stock.lot', string='刀盘批次', compute='_compute_functional_tool_num', store=True)
|
||||
pad_freight_id = fields.Many2one('sf.shelf.location', '刀盘目标货位',
|
||||
domain="[('product_id', 'in', (pad_product_id, False))]")
|
||||
domain="[('product_id', 'in', (pad_product_id, False)),('rotative_Boolean', '=', True)]")
|
||||
|
||||
# 夹头
|
||||
chuck_product_id = fields.Many2one('product.product', string='夹头', compute='_compute_functional_tool_num',
|
||||
@@ -843,7 +859,7 @@ class FunctionalToolDismantle(models.Model):
|
||||
chuck_brand_id = fields.Many2one('sf.machine.brand', string='夹头品牌', related='chuck_product_id.brand_id')
|
||||
chuck_lot_id = fields.Many2one('stock.lot', string='夹头批次', compute='_compute_functional_tool_num', store=True)
|
||||
chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位',
|
||||
domain="[('product_id', 'in', (chuck_product_id, False))]")
|
||||
domain="[('product_id', 'in', (chuck_product_id, False)),('rotative_Boolean', '=', True)]")
|
||||
|
||||
@api.onchange('functional_tool_id')
|
||||
def _onchange_freight(self):
|
||||
@@ -933,77 +949,50 @@ class FunctionalToolDismantle(models.Model):
|
||||
self.rfid, self.functional_tool_id.current_location))
|
||||
# 目标重复校验
|
||||
self.location_duplicate_check()
|
||||
location = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
|
||||
location_dest = self.env['stock.location'].search([('name', '=', '刀具房')])
|
||||
datas = {'scrap': [], 'picking': []}
|
||||
# =================刀柄是否[报废]拆解=======
|
||||
location_dest_scrap_ids = self.env['stock.location'].search([('name', 'in', ('Scrap', '报废'))])
|
||||
if self.handle_rfid:
|
||||
lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)])
|
||||
if not lot:
|
||||
raise ValidationError('Rfid为【%s】的功能刀具序列号不存在!' % self.handle_rfid)
|
||||
functional_tool_assembly = self.functional_tool_id.functional_tool_name_id
|
||||
raise ValidationError('Rfid为【%s】的刀柄序列号不存在!' % self.handle_rfid)
|
||||
if self.scrap_boolean:
|
||||
# 刀柄报废 入库到Scrap
|
||||
lot.create_stock_quant(location, location_dest_scrap_ids[-1], functional_tool_assembly.id, code,
|
||||
functional_tool_assembly, functional_tool_assembly.tool_groups_id)
|
||||
datas['scrap'].append({'lot_id': lot})
|
||||
lot.tool_material_status = '报废'
|
||||
else:
|
||||
# 刀柄不报废 入库到刀具房
|
||||
lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, code,
|
||||
functional_tool_assembly, functional_tool_assembly.tool_groups_id)
|
||||
datas['picking'].append({'lot_id': lot, 'destination': self.env['sf.shelf.location']})
|
||||
lot.tool_material_status = '可用'
|
||||
|
||||
# ==============功能刀具[报废]拆解================
|
||||
if self.dismantle_cause in ['寿命到期报废', '崩刀报废']:
|
||||
# 除刀柄外物料报废 入库到Scrap
|
||||
if self.integral_product_id:
|
||||
self.integral_product_id.dismantle_stock_moves(False, self.integral_lot_id, location,
|
||||
location_dest_scrap_ids[-1], code)
|
||||
datas['scrap'].append({'lot_id': self.integral_lot_id})
|
||||
elif self.blade_product_id:
|
||||
self.blade_product_id.dismantle_stock_moves(False, self.blade_lot_id, location,
|
||||
location_dest_scrap_ids[-1], code)
|
||||
datas['scrap'].append({'lot_id': self.blade_lot_id})
|
||||
if self.bar_product_id:
|
||||
self.bar_product_id.dismantle_stock_moves(False, self.bar_lot_id, location,
|
||||
location_dest_scrap_ids[-1], code)
|
||||
datas['scrap'].append({'lot_id': self.bar_lot_id})
|
||||
elif self.pad_product_id:
|
||||
self.pad_product_id.dismantle_stock_moves(False, self.pad_lot_id, location,
|
||||
location_dest_scrap_ids[-1], code)
|
||||
datas['scrap'].append({'lot_id': self.pad_lot_id})
|
||||
if self.chuck_product_id:
|
||||
self.chuck_product_id.dismantle_stock_moves(False, self.chuck_lot_id, location,
|
||||
location_dest_scrap_ids[-1], code)
|
||||
# ===========功能刀具[磨削]拆解==============
|
||||
# elif self.dismantle_cause in ['刀具需磨削']:
|
||||
# location_dest = self.env['stock.location'].search([('name', '=', '磨削房')])
|
||||
# # 除刀柄外物料拆解 入库到具体库位
|
||||
# if self.integral_product_id:
|
||||
# self.integral_product_id.dismantle_stock_moves(False, location, location_dest)
|
||||
# elif self.blade_product_id:
|
||||
# self.blade_product_id.dismantle_stock_moves(False, location, location_dest)
|
||||
# if self.bar_product_id:
|
||||
# self.bar_product_id.dismantle_stock_moves(False, location, location_dest)
|
||||
# elif self.pad_product_id:
|
||||
# self.pad_product_id.dismantle_stock_moves(False, location, location_dest)
|
||||
# if self.chuck_product_id:
|
||||
# self.chuck_product_id.dismantle_stock_moves(False, location, location_dest)
|
||||
datas['scrap'].append({'lot_id': self.chuck_lot_id})
|
||||
# ==============功能刀具[更换,磨削]拆解==============
|
||||
elif self.dismantle_cause in ['更换为其他刀具', '刀具需磨削']:
|
||||
# 除刀柄外物料拆解 入库到具体货位
|
||||
if self.integral_freight_id:
|
||||
self.integral_product_id.dismantle_stock_moves(self.integral_freight_id, self.integral_lot_id, location,
|
||||
location_dest, code)
|
||||
datas['picking'].append({'lot_id': self.integral_lot_id, 'destination': self.integral_freight_id})
|
||||
elif self.blade_freight_id:
|
||||
self.blade_product_id.dismantle_stock_moves(self.blade_freight_id, self.blade_lot_id, location,
|
||||
location_dest, code)
|
||||
datas['picking'].append({'lot_id': self.blade_lot_id, 'destination': self.blade_freight_id})
|
||||
if self.bar_freight_id:
|
||||
self.bar_product_id.dismantle_stock_moves(self.bar_freight_id, self.bar_lot_id, location,
|
||||
location_dest, code)
|
||||
datas['picking'].append({'lot_id': self.bar_lot_id, 'destination': self.bar_freight_id})
|
||||
elif self.pad_freight_id:
|
||||
self.pad_product_id.dismantle_stock_moves(self.pad_freight_id, self.pad_lot_id, location,
|
||||
location_dest, code)
|
||||
datas['picking'].append({'lot_id': self.pad_lot_id, 'destination': self.pad_freight_id})
|
||||
if self.chuck_freight_id:
|
||||
self.chuck_product_id.dismantle_stock_moves(self.chuck_freight_id, self.chuck_lot_id, location,
|
||||
location_dest, code)
|
||||
# ===============删除功能刀具的Rfid字段的值, 赋值给Rfid(已拆解)字段=====
|
||||
datas['picking'].append({'lot_id': self.chuck_lot_id, 'destination': self.chuck_freight_id})
|
||||
self.create_tool_picking_scrap(datas)
|
||||
# ===============创建功能刀具拆解移动记录=====
|
||||
self.env['stock.move'].create_functional_tool_stock_move(self)
|
||||
# 修改功能刀具数据
|
||||
self.functional_tool_id.write({
|
||||
'rfid_dismantle': self.functional_tool_id.rfid,
|
||||
'rfid': '',
|
||||
@@ -1011,37 +1000,173 @@ class FunctionalToolDismantle(models.Model):
|
||||
})
|
||||
# 修改拆解单的值
|
||||
self.write({
|
||||
'rfid_dismantle': self.rfid,
|
||||
'dismantle_data': fields.Datetime.now(),
|
||||
'dismantle_person': self.env.user.name,
|
||||
'rfid': '',
|
||||
'rfid': '%s(已拆解)' % self.rfid,
|
||||
'state': '已拆解'
|
||||
})
|
||||
logging.info('【%s】刀具拆解成功!' % self.name)
|
||||
|
||||
def create_tool_picking_scrap(self, datas):
|
||||
scrap_data = datas['scrap']
|
||||
picking_data = datas['picking']
|
||||
if scrap_data:
|
||||
for data in scrap_data:
|
||||
if data:
|
||||
self.env['stock.scrap'].create_tool_dismantle_stock_scrap(data['lot_id'], self)
|
||||
if picking_data:
|
||||
picking_id = self.env['stock.picking'].create_tool_dismantle_picking(self)
|
||||
self.picking_id = picking_id.id
|
||||
self.env['stock.move'].create_tool_stock_move({'data': picking_data, 'picking_id': picking_id})
|
||||
# 将刀具物料出库库单的状态更改为就绪
|
||||
picking_id.action_confirm()
|
||||
# 修改刀具物料出库移动历史记录
|
||||
self.env['stock.move'].write_tool_stock_move_line({'data': picking_data, 'picking_id': picking_id})
|
||||
# 设置数量,并验证完成
|
||||
picking_id.action_set_quantities_to_reservation()
|
||||
picking_id.button_validate()
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
def action_open_reference1(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'res_model': self._name,
|
||||
'type': 'ir.actions.act_window',
|
||||
'views': [[False, "form"]],
|
||||
'res_id': self.id,
|
||||
}
|
||||
|
||||
def dismantle_stock_moves(self, shelf_location_id, lot_id, location_id, location_dest_id, code):
|
||||
# 创建功能刀具拆解单产品库存移动记录
|
||||
stock_move_id = self.env['stock.move'].sudo().create({
|
||||
'name': code,
|
||||
'product_id': self.id,
|
||||
def open_function_tool_stock_move_line(self):
|
||||
action = self.env.ref('sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_act')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('functional_tool_dismantle_id', '=', self.id), ('qty_done', '>', 0)]
|
||||
return result
|
||||
|
||||
def open_tool_stock_picking(self):
|
||||
action = self.env.ref('stock.action_picking_tree_all')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('origin', '=', self.code)]
|
||||
return result
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
def create_tool_dismantle_picking(self, obj):
|
||||
"""
|
||||
创建刀具物料入库单
|
||||
"""
|
||||
# 获取名称为内部调拨的作业类型
|
||||
picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '内部调拨')])
|
||||
location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
|
||||
location_dest_id = self.env['stock.location'].search([('name', '=', '刀具房')])
|
||||
if not location_id:
|
||||
raise ValidationError('缺少名称为【刀具组装位置】的仓库管理地点')
|
||||
if not location_dest_id:
|
||||
raise ValidationError('缺少名称为【刀具房】的仓库管理地点')
|
||||
# 创建刀具物料出库单
|
||||
picking_id = self.env['stock.picking'].create({
|
||||
'name': self._get_name_stock1(picking_type_id),
|
||||
'picking_type_id': picking_type_id.id,
|
||||
'location_id': location_id.id,
|
||||
'location_dest_id': location_dest_id.id,
|
||||
'origin': obj.code
|
||||
})
|
||||
|
||||
return picking_id
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
def create_tool_stock_move(self, datas):
|
||||
picking_id = datas['picking_id']
|
||||
data = datas['data']
|
||||
stock_move_ids = []
|
||||
for res in data:
|
||||
if res:
|
||||
# 创建库存移动记录
|
||||
stock_move_id = self.env['stock.move'].sudo().create({
|
||||
'name': picking_id.name,
|
||||
'picking_id': picking_id.id,
|
||||
'product_id': res['lot_id'].product_id.id,
|
||||
'location_id': picking_id.location_id.id,
|
||||
'location_dest_id': picking_id.location_dest_id.id,
|
||||
'product_uom_qty': 1.00,
|
||||
'reserved_availability': 1.00
|
||||
})
|
||||
stock_move_ids.append(stock_move_id)
|
||||
return stock_move_ids
|
||||
|
||||
def write_tool_stock_move_line(self, datas):
|
||||
picking_id = datas['picking_id']
|
||||
data = datas['data']
|
||||
move_line_ids = picking_id.move_line_ids
|
||||
for move_line_id in move_line_ids:
|
||||
for res in data:
|
||||
if move_line_id.lot_id.product_id == res['lot_id'].product_id:
|
||||
move_line_id.write({
|
||||
'destination_location_id': res.get('destination').id,
|
||||
'lot_id': res.get('lot_id').id
|
||||
})
|
||||
return True
|
||||
|
||||
def create_functional_tool_stock_move(self, dismantle_id):
|
||||
"""
|
||||
对功能刀具拆解过程的功能刀具进行库存移动,以及创建移动历史
|
||||
"""
|
||||
location_dismantle_id = self.env['stock.location'].search([('name', '=', '拆解')])
|
||||
if not location_dismantle_id:
|
||||
raise ValidationError('缺少名称为【拆解】的仓库管理地点')
|
||||
tool_id = dismantle_id.functional_tool_id
|
||||
# 创建库存移动记录
|
||||
stock_move_id = self.env['stock.move'].sudo().create({
|
||||
'name': dismantle_id.code,
|
||||
'product_id': tool_id.barcode_id.product_id.id,
|
||||
'location_id': tool_id.current_location_id.id,
|
||||
'location_dest_id': location_dismantle_id.id,
|
||||
'product_uom_qty': 1.00,
|
||||
'state': 'done'
|
||||
})
|
||||
|
||||
# 创建移动历史记录
|
||||
stock_move_line_id = self.env['stock.move.line'].sudo().create({
|
||||
'product_id': self.id,
|
||||
'lot_id': lot_id.id,
|
||||
'product_id': tool_id.barcode_id.product_id.id,
|
||||
'functional_tool_dismantle_id': dismantle_id.id,
|
||||
'lot_id': tool_id.barcode_id.id,
|
||||
'move_id': stock_move_id.id,
|
||||
'destination_location_id': shelf_location_id.id if shelf_location_id else False,
|
||||
'install_tool_time': fields.Datetime.now(),
|
||||
'qty_done': 1.0,
|
||||
'state': 'done',
|
||||
'functional_tool_type_id': tool_id.sf_cutting_tool_type_id.id,
|
||||
'diameter': tool_id.functional_tool_diameter,
|
||||
'knife_tip_r_angle': tool_id.knife_tip_r_angle,
|
||||
'code': tool_id.code,
|
||||
'rfid': tool_id.rfid,
|
||||
'functional_tool_name': tool_id.name,
|
||||
'tool_groups_id': tool_id.tool_groups_id.id
|
||||
})
|
||||
|
||||
return stock_move_id, stock_move_line_id
|
||||
|
||||
|
||||
class CustomStockScrap(models.Model):
|
||||
_inherit = 'stock.scrap'
|
||||
|
||||
functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', string="功能刀具拆解单")
|
||||
|
||||
def create_tool_dismantle_stock_scrap(self, lot, dismantle_id):
|
||||
location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
|
||||
scrap_location_id = self.env['stock.location'].search([('name', 'in', ('Scrap', '报废'))])
|
||||
if not location_id:
|
||||
raise ValidationError('缺少名称为【刀具组装位置】的仓库管理地点')
|
||||
if not scrap_location_id:
|
||||
raise ValidationError('缺少名称为【Scrap】或【Scrap】的仓库管理地点')
|
||||
stock_scrap_id = self.create({
|
||||
'product_id': lot.product_id.id,
|
||||
'lot_id': lot.id,
|
||||
'location_id': location_id.id,
|
||||
'scrap_location_id': scrap_location_id.id,
|
||||
'functional_tool_dismantle_id': dismantle_id.id,
|
||||
'origin': dismantle_id.code
|
||||
})
|
||||
# 完成报废单
|
||||
stock_scrap_id.action_validate()
|
||||
return stock_scrap_id
|
||||
|
||||
@@ -53,7 +53,8 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools',
|
||||
string='功能刀具安全库存', readonly=True)
|
||||
|
||||
@api.depends('barcode_id.quant_ids', 'functional_tool_status', 'current_shelf_location_id')
|
||||
@api.depends('barcode_id.quant_ids', 'barcode_id.quant_ids.location_id', 'functional_tool_status',
|
||||
'current_shelf_location_id')
|
||||
def _compute_current_location_id(self):
|
||||
for record in self:
|
||||
if record.functional_tool_status == '已拆除':
|
||||
@@ -252,11 +253,28 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
def open_safety_stock(self):
|
||||
action = self.env.ref('sf_tool_management.sf_real_time_distribution_of_functional_tools_view_act')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('name', '=', self.name), ('diameter', '=', self.functional_tool_diameter),
|
||||
('knife_tip_r_angle', '=', self.knife_tip_r_angle),
|
||||
('coarse_middle_thin', '=', self.coarse_middle_thin)]
|
||||
result['domain'] = [('id', '=', self.safe_inventory_id.id)]
|
||||
return result
|
||||
|
||||
def cnc_function_tool_use_verify(self):
|
||||
"""
|
||||
cnc程序用刀可用校验(校验是否是制造订单所缺刀)
|
||||
"""
|
||||
if self.tool_name_id.name:
|
||||
cnc_processing_ids = self.env['sf.cnc.processing'].search(
|
||||
[('tool_state', '=', '1'), ('cutting_tool_name', '=', self.tool_name_id.name)])
|
||||
production_ids = []
|
||||
if cnc_processing_ids:
|
||||
for item in cnc_processing_ids:
|
||||
if item.workorder_id and item.workorder_id.production_id not in production_ids:
|
||||
production_ids.append(item.workorder_id.production_id)
|
||||
if production_ids:
|
||||
# 对同一制造订单的工单的cnc编程单的功能刀具状态进行变更,并调用工单的功能刀具状态计算方法
|
||||
for production_id in production_ids:
|
||||
cnc_ids = cnc_processing_ids.filtered(lambda a: a.workorder_id.production_id == production_id)
|
||||
cnc_ids.sudo().write({'tool_state': '0'})
|
||||
cnc_ids.workorder_id._compute_tool_state()
|
||||
|
||||
def tool_inventory_displacement_out(self):
|
||||
"""
|
||||
机床当前刀库实时信息接口,功能刀具出库
|
||||
@@ -267,6 +285,7 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
self.create_stock_move(stock_location_id, False)
|
||||
self.current_location_id = stock_location_id.id
|
||||
self.current_shelf_location_id = False
|
||||
|
||||
# self.barcode_id.create_stock_quant(location_inventory_id, stock_location_id,
|
||||
# self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id,
|
||||
# self.functional_tool_name_id.tool_groups_id)
|
||||
@@ -372,6 +391,7 @@ class StockMoveLine(models.Model):
|
||||
_order = 'date desc'
|
||||
|
||||
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单')
|
||||
functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', string='功能刀具拆解单')
|
||||
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
|
||||
group_expand='_read_group_functional_tool_type_id')
|
||||
functional_tool_name = fields.Char('刀具名称')
|
||||
@@ -392,6 +412,9 @@ class StockMoveLine(models.Model):
|
||||
if self.functional_tool_name_id:
|
||||
action = self.functional_tool_name_id.action_open_reference1()
|
||||
return action
|
||||
if self.functional_tool_dismantle_id:
|
||||
action = self.functional_tool_dismantle_id.action_open_reference1()
|
||||
return action
|
||||
elif self.move_id:
|
||||
action = self.move_id.action_open_reference()
|
||||
if action['res_model'] != 'stock.move':
|
||||
@@ -409,13 +432,14 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
_inherit = ['mail.thread']
|
||||
_description = '功能刀具安全库存'
|
||||
|
||||
name = fields.Char('名称', readonly=True, compute='_compute_name', store=True)
|
||||
name = fields.Char('名称', compute='_compute_num', store=True)
|
||||
functional_name_id = fields.Many2one('sf.tool.inventory', string='功能刀具名称', required=True)
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=False, required=True)
|
||||
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False,
|
||||
group_expand='_read_mrs_cutting_tool_type_ids', store=True)
|
||||
diameter = fields.Float(string='刀具直径(mm)', readonly=False)
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=False)
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_num', store=True)
|
||||
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
|
||||
compute='_compute_num', store=True,
|
||||
group_expand='_read_mrs_cutting_tool_type_ids')
|
||||
diameter = fields.Float(string='刀具直径(mm)', compute='_compute_num', store=True)
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', compute='_compute_num', store=True)
|
||||
tool_stock_num = fields.Integer(string='刀具房数量', compute='_compute_stock_num', store=True)
|
||||
side_shelf_num = fields.Integer(string='线边刀库数量', compute='_compute_stock_num', store=True)
|
||||
on_tool_stock_num = fields.Integer(string='机内刀库数量', compute='_compute_stock_num', store=True)
|
||||
@@ -460,22 +484,18 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
@api.onchange('functional_name_id')
|
||||
def _onchange_num(self):
|
||||
@api.depends('functional_name_id', 'functional_name_id.diameter', 'functional_name_id.angle',
|
||||
'functional_name_id.functional_cutting_tool_model_id')
|
||||
def _compute_num(self):
|
||||
for item in self:
|
||||
if item.functional_name_id:
|
||||
item.tool_groups_id = item.functional_name_id.tool_groups_id.id
|
||||
item.sf_cutting_tool_type_id = item.functional_name_id.functional_cutting_tool_model_id.id
|
||||
item.diameter = item.functional_name_id.diameter
|
||||
item.knife_tip_r_angle = item.functional_name_id.angle
|
||||
|
||||
@api.depends('functional_name_id')
|
||||
def _compute_name(self):
|
||||
for obj in self:
|
||||
if obj.tool_groups_id:
|
||||
obj.name = obj.functional_name_id.name
|
||||
item.name = item.functional_name_id.name
|
||||
else:
|
||||
obj.sudo().name = ''
|
||||
item.sudo().name = ''
|
||||
|
||||
@api.constrains('min_stock_num', 'max_stock_num')
|
||||
def _check_stock_num(self):
|
||||
@@ -583,4 +603,10 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
for vals in vals_list:
|
||||
vals['status_create'] = False
|
||||
records = super(RealTimeDistributionOfFunctionalTools, self).create(vals_list)
|
||||
for item in records:
|
||||
if item:
|
||||
record = self.search([('functional_name_id', '=', item.functional_name_id.id)])
|
||||
if len(record) > 1:
|
||||
raise ValidationError(
|
||||
'功能刀具名称为【%s】的安全库存已经存在,请勿重复创建!!!' % item.functional_name_id.name)
|
||||
return records
|
||||
|
||||
@@ -37,14 +37,10 @@ class ToolDatasync(models.Model):
|
||||
|
||||
def _cron_tool_datasync_all(self):
|
||||
try:
|
||||
self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all()
|
||||
|
||||
self.env['stock.lot'].sudo().sync_enroll_fixture_material_stock_all()
|
||||
|
||||
self.env['sf.tool.material.search'].sudo().sync_enroll_tool_material_all()
|
||||
|
||||
self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all()
|
||||
self.env['sf.fixture.material.search'].sudo().sync_enroll_fixture_material_all()
|
||||
|
||||
self.env['stock.lot'].sudo().sync_enroll_fixture_material_stock_all()
|
||||
self.env['sf.functional.cutting.tool.entity'].sudo().esync_enroll_functional_tool_entity_all()
|
||||
logging.info("已全部同步完成!!!")
|
||||
# self.env['sf.functional.tool.warning'].sudo().sync_enroll_functional_tool_warning_all()
|
||||
@@ -106,7 +102,7 @@ class StockLot(models.Model):
|
||||
logging.info("没有刀具物料序列号信息")
|
||||
except Exception as e:
|
||||
logging.info("刀具物料序列号同步失败:%s" % e)
|
||||
|
||||
|
||||
|
||||
class ToolMaterial(models.Model):
|
||||
_inherit = 'sf.tool.material.search'
|
||||
@@ -198,7 +194,7 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
for item in objs_all:
|
||||
val = {
|
||||
'id': item.id,
|
||||
'code': item.code,
|
||||
'code': False if not item.code else item.code.split('-', 1)[1],
|
||||
'name': item.name,
|
||||
'rfid': item.rfid,
|
||||
'tool_groups_name': item.tool_groups_id.name,
|
||||
|
||||
@@ -3,6 +3,7 @@ import requests
|
||||
import logging
|
||||
from odoo import models, api, fields
|
||||
from odoo.exceptions import ValidationError
|
||||
from datetime import datetime, timedelta
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
|
||||
|
||||
@@ -101,7 +102,7 @@ class SfMaintenanceEquipment(models.Model):
|
||||
tool_install_time = {'Nomal': '正常', 'Warning': '报警'}
|
||||
equipment_tool_id.write({
|
||||
'functional_tool_name_id': functional_tool_id.id,
|
||||
'tool_install_time': time
|
||||
'tool_install_time': time - timedelta(hours=8)
|
||||
})
|
||||
if functional_tool_id.current_location != '机内刀库':
|
||||
# 对功能刀具进行移动到生产线
|
||||
|
||||
@@ -29,13 +29,106 @@ class CNCprocessing(models.Model):
|
||||
# else:
|
||||
# raise ValidationError("MES装刀指令发送失败")
|
||||
|
||||
def cnc_tool_checkout(self, cnc_processing_ids):
|
||||
"""
|
||||
根据传入的工单信息,查询是否有需要的功能刀具,如果没有则生成CAM工单程序用刀计划
|
||||
"""
|
||||
logging.info('开始进行工单cnc程序用刀校验!!!')
|
||||
logging.info(f'cnc_processing_ids:{cnc_processing_ids}')
|
||||
if not cnc_processing_ids:
|
||||
return False
|
||||
cam_id = self.env['sf.cam.work.order.program.knife.plan']
|
||||
production_ids = [] # 制造订单集
|
||||
datas = {'缺刀': {}, '无效刀': {}} # 缺刀/无效刀集
|
||||
for cnc_processing in cnc_processing_ids:
|
||||
# ======创建字典: {'缺刀': {'制造订单1': {'加工面1': [], ...}, ...}, '无效刀': {'制造订单1': {'加工面1': [], ...}, ...}}======
|
||||
production_name = cnc_processing.workorder_id.production_id.name # 制造订单
|
||||
processing_panel = cnc_processing.workorder_id.processing_panel # 加工面
|
||||
if production_name not in list(datas['缺刀'].keys()):
|
||||
datas['缺刀'].update({production_name: {processing_panel: []}})
|
||||
datas['无效刀'].update({production_name: {processing_panel: []}})
|
||||
production_ids.append(cnc_processing.workorder_id.production_id)
|
||||
else:
|
||||
if processing_panel not in list(datas['缺刀'].get(production_name).keys()):
|
||||
datas['缺刀'].get(production_name).update({processing_panel: []})
|
||||
datas['无效刀'].get(production_name).update({processing_panel: []})
|
||||
# ======================================
|
||||
if cnc_processing.cutting_tool_name:
|
||||
tool_name = cnc_processing.cutting_tool_name
|
||||
# 检验CNC用刀是否是功能刀具清单中的刀具
|
||||
tool_inventory_id = self.env['sf.tool.inventory'].sudo().search([('name', '=', tool_name)])
|
||||
if not tool_inventory_id:
|
||||
if cnc_processing.cutting_tool_name not in datas['无效刀'][production_name][processing_panel]:
|
||||
datas['无效刀'][production_name][processing_panel].append(cnc_processing.cutting_tool_name)
|
||||
cnc_processing.tool_state = '2'
|
||||
logging.info(f'"无效刀":[{production_name}、{processing_panel}、{cnc_processing.cutting_tool_name}]')
|
||||
# 跳过本次循环
|
||||
continue
|
||||
# 校验CNC用刀在系统是否存在
|
||||
functional_tools = self.env['sf.functional.cutting.tool.entity'].sudo().search(
|
||||
[('tool_name_id', '=', tool_inventory_id.id), ('functional_tool_status', '=', '正常')])
|
||||
# 判断线边、机内是否有满足条件的刀
|
||||
if not functional_tools.filtered(lambda p: p.current_location in ('线边刀库', '机内刀库')):
|
||||
if cnc_processing.cutting_tool_name not in datas['缺刀'][production_name][processing_panel]:
|
||||
datas['缺刀'][production_name][processing_panel].append(cnc_processing.cutting_tool_name)
|
||||
cnc_processing.tool_state = '1'
|
||||
logging.info(f'"缺刀":[{production_name}、{processing_panel}、{cnc_processing.cutting_tool_name}]')
|
||||
# 判断是否有满足条件的刀
|
||||
if not functional_tools:
|
||||
# 创建CAM申请装刀记录
|
||||
cam_id.create_cam_work_plan(cnc_processing)
|
||||
logging.info('成功调用CAM工单程序用刀计划创建方法!!!')
|
||||
logging.info(f'datas:{datas}')
|
||||
for production_id in production_ids:
|
||||
logging.info(f'production_id: {production_id}')
|
||||
if production_id:
|
||||
data1 = datas['无效刀'].get(production_id.name) # data1: {'加工面1': [], ...}
|
||||
data2 = datas['缺刀'].get(production_id.name) # data2: {'加工面1': [], ...}
|
||||
# tool_state_remark1 = ''
|
||||
tool_state_remark2 = ''
|
||||
# 对无效刀信息进行处理
|
||||
for key in data1:
|
||||
if data1.get(key):
|
||||
# if tool_state_remark1 != '':
|
||||
# tool_state_remark1 = f'{tool_state_remark1}\n{key}无效刀:{data1.get(key)}'
|
||||
# else:
|
||||
# tool_state_remark1 = f'{key}无效刀:{data1.get(key)}'
|
||||
# 无效刀处理逻辑
|
||||
# 1、创建制造订单无效刀检测结果记录
|
||||
logging.info('创建制造订单无效刀检测结果记录!')
|
||||
production_id.detection_result_ids.create({
|
||||
'production_id': production_id.id,
|
||||
'processing_panel': key,
|
||||
'routing_type': 'CNC加工',
|
||||
'rework_reason': 'programming', # 原因:编程(programming)
|
||||
'detailed_reason': '无效功能刀具',
|
||||
'test_results': '返工',
|
||||
'handle_result': '待处理'
|
||||
})
|
||||
# 修改当前面装夹预调工单的 is_rework 为 True
|
||||
# work_ids = production_id.workorder_ids.filtered(
|
||||
# lambda a: a.routing_type == '装夹预调' and a.processing_panel == key and not a.is_rework)
|
||||
# work_ids.write({'is_rework': True})
|
||||
# 对缺刀信息进行处理
|
||||
for key in data2:
|
||||
if data2.get(key):
|
||||
if tool_state_remark2 != '':
|
||||
tool_state_remark2 = f'{tool_state_remark2}\n{key}缺刀:{data2.get(key)}'
|
||||
else:
|
||||
tool_state_remark2 = f'{key}缺刀:{data2.get(key)}'
|
||||
# 将备注信息存入制造订单功能刀具状态的备注字段
|
||||
logging.info('修改制造订单功能刀具状态的备注字段')
|
||||
production_id.write({
|
||||
'tool_state_remark': tool_state_remark2,
|
||||
# 'tool_state_remark2': tool_state_remark1
|
||||
})
|
||||
logging.info('工单cnc程序用刀校验已完成!')
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals):
|
||||
obj = super(CNCprocessing, self).create(vals)
|
||||
for item in obj:
|
||||
# 调用CAM工单程序用刀计划创建方法
|
||||
self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(item)
|
||||
logging.info('成功调用CAM工单程序用刀计划创建方法!!!')
|
||||
# 调用CAM工单程序用刀计划创建方法
|
||||
self.cnc_tool_checkout(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@@ -21,3 +21,40 @@ class ShelfLocation(models.Model):
|
||||
continue
|
||||
item.tool_rfid = ''
|
||||
item.tool_name_id = False
|
||||
|
||||
|
||||
class StockMoveLine(models.Model):
|
||||
_inherit = 'stock.move.line'
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
records = super(StockMoveLine, self).create(vals_list)
|
||||
move_lines = records.filtered(lambda a: a.product_id.categ_id.name == '功能刀具' and a.state == 'done')
|
||||
if move_lines: # 校验是否为功能刀具移动历史
|
||||
self.button_function_tool_use_verify(move_lines)
|
||||
return records
|
||||
|
||||
def button_function_tool_use_verify(self, move_lines):
|
||||
"""
|
||||
对所有从【刀具房】到【制造前】的功能刀具进行校验(校验是否为制造订单所缺的刀)
|
||||
"""
|
||||
location_id = self.env['stock.location'].search([('name', '=', '刀具房')])
|
||||
location_dest_id = self.env['stock.location'].search([('name', '=', '制造前')])
|
||||
line_ids = move_lines.filtered(
|
||||
lambda a: a.location_id == location_id and a.location_dest_id == location_dest_id)
|
||||
for line_id in line_ids:
|
||||
if line_id.lot_id:
|
||||
self.env['sf.functional.cutting.tool.entity'].sudo().search(
|
||||
[('barcode_id', '=', line_id.lot_id.id),
|
||||
('functional_tool_status', '=', '正常')]).cnc_function_tool_use_verify()
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
def button_validate(self):
|
||||
res = super().button_validate()
|
||||
move_lines = self.move_line_ids.filtered(lambda a: a.product_id.categ_id.name == '功能刀具')
|
||||
if move_lines:
|
||||
self.env['stock.move.line'].sudo().button_function_tool_use_verify(move_lines)
|
||||
return res
|
||||
|
||||
@@ -25,7 +25,8 @@ class ToolMaterial(models.Model):
|
||||
have_been_used_num = fields.Integer('在用数量', compute='_compute_number', store=True)
|
||||
scrap_num = fields.Integer('报废数量', compute='_compute_number', store=True)
|
||||
|
||||
barcode_ids = fields.One2many('stock.lot', 'tool_material_search_id', string='序列号', readonly=True)
|
||||
barcode_ids = fields.One2many('stock.lot', 'tool_material_search_id', string='序列号', readonly=True,
|
||||
domain=[('tool_material_status', '!=', '未入库')])
|
||||
|
||||
@api.depends('product_id.stock_quant_ids.quantity')
|
||||
def _compute_number(self):
|
||||
@@ -46,8 +47,6 @@ class ToolMaterial(models.Model):
|
||||
record.scrap_num = scrap_num
|
||||
record.number = usable_num + have_been_used_num + scrap_num
|
||||
|
||||
|
||||
|
||||
@api.model
|
||||
def _read_group_cutting_tool_material_id(self, categories, domain, order):
|
||||
cutting_tool_material_id = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
<field name="current_location" string="当前位置"/>
|
||||
|
||||
<field name="current_location_id" invisible="1"/>
|
||||
<field name="current_location" optional="hide"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -61,13 +60,9 @@
|
||||
</button>
|
||||
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
|
||||
name="open_stock_move_line"
|
||||
icon="fa-list-ul"
|
||||
type="object">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span>
|
||||
出库入库记录
|
||||
</span>
|
||||
</div>
|
||||
<i class="fa fa-fw o_button_icon fa-exchange"/>
|
||||
<span>出库入库记录</span>
|
||||
</button>
|
||||
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
|
||||
name="open_safety_stock"
|
||||
@@ -174,7 +169,7 @@
|
||||
<field name="cut_time" attrs="{'invisible': [('new_former','=','0')]}"/>
|
||||
<field name="cut_length" attrs="{'invisible': [('new_former','=','0')]}"/>
|
||||
<field name="cut_number" attrs="{'invisible': [('new_former','=','0')]}"/>
|
||||
<field name="current_location_id" string="当前位置"/>
|
||||
<field name="current_location_id" string="当前位置" invisible="1"/>
|
||||
<field name="current_location" string="当前位置"/>
|
||||
<field name="current_shelf_location_id" string="当前货位"
|
||||
attrs="{'invisible': [('current_shelf_location_id', '=', False)]}"/>
|
||||
@@ -482,18 +477,19 @@
|
||||
<field name="reference" string="单据号"/>
|
||||
<field name="lot_id" invisible="1"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id" optional="hide"/>
|
||||
<field name="functional_tool_name" string="功能刀具名称"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time"/>
|
||||
<field name="location_id"/>
|
||||
<field name="current_location_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="destination_location_id"/>
|
||||
<field name="date"/>
|
||||
<field name="qty_done" string="数量"/>
|
||||
<field name="functional_tool_type_id" invisible="True"/>
|
||||
<field name="functional_tool_type_id" invisible="1"/>
|
||||
<field name="functional_tool_name_id" invisible="1"/>
|
||||
<field name="functional_tool_dismantle_id" invisible="1"/>
|
||||
<field name="install_tool_time" invisible="1"/>
|
||||
<!-- <button name="enroll_functional_tool_move" string="安全库存注册" type="object" class="btn-primary"/>-->
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
@@ -407,6 +407,7 @@
|
||||
<field name="plan_execute_status"/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="plan_execute_status" string="状态" enable_counters="1" icon="fa-filter"/>
|
||||
<field name="production_line_id" string="生产线" enable_counters="1" icon="fa-filter"/>
|
||||
<field name="functional_tool_type_id" string="功能刀具类型" enable_counters="1"
|
||||
icon="fa-filter"/>
|
||||
@@ -476,6 +477,17 @@
|
||||
<field name="assemble_status" widget="statusbar" statusbar_visible="0,1"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button class="oe_stat_button" name="open_tool_stock_picking" icon="fa-truck" type="object"
|
||||
attrs="{'invisible': [('assemble_status', '!=', '1')]}">
|
||||
<div name="delivery_count" class="o_field_widget o_readonly_modifier o_field_statinfo">
|
||||
<span class="o_stat_info o_stat_value">
|
||||
<field name="picking_num"/>
|
||||
</span>
|
||||
<span class="o_stat_text">调拨</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="assembly_order_code"/>
|
||||
@@ -711,10 +723,14 @@
|
||||
</searchpanel>
|
||||
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="功能刀具名称" name="name" domain="[]" context="{'group_by': 'functional_tool_name'}"/>
|
||||
<filter string="刀具组" name="tool_groups" domain="[]" context="{'group_by': 'tool_groups_id'}"/>
|
||||
<filter string="任务来源" name="loading_task_source" domain="[]" context="{'group_by': 'loading_task_source'}"/>
|
||||
<filter string="用刀时间" name="use_tool_time" domain="[]" context="{'group_by': 'use_tool_time'}"/>
|
||||
<filter string="功能刀具名称" name="name" domain="[]"
|
||||
context="{'group_by': 'functional_tool_name'}"/>
|
||||
<filter string="刀具组" name="tool_groups" domain="[]"
|
||||
context="{'group_by': 'tool_groups_id'}"/>
|
||||
<filter string="任务来源" name="loading_task_source" domain="[]"
|
||||
context="{'group_by': 'loading_task_source'}"/>
|
||||
<filter string="用刀时间" name="use_tool_time" domain="[]"
|
||||
context="{'group_by': 'use_tool_time'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
@@ -759,10 +775,25 @@
|
||||
<form>
|
||||
<header>
|
||||
<button string="确认拆解" name="confirmation_disassembly" type="object" class="btn-primary"
|
||||
confirm="是否确认拆解" attrs="{'invisible': [('state', '=', '已拆解')]}"/>
|
||||
confirm="是否确认拆解" attrs="{'invisible': [('state', '!=', '待拆解')]}"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="待拆解,已拆解"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button class="oe_stat_button" name="open_tool_stock_picking" icon="fa-truck" type="object"
|
||||
attrs="{'invisible':[('state', '!=', '已拆解')]}">
|
||||
<div name="delivery_count" class="o_field_widget o_readonly_modifier o_field_statinfo">
|
||||
<span class="o_stat_info o_stat_value">
|
||||
<field name="picking_num"/>
|
||||
</span>
|
||||
<span class="o_stat_text">调拨</span>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" name="open_function_tool_stock_move_line" icon="fa-exchange"
|
||||
type="object">
|
||||
<span>功能刀具移动</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="code"/>
|
||||
@@ -773,12 +804,13 @@
|
||||
<group>
|
||||
<field name="functional_tool_id" placeholder="请选择将要拆解的功能刀具"
|
||||
options="{'no_create': True}" attrs="{'readonly': [('state', '=', '已拆解')]}"/>
|
||||
<field name="rfid" attrs="{'invisible': [('state', '=', '已拆解')]}"/>
|
||||
<field name="rfid_dismantle" attrs="{'invisible': [('state', '!=', '已拆解')]}"/>
|
||||
<field name="rfid" attrs="{'invisible': [('rfid', '=', '')]}"/>
|
||||
<field name="rfid_dismantle" attrs="{'invisible': [('rfid_dismantle', '=', False)]}"/>
|
||||
<field name="tool_type_id"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="picking_id" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="image"/>
|
||||
@@ -791,8 +823,8 @@
|
||||
attrs="{'readonly': [('state', '=', '已拆解')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="scrap_id"
|
||||
attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])]}"/>
|
||||
<!-- <field name="scrap_id"-->
|
||||
<!-- attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])]}"/>-->
|
||||
<field name="grinding_id"
|
||||
attrs="{'invisible': [('dismantle_cause', 'not in', ['刀具需磨削'])]}"/>
|
||||
</group>
|
||||
@@ -879,6 +911,23 @@
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="报废"
|
||||
attrs="{'invisible':[('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])]}">
|
||||
<field name="scrap_ids">
|
||||
<tree>
|
||||
<field name="name"/>
|
||||
<field name="product_id"/>
|
||||
<field name="lot_id"/>
|
||||
<field name="location_id"/>
|
||||
<field name="scrap_location_id"/>
|
||||
<field name="scrap_qty"/>
|
||||
<field name="product_uom_id"/>
|
||||
<field name="date_done"/>
|
||||
<field name="state" widget="badge" decoration-success="state == 'done'"
|
||||
decoration-muted="state == 'draft'"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="其他">
|
||||
<group>
|
||||
<group>
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<field name="name"/>
|
||||
<field name="rfid"/>
|
||||
<field name="product_qty"/>
|
||||
<field name="create_date" string="入库日期"/>
|
||||
<field name="tool_material_status"/>
|
||||
<!-- <button name="enroll_tool_material_stock" string="序列号注册" type="object" class="btn-primary"/>-->
|
||||
</tree>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import logging
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
from datetime import timedelta, datetime, date
|
||||
|
||||
from odoo import fields, models, api
|
||||
from odoo.exceptions import ValidationError
|
||||
@@ -603,6 +603,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
功能刀具组装
|
||||
:return:
|
||||
"""
|
||||
logging.info('功能刀具开始组装!')
|
||||
# 获取组装单对象
|
||||
functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([
|
||||
('assembly_order_code', '=', self.assembly_order_code),
|
||||
@@ -621,26 +622,10 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
desc_1 = self.get_desc_1(stock_lot)
|
||||
# 封装功能刀具数据,用于创建功能刀具记录
|
||||
desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly)
|
||||
# 创建刀具组装入库单
|
||||
self.env['stock.picking'].create_stocking_picking(stock_lot, functional_tool_assembly, self)
|
||||
# 刀具物料出库
|
||||
if self.handle_code_id:
|
||||
product_id.tool_material_stock_moves(self.handle_code_id, self.assembly_order_code)
|
||||
if self.integral_product_id:
|
||||
self.integral_product_id.material_stock_moves(self.integral_freight_barcode_id,
|
||||
self.integral_freight_lot_id, self.assembly_order_code)
|
||||
if self.blade_product_id:
|
||||
self.blade_product_id.material_stock_moves(self.blade_freight_barcode_id,
|
||||
self.blade_freight_lot_id, self.assembly_order_code)
|
||||
if self.bar_product_id:
|
||||
self.bar_product_id.material_stock_moves(self.bar_freight_barcode_id,
|
||||
self.bar_freight_lot_id, self.assembly_order_code)
|
||||
if self.pad_product_id:
|
||||
self.pad_product_id.material_stock_moves(self.pad_freight_barcode_id,
|
||||
self.pad_freight_lot_id, self.assembly_order_code)
|
||||
if self.chuck_product_id:
|
||||
self.chuck_product_id.material_stock_moves(self.chuck_freight_barcode_id,
|
||||
self.chuck_freight_lot_id, self.assembly_order_code)
|
||||
# 创建功能刀具组装入库单
|
||||
self.env['stock.picking'].create_tool_stocking_picking(stock_lot, functional_tool_assembly, self)
|
||||
# 创建刀具物料出库单
|
||||
self.env['stock.picking'].create_tool_stocking_picking1(self)
|
||||
|
||||
# ============================创建功能刀具列表、安全库存记录===============================
|
||||
# 创建功能刀具列表记录
|
||||
@@ -665,6 +650,8 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
])
|
||||
cam_plan.write({'plan_execute_status': '2'})
|
||||
|
||||
logging.info('功能刀具组装完成!')
|
||||
|
||||
# 关闭弹出窗口
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -786,9 +773,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
def create_stocking_picking(self, stock_lot, functional_tool_assembly, obj):
|
||||
def create_tool_stocking_picking(self, stock_lot, functional_tool_assembly, obj):
|
||||
"""
|
||||
创建刀具组装入库单
|
||||
创建功能刀具组装入库单
|
||||
"""
|
||||
# 获取名称为刀具组装入库的作业类型
|
||||
picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '刀具组装入库')])
|
||||
@@ -807,6 +794,7 @@ class StockPicking(models.Model):
|
||||
'location_id': picking_id.location_id.id,
|
||||
'location_dest_id': picking_id.location_dest_id.id,
|
||||
'lot_id': stock_lot.id,
|
||||
'install_tool_time': fields.Datetime.now(),
|
||||
'qty_done': 1,
|
||||
'functional_tool_name_id': functional_tool_assembly.id,
|
||||
'functional_tool_type_id': obj.functional_tool_type_id.id,
|
||||
@@ -836,6 +824,102 @@ class StockPicking(models.Model):
|
||||
num = "%03d" % m
|
||||
return name + str(num)
|
||||
|
||||
def create_tool_stocking_picking1(self, obj):
|
||||
"""
|
||||
创建刀具物料出库单
|
||||
"""
|
||||
# 获取名称为内部调拨的作业类型
|
||||
picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '内部调拨')])
|
||||
# 创建刀具物料出库单
|
||||
picking_id = self.env['stock.picking'].create({
|
||||
'name': self._get_name_stock1(picking_type_id),
|
||||
'picking_type_id': picking_type_id.id,
|
||||
'location_id': self.env['stock.location'].search([('name', '=', '刀具房')]).id,
|
||||
'location_dest_id': self.env['stock.location'].search([('name', '=', '刀具组装位置')]).id,
|
||||
'origin': obj.assembly_order_code
|
||||
})
|
||||
# =============刀具物料出库===================
|
||||
stock_move_id = self.env['stock.move']
|
||||
datas = {'data': [], 'picking_id': picking_id}
|
||||
if obj.handle_code_id:
|
||||
datas['data'].append(
|
||||
{'current_location_id': self.env['sf.shelf.location'], 'lot_id': obj.handle_code_id})
|
||||
if obj.integral_product_id:
|
||||
datas['data'].append(
|
||||
{'current_location_id': obj.integral_freight_barcode_id, 'lot_id': obj.integral_freight_lot_id.lot_id})
|
||||
if obj.blade_product_id:
|
||||
datas['data'].append(
|
||||
{'current_location_id': obj.blade_freight_barcode_id, 'lot_id': obj.blade_freight_lot_id.lot_id})
|
||||
if obj.bar_product_id:
|
||||
datas['data'].append(
|
||||
{'current_location_id': obj.bar_freight_barcode_id, 'lot_id': obj.bar_freight_lot_id.lot_id})
|
||||
if obj.pad_product_id:
|
||||
datas['data'].append(
|
||||
{'current_location_id': obj.pad_freight_barcode_id, 'lot_id': obj.pad_freight_lot_id.lot_id})
|
||||
if obj.chuck_product_id:
|
||||
datas['data'].append(
|
||||
{'current_location_id': obj.chuck_freight_barcode_id, 'lot_id': obj.chuck_freight_lot_id.lot_id})
|
||||
# 创建刀具物料出库库存移动记录
|
||||
stock_move_id.create_tool_material_stock_moves(datas)
|
||||
# 将刀具物料出库库单的状态更改为就绪
|
||||
picking_id.action_confirm()
|
||||
# 修改刀具物料出库移动历史记录
|
||||
stock_move_id.write_tool_material_stock_move_lines(datas)
|
||||
# 设置数量,并验证完成
|
||||
picking_id.action_set_quantities_to_reservation()
|
||||
picking_id.button_validate()
|
||||
logging.info(f'刀具物料调拨单状态:{picking_id.state}')
|
||||
|
||||
def _get_name_stock1(self, picking_type_id):
|
||||
name = f'{picking_type_id.sequence_id.prefix}DJ/{date.today().strftime("%y")}'
|
||||
stock_id = self.env['stock.picking'].sudo().search(
|
||||
[('name', 'like', name), ('picking_type_id', '=', picking_type_id.id)],
|
||||
limit=1,
|
||||
order="id desc"
|
||||
)
|
||||
if not stock_id:
|
||||
num = "%05d" % 1
|
||||
else:
|
||||
m = int(stock_id.name[-5:]) + 1
|
||||
num = "%05d" % m
|
||||
return name + str(num)
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
def create_tool_material_stock_moves(self, datas):
|
||||
picking_id = datas['picking_id']
|
||||
data = datas['data']
|
||||
stock_move_ids = []
|
||||
for res in data:
|
||||
if res:
|
||||
# 创建库存移动记录
|
||||
stock_move_id = self.env['stock.move'].sudo().create({
|
||||
'name': picking_id.name,
|
||||
'picking_id': picking_id.id,
|
||||
'product_id': res['lot_id'].product_id.id,
|
||||
'location_id': picking_id.location_id.id,
|
||||
'location_dest_id': picking_id.location_dest_id.id,
|
||||
'product_uom_qty': 1.00,
|
||||
'reserved_availability': 1.00
|
||||
})
|
||||
stock_move_ids.append(stock_move_id)
|
||||
return stock_move_ids
|
||||
|
||||
def write_tool_material_stock_move_lines(self, datas):
|
||||
picking_id = datas['picking_id']
|
||||
data = datas['data']
|
||||
move_line_ids = picking_id.move_line_ids
|
||||
for move_line_id in move_line_ids:
|
||||
for res in data:
|
||||
if move_line_id.lot_id.product_id == res['lot_id'].product_id:
|
||||
move_line_id.write({
|
||||
'current_location_id': res.get('current_location_id').id,
|
||||
'lot_id': res.get('lot_id').id
|
||||
})
|
||||
return True
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
@@ -853,13 +937,6 @@ class ProductProduct(models.Model):
|
||||
'product_id': product_id[0].id,
|
||||
'company_id': self.env.company.id
|
||||
})
|
||||
# 获取位置对象
|
||||
location_inventory_ids = self.env['stock.location'].search([('name', 'in', ('Production', '生产'))])
|
||||
stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')])
|
||||
# 创建功能刀具该批次/序列号 库存移动和移动历史
|
||||
stock_lot.create_stock_quant(location_inventory_ids[-1], stock_location_id, functional_tool_assembly.id,
|
||||
obj.assembly_order_code, obj, obj.after_tool_groups_id)
|
||||
|
||||
return stock_lot
|
||||
|
||||
def get_stock_lot_name(self, obj):
|
||||
@@ -877,87 +954,3 @@ class ProductProduct(models.Model):
|
||||
m = int(stock_lot_id.name[-3:]) + 1
|
||||
num = "%03d" % m
|
||||
return '%s-%s' % (code, num)
|
||||
|
||||
def tool_material_stock_moves(self, tool_material, assembly_order_code):
|
||||
"""
|
||||
对刀具物料进行库存移动到 刀具组装位置
|
||||
"""
|
||||
# 获取位置对象
|
||||
location_inventory_id = tool_material.quant_ids.location_id[-1]
|
||||
stock_location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
|
||||
# 创建功能刀具该批次/序列号 库存移动和移动历史
|
||||
tool_material.create_stock_quant(location_inventory_id, stock_location_id, None, assembly_order_code, False,
|
||||
False)
|
||||
|
||||
def material_stock_moves(self, shelf_location_barcode_id, lot_id, assembly_order_code):
|
||||
# 创建库存移动记录
|
||||
stock_move_id = self.env['stock.move'].sudo().create({
|
||||
'name': assembly_order_code,
|
||||
'product_id': self.id,
|
||||
'location_id': self.env['stock.location'].search([('name', '=', '刀具房')]).id,
|
||||
'location_dest_id': self.env['stock.location'].search([('name', '=', '刀具组装位置')]).id,
|
||||
'product_uom_qty': 1.00,
|
||||
'state': 'done'
|
||||
})
|
||||
|
||||
# 创建移动历史记录
|
||||
stock_move_line_id = self.env['stock.move.line'].sudo().create({
|
||||
'product_id': self.id,
|
||||
'move_id': stock_move_id.id,
|
||||
'lot_id': lot_id.lot_id.id,
|
||||
'current_location_id': shelf_location_barcode_id.id,
|
||||
'install_tool_time': fields.Datetime.now(),
|
||||
'qty_done': 1.0,
|
||||
'state': 'done',
|
||||
})
|
||||
return stock_move_id, stock_move_line_id
|
||||
|
||||
|
||||
class StockLot(models.Model):
|
||||
_inherit = 'stock.lot'
|
||||
|
||||
def create_stock_quant(self, location_inventory_id, stock_location_id, functional_tool_assembly_id, name, obj,
|
||||
tool_groups_id):
|
||||
"""
|
||||
对功能刀具组装过程的功能刀具和刀具物料进行库存移动,以及创建移动历史
|
||||
"""
|
||||
|
||||
# 创建库存移动记录
|
||||
stock_move_id = self.env['stock.move'].sudo().create({
|
||||
'name': name,
|
||||
'product_id': self.product_id.id,
|
||||
'location_id': location_inventory_id.id,
|
||||
'location_dest_id': stock_location_id.id,
|
||||
'product_uom_qty': 1.00,
|
||||
'state': 'done'
|
||||
})
|
||||
|
||||
# 创建移动历史记录
|
||||
stock_move_line_id = self.env['stock.move.line'].sudo().create({
|
||||
'product_id': self.product_id.id,
|
||||
'functional_tool_name_id': functional_tool_assembly_id,
|
||||
'lot_id': self.id,
|
||||
'move_id': stock_move_id.id,
|
||||
'install_tool_time': fields.Datetime.now(),
|
||||
'qty_done': 1.0,
|
||||
'state': 'done',
|
||||
'functional_tool_type_id': False if not obj else obj.functional_tool_type_id.id,
|
||||
'diameter': None if not obj else obj.after_assembly_functional_tool_diameter,
|
||||
'knife_tip_r_angle': None if not obj else obj.after_assembly_knife_tip_r_angle,
|
||||
'code': '' if not obj else obj.code,
|
||||
'rfid': '' if not obj else obj.rfid,
|
||||
'functional_tool_name': '' if not obj else obj.after_assembly_functional_tool_name,
|
||||
'tool_groups_id': False if not tool_groups_id else tool_groups_id.id
|
||||
})
|
||||
return stock_move_id, stock_move_line_id
|
||||
|
||||
# class StockQuant(models.Model):
|
||||
# _inherit = 'stock.quant'
|
||||
#
|
||||
# @api.model_create_multi
|
||||
# def create(self, vals_list):
|
||||
# records = super(StockQuant, self).create(vals_list)
|
||||
# for record in records:
|
||||
# if record.lot_id.product_id.categ_id.name == '刀具':
|
||||
# record.lot_id.enroll_tool_material_stock()
|
||||
# return records
|
||||
|
||||
@@ -254,6 +254,7 @@ class SfShelf(models.Model):
|
||||
shelf_height = fields.Float(string='货架高度(m)')
|
||||
shelf_layer = fields.Integer(string='货架层数')
|
||||
layer_capacity = fields.Integer(string='层数容量')
|
||||
shelf_rotative_Boolean = fields.Boolean('循环货架', default=False)
|
||||
|
||||
# 是否有货位
|
||||
is_there_area = fields.Boolean(string='是否有货位', compute='_compute_is_there_area', default=False, store=True)
|
||||
@@ -361,6 +362,7 @@ class ShelfLocation(models.Model):
|
||||
|
||||
name = fields.Char('货位名称', required=True, size=20)
|
||||
barcode = fields.Char('货位编码', copy=False, size=50)
|
||||
rotative_Boolean = fields.Boolean('循环货位', related='shelf_id.shelf_rotative_Boolean', store=True)
|
||||
qr_code = fields.Binary(string='二维码', compute='_compute_location_qr_code', store=True)
|
||||
|
||||
# 货架
|
||||
@@ -416,19 +418,19 @@ class ShelfLocation(models.Model):
|
||||
host = printer_config.printer_id.ip_address
|
||||
port = printer_config.printer_id.port
|
||||
self.print_qr_code(barcode, host, port)
|
||||
# 获取当前wizard的视图ID或其他标识信息
|
||||
view_id = self.env.context.get('view_id')
|
||||
# 构造返回wizard页面的action字典
|
||||
action = {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': '返回 Wizard',
|
||||
'res_model': 'sf.shelf', # 替换为你的wizard模型名称
|
||||
'view_mode': 'form',
|
||||
'view_id': view_id, # 如果需要基于特定的视图返回
|
||||
'target': 'new', # 如果需要在新的窗口或标签页打开
|
||||
'res_id': self.shelf_id, # 如果你想要返回当前记录的视图
|
||||
}
|
||||
return action
|
||||
# # 获取当前wizard的视图ID或其他标识信息
|
||||
# view_id = self.env.context.get('view_id')
|
||||
# # 构造返回wizard页面的action字典
|
||||
# action = {
|
||||
# 'type': 'ir.actions.act_window',
|
||||
# 'name': '返回 Wizard',
|
||||
# 'res_model': 'sf.shelf', # 替换为你的wizard模型名称
|
||||
# 'view_mode': 'form',
|
||||
# 'view_id': view_id, # 如果需要基于特定的视图返回
|
||||
# 'target': 'new', # 如果需要在新的窗口或标签页打开
|
||||
# 'res_id': self.shelf_id, # 如果你想要返回当前记录的视图
|
||||
# }
|
||||
# return action
|
||||
|
||||
# # 仓库类别(selection:库区、库位、货位)
|
||||
# location_type = fields.Selection([
|
||||
@@ -557,8 +559,10 @@ class SfStockMoveLine(models.Model):
|
||||
_name = 'stock.move.line'
|
||||
_inherit = ['stock.move.line', 'printing.utils']
|
||||
|
||||
stock_lot_name = fields.Char('序列号名称', related='lot_id.name')
|
||||
current_location_id = fields.Many2one(
|
||||
'sf.shelf.location', string='当前货位', compute='_compute_current_location_id', store=True)
|
||||
'sf.shelf.location', string='当前货位', compute='_compute_current_location_id', store=True, readonly=False,
|
||||
domain="[('product_id', '=', product_id),'|',('product_sn_id.name', '=', stock_lot_name),('product_sn_ids.lot_id.name','=',stock_lot_name)]")
|
||||
# location_dest_id = fields.Many2one('stock.location', string='目标库位')
|
||||
location_dest_id_product_type = fields.Many2many(related='location_dest_id.product_type')
|
||||
location_dest_id_value = fields.Integer(compute='_compute_location_dest_id_value', store=True)
|
||||
@@ -622,6 +626,11 @@ class SfStockMoveLine(models.Model):
|
||||
if not qr_code_data:
|
||||
raise UserError("没有找到二维码数据。")
|
||||
lot_name = self.lot_name
|
||||
|
||||
# 增加"当为坯料时,只打印序列号的前面部分"
|
||||
if self.lot_name: # 确保 lot_name 存在
|
||||
if self.product_id.categ_id.name == '坯料':
|
||||
lot_name = lot_name.split('[', 1)[0]
|
||||
# host = "192.168.50.110" # 可以根据实际情况修改
|
||||
# port = 9100 # 可以根据实际情况修改
|
||||
|
||||
@@ -851,7 +860,9 @@ class SfStockMoveLine(models.Model):
|
||||
def compute_destination_location_id(self):
|
||||
for record in self:
|
||||
obj = self.env['sf.shelf.location'].search([('name', '=',
|
||||
self.destination_location_id.name)])
|
||||
record.destination_location_id.name)])
|
||||
if obj and obj.product_id and obj.product_id != record.product_id:
|
||||
raise ValidationError('目标货位【%s】已被【%s】产品占用!' % (obj.code, obj.product_id))
|
||||
if record.lot_id:
|
||||
if record.product_id.tracking == 'serial':
|
||||
shelf_location_obj = self.env['sf.shelf.location'].search(
|
||||
@@ -864,7 +875,7 @@ class SfStockMoveLine(models.Model):
|
||||
if obj:
|
||||
obj.product_sn_id = record.lot_id.id
|
||||
elif record.product_id.tracking == 'lot':
|
||||
self.put_shelf_location(record)
|
||||
record.put_shelf_location(record)
|
||||
if not obj.product_id:
|
||||
obj.product_id = record.product_id.id
|
||||
else:
|
||||
@@ -975,15 +986,26 @@ class SfStockPicking(models.Model):
|
||||
# 调用入库方法进行入库刀货位
|
||||
line.compute_destination_location_id()
|
||||
else:
|
||||
# 对除刀柄之外的刀具物料进行 目标货位必填校验
|
||||
# 对除刀柄之外的刀具物料入库到刀具房进行 目标货位必填校验
|
||||
if self.location_dest_id.name == '刀具房' and line.product_id.cutting_tool_material_id.name not in (
|
||||
'刀柄', False):
|
||||
raise ValidationError('请选择【%s】产品的目标货位!' % line.product_id.name)
|
||||
if line.current_location_id:
|
||||
# 对货位的批次产品进行出货
|
||||
line.put_shelf_location(line)
|
||||
|
||||
if line.current_location_id:
|
||||
# 按序列号管理的产品
|
||||
if line.current_location_id.product_sn_id:
|
||||
line.current_location_id.product_sn_id = False
|
||||
# line.current_location_id.location_status = '空闲'
|
||||
line.current_location_id.product_num = 0
|
||||
line.current_location_id.product_id = False
|
||||
else:
|
||||
# 对除刀柄之外的刀具物料从刀具房出库进行 当前货位必填校验
|
||||
if self.location_id.name == '刀具房' and line.product_id.cutting_tool_material_id.name not in (
|
||||
'刀柄', False):
|
||||
raise ValidationError('请选择【%s】产品的当前货位!' % line.product_id.name)
|
||||
|
||||
# 对入库作业的刀柄和托盘进行Rfid绑定校验
|
||||
for move in self.move_ids:
|
||||
@@ -1110,6 +1132,7 @@ class CustomStockMove(models.Model):
|
||||
采购入库扫码绑定Rfid码
|
||||
"""
|
||||
for record in self:
|
||||
logging.info('Rfid:%s' % barcode)
|
||||
if record:
|
||||
lot = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)])
|
||||
if lot:
|
||||
@@ -1121,7 +1144,9 @@ class CustomStockMove(models.Model):
|
||||
'该Rfid【%s】已经被序列号为【%s】的【%s】物料所占用!' % (barcode, lot.name, material))
|
||||
if '刀柄' in (record.product_id.cutting_tool_material_id.name or '') or '托盘' in (
|
||||
record.product_id.fixture_material_id.name or ''):
|
||||
logging.info('开始录入Rfid:%s' % record.move_line_nosuggest_ids)
|
||||
for move_line_nosuggest_id in record.move_line_nosuggest_ids:
|
||||
logging.info('录入的记录%s , Rfid:%s' % (move_line_nosuggest_id, move_line_nosuggest_id.rfid))
|
||||
if move_line_nosuggest_id.rfid:
|
||||
if move_line_nosuggest_id.rfid == barcode:
|
||||
if record.product_id.cutting_tool_material_id.name:
|
||||
@@ -1130,7 +1155,9 @@ class CustomStockMove(models.Model):
|
||||
raise ValidationError('该托盘的Rfid已经录入,请勿重复录入!!!')
|
||||
else:
|
||||
line_id = int(re.sub(r"\D", "", str(move_line_nosuggest_id.id)))
|
||||
self.env['stock.move.line'].sudo().search([('id', '=', line_id)]).write({'rfid': barcode})
|
||||
res = self.env['stock.move.line'].sudo().search([('id', '=', line_id)]).write(
|
||||
{'rfid': barcode})
|
||||
logging.info('Rfid是否录入:%s' % res)
|
||||
move_line_nosuggest_id.rfid = barcode
|
||||
break
|
||||
else:
|
||||
@@ -1184,6 +1211,12 @@ class CustomStockMove(models.Model):
|
||||
# todo 待控制
|
||||
if not lot_name:
|
||||
raise ValidationError("请先分配序列号")
|
||||
|
||||
# 增加"当为坯料时,只打印序列号的前面部分"
|
||||
if record.lot_name: # 确保 lot_name 存在
|
||||
if record.product_id.categ_id.name == '坯料':
|
||||
lot_name = lot_name.split('[', 1)[0]
|
||||
|
||||
# host = "192.168.50.110" # 可以根据实际情况修改
|
||||
# port = 9100 # 可以根据实际情况修改
|
||||
|
||||
|
||||
@@ -7,16 +7,18 @@
|
||||
<field name="inherit_id" ref="stock.view_stock_move_line_detailed_operation_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='location_id'][2]" position="after">
|
||||
<field name="current_location_id" force_save="1"/>
|
||||
<field name="stock_lot_name" invisible="1"/>
|
||||
<field name="current_location_id" force_save="1"
|
||||
options="{'no_create': True,'no_create_edit':True}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='location_dest_id'][2]" position="after">
|
||||
<field name="current_product_id" invisible="1"/>
|
||||
<field name="there_is_no_sn" invisible="1"/>
|
||||
<!-- <field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), -->
|
||||
<!-- '|', -->
|
||||
<!-- ('location_status', '=', '空闲'), -->
|
||||
<!-- ('location_status', '=', '占用'), ('product_id', '=', current_product_id) -->
|
||||
<!-- ]"/> -->
|
||||
<!-- <field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), -->
|
||||
<!-- '|', -->
|
||||
<!-- ('location_status', '=', '空闲'), -->
|
||||
<!-- ('location_status', '=', '占用'), ('product_id', '=', current_product_id) -->
|
||||
<!-- ]"/> -->
|
||||
<field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), '|',
|
||||
('location_status', '=', '空闲'), ('product_id', '=', current_product_id), ('product_sn_id',
|
||||
'=', there_is_no_sn)]" options="{'no_create': True,'no_create_edit':True}"/>
|
||||
@@ -55,6 +57,7 @@
|
||||
<field name="inherit_id" ref="stock.view_move_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form//sheet//group//group//field[@name='location_id']" position="after">
|
||||
<field name="stock_lot_name" invisible="1"/>
|
||||
<field name="current_location_id" options="{'no_create': False}" force_save="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//form//sheet//group//group//field[@name='location_dest_id']" position="after">
|
||||
@@ -99,11 +102,11 @@
|
||||
attrs="{'invisible': ['|', '|', '|', ('picking_type_code', '=', 'incoming'), ('immediate_transfer', '=', True), '&', ('state', '!=', 'assigned'), ('move_type', '!=', 'one'), '&', ('state', 'not in', ('assigned', 'confirmed')), ('move_type', '=', 'one')]}"
|
||||
data-hotkey="w"/>
|
||||
</xpath>
|
||||
<xpath expr="//form//header//button[@name='button_scrap']" position="replace">
|
||||
<button name="button_scrap" groups="sf_base.group_sf_stock_user" type="object" string="报废"
|
||||
attrs="{'invisible': ['|', '&', ('picking_type_code', '=', 'incoming'), ('state', '!=', 'done'), '&', ('picking_type_code', '=', 'outgoing'), ('state', '=', 'done')]}"
|
||||
data-hotkey="y"/>
|
||||
</xpath>
|
||||
<!-- <xpath expr="//form//header//button[@name='button_scrap']" position="replace">-->
|
||||
<!-- <button name="button_scrap" groups="sf_base.group_sf_stock_user" type="object" string="报废"-->
|
||||
<!-- attrs="{'invisible': ['|', '&', ('picking_type_code', '=', 'incoming'), ('state', '!=', 'done'), '&', ('picking_type_code', '=', 'outgoing'), ('state', '=', 'done')]}"-->
|
||||
<!-- data-hotkey="y"/>-->
|
||||
<!-- </xpath>-->
|
||||
<xpath expr="//form//header//button[@name='action_assign']" position="replace">
|
||||
<button name="action_assign" attrs="{'invisible': [('show_check_availability', '=', False)]}"
|
||||
string="检查可用量" type="object" class="oe_highlight"
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<field name="shelf_height" string="货架高度(m)"/>
|
||||
<field name="shelf_layer" string="货架层数"/>
|
||||
<field name="layer_capacity" string="层数容量"/>
|
||||
<field name="shelf_rotative_Boolean"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="货位">
|
||||
@@ -169,6 +170,7 @@
|
||||
<group>
|
||||
<field name="barcode" readonly="1"/>
|
||||
<field name="name" readonly="1"/>
|
||||
<field name="rotative_Boolean" invisible="1"/>
|
||||
<field name="shelf_id" readonly="1"/>
|
||||
<field name="location_id" readonly="1"/>
|
||||
<field name="product_id"/>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record model="ir.actions.act_window" id="stock.stock_picking_type_action">
|
||||
<field name="context">{'search_default_groupby_code':1}</field>
|
||||
</record>
|
||||
|
||||
<record id="view_location_form_sf_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.location.form.sf.inherit</field>
|
||||
|
||||
138
sg_wechat_enterprise/.gitignore
vendored
Normal file
138
sg_wechat_enterprise/.gitignore
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
3
sg_wechat_enterprise/__init__.py
Normal file
3
sg_wechat_enterprise/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from . import we_api
|
||||
from . import models
|
||||
from . import controllers
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user