Compare commits
319 Commits
release/re
...
master_sf_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bc4072a8f | ||
|
|
957c5583bd | ||
|
|
9c4c2b85dd | ||
|
|
56af286500 | ||
|
|
cc83029c72 | ||
|
|
79ab1cc573 | ||
|
|
bda3df7806 | ||
|
|
150b684354 | ||
|
|
d69dc20fd1 | ||
|
|
e9c9b77112 | ||
|
|
495f92bd80 | ||
|
|
8a97fd08e2 | ||
|
|
1551ea4b12 | ||
|
|
75c5cca9a0 | ||
|
|
6b6be85057 | ||
|
|
7fb3c32d07 | ||
|
|
8203975142 | ||
|
|
449cf5bfb1 | ||
|
|
d7d5ccc142 | ||
|
|
8710df6dc2 | ||
|
|
f5c1457707 | ||
|
|
5155135cb4 | ||
|
|
4421eed1d0 | ||
|
|
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 | ||
|
|
f005a29beb | ||
|
|
6a24776701 | ||
|
|
09d06980b5 | ||
|
|
8b492fc093 | ||
|
|
9e56aeda67 | ||
|
|
b4535e88c9 | ||
|
|
ba03790832 | ||
|
|
be94cd0d54 | ||
|
|
3148cd55b8 | ||
|
|
665ebaab9e | ||
|
|
65e209fe2a | ||
|
|
40969adc2c | ||
|
|
95e89d8979 | ||
|
|
5b400b746e | ||
|
|
828b4b0f6b | ||
|
|
27ba002b51 | ||
|
|
2cd83c87e2 | ||
|
|
ba87d07af7 | ||
|
|
7d2c705c35 | ||
|
|
f3c2db7add | ||
|
|
0af6d7f4cd | ||
|
|
a82a54c464 | ||
|
|
d4253b21fe | ||
|
|
8356e898aa | ||
|
|
f67d08fc88 | ||
|
|
0a40409c6c | ||
|
|
927f74213e | ||
|
|
8b8570a901 | ||
|
|
ec30a07394 | ||
|
|
9110c81c73 | ||
|
|
5f4ecf8ff9 | ||
|
|
e453508f17 | ||
|
|
733b554942 | ||
|
|
eff2032762 | ||
|
|
16a00bdb10 | ||
|
|
de6014d1dd | ||
|
|
66b66a935f | ||
|
|
612906e01d | ||
|
|
21f94e5523 | ||
|
|
f8c1d75b63 | ||
|
|
fcba3b18b7 | ||
|
|
c6a509c6f4 | ||
|
|
ecf265fee7 | ||
|
|
60560fe195 | ||
|
|
67b48814f6 | ||
|
|
21f2a704db | ||
|
|
1f32aafc9b | ||
|
|
b390712308 | ||
|
|
c035ab8156 | ||
|
|
c0b673bfd0 | ||
|
|
6dae144d76 | ||
|
|
25dddb5b3b | ||
|
|
4497fb04c1 | ||
|
|
bc4dc82beb | ||
|
|
47305a2e61 | ||
|
|
9e58835082 | ||
|
|
63fa0e0c37 | ||
|
|
c6c9974326 | ||
|
|
d63c3b76bf | ||
|
|
3793d0a174 | ||
|
|
903fdee420 | ||
|
|
ee17889fe8 | ||
|
|
5bec3d6061 | ||
|
|
0fc5b12894 | ||
|
|
3258b6cc75 | ||
|
|
017404fe45 | ||
|
|
cde6c76f83 | ||
|
|
7dea8c7c1e | ||
|
|
8ade3b43c4 | ||
|
|
c2b7abaae1 | ||
|
|
c1f33c5e14 | ||
|
|
01f55350e2 | ||
|
|
9202409a89 | ||
|
|
2e779c4a68 | ||
|
|
5751837ddd | ||
|
|
e2f86097a0 | ||
|
|
77ad0dd635 | ||
|
|
73e03bd815 | ||
|
|
51cd156e75 | ||
|
|
b447db1b13 | ||
|
|
e3911c8f5a | ||
|
|
2892cdd99f | ||
|
|
2862c5a888 | ||
|
|
ad8927fb83 | ||
|
|
e1f4e1e701 | ||
|
|
1e90b9a18a | ||
|
|
24edef023f | ||
|
|
4894576d25 | ||
|
|
904c63bfcb | ||
|
|
a86ceb951b | ||
|
|
dd9015dff9 | ||
|
|
642877ff45 | ||
|
|
c1935e62b9 | ||
|
|
aa0b6a9b21 | ||
|
|
9c6ca3758b | ||
|
|
42644d449f | ||
|
|
519c534a89 | ||
|
|
741c5cf3d6 | ||
|
|
fa7e023dd1 | ||
|
|
0f32b0acb1 | ||
|
|
6a7fa89b67 | ||
|
|
c13078291f | ||
|
|
a3580411d6 | ||
|
|
d7779cdb58 | ||
|
|
adafce85bd | ||
|
|
7be5b53767 | ||
|
|
2cc91eea75 | ||
|
|
8c285c0eb5 | ||
|
|
22e24c5ed3 | ||
|
|
4459ed2e81 | ||
|
|
52bf899a1f | ||
|
|
002727070d | ||
|
|
81327f04de | ||
|
|
e8c86c6306 | ||
|
|
fd6b579e2a | ||
|
|
0b2b162d85 | ||
|
|
e306d02ff2 | ||
|
|
09c56b2c07 | ||
|
|
1af160542c | ||
|
|
71246af16a | ||
|
|
e290760895 | ||
|
|
fdfd01605d | ||
|
|
8bd5841d7a | ||
|
|
6fc94042ee | ||
|
|
711e0d1437 | ||
|
|
49d55822cc | ||
|
|
ea6de0c248 | ||
|
|
2db81ac2cc | ||
|
|
a673630fd3 | ||
|
|
d213a2cf54 | ||
|
|
6c5b888bba | ||
|
|
aa6b476e35 | ||
|
|
263253e79e | ||
|
|
edda681940 | ||
|
|
7043d2b8b7 | ||
|
|
6d66872dee | ||
|
|
3ab378f3bd | ||
|
|
26c979ef1d | ||
|
|
9aa4858774 | ||
|
|
d883a7ff22 | ||
|
|
17678c53c9 | ||
|
|
fb3cc095b2 | ||
|
|
c437c185a4 | ||
|
|
b3eb3ee8fa | ||
|
|
b9ec821293 | ||
|
|
f8a9fcc0ce | ||
|
|
d12714dd65 | ||
|
|
a1bea537bb | ||
|
|
5350675355 | ||
|
|
65d2593db9 | ||
|
|
a529c5513e | ||
|
|
f5f881f256 | ||
|
|
d2babec1aa | ||
|
|
a1d8b88db2 | ||
|
|
7ab954ebbc | ||
|
|
f7723f1b9c | ||
|
|
fe88a416a7 | ||
|
|
ef80848e9b | ||
|
|
138dd40a9e | ||
|
|
dc210f7263 | ||
|
|
9055e7ed8b | ||
|
|
6890ddf615 | ||
|
|
6dc29fb50a | ||
|
|
412bf4b9be | ||
|
|
c7df18ace6 | ||
|
|
053eba5887 | ||
|
|
e935b2fa11 | ||
|
|
d5bc610214 | ||
|
|
2ca67eb8ad | ||
|
|
b6a69debd8 | ||
|
|
147ac35239 | ||
|
|
3c3f375120 | ||
|
|
c87f310bb3 | ||
|
|
f53eecbb57 | ||
|
|
1743fa45b5 | ||
|
|
75f30922e6 | ||
|
|
3a0db05c33 | ||
|
|
5f42b5d056 | ||
|
|
c698b50853 | ||
|
|
251786f6be | ||
|
|
66b4df5193 | ||
|
|
57b264b84d | ||
|
|
ff12a86406 | ||
|
|
b0b3ce7d99 | ||
|
|
8d02a94f78 | ||
|
|
4f6e4a8ed3 | ||
|
|
b524e385a1 | ||
|
|
d22f08d187 | ||
|
|
2ba53bbb02 | ||
|
|
38e0a62130 | ||
|
|
bf1b14290e | ||
|
|
1b6ca90bd4 |
@@ -504,3 +504,30 @@ div:has(.o_required_modifier) > label::before {
|
||||
background-color: #4A4F59;
|
||||
border-color: #4A4F59;
|
||||
}
|
||||
|
||||
// 功能刀具组装单 弹窗样式
|
||||
.o_horizontal_separator.mt-4.mb-3.text-uppercase.fw-bolder.small ~ div.col-lg-6 .o_inner_group.col-lg-6 {
|
||||
width: 100%;
|
||||
}
|
||||
.o_horizontal_separator.mt-4.mb-3.text-uppercase.fw-bolder.small ~ div .o_inner_group .o_wrap_field.d-flex.d-sm-contents.flex-column{
|
||||
display: flex!important;
|
||||
flex-direction: row!important;
|
||||
input {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置表格横向滚动
|
||||
.o_list_renderer.o_renderer {
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
// 设置表单页面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,51 +301,25 @@ 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']
|
||||
)
|
||||
|
||||
[('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
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class MrpWorkcenter(models.Model):
|
||||
|
||||
class MrpProductionWorkcenterLine(models.Model):
|
||||
_name = 'mrp.workorder'
|
||||
_inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin']
|
||||
_inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin', 'mail.thread', 'mail.activity.mixin']
|
||||
|
||||
quality_point_ids = fields.Many2many('quality.point', compute='_compute_quality_point_ids', store=True)
|
||||
quality_point_count = fields.Integer('Steps', compute='_compute_quality_point_count')
|
||||
@@ -47,14 +47,17 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
|
||||
is_last_lot = fields.Boolean('Is Last lot', compute='_compute_is_last_lot')
|
||||
is_first_started_wo = fields.Boolean('Is The first Work Order', compute='_compute_is_last_unfinished_wo')
|
||||
is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo', store=False)
|
||||
is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo',
|
||||
store=False)
|
||||
lot_id = fields.Many2one(related='current_quality_check_id.lot_id', readonly=False)
|
||||
move_id = fields.Many2one(related='current_quality_check_id.move_id', readonly=False)
|
||||
move_line_id = fields.Many2one(related='current_quality_check_id.move_line_id', readonly=False)
|
||||
move_line_ids = fields.One2many(related='move_id.move_line_ids')
|
||||
quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State", readonly=False)
|
||||
quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State",
|
||||
readonly=False)
|
||||
qty_done = fields.Float(related='current_quality_check_id.qty_done', readonly=False)
|
||||
test_type_id = fields.Many2one('quality.point.test_type', 'Test Type', related='current_quality_check_id.test_type_id')
|
||||
test_type_id = fields.Many2one('quality.point.test_type', 'Test Type',
|
||||
related='current_quality_check_id.test_type_id')
|
||||
test_type = fields.Char(related='test_type_id.technical_name')
|
||||
user_id = fields.Many2one(related='current_quality_check_id.user_id', readonly=False)
|
||||
worksheet_page = fields.Integer('Worksheet page')
|
||||
@@ -65,7 +68,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
def _compute_quality_point_ids(self):
|
||||
for workorder in self:
|
||||
quality_points = workorder.operation_id.quality_point_ids
|
||||
quality_points = quality_points.filtered(lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
|
||||
quality_points = quality_points.filtered(
|
||||
lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
|
||||
workorder.quality_point_ids = quality_points
|
||||
|
||||
@api.depends('operation_id')
|
||||
@@ -91,7 +95,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
@api.depends('check_ids')
|
||||
def _compute_finished_product_check_ids(self):
|
||||
for wo in self:
|
||||
wo.finished_product_check_ids = wo.check_ids.filtered(lambda c: c.finished_product_sequence == wo.qty_produced)
|
||||
wo.finished_product_check_ids = wo.check_ids.filtered(
|
||||
lambda c: c.finished_product_sequence == wo.qty_produced)
|
||||
|
||||
def write(self, values):
|
||||
res = super().write(values)
|
||||
@@ -138,7 +143,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
self.finished_lot_id = self.env['stock.lot'].create({
|
||||
'product_id': self.product_id.id,
|
||||
'company_id': self.company_id.id,
|
||||
'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env['ir.sequence'].next_by_code('stock.lot.serial'),
|
||||
'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env[
|
||||
'ir.sequence'].next_by_code('stock.lot.serial'),
|
||||
})
|
||||
|
||||
def _create_subsequent_checks(self):
|
||||
@@ -152,7 +158,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
"""
|
||||
# Create another quality check if necessary
|
||||
next_check = self.current_quality_check_id.next_check_id
|
||||
if next_check.component_id != self.current_quality_check_id.product_id or\
|
||||
if next_check.component_id != self.current_quality_check_id.product_id or \
|
||||
next_check.point_id != self.current_quality_check_id.point_id:
|
||||
# TODO: manage reservation here
|
||||
|
||||
@@ -279,7 +285,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
if self.current_quality_check_id:
|
||||
team = self.current_quality_check_id.team_id
|
||||
else:
|
||||
team = self.env['quality.alert.team'].search(['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
|
||||
team = self.env['quality.alert.team'].search(
|
||||
['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'quality.check',
|
||||
@@ -320,7 +327,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
production = wo.production_id
|
||||
|
||||
move_raw_ids = wo.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel'))
|
||||
move_finished_ids = wo.move_finished_ids.filtered(lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id)
|
||||
move_finished_ids = wo.move_finished_ids.filtered(
|
||||
lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id)
|
||||
previous_check = self.env['quality.check']
|
||||
for point in wo.quality_point_ids:
|
||||
# Check if we need a quality control for this point
|
||||
@@ -342,11 +350,13 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
if point.test_type == 'register_byproducts':
|
||||
moves = move_finished_ids.filtered(lambda m: m.product_id == point.component_id)
|
||||
if not moves:
|
||||
moves = production.move_finished_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||
moves = production.move_finished_ids.filtered(
|
||||
lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||
elif point.test_type == 'register_consumed_materials':
|
||||
moves = move_raw_ids.filtered(lambda m: m.product_id == point.component_id)
|
||||
if not moves:
|
||||
moves = production.move_raw_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||
moves = production.move_raw_ids.filtered(
|
||||
lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||
else:
|
||||
check = self.env['quality.check'].create(values)
|
||||
previous_check.next_check_id = check
|
||||
@@ -363,8 +373,10 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
processed_move |= moves
|
||||
|
||||
# Generate quality checks associated with unreferenced components
|
||||
moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: (move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id)
|
||||
quality_team_id = self.env['quality.alert.team'].search(['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id
|
||||
moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: (
|
||||
move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id)
|
||||
quality_team_id = self.env['quality.alert.team'].search(
|
||||
['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id
|
||||
for move in moves_without_check:
|
||||
values = {
|
||||
'production_id': production.id,
|
||||
@@ -412,7 +424,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
|
||||
backorder = False
|
||||
# Trigger the backorder process if we produce less than expected
|
||||
if float_compare(self.qty_producing, self.qty_remaining, precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
|
||||
if float_compare(self.qty_producing, self.qty_remaining,
|
||||
precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
|
||||
backorder = self.production_id._split_productions()[1:]
|
||||
for workorder in backorder.workorder_ids:
|
||||
if workorder.product_tracking == 'serial':
|
||||
@@ -423,7 +436,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
else:
|
||||
if self.operation_id:
|
||||
backorder = (self.production_id.procurement_group_id.mrp_production_ids - self.production_id).filtered(
|
||||
lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in ('cancel', 'done')
|
||||
lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in (
|
||||
'cancel', 'done')
|
||||
)[:1]
|
||||
else:
|
||||
index = list(self.production_id.workorder_ids).index(self)
|
||||
@@ -442,7 +456,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
wo.current_quality_check_id._update_component_quantity()
|
||||
if not self.env.context.get('no_start_next'):
|
||||
if self.operation_id:
|
||||
return backorder.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
|
||||
return backorder.workorder_ids.filtered(
|
||||
lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
|
||||
else:
|
||||
index = list(self.production_id.workorder_ids).index(self)
|
||||
return backorder.workorder_ids[index].open_tablet_view()
|
||||
@@ -466,7 +481,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
|
||||
def open_tablet_view(self):
|
||||
self.ensure_one()
|
||||
if not self.is_user_working and self.working_state != 'blocked' and self.state in ('ready', 'waiting', 'progress', 'pending'):
|
||||
if not self.is_user_working and self.working_state != 'blocked' and self.state in (
|
||||
'ready', 'waiting', 'progress', 'pending'):
|
||||
self.button_start()
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("mrp_workorder.tablet_client_action")
|
||||
action['target'] = 'fullscreen'
|
||||
@@ -521,7 +537,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
data = {
|
||||
'mrp.workorder': self.read(self._get_fields_for_tablet(), load=False)[0],
|
||||
'quality.check': self.check_ids._get_fields_for_tablet(sorted_check_list),
|
||||
'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[0] if self.operation_id else {},
|
||||
'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[
|
||||
0] if self.operation_id else {},
|
||||
'working_state': self.workcenter_id.working_state,
|
||||
'views': {
|
||||
'workorder': self.env.ref('mrp_workorder.mrp_workorder_view_form_tablet').id,
|
||||
@@ -553,7 +570,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
|
||||
return {
|
||||
'duration': self.duration,
|
||||
'position': bisect_left(last30op, self.duration), # which position regarded other workorders ranked by duration
|
||||
'position': bisect_left(last30op, self.duration),
|
||||
# which position regarded other workorders ranked by duration
|
||||
'quality_score': score,
|
||||
'show_rainbow': show_rainbow,
|
||||
}
|
||||
|
||||
@@ -27,6 +27,13 @@
|
||||
</field>
|
||||
</page>
|
||||
</page>
|
||||
<xpath expr="//sheet" position="after">
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids" options="{'post_refresh': 'recipients'}"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ class ToolInventory(models.Model):
|
||||
work_material = fields.Selection([('钢', '钢'), ('铝', '铝')], string='加工材料')
|
||||
life_span = fields.Float('寿命(min)')
|
||||
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组')
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组', required=True)
|
||||
|
||||
active = fields.Boolean('已归档', default=True)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
.o_data_row .w-100 {
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
display: block !important;
|
||||
//display: block !important;
|
||||
}
|
||||
|
||||
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove) {
|
||||
|
||||
@@ -555,9 +555,9 @@
|
||||
<field name="model">sf.tool.inventory</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具清单" create="1" edit="1" delete="0" editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="name" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="functional_cutting_tool_model_id"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="tool_groups_id" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="work_material"/>
|
||||
<field name="life_span"/>
|
||||
<field name="prefix" optional="hide"/>
|
||||
|
||||
@@ -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__)
|
||||
@@ -14,7 +14,7 @@ _logger = logging.getLogger(__name__)
|
||||
class JdEclp(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
senderNickName = fields.Char(string='寄件工厂简称', required=True, default='MW')
|
||||
senderNickName = fields.Char(string='寄件工厂简称', required=True, default='XT')
|
||||
|
||||
# receiverName = fields.Char(string='收件人姓名')
|
||||
# receiverMobile = fields.Char(string='收件人电话')
|
||||
@@ -67,9 +67,10 @@ class JdEclp(models.Model):
|
||||
"""
|
||||
判断是否为出库单
|
||||
"""
|
||||
if self.name:
|
||||
is_check_out = self.name.split('/')
|
||||
self.check_out = is_check_out[1]
|
||||
for record in self:
|
||||
if record.name:
|
||||
is_check_out = record.name.split('/')
|
||||
record.check_out = is_check_out[1]
|
||||
|
||||
@api.depends('carrier_tracking_ref')
|
||||
def query_bill_pdf(self):
|
||||
@@ -160,15 +161,25 @@ class JdEclp(models.Model):
|
||||
url2 = config['bfm_url'] + '/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']
|
||||
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):
|
||||
"""
|
||||
|
||||
@@ -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,16 +45,26 @@
|
||||
<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%')]"/> -->
|
||||
<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')]}"/>
|
||||
@@ -64,23 +74,21 @@
|
||||
<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')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="logistics_status"/>
|
||||
</xpath>
|
||||
<xpath expr="//group//field[@name='group_id']" position="after">
|
||||
<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[@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>
|
||||
@@ -10,6 +10,7 @@
|
||||
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name='is_bfm' invisible="1"/>
|
||||
<field name='categ_type' invisible="1"/>
|
||||
<field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
|
||||
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
|
||||
<field name="upload_model_file"
|
||||
widget="many2many_binary"
|
||||
@@ -87,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"
|
||||
@@ -304,7 +305,7 @@
|
||||
<field name="cutting_tool_blade_type"
|
||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="cutting_tool_coarse_medium_fine" string="粗/中/精" placeholder="请选择"
|
||||
attrs="{'required': [('cutting_tool_type','=','整体式刀具')],'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))],'readonly': [('id', '!=', False)]}"/>
|
||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))],'readonly': [('id', '!=', False)]}"/>
|
||||
<!--整体式刀具-->
|
||||
<field name="cutting_tool_shank_diameter" string="柄部直径(mm)" class="diameter"
|
||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
<filter string="人工编程" name="manual_quotation" domain="[('manual_quotation', '=', True)]"/>
|
||||
<filter string="自动编程" name="no_manual_quotation" domain="[('manual_quotation', '=', False)]"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='production_id']" position="before">
|
||||
<field name="product_tmpl_name"/>
|
||||
<field name="rfid_code"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -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,23 +17,30 @@
|
||||
</group>
|
||||
<div>
|
||||
<div>
|
||||
<field name="button_compensation_state" attrs='{"invisible": ["|",
|
||||
("state","!=","progress"),("user_permissions","=",False)]}'/>
|
||||
<button string="一键补偿" name="compensation" type="object" confirm="是否确认下发补偿"
|
||||
class="btn-primary" attrs='{"invisible": ["|",
|
||||
("state","!=","progress"),("user_permissions","=",False)]}'/>
|
||||
<span> </span>
|
||||
<button string="一键下发" name="up_all" type="object" style="text-align: right;" confirm="是否确认一键下发"
|
||||
class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",
|
||||
("state","!=","progress"),("user_permissions","=",False)]}'/>
|
||||
<span> </span>
|
||||
<button string="合并下发" id="action_up_select" name="%(sf_machine_connect.action_up_select)d"
|
||||
type="action" class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",
|
||||
("state","!=","progress"),("user_permissions","=",False)]}'/>
|
||||
<span> </span>
|
||||
<button string="一键合并下发" name="up_merge_all" type="object" style="text-align: right;" confirm="是否确认一键合并下发"
|
||||
class="btn-primary" context="{'default_workorder_id': id}" 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 string="一键补偿" name="compensation" type="object" confirm="是否确认下发补偿"-->
|
||||
<!-- class="btn-primary" attrs='{"invisible": ["|",-->
|
||||
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>-->
|
||||
<!-- <span> </span>-->
|
||||
<!-- <button string="一键下发" name="up_all" type="object" style="text-align: right;" confirm="是否确认一键下发"-->
|
||||
<!-- class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",-->
|
||||
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>-->
|
||||
<!-- <span> </span>-->
|
||||
<!-- <button string="合并下发" id="action_up_select" name="%(sf_machine_connect.action_up_select)d"-->
|
||||
<!-- type="action" class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",-->
|
||||
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>-->
|
||||
<!-- <span> </span>-->
|
||||
<!-- <button string="一键合并下发" name="up_merge_all" type="object" style="text-align: right;" confirm="是否确认一键合并下发"-->
|
||||
<!-- class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",-->
|
||||
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>-->
|
||||
</div>
|
||||
</div>
|
||||
</group>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<tree>
|
||||
<field name="sequence_number"/>
|
||||
<field name="program_name"/>
|
||||
<field name="cnc_id" string="文件"/>
|
||||
<field name="functional_tool_type_id"/>
|
||||
<field name="cutting_tool_name"/>
|
||||
<field name="cutting_tool_no"/>
|
||||
|
||||
@@ -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="是否确认下发此程序"-->
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -8,7 +8,7 @@ from odoo.http import request
|
||||
|
||||
class Manufacturing_Connect(http.Controller):
|
||||
|
||||
@http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def get_Work_Info(self, **kw):
|
||||
"""
|
||||
@@ -162,7 +162,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)], limit=1)
|
||||
if not workorder:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单不存在'}
|
||||
return json.JSONEncoder().encode(res)
|
||||
@@ -203,31 +204,35 @@ 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)], limit=1)
|
||||
if not workorder:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单不存在'}
|
||||
return json.JSONEncoder().encode(res)
|
||||
if workorder.state != 'progress':
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单未开始'}
|
||||
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 = '待解除装夹'
|
||||
|
||||
# 根据工单的实际结束时间修改排程单的结束时间、状态,同时修改销售订单的状态
|
||||
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'})
|
||||
# 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'})
|
||||
|
||||
@@ -315,15 +320,15 @@ class Manufacturing_Connect(http.Controller):
|
||||
[('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', 'CNC加工')])
|
||||
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程序数据'}
|
||||
@@ -458,6 +463,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
if f'RfidCode{i}' in ret:
|
||||
rfid_code = ret[f'RfidCode{i}']
|
||||
logging.info('RfidCode:%s' % rfid_code)
|
||||
if rfid_code is not None:
|
||||
domain = [
|
||||
('rfid_code', '=', rfid_code),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
@@ -469,7 +475,8 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info(
|
||||
'制造订单产线状态:%s' % order.production_id.production_line_state)
|
||||
order.production_id.write({'production_line_state': '已上产线'})
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search([
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[
|
||||
('rfid_code', '=', rfid_code), ('type', '=', '上产线'),
|
||||
('production_id', '=', order.production_id.id)])
|
||||
if workpiece_delivery.status == '待下发':
|
||||
@@ -513,6 +520,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
if f'RfidCode{i}' in ret:
|
||||
rfid_code = ret[f'RfidCode{i}']
|
||||
logging.info('RfidCode:%s' % rfid_code)
|
||||
if rfid_code is not None:
|
||||
domain = [
|
||||
('rfid_code', '=', rfid_code),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
@@ -524,7 +532,8 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info(
|
||||
'制造订单产线状态:%s' % order.production_id.production_line_state)
|
||||
order.production_id.write({'production_line_state': '已下产线'})
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search([
|
||||
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)
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
import requests
|
||||
import logging
|
||||
import time
|
||||
from odoo import fields, models
|
||||
from odoo import fields, models, api
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class AgvSetting(models.Model):
|
||||
@@ -59,11 +60,17 @@ class AgvTaskRoute(models.Model):
|
||||
('F01', '搬运'), ], string='任务类型', default="F01")
|
||||
route_type = fields.Selection([
|
||||
('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型')
|
||||
start_site_id = fields.Many2one('sf.agv.site', '起点接驳站位置编号')
|
||||
end_site_id = fields.Many2one('sf.agv.site', '终点接驳站位置编号')
|
||||
start_site_id = fields.Many2one('sf.agv.site', '起点接驳站')
|
||||
end_site_id = fields.Many2one('sf.agv.site', '终点接驳站')
|
||||
destination_production_line_id = fields.Many2one('sf.production.line', '目的生产线')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
|
||||
@api.constrains('end_site_id')
|
||||
def _check_end_site_id(self):
|
||||
if self.end_site_id:
|
||||
if self.end_site_id == self.start_site_id:
|
||||
raise UserError("您选择的终点接驳站与起点接驳站重复,请重新选择")
|
||||
|
||||
|
||||
class Center_controlInterfaceLog(models.Model):
|
||||
_name = 'center_control.interface.log'
|
||||
|
||||
@@ -5,7 +5,7 @@ import re
|
||||
import requests
|
||||
from itertools import groupby
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError,ValidationError
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
|
||||
|
||||
@@ -30,13 +30,10 @@ class MrpProduction(models.Model):
|
||||
# ('completed', '已完工')
|
||||
# ])
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('confirmed', 'Confirmed'),
|
||||
('progress', '待排程'),
|
||||
('pending_cam', '待装夹'),
|
||||
('pending_processing', '待加工'),
|
||||
('pending_era_cam', '待解除装夹'),
|
||||
('completed', '已完工'),
|
||||
('draft', '草稿'),
|
||||
('confirmed', '待排程'),
|
||||
('pending_cam', '待加工'),
|
||||
('progress', '加工中'),
|
||||
('to_close', 'To Close'),
|
||||
('done', 'Done'),
|
||||
('cancel', 'Cancelled')], string='State',
|
||||
@@ -53,13 +50,14 @@ class MrpProduction(models.Model):
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
programming_no = fields.Char('编程单号')
|
||||
work_state = fields.Char('业务状态')
|
||||
programming_state = fields.Char('编程状态')
|
||||
programming_state = fields.Selection(
|
||||
[('编程中', '编程中'), ('已编程', '已编程')], string='编程状态', tracking=True)
|
||||
glb_file = fields.Binary("glb模型文件")
|
||||
production_line_id = fields.Many2one('sf.production.line', string='生产线')
|
||||
production_line_id = fields.Many2one('sf.production.line', string='生产线', tracking=True)
|
||||
plan_start_processing_time = fields.Datetime('计划开始加工时间')
|
||||
production_line_state = fields.Selection(
|
||||
[('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
|
||||
string='上/下产线', default='待上产线')
|
||||
string='上/下产线', default='待上产线', tracking=True)
|
||||
# 工序状态
|
||||
# Todo 研究下用法
|
||||
process_state = fields.Selection([
|
||||
@@ -77,10 +75,11 @@ class MrpProduction(models.Model):
|
||||
part_drawing = fields.Binary('零件图纸')
|
||||
|
||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
||||
rework_production = fields.Many2one('mrp.production', string='返工的制造订单')
|
||||
|
||||
@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')
|
||||
'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:
|
||||
@@ -108,22 +107,19 @@ 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 == 'to_close' and production.schedule_state == '已排':
|
||||
production.state = 'pending_cam'
|
||||
|
||||
if production.state == 'progress':
|
||||
if all(wo_state not in ('progress', 'done') for wo_state in production.workorder_ids.mapped('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'
|
||||
|
||||
def action_check(self):
|
||||
"""
|
||||
@@ -154,6 +150,28 @@ class MrpProduction(models.Model):
|
||||
for production in self:
|
||||
production.maintenance_count = len(production.request_ids)
|
||||
|
||||
# 制造订单报废:编程单更新
|
||||
def updateCNC(self):
|
||||
try:
|
||||
res = {'production_no': self.name, 'programming_no': self.programming_no,
|
||||
'order_no': self.origin}
|
||||
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'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
res['token'] = configsettings['token']
|
||||
ret = requests.post(config_url, json={}, data=res, headers=config_header)
|
||||
ret = ret.json()
|
||||
logging.info('updateCNC-ret:%s' % ret)
|
||||
if ret['status'] == 1:
|
||||
self.write({'work_state': '已编程'})
|
||||
else:
|
||||
raise UserError(ret['message'])
|
||||
except Exception as e:
|
||||
logging.info('updateCNC error:%s' % e)
|
||||
raise UserError("更新程单失败,请联系管理员")
|
||||
|
||||
# cnc程序获取
|
||||
def fetchCNC(self, production_names):
|
||||
cnc = self.env['mrp.production'].search([('id', '=', self.id)])
|
||||
@@ -171,6 +189,7 @@ class MrpProduction(models.Model):
|
||||
'production_no': production_names,
|
||||
'machine_tool_code': '',
|
||||
'product_name': cnc.product_id.name,
|
||||
'remanufacture_type': '',
|
||||
'model_code': cnc.product_id.model_code,
|
||||
'material_code': self.env['sf.production.materials'].search(
|
||||
[('id', '=', cnc.product_id.materials_id.id)]).materials_no,
|
||||
@@ -268,15 +287,7 @@ class MrpProduction(models.Model):
|
||||
# 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制;
|
||||
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
|
||||
|
||||
def _create_workorder3(self):
|
||||
# 根据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]
|
||||
def _create_workorder3(self, item):
|
||||
for production in self:
|
||||
if not production.bom_id or not production.product_id:
|
||||
continue
|
||||
@@ -304,18 +315,6 @@ class MrpProduction(models.Model):
|
||||
'state': 'pending',
|
||||
}]
|
||||
if production.product_id.categ_id.type == '成品':
|
||||
if production.product_id.id in product_id_to_production_names:
|
||||
# # 同一个产品多个制造订单对应一个编程单和模型库
|
||||
# # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递
|
||||
if not production.programming_no:
|
||||
production_programming = self.search(
|
||||
[('product_id.id', '=', production.product_id.id), ('origin', '=', production.origin)],
|
||||
limit=1, order='id asc')
|
||||
if not production_programming.programming_no:
|
||||
production.fetchCNC(', '.join(product_id_to_production_names[production.product_id.id]))
|
||||
else:
|
||||
production.write({'programming_no': production_programming.programming_no,
|
||||
'programming_state': '编程中'})
|
||||
# # 根据加工面板的面数及对应的工序模板生成工单
|
||||
i = 0
|
||||
processing_panel_len = len(production.product_id.model_processing_panel.split(','))
|
||||
@@ -328,13 +327,14 @@ class MrpProduction(models.Model):
|
||||
for route in product_routing_workcenter:
|
||||
if route.is_repeat is True:
|
||||
workorders_values.append(
|
||||
self.env['mrp.workorder'].json_workorder_str(k, production, route))
|
||||
if i == processing_panel_len and route.routing_type == '解除装夹':
|
||||
workorders_values.append(
|
||||
self.env['mrp.workorder'].json_workorder_str(k, production, route))
|
||||
self.env['mrp.workorder'].json_workorder_str(k, production, route, item))
|
||||
# if i == processing_panel_len and route.routing_type == '解除装夹':
|
||||
# workorders_values.append(
|
||||
# self.env['mrp.workorder'].json_workorder_str(k, production, route))
|
||||
# 表面工艺工序
|
||||
# 获取表面工艺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 = []
|
||||
@@ -349,6 +349,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:
|
||||
@@ -379,6 +380,52 @@ class MrpProduction(models.Model):
|
||||
workorders_values.append(
|
||||
self.env['mrp.workorder'].json_workorder_str('', production, route))
|
||||
production.workorder_ids = workorders_values
|
||||
# for production_item in productions:
|
||||
process_parameter_workorder = self.env['mrp.workorder'].search(
|
||||
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.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)
|
||||
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)
|
||||
if m == len(consecutive_workorders) - 1 and m != 0:
|
||||
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
|
||||
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)
|
||||
if is_pick is False and m == 0:
|
||||
if len(sorted_workorders) == 1:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production)
|
||||
else:
|
||||
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production)
|
||||
for workorder in production.workorder_ids:
|
||||
workorder.duration_expected = workorder._get_duration_expected()
|
||||
|
||||
@@ -406,20 +453,15 @@ class MrpProduction(models.Model):
|
||||
|
||||
# 工单排序
|
||||
def _reset_work_order_sequence1(self, k):
|
||||
sequen = 0
|
||||
for rec in self:
|
||||
current_sequence = 10
|
||||
cnc_workorder = rec.workorder_ids.filtered(lambda wo: wo.name == "CNC加工")
|
||||
cnc_back_workorder = rec.workorder_ids.filtered(lambda wo: wo.name == "CNC加工(返工)")
|
||||
for work in rec.workorder_ids:
|
||||
work.sequence = current_sequence
|
||||
current_sequence += 10
|
||||
if work.name == '后置三元质量检测' and work.processing_panel == k:
|
||||
sequen = work.sequence
|
||||
|
||||
for work in rec.workorder_ids:
|
||||
if work.name == '后置三元质量检测(返工)' and work.processing_panel == k:
|
||||
work.sequence = sequen + 2
|
||||
if work.name == 'CNC加工(返工)' and work.processing_panel == k:
|
||||
work.sequence = sequen + 1
|
||||
if work.name == cnc_workorder.name and work.processing_panel == k:
|
||||
cnc_back_workorder.write({'sequence': work.sequence + 1})
|
||||
print(cnc_back_workorder.sequence)
|
||||
elif work.routing_type not in ['装夹预调'] and work != cnc_back_workorder:
|
||||
work.sequence += 1
|
||||
|
||||
# 在制造订单上新增工单
|
||||
def _create_workorder1(self, k):
|
||||
@@ -459,13 +501,7 @@ class MrpProduction(models.Model):
|
||||
order='sequence asc'
|
||||
)
|
||||
i += 1
|
||||
|
||||
for route in routingworkcenter:
|
||||
|
||||
# if route.routing_type == '后置三元质量检测':
|
||||
# workorders_values.append(
|
||||
# self.env['mrp.workorder'].json_workorder_str1(k, production, route)
|
||||
# )
|
||||
if route.routing_type == 'CNC加工':
|
||||
workorders_values.append(
|
||||
self.env['mrp.workorder'].json_workorder_str1(k, production, route))
|
||||
@@ -484,15 +520,23 @@ class MrpProduction(models.Model):
|
||||
def _reset_work_order_sequence(self):
|
||||
for rec in self:
|
||||
sequence_list = {}
|
||||
# 产品模型类型
|
||||
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:
|
||||
sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
|
||||
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
|
||||
@@ -518,12 +562,21 @@ class MrpProduction(models.Model):
|
||||
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('该产品没有选择【模版类型】!')
|
||||
|
||||
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)
|
||||
# if work.name == '获取CNC加工程序':
|
||||
@@ -532,8 +585,8 @@ class MrpProduction(models.Model):
|
||||
# work.button_finish()
|
||||
|
||||
# 创建工单并进行排序
|
||||
def _create_workorder(self):
|
||||
self._create_workorder3()
|
||||
def _create_workorder(self, item):
|
||||
self._create_workorder3(item)
|
||||
self._reset_work_order_sequence()
|
||||
return True
|
||||
|
||||
@@ -577,9 +630,10 @@ class MrpProduction(models.Model):
|
||||
})
|
||||
|
||||
for production in self:
|
||||
logging.info('qty_produced:%s' % production.qty_produced)
|
||||
production.write({
|
||||
'date_finished': fields.Datetime.now(),
|
||||
'product_qty': production.qty_produced,
|
||||
'product_qty': production.product_qty if production.qty_produced < 1.0 else production.qty_produced,
|
||||
'priority': '0',
|
||||
'is_locked': True,
|
||||
'state': 'done',
|
||||
@@ -605,6 +659,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_')}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import re
|
||||
|
||||
import json
|
||||
import logging
|
||||
import base64
|
||||
import urllib.parse
|
||||
@@ -19,7 +19,9 @@ 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 = 'id'
|
||||
|
||||
product_tmpl_name = fields.Char('坯料产品名称', related='production_bom_id.bom_line_ids.product_id.name')
|
||||
|
||||
product_tmpl_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True,
|
||||
string="坯料长度(mm)")
|
||||
@@ -102,7 +104,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
Z10_axis = fields.Float(default=0)
|
||||
X_deviation_angle = fields.Integer(string="X轴偏差度", default=0)
|
||||
test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], default='合格',
|
||||
string="检测结果")
|
||||
string="检测结果", tracking=True)
|
||||
cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序")
|
||||
cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序")
|
||||
tray_code = fields.Char(string="托盘编码")
|
||||
@@ -133,12 +135,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
return action
|
||||
|
||||
supplier_id = fields.Many2one('res.partner', string='外协供应商')
|
||||
equipment_id = fields.Many2one('maintenance.equipment', string='加工设备')
|
||||
is_ok = fields.Boolean(string='是否合格')
|
||||
# 加工人
|
||||
processing_user_id = fields.Many2one('res.users', string='加工人')
|
||||
# 检测人
|
||||
inspection_user_id = fields.Many2one('res.users', string='检测人')
|
||||
equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True)
|
||||
# 保存名称
|
||||
save_name = fields.Char(string='检测文件保存名称', compute='_compute_save_name')
|
||||
# 获取数据状态
|
||||
@@ -195,11 +192,18 @@ class ResMrpWorkOrder(models.Model):
|
||||
rfid_code_old = fields.Char('RFID码(已解除)')
|
||||
|
||||
production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id',
|
||||
string='生产线', store=True)
|
||||
string='生产线', store=True, tracking=True)
|
||||
production_line_state = fields.Selection(related='production_id.production_line_state',
|
||||
string='上/下产线', store=True)
|
||||
string='上/下产线', store=True, tracking=True)
|
||||
detection_report = fields.Binary('检测报告', readonly=True)
|
||||
is_remanufacture = fields.Boolean(string='是否重新生成制造订单', default=True)
|
||||
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)
|
||||
detailed_reason = fields.Text('详细原因')
|
||||
|
||||
# is_send_program_again = fields.Boolean(string='是否重新下发NC程序', default=False)
|
||||
|
||||
@api.onchange('rfid_code')
|
||||
def _onchange(self):
|
||||
@@ -226,16 +230,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:
|
||||
@@ -466,7 +460,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
raise UserError(_("该工单暂未完成,无法进行工件配送"))
|
||||
|
||||
# 拼接工单对象属性值
|
||||
def json_workorder_str(self, k, production, route):
|
||||
def json_workorder_str(self, k, production, route, item):
|
||||
# 计算预计时长duration_expected
|
||||
if route.routing_type == '切割':
|
||||
duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
|
||||
@@ -499,7 +493,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
'processing_panel': k,
|
||||
'quality_point_ids': route.route_workcenter_id.quality_point_ids,
|
||||
'routing_type': route.routing_type,
|
||||
'work_state': '待发起',
|
||||
# 'work_state': '待发起',
|
||||
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,
|
||||
route.routing_type,
|
||||
production.product_id),
|
||||
@@ -508,6 +502,10 @@ class ResMrpWorkOrder(models.Model):
|
||||
'date_planned_finished': datetime.now() + timedelta(days=1),
|
||||
'duration_expected': duration_expected,
|
||||
'duration': 0,
|
||||
'cnc_ids': False if route.routing_type != 'CNC加工' else self.env['sf.cnc.processing']._json_cnc_processing(
|
||||
k, item),
|
||||
'cmm_ids': False if route.routing_type != 'CNC加工' else self.env['sf.cmm.program']._json_cmm_program(k,
|
||||
item),
|
||||
'workpiece_delivery_ids': False if not route.routing_type == '装夹预调' else self._json_workpiece_delivery_list(
|
||||
production)
|
||||
}]
|
||||
@@ -672,18 +670,64 @@ class ResMrpWorkOrder(models.Model):
|
||||
"""
|
||||
重新生成制造订单或者重新生成工单
|
||||
"""
|
||||
if self.test_results == '报废':
|
||||
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_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[
|
||||
@@ -704,13 +748,36 @@ class ResMrpWorkOrder(models.Model):
|
||||
'mail.message_origin_link',
|
||||
values={'self': production, 'origin': origin_production},
|
||||
subtype_id=self.env.ref('mail.mt_note').id)
|
||||
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 = '合格'
|
||||
|
||||
'''
|
||||
创建生产计划
|
||||
'''
|
||||
# 工单耗时
|
||||
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, '', {
|
||||
@@ -720,7 +787,6 @@ class ResMrpWorkOrder(models.Model):
|
||||
'name': '%s(返工)' % route.route_workcenter_id.name,
|
||||
'processing_panel': k,
|
||||
'routing_type': route.routing_type,
|
||||
'work_state': '' if not route.routing_type == '获取CNC加工程序' else '待发起',
|
||||
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,
|
||||
route.routing_type,
|
||||
production.product_id),
|
||||
@@ -728,10 +794,37 @@ class ResMrpWorkOrder(models.Model):
|
||||
'date_planned_finished': datetime.now() + timedelta(days=1),
|
||||
'duration_expected': 60,
|
||||
'duration': 0,
|
||||
|
||||
'manual_quotation': production.workorder_ids.filtered(
|
||||
lambda t: t.routing_type == 'CNC加工').manual_quotation,
|
||||
'rfid_code': production.workorder_ids.filtered(lambda t: t.routing_type == 'CNC加工').rfid_code,
|
||||
'cnc_ids': production.workorder_ids.filtered(lambda t: t.routing_type == 'CNC加工').cnc_ids,
|
||||
'cmm_ids': production.workorder_ids.filtered(lambda t: t.routing_type == 'CNC加工').cmm_ids,
|
||||
}]
|
||||
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'
|
||||
|
||||
# 重写工单开始按钮方法
|
||||
def button_start(self):
|
||||
if self.routing_type == '装夹预调':
|
||||
@@ -749,12 +842,12 @@ 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:
|
||||
# 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))
|
||||
if self.routing_type == '解除装夹':
|
||||
'''
|
||||
记录开始时间
|
||||
@@ -769,10 +862,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':
|
||||
@@ -887,6 +979,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
raise UserError(
|
||||
'请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name)
|
||||
tem_date_planned_finished = record.date_planned_finished
|
||||
tem_date_finished = record.date_finished
|
||||
logging.info('routing_type:%s' % record.routing_type)
|
||||
super().button_finish()
|
||||
logging.info('date_planned_finished:%s' % record.date_planned_finished)
|
||||
@@ -895,26 +988,42 @@ 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 is_production_id is True and record.routing_type in ['解除装夹', '表面工艺']:
|
||||
if record.routing_type == '解除装夹':
|
||||
for workorder in record.production_id.workorder_ids:
|
||||
workorder.rfid_code_old = workorder.rfid_code
|
||||
workorder.rfid_code = None
|
||||
if workorder.processing_panel == record.processing_panel:
|
||||
rfid_code = workorder.rfid_code
|
||||
workorder.write({'rfid_code_old': rfid_code,
|
||||
'rfid_code': False})
|
||||
workorder.rfid_code_old = rfid_code
|
||||
workorder.rfid_code = False
|
||||
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 ['表面工艺']:
|
||||
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):
|
||||
@@ -956,6 +1065,32 @@ class ResMrpWorkOrder(models.Model):
|
||||
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:
|
||||
# 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程序失败,请联系管理员")
|
||||
|
||||
|
||||
class CNCprocessing(models.Model):
|
||||
_name = 'sf.cnc.processing'
|
||||
@@ -981,6 +1116,7 @@ class CNCprocessing(models.Model):
|
||||
production_id = fields.Many2one('mrp.production', string="制造订单")
|
||||
button_state = fields.Boolean(string='是否已经下发')
|
||||
program_path = fields.Char('程序文件路径')
|
||||
program_create_date = fields.Datetime('程序创建日期')
|
||||
|
||||
# mrs下发编程单创建CNC加工
|
||||
def cnc_processing_create(self, cnc_workorder, ret, program_path, program_path_tmp):
|
||||
@@ -1013,30 +1149,35 @@ class CNCprocessing(models.Model):
|
||||
cnc_workorder.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||||
return cnc_processing
|
||||
|
||||
def _json_cnc_processing(self, obj):
|
||||
cnc_processing_str = (0, 0, {
|
||||
'sequence_number': obj['sequence_number'],
|
||||
'program_name': obj['program_name'],
|
||||
'cutting_tool_name': obj['cutting_tool_name'],
|
||||
'cutting_tool_no': obj['cutting_tool_no'],
|
||||
'processing_type': obj['processing_type'],
|
||||
'margin_x_y': obj['margin_x_y'],
|
||||
'margin_z': obj['margin_z'],
|
||||
'depth_of_processing_z': obj['depth_of_processing_z'],
|
||||
'cutting_tool_extension_length': obj['cutting_tool_extension_length'],
|
||||
'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
|
||||
'estimated_processing_time': obj['estimated_processing_time'],
|
||||
'program_path': obj['program_path'],
|
||||
'cnc_id': obj['cnc_id'].id,
|
||||
'remark': obj['remark']
|
||||
})
|
||||
return cnc_processing_str
|
||||
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']
|
||||
}))
|
||||
return cnc_processing
|
||||
|
||||
# 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配
|
||||
def get_cnc_processing_file(self, serverdir, cnc_processing, program_path):
|
||||
logging.info('serverdir:%s' % serverdir)
|
||||
logging.info('cnc_processing:%s' % cnc_processing)
|
||||
for root, dirs, files in os.walk(serverdir):
|
||||
for f in files:
|
||||
logging.info('splitext(f):%s' % os.path.splitext(f)[1])
|
||||
if os.path.splitext(f)[1] == ".pdf":
|
||||
full_path = os.path.join(serverdir, root, f)
|
||||
cnc_processing.workorder_id.cnc_worksheet = base64.b64encode(
|
||||
@@ -1058,14 +1199,16 @@ class CNCprocessing(models.Model):
|
||||
})
|
||||
return attachment
|
||||
|
||||
# 将FTP的nc文件下载到临时目录
|
||||
# 将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'])
|
||||
download_state = ftp.download_file_tree(remotepath, serverdir)
|
||||
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
|
||||
|
||||
@@ -1110,6 +1253,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)])
|
||||
@@ -1142,17 +1286,18 @@ class SfWorkOrderBarcodes(models.Model):
|
||||
workorder.write(val)
|
||||
self.write(val)
|
||||
workorder_rfid = self.env['mrp.workorder'].search(
|
||||
[('production_id', '=', workorder.production_id.id)])
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('processing_panel', '=', workorder.processing_panel)])
|
||||
if workorder_rfid:
|
||||
for item in workorder_rfid:
|
||||
item.write({'rfid_code': barcode})
|
||||
logging.info("Rfid绑定成功!!!")
|
||||
logging.info("Rfid[%s]绑定成功!!!" % barcode)
|
||||
else:
|
||||
raise UserError('该Rfid【%s】绑定的是【%s】, 不是托盘!!!' % (barcode, lot.product_id.name))
|
||||
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({
|
||||
@@ -1206,17 +1351,18 @@ class SfWorkOrderBarcodes(models.Model):
|
||||
|
||||
class WorkPieceDelivery(models.Model):
|
||||
_name = "sf.workpiece.delivery"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_description = '工件配送'
|
||||
|
||||
name = fields.Char('单据编号')
|
||||
name = fields.Char('单据编码')
|
||||
workorder_id = fields.Many2one('mrp.workorder', string='工单', readonly=True)
|
||||
workorder_state = fields.Selection(related='workorder_id.state', string='工单状态')
|
||||
rfid_code = fields.Char(related='workorder_id.rfid_code', string='rfid码', store=True)
|
||||
production_id = fields.Many2one('mrp.production', string='制造订单号', readonly=True)
|
||||
production_line_id = fields.Many2one('sf.production.line', string='目的生产线')
|
||||
production_line_id = fields.Many2one('sf.production.line', string='目的生产线', tracking=True)
|
||||
plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True)
|
||||
|
||||
route_id = fields.Many2one('sf.agv.task.route', '任务路线')
|
||||
route_id = fields.Many2one('sf.agv.task.route', '任务路线', tracking=True)
|
||||
feeder_station_start_id = fields.Many2one('sf.agv.site', '起点接驳站')
|
||||
feeder_station_destination_id = fields.Many2one('sf.agv.site', '目的接驳站')
|
||||
task_delivery_time = fields.Datetime('任务下发时间')
|
||||
@@ -1225,26 +1371,41 @@ class WorkPieceDelivery(models.Model):
|
||||
[('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型')
|
||||
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
|
||||
status = fields.Selection(
|
||||
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', default='待下发')
|
||||
is_cnc_program_down = fields.Boolean('程序是否下发', default=False)
|
||||
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', default='待下发',
|
||||
tracking=True)
|
||||
is_cnc_program_down = fields.Boolean('程序是否下发', default=False, tracking=True)
|
||||
is_manual_work = fields.Boolean('人工操作', default=False)
|
||||
active = fields.Boolean(string="有效", default=True)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals['route_id'] and vals.get('type') is None:
|
||||
vals['type'] = '运送空料架'
|
||||
else:
|
||||
if vals.get('name', '/') == '/' or vals.get('name', '/') is False:
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('sf.workpiece.delivery') or '/'
|
||||
else:
|
||||
vals['type'] = '运送空料架'
|
||||
obj = super(WorkPieceDelivery, self).create(vals)
|
||||
if obj.type == '运送空料架':
|
||||
if obj.name is False:
|
||||
obj.name = "运送空料架路线:%s-%s" % (
|
||||
obj.feeder_station_start_id.name, obj.feeder_station_destination_id.name)
|
||||
return obj
|
||||
|
||||
@api.constrains('name')
|
||||
def _check_name(self):
|
||||
@api.constrains('route_id')
|
||||
def _check_route_id(self):
|
||||
if self.type == '运送空料架':
|
||||
wd = self.sudo().search([('name', '=', self.name), ('id', '!=', self.id)])
|
||||
if wd:
|
||||
raise UserError("该名称已存在")
|
||||
if self.route_id and self.name is False:
|
||||
route = self.sudo().search(
|
||||
[('route_id', '=', self.route_id.id), ('id', '!=', self.id), ('name', 'ilike', '运送空料架路线')])
|
||||
if route:
|
||||
raise UserError("该任务路线已存在,请重新选择")
|
||||
|
||||
# @api.constrains('name')
|
||||
# def _check_name(self):
|
||||
# if self.type == '运送空料架':
|
||||
# wd = self.sudo().search([('name', '=', self.name), ('id', '!=', self.id)])
|
||||
# if wd:
|
||||
# raise UserError("该名称已存在")
|
||||
|
||||
def action_delivery_history(self):
|
||||
return {
|
||||
@@ -1453,80 +1614,22 @@ class CMMprogram(models.Model):
|
||||
_name = 'sf.cmm.program'
|
||||
_description = "CMM程序"
|
||||
|
||||
cmm_id = fields.Many2one('ir.attachment')
|
||||
sequence_number = fields.Integer('序号')
|
||||
program_name = fields.Char('程序名')
|
||||
cutting_tool_name = fields.Char('刀具名称')
|
||||
cutting_tool_no = fields.Char('刀号')
|
||||
processing_type = fields.Char('加工类型')
|
||||
margin_x_y = fields.Char('余量_X/Y')
|
||||
margin_z = fields.Char('余量_Z')
|
||||
depth_of_processing_z = fields.Char('加工深度(Z)')
|
||||
cutting_tool_extension_length = fields.Char('刀具伸出长度')
|
||||
cutting_tool_handle_type = fields.Char('刀柄型号')
|
||||
estimated_processing_time = fields.Char('预计加工时间')
|
||||
remark = fields.Text('备注')
|
||||
workorder_id = fields.Many2one('mrp.workorder', string="工单")
|
||||
production_id = fields.Many2one('mrp.production', string="制造订单")
|
||||
program_path = fields.Char('程序文件路径')
|
||||
program_create_date = fields.Datetime('程序创建日期')
|
||||
|
||||
def cmm_program_create(self, ret, program_path, program_path_tmp):
|
||||
cmm_program = None
|
||||
for obj in ret['programming_list']:
|
||||
workorder = self.env['mrp.workorder'].search(
|
||||
[('production_id.name', '=', ret['production_order_no'].split(',')[0]),
|
||||
('processing_panel', '=', obj['processing_panel']),
|
||||
('routing_type', '=', 'CNC加工')])
|
||||
if obj['program_name'] in program_path:
|
||||
logging.info('obj:%s' % obj['program_name'])
|
||||
cmm_program = self.sudo().create({
|
||||
'workorder_id': workorder.id,
|
||||
'sequence_number': obj['sequence_number'],
|
||||
'program_name': obj['program_name'],
|
||||
'cutting_tool_name': obj['cutting_tool_name'],
|
||||
'cutting_tool_no': obj['cutting_tool_no'],
|
||||
'processing_type': obj['processing_type'],
|
||||
'margin_x_y': obj['margin_x_y'],
|
||||
'margin_z': obj['margin_z'],
|
||||
'depth_of_processing_z': obj['depth_of_processing_z'],
|
||||
'cutting_tool_extension_length': obj['cutting_tool_extension_length'],
|
||||
'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
|
||||
'estimated_processing_time': obj['estimated_processing_time'],
|
||||
'remark': obj['remark'],
|
||||
'program_path': program_path.replace('/tmp', '')
|
||||
})
|
||||
cmm_program.get_cmm_program_file(program_path_tmp, cmm_program, program_path)
|
||||
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'),
|
||||
}))
|
||||
return cmm_program
|
||||
|
||||
# 根据程序名和加工面匹配到ftp里对应的cmm程序名
|
||||
def get_cmm_program_file(self, serverdir, cmm_program, program_path):
|
||||
logging.info('cmm-serverdir:%s' % serverdir)
|
||||
for root, dirs, files in os.walk(serverdir):
|
||||
for f in files:
|
||||
if f in program_path:
|
||||
cmm_program_file_path = os.path.join(serverdir, root, f)
|
||||
self.write_file_cmm(cmm_program_file_path, cmm_program)
|
||||
|
||||
# 创建附件(nc文件)
|
||||
def attachment_create(self, name, data):
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
'datas': base64.b64encode(data),
|
||||
'type': 'binary',
|
||||
'public': True,
|
||||
'description': '程序文件',
|
||||
'name': name
|
||||
})
|
||||
return attachment
|
||||
|
||||
# 将cmm文件存到attach的datas里
|
||||
def write_file_cmm(self, cmm_file_path, cnc):
|
||||
cmm_file_name = cmm_file_path.split('/')
|
||||
logging.info('cmm_file_name:%s' % cmm_file_name[-1])
|
||||
if os.path.exists(cmm_file_path):
|
||||
with open(cmm_file_path, 'rb') as file:
|
||||
data_bytes = file.read()
|
||||
attachment = self.attachment_create(cnc.program_name + cmm_file_name[-1], data_bytes)
|
||||
cnc.write({'cmm_id': attachment.id})
|
||||
file.close()
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -539,6 +539,7 @@ class ResProductMo(models.Model):
|
||||
|
||||
# bfm下单
|
||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
||||
part_number = fields.Char(string='零件图号', readonly=True)
|
||||
|
||||
@api.constrains('tool_length')
|
||||
def _check_tool_length_size(self):
|
||||
@@ -615,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'],
|
||||
@@ -633,8 +634,10 @@ 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 '',
|
||||
'active': True,
|
||||
}
|
||||
copy_product_id.sudo().write(vals)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
import qrcode
|
||||
from itertools import groupby
|
||||
from collections import defaultdict, namedtuple
|
||||
import logging
|
||||
import io
|
||||
@@ -203,64 +204,18 @@ class StockRule(models.Model):
|
||||
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
|
||||
productions_values)
|
||||
|
||||
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
||||
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||
self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
||||
|
||||
'''
|
||||
创建工单
|
||||
'''
|
||||
productions._create_workorder()
|
||||
|
||||
# productions._create_workorder()
|
||||
#
|
||||
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_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:
|
||||
'''
|
||||
创建制造订单时生成序列号
|
||||
@@ -306,6 +261,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
|
||||
|
||||
|
||||
@@ -509,10 +487,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(
|
||||
@@ -528,18 +506,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':
|
||||
# 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)])
|
||||
production = self.env['mrp.production'].search([('name', '=', 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))
|
||||
self.env['stock.move.line'].create(move_in.get_move_line(production, None))
|
||||
|
||||
return res
|
||||
|
||||
@@ -621,7 +598,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,
|
||||
@@ -630,10 +607,10 @@ 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,
|
||||
# 'workorder_id': '' if not sorted_workorders else sorted_workorders.id,
|
||||
# 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id,
|
||||
'state': 'assigned',
|
||||
}
|
||||
|
||||
@@ -701,13 +678,36 @@ class ReStockMove(models.Model):
|
||||
),
|
||||
}
|
||||
|
||||
def put_move_line(self):
|
||||
"""
|
||||
确认订单时,自动分配序列号
|
||||
"""
|
||||
if self.product_id.tracking == "serial":
|
||||
if self.product_id.categ_id.name == '刀具':
|
||||
self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin)
|
||||
else:
|
||||
self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id)
|
||||
self._generate_serial_numbers()
|
||||
for item in self.move_line_nosuggest_ids:
|
||||
if item.lot_name:
|
||||
lot_name = item.lot_name
|
||||
if item.product_id.categ_id.name == '坯料':
|
||||
lot_name = lot_name.split('[', 1)[0]
|
||||
item.lot_qr_code = self.compute_lot_qr_code(lot_name)
|
||||
|
||||
def _put_tool_lot(self, company, product, origin):
|
||||
if product.tracking == "lot" and self.product_id.categ_id.name == '刀具':
|
||||
if not self.move_line_nosuggest_ids:
|
||||
lot_names = self.env['stock.lot'].generate_lot_names(
|
||||
'%s-%s-%s' % ('%s-T-DJWL-%s' % (
|
||||
lot_code = '%s-%s-%s' % ('%s-T-DJWL-%s' % (
|
||||
product.cutting_tool_model_id.code.split('-')[0], product.cutting_tool_material_id.code),
|
||||
datetime.now().strftime("%Y%m%d"), origin), 1)
|
||||
datetime.now().strftime("%Y%m%d"), origin)
|
||||
move_line_ids = self.env['stock.move.line'].sudo().search([('lot_name', 'like', lot_code)], limit=1,
|
||||
order='id desc')
|
||||
if not move_line_ids:
|
||||
lot_code = '%s-001' % lot_code
|
||||
else:
|
||||
lot_code = '%s-%03d' % (lot_code, int(move_line_ids.lot_name[-3:]) + 1)
|
||||
lot_names = self.env['stock.lot'].generate_lot_names(lot_code, 1)
|
||||
move_lines_commands = self._generate_serial_move_line_commands_tool_lot(lot_names)
|
||||
self.write({'move_line_nosuggest_ids': move_lines_commands})
|
||||
for item in self.move_line_nosuggest_ids:
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_sf_cnc_processing_group_sf_mrp_user,sf_cnc_processing,model_sf_cnc_processing,sf_base.group_sf_mrp_user,1,0,0,0
|
||||
access_sf_cnc_processing_manager,sf_cnc_processing,model_sf_cnc_processing,sf_base.group_sf_mrp_manager,1,1,1,0
|
||||
access_sf_cmm_program_group_sf_mrp_user_group_sf_mrp_user,sf_cmm_program_group_sf_mrp_user,model_sf_cmm_program,sf_base.group_sf_mrp_user,1,0,0,0
|
||||
access_sf_cmm_program_group_sf_mrp_user,sf_cmm_program_group_sf_mrp_user,model_sf_cmm_program,sf_base.group_sf_mrp_user,1,0,0,0
|
||||
access_sf_cmm_program_group_sf_mrp_manager,sf_cmm_program_group_sf_mrp_manager,model_sf_cmm_program,sf_base.group_sf_mrp_manager,1,0,0,0
|
||||
access_sf_cmm_program_admin,sf_cmm_program_admin,model_sf_cmm_program,base.group_system,1,1,1,1
|
||||
access_sf_model_type_group_sf_mrp_user,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_user,1,0,0,0
|
||||
access_sf_model_type_admin,sf_model_type_admin,model_sf_model_type,base.group_system,1,1,1,0
|
||||
access_sf_model_type_manager,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_manager,1,1,1,0
|
||||
|
||||
|
@@ -7,9 +7,9 @@
|
||||
<field name="model">sf.agv.site</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom">
|
||||
<field name="name" required="1"/>
|
||||
<field name="owning_region" required="1"/>
|
||||
<field name="state" required="1"/>
|
||||
<field name="name" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="owning_region" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="state" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="divide_the_work" required="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -34,12 +34,14 @@
|
||||
<field name="model">sf.agv.task.route</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom">
|
||||
<field name="name" required="1"/>
|
||||
<field name="name" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="type" readonly="1" string="任务类型"/>
|
||||
<field name="route_type" string="类型"/>
|
||||
<field name="start_site_id" required="1" options="{'no_create': True}" string="起点接驳站"/>
|
||||
<field name="route_type" string="类型" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="start_site_id" required="1" options="{'no_create': True}" string="起点接驳站"
|
||||
attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="end_site_id" required="1" options="{'no_create': True}" string="终点接驳站"/>
|
||||
<field name="destination_production_line_id" required="1" options="{'no_create': True}"/>
|
||||
<field name="destination_production_line_id" required="1" options="{'no_create': True}"
|
||||
attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -73,7 +75,8 @@
|
||||
<field name="model">center_control.interface.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Logs">
|
||||
<field name="name"/>
|
||||
<field name="name" filter_domain="[('name','ilike', self)]"/>
|
||||
<field name="content" filter_domain="[('content','ilike', self)]"/>
|
||||
<group expand="0" string="分组">
|
||||
<field name="interface_call_date"/>
|
||||
</group>
|
||||
|
||||
@@ -62,24 +62,25 @@
|
||||
<field name="inherit_id" ref="mrp.mrp_production_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='state']" position="attributes">
|
||||
<!-- <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
|
||||
<!-- <attribute name="statusbar_visible">draft,confirmed,progress,pending_processing,completed,done -->
|
||||
<!-- </attribute> -->
|
||||
<attribute name="statusbar_visible">
|
||||
confirmed,pending_cam,progress,done
|
||||
</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet//group//group[2]//label" position="before">
|
||||
<!-- <field name="process_state"/> -->
|
||||
<!-- <field name="process_state"/> -->
|
||||
<field name="state"/>
|
||||
<!-- <field name="process_state"/> -->
|
||||
<!-- <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 =='编程中'"/>
|
||||
<field name="work_state" invisible="1"/>
|
||||
<field name="schedule_state" invisible='1'/>
|
||||
<field name="manual_quotation" readonly="1"/>
|
||||
<field name="programming_state" readonly="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='user_id']" position="before">
|
||||
<field name="plan_start_processing_time" readonly="1"/>
|
||||
@@ -87,7 +88,7 @@
|
||||
<xpath expr="//field[@name='user_id']" position="after">
|
||||
<field name="production_line_id" readonly="1"/>
|
||||
<field name="production_line_state" readonly="1"/>
|
||||
<field name="part_number"/>
|
||||
<field name="part_number" string="成品的零件图号"/>
|
||||
<field name="part_drawing"/>
|
||||
</xpath>
|
||||
<xpath expr="//header//button[@name='action_cancel']" position="replace">
|
||||
@@ -254,7 +255,9 @@
|
||||
</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>
|
||||
</field>
|
||||
</record>
|
||||
@@ -279,8 +282,10 @@
|
||||
<field name="arch" type="xml">
|
||||
<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加工')]}"
|
||||
<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">
|
||||
@@ -291,7 +296,8 @@
|
||||
<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加工')]}"
|
||||
groups="sf_base.group_sf_mrp_user"/>
|
||||
groups="sf_base.group_sf_mrp_user"
|
||||
confirm="是否确认完成?"/>
|
||||
</xpath>
|
||||
<xpath expr="//tree//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="replace">
|
||||
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="Block"
|
||||
@@ -309,10 +315,10 @@
|
||||
<button name="action_open_wizard" type="object" icon="fa-external-link" class="oe_edit_only"
|
||||
title="Open Work Order"
|
||||
context="{'default_workcenter_id': workcenter_id}" groups="sf_base.group_sf_mrp_user"/>
|
||||
<!-- ======= -->
|
||||
<!-- <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)]}" -->
|
||||
<!-- groups="sf_base.group_sf_mrp_user"/> -->
|
||||
<!-- ======= -->
|
||||
<!-- <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)]}" -->
|
||||
<!-- groups="sf_base.group_sf_mrp_user"/> -->
|
||||
</xpath>
|
||||
<xpath expr="//tree//button[@name='button_pending']" position="replace">
|
||||
<button name="button_pending" type="object" string="暂停" class="btn-warning"
|
||||
@@ -322,7 +328,7 @@
|
||||
<xpath expr="//tree//button[@name='button_finish']" position="replace">
|
||||
<button name="button_finish" type="object" string="完成" class="btn-success"
|
||||
attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"
|
||||
groups="sf_base.group_sf_mrp_user"/>
|
||||
groups="sf_base.group_sf_mrp_user" confirm="是否确认完成?"/>
|
||||
</xpath>
|
||||
<xpath expr="//tree//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="replace">
|
||||
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="阻塞"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<field name="name" decoration-success="is_subcontract" decoration-bf="is_subcontract"/>
|
||||
</field>
|
||||
<field name="name" position="before">
|
||||
<field name="sequence"/>
|
||||
<field name="sequence" optional="hide"/>
|
||||
<field name='user_permissions' invisible="1"/>
|
||||
</field>
|
||||
<field name="name" position="after">
|
||||
@@ -19,6 +19,13 @@
|
||||
</field>
|
||||
<field name="state" position="after">
|
||||
<field name="work_state" optional="hide"/>
|
||||
<field name="product_tmpl_name" invisible="1"/>
|
||||
</field>
|
||||
<field name="duration" position="replace">
|
||||
<field name="duration" optional="hide"/>
|
||||
</field>
|
||||
<field name="workcenter_id" position="replace">
|
||||
<field name="workcenter_id" optional="hide"/>
|
||||
</field>
|
||||
<field name="product_id" position="after">
|
||||
<field name="equipment_id" optional="hide"/>
|
||||
@@ -30,7 +37,7 @@
|
||||
<field name="date_planned_start" string="计划开始日期" optional="show"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='date_planned_finished']" position="replace">
|
||||
<field name="date_planned_finished" string="计划结束日期" optional="show"/>
|
||||
<field name="date_planned_finished" string="计划结束日期" optional="hide"/>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='button_start']" position="attributes">
|
||||
<attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',
|
||||
@@ -80,11 +87,11 @@
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('mrp.mrp_production_workorder_tree_editable_view')}) ]"/>
|
||||
<!-- (0, 0, {'view_mode': 'kanban', 'view_id': ref('mrp.workcenter_line_kanban')})-->
|
||||
<!-- (0, 0, {'view_mode': 'kanban', 'view_id': ref('mrp.workcenter_line_kanban')})-->
|
||||
<!-- <field name="target">fullscreen</field>-->
|
||||
<field name="target">current</field>
|
||||
<field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>
|
||||
<field name="context">{'search_default_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">
|
||||
没有工单要做!
|
||||
@@ -117,6 +124,7 @@
|
||||
<field name='user_permissions' invisible="1"/>
|
||||
<field name='name' invisible="1"/>
|
||||
<field name='is_delivery' 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加工', '解除装夹'))]}" -->
|
||||
@@ -128,7 +136,7 @@
|
||||
<!-- 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"
|
||||
<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)]}"/>
|
||||
<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)]}"/>
|
||||
@@ -151,7 +159,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)]}"/>
|
||||
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)]}"/>-->
|
||||
</xpath>
|
||||
<xpath expr="//page[1]" position="before">
|
||||
<page string="开料要求" attrs='{"invisible": [("routing_type","!=","切割")]}'>
|
||||
@@ -170,8 +183,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>
|
||||
@@ -203,20 +219,17 @@
|
||||
<field name="processing_panel" readonly="1"
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
|
||||
<field name="equipment_id"
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/>
|
||||
<field name="production_line_id"
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
|
||||
<field name="production_line_state"
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
|
||||
<field name="functional_fixture_id"
|
||||
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
||||
<field name="functional_fixture_code" force_save="1"
|
||||
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
||||
<field name="functional_fixture_type_id"
|
||||
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
||||
<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)]}"/>
|
||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/>
|
||||
<!-- <field name="functional_fixture_id" -->
|
||||
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> -->
|
||||
<!-- <field name="functional_fixture_code" force_save="1" -->
|
||||
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> -->
|
||||
<!-- <field name="functional_fixture_type_id" -->
|
||||
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> -->
|
||||
</group>
|
||||
<!-- <group>-->
|
||||
<!-- <div>-->
|
||||
@@ -229,23 +242,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","!=","装夹")]}'>-->
|
||||
@@ -281,20 +277,26 @@
|
||||
<!-- </group>-->
|
||||
<group string="托盘">
|
||||
<field name="tray_serial_number" readonly="1" string="序列号"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="tray_product_id" readonly="1" string="名称"/>
|
||||
<field name="tray_brand_id" readonly="1" string="品牌"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="tray_type_id" readonly="1" string="类型"/>
|
||||
<field name="tray_model_id" readonly="1" string="型号"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="加工图纸">
|
||||
<!-- 隐藏加工图纸字段名 -->
|
||||
<field name="processing_drawing" widget="pdf_viewer" string="" readonly="1"/>
|
||||
</group>
|
||||
<group string="预调程序信息">
|
||||
<field name="preset_program_information" colspan="2" nolabel="1"
|
||||
placeholder="如有预调程序信息请在此处输入....."/>
|
||||
</group>
|
||||
<group string="加工图纸">
|
||||
<!-- 隐藏加工图纸字段名 -->
|
||||
<field name="processing_drawing" widget="pdf_viewer" string=""/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="前置三元检测定位参数" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'>
|
||||
|
||||
@@ -464,7 +466,10 @@
|
||||
<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 == '待配送'"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
@@ -477,8 +482,13 @@
|
||||
<page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||
<group>
|
||||
<field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/>
|
||||
<field name="is_remanufacture" attrs='{"invisible":[("test_results","=","合格")]}'/>
|
||||
<field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>
|
||||
<!-- <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="detection_report" attrs='{"invisible":[("results","!=",False)]}'
|
||||
widget="pdf_viewer"/>
|
||||
</group>
|
||||
@@ -491,11 +501,11 @@
|
||||
</xpath>
|
||||
<xpath expr="//page[1]" position="before">
|
||||
<page string="CNC程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||
<field name="cnc_ids" widget="one2many" string="工作程序" default_order="sequence_number,id">
|
||||
<tree decoration-success="button_state" decoration-bf="button_state">
|
||||
<field name="cnc_ids" widget="one2many" string="工作程序" default_order="sequence_number,id"
|
||||
readonly="1">
|
||||
<tree>
|
||||
<field name="sequence_number"/>
|
||||
<field name="program_name"/>
|
||||
<field name="cnc_id" string="文件"/>
|
||||
<field name="cutting_tool_name"/>
|
||||
<field name="cutting_tool_no"/>
|
||||
<field name="processing_type"/>
|
||||
@@ -505,8 +515,10 @@
|
||||
<field name="cutting_tool_extension_length"/>
|
||||
<field name="cutting_tool_handle_type"/>
|
||||
<field name="estimated_processing_time"/>
|
||||
<field name="program_path"/>
|
||||
<field name="program_create_date"/>
|
||||
<field name="remark"/>
|
||||
<field name="button_state" invisible="1"/>
|
||||
<!-- <field name="button_state" invisible="1"/>-->
|
||||
</tree>
|
||||
</field>
|
||||
<group>
|
||||
@@ -514,20 +526,12 @@
|
||||
</group>
|
||||
</page>
|
||||
<page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||
<field name="cmm_ids" widget="one2many" string="CMM程序">
|
||||
<field name="cmm_ids" widget="one2many" string="CMM程序" readonly="1">
|
||||
<tree>
|
||||
<field name="sequence_number"/>
|
||||
<field name="program_name"/>
|
||||
<field name="cmm_id" string="文件"/>
|
||||
<field name="cutting_tool_name"/>
|
||||
<field name="cutting_tool_no"/>
|
||||
<field name="processing_type"/>
|
||||
<field name="margin_x_y"/>
|
||||
<field name="margin_z"/>
|
||||
<field name="depth_of_processing_z"/>
|
||||
<field name="cutting_tool_extension_length"/>
|
||||
<field name="cutting_tool_handle_type"/>
|
||||
<field name="estimated_processing_time"/>
|
||||
<field name="program_path"/>
|
||||
<field name="program_create_date"/>
|
||||
<field name="remark"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -557,9 +561,6 @@
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//form//sheet//group//group//div[3]" position="after">
|
||||
<field name="is_ok"/>
|
||||
<field name="processing_user_id"/>
|
||||
<field name="inspection_user_id"/>
|
||||
<field name="save_name" widget="CopyClipboardChar"
|
||||
attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/>
|
||||
<label for="material_length" string="物料尺寸"/>
|
||||
@@ -573,11 +574,22 @@
|
||||
<label for="material_height" string="高"/>
|
||||
<field name="material_height" class="o_address_zip"/>
|
||||
</div>
|
||||
<field name="part_number"/>
|
||||
<field name="part_number" string="成品的零件图号"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="workcenter_form_workorder_search" model="ir.ui.view">
|
||||
<field name="name">custom.workorder.search</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
<field name="inherit_id" ref="mrp.view_mrp_production_work_order_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_id" position="after">
|
||||
<field name="part_number" string="成品零件图号"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="mrp_workorder_action_schedule" model="ir.actions.act_window">
|
||||
<field name="name">工单</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
@@ -604,7 +616,7 @@
|
||||
<field name="name">工件配送</field>
|
||||
<field name="model">sf.workpiece.delivery</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="工件配送" editable="bottom" class="center" create="0" delete="0">
|
||||
<tree string="工件配送" class="center" create="0" delete="0">
|
||||
<header>
|
||||
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
|
||||
</header>
|
||||
@@ -612,13 +624,13 @@
|
||||
decoration-success="status == '已配送'"
|
||||
decoration-warning="status == '待下发'"
|
||||
decoration-danger="status == '待配送'"/>
|
||||
<field name="name"/>
|
||||
<field name="production_id"/>
|
||||
<field name="type" readonly="1"/>
|
||||
<field name="production_line_id" options="{'no_create': True}" readonly="1"/>
|
||||
<field name="route_id" options="{'no_create': True}"
|
||||
domain="[('route_type','in',['上产线','下产线'])]"/>
|
||||
<field name="feeder_station_start_id" readonly="1" force_save="1"/>
|
||||
<field name="feeder_station_start_id" readonly="1" force_save="1"/>
|
||||
<field name="feeder_station_destination_id" readonly="1" force_save="1"/>
|
||||
<field name="is_cnc_program_down" readonly="1"/>
|
||||
<!-- <field name="rfid_code"/>-->
|
||||
@@ -629,13 +641,58 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_workpiece_delivery_form" model="ir.ui.view">
|
||||
<field name="name">工件配送</field>
|
||||
<field name="model">sf.workpiece.delivery</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="工件配送" create="0" delete="0">
|
||||
<header>
|
||||
<field name="status" widget="statusbar"/>
|
||||
<button name="button_delivery" type="object" string="配送" class="oe_highlight"
|
||||
attrs="{'invisible': [('status', '!=', '待下发')]}"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group string="基本信息">
|
||||
<field name="production_id"/>
|
||||
<field name="type" readonly="1"/>
|
||||
<field name="production_line_id" options="{'no_create': True}" readonly="1"/>
|
||||
<field name="is_cnc_program_down" readonly="1"/>
|
||||
<!-- <field name="rfid_code"/>-->
|
||||
</group>
|
||||
<group string="配送信息">
|
||||
<field name="route_id" options="{'no_create': True}"
|
||||
domain="[('route_type','in',['上产线','下产线'])]"/>
|
||||
<field name="feeder_station_start_id" readonly="1" force_save="1"/>
|
||||
<field name="feeder_station_destination_id" readonly="1" force_save="1"/>
|
||||
<field name="task_delivery_time" readonly="1"/>
|
||||
<field name="task_completion_time" readonly="1"/>
|
||||
<field name="delivery_duration" widget="float_time"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids" options="{'post_refresh': 'recipients'}"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_workpiece_delivery_search" model="ir.ui.view">
|
||||
<field name="name">工件配送</field>
|
||||
<field name="model">sf.workpiece.delivery</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="工件配送">
|
||||
<filter string="上产线" name="on_up" domain="[('type', '=', '上产线')]"/>
|
||||
<filter string="下产线" name="on_down" domain="[('type', '=', '下产线' )]"/>
|
||||
<filter name="filter_to_be_issued" string="待下发" domain="[('status', 'in', ['待下发'])]"/>
|
||||
<filter name="filter_waiting_delivery" string="待配送" domain="[('status', 'in', ['待配送'])]"/>
|
||||
<filter name="filter_delivered" string="已配送" domain="[('status', 'in', ['已配送'])]"/>
|
||||
<field name="rfid_code"/>
|
||||
<field name="production_id"/>
|
||||
<field name="feeder_station_start_id"/>
|
||||
@@ -652,13 +709,15 @@
|
||||
</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>
|
||||
<field name="search_view_id" ref="sf_workpiece_delivery_search"/>
|
||||
<field name="context">{'search_default_on_up':1}</field>
|
||||
<field name="view_mode">tree,search</field>
|
||||
<field name="context">{'search_default_filter_to_be_issued': 1,
|
||||
'search_default_filter_waiting_delivery': 1}
|
||||
</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">
|
||||
[('type','in',['上产线','下产线']),('workorder_state','=','done'),('is_manual_work','=',false)]
|
||||
</field>
|
||||
@@ -671,23 +730,39 @@
|
||||
<field name="model">sf.workpiece.delivery</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="工件配送" editable="bottom" class="center" delete="0" create="1">
|
||||
<header>
|
||||
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
|
||||
</header>
|
||||
<field name="name" string="路线名称" attrs="{'readonly': [('id', '!=', False)]}"
|
||||
placeholder="例如:运送空料架路线:G01-A01" required="1" force_save="1"/>
|
||||
<!-- <header>-->
|
||||
<!-- <button name="button_delivery" type="object" string="配送" class="oe_highlight"/>-->
|
||||
<!-- </header>-->
|
||||
<!-- <field name="name" string="路线名称" attrs="{'readonly': [('id', '!=', False)]}"-->
|
||||
<!-- placeholder="例如:运送空料架路线:G01-A01" required="1" force_save="1"/>-->
|
||||
<field name="route_id" options="{'no_create': True}" required="1"
|
||||
attrs="{'readonly': [('id', '!=', False)]}" domain="[('route_type', '=', '运送空料架')]"
|
||||
force_save="1"/>
|
||||
<field name="feeder_station_start_id" readonly="1" force_save="1"/>
|
||||
<!-- <field name="type" readonly="1"/>-->
|
||||
<field name="feeder_station_destination_id" readonly="1" force_save="1"/>
|
||||
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
|
||||
<button name="action_delivery_history" type="object" class="btn btn-link text-info" icon="fa-history"
|
||||
string="历史"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- <record id="sf_workpiece_delivery_empty_racks_kanban" model="ir.ui.view">-->
|
||||
<!-- <field name="name">sf.workpiece.delivery.view.kanban</field>-->
|
||||
<!-- <field name="model">sf.workpiece.delivery</field>-->
|
||||
<!-- <field name="arch" type="xml">-->
|
||||
<!-- <kanban>-->
|
||||
<!-- <field name="route_id"/>-->
|
||||
<!-- <field name="feeder_station_start_id"/>-->
|
||||
<!-- <field name="feeder_station_destination_id"/>-->
|
||||
<!--<!– <button name="button_delivery" type="object" string="配送" class="oe_highlight"/>–>-->
|
||||
<!--<!– <button name="action_delivery_history" type="object" class="btn btn-link text-info" icon="fa-history"–>-->
|
||||
<!--<!– string="历史"/>–>-->
|
||||
<!-- </kanban>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<record id="sf_workpiece_delivery_empty_racks_tree" model="ir.ui.view">
|
||||
<field name="name">空料架配送</field>
|
||||
<field name="model">sf.workpiece.delivery</field>
|
||||
@@ -710,6 +785,7 @@
|
||||
<field name="model">sf.workpiece.delivery</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="运送空料架">
|
||||
<filter name="filter_active" string="已归档" domain="[('active', '=', False)]"/>
|
||||
<field name="route_id"/>
|
||||
<field name="feeder_station_start_id"/>
|
||||
<field name="feeder_station_destination_id"/>
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
<field name="model">stock.lot</field>
|
||||
<field name="inherit_id" ref="stock.view_production_lot_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='create_date']" position="after">
|
||||
<field name="rfid" invisible="1"/>
|
||||
<xpath expr="//field[@name='name']" position="after">
|
||||
<field name="rfid"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -24,78 +24,91 @@ class Sf_Mrs_Connect(http.Controller):
|
||||
ret = json.loads(datas)
|
||||
ret = json.loads(ret['result'])
|
||||
logging.info('下发编程单:%s' % ret)
|
||||
is_delete_file = False
|
||||
# 查询状态为进行中且类型为获取CNC加工程序的工单
|
||||
cnc_production = request.env['mrp.production'].with_user(
|
||||
request.env.ref("base.user_admin")).search([('name', '=', ret['production_order_no'].split(',')[0])])
|
||||
cnc_program = request.env['mrp.production'].with_user(
|
||||
productions = request.env['mrp.production'].with_user(
|
||||
request.env.ref("base.user_admin")).search(
|
||||
[('programming_no', '=', cnc_production.programming_no), ('id', '!=', cnc_production.id)])
|
||||
if cnc_production.workorder_ids.filtered(lambda a: a.routing_type == 'CNC加工').cnc_ids:
|
||||
is_delete_file = True
|
||||
cnc_production.workorder_ids.filtered(
|
||||
lambda a1: a1.routing_type == 'CNC加工').cnc_ids.sudo().unlink()
|
||||
request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(cnc_production)
|
||||
if cnc_program.workorder_ids.filtered(lambda c: c.routing_type == 'CNC加工').cnc_ids:
|
||||
cnc_program.workorder_ids.filtered(
|
||||
lambda c1: c1.routing_type == 'CNC加工').cnc_ids.sudo().unlink()
|
||||
request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(cnc_program)
|
||||
# cnc_program = request.env['mrp.production'].with_user(
|
||||
# request.env.ref("base.user_admin")).search([('programming_no', '=', cnc_production.programming_no)])
|
||||
logging.info('制造订单号:%s' % cnc_production.name)
|
||||
if cnc_production:
|
||||
# if ret['glb_file']:
|
||||
# cnc_production.glb_file = base64.b64encode(ret['glb_file'])
|
||||
# 拉取所有加工面的程序文件
|
||||
if is_delete_file is True:
|
||||
program_path_tmp_r = os.path.join('/tmp', ret['folder_name'], 'return', 'R')
|
||||
[('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)
|
||||
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)
|
||||
for r in ret['processing_panel']:
|
||||
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:
|
||||
if download_state is False:
|
||||
res['status'] = -2
|
||||
res['message'] = '制造订单号为%s的CNC程序文件从FTP拉取失败' % (cnc_production.name)
|
||||
res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no'])
|
||||
return json.JSONEncoder().encode(res)
|
||||
logging.info('创建cnc工单')
|
||||
program_path_tmp = os.path.join('/tmp', ret['folder_name'], 'return', r)
|
||||
# program_path_tmp = "C://Users//43484//Desktop//机企猫工作文档//其他//model_analysis"
|
||||
files = os.listdir(program_path_tmp)
|
||||
cnc_processing_arr = []
|
||||
for f in files:
|
||||
program_path = os.path.join(program_path_tmp, f)
|
||||
logging.info('cnc程序路径 :%s' % program_path)
|
||||
if f.endswith(".doc"):
|
||||
# 插入cmm程序数据
|
||||
cmm_program = request.env['sf.cmm.program'].with_user(
|
||||
request.env.ref("base.user_admin")).cmm_program_create(ret, program_path, program_path_tmp)
|
||||
cnc_processing = request.env['sf.cnc.processing'].with_user(
|
||||
request.env.ref("base.user_admin")).cnc_processing_create(cnc_production, ret, program_path,
|
||||
program_path_tmp)
|
||||
logging.info('cnc_processing111:%s' % cnc_processing)
|
||||
if cnc_processing:
|
||||
cnc_processing_arr.append(cnc_processing._json_cnc_processing(cnc_processing))
|
||||
if (cnc_program and cnc_processing_arr) or (not cnc_program and cnc_processing_arr):
|
||||
cnc_production.workorder_ids.filtered(lambda g: g.routing_type == '装夹预调').write(
|
||||
{'processing_drawing': cnc_production.workorder_ids.filtered(
|
||||
lambda g1: g1.routing_type == 'CNC加工').cnc_worksheet})
|
||||
if cnc_program and cnc_processing_arr:
|
||||
cnc_program.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||||
cnc_program.workorder_ids.filtered(lambda d: d.routing_type == '装夹预调').write(
|
||||
{'processing_drawing': cnc_production.workorder_ids.filtered(
|
||||
lambda d1: d1.routing_type == 'CNC加工').cnc_worksheet})
|
||||
cnc_program.workorder_ids.filtered(lambda b: b.routing_type == 'CNC加工').write(
|
||||
{'cnc_ids': cnc_processing_arr, 'cnc_worksheet': cnc_production.workorder_ids.filtered(
|
||||
lambda b1: b1.routing_type == 'CNC加工').cnc_worksheet})
|
||||
cnc_program |= cnc_production
|
||||
if not cnc_program and cnc_processing_arr:
|
||||
cnc_program = cnc_production
|
||||
cnc_program_ids = [item.id for item in cnc_program]
|
||||
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(
|
||||
# {'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:
|
||||
|
||||
@@ -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,6 +49,26 @@ 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):
|
||||
# result = chardet.detect(s)
|
||||
@@ -43,6 +80,8 @@ class FtpController():
|
||||
os.makedirs(serverdir)
|
||||
try:
|
||||
logging.info("进入FTP目录 ")
|
||||
self.ftp.pwd()
|
||||
logging.info('当前目录:%s' % self.ftp.pwd())
|
||||
logging.info('目录:%s' % target_dir)
|
||||
target_dir1 = target_dir.split('/')
|
||||
logging.info('目录1:%s' % target_dir1[1])
|
||||
|
||||
@@ -19,7 +19,7 @@ class sf_production_plan(models.Model):
|
||||
('done', '已排程'),
|
||||
('processing', '加工中'),
|
||||
('finished', '已完成')
|
||||
], string='工单状态', tracking=True)
|
||||
], string='状态', tracking=True)
|
||||
|
||||
state_order = fields.Integer(compute='_compute_state_order', store=True)
|
||||
|
||||
@@ -36,8 +36,8 @@ class sf_production_plan(models.Model):
|
||||
|
||||
_order = 'state_order asc, write_date desc'
|
||||
|
||||
name = fields.Char(string='工单编号')
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
name = fields.Char(string='制造订单')
|
||||
# active = fields.Boolean(string='已归档', default=True)
|
||||
# selected = fields.Boolean(default=False)
|
||||
# order_number = fields.Char(string='订单号')
|
||||
order_deadline = fields.Datetime(string='订单交期')
|
||||
@@ -52,7 +52,7 @@ class sf_production_plan(models.Model):
|
||||
schedule_setting = fields.Selection([
|
||||
('reverse', '倒排'), ('positive', '顺排')], string='排程设置', default='reverse')
|
||||
product_id = fields.Many2one('product.product', '关联产品')
|
||||
origin = fields.Char(string='订单号')
|
||||
origin = fields.Char(string='销售订单')
|
||||
# # 加工时长
|
||||
# process_time = fields.Float(string='加工时长', digits=(16, 2))
|
||||
# 实际加工时长、实际开始时间、实际结束时间
|
||||
@@ -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):
|
||||
@@ -200,6 +200,7 @@ class sf_production_plan(models.Model):
|
||||
raise ValidationError("未选择生产线")
|
||||
else:
|
||||
workorder_id_list = record.production_id.workorder_ids.ids
|
||||
if record.production_id:
|
||||
if record.production_id.workorder_ids:
|
||||
for item in record.production_id.workorder_ids:
|
||||
if item.name == 'CNC加工':
|
||||
@@ -231,12 +232,12 @@ class sf_production_plan(models.Model):
|
||||
# record.production_id.date_planned_start = record.date_planned_start
|
||||
# record.production_id.date_planned_finished = record.date_planned_finished
|
||||
record.sudo().production_id.production_line_id = record.production_line_id.id
|
||||
if record.production_id.workorder_ids:
|
||||
record.sudo().production_id.workorder_ids.filtered(
|
||||
lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write(
|
||||
{'production_line_id': record.production_line_id.id,
|
||||
'plan_start_processing_time': record.date_planned_start})
|
||||
else:
|
||||
raise ValidationError("未找到工单")
|
||||
|
||||
# record.date_planned_finished = record.date_planned_start + timedelta(days=3)
|
||||
# record.state = 'done'
|
||||
return {
|
||||
|
||||
@@ -17,18 +17,18 @@
|
||||
decoration-danger="state == 'finished'"/>
|
||||
<field name="name"/>
|
||||
<field name="origin"/>
|
||||
<field name="order_deadline"/>
|
||||
<field name="order_deadline" widget="date"/>
|
||||
<field name="product_qty"/>
|
||||
<field name="production_line_id"/>
|
||||
<field name="date_planned_start"/>
|
||||
<field name="date_planned_finished"/>
|
||||
<field name="actual_start_time"/>
|
||||
<field name="actual_end_time"/>
|
||||
<field name="actual_process_time"/>
|
||||
<field name="schedule_setting"/>
|
||||
<button name="do_production_schedule" class="btn schedule_done" string="生产排程" type="object"
|
||||
attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('actual_start_time', '!=', False)]}"
|
||||
groups="sf_base.group_plan_dispatch"/>
|
||||
<field name="actual_start_time" optional='hide'/>
|
||||
<field name="actual_end_time" optional='hide'/>
|
||||
<field name="actual_process_time" optional='hide'/>
|
||||
<field name="schedule_setting" optional='hide'/>
|
||||
<!-- <button name="do_production_schedule" class="btn schedule_done" string="生产排程" type="object" -->
|
||||
<!-- attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('actual_start_time', '!=', False)]}" -->
|
||||
<!-- groups="sf_base.group_plan_dispatch"/> -->
|
||||
<button name="cancel_production_schedule" class="btn schedule_cancel" string="取消排程" type="object"
|
||||
attrs="{'invisible': ['|', ('state', '!=', 'done'), ('actual_start_time', '!=', False)]}"
|
||||
groups="sf_base.group_plan_dispatch"/>
|
||||
@@ -63,12 +63,12 @@
|
||||
</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"/>
|
||||
<field name="product_qty"/>
|
||||
<field name="order_deadline"/>
|
||||
<field name="order_deadline" widget="date"/>
|
||||
<!-- <field name="process_time"/> -->
|
||||
<field name="schedule_setting"/>
|
||||
<field name="production_line_id" domain="[('name', 'ilike', 'CNC')]"/>
|
||||
@@ -135,12 +135,13 @@
|
||||
<!-- <field name="delivery_quantity"/> -->
|
||||
<!-- <field name="delivery_date"/> -->
|
||||
<!-- </group> -->
|
||||
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="message_ids"/>
|
||||
</div>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -151,16 +152,27 @@
|
||||
<field name="model">sf.production.plan</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="订单计划">
|
||||
|
||||
<!-- Your other filters go here -->
|
||||
<filter name="archived" string="已归档" domain="[('active','=',False)]"/>
|
||||
<filter name="not archived" string="未归档" domain="[('active','=',True)]"/>
|
||||
<!-- <filter name="archived" string="已归档" domain="[('active','=',False)]"/> -->
|
||||
<!-- <filter name="not archived" string="未归档" domain="[('active','=',True)]"/> -->
|
||||
<field name="name"/>
|
||||
<field name="product_qty"/>
|
||||
<field name="date_planned_start"/>
|
||||
<field name="date_planned_finished"/>
|
||||
<field name="state"/>
|
||||
<searchpanel class="account_root">
|
||||
<field name="state" icon="fa-filter"/>
|
||||
<filter string="待排程" name="draft" domain="[('state','=','draft')]"/>
|
||||
<filter string="已排程" name="done" domain="[('state','=','done')]"/>
|
||||
<filter string="加工中" name="processing" domain="[('state','=','processing')]"/>
|
||||
<filter string="已完成" name="finished" domain="[('state','=','finished')]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter name="group_by_state" string="状态" domain="[]" context="{'group_by': 'state'}"/>
|
||||
</group>
|
||||
<group expand="0" string="Group By">
|
||||
<filter name="group_by_production_line_id" string="生产线" domain="[]" context="{'group_by': 'production_line_id'}"/>
|
||||
</group>
|
||||
<searchpanel>
|
||||
<!-- <field name="state" icon="fa-filter"/> -->
|
||||
<field name="production_line_id" select="multi" string="生产线" icon="fa-building" enable_counters="1"/>
|
||||
<field name="state" select="multi" string="状态" icon="fa-building" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
@@ -187,30 +199,41 @@
|
||||
<field name="date_planned_start"/>
|
||||
<field name="date_planned_finished"/>
|
||||
<field name="state"/>
|
||||
<field name="origin"/>
|
||||
<field name="order_deadline"/>
|
||||
<field name="product_id"/>
|
||||
<templates>
|
||||
<div t-name="gantt-popover" class="container-fluid">
|
||||
<div class="row g-0">
|
||||
<div class="col">
|
||||
<ul class="ps-1 mb-0 list-unstyled">
|
||||
<li>
|
||||
<strong>开始时间:</strong>
|
||||
<t t-out="userTimezoneStartDate.format('L LTS')"/>
|
||||
<strong>销售订单号:</strong>
|
||||
<t t-out="origin"/>
|
||||
</li>
|
||||
<li>
|
||||
<strong>结束时间:</strong>
|
||||
<t t-out="userTimezoneStopDate.format('L LTS')"/>
|
||||
</li>
|
||||
<li>
|
||||
<strong>名称:</strong>
|
||||
<strong>制造订单号:</strong>
|
||||
<t t-out="name"/>
|
||||
</li>
|
||||
<li>
|
||||
<strong>订单交期:</strong>
|
||||
<t t-out="order_deadline.format('L LTS')"/>
|
||||
</li>
|
||||
<li>
|
||||
<strong>产品名称:</strong>
|
||||
<t t-out="product_id[1]"/>
|
||||
</li>
|
||||
<li>
|
||||
<strong>数量:</strong>
|
||||
<t t-out="product_qty"/>
|
||||
</li>
|
||||
<li>
|
||||
<strong>状态:</strong>
|
||||
<t t-out="state"/>
|
||||
<strong>计划开始时间:</strong>
|
||||
<t t-out="userTimezoneStartDate.format('L LTS')"/>
|
||||
</li>
|
||||
<li>
|
||||
<strong>计划结束时间:</strong>
|
||||
<t t-out="userTimezoneStopDate.format('L LTS')"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -245,6 +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_draft': 1, 'display_complete': True}</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
|
||||
@@ -114488,10 +114488,21 @@ msgid "径跳精度(mm)"
|
||||
msgstr ""
|
||||
|
||||
#. module: sf_manufacturing
|
||||
#: model:ir.model.fields.selection,name:sf_manufacturing.selection__mrp_production__state__progress
|
||||
#: model:ir.model.fields.selection,name:sf_manufacturing.selection__mrp_production__state__draft
|
||||
msgid "待排程"
|
||||
msgstr "待排程"
|
||||
|
||||
#. module: sf_manufacturing
|
||||
#: model:ir.model.fields.selection,name:sf_manufacturing.selection__mrp_production__process_state__待加工
|
||||
#: model:ir.model.fields.selection,name:sf_manufacturing.selection__mrp_production__state__confirmed
|
||||
msgid "待加工"
|
||||
msgstr "待加工"
|
||||
|
||||
#. module: sf_manufacturing
|
||||
#: model:ir.model.fields.selection,name:sf_manufacturing.selection__mrp_production__state__progress
|
||||
msgid "待排程"
|
||||
msgstr "加工中"
|
||||
|
||||
#. module: sf_base
|
||||
#: model:ir.model.fields,field_description:sf_base.field_sf_cutting_tool_model__jump_accuracy
|
||||
msgid "径跳精度(um)"
|
||||
|
||||
@@ -19,6 +19,7 @@ from . import parser_and_calculate_work_time as pc
|
||||
|
||||
class QuickEasyOrder(models.Model):
|
||||
_name = 'quick.easy.order'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_description = '简易下单'
|
||||
_order = 'id desc'
|
||||
|
||||
@@ -35,13 +36,14 @@ class QuickEasyOrder(models.Model):
|
||||
('0.03', '±0.03mm'),
|
||||
('0.02', '±0.02mm'),
|
||||
('0.01', '±0.01mm')], string='加工精度', default='0.10')
|
||||
material_id = fields.Many2one('sf.production.materials', '材料')
|
||||
material_model_id = fields.Many2one('sf.materials.model', '型号')
|
||||
material_id = fields.Many2one('sf.production.materials', '材料', tracking=True)
|
||||
material_model_id = fields.Many2one('sf.materials.model', '型号', tracking=True)
|
||||
# process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||
parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数')
|
||||
quantity = fields.Integer('数量', default=1)
|
||||
unit_price = fields.Float('单价')
|
||||
price = fields.Float('总价')
|
||||
parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数',
|
||||
tracking=True)
|
||||
quantity = fields.Integer('数量', default=1, tracking=True)
|
||||
unit_price = fields.Float('单价', tracking=True)
|
||||
price = fields.Float('总价', tracking=True)
|
||||
model_file = fields.Binary('glb模型文件')
|
||||
upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件')
|
||||
delivery_time = fields.Date('交货日期')
|
||||
@@ -49,10 +51,10 @@ class QuickEasyOrder(models.Model):
|
||||
state = fields.Selection([('草稿', '草稿'), ('待派单', '待派单'),
|
||||
('待接单', '待接单'), ('加工中', '加工中'),
|
||||
('物流中', '物流中'), ('已交付', '已交付')], string='订单状态', default='草稿',
|
||||
readonly=True)
|
||||
readonly=True, tracking=True)
|
||||
model_color_state = fields.Selection([
|
||||
('success', '成功'),
|
||||
('fail', '失败')], string='模型上色状态')
|
||||
('fail', '失败')], string='模型上色状态', tracking=True)
|
||||
processing_time = fields.Integer('加工时长(min)')
|
||||
sale_order_id = fields.Many2one('sale.order', '销售订单号')
|
||||
|
||||
@@ -94,8 +96,7 @@ class QuickEasyOrder(models.Model):
|
||||
obj.state = '待接单'
|
||||
return obj
|
||||
|
||||
|
||||
def model_analyze(self,model_attachment):
|
||||
def model_analyze(self, model_attachment):
|
||||
"""
|
||||
step模型解析,上传模型时转为web可显示的格式
|
||||
:return:
|
||||
|
||||
@@ -16,6 +16,7 @@ from odoo.exceptions import ValidationError, UserError
|
||||
|
||||
class QuickEasyOrder(models.Model):
|
||||
_name = 'quick.easy.order'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_description = '简易下单'
|
||||
_order = 'id desc'
|
||||
|
||||
@@ -32,13 +33,15 @@ class QuickEasyOrder(models.Model):
|
||||
('0.03', '±0.03mm'),
|
||||
('0.02', '±0.02mm'),
|
||||
('0.01', '±0.01mm')], string='加工精度', default='0.10')
|
||||
material_id = fields.Many2one('sf.production.materials', '材料')
|
||||
material_model_id = fields.Many2one('sf.materials.model', '型号', domain="[('materials_id', '=', material_id)]")
|
||||
material_id = fields.Many2one('sf.production.materials', '材料', tracking=True)
|
||||
material_model_id = fields.Many2one('sf.materials.model', '型号', domain="[('materials_id', '=', material_id)]",
|
||||
tracking=True)
|
||||
# process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||
parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数')
|
||||
quantity = fields.Integer('数量', default=1)
|
||||
unit_price = fields.Float('单价')
|
||||
price = fields.Float('总价')
|
||||
parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数',
|
||||
tracking=True)
|
||||
quantity = fields.Integer('数量', default=1, tracking=True)
|
||||
unit_price = fields.Float('单价', tracking=True)
|
||||
price = fields.Float('总价', tracking=True)
|
||||
model_file = fields.Binary('glb模型文件')
|
||||
upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件')
|
||||
delivery_time = fields.Date('交货日期')
|
||||
@@ -46,10 +49,10 @@ class QuickEasyOrder(models.Model):
|
||||
state = fields.Selection([('草稿', '草稿'), ('待派单', '待派单'),
|
||||
('待接单', '待接单'), ('加工中', '加工中'),
|
||||
('物流中', '物流中'), ('已交付', '已交付')], string='订单状态', default='草稿',
|
||||
readonly=True)
|
||||
readonly=True, tracking=True)
|
||||
model_color_state = fields.Selection([
|
||||
('success', '成功'),
|
||||
('fail', '失败')], string='模型上色状态')
|
||||
('fail', '失败')], string='模型上色状态', tracking=True)
|
||||
processing_time = fields.Integer('加工时长(min)')
|
||||
sale_order_id = fields.Many2one('sale.order', '销售订单号')
|
||||
|
||||
|
||||
@@ -171,6 +171,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,
|
||||
@@ -215,6 +220,17 @@ class RePurchaseOrder(models.Model):
|
||||
if len(product_id) != len(line):
|
||||
raise ValidationError('【%s】已存在,请勿重复添加' % product[-1].name)
|
||||
|
||||
def button_confirm(self):
|
||||
result = super(RePurchaseOrder, self).button_confirm()
|
||||
for item in self:
|
||||
# 确认订单时,自动分配序列号
|
||||
if item.picking_ids:
|
||||
for picking_id in item.picking_ids:
|
||||
if picking_id.move_ids:
|
||||
for move_id in picking_id.move_ids:
|
||||
move_id.put_move_line()
|
||||
return result
|
||||
|
||||
|
||||
class ResPartnerToSale(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
@@ -233,12 +249,12 @@ class ResPartnerToSale(models.Model):
|
||||
if obj:
|
||||
raise UserError('该税ID已存在,请重新输入')
|
||||
|
||||
@api.constrains('email')
|
||||
def _check_email(self):
|
||||
if self.customer_rank > 0:
|
||||
obj = self.sudo().search([('email', '=', self.email), ('id', '!=', self.id), ('active', '=', True)])
|
||||
if obj:
|
||||
raise UserError('该邮箱已存在,请重新输入')
|
||||
# @api.constrains('email')
|
||||
# def _check_email(self):
|
||||
# if self.customer_rank > 0:
|
||||
# obj = self.sudo().search([('email', '=', self.email), ('id', '!=', self.id), ('active', '=', True)])
|
||||
# if obj:
|
||||
# raise UserError('该邮箱已存在,请重新输入')
|
||||
|
||||
@api.model
|
||||
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids" options="{'post_refresh': 'recipients'}"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -24,18 +24,18 @@
|
||||
<attribute name="required">1</attribute>
|
||||
<attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>
|
||||
</field>
|
||||
<field name="email" position="replace">
|
||||
<field name="email"
|
||||
attrs="{'readonly': [('id','!=', False)]}"/>
|
||||
</field>
|
||||
<field name="mobile" position="attributes">
|
||||
<attribute name="attrs">{'required': [('phone', '=', False)],'readonly': [('id','!=', False)]}
|
||||
</attribute>
|
||||
</field>
|
||||
<field name="phone" position="attributes">
|
||||
<attribute name="attrs">{'required': [('mobile', '=', False)],'readonly': [('id','!=', False)]}
|
||||
</attribute>
|
||||
</field>
|
||||
<!-- <field name="email" position="replace">-->
|
||||
<!-- <field name="email"-->
|
||||
<!-- attrs="{'readonly': [('id','!=', False)]}"/>-->
|
||||
<!-- </field>-->
|
||||
<!-- <field name="mobile" position="attributes">-->
|
||||
<!-- <attribute name="attrs">{'required': [('phone', '=', False)],'readonly': [('id','!=', False)]}-->
|
||||
<!-- </attribute>-->
|
||||
<!-- </field>-->
|
||||
<!-- <field name="phone" position="attributes">-->
|
||||
<!-- <attribute name="attrs">{'required': [('mobile', '=', False)],'readonly': [('id','!=', False)]}-->
|
||||
<!-- </attribute>-->
|
||||
<!-- </field>-->
|
||||
<field name="street" position="attributes">
|
||||
<attribute name="attrs">{'readonly': [('id','!=', False)]}
|
||||
</attribute>
|
||||
@@ -56,10 +56,10 @@
|
||||
<field name="user_id" widget="many2one_avatar_user" context="{'is_sale': True }"
|
||||
attrs="{'required' : [('customer_rank','>', 0)]}"/>
|
||||
</xpath>
|
||||
<field name="category_id" position="attributes">
|
||||
<attribute name="required">1</attribute>
|
||||
<attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>
|
||||
</field>
|
||||
<!-- <field name="category_id" position="attributes">-->
|
||||
<!-- <attribute name="required">1</attribute>-->
|
||||
<!-- <attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>-->
|
||||
<!-- </field>-->
|
||||
<field name="company_registry" position="attributes">
|
||||
<attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>
|
||||
</field>
|
||||
@@ -101,7 +101,7 @@
|
||||
<field name="property_supplier_payment_term_id" position="before">
|
||||
<field name="purchase_user_id" context="{'supplier_rank': supplier_rank }"
|
||||
widget="many2one_avatar_user"
|
||||
attrs="{'required' : [('supplier_rank','>', 0)],'readonly': [('customer_rank','>', 0)]}"/>
|
||||
attrs="{'required' : [('supplier_rank','>', 0)]}"/>
|
||||
</field>
|
||||
<xpath expr="//field[@name='property_account_position_id']" position="attributes">
|
||||
<attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>
|
||||
@@ -195,10 +195,10 @@
|
||||
<attribute name="attrs">{'invisible': [('customer_rank','=', 0)]}
|
||||
</attribute>
|
||||
</field>
|
||||
<field name="user_id" position="before">
|
||||
<field name="purchase_user_id" widget="many2one_avatar_user"
|
||||
attrs="{'invisible' : [('supplier_rank','=', 0)]}"/>
|
||||
</field>
|
||||
<!-- <field name="user_id" position="before">-->
|
||||
<!-- <field name="purchase_user_id" widget="many2one_avatar_user"-->
|
||||
<!-- attrs="{'invisible' : [('supplier_rank','=', 0)]}"/>-->
|
||||
<!-- </field>-->
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
@@ -1,54 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="sale_order_view_search_inherit_sf" model="ir.ui.view">
|
||||
<field name="name">sale.order.search.inherit.sf</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="mode">primary</field>
|
||||
<field name="inherit_id" ref="sale.view_sales_order_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<filter name="my_sale_orders_filter" position="replace">
|
||||
<field name="campaign_id"/>
|
||||
<separator/>
|
||||
<filter string="报价" name="draft" domain="[('state','in',('draft', 'sent'))]"/>
|
||||
<filter string="销售订单" name="sales" domain="[('state','in',('sale','done'))]"/>
|
||||
<separator/>
|
||||
<filter string="创建日期" name="filter_create_date" date="create_date"/>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_quotations_with_onboarding_inherit_sf" model="ir.actions.act_window">
|
||||
<field name="name">报价</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_id" ref="sale.view_quotation_tree_with_onboarding"/>
|
||||
<field name="view_mode">tree,kanban,form,calendar,pivot,graph,activity</field>
|
||||
<field name="search_view_id" ref="sale_order_view_search_inherit_sf"/>
|
||||
<field name="context">{'search_default_my_quotation': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a new quotation, the first step of a new sale!
|
||||
</p>
|
||||
<p>
|
||||
Once the quotation is confirmed by the customer, it becomes a sales order.
|
||||
<br/>
|
||||
You will be able to create an invoice and collect the payment.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- <menuitem id="menu_sale_quotations">-->
|
||||
<!-- <field name="active" eval="False"/>-->
|
||||
<!-- </menuitem>-->
|
||||
|
||||
<menuitem id="menu_sale_quotations_inherit_sf"
|
||||
action="action_quotations_with_onboarding_inherit_sf"
|
||||
groups="sales_team.group_sale_salesman,sf_base.group_sale_salemanager,sf_base.group_sale_director"
|
||||
parent="sale.sale_order_menu"
|
||||
sequence="11"/>
|
||||
|
||||
<record model="ir.ui.view" id="view_sale_order_form_inherit_sf">
|
||||
<field name="name">sale.order.form.inherit.sf</field>
|
||||
<field name="model">sale.order</field>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
'views/tool_material_search.xml',
|
||||
'views/fixture_material_search_views.xml',
|
||||
'views/menu_view.xml',
|
||||
'views/stock.xml',
|
||||
'data/tool_data.xml',
|
||||
],
|
||||
'demo': [
|
||||
|
||||
@@ -109,6 +109,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
res = {'Succeed': True, 'Datas': []}
|
||||
try:
|
||||
datas = request.httprequest.data
|
||||
logging.info('datas: %s' % datas)
|
||||
ret = str(datas, 'utf-8')
|
||||
data_lists = ret.split(",")
|
||||
data_list = [data.replace('+', '') for data in data_lists]
|
||||
@@ -120,7 +121,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
{'Succeed': False, 'ErrorCode': 201, 'code': data_list[0], 'Error': '没有找到正在组装的组装单!'})
|
||||
tool_assembly.write({
|
||||
'after_assembly_tool_loading_length': float(data_list[1] or "0"), # 高度(总长度)
|
||||
'after_assembly_functional_tool_diameter': float(data_list[2] or "0"), # 直径
|
||||
'after_assembly_functional_tool_diameter': float(data_list[2] or "0") * 2, # 直径
|
||||
'after_assembly_knife_tip_r_angle': float(data_list[3] or "0") # R角
|
||||
})
|
||||
except Exception as e:
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<field name="model_id" ref="model_sf_tool_datasync"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._cron_tool_datasync_all()</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="interval_number">12</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -7,4 +7,5 @@ from . import functional_tool_enroll
|
||||
from . import fixture_material_search
|
||||
from . import fixture_enroll
|
||||
from . import temporary_data_processing_methods
|
||||
from . import stock
|
||||
|
||||
|
||||
@@ -283,7 +283,8 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
|
||||
|
||||
'loading_task_source': '0',
|
||||
'applicant': self.env.user.name,
|
||||
'use_tool_time': self.need_knife_time,
|
||||
'use_tool_time': fields.Datetime.now() + timedelta(
|
||||
hours=4) if not self.need_knife_time else self.need_knife_time,
|
||||
'reason_for_applying': '工单用刀',
|
||||
|
||||
'sf_cam_work_order_program_knife_plan_id': self.id
|
||||
@@ -580,6 +581,15 @@ class FunctionalToolAssembly(models.Model):
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
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 put_start_preset(self):
|
||||
self.search([('start_preset_bool', '=', True)]).write({'start_preset_bool': False})
|
||||
self.write({
|
||||
@@ -749,7 +759,8 @@ class FunctionalToolDismantle(models.Model):
|
||||
return 'GNDJ-CJD-%s-%s' % (datetime, num)
|
||||
|
||||
functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True,
|
||||
domain=[('functional_tool_status', '!=', '已拆除')])
|
||||
domain=[('functional_tool_status', '!=', '已拆除'),
|
||||
('current_location', '=', '刀具房')])
|
||||
tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
|
||||
compute='_compute_functional_tool_num')
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_functional_tool_num', store=True)
|
||||
@@ -925,7 +936,7 @@ class FunctionalToolDismantle(models.Model):
|
||||
location = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
|
||||
location_dest = self.env['stock.location'].search([('name', '=', '刀具房')])
|
||||
# =================刀柄是否[报废]拆解=======
|
||||
location_dest_scrap = self.env['stock.location'].search([('name', '=', 'Scrap')])
|
||||
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:
|
||||
@@ -933,30 +944,31 @@ class FunctionalToolDismantle(models.Model):
|
||||
functional_tool_assembly = self.functional_tool_id.functional_tool_name_id
|
||||
if self.scrap_boolean:
|
||||
# 刀柄报废 入库到Scrap
|
||||
lot.create_stock_quant(location, location_dest_scrap, functional_tool_assembly.id, code,
|
||||
functional_tool_assembly, functional_tool_assembly.tool_groups_id)
|
||||
lot.create_stock_quant(location, location_dest_scrap_ids[-1], False, code, False, False)
|
||||
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)
|
||||
lot.create_stock_quant(location, location_dest, False, code, False, False)
|
||||
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, code)
|
||||
location_dest_scrap_ids[-1], code)
|
||||
elif self.blade_product_id:
|
||||
self.blade_product_id.dismantle_stock_moves(False, self.blade_lot_id, location, location_dest_scrap,
|
||||
code)
|
||||
self.blade_product_id.dismantle_stock_moves(False, self.blade_lot_id, location,
|
||||
location_dest_scrap_ids[-1], code)
|
||||
if self.bar_product_id:
|
||||
self.bar_product_id.dismantle_stock_moves(False, self.bar_lot_id, location, location_dest_scrap,
|
||||
code)
|
||||
self.bar_product_id.dismantle_stock_moves(False, self.bar_lot_id, location,
|
||||
location_dest_scrap_ids[-1], code)
|
||||
elif self.pad_product_id:
|
||||
self.pad_product_id.dismantle_stock_moves(False, self.pad_lot_id, location, location_dest_scrap,
|
||||
code)
|
||||
self.pad_product_id.dismantle_stock_moves(False, self.pad_lot_id, location,
|
||||
location_dest_scrap_ids[-1], code)
|
||||
if self.chuck_product_id:
|
||||
self.chuck_product_id.dismantle_stock_moves(False, self.chuck_lot_id, location, location_dest_scrap,
|
||||
code)
|
||||
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', '=', '磨削房')])
|
||||
@@ -1024,7 +1036,7 @@ class ProductProduct(models.Model):
|
||||
'product_id': self.id,
|
||||
'lot_id': lot_id.id,
|
||||
'move_id': stock_move_id.id,
|
||||
'destination_location_id': shelf_location_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',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
import base64
|
||||
import requests
|
||||
import logging
|
||||
from odoo import models, api
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
from odoo.exceptions import UserError
|
||||
@@ -10,14 +11,17 @@ class StockLot(models.Model):
|
||||
_inherit = 'stock.lot'
|
||||
_description = '夹具物料序列号注册'
|
||||
|
||||
def enroll_fixture_material_stock(self):
|
||||
def sync_enroll_fixture_material_stock_all(self):
|
||||
logging.info("调用 sync_enroll_fixture_material_stock_all 同步接口")
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + "/api/fixture_material_stock/create"
|
||||
objs_all = self.env['stock.lot'].search([('id', '=', self.id)])
|
||||
product_ids = self.env['product.product'].sudo().search([('categ_type', '=', '夹具')]).ids
|
||||
objs_all = self.env['stock.lot'].search([('rfid', '!=', False), ('product_id', 'in', product_ids)])
|
||||
fixture_material_stock_list = []
|
||||
try:
|
||||
if objs_all:
|
||||
for item in objs_all:
|
||||
val = {
|
||||
@@ -31,9 +35,12 @@ class StockLot(models.Model):
|
||||
r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
|
||||
ret = r.json()
|
||||
if ret.get('code') == 200:
|
||||
logging.info("夹具物料序列号每日同步成功")
|
||||
return '夹具物料序列号注册成功'
|
||||
else:
|
||||
raise UserError("没有注册夹具物料序列号信息")
|
||||
logging.info("没有注册夹具物料序列号信息")
|
||||
except Exception as e:
|
||||
logging.info("夹具物料序列号同步失败:%s" % e)
|
||||
|
||||
|
||||
class FixtureMaterialSearch(models.Model):
|
||||
@@ -42,14 +49,16 @@ class FixtureMaterialSearch(models.Model):
|
||||
|
||||
crea_url = "/api/fixture_material/create"
|
||||
|
||||
def enroll_fixture_material(self):
|
||||
def sync_enroll_fixture_material_all(self):
|
||||
logging.info("调用 sync_enroll_fixture_material_all 同步接口")
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.search([('id', '=', self.id)])
|
||||
objs_all = self.search([])
|
||||
fixture_material_list = []
|
||||
try:
|
||||
if objs_all:
|
||||
for obj in objs_all:
|
||||
val = {
|
||||
@@ -69,14 +78,17 @@ class FixtureMaterialSearch(models.Model):
|
||||
r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
|
||||
ret = r.json()
|
||||
if ret.get('code') == 200:
|
||||
logging.info("夹具物料每日同步成功")
|
||||
return '夹具物料注册成功'
|
||||
else:
|
||||
raise UserError("没有注册夹具物料信息")
|
||||
logging.info("没有注册夹具物料信息")
|
||||
except Exception as e:
|
||||
logging.info("夹具物料同步失败:%s" % e)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
records = super(FixtureMaterialSearch, self).create(vals_list)
|
||||
for record in records:
|
||||
if record:
|
||||
record.enroll_fixture_material()
|
||||
return records
|
||||
# @api.model_create_multi
|
||||
# def create(self, vals_list):
|
||||
# records = super(FixtureMaterialSearch, self).create(vals_list)
|
||||
# for record in records:
|
||||
# if record:
|
||||
# record.enroll_fixture_material()
|
||||
# return records
|
||||
|
||||
@@ -14,7 +14,8 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
|
||||
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单', readonly=True)
|
||||
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id',
|
||||
store=True)
|
||||
code = fields.Char('编码')
|
||||
rfid = fields.Char('Rfid', readonly=True)
|
||||
rfid_dismantle = fields.Char('Rfid(已拆解)', readonly=True)
|
||||
@@ -30,56 +31,61 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精', readonly=True)
|
||||
new_former = fields.Selection([('0', '新'), ('1', '旧')], string='新/旧', readonly=True)
|
||||
tool_loading_length = fields.Float(string='总长度(mm)', readonly=True, digits=(10, 3))
|
||||
handle_length = fields.Float(string='刀柄长度(mm)',readonly=True, digits=(10, 3))
|
||||
handle_length = fields.Float(string='刀柄长度(mm)', readonly=True, digits=(10, 3))
|
||||
functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True, digits=(10, 3))
|
||||
effective_length = fields.Float(string='有效长(mm)', readonly=True)
|
||||
tool_room_num = fields.Integer(string='刀具房数量', readonly=True)
|
||||
line_edge_knife_library_num = fields.Integer(string='线边刀库数量', readonly=True)
|
||||
machine_knife_library_num = fields.Integer(string='机内刀库数量', readonly=True)
|
||||
tool_room_num = fields.Integer(string='刀具房数量', compute='_compute_num', store=True)
|
||||
line_edge_knife_library_num = fields.Integer(string='线边刀库数量', compute='_compute_num', store=True)
|
||||
machine_knife_library_num = fields.Integer(string='机内刀库数量', compute='_compute_num', store=True)
|
||||
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
|
||||
alarm_value = fields.Integer(string='报警值(min)', readonly=True)
|
||||
used_value = fields.Integer(string='已使用值(min)', readonly=True)
|
||||
functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')],
|
||||
string='状态', store=True, default='正常')
|
||||
current_location_id = fields.Many2one('stock.location', string='当前位置', readonly=True)
|
||||
current_location_id = fields.Many2one('stock.location', string='当前位置', compute='_compute_current_location_id',
|
||||
store=True)
|
||||
current_shelf_location_id = fields.Many2one('sf.shelf.location', string='当前货位', readonly=True)
|
||||
current_location = fields.Selection(
|
||||
[('组装后', '组装后'), ('刀具房', '刀具房'), ('线边刀库', '线边刀库'), ('机内刀库', '机内刀库')],
|
||||
string='位置', compute='_compute_current_location_id', store=True)
|
||||
image = fields.Binary('图片', readonly=True)
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools',
|
||||
string='功能刀具安全库存', readonly=True)
|
||||
|
||||
@api.depends('barcode_id.quant_ids', 'functional_tool_status')
|
||||
@api.depends('barcode_id.quant_ids', 'functional_tool_status', 'current_shelf_location_id')
|
||||
def _compute_current_location_id(self):
|
||||
for record in self:
|
||||
if record.functional_tool_status == '已拆除':
|
||||
record.current_location_id = False
|
||||
record.current_location = False
|
||||
else:
|
||||
if record.barcode_id.quant_ids:
|
||||
for quant_id in record.barcode_id.quant_ids:
|
||||
if quant_id.inventory_quantity_auto_apply > 0:
|
||||
record.current_location_id = quant_id.location_id
|
||||
if quant_id.location_id.name == '制造前':
|
||||
if not record.current_shelf_location_id:
|
||||
record.current_location = '机内刀库'
|
||||
else:
|
||||
record.current_location = quant_id.location_id.name
|
||||
if record.current_location_id:
|
||||
record.sudo().get_location_num()
|
||||
record.current_location = '线边刀库'
|
||||
else:
|
||||
record.current_location = '刀具房'
|
||||
else:
|
||||
record.current_location_id = False
|
||||
record.current_location = False
|
||||
if record.functional_tool_status == '已拆除':
|
||||
record.current_location_id = False
|
||||
record.current_location = False
|
||||
record.tool_room_num = 0
|
||||
record.line_edge_knife_library_num = 0
|
||||
record.machine_knife_library_num = 0
|
||||
|
||||
def get_location_num(self):
|
||||
@api.depends('current_location', 'functional_tool_status')
|
||||
def _compute_num(self):
|
||||
"""
|
||||
计算库存位置数量
|
||||
"""
|
||||
for obj in self:
|
||||
if obj.functional_tool_status == '已拆除':
|
||||
obj.tool_room_num = 0
|
||||
obj.line_edge_knife_library_num = 0
|
||||
obj.machine_knife_library_num = 0
|
||||
else:
|
||||
if obj.current_location_id:
|
||||
obj.tool_room_num = 0
|
||||
obj.line_edge_knife_library_num = 0
|
||||
@@ -91,6 +97,70 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
elif "机内刀库" in obj.current_location:
|
||||
obj.machine_knife_library_num = 1
|
||||
|
||||
def tool_in_out_stock_location(self, location_id):
|
||||
tool_room_id = self.env['stock.location'].search([('name', '=', '刀具房')])
|
||||
pre_manufacturing_id = self.env['stock.location'].search([('name', '=', '制造前')])
|
||||
for item in self:
|
||||
# 中控反馈该位置有刀
|
||||
if item:
|
||||
# 系统该位置有刀
|
||||
if location_id.product_sn_id:
|
||||
# 中控反馈和系统中,该位置是同一把刀
|
||||
if item.barcode_id == location_id.product_sn_id:
|
||||
return True
|
||||
# 中控反馈和系统中,该位置不是同一把刀
|
||||
else:
|
||||
# 原刀从线边出库
|
||||
item.tool_in_out_stock_location_1(location_id, tool_room_id)
|
||||
# 新刀入库到线边
|
||||
item.create_stock_move(pre_manufacturing_id, location_id)
|
||||
item.current_shelf_location_id = location_id.id
|
||||
|
||||
# 中控反馈该位置没有刀
|
||||
else:
|
||||
# 系统该位置有刀
|
||||
if location_id.product_sn_id:
|
||||
item.tool_in_out_stock_location_1(location_id, tool_room_id)
|
||||
|
||||
def tool_in_out_stock_location_1(self, location_id, tool_room_id):
|
||||
tool = self.env['sf.functional.cutting.tool.entity'].search(
|
||||
[('barcode_id', '=', location_id.product_sn_id.id)])
|
||||
if tool.current_location == '线边刀库':
|
||||
tool.create_stock_move(tool_room_id, False)
|
||||
# 修改功能刀具的当前位置
|
||||
tool.current_shelf_location_id = False
|
||||
|
||||
def create_stock_move(self, location_dest_id, destination_location_id):
|
||||
|
||||
# 创建库存移动记录
|
||||
stock_move_id = self.env['stock.move'].sudo().create({
|
||||
'name': '/',
|
||||
'product_id': self.barcode_id.product_id.id,
|
||||
'location_id': self.current_location_id.id,
|
||||
'location_dest_id': location_dest_id.id,
|
||||
'product_uom_qty': 1.00,
|
||||
'state': 'done'
|
||||
})
|
||||
|
||||
# 创建移动历史记录
|
||||
stock_move_line_id = self.env['stock.move.line'].sudo().create({
|
||||
'product_id': self.barcode_id.product_id.id,
|
||||
'lot_id': self.barcode_id.id,
|
||||
'move_id': stock_move_id.id,
|
||||
'current_location_id': False if not self.current_shelf_location_id else self.current_shelf_location_id.id,
|
||||
'destination_location_id': False if not destination_location_id else destination_location_id.id,
|
||||
'qty_done': 1.0,
|
||||
'state': 'done',
|
||||
'functional_tool_type_id': self.sf_cutting_tool_type_id.id,
|
||||
'diameter': self.functional_tool_diameter,
|
||||
'knife_tip_r_angle': self.knife_tip_r_angle,
|
||||
'code': self.code,
|
||||
'rfid': self.rfid,
|
||||
'functional_tool_name': self.name,
|
||||
'tool_groups_id': self.tool_groups_id.id
|
||||
})
|
||||
return stock_move_id, stock_move_line_id
|
||||
|
||||
@api.model
|
||||
def _read_group_mrs_cutting_tool_type_id(self, categories, domain, order):
|
||||
mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
@@ -192,12 +262,14 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
机床当前刀库实时信息接口,功能刀具出库
|
||||
"""
|
||||
# 获取位置对象
|
||||
location_inventory_id = self.current_location_id
|
||||
stock_location_id = self.env['stock.location'].search([('name', '=', '制造前')])
|
||||
# 创建功能刀具该批次/序列号 库存移动和移动历史
|
||||
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)
|
||||
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)
|
||||
|
||||
# ==========刀具组接口==========
|
||||
# def _register_functional_tool_groups(self, obj):
|
||||
@@ -305,7 +377,7 @@ class StockMoveLine(models.Model):
|
||||
functional_tool_name = fields.Char('刀具名称')
|
||||
diameter = fields.Float(string='刀具直径(mm)')
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)')
|
||||
install_tool_time = fields.Datetime("刀具组装时间", default=fields.Datetime.now())
|
||||
install_tool_time = fields.Datetime("刀具组装时间")
|
||||
code = fields.Char('编码')
|
||||
rfid = fields.Char('Rfid')
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组')
|
||||
@@ -315,6 +387,22 @@ class StockMoveLine(models.Model):
|
||||
names = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return categories.browse(names)
|
||||
|
||||
def action_open_reference1(self):
|
||||
self.ensure_one()
|
||||
if self.functional_tool_name_id:
|
||||
action = self.functional_tool_name_id.action_open_reference1()
|
||||
return action
|
||||
elif self.move_id:
|
||||
action = self.move_id.action_open_reference()
|
||||
if action['res_model'] != 'stock.move':
|
||||
return action
|
||||
return {
|
||||
'res_model': self._name,
|
||||
'type': 'ir.actions.act_window',
|
||||
'views': [[False, "form"]],
|
||||
'res_id': self.id,
|
||||
}
|
||||
|
||||
|
||||
class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
_name = 'sf.real.time.distribution.of.functional.tools'
|
||||
@@ -328,10 +416,10 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
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_stock_num = fields.Integer(string='刀具房数量')
|
||||
side_shelf_num = fields.Integer(string='线边刀库数量')
|
||||
on_tool_stock_num = fields.Integer(string='机内刀库数量')
|
||||
tool_stock_total = fields.Integer(string='当前库存量', readonly=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)
|
||||
tool_stock_total = fields.Integer(string='当前库存量', compute='_compute_tool_stock_total', store=True)
|
||||
min_stock_num = fields.Integer('最低库存量', tracking=True)
|
||||
max_stock_num = fields.Integer('最高库存量', tracking=True)
|
||||
batch_replenishment_num = fields.Integer('批次补货量', readonly=True, compute='_compute_batch_replenishment_num',
|
||||
@@ -404,10 +492,6 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
def _compute_batch_replenishment_num(self):
|
||||
for tool in self:
|
||||
if tool:
|
||||
# 计算刀具房数量、线边刀库数量、机内刀库数量
|
||||
tool.sudo().get_stock_num(tool)
|
||||
# 计算当前库存量
|
||||
tool.sudo().tool_stock_total = tool.tool_stock_num + tool.side_shelf_num + tool.on_tool_stock_num
|
||||
# 如果当前库存量小于最低库存量,计算批次补货量
|
||||
tool.sudo().open_batch_replenishment_num(tool)
|
||||
|
||||
@@ -426,6 +510,38 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
else:
|
||||
tool.sudo().batch_replenishment_num = 0
|
||||
|
||||
@api.depends('sf_functional_tool_entity_ids', 'sf_functional_tool_entity_ids.tool_room_num',
|
||||
'sf_functional_tool_entity_ids.line_edge_knife_library_num',
|
||||
'sf_functional_tool_entity_ids.machine_knife_library_num')
|
||||
def _compute_stock_num(self):
|
||||
"""
|
||||
计算刀具房数量、线边刀库数量、机内刀库数量
|
||||
"""
|
||||
for tool in self:
|
||||
if tool:
|
||||
tool.tool_stock_num = 0
|
||||
tool.side_shelf_num = 0
|
||||
tool.on_tool_stock_num = 0
|
||||
if tool.sf_functional_tool_entity_ids:
|
||||
for cutting_tool in tool.sf_functional_tool_entity_ids:
|
||||
if cutting_tool.tool_room_num > 0:
|
||||
tool.tool_stock_num += 1
|
||||
elif cutting_tool.line_edge_knife_library_num > 0:
|
||||
tool.side_shelf_num += 1
|
||||
elif cutting_tool.machine_knife_library_num > 0:
|
||||
tool.on_tool_stock_num += 1
|
||||
else:
|
||||
tool.tool_stock_num = 0
|
||||
tool.side_shelf_num = 0
|
||||
tool.on_tool_stock_num = 0
|
||||
|
||||
@api.depends('tool_stock_num', 'side_shelf_num', 'on_tool_stock_num')
|
||||
def _compute_tool_stock_total(self):
|
||||
for tool in self:
|
||||
if tool:
|
||||
# 计算当前库存量
|
||||
tool.tool_stock_total = tool.tool_stock_num + tool.side_shelf_num + tool.on_tool_stock_num
|
||||
|
||||
def create_functional_tool_assembly(self, tool):
|
||||
"""
|
||||
创建功能刀具组装单
|
||||
@@ -446,27 +562,6 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
})
|
||||
tool.sudo().sf_functional_tool_assembly_ids = [(4, functional_tool_assembly.id)]
|
||||
|
||||
def get_stock_num(self, tool):
|
||||
"""
|
||||
计算刀具房数量、线边刀库数量、机内刀库数量
|
||||
"""
|
||||
if tool:
|
||||
tool.tool_stock_num = 0
|
||||
tool.side_shelf_num = 0
|
||||
tool.on_tool_stock_num = 0
|
||||
if tool.sf_functional_tool_entity_ids:
|
||||
for cutting_tool in tool.sf_functional_tool_entity_ids:
|
||||
if cutting_tool.tool_room_num > 0:
|
||||
tool.tool_stock_num += 1
|
||||
elif cutting_tool.line_edge_knife_library_num > 0:
|
||||
tool.side_shelf_num += 1
|
||||
elif cutting_tool.machine_knife_library_num > 0:
|
||||
tool.on_tool_stock_num += 1
|
||||
else:
|
||||
tool.tool_stock_num = 0
|
||||
tool.side_shelf_num = 0
|
||||
tool.on_tool_stock_num = 0
|
||||
|
||||
def create_or_edit_safety_stock(self, vals, sf_functional_tool_entity_ids):
|
||||
"""
|
||||
根据传入的信息新增或者更新功能刀具安全库存的信息
|
||||
|
||||
@@ -33,23 +33,26 @@ def get_suitable_coolant_names(item):
|
||||
|
||||
class ToolDatasync(models.Model):
|
||||
_name = 'sf.tool.datasync'
|
||||
_description = '定时同步所有刀具'
|
||||
_description = '定时同步所有刀具、夹具'
|
||||
|
||||
def _cron_tool_datasync_all(self):
|
||||
try:
|
||||
self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all()
|
||||
logging.info("刀具物料序列号每日同步成功")
|
||||
|
||||
self.env['stock.lot'].sudo().sync_enroll_fixture_material_stock_all()
|
||||
|
||||
self.env['sf.tool.material.search'].sudo().sync_enroll_tool_material_all()
|
||||
logging.info("刀具物料每日同步成功")
|
||||
|
||||
self.env['sf.fixture.material.search'].sudo().sync_enroll_fixture_material_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()
|
||||
logging.info("功能刀具预警每日同步成功")
|
||||
self.env['stock.move.line'].sudo().sync_enroll_functional_tool_move_all()
|
||||
logging.info("功能刀具出入库记录每日同步成功")
|
||||
self.env[
|
||||
'sf.real.time.distribution.of.functional.tools'].sudo().sync_enroll_functional_tool_real_time_distribution_all()
|
||||
logging.info("功能刀具安全库存每日同步成功")
|
||||
logging.info("已全部同步完成!!!")
|
||||
# self.env['sf.functional.tool.warning'].sudo().sync_enroll_functional_tool_warning_all()
|
||||
# logging.info("功能刀具预警每日同步成功")
|
||||
# self.env['stock.move.line'].sudo().sync_enroll_functional_tool_move_all()
|
||||
# logging.info("功能刀具出入库记录每日同步成功")
|
||||
# self.env['sf.real.time.distribution.of.functional.tools'].sudo().sync_enroll_functional_tool_real_time_distribution_all()
|
||||
# logging.info("功能刀具安全库存每日同步成功")
|
||||
except Exception as e:
|
||||
logging.info("捕获错误信息:%s" % e)
|
||||
raise ValidationError("数据错误导致同步失败,请联系管理员")
|
||||
@@ -59,24 +62,25 @@ class StockLot(models.Model):
|
||||
_inherit = 'stock.lot'
|
||||
_description = '刀具物料序列号注册'
|
||||
|
||||
def enroll_tool_material_stock(self):
|
||||
logging.info('调用刀具物料序列号注册接口: enroll_tool_material_stock()')
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create"
|
||||
objs_all = self.env['stock.lot'].search([('id', '=', self.id), ('active', 'in', [True, False])])
|
||||
self._get_sync_stock_lot(objs_all, str_url, token, headers)
|
||||
# def enroll_tool_material_stock(self):
|
||||
# logging.info('调用刀具物料序列号注册接口: enroll_tool_material_stock()')
|
||||
# sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
# token = sf_sync_config['token']
|
||||
# sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
# headers = Common.get_headers(self, token, sf_secret_key)
|
||||
# str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create"
|
||||
# objs_all = self.env['stock.lot'].search([('id', '=', self.id), ('active', 'in', [True, False])])
|
||||
# self._get_sync_stock_lot(objs_all, str_url, token, headers)
|
||||
|
||||
def sync_enroll_tool_material_stock_all(self):
|
||||
logging.info('调用刀具物料序列号注册接口: sync_enroll_tool_material_stock_all()')
|
||||
logging.info('调用 sync_enroll_tool_material_stock_all 同步接口')
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create"
|
||||
objs_all = self.env['stock.lot'].search([('rfid', '!=', False)])
|
||||
product_ids = self.env['product.product'].sudo().search([('categ_type', '=', '刀具')]).ids
|
||||
objs_all = self.env['stock.lot'].search([('product_id', 'in', product_ids)])
|
||||
self._get_sync_stock_lot(objs_all, str_url, token, headers)
|
||||
|
||||
def _get_sync_stock_lot(self, objs_all, str_url, token, headers):
|
||||
@@ -86,6 +90,7 @@ class StockLot(models.Model):
|
||||
for item in objs_all:
|
||||
val = {
|
||||
'name': item.name,
|
||||
'qty': item.product_qty,
|
||||
'tool_material_status': item.tool_material_status,
|
||||
'location': [] if not item.quant_ids else item.quant_ids[-1].location_id.name,
|
||||
'tool_material_search_id': item.tool_material_search_id.id,
|
||||
@@ -95,11 +100,12 @@ class StockLot(models.Model):
|
||||
r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
|
||||
ret = r.json()
|
||||
if ret.get('code') == 200:
|
||||
return '刀具物料序列号注册成功'
|
||||
logging.info("刀具物料序列号每日同步成功")
|
||||
return '刀具(夹具)物料序列号注册成功'
|
||||
else:
|
||||
logging.info("没有注册刀具物料序列号信息")
|
||||
logging.info("没有刀具物料序列号信息")
|
||||
except Exception as e:
|
||||
logging.info("捕获错误信息:%s" % e)
|
||||
logging.info("刀具物料序列号同步失败:%s" % e)
|
||||
|
||||
|
||||
class ToolMaterial(models.Model):
|
||||
@@ -108,18 +114,18 @@ class ToolMaterial(models.Model):
|
||||
|
||||
crea_url = '/api/tool_material/create'
|
||||
|
||||
def enroll_tool_material(self):
|
||||
logging.info('调用刀具物料注册接口: enroll_tool_material()')
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.search([('id', '=', self.id)])
|
||||
self._get_sync_tool_material_search(objs_all, str_url, token, headers)
|
||||
# def enroll_tool_material(self):
|
||||
# logging.info('调用刀具物料注册接口: enroll_tool_material()')
|
||||
# sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
# token = sf_sync_config['token']
|
||||
# sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
# headers = Common.get_headers(self, token, sf_secret_key)
|
||||
# str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
# objs_all = self.search([('id', '=', self.id)])
|
||||
# self._get_sync_tool_material_search(objs_all, str_url, token, headers)
|
||||
|
||||
def sync_enroll_tool_material_all(self):
|
||||
logging.info('调用刀具物料注册接口: sync_enroll_tool_material_all()')
|
||||
logging.info('调用 sync_enroll_tool_material_all 同步接口')
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
@@ -150,11 +156,12 @@ class ToolMaterial(models.Model):
|
||||
r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
|
||||
ret = r.json()
|
||||
if ret.get('code') == 200:
|
||||
logging.info("刀具物料每日同步成功")
|
||||
return '刀具物料注册成功'
|
||||
else:
|
||||
logging.info('没有注册刀具物料信息')
|
||||
except Exception as e:
|
||||
logging.info("捕获错误信息:%s" % e)
|
||||
logging.info("刀具物料同步失败:%s" % e)
|
||||
|
||||
|
||||
class FunctionalCuttingToolEntity(models.Model):
|
||||
@@ -164,18 +171,18 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
crea_url = "/api/functional_tool_entity/create"
|
||||
|
||||
# 注册同步功能刀具列表
|
||||
def enroll_functional_tool_entity(self):
|
||||
logging.info('调用功能刀具列表注册接口: enroll_functional_tool_entity()')
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.env['sf.functional.cutting.tool.entity'].search([('id', '=', self.id)])
|
||||
self._get_sync_functional_cutting_tool_entity(objs_all, str_url, token, headers)
|
||||
# def enroll_functional_tool_entity(self):
|
||||
# logging.info('调用功能刀具列表注册接口: enroll_functional_tool_entity()')
|
||||
# sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
# token = sf_sync_config['token']
|
||||
# sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
# headers = Common.get_headers(self, token, sf_secret_key)
|
||||
# str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
# objs_all = self.env['sf.functional.cutting.tool.entity'].search([('id', '=', self.id)])
|
||||
# self._get_sync_functional_cutting_tool_entity(objs_all, str_url, token, headers)
|
||||
|
||||
def esync_enroll_functional_tool_entity_all(self):
|
||||
logging.info('调用功能刀具列表注册接口: esync_enroll_functional_tool_entity_all()')
|
||||
logging.info('调用 esync_enroll_functional_tool_entity_all 同步接口')
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
@@ -202,6 +209,7 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
'coarse_middle_thin': item.coarse_middle_thin,
|
||||
'new_former': item.new_former,
|
||||
'tool_loading_length': item.tool_loading_length,
|
||||
'handle_length': item.handle_length,
|
||||
'functional_tool_length': item.functional_tool_length,
|
||||
'effective_length': item.effective_length,
|
||||
'max_lifetime_value': item.max_lifetime_value,
|
||||
@@ -226,19 +234,19 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
'blade_tip_characteristics_name': item.blade_tip_characteristics_id.name,
|
||||
'handle_type_name': item.handle_type_id.name,
|
||||
'cutting_direction_names': get_cutting_direction_names(item),
|
||||
'suitable_coolant_names': get_suitable_coolant_names(item),
|
||||
'active': item.active,
|
||||
'suitable_coolant_names': get_suitable_coolant_names(item)
|
||||
}
|
||||
functional_tool_list.append(val)
|
||||
kw = json.dumps(functional_tool_list, ensure_ascii=False)
|
||||
r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
|
||||
ret = r.json()
|
||||
if ret.get('code') == 200:
|
||||
logging.info("功能刀具列表每日同步成功")
|
||||
return "功能刀具注册成功"
|
||||
else:
|
||||
logging.info('没有注册功能刀具信息')
|
||||
except Exception as e:
|
||||
logging.info("捕获错误信息:%s" % e)
|
||||
logging.info("功能刀具同步失败:%s" % e)
|
||||
|
||||
|
||||
class FunctionalToolWarning(models.Model):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -44,6 +45,7 @@ class SfMaintenanceEquipment(models.Model):
|
||||
|
||||
# ==========机床当前刀库实时信息接口==========
|
||||
def register_equipment_tool(self):
|
||||
try:
|
||||
config = self.env['res.config.settings'].get_values()
|
||||
# token = sf_sync_config['token'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A]
|
||||
headers = {'Authorization': config['center_control_Authorization']}
|
||||
@@ -58,8 +60,11 @@ class SfMaintenanceEquipment(models.Model):
|
||||
return "机床当前刀库实时信息指令发送成功"
|
||||
else:
|
||||
raise ValidationError("机床当前刀库实时信息指令发送失败")
|
||||
except Exception as e:
|
||||
logging.info("register_equipment_tool()捕获错误信息:%s" % e)
|
||||
|
||||
def write_maintenance_equipment_tool(self, datas):
|
||||
try:
|
||||
if datas:
|
||||
# 清除设备机床刀位的刀具信息
|
||||
for obj in self.product_template_ids:
|
||||
@@ -76,6 +81,8 @@ class SfMaintenanceEquipment(models.Model):
|
||||
functional_tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search(
|
||||
[('rfid', '=', data['RfidCode'])])
|
||||
if functional_tool_id:
|
||||
if len(functional_tool_id) > 1:
|
||||
functional_tool_id = functional_tool_id[-1]
|
||||
# 查询该功能刀具是否已经装在机床内其他位置,如果是就删除
|
||||
equipment_tools = self.env['maintenance.equipment.tool'].sudo().search(
|
||||
[('functional_tool_name_id', '=', functional_tool_id.id), ('code', '!=', tool_id)])
|
||||
@@ -95,10 +102,10 @@ 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_id.name != '制造前':
|
||||
# 对功能刀具进行出库到生产线
|
||||
if functional_tool_id.current_location != '机内刀库':
|
||||
# 对功能刀具进行移动到生产线
|
||||
functional_tool_id.tool_inventory_displacement_out()
|
||||
functional_tool_id.write({
|
||||
'max_lifetime_value': data['MaxLife'],
|
||||
@@ -106,9 +113,11 @@ class SfMaintenanceEquipment(models.Model):
|
||||
'functional_tool_status': tool_install_time.get(data['State'])
|
||||
})
|
||||
else:
|
||||
raise ValidationError('获取的【%s】设备不存在!!!' % data['DeviceId'])
|
||||
logging.info('获取的【%s】设备不存在!!!' % data['DeviceId'])
|
||||
else:
|
||||
raise ValidationError('没有获取到刀具库信息!!!')
|
||||
logging.info('没有获取到【%s】设备的刀具库信息!!!' % self.name)
|
||||
except Exception as e:
|
||||
logging.info("write_maintenance_equipment_tool()捕获错误信息:%s" % e)
|
||||
|
||||
|
||||
class StockLot(models.Model):
|
||||
@@ -134,9 +143,6 @@ class StockLot(models.Model):
|
||||
record.tool_material_status = '报废'
|
||||
else:
|
||||
record.tool_material_status = '未入库'
|
||||
if record.fixture_material_search_id:
|
||||
# 注册夹具物料状态到cloud平台
|
||||
record.enroll_fixture_material_stock()
|
||||
|
||||
@api.model
|
||||
def name_search(self, name='', args=None, operator='ilike', limit=100):
|
||||
|
||||
23
sf_tool_management/models/stock.py
Normal file
23
sf_tool_management/models/stock.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
|
||||
class ShelfLocation(models.Model):
|
||||
_inherit = 'sf.shelf.location'
|
||||
|
||||
tool_rfid = fields.Char('Rfid', compute='_compute_tool', store=True)
|
||||
tool_name_id = fields.Many2one('sf.functional.cutting.tool.entity', string='功能刀具名称', compute='_compute_tool',
|
||||
store=True)
|
||||
|
||||
@api.depends('product_id')
|
||||
def _compute_tool(self):
|
||||
for item in self:
|
||||
if item.product_id:
|
||||
if item.product_id.categ_id.name == '功能刀具':
|
||||
tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search(
|
||||
[('barcode_id', '=', item.product_sn_id.id)])
|
||||
if tool_id:
|
||||
item.tool_rfid = tool_id.rfid
|
||||
item.tool_name_id = tool_id.id
|
||||
continue
|
||||
item.tool_rfid = ''
|
||||
item.tool_name_id = False
|
||||
@@ -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):
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<field name="name">sf.functional.cutting.tool.entity.list.tree</field>
|
||||
<field name="model">sf.functional.cutting.tool.entity</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具列表" create="0" edit="0" delete="0">
|
||||
<tree string="功能刀具" create="0" edit="0" delete="0">
|
||||
<field name="barcode_id" invisible="1"/>
|
||||
<field name="rfid"/>
|
||||
<field name="tool_name_id"/>
|
||||
@@ -19,15 +19,16 @@
|
||||
<field name="tool_loading_length" optional="hide"/>
|
||||
<field name="functional_tool_length" optional="hide"/>
|
||||
<field name="effective_length" optional="hide"/>
|
||||
<field name="tool_room_num"/>
|
||||
<field name="line_edge_knife_library_num"/>
|
||||
<field name="machine_knife_library_num"/>
|
||||
<field name="tool_room_num" optional="hide"/>
|
||||
<field name="line_edge_knife_library_num" optional="hide"/>
|
||||
<field name="machine_knife_library_num" optional="hide"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status"/>
|
||||
<field name="current_location" string="当前位置"/>
|
||||
|
||||
<field name="current_location_id" optional="hide"/>
|
||||
<field name="current_location_id" invisible="1"/>
|
||||
<field name="current_location" optional="hide"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
</tree>
|
||||
@@ -46,8 +47,8 @@
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<!-- <button name="button_safe_inventory_id" string="更新功能刀具关联的安全库存记录"-->
|
||||
<!-- type="object" class="btn-primary"/>-->
|
||||
<!-- <button name="button_safe_inventory_id" string="更新功能刀具关联的安全库存记录"-->
|
||||
<!-- type="object" class="btn-primary"/>-->
|
||||
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
|
||||
name="open_functional_tool_warning"
|
||||
icon="fa-list-ul"
|
||||
@@ -173,7 +174,10 @@
|
||||
<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" string="当前位置"/>
|
||||
<field name="current_shelf_location_id" string="当前货位"
|
||||
attrs="{'invisible': [('current_shelf_location_id', '=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
@@ -189,19 +193,34 @@
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="rfid"/>
|
||||
<field name="barcode_id"/>
|
||||
<field name="tool_name_id"/>
|
||||
<field name="functional_tool_diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<filter string="刀具房" name="tool_room" domain="[('current_location', '=', '刀具房')]"/>
|
||||
<filter string="线边刀库" name="storage_area" domain="[('current_location', '=', '线边刀库')]"/>
|
||||
<filter string="机内刀库" name="machine_knife_library"
|
||||
domain="[('current_location', '=', '机内刀库')]"/>
|
||||
<separator/>
|
||||
<filter string="正常" name="normal" domain="[('functional_tool_status', '=', '正常')]"/>
|
||||
<filter string="报警" name="alarm" domain="[('functional_tool_status', '=', '报警')]"/>
|
||||
<separator/>
|
||||
<filter string="未拆除" name="no_state_removed"
|
||||
domain="[('functional_tool_status', '!=', '已拆除')]"/>
|
||||
<filter string="已拆除" name="state_removed" domain="[('functional_tool_status', '=', '已拆除')]"/>
|
||||
<separator/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="sf_cutting_tool_type_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="current_location" icon="fa-building" enable_counters="1"/>
|
||||
<field name="functional_tool_status" icon="fa-building" enable_counters="1"/>
|
||||
<field name="sf_cutting_tool_type_id" icon="fa-building" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
<group expand="0">
|
||||
<filter string="功能刀具名称" name="tool_name" domain="[]"
|
||||
context="{'group_by': 'tool_name_id'}"/>
|
||||
<filter string="刀具组" name="tool_groups" domain="[]"
|
||||
context="{'group_by': 'tool_groups_id'}"/>
|
||||
<filter string="当前位置" name="current_location" domain="[]"
|
||||
context="{'group_by': 'current_location'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
@@ -297,11 +316,10 @@
|
||||
<tree>
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="functional_name_id"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="coarse_middle_thin"/>
|
||||
<field name="coarse_middle_thin" optional="hide"/>
|
||||
<field name="tool_stock_num"/>
|
||||
<field name="side_shelf_num"/>
|
||||
<field name="on_tool_stock_num"/>
|
||||
@@ -310,6 +328,8 @@
|
||||
<field name="max_stock_num"/>
|
||||
<field name="batch_replenishment_num"/>
|
||||
<field name="unit"/>
|
||||
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -425,21 +445,20 @@
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="sf_cutting_tool_type_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="tool_stock_num"/>
|
||||
<field name="side_shelf_num"/>
|
||||
<field name="on_tool_stock_num"/>
|
||||
<field name="tool_stock_total"/>
|
||||
<field name="min_stock_num"/>
|
||||
<field name="max_stock_num"/>
|
||||
<field name="batch_replenishment_num"/>
|
||||
<field name="unit"/>
|
||||
<filter string="需补货" name="batch_replenishment" domain="[('batch_replenishment_num', '>', 0)]"/>
|
||||
<separator/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="sf_cutting_tool_type_id" enable_counters="1" icon="fa-building"/>
|
||||
</searchpanel>
|
||||
<group expand="0">
|
||||
<filter string="刀具组" name="tool_groups" domain="[]"
|
||||
context="{'group_by': 'tool_groups_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
@@ -458,7 +477,8 @@
|
||||
<field name="name">功能刀具出入库记录</field>
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具出入库记录" create="0" edit="0" delete="0">
|
||||
<tree string="功能刀具出入库记录" create="0" edit="0" delete="0" default_order="id desc"
|
||||
action="action_open_reference1" type="object">
|
||||
<field name="reference" string="单据号"/>
|
||||
<field name="lot_id" invisible="1"/>
|
||||
<field name="rfid"/>
|
||||
@@ -468,7 +488,9 @@
|
||||
<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"/>
|
||||
@@ -483,21 +505,20 @@
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="reference"/>
|
||||
<field name="lot_id"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time"/>
|
||||
<field name="location_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="date"/>
|
||||
<field name="qty_done"/>
|
||||
<field name="functional_tool_type_id" invisible="True"/>
|
||||
<field name="reference"/>
|
||||
<field name="lot_id"/>
|
||||
<searchpanel>
|
||||
<field name="functional_tool_type_id" enable_counters="1" icon="fa-building"/>
|
||||
</searchpanel>
|
||||
<group expand="0">
|
||||
<filter string="功能刀具名称" name="functional_tool_name" domain="[]"
|
||||
context="{'group_by': 'functional_tool_name'}"/>
|
||||
<filter string="日期" name="date" domain="[]" context="{'group_by': 'date'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
@@ -511,7 +532,7 @@
|
||||
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_tree"/>
|
||||
<field name="search_view_id"
|
||||
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_search"/>
|
||||
<field name="domain">[('functional_tool_name_id', '!=', False)]</field>
|
||||
<field name="domain">[('rfid', '!=', ''),('functional_tool_name', '!=', '')]</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
14
sf_tool_management/views/stock.xml
Normal file
14
sf_tool_management/views/stock.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="view_shelf_location_tool" model="ir.ui.view">
|
||||
<field name="name">sf.shelf.location.form.tool</field>
|
||||
<field name="model">sf.shelf.location</field>
|
||||
<field name="inherit_id" ref="sf_warehouse.view_shelf_location_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='product_id']" position="after">
|
||||
<field name="tool_rfid" attrs="{'invisible': [('tool_name_id', '=', False)]}"/>
|
||||
<field name="tool_name_id" attrs="{'invisible': [('tool_name_id', '=', False)]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -434,17 +434,17 @@
|
||||
<field name="code" optional="hide"/>
|
||||
<field name="functional_tool_name"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="functional_tool_diameter" string="刀具直径"/>
|
||||
<field name="functional_tool_diameter" string="刀具直径(mm)"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="coarse_middle_thin" optional="hide"/>
|
||||
<field name="new_former" optional="hide"/>
|
||||
<field name="tool_loading_length" optional="hide"/>
|
||||
<field name="functional_tool_length" optional="hide"/>
|
||||
<field name="effective_length" optional="hide"/>
|
||||
<field name="effective_length" invisible="1"/>
|
||||
<field name="loading_task_source" string="任务来源"/>
|
||||
<field name="use_tool_time"/>
|
||||
<field name="production_line_name_id"/>
|
||||
<field name="machine_tool_name_id"/>
|
||||
<field name="production_line_name_id" optional="hide"/>
|
||||
<field name="machine_tool_name_id" optional="hide"/>
|
||||
<field name="applicant"/>
|
||||
<field name="apply_time"/>
|
||||
<field name="assemble_status" optional="hide"/>
|
||||
@@ -693,30 +693,29 @@
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="assembly_order_code"/>
|
||||
<field name="barcode_id" optional="hide"/>
|
||||
<field name="code" string="功能刀具编码"/>
|
||||
<field name="barcode_id"/>
|
||||
<field name="functional_tool_name"/>
|
||||
<field name="functional_tool_diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="coarse_middle_thin"/>
|
||||
<field name="new_former"/>
|
||||
<field name="tool_loading_length"/>
|
||||
<field name="functional_tool_length"/>
|
||||
<field name="effective_length"/>
|
||||
<field name="functional_tool_type_id"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="loading_task_source" string="任务来源"/>
|
||||
<field name="use_tool_time"/>
|
||||
<field name="production_line_name_id"/>
|
||||
<field name="machine_tool_name_id"/>
|
||||
<field name="applicant"/>
|
||||
<field name="apply_time"/>
|
||||
<field name="functional_tool_type_id"/>
|
||||
<filter name="no_assemble_status" string="未组装" domain="[('assemble_status', '=', '0')]"/>
|
||||
<filter name="yes_assemble_status" string="已组装" domain="[('assemble_status', '=', '1')]"/>
|
||||
<separator/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="functional_tool_type_id" enable_counters="1" icon="fa-filter"/>
|
||||
<!-- <field name="assemble_status" enable_counters="1" icon="fa-filter"/>-->
|
||||
</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'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
<tree>
|
||||
<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>
|
||||
|
||||
@@ -854,10 +854,10 @@ class ProductProduct(models.Model):
|
||||
'company_id': self.env.company.id
|
||||
})
|
||||
# 获取位置对象
|
||||
location_inventory_id = self.env['stock.location'].search([('name', '=', 'Production')])
|
||||
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_id, stock_location_id, functional_tool_assembly.id,
|
||||
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
|
||||
|
||||
@@ -557,8 +557,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 +624,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 +858,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 +873,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:
|
||||
@@ -933,14 +942,36 @@ class SfStockPicking(models.Model):
|
||||
|
||||
check_in = fields.Char(string='查询是否为入库单', compute='_check_is_in')
|
||||
|
||||
def batch_stock_move(self):
|
||||
"""
|
||||
批量调拨,非就绪状态的会被忽略,完成后有通知提示
|
||||
"""
|
||||
for record in self:
|
||||
if record.state != 'assigned':
|
||||
continue
|
||||
record.action_set_quantities_to_reservation()
|
||||
record.button_validate()
|
||||
|
||||
notification_message = '批量调拨完成!请注意,状态非就绪的单据会被忽略'
|
||||
return {
|
||||
'effect': {
|
||||
'fadeout': 'fast',
|
||||
'message': notification_message,
|
||||
'img_url': '/web/image/%s/%s/image_1024' % (
|
||||
self.create_uid._name, self.create_uid.id) if 0 else '/web/static/img/smile.svg',
|
||||
'type': 'rainbow_man',
|
||||
}
|
||||
}
|
||||
|
||||
@api.depends('name')
|
||||
def _check_is_in(self):
|
||||
"""
|
||||
判断是否为出库单
|
||||
"""
|
||||
if self.name:
|
||||
is_check_in = self.name.split('/')
|
||||
self.check_in = is_check_in[1]
|
||||
for record in self:
|
||||
if record.name:
|
||||
is_check_in = record.name.split('/')
|
||||
record.check_in = is_check_in[1]
|
||||
|
||||
def button_validate(self):
|
||||
"""
|
||||
@@ -953,15 +984,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:
|
||||
@@ -1088,6 +1130,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:
|
||||
@@ -1099,7 +1142,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:
|
||||
@@ -1108,7 +1153,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:
|
||||
@@ -1121,7 +1168,10 @@ class CustomStockMove(models.Model):
|
||||
move_lines = self.move_line_ids # 获取当前 stock.move 对应的所有 stock.move.line 记录
|
||||
for line in move_lines:
|
||||
if line.lot_name: # 确保 lot_name 存在
|
||||
qr_data = self.compute_lot_qr_code(line.lot_name)
|
||||
lot_name = line.lot_name
|
||||
if line.product_id.categ_id.name == '坯料':
|
||||
lot_name = lot_name.split('[', 1)[0]
|
||||
qr_data = self.compute_lot_qr_code(lot_name)
|
||||
# 假设 stock.move.line 模型中有一个字段叫做 lot_qr_code 用于存储二维码数据
|
||||
line.lot_qr_code = qr_data
|
||||
return result
|
||||
@@ -1159,6 +1209,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 # 可以根据实际情况修改
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class MrsShelfLocationDataSync(models.Model):
|
||||
paired_data = list(zip(my_data, their_data))
|
||||
return paired_data
|
||||
|
||||
shelf_1_obj = self.env['sf.shelf'].search([('name', '=', '一号线边刀架')], limit=1)
|
||||
shelf_1_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-一号线边刀架')], limit=1)
|
||||
tool_location_objs_1 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_1_obj.id)], order='id')
|
||||
|
||||
location_codes_1 = [location.barcode for location in tool_location_objs_1]
|
||||
@@ -32,7 +32,7 @@ class MrsShelfLocationDataSync(models.Model):
|
||||
aligned_data_1 = align_data(location_codes_1, their_data_1)
|
||||
|
||||
# 2
|
||||
shelf_2_obj = self.env['sf.shelf'].search([('name', '=', '二号线边刀架')], limit=1)
|
||||
shelf_2_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-二号线边刀架')], limit=1)
|
||||
tool_location_objs_2 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_2_obj.id)], order='id')
|
||||
|
||||
location_codes_2 = [location.barcode for location in tool_location_objs_2]
|
||||
@@ -44,7 +44,7 @@ class MrsShelfLocationDataSync(models.Model):
|
||||
aligned_data_2 = align_data(location_codes_2, their_data_2)
|
||||
|
||||
# 4
|
||||
shelf_4_obj = self.env['sf.shelf'].search([('name', '=', '一号线边料架')], limit=1)
|
||||
shelf_4_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-一号线边料架')], limit=1)
|
||||
tool_location_objs_4 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_4_obj.id)], order='id')
|
||||
|
||||
location_codes_4 = [location.barcode for location in tool_location_objs_4]
|
||||
@@ -56,7 +56,7 @@ class MrsShelfLocationDataSync(models.Model):
|
||||
aligned_data_4 = align_data(location_codes_4, their_data_4)
|
||||
|
||||
# 3
|
||||
shelf_3_obj = self.env['sf.shelf'].search([('name', '=', '一号线边料架')], limit=1)
|
||||
shelf_3_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-二号线边料架')], limit=1)
|
||||
tool_location_objs_3 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_3_obj.id)], order='id')
|
||||
|
||||
location_codes_3 = [location.barcode for location in tool_location_objs_3]
|
||||
@@ -68,7 +68,7 @@ class MrsShelfLocationDataSync(models.Model):
|
||||
aligned_data_3 = align_data(location_codes_3, their_data_3)
|
||||
|
||||
# 5
|
||||
shelf_5_obj = self.env['sf.shelf'].search([('name', '=', '一号线边料架')], limit=1)
|
||||
shelf_5_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-三号线边料架')], limit=1)
|
||||
tool_location_objs_5 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_5_obj.id)], order='id')
|
||||
|
||||
location_codes_5 = [location.barcode for location in tool_location_objs_5]
|
||||
@@ -95,12 +95,29 @@ class MrsShelfLocationDataSync(models.Model):
|
||||
return code_pair[0]
|
||||
return None # 如果没有找到对应的值,返回None或适当的默认值
|
||||
|
||||
# 定时更新所有设备机床刀库信息
|
||||
equipment_ids = self.env['maintenance.equipment'].search(
|
||||
[('equipment_type', '=', '机床'), ('function_type', '!=', False)])
|
||||
for equipment_id in equipment_ids:
|
||||
if equipment_id:
|
||||
equipment_id.register_equipment_tool()
|
||||
|
||||
shelfinfo = self.env['sf.shelf.location'].get_sf_shelf_location_info()
|
||||
print('shelfinfo:', shelfinfo)
|
||||
for item in shelfinfo:
|
||||
shelf_barcode = find_our_code(item['Postion'], total_data)
|
||||
location_id = self.env['sf.shelf.location'].search([('barcode', '=', shelf_barcode)], limit=1)
|
||||
if location_id:
|
||||
# 如果是线边刀库信息,则对功能刀具移动生成记录
|
||||
if 'Tool' in item['Postion']:
|
||||
tool = self.env['sf.functional.cutting.tool.entity'].sudo().search(
|
||||
[('rfid', '=', item['RfidCode']), ('functional_tool_status', '!=', '已拆除')])
|
||||
tool.tool_in_out_stock_location(location_id)
|
||||
if tool:
|
||||
location_id.product_sn_id = tool.barcode_id.id
|
||||
else:
|
||||
location_id.product_sn_id = False
|
||||
else:
|
||||
stock_lot_obj = self.env['stock.lot'].search([('rfid', '=', item['RfidCode'])], limit=1)
|
||||
if stock_lot_obj:
|
||||
location_id.product_sn_id = stock_lot_obj.id
|
||||
|
||||
@@ -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">
|
||||
@@ -149,6 +152,9 @@
|
||||
<button name="action_assign" type="object" string="检查可用量"
|
||||
groups="sf_base.group_sf_stock_user"/>
|
||||
</xpath>
|
||||
<xpath expr="//header" position="inside">
|
||||
<button name="batch_stock_move" type='object' string="批量调拨"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -592,8 +592,23 @@ var GanttRow = Widget.extend({
|
||||
});
|
||||
pill.decorations = pillDecorations;
|
||||
|
||||
if (self.colorField) {
|
||||
pill._color = self._getColor(pill[self.colorField]);
|
||||
// let isDelay = false
|
||||
// if(pill.state != 'processing' && pill.state != 'finished') { // 判断待加工
|
||||
// isDelay = pill.order_deadline.isBefore(new Date())
|
||||
// }
|
||||
pill.exState = ''
|
||||
if (self.colorField){
|
||||
// console.log(self.colorField, self, pill, '颜色')
|
||||
// pill._color = self._getColor(pill[self.colorField]);
|
||||
// 设置pill背景颜色2 修改时间2024年6月25日17:09:43
|
||||
let isDelay = false
|
||||
if(pill.state != 'processing' && pill.state != 'finished') { // 判断待加工
|
||||
isDelay = pill.order_deadline.isBefore(new Date())
|
||||
}
|
||||
if(isDelay) {
|
||||
pill.disableDragdrop = true
|
||||
}
|
||||
pill._color = self._getColor2(isDelay ? 'delay' : pill.state);
|
||||
}
|
||||
|
||||
if (self.progressField) {
|
||||
@@ -613,6 +628,13 @@ var GanttRow = Widget.extend({
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
_getColor2 (state) {
|
||||
return {
|
||||
'finished': 'ccc',
|
||||
'delay': 9,
|
||||
'processing': 13 // 绿色
|
||||
}[state]
|
||||
},
|
||||
/**
|
||||
* Get context to evaluate decoration
|
||||
*
|
||||
@@ -867,10 +889,11 @@ var GanttRow = Widget.extend({
|
||||
if ($pill.hasClass('ui-draggable-dragging')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var pill = _.findWhere(this.pills, { id: $pill.data('id') });
|
||||
|
||||
if(pill.state == 'finished'){ // 已完成状态不能拖拽
|
||||
return;
|
||||
}
|
||||
// DRAGGABLE
|
||||
if (this.options.canEdit && !pill.disableStartResize && !pill.disableStopResize && !this.isGroup) {
|
||||
|
||||
|
||||
@@ -754,3 +754,7 @@
|
||||
left: -0.5 * $o-connector-creator-bullet-diameter;
|
||||
}
|
||||
}
|
||||
|
||||
.o_gantt_view .o_gantt_row_nogroup .o_gantt_pill.o_gantt_color_ccc {
|
||||
background-color: #ccc;
|
||||
}
|
||||
Reference in New Issue
Block a user