Compare commits

..

3 Commits

240 changed files with 79172 additions and 26295 deletions

View File

@@ -5,7 +5,7 @@ import {patch} from '@web/core/utils/patch';
import {_t} from "@web/core/l10n/translation"; import {_t} from "@web/core/l10n/translation";
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator"; import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
import {ListRenderer} from "@web/views/list/list_renderer"; import {ListRenderer} from "@web/views/list/list_renderer";
// import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field"; import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field";
import {Field} from "@web/views/fields/field"; import {Field} from "@web/views/fields/field";
@@ -153,34 +153,34 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
// 根据进度条设置水印 // 根据进度条设置水印
// const statusbar_params = { const statusbar_params = {
// '已完工': 'bg-primary', '已完工': 'bg-primary',
// '完成': 'bg-primary', '完成': 'bg-primary',
// '采购订单': 'bg-primary', '采购订单': 'bg-primary',
// '作废': 'bg-danger', '作废': 'bg-danger',
// '封存(报废)': 'bg-danger', '封存(报废)': 'bg-danger',
// } }
// patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', { patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', {
// setup() { setup() {
// owl.onMounted(this.ribbons); owl.onMounted(this.ribbons);
// return this._super(...arguments); return this._super(...arguments);
// }, },
// ribbons() { ribbons() {
// try { try {
// const dom = $('.o_form_sheet.position-relative') const dom = $('.o_form_sheet.position-relative')
// const status = statusbar_params[this.currentName] const status = statusbar_params[this.currentName]
// if(status && dom.length) { if(status && dom.length) {
// dom.prepend(`<div class="o_widget o_widget_web_ribbon"> dom.prepend(`<div class="o_widget o_widget_web_ribbon">
// <div class="ribbon ribbon-top-right"> <div class="ribbon ribbon-top-right">
// <span class="bg-opacity-75 ${status}" title="">${this.currentName}</span> <span class="bg-opacity-75 ${status}" title="">${this.currentName}</span>
// </div> </div>
// </div>`) </div>`)
// } }
// } catch (e) { } catch (e) {
// console.log(e) console.log(e)
// } }
// } }
// }) })
$(function () { $(function () {
document.addEventListener('click', function () { document.addEventListener('click', function () {

View File

@@ -527,8 +527,3 @@ div:has(.o_required_modifier) > label::before {
.o_form_view .o_group .o_wrap_label .o_form_label { .o_form_view .o_group .o_wrap_label .o_form_label {
white-space: nowrap; white-space: nowrap;
} }
// 修复表格内容覆盖表头bug
.o_list_renderer .o_list_table tbody th {
position: unset;
}

View File

@@ -301,25 +301,51 @@ def unlink(self):
# This is used to restrict the access right to unlink a record # This is used to restrict the access right to unlink a record
current_model_id = self.env['ir.model'].sudo().search( current_model_id = self.env['ir.model'].sudo().search(
[('model', '=', self._name)]).id [('model', '=', self._name)]).id
access_right_rec = self.env['access.right'].sudo().search_read( # access_right_rec = self.env['access.right'].sudo().search_read(
[('model_id', '=', current_model_id)], ['model_id', 'is_delete', # [('model_id', '=', current_model_id)], ['model_id', 'is_delete',
'groups_id']) # 'groups_id'])
if access_right_rec and not self.env.is_admin(): # if access_right_rec and not self.env.is_admin():
for rec in access_right_rec: # for rec in access_right_rec:
group_name = self.env['ir.model.data'].sudo().search([ # group_name = self.env['ir.model.data'].sudo().search([
('model', '=', 'res.groups'), # ('model', '=', 'res.groups'),
('res_id', '=', rec['groups_id'][0]) # ('res_id', '=', rec['groups_id'][0])
]).name # ]).name
module_name = self.env['ir.model.data'].sudo().search([ # module_name = self.env['ir.model.data'].sudo().search([
('model', '=', 'res.groups'), # ('model', '=', 'res.groups'),
('res_id', '=', rec['groups_id'][0]) # ('res_id', '=', rec['groups_id'][0])
]).module # ]).module
group = module_name + "." + group_name # group = module_name + "." + group_name
if self.env.user.has_group(group): # if self.env.user.has_group(group):
if rec['is_delete']: # if rec['is_delete']:
raise UserError(_('You are restricted from performing this' # raise UserError(_('You are restricted from performing this'
' operation. Please contact the' # ' operation. Please contact the'
' administrator.')) # ' administrator.'))
# 检查 'access.right' 模型是否存在于环境中
if 'access.right' in self.env:
# current_model_id = self.env['ir.model'].sudo().search([('model', '=', self._name)]).id
access_right_rec = self.env['access.right'].sudo().search_read(
[('model_id', '=', current_model_id)], ['model_id', 'is_delete', 'groups_id']
)
if access_right_rec and not self.env.is_admin():
for rec in access_right_rec:
group_data = self.env['ir.model.data'].sudo().search_read(
[('model', '=', 'res.groups'), ('res_id', '=', rec['groups_id'][0])],
['name', 'module']
)
if group_data:
group_name = group_data[0]['name']
module_name = group_data[0]['module']
group_xml_id = f"{module_name}.{group_name}"
if self.env.user.has_group(group_xml_id) and rec['is_delete']:
raise UserError(
_('You are restricted from performing this operation. Please contact the administrator.'))
else:
# 如果 'access.right' 模型不存在,可以在这里定义备选逻辑
pass
return True return True

View File

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

View File

@@ -1,39 +0,0 @@
# -*- coding: utf-8 -*-
{
'name': "jikimo_system_order",
'summary': """
系统工单""",
'description': """
用于处理针对系统的工作任务;
员工可以通过系统工单发起申请,由维护人员处理以后,填写处理结果。
""",
'author': "机企猫",
'website': "http://www.jikimo.com",
# Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/master/odoo/addons/base/module/module_data.xml
# for the full list
'category': 'Uncategorized',
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['base','mail'],
# always loaded
'data': [
'security/account_security.xml',
'security/ir.model.access.csv',
'wizard/order_wizard.xml',
'views/notice_user_config.xml',
'views/yizuo_system_order_view.xml',
'views/work_order_number.xml',
'views/res_config_settings_views.xml',
],
# only loaded in demonstration mode
'demo': [
'demo/demo.xml',
],
}

View File

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

View File

@@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import http
# class TopSystemOrder(http.Controller):
# @http.route('/jikimo_system_order/jikimo_system_order/', auth='public')
# def index(self, **kw):
# return "Hello, world"
# @http.route('/jikimo_system_order/jikimo_system_order/objects/', auth='public')
# def list(self, **kw):
# return http.request.render('jikimo_system_order.listing', {
# 'root': '/jikimo_system_order/jikimo_system_order',
# 'objects': http.request.env['jikimo_system_order.jikimo_system_order'].search([]),
# })
# @http.route('/jikimo_system_order/jikimo_system_order/objects/<model("jikimo_system_order.jikimo_system_order"):obj>/', auth='public')
# def object(self, obj, **kw):
# return http.request.render('jikimo_system_order.object', {
# 'object': obj
# })

View File

@@ -1,30 +0,0 @@
<odoo>
<data>
<!-- -->
<!-- <record id="object0" model="jikimo_system_order.jikimo_system_order"> -->
<!-- <field name="name">Object 0</field> -->
<!-- <field name="value">0</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object1" model="jikimo_system_order.jikimo_system_order"> -->
<!-- <field name="name">Object 1</field> -->
<!-- <field name="value">10</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object2" model="jikimo_system_order.jikimo_system_order"> -->
<!-- <field name="name">Object 2</field> -->
<!-- <field name="value">20</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object3" model="jikimo_system_order.jikimo_system_order"> -->
<!-- <field name="name">Object 3</field> -->
<!-- <field name="value">30</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object4" model="jikimo_system_order.jikimo_system_order"> -->
<!-- <field name="name">Object 4</field> -->
<!-- <field name="value">40</field> -->
<!-- </record> -->
<!-- -->
</data>
</odoo>

View File

@@ -1,7 +0,0 @@
# -*- coding: utf-8 -*-
from . import constant
from . import order_classify
from . import system_work_order
from . import work_order_template
from . import res_config_setting

View File

@@ -1,7 +0,0 @@
# -*- coding: utf-8 -*-
# 工单状态
STATE_SELECTION = [('draft', u'草稿'), ('unconfirmed', u'待确认'), ('pending', u'待处理'),
('processed', u'已处理待评分'), ('completed', u'已完成'), ('closed', u'已关闭')]
GRADE = [('1', '1非常不满意'), ('2', '2不满意'), ('3', '3一般'), ('4', '4满意'), ('5', '5非常满意')]

View File

@@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
from odoo.exceptions import ValidationError
class OrderClassify(models.Model):
_name = 'order.classify'
_order = 'sequence, name'
@api.constrains('name')
def check_base_name(self):
"""类型名称唯一"""
name_obj = self.env['order.classify'].search([('name', '=', self.name)])
if len(name_obj) >= 2:
raise ValidationError(u'该类型已存在')
# 名称
name = fields.Char(string=u'名称', size=20)
# 排序
sequence = fields.Integer(default=10)
# 是否有效
state = fields.Boolean(default=True, string='是否有效')

View File

@@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
import logging
from odoo import api, fields, models, _
_logger = logging.getLogger(__name__)
class ResModelWeConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
lost_agent_id = fields.Char('企微通知应用ID')
@api.model
def get_values(self):
"""
重载获取参数的方法,参数都存在系统参数中
:return:
"""
values = super(ResModelWeConfigSettings, self).get_values()
config = self.env['ir.config_parameter'].sudo()
lost_agent_id = config.get_param('lost_agent_id', default='')
values.update(
lost_agent_id=lost_agent_id,
)
return values
def set_values(self):
super(ResModelWeConfigSettings, self).set_values()
ir_config = self.env['ir.config_parameter'].sudo()
ir_config.set_param("lost_agent_id", self.lost_agent_id or "")

View File

@@ -1,183 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
from odoo.exceptions import ValidationError
from odoo import exceptions
from .constant import STATE_SELECTION, GRADE
import datetime
import logging
class SystemWorkOrder(models.Model):
_name = 'system.work.order'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'date desc'
_description = u'系统工单'
_rec_name = 'order_number'
def get_is_technicist(self):
self._cr.execute(
"select u.id from res_users u left join res_groups_users_rel r on r.uid = u.id where r.gid in (select g.id from res_groups g where g.name = '技术员权限') and u.id ='%s'",
(self.env.user.id,))
hr = self._cr.dictfetchall()
if len(hr) > 0:
return True
else:
return False
# def get_user_department_id(self):
# """根据用户id系统员工id"""
# employee = self.env['hr.employee'].sudo().search([('user_id', '=', self.env.uid)], limit=1)
# if employee:
# if len(employee) > 0:
# if not employee.department_id:
# raise exceptions.Warning(u'您当前使用的用户没有所属部门')
# return employee.department_id
# else:
# return False
# else:
# raise exceptions.Warning(u'您当前使用的用户没有关联员工')
@api.onchange('order_template_id')
def get_title(self):
"""选择模板自动填充"""
if self.order_template_id:
self.title = self.order_template_id.title_template
self.text = self.order_template_id.text_template
# 工单编号
order_number = fields.Char(string=u'工单编号', default='/')
# 紧急程度
urgency_degree = fields.Selection([('0', u'0星'), ('1', u'一星'), ('2', u'二星'), ('3', u'三星'), ('4', u'四星'),
('5', u'五星')], string=u'紧急程度', help='五星为最紧急!', default='5')
# 工单分类(可以配置,并调整优先级)
order_type = fields.Many2one('order.classify', string=u'工单分类', domain=[('state', '=', True)])
# 发起人所属公司(res.company)
initiator_company_id = fields.Many2one('res.company', string=u'发起人所属公司', default=lambda self: self.env.user.company_id)
# 发起人部门(hr.department)
# initiator_department_id = fields.Many2one('hr.department', string=u'发起人部门', default=get_user_department_id)
# 发起人(hr.employee)
initiator_id = fields.Many2one('res.users', string=u'发起人', default=lambda self: self.env.user)
# 发起时间
date = fields.Datetime(string=u'发起时间', default=lambda self: fields.datetime.now())
# 确认人
confirm_id = fields.Many2one('res.users', string=u'确认人')
# 确认日期
confirmation_date = fields.Datetime(string=u'确认时间')
# 模板
order_template_id = fields.Many2one('work.order.template', string=u'模板', domain=[('state', '=', True)])
# 标题
title = fields.Char(string=u'标题')
# 正文
text = fields.Html(string=u'正文')
# 状态[草稿\待确认\待处理\已处理\已关闭]
state = fields.Selection(STATE_SELECTION, default='draft', string=u'状态')
# 关闭原因
close_cause = fields.Text(string=u'关闭问题原因')
# 关闭时间
close_time = fields.Datetime(string=u'关闭问题时间')
# 关闭人
close_user_id = fields.Many2one('res.users', string=u'关闭人')
# 解决人
solve_people_id = fields.Many2one('res.users', string=u'解决人')
# 用户实际问题
users_problem = fields.Text(string=u'用户实际问题')
# 最终解决方案
solution = fields.Text(string=u'最终解决方案')
# 判断是否为技术人员
# is_technicist = fields.Boolean(string=u'是否为技术人员', default=get_is_technicist)
# 打分
grade = fields.Selection(GRADE, string=u'评分')
# 评价按钮的显示
is_display = fields.Boolean('控制显示评价按钮', compute='compute_is_display')
def compute_is_display(self):
for item in self:
if item.state == 'processed' and self.env.user.id == item.initiator_id.id:
item.is_display = True
else:
item.is_display = False
@api.onchange('order_type')
def _onchange_order_type(self):
self.order_template_id = None
self.title = None
self.text = None
@api.model
def create(self, vals):
# 创建编号
if vals.get('order_number', '/') == '/':
vals['order_number'] = self.env['ir.sequence'].get('system.work.order') or '/'
return super(SystemWorkOrder, self).create(vals)
def do_draft(self, order=None):
"""状态草稿"""
bill = self
if order:
bill = order
if bill.state == 'unconfirmed':
state_remark = u'待确认 --> 草稿'
# bill.message_post(u'操作人:%s操作时间%s状态变更过程%s' % (self.env.user.name,
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
bill.state = 'draft'
def do_unconfirmed(self):
"""状态待确认"""
if self.state == 'draft':
state_remark = u'草稿 --> 待确认'
# self.message_post(u'操作人:%s操作时间%s状态变更过程%s' % (
# self.env.user.name,
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
self.state = 'unconfirmed'
# 获取通知人
objs = self.env['system.order.notice'].search([])
user_ids = objs.notice_user_ids.filtered(lambda item: item.we_employee_id not in ['', False])
we_employee_ids = user_ids.mapped('we_employee_id')
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
# agent_id, user_ids, content
content = """您有一张工单<font color=\"warning\">待处理</font>:**工单标题:{2}**
>创建人:{1}
>提交时间:{3}
>紧急程度:{0}
请查看工单消息,并及时处理!
""".format(self.urgency_degree,
self.initiator_id.name, self.title, (self.date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'))
for we_employee_id in we_employee_ids:
try:
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
except Exception as e:
logging.error('工单处理发送消息异常%s' % str(e))
return True
def do_pending(self):
"""状态待处理"""
if self.state == 'unconfirmed':
state_remark = u'待确认 --> 待处理'
# self.message_post(u'操作人:%s操作时间%s状态变更过程%s' % (
# self.env.user.name,
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
self.state = 'pending'
self.confirm_id = self.env.user
self.confirmation_date = fields.datetime.now()
return True
def urned_off(self):
"""状态关闭"""
if self.close_cause:
self.state = 'closed'
self.close_time = fields.datetime.now()
else:
raise ValidationError(u'请注明关闭原因')
return True
def unlink(self):
for item in self:
if item.state != "draft":
raise ValidationError(u'只能删除状态为【草稿】的工单。')
elif item.env.uid != item.initiator_id.id:
raise ValidationError(u'非本人不能删除')
else:
super(SystemWorkOrder, item).unlink()

View File

@@ -1,38 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class WorkOrderTemplate(models.Model):
_name = 'work.order.template'
_order = 'num'
# 编号
num = fields.Char(string=u'编号', default='/')
# 名称
name = fields.Char(string=u'模板名称', required="1")
# 分类
work_order_type = fields.Many2one('order.classify', string=u'系统工单分类', domain=[('state', '=', True)])
# 模板标题
title_template = fields.Char(string=u'模板标题')
# 模板正文
text_template = fields.Html(string=u'模板正文')
# 模板说明
template_explain = fields.Text(string=u'模板说明')
# 是否有效
state = fields.Boolean(default=True, string=u'是否有效')
@api.model
def create(self, vals):
# 创建编号
if vals.get('num', '/') == '/':
vals['num'] = self.env['ir.sequence'].get('work.order.template') or '/'
return super(WorkOrderTemplate, self).create(vals)
class SystemOrderNotice(models.Model):
_name = 'system.order.notice'
_description = '工单处理人设置'
notice_user_ids = fields.Many2many('res.users', string='工单处理人')

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="0"> <!-- noupdate表示当模块升级时是否更新本条数据-->
<!--运维权限组-->
<record id="group_operations_permissions_rwc" model="res.groups">
<field name="name">运维权限</field>
</record>
<record id="system_order_user_rule" model="ir.rule">
<field name="name">用户访问工单信息</field>
<field name="model_id" ref="model_system_work_order"/>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
<field name="domain_force">[('initiator_id', '=', user.id)]</field>
</record>
<record id="system_order_group_operations_rule" model="ir.rule">
<field name="name">运维访问工单信息</field>
<field name="model_id" ref="model_system_work_order"/>
<field name="groups" eval="[(4, ref('jikimo_system_order.group_operations_permissions_rwc'))]"/>
<field name="domain_force">[(1, '=', 1)]</field>
</record>
</data>
</odoo>

View File

@@ -1,16 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
inside_system_order_classify_r,jikimo_system_order.order_classify,model_order_classify,,1,1,1,1
inside_system_work_order_rc,jikimo_system_order.system_work_order,model_system_work_order,,1,1,1,1
inside_work_order_template_r,jikimo_system_order.work_order_template,model_work_order_template,,1,1,1,1
inside_system_order_classify_rwc,jikimo_system_order.order_classify,model_order_classify,group_operations_permissions_rwc,1,1,1,0
inside_system_work_order_rwc,jikimo_system_order.system_work_order,model_system_work_order,group_operations_permissions_rwc,1,1,1,0
inside_work_order_template_rwc,jikimo_system_order.work_order_template,model_work_order_template,group_operations_permissions_rwc,1,1,1,0
order_close_wizard_group_user,jikimo_system_order.order_close_wizard,model_order_close_wizard,base.group_user,1,1,1,1
order_other_wizard_group_user,jikimo_system_order.order_other_wizard,model_order_other_wizard,base.group_user,1,1,1,1
order_technician_wizard_group_user,jikimo_system_order.order_technician_wizard,model_order_technician_wizard,base.group_user,1,1,1,1
system_work_order_wizard_group_user,jikimo_system_order.system_work_order_wizard,model_system_work_order_wizard,base.group_user,1,1,1,1
system_order_notice_group_user,jikimo_system_order.system_order_notice,model_system_order_notice,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 inside_system_order_classify_r jikimo_system_order.order_classify model_order_classify 1 1 1 1
3 inside_system_work_order_rc jikimo_system_order.system_work_order model_system_work_order 1 1 1 1
4 inside_work_order_template_r jikimo_system_order.work_order_template model_work_order_template 1 1 1 1
5 inside_system_order_classify_rwc jikimo_system_order.order_classify model_order_classify group_operations_permissions_rwc 1 1 1 0
6 inside_system_work_order_rwc jikimo_system_order.system_work_order model_system_work_order group_operations_permissions_rwc 1 1 1 0
7 inside_work_order_template_rwc jikimo_system_order.work_order_template model_work_order_template group_operations_permissions_rwc 1 1 1 0
8 order_close_wizard_group_user jikimo_system_order.order_close_wizard model_order_close_wizard base.group_user 1 1 1 1
9 order_other_wizard_group_user jikimo_system_order.order_other_wizard model_order_other_wizard base.group_user 1 1 1 1
10 order_technician_wizard_group_user jikimo_system_order.order_technician_wizard model_order_technician_wizard base.group_user 1 1 1 1
11 system_work_order_wizard_group_user jikimo_system_order.system_work_order_wizard model_system_work_order_wizard base.group_user 1 1 1 1
12 system_order_notice_group_user jikimo_system_order.system_order_notice model_system_order_notice base.group_user 1 1 1 1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
# ---------- 工单通知处理人设置 ------------
<record model="ir.ui.view" id="tree_system_order_notice_view">
<field name="name">tree.system.order.notice</field>
<field name="model">system.order.notice</field>
<field name="arch" type="xml">
<tree string="工单处理人设置" editable="top">
<field name="notice_user_ids" widget="many2many_tags" required="1" options="{'no_create': True, 'no_edit': True}"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="search_system_order_notice_view">
<field name="name">search.system.order.notice</field>
<field name="model">system.order.notice</field>
<field name="arch" type="xml">
<search string="工单处理人设置">
<field name="notice_user_ids" string="模糊搜索"
filter_domain="[('notice_user_ids', 'ilike', self)]"/>
<separator></separator>
<field name="notice_user_ids" string="处理人"/>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_system_order_notice_view">
<field name="name">工单处理人</field>
<field name="res_model">system.order.notice</field>
<field name="view_mode">tree</field>
<field name="domain">[]</field>
<field name="context">{}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
[工单处理人] 还没有哦!点左上角的[创建]按钮,沙发归你了!
</p>
<p>
</p>
</field>
</record>
</data>
</odoo>

View File

@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="res_config_settings_we_view_form_inherit" model="ir.ui.view">
<field name="name">res.config.settings.we.view.form.inherit.bpm</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('app_settings_block')]/div[6]" position="after">
<div>
<h2>企微通知应用ID</h2>
<div class="row mt16 o_settings_container" id="jd_api">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<div class="text-muted">
<label for="lost_agent_id"/>
<field name="lost_agent_id"/>
</div>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="True">
<!-- 工单流水号 -->
<record id="seq_work_order" model="ir.sequence">
<field name="name">seq_work_order</field>
<field name="company_id"/>
<field name="code">system.work.order</field>
<field name="prefix">SO%(year)s%(month)s%(day)s</field>
<field name="padding">1</field>
</record>
<!-- 模板编号 -->
<record id="seq_order_template" model="ir.sequence">
<field name="name">seq_order_template</field>
<field name="company_id"/>
<field name="code">work.order.template</field>
<field name="prefix">TL</field>
<field name="padding">1</field>
</record>
</data>
</odoo>

View File

@@ -1,243 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!--工单信息-->
<record model="ir.ui.view" id="work_order_tree">
<field name="name">工单信息</field>
<field name="model">system.work.order</field><!--对应表单名称-->
<field name="arch" type="xml">
<tree>
<field name="state" widget="badge" decoration-primary="state == 'draft'"
decoration-success="state in ('processed', 'completed')"
decoration-danger="state == 'pending'" decoration-warning="state in ('unconfirmed')"/>
<field name="order_number"/>
<field name="title"/>
<field name="initiator_id"/>
<field name="date"/>
</tree>
</field>
</record>
<!--新建系统工单-->
<record model="ir.ui.view" id="ork_order_form">
<field name="name">新建系统工单</field>
<field name="model">system.work.order</field>
<field name="arch" type="xml">
<form>
<header>
<field name="is_display" invisible="1"/>
<button string='提交' class="oe_highlight" states="draft"
type="object" name="do_unconfirmed"
attrs="{'invisible': [('state', '!=', 'draft')]}"/>
<button string='追回编辑' states="unconfirmed"
type="action" name="%(system_work_order_wizard_view_act_window)d"
context="{'explain':'确认要执行此操作吗?','object_name':'system.work.order','function_name':'do_draft','object_id':id}"/>
<button name="do_pending" states="unconfirmed"
string="确认可处理" type="object" class="oe_highlight"
groups="jikimo_system_order.group_operations_permissions_rwc"/>
<button string='处理工单' class="oe_highlight" states="pending"
type="action" name="%(launch_order_technician_wizard)d"
groups="jikimo_system_order.group_operations_permissions_rwc"/>
<button string='评价' class="oe_highlight" attrs="{'invisible': [('is_display', '=', False)]}"
type="action" name="%(launch_order_other_wizard)d" context="{'active_id':id}"/>
<button name="%(launch_order_close_wizard)d" string="关闭该工单"
attrs="{'invisible': ['|',('state', '=', 'draft'),'|',('state','=','completed'),('state','=','closed')]}"
type="action" context="{'active_id':id}"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>
<group>
<!-- <label for="order_number" class="oe_edit_only"/>-->
<group>
<field name="order_number" required="True" readonly="1"/>
<field name="order_type" required="True" attrs="{'readonly': [('state', '!=', 'draft')]}" options="{'no_create': True}"/>
<field name="date" required="True" readonly="True"/>
<field name="order_template_id" attrs="{'readonly': [('state', '!=', 'draft')]}"
domain="[('work_order_type','=',order_type),('state','=',True)]" options="{'no_create': True}"/>
<field name="confirmation_date" readonly="True"/>
<field name="urgency_degree" required="True" attrs="{'readonly': [('state','!=','draft')]}" widget="priority"/>
</group>
<group>
<field name="initiator_company_id" required="True" readonly="True"/>
<!-- <field name="initiator_department_id" required="True" readonly="True"/>-->
<field name="initiator_id" required="True" readonly="True"/>
<field name="confirm_id" readonly="True"/>
<field name="solve_people_id" readonly="True"/>
<field name="close_user_id" readonly="True"/>
</group>
<group>
<field name="title" attrs="{'readonly': [('state', '!=', 'draft')]}" required="True"/>
</group>
</group>
<notebook>
<page string="工单内容">
<field name="text" attrs="{'readonly': [('state','!=','draft')]}" required="True"/>
</page>
<page string="解决方案">
<group>
<field name="users_problem" readonly="True"/>
<field name="solution" readonly="True"/>
</group>
</page>
<page string="其他">
<group>
<field name="close_cause" readonly="True"/>
<field name="close_time" readonly="True"/>
<field name="grade" readonly="True"/>
</group>
</page>
</notebook>
</sheet>
<!-- <div class="oe_chatter">-->
<!-- <field name="message_follower_ids" widget="mail_followers"/>-->
<!-- <field name="message_ids" widget="mail_thread"/>-->
<!-- </div>-->
</form>
</field>
</record>
<!-- 搜索工单 -->
<record model="ir.ui.view" id="restaurant_search">
<field name="name">搜索工单</field>
<field name="model">system.work.order</field>
<field name="arch" type="xml">
<search>
<field string='发起人' name="initiator_id" widget="char" required="True"/>
<field string='标题' name="title" widget="char"/>
<field string='正文' name="text" widget="html"/>
<field string='实际问题' name="users_problem" widget="text"/>
<field string='解决方案' name="solution" widget="text"/>
<filter name="today" string="今日工单" domain="[('date','=',time.strftime('%%Y-%%m-%%d'))]"/>
<filter name="yesterday" string="昨日工单"
domain="[('date', '=', (context_today() - relativedelta(days=1)).strftime('%Y-%m-%d'))]"/>
<filter name="month" string="本月工单"
domain="[('date','&gt;=', time.strftime('%Y-%m-01')),('date','&lt;', (context_today() + relativedelta(months=1)).strftime('%Y-%m-01'))]"/>
<filter name="last_month" string="上月工单"
domain="[('date','&lt;', time.strftime('%Y-%m-01')),('date','&gt;=', (context_today() - relativedelta(months=1)).strftime('%Y-%m-01'))]"/>
<filter name="unconfirmed" string="待确认" domain="[('state','=','unconfirmed')]"/>
<filter name="pending" string="待处理" domain="[('state','=','pending')]"/>
<filter name="processed" string="已处理"
domain="['|', ('state','=','processed'), ('state','=','closed')]"/>
<group>
<filter string='发起人' name="initiator_id" context='{"group_by":"initiator_id"}'/>
<filter string='工单分类' name="order_type" context='{"group_by":"order_type"}'/>
<filter string='模板' name="order_template_id" context='{"group_by":"order_template_id"}'/>
<filter string='状态' name="state" context='{"group_by":"state"}'/>
<filter string='紧急情况' name="state" context='{"group_by":"urgency_degree"}'/>
</group>
</search>
</field>
</record>
<record model="ir.ui.view" id="graph_tree">
<field name="name">工单图表</field>
<field name="model">system.work.order</field><!--对应表单名称-->
<field name="arch" type="xml">
<pivot>
<field name="date" type="row" interval="day"/>
<field name="order_type" type="col"/>
<field name="state" type="row"/>
</pivot>
</field>
</record>
<!-- 工单 -->
<record model="ir.actions.act_window" id="system_order">
<field name="name">工单</field>
<field name="res_model">system.work.order</field>
<field name="view_mode">tree,form,search,graph,pivot</field>
</record>
<!--工单模板信息-->
<record model="ir.ui.view" id="order_template_tree">
<field name="name">工单模板信息</field>
<field name="model">work.order.template</field><!--对应表单名称-->
<field name="arch" type="xml">
<tree>
<field name="num"/>
<field name="name"/>
<field name="work_order_type"/>
<field name="title_template"/>
<field name="template_explain"/>
<field name="state"/>
</tree>
</field>
</record>
<!--新建系统工单模板-->
<record model="ir.ui.view" id="order_template_form">
<field name="name">新建系统工单模板</field>
<field name="model">work.order.template</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="num" required="True" readonly="True"/>
<field name="name" required="True"/>
<field name="work_order_type" required="True"/>
<field name="template_explain" required="True" style="height: 50px;"/>
<field name="title_template" required="True"/>
<field name="state"/>
<field name="text_template" required="True"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- 工单模板 -->
<record model="ir.actions.act_window" id="work_template">
<field name="name">工单模板</field>
<field name="res_model">work.order.template</field>
<field name="view_mode">tree,form</field>
</record>
<!--工单分类信息-->
<record model="ir.ui.view" id="order_type_tree">
<field name="name">工单分类信息</field>
<field name="model">order.classify</field><!--对应表单名称-->
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="state"/>
</tree>
</field>
</record>
<!--新建系统分类信息-->
<record model="ir.ui.view" id="order_type_form">
<field name="name">新建系统分类信息</field>
<field name="model">order.classify</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name" required="True"/>
<field name="sequence" invisible="True"/>
<field name="state"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- 工单分类 -->
<record model="ir.actions.act_window" id="classify">
<field name="name">工单分类</field>
<field name="res_model">order.classify</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="系统工单" id="work_order_1_list" web_icon="jikimo_system_order,static/description/icon.png"/>
<menuitem name="工单" id="work_order" parent="work_order_1_list" action="system_order"/>
<menuitem name="工单模板" id="work_order_template" parent="work_order_1_list" action="work_template" groups="jikimo_system_order.group_operations_permissions_rwc"/>
<menuitem name="工单分类" id="work_order_type" parent="work_order_1_list" action="classify" groups="jikimo_system_order.group_operations_permissions_rwc"/>
<menuitem name="工单设置" id="system_order_notice_user_config" parent="work_order_1_list" action="action_system_order_notice_view" groups="jikimo_system_order.group_operations_permissions_rwc"/>
</data>
</odoo>

View File

@@ -1,6 +0,0 @@
# -*- coding: utf-8 -*-
from . import order_other_wizard
from . import order_technician_wizard
from . import order_close_wizard
from . import system_work_order_wizard

View File

@@ -1,79 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION
from odoo.exceptions import ValidationError
import datetime, logging
class OrderCloseWizard(models.TransientModel):
_name = 'order.close.wizard'
def get_context(self):
if self._context.get('active_id'):
obj = self.env['system.work.order'].browse(self._context.get('active_id'))
if obj.initiator_id.id != self.env.user.id:
raise ValidationError(u'非本人无法操作')
return obj
order_id = fields.Many2one('system.work.order', string=u'工单ID',
default=lambda self: self.get_context().id)
# 关闭原因
close_cause = fields.Text(string=u'关闭问题原因', default=lambda self: self.get_context().close_cause)
# 关闭时间
close_time = fields.Datetime(string=u'关闭问题时间', default=fields.datetime.now())
# 状态
state = fields.Selection(STATE_SELECTION, default='closed', string=u'状态')
# 关闭人
close_user_id = fields.Many2one('res.users', string=u'关闭人', default=lambda self: self.env.user)
def sure(self):
self.order_id.close_cause = self.close_cause
self.order_id.close_time = self.close_time
if self.order_id.state == 'unconfirmed':
state_remark = u'待确认 --> 已关闭'
if self.order_id.state == 'pending':
state_remark = u'待处理 --> 已关闭'
if self.order_id.state == 'processed':
state_remark = u'已处理待评分 --> 已关闭'
# self.order_id.message_post(u'操作人:%s操作时间%s状态变更过程%s' % (
# self.env.user.name,
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
self.order_id.state = self.state
self.order_id.close_user_id = self.close_user_id
we_employee_ids = []
if self.order_id.initiator_id.we_employee_id:
we_employee_ids.append(self.order_id.initiator_id.we_employee_id)
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
# agent_id, user_ids, content
content = """您提交的工单-**工单标题:{0}**-<font color=\"#FF0000\">**已关闭**</font>
>提交时间:{1}
>处理时间:{2}
>处理人:{3}
如有问题,请联系系统管理员!
""".format(self.order_id.title,
(self.order_id.date + datetime.timedelta(hours=8)).strftime(
'%Y-%m-%d %H:%M'), (datetime.datetime.now() + datetime.timedelta(
hours=8)).strftime('%Y-%m-%d %H:%M'), self.env.user.name or '')
# wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_ids, content=content)
for we_employee_id in we_employee_ids:
try:
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
except Exception as e:
logging.error('工单关闭发送消息异常%s' % str(e))
return {}

View File

@@ -1,42 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
from odoo.exceptions import ValidationError
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION, GRADE
import datetime
class OrderOtherWizard(models.TransientModel):
_name = 'order.other.wizard'
def get_context(self):
if self._context.get('active_id'):
obj = self.env['system.work.order'].browse(self._context.get('active_id'))
if obj.initiator_id.id != self.env.user.id:
raise ValidationError(u'非本人无法操作')
return obj
order_id = fields.Many2one('system.work.order', string=u'工单ID',
default=lambda self: self.get_context().id)
# 关闭时间
close_time = fields.Datetime(string=u'关闭时间', default=fields.datetime.now())
# 状态
state = fields.Selection(STATE_SELECTION, default='completed', string=u'状态')
# 打分
grade = fields.Selection(GRADE, string=u'评分')
# 关闭人
close_user_id = fields.Many2one('res.users', string=u'关闭人', default=lambda self: self.env.user)
def sure(self):
self.order_id.close_time = self.close_time
self.order_id.grade = self.grade
if self.order_id.state == 'processed':
state_remark = u'已处理待评分 --> 已完成'
# self.order_id.message_post(u'操作人:%s操作时间%s状态变更过程%s' % (
# self.env.user.name,
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
self.order_id.state = self.state
self.order_id.close_user_id = self.close_user_id
return {}

View File

@@ -1,59 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION
import datetime
import logging
class OrderTechnicianWizard(models.TransientModel):
_name = 'order.technician.wizard'
order_id = fields.Many2one('system.work.order', string=u'工单ID',
default=lambda self: self.env.context.get('active_id'))
# 解决人
solve_people_id = fields.Many2one('res.users', string=u'解决人', default=lambda self: self.env.user)
# 用户实际问题
users_problem = fields.Text(string=u'用户实际问题')
# 最终解决方案
solution = fields.Text(string=u'最终解决方案')
# 状态
state = fields.Selection(STATE_SELECTION, default='processed', string=u'状态')
def sure(self):
self.order_id.solve_people_id = self.solve_people_id
self.order_id.users_problem = self.users_problem
self.order_id.solution = self.solution
if self.order_id.state == 'pending':
state_remark = u'待处理 --> 已处理待评分'
# self.order_id.message_post(u'操作人:%s操作时间%s状态变更过程%s' % (
# self.env.user.name,
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
self.order_id.state = self.state
# 获取通知人
# objs = self.env['system.order.notice'].search([])
# user_ids = objs.notice_user_ids.filtered(lambda item: item.we_employee_id not in ['', False])
# we_employee_ids = user_ids.mapped('we_employee_id')
we_employee_ids = []
if self.order_id.initiator_id.we_employee_id:
we_employee_ids.append(self.order_id.initiator_id.we_employee_id)
print(we_employee_ids)
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
# agent_id, user_ids, content
content = """您提交的工单-**工单标题:{0}**-<font color=\"info\">**已处理**</font>
>提交时间:{1}
>处理反馈:{4}
>处理时间:{2}
>处理人:{3}
如有问题,请联系系统管理员!
""".format(self.order_id.title,
(self.order_id.date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'), (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'), self.env.user.name or '', self.solution or '')
# wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_ids, content=content)
for we_employee_id in we_employee_ids:
try:
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
except Exception as e:
logging.error('工单处理发送消息异常%s' % str(e))
return {}

View File

@@ -1,122 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- 技术员向导form-->
<record model="ir.ui.view" id="wizard_technician_form_view">
<field name="name">技术员向导</field>
<field name="model">order.technician.wizard</field>
<field name="arch" type="xml">
<form string="技术员编辑">
<group>
<field name="order_id" required="1" readonly="1"/>
<field name="solve_people_id" required="1"/>
<field name="users_problem" required="1" style="height: 50px;"/>
<field name="solution" required="1" style="height: 50px;"/>
</group>
<footer>
<button name="sure" string="确定" type="object" class="oe_highlight"/>
or
<button string="取消" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="launch_order_technician_wizard">
<field name="name">技术员编辑</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">order.technician.wizard</field>
<field name="view_mode">form</field>
<field name="view_id" ref="wizard_technician_form_view"/>
<field name="context">{'display_default_code':False}</field>
<field name="target">new</field>
</record>
<!-- 其它向导form-->
<record model="ir.ui.view" id="wizard_other_form_view">
<field name="name">其它向导</field>
<field name="model">order.other.wizard</field>
<field name="arch" type="xml">
<form string="其它编辑">
<group>
<field name="order_id" required="1" readonly="1"/>
<field name="close_time" required="1" readonly="1"/>
<field name="grade" required="1"/>
<field name="close_user_id" required="1" readonly="1"/>
</group>
<footer>
<button name="sure" string="确定" type="object" class="oe_highlight"/>
or
<button string="取消" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="launch_order_other_wizard">
<field name="name">其它编辑</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">order.other.wizard</field>
<field name="view_mode">form</field>
<field name="view_id" ref="wizard_other_form_view"/>
<field name="context">{'display_default_code':False}</field>
<field name="target">new</field>
</record>
<!--关闭向导form-->
<record model="ir.ui.view" id="wizard_close_form_view">
<field name="name">关闭向导</field>
<field name="model">order.close.wizard</field>
<field name="arch" type="xml">
<form string="关闭工单">
<group>
<field name="order_id" required="1" readonly="1"/>
<field name="close_cause" required="1" style="height: 50px;"/>
<field name="close_time" required="1" readonly="1"/>
<field name="close_user_id" required="1" readonly="1"/>
</group>
<footer>
<button name="sure" string="确定" type="object" class="oe_highlight"/>
or
<button string="取消" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="launch_order_close_wizard">
<field name="name">关闭工单</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">order.close.wizard</field>
<field name="view_mode">form</field>
<field name="view_id" ref="wizard_close_form_view"/>
<field name="context">{'display_default_code':False}</field>
<field name="target">new</field>
</record>
<record id="system_work_order_wizard_view" model="ir.ui.view">
<field name="name">system_work_order_wizard_view</field>
<field name="model">system.work.order.wizard</field>
<field name="arch" type="xml">
<form string="二次确认">
<field name="explain" readonly="1"/>
<footer>
<button name="sure" string="确定" type="object" class="oe_highlight"/>
or
<button string="取消" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="system_work_order_wizard_view_act_window">
<field name="name">二次确认</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">system.work.order.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</odoo>

View File

@@ -1,42 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/12/12 9:46
# @Author : GuoXiang
# @Site :
# @File : system_work_order_wizard.py
# @Software: PyCharm
# @Desc :
# @license : Copyright©2018 www.dasmaster.com All Rights Reserved.
# @Contact : xg1230205321@163.com
from odoo import models, api, fields
from odoo.exceptions import ValidationError
class SystemWorkOrderWizard(models.TransientModel):
_name = "system.work.order.wizard"
_description = u"追回确认"
def _get_explain(self):
if self._context.get('object_id'):
obj = self.env['system.work.order'].browse(self._context.get('object_id'))
if obj.initiator_id.id != self.env.user.id:
raise ValidationError(u'非本人无法操作')
if self._context.get('explain'):
return self._context["explain"]
explain = fields.Char(default=_get_explain)
def sure(self):
"""
确认
:return:
"""
if self._context.get('object_id') and self._context.get('object_name') and self._context.get(
'explain') and self._context.get('function_name'):
work_sheet_obj = self.env[self._context["object_name"]].search([('id', '=', int(self._context["object_id"]))])
class_name = self._context.get('object_name') # 获得对象类名
method_name = self._context.get('function_name') # 获得对象的方法
obj_function = getattr(self.env[class_name], method_name)
obj_function(work_sheet_obj)

View File

@@ -11,10 +11,11 @@ class Printer(models.Model):
class TableStyle(models.Model): class TableStyle(models.Model):
_name = 'table.style' _name = 'label.style'
_description = '标签样式' _description = '标签样式'
name = fields.Char(string='名称', required=True) name = fields.Char(string='名称', required=True)
zpl_code = fields.Text(string='zpl指令')
# todo # todo
@@ -25,4 +26,5 @@ class PrinterConfiguration(models.Model):
name = fields.Char(string='名称', required=True) name = fields.Char(string='名称', required=True)
printer_id = fields.Many2one('printer', string='打印机') printer_id = fields.Many2one('printer', string='打印机')
model = fields.Many2one('ir.model', string='模型名称') model = fields.Many2one('ir.model', string='模型名称')
label_id = fields.Many2one('label.style', '标签')
# # 其他相关字段... # # 其他相关字段...

View File

@@ -43,19 +43,19 @@ class PrintingUtils(models.AbstractModel):
zpl_code += "^CI28\n" zpl_code += "^CI28\n"
# 设置二维码位置 # 设置二维码位置
zpl_code += "^FO50,50\n" # 调整二维码位置,使其与资产编号在同一行 zpl_code += "^FO50,260\n" # 调整二维码位置,使其与资产编号在同一行
zpl_code += f"^BQN,2,6^FDLM,B0093{code}^FS\n" zpl_code += f"^BQN,2,5^FDLM,B0093{code}^FS\n"
# 设置资产编号文本位置 # # 设置资产编号文本位置
zpl_code += "^FO300,60\n" # 资产编号文本的位置,与二维码在同一行 # zpl_code += "^FO300,60\n" # 资产编号文本的位置,与二维码在同一行
zpl_code += "^A1N,45,45^FD编码名称: ^FS\n" # zpl_code += "^A1N,45,45^FD编码名称: ^FS\n"
# 设置{code}文本位置 # 设置{code}文本位置
# 假设{code}文本需要位于资产编号和二维码下方,中间位置 # 假设{code}文本需要位于资产编号和二维码下方,中间位置
# 设置{code}文本位置并启用自动换行 # 设置{code}文本位置并启用自动换行
zpl_code += "^FO300,120\n" # {code}文本的起始位置 zpl_code += "^FO240,10\n" # {code}文本的起始位置
zpl_code += "^FB400,4,0,L,0\n" # 定义一个宽度为500点的文本框最多4行左对齐 zpl_code += "^FB600,10,0,L,0\n" # 定义一个宽度为500点的文本框最多4行左对齐
zpl_code += f"^A1N,40,40^FD{code}^FS\n" zpl_code += f"^A1B,40,40^FD{code}^FS\n"
# 在{code}文本框周围绘制线框 # 在{code}文本框周围绘制线框
# 假设线框的外部尺寸为宽度500点高度200点 # 假设线框的外部尺寸为宽度500点高度200点

View File

@@ -61,10 +61,12 @@ class MrsMaterialModel(models.Model):
supplier_ids = fields.One2many('sf.supplier.sort', 'materials_model_id', string='供应商') supplier_ids = fields.One2many('sf.supplier.sort', 'materials_model_id', string='供应商')
active = fields.Boolean('有效', default=True) active = fields.Boolean('有效', default=True)
@api.constrains("gain_way") @api.onchange('gain_way')
def _check_supplier_ids(self): def _check_gain_way(self):
for item in self: if not self.gain_way:
if item.gain_way in ('外协', '采购') and not item.supplier_ids: raise UserError("请选择获取方式")
if self.gain_way in ['外协', '采购']:
if not self.supplier_ids:
raise UserError("请添加供应商") raise UserError("请添加供应商")
@@ -92,10 +94,8 @@ class MrsProductionProcess(models.Model):
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂') partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
active = fields.Boolean('有效', default=True) active = fields.Boolean('有效', default=True)
parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数') parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数')
category_id = fields.Many2one('sf.production.process.category', string='表面工艺类别') category_id = fields.Many2one('sf.production.process.category')
# workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True) # workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True)
processing_day = fields.Float('加工天数/d')
travel_day = fields.Float('路途天数/d')
# class MrsProcessingTechnology(models.Model): # class MrsProcessingTechnology(models.Model):
@@ -143,10 +143,7 @@ class MrsProductionProcessParameter(models.Model):
is_check = fields.Boolean(default=False) is_check = fields.Boolean(default=False)
# price = fields.Float('单价') # price = fields.Float('单价')
process_id = fields.Many2one('sf.production.process', string='表面工艺') process_id = fields.Many2one('sf.production.process', string='表面工艺')
process_description = fields.Char(string='工艺描述')
materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料') materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料')
processing_day = fields.Float('加工天数/d')
travel_day = fields.Float('路途天数/d')
active = fields.Boolean('有效', default=True) active = fields.Boolean('有效', default=True)
def name_get(self): def name_get(self):

View File

@@ -331,7 +331,7 @@ class ToolInventory(models.Model):
work_material = fields.Selection([('', ''), ('', '')], string='加工材料') work_material = fields.Selection([('', ''), ('', '')], string='加工材料')
life_span = fields.Float('寿命(min)') life_span = fields.Float('寿命(min)')
tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组', required=True) tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组')
active = fields.Boolean('已归档', default=True) active = fields.Boolean('已归档', default=True)

View File

@@ -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_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_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_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,1,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,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,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,0,1,0
access_sf_production_process,sf_production_process,model_sf_production_process,base.group_user,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_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 access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0
@@ -208,6 +208,7 @@ access_sf_machine_brand_tags_group_purchase_director,sf_machine_brand_tags_group
access_printer,printer,model_printer,base.group_user,1,1,1,1 access_printer,printer,model_printer,base.group_user,1,1,1,1
access_printer_configuration,printer.configuration,model_printer_configuration,base.group_user,1,1,1,1 access_printer_configuration,printer.configuration,model_printer_configuration,base.group_user,1,1,1,1
access_label_style,label.style,model_label_style,base.group_user,1,1,1,1
access_group_sf_mrp_user,sf_tool_inventory,model_sf_tool_inventory,base.group_user,1,1,1,0 access_group_sf_mrp_user,sf_tool_inventory,model_sf_tool_inventory,base.group_user,1,1,1,0
access_group_sf_mrp_user_admin,sf_tool_inventory_admin,model_sf_tool_inventory,base.group_system,1,1,1,0 access_group_sf_mrp_user_admin,sf_tool_inventory_admin,model_sf_tool_inventory,base.group_system,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
11 access_sf_machine_control_system_admin sf_machine_control_system_admin model_sf_machine_control_system base.group_system 1 1 1 0
12 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
13 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
14 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 0 1 0
15 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 0 1 0
16 access_sf_production_process sf_production_process model_sf_production_process base.group_user 1 1 1 0
17 access_sf_production_process_admin sf_production_process_admin model_sf_production_process base.group_system 1 1 1 0
18 access_sf_production_materials sf_production_materials model_sf_production_materials base.group_user 1 1 1 0
208 access_sf_multi_mounting_type_group_purchase_director access_sf_fixture_material_group_purchase_director sf_multi_mounting_type_group_purchase_director sf_fixture_material_group_purchase_director model_sf_multi_mounting_type model_sf_fixture_material sf_base.group_purchase_director 1 0 0 0
209 access_sf_fixture_model_group_purchase_director access_sf_multi_mounting_type_group_purchase_director sf_fixture_model_group_purchase_director sf_multi_mounting_type_group_purchase_director model_sf_fixture_model model_sf_multi_mounting_type sf_base.group_purchase_director 1 0 0 0
210 access_sf_fixture_materials_basic_parameters_group_purchase_director access_sf_fixture_model_group_purchase_director sf_fixture_materials_basic_parameters_group_purchase_director sf_fixture_model_group_purchase_director model_sf_fixture_materials_basic_parameters model_sf_fixture_model sf_base.group_purchase_director 1 0 0 0
211 access_sf_fixture_materials_basic_parameters_group_purchase_director sf_fixture_materials_basic_parameters_group_purchase_director model_sf_fixture_materials_basic_parameters sf_base.group_purchase_director 1 0 0 0
212 access_sf_machine_tool_type_group_purchase_director sf_machine_tool_type_group_purchase_director model_sf_machine_tool_type sf_base.group_purchase_director 1 0 0 0
213 access_sf_fixture_material_group_sale_director sf_fixture_material_group_sale_director model_sf_fixture_material sf_base.group_sale_director 1 0 0 0
214 access_sf_multi_mounting_type_group_sale_director sf_multi_mounting_type_group_sale_director model_sf_multi_mounting_type sf_base.group_sale_director 1 0 0 0

View File

@@ -38,6 +38,7 @@
<field name="name"/> <field name="name"/>
<field name="printer_id"/> <field name="printer_id"/>
<field name="model"/> <field name="model"/>
<field name="label_id"/>
<!-- 其他字段... --> <!-- 其他字段... -->
</tree> </tree>
</field> </field>
@@ -53,6 +54,36 @@
<field name="name"/> <field name="name"/>
<field name="printer_id"/> <field name="printer_id"/>
<field name="model"/> <field name="model"/>
<field name="label_id"/>
<!-- 其他字段... -->
</group>
</sheet>
</form>
</field>
</record>
<record id="view_label_style_tree" model="ir.ui.view">
<field name="name">label.style.tree</field>
<field name="model">label.style</field>
<field name="arch" type="xml">
<tree string="label style">
<field name="name"/>
<!-- <field name="zpl_code"/> -->
<!-- 其他字段... -->
</tree>
</field>
</record>
<record id="view_label_style_form" model="ir.ui.view">
<field name="name">label.style.form</field>
<field name="model">label.style</field>
<field name="arch" type="xml">
<form string="label style">
<sheet>
<group>
<field name="name"/>
<field name="zpl_code"/>
<!-- 其他字段... --> <!-- 其他字段... -->
</group> </group>
</sheet> </sheet>
@@ -74,6 +105,11 @@
<field name="res_model">printer.configuration</field> <field name="res_model">printer.configuration</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<record id="action_label_style" model="ir.actions.act_window">
<field name="name">标签样式</field>
<field name="res_model">label.style</field>
<field name="view_mode">tree,form,kanban</field>
</record>
<!-- Add a menu item for the printer configuration --> <!-- Add a menu item for the printer configuration -->
<!-- <record id="menu_printer_configuration" model="ir.ui.menu"> --> <!-- <record id="menu_printer_configuration" model="ir.ui.menu"> -->
@@ -108,5 +144,12 @@
sequence="2" sequence="2"
parent="printer_main_menu"/> parent="printer_main_menu"/>
<menuitem
id="menu_label_style"
name="标签样式"
action="action_label_style"
sequence="3"
parent="printer_main_menu"/>
</data> </data>
</odoo> </odoo>

View File

@@ -27,13 +27,9 @@
<group> <group>
<field name="code" readonly="1"/> <field name="code" readonly="1"/>
<field name="process_id" readonly="1"/> <field name="process_id" readonly="1"/>
<field name="process_description" readonly="1"/>
<field name="gain_way"/> <field name="gain_way"/>
</group> </group>
<group>
<field name="processing_day" readonly="1"/>
<field name="travel_day" readonly="1"/>
</group>
</group> </group>
<notebook> <notebook>
<page string="适用材料"> <page string="适用材料">
@@ -183,46 +179,41 @@
</div> </div>
<group> <group>
<group> <group>
<field name="code" readonly="1"/> <field name="code"/>
<field name="category_id" readonly="1"/>
</group> </group>
<group> <notebook>
<field name="processing_day" readonly="1"/> <page string="可选参数">
<field name="travel_day" readonly="1"/> <field name="parameter_ids">
</group> <tree force_save="1">
</group> <field name="code" readonly="1" force_save="1"/>
<notebook> <field name="name"/>
<page string="可选参数"> <field name="gain_way"/>
<field name="parameter_ids"> <field name='process_id' default="default"/>
<tree force_save="1"> </tree>
<field name="code" readonly="1" force_save="1"/> <form>
<field name="name"/> <sheet>
<field name="gain_way"/>
<field name='process_id' default="default"/>
</tree>
<form>
<sheet>
<group>
<group> <group>
<field name="code"/> <group>
<field name="name" string="参数名"/> <field name="code"/>
<field name="name" string="参数名"/>
</group>
<group>
<field name='process_id'/>
<field name="gain_way"/>
</group>
</group> </group>
<group> <notebook>
<field name='process_id'/> <page string="适用材料">
<field name="gain_way"/> <field name="materials_model_ids"/>
</group> </page>
</group> </notebook>
<notebook> </sheet>
<page string="适用材料"> </form>
<field name="materials_model_ids"/> </field>
</page> </page>
</notebook>
</sheet>
</form>
</field>
</page>
</notebook> </notebook>
</group>
<group> <group>
<group> <group>
<field name="remark"/> <field name="remark"/>
@@ -260,7 +251,7 @@
<group> <group>
<group> <group>
<field name="materials_no" readonly="1" force_save="1"/> <field name="materials_no" readonly="1" force_save="1"/>
<field name="gain_way" required="0"/> <field name="gain_way" required="1"/>
<field name="tensile_strength" required="1"/> <field name="tensile_strength" required="1"/>
<field name="hardness" required="1"/> <field name="hardness" required="1"/>
<field name="density" readonly="1"/> <field name="density" readonly="1"/>
@@ -279,9 +270,9 @@
<notebook> <notebook>
<page string="供应商"> <page string="供应商">
<field name='supplier_ids' class="supplier_ids_set_css"> <field name='supplier_ids' class="supplier_ids_set_css">
<tree editable='bottom' delete="1"> <tree editable='bottom'>
<field name="sequence" widget="handle" string="序号"/> <field name="sequence" widget="handle" string="序号"/>
<field name="partner_id" string="名称" options="{'no_create': True}"/> <field name="partner_id" string="名称"/>
</tree> </tree>
</field> </field>
</page> </page>

View File

@@ -555,9 +555,9 @@
<field name="model">sf.tool.inventory</field> <field name="model">sf.tool.inventory</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="功能刀具清单" create="1" edit="1" delete="0" editable="bottom"> <tree string="功能刀具清单" create="1" edit="1" delete="0" editable="bottom">
<field name="name" attrs="{'readonly': [('id', '!=', False)]}"/> <field name="name"/>
<field name="functional_cutting_tool_model_id"/> <field name="functional_cutting_tool_model_id"/>
<field name="tool_groups_id" required="1" attrs="{'readonly': [('id', '!=', False)]}"/> <field name="tool_groups_id"/>
<field name="work_material"/> <field name="work_material"/>
<field name="life_span"/> <field name="life_span"/>
<field name="prefix" optional="hide"/> <field name="prefix" optional="hide"/>

View File

@@ -21,7 +21,6 @@ class Http(models.AbstractModel):
def _auth_method_sf_token(cls): def _auth_method_sf_token(cls):
# 从headers.environ中获取对方传过来的token,timestamp,加密的校验字符串 # 从headers.environ中获取对方传过来的token,timestamp,加密的校验字符串
datas = request.httprequest.headers.environ datas = request.httprequest.headers.environ
_logger.info('datas:%s' % datas)
if 'HTTP_TOKEN' in datas: if 'HTTP_TOKEN' in datas:
_logger.info('token:%s' % datas['HTTP_TOKEN']) _logger.info('token:%s' % datas['HTTP_TOKEN'])
# 查询密钥 # 查询密钥

View File

@@ -5,7 +5,7 @@ import requests
import cpca import cpca
# from odoo.exceptions import UserError # from odoo.exceptions import UserError
# from odoo.exceptions import ValidationError # from odoo.exceptions import ValidationError
from odoo import api, fields, models, _ from odoo import api, fields, models
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -14,7 +14,7 @@ _logger = logging.getLogger(__name__)
class JdEclp(models.Model): class JdEclp(models.Model):
_inherit = 'stock.picking' _inherit = 'stock.picking'
senderNickName = fields.Char(string='寄件工厂简称', required=True, default='XT') senderNickName = fields.Char(string='寄件工厂简称', required=True, default='MW')
# receiverName = fields.Char(string='收件人姓名') # receiverName = fields.Char(string='收件人姓名')
# receiverMobile = fields.Char(string='收件人电话') # receiverMobile = fields.Char(string='收件人电话')
@@ -149,7 +149,7 @@ class JdEclp(models.Model):
}, },
} }
_logger.info('准备调接口1') _logger.info('准备调接口1')
url1 = config['bfm_url_new'] + '/api/create/jd/order' url1 = config['bfm_url'] + '/api/create/jd/order'
requests.post(url1, json=json1, data=None) requests.post(url1, json=json1, data=None)
_logger.info('调用成功1') _logger.info('调用成功1')
_logger.info('准备调接口2') _logger.info('准备调接口2')
@@ -158,31 +158,18 @@ class JdEclp(models.Model):
'orderNo': self.origin, 'orderNo': self.origin,
}, },
} }
url2 = config['bfm_url_new'] + '/api/get/jd/no' url2 = config['bfm_url'] + '/api/get/jd/no'
response = requests.post(url2, json=json2, data=None) response = requests.post(url2, json=json2, data=None)
# _logger.info('调用成功2', response.json()['result']['wbNo']) # _logger.info('调用成功2', response.json()['result']['wbNo'])
tem_ret = response.json().get('result') self.carrier_tracking_ref = response.json()['result']['wbNo']
if not tem_ret:
raise ValidationError('京东物流返回异常,请联系管理员')
self.carrier_tracking_ref = response.json()['result'].get('wbNo')
if not self.carrier_tracking_ref:
raise ValidationError('物流下单未成功,请联系管理员')
self.is_bill = True self.is_bill = True
self.logistics_status = '1' self.logistics_status = '1'
notification = { # # 京东物流下单后,销售订单状态改为待收货
'type': 'ir.actions.client', # self.env['sale.order'].search([('name', '=', self.origin)]).write({'scheduled_status': 'to receive'})
'tag': 'display_notification',
'params': {
'title': _('成功'),
'type': 'success',
'message': '物流下单成功',
'sticky': False,
'next': {'type': 'ir.actions.client', 'tag': 'reload'}
}
}
return notification # else:
# raise UserError("选择京东物流才能下单呦")
def get_bill(self): def get_bill(self):
""" """
@@ -196,7 +183,7 @@ class JdEclp(models.Model):
'no': self.origin, 'no': self.origin,
}, },
} }
url1 = config['bfm_url_new'] + '/api/create/jd/bill' url1 = config['bfm_url'] + '/api/create/jd/bill'
response = requests.post(url1, json=json1, data=None) response = requests.post(url1, json=json1, data=None)
# _logger.info('调用成功2', response.json()) # _logger.info('调用成功2', response.json())

View File

@@ -30,7 +30,7 @@ class StatusChange(models.Model):
'process_start_time': process_start_time, 'process_start_time': process_start_time,
}, },
} }
url1 = config['bfm_url_new'] + '/api/get/state/get_order' url1 = config['bfm_url'] + '/api/get/state/get_order'
requests.post(url1, json=json1, data=None) requests.post(url1, json=json1, data=None)
logging.info('接口已经执行=============') logging.info('接口已经执行=============')
@@ -54,7 +54,7 @@ class StatusChange(models.Model):
'state': '待派单', 'state': '待派单',
}, },
} }
url1 = config['bfm_url_new'] + '/api/get/state/cancel_order' url1 = config['bfm_url'] + '/api/get/state/cancel_order'
requests.post(url1, json=json1, data=None) requests.post(url1, json=json1, data=None)
return res return res

View File

@@ -32,7 +32,7 @@
<field name="is_bill" invisible="True"/> <field name="is_bill" invisible="True"/>
<field name="logistics_status" invisible="True"/> <field name="logistics_status" invisible="True"/>
<field name="logistics_way" 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', '=', '自提')]}"/> attrs="{'invisible': ['|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('is_bill', '=', True), ('logistics_way', '=', '自提')]}"/>
<button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary" <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', '=', '自提')]}"/> attrs="{'invisible': ['|', '|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('logistics_status', '=', '2'), ('is_bill', '=', False), ('logistics_way', '=', '自提')]}"/>
@@ -45,50 +45,42 @@
<field name="model">stock.picking</field> <field name="model">stock.picking</field>
<field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form"/> <field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="location_id" position="after"> <field name="location_id" position="after">
<field name="logistics_status" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="logistics_status" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="logistics_way" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="logistics_way" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</field> </field>
</field>
</record>
<record id="tracking_only_view" model="ir.ui.view"> <xpath expr="//group//field[@name='carrier_id']" position="after">
<field name="name">tracking only</field> <!-- <field name="senderNickName" domain="[('self.name', 'like', '%OUT%')]"/> -->
<field name="model">stock.picking</field> <field name="senderNickName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="inherit_id" ref="stock.view_picking_form"/> <field name="expressItemName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="arch" type="xml"> <field name="deliveryType" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<xpath expr="//form//sheet//notebook//page[@name='operations']" position="after"> <field name="receiverName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<page string="发货信息" name="tracking"> <field name="receiverMobile" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<group> <field name="receiverProvinceName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<group> <field name="receiverCityName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="senderNickName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="receiverCountyName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="expressItemName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="receiverTownName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="grossWeight" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="receiverCompany" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="grossVolume" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="remark" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="deliveryType" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="grossWeight" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="grossVolume" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverMobile" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="pickupBeginTime" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverProvinceName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="bill_show" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCityName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/> <field name="logistics_status"/>
<field name="receiverCountyName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverTownName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCompany" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="remark" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="pickupBeginTime" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</group>
<group>
<field name="logistics_status"/>
<field name="carrier_id"/>
<field name="carrier_tracking_ref"/>
<field name="bill_show" attrs="{'invisible': [('check_out', '!=', 'OUT')]}" string='面单下载'/>
<field name="bill_show" widget="pdf_viewer" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</group>
</group>
</page>
</xpath> </xpath>
<xpath expr="//group//field[@name='group_id']" position="after">
<field name="bill_show" widget="pdf_viewer" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</xpath>
<!-- <xpath expr="//group[@name='other_infos']" position="after"> -->
<!-- <div> -->
<!-- <button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"/> -->
<!-- </div> -->
<!-- <div> -->
<!-- <button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"/> -->
<!-- </div> -->
<!-- </xpath> -->
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -22,16 +22,6 @@
<field name="company_id" ref="base.main_company"/> <field name="company_id" ref="base.main_company"/>
</record> </record>
<record id="stock_location_tool_dismantle" model="stock.location">
<field name="name">拆解</field>
<field name="location_id" ref="stock.stock_location_locations_virtual"/>
<field name="usage">internal</field>
<field name="barcode">DJCJ</field>
<field name="scrap_location">true</field>
<field name="active">true</field>
<field name="company_id" ref="base.main_company"/>
</record>
<record id="after_assembly_picking_in" model="stock.picking.type"> <record id="after_assembly_picking_in" model="stock.picking.type">
<field name="name">刀具组装入库</field> <field name="name">刀具组装入库</field>

View File

@@ -88,7 +88,7 @@
</div> </div>
<field name="model_volume" string="体积[mm³]"/> <field name="model_volume" string="体积[mm³]"/>
<field name="product_model_type_id" string="模型类型"/> <field name="product_model_type_id" string="模型类型"/>
<field name="model_processing_panel" placeholder="例如R,U" string="加工面板" readonly="1"/> <field name="model_processing_panel" placeholder="例如R,U" string="加工面板"/>
<field name="model_machining_precision"/> <field name="model_machining_precision"/>
<field name="model_process_parameters_ids" string="表面工艺参数" <field name="model_process_parameters_ids" string="表面工艺参数"
widget="many2many_tags" widget="many2many_tags"
@@ -305,7 +305,7 @@
<field name="cutting_tool_blade_type" <field name="cutting_tool_blade_type"
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/> attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
<field name="cutting_tool_coarse_medium_fine" string="粗/中/精" placeholder="请选择" <field name="cutting_tool_coarse_medium_fine" string="粗/中/精" placeholder="请选择"
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))],'readonly': [('id', '!=', False)]}"/> attrs="{'required': [('cutting_tool_type','=','整体式刀具')],'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))],'readonly': [('id', '!=', False)]}"/>
<!--整体式刀具--> <!--整体式刀具-->
<field name="cutting_tool_shank_diameter" string="柄部直径(mm)" class="diameter" <field name="cutting_tool_shank_diameter" string="柄部直径(mm)" class="diameter"
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/> attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>

View File

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

View File

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

View File

@@ -1,98 +0,0 @@
# -*- coding: utf-8 -*-
import ast
import json
import logging
from odoo import http
from odoo.http import request
class Sf_Dashboard_Connect(http.Controller):
@http.route('/api/get_machine_datas/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
cors="*")
def get_machine_datas_list(self, **kw):
"""
拿到机床数据返回给大屏展示
:param kw:
:return:
"""
res = {'status': 1, 'message': '成功', 'data': []}
logging.info('前端请求机床数据的参数为:%s' % kw)
# tem_list = [
# "XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-1", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-3",
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-4", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-5",
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-6", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-7",
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-8", "XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-2",
# "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-9", "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-10",
# "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-11", "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-12",
# "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-13", "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-14"
# ]
try:
equipment_obj = request.env['maintenance.equipment'].sudo()
# 获取请求的机床数据
machine_list = ast.literal_eval(kw['machine_list'])
for item in machine_list:
machine_data = equipment_obj.search([('code', '=', item)])
if machine_data:
res['data'].append({
'id': machine_data.id,
'name': machine_data.name,
'code': machine_data.code,
'status': machine_data.status,
'run_status': machine_data.run_status,
'run_time': machine_data.run_time,
'system_date': machine_data.system_date,
'system_time': machine_data.system_time,
'cut_time': machine_data.cut_time,
'cut_status': machine_data.cut_status,
'program': machine_data.program,
'program_name': machine_data.program_name,
'program_status': machine_data.program_status,
'tool_num': machine_data.tool_num,
'machine_power_on_time': machine_data.machine_power_on_time,
'product_counts': machine_data.product_counts,
'mode': machine_data.mode,
'start_time': machine_data.start_time,
'end_time': machine_data.end_time,
'program_start_time': machine_data.program_start_time,
'program_end_time': machine_data.program_end_time,
'standby_start_time': machine_data.standby_start_time,
'standby_end_time': machine_data.standby_end_time,
'offline_start_time': machine_data.offline_start_time,
'offline_end_time': machine_data.offline_end_time,
'emg_status': machine_data.emg_status,
'current_program': machine_data.current_program,
'current_program_seq': machine_data.current_program_seq,
'x_abs_pos': machine_data.x_abs_pos,
'y_abs_pos': machine_data.y_abs_pos,
'z_abs_pos': machine_data.z_abs_pos,
'feed_speed_set': machine_data.feed_speed_set,
'act_feed_speed': machine_data.act_feed_speed,
'spindle_speed_set': machine_data.spindle_speed_set,
'act_spindle_speed': machine_data.act_spindle_speed,
'spindle_load': machine_data.spindle_load,
'x_axis_load': machine_data.x_axis_load,
'y_axis_load': machine_data.y_axis_load,
'z_axis_load': machine_data.z_axis_load,
'rapid_feed': machine_data.rapid_feed,
'feed_rate': machine_data.feed_rate,
'x_mach_coord': machine_data.x_mach_coord,
'y_mach_coord': machine_data.y_mach_coord,
'z_mach_coord': machine_data.z_mach_coord,
'x_rel_coord': machine_data.x_rel_coord,
'y_rel_coord': machine_data.y_rel_coord,
'z_rel_coord': machine_data.z_rel_coord,
'x_dis_coord': machine_data.x_dis_coord,
'y_dis_coord': machine_data.y_dis_coord,
'z_dis_coord': machine_data.z_dis_coord,
'alarm_time': machine_data.alarm_time,
'alarm_msg': machine_data.alarm_msg,
'clear_time': machine_data.clear_time,
})
return json.JSONEncoder().encode(res)
except Exception as e:
logging.info('前端请求机床数据失败,原因:%s' % e)
res['status'] = -1
res['message'] = '前端请求机床数据失败,原因:%s' % e
return json.JSONEncoder().encode(res)

View File

@@ -123,159 +123,128 @@ class Machine_ftp(models.Model):
# workorder_ids = fields.One2many('mrp.workorder', 'machine_tool_id', string='工单') # workorder_ids = fields.One2many('mrp.workorder', 'machine_tool_id', string='工单')
# # 机床配置项目 # 机床配置项目
# # ftp相关 # ftp相关
# ftp_num = fields.Char('ftp账号') ftp_num = fields.Char('ftp账号')
# ftp_pwd = fields.Char('ftp密码') ftp_pwd = fields.Char('ftp密码')
# ftp_host = fields.Char('ftp地址') ftp_host = fields.Char('ftp地址')
# ftp_port = fields.Integer('ftp端口') ftp_port = fields.Integer('ftp端口')
# ftp_remote_path = fields.Char('机床ftp路径') ftp_remote_path = fields.Char('机床ftp路径')
# # 补偿值写入相关 # 补偿值写入相关
# x_compensation_node = fields.Char('x补偿值节点') x_compensation_node = fields.Char('x补偿值节点')
# y_compensation_node = fields.Char('y补偿值节点') y_compensation_node = fields.Char('y补偿值节点')
# # 数采配置相关 # 数采配置相关
# machine_ip = fields.Char('机床IP') machine_ip = fields.Char('机床IP')
# machine_signed = fields.Char('机床刷新间隔') machine_signed = fields.Char('机床刷新间隔')
# machine_status = fields.Char('机床在线状态') machine_status = fields.Char('机床在线状态')
# machine_cnc_type = fields.Char('机床CNC型号') machine_cnc_type = fields.Char('机床CNC型号')
# machine_axis_count = fields.Char('机床轴总数') machine_axis_count = fields.Char('机床轴总数')
# machine_run_status = fields.Char('机床运行状态') machine_run_status = fields.Char('机床运行状态')
# machine_emg_status = fields.Char('机床急停状态') machine_emg_status = fields.Char('机床急停状态')
# machine_cut_status = fields.Char('机床当前切削状态') machine_cut_status = fields.Char('机床当前切削状态')
# machine_mode = fields.Char('机床当前操作模式') machine_mode = fields.Char('机床当前操作模式')
# machine_spindle_load = fields.Char('机床主轴负载') machine_spindle_load = fields.Char('机床主轴负载')
# machine_x_mach = fields.Char('机床X轴机械坐标') machine_x_mach = fields.Char('机床X轴机械坐标')
# machine_x_abs_mach = fields.Char('机床X轴当前位置') machine_x_abs_mach = fields.Char('机床X轴当前位置')
# machine_x_rel_mach = fields.Char('机床X轴相对工件坐标') machine_x_rel_mach = fields.Char('机床X轴相对工件坐标')
# machine_x_dis_mach = fields.Char('机床X轴目标距离') machine_x_dis_mach = fields.Char('机床X轴目标距离')
# machine_x_axis_load = fields.Char('机床X轴伺服轴负载') machine_x_axis_load = fields.Char('机床X轴伺服轴负载')
# machine_y_mach = fields.Char('机床Y轴机械坐标') machine_y_mach = fields.Char('机床Y轴机械坐标')
# machine_y_abs_mach = fields.Char('机床Y轴当前位置') machine_y_abs_mach = fields.Char('机床Y轴当前位置')
# machine_y_rel_mach = fields.Char('机床Y轴相对工件坐标') machine_y_rel_mach = fields.Char('机床Y轴相对工件坐标')
# machine_y_dis_mach = fields.Char('机床Y轴目标距离') machine_y_dis_mach = fields.Char('机床Y轴目标距离')
# machine_y_axis_load = fields.Char('机床Y轴伺服轴负载') machine_y_axis_load = fields.Char('机床Y轴伺服轴负载')
# machine_z_mach = fields.Char('机床Z轴机械坐标') machine_z_mach = fields.Char('机床Z轴机械坐标')
# machine_z_abs_mach = fields.Char('机床Z轴当前位置') machine_z_abs_mach = fields.Char('机床Z轴当前位置')
# machine_z_rel_mach = fields.Char('机床Z轴相对工件坐标') machine_z_rel_mach = fields.Char('机床Z轴相对工件坐标')
# machine_z_dis_mach = fields.Char('机床Z轴目标距离') machine_z_dis_mach = fields.Char('机床Z轴目标距离')
# machine_z_axis_load = fields.Char('机床Z轴伺服轴负载') machine_z_axis_load = fields.Char('机床Z轴伺服轴负载')
# machine_tool_num = fields.Char('机床当前刀位号') machine_tool_num = fields.Char('机床当前刀位号')
# machine_program = fields.Char('机床主程序名称') machine_program = fields.Char('机床主程序名称')
# machine_current_prg = fields.Char('机床当前执行指令') machine_current_prg = fields.Char('机床当前执行指令')
# machine_prg_seq = fields.Char('机床当前执行语句号') machine_prg_seq = fields.Char('机床当前执行语句号')
# machine_spindle_speed_set = fields.Char('机床设定主轴速度') machine_spindle_speed_set = fields.Char('机床设定主轴速度')
# machine_act_spindle_speed = fields.Char('机床实际主轴转速') machine_act_spindle_speed = fields.Char('机床实际主轴转速')
# machine_feed_speed_set = fields.Char('机床设定进给速度') machine_feed_speed_set = fields.Char('机床设定进给速度')
# machine_act_feed_speed = fields.Char('机床实际进给速度') machine_act_feed_speed = fields.Char('机床实际进给速度')
# machine_spindle_feed = fields.Char('机床主轴倍率') machine_spindle_feed = fields.Char('机床主轴倍率')
# machine_feed_rate = fields.Char('机床进给倍率') machine_feed_rate = fields.Char('机床进给倍率')
# machine_rapid_feed = fields.Char('机床快速移动倍率') machine_rapid_feed = fields.Char('机床快速移动倍率')
# machine_run_time = fields.Char('机床运行时间') machine_run_time = fields.Char('机床运行时间')
# machine_cut_time = fields.Char('机床切削时间') machine_cut_time = fields.Char('机床切削时间')
# machine_keep_alive_time = fields.Char('机床上电时间') machine_keep_alive_time = fields.Char('机床上电时间')
# machine_circle_time = fields.Char('机床循环时间') machine_circle_time = fields.Char('机床循环时间')
# machine_product_counts = fields.Char('机床加工件数') machine_product_counts = fields.Char('机床加工件数')
# machine_system_date = fields.Char('机床系统日期') machine_system_date = fields.Char('机床系统日期')
# machine_system_time = fields.Char('机床系统时间') machine_system_time = fields.Char('机床系统时间')
# machine_alarm_msg = fields.Char('机床系统报警') machine_alarm_msg = fields.Char('机床系统报警')
# # 刀位配置 # 刀位配置
# tool_num1 = fields.Char('刀位1') tool_num1 = fields.Char('刀位1')
# tool_num2 = fields.Char('刀位2') tool_num2 = fields.Char('刀位2')
# tool_num3 = fields.Char('刀位3') tool_num3 = fields.Char('刀位3')
# tool_num4 = fields.Char('刀位4') tool_num4 = fields.Char('刀位4')
# tool_num5 = fields.Char('刀位5') tool_num5 = fields.Char('刀位5')
# tool_num6 = fields.Char('刀位6') tool_num6 = fields.Char('刀位6')
# tool_num7 = fields.Char('刀位7') tool_num7 = fields.Char('刀位7')
# tool_num8 = fields.Char('刀位8') tool_num8 = fields.Char('刀位8')
# tool_num9 = fields.Char('刀位9') tool_num9 = fields.Char('刀位9')
# tool_num10 = fields.Char('刀位10') tool_num10 = fields.Char('刀位10')
# tool_num11 = fields.Char('刀位11') tool_num11 = fields.Char('刀位11')
# tool_num12 = fields.Char('刀位12') tool_num12 = fields.Char('刀位12')
# tool_num13 = fields.Char('刀位13') tool_num13 = fields.Char('刀位13')
# tool_num14 = fields.Char('刀位14') tool_num14 = fields.Char('刀位14')
# tool_num15 = fields.Char('刀位15') tool_num15 = fields.Char('刀位15')
# tool_num16 = fields.Char('刀位16') tool_num16 = fields.Char('刀位16')
# tool_num17 = fields.Char('刀位17') tool_num17 = fields.Char('刀位17')
# tool_num18 = fields.Char('刀位18') tool_num18 = fields.Char('刀位18')
# tool_num19 = fields.Char('刀位19') tool_num19 = fields.Char('刀位19')
# tool_num20 = fields.Char('刀位20') tool_num20 = fields.Char('刀位20')
# tool_num21 = fields.Char('刀位21') tool_num21 = fields.Char('刀位21')
# tool_num22 = fields.Char('刀位22') tool_num22 = fields.Char('刀位22')
# tool_num23 = fields.Char('刀位23') tool_num23 = fields.Char('刀位23')
# tool_num24 = fields.Char('刀位24') tool_num24 = fields.Char('刀位24')
# 机床采集项目 # 机床采集项目
timestamp = fields.Datetime('时间戳', readonly=True) timestamp = fields.Datetime('时间戳', readonly=True)
status = fields.Boolean('机床在线状态', readonly=True) signed = fields.Integer('刷新间隔', readonly=True)
# run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], string='机床运行状态', status = fields.Boolean('在线状态', readonly=True)
# readonly=True, default='0') time_on = fields.Char('总在线时长', readonly=True)
run_status = fields.Char('机床运行状态', readonly=True) time_on_now = fields.Char('本次在线时长', readonly=True)
run_time = fields.Char('机床累计运行时长', readonly=True) tool_num = fields.Integer('当前刀具', readonly=True)
# 机床系统日期 program = fields.Char('当前程序', readonly=True)
system_date = fields.Char('机床系统日期', readonly=True) run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], string='运行状态',
# 机床系统时间 readonly=True, default='0')
system_time = fields.Char('机床系统时间', readonly=True) run_time = fields.Char('总运行时长', readonly=True)
cut_time = fields.Char('机床累计切削时', readonly=True) cut_time = fields.Char('切削时', readonly=True)
# cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], string='机床当前切削状态', cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], string='切削状态',
# readonly=True, default='0') readonly=True, default='0')
cut_status = fields.Char('机床当前切削状态', readonly=True) spindle_speed = fields.Char('主轴转速', readonly=True)
# 当前程序名
program = fields.Char('机床当前程序', readonly=True)
# 当前刀具号
tool_num = fields.Integer('机床当前刀具号', readonly=True)
# 机床通电开机时间, 机床加工件数, 机床当前操作模式, 开始加工时间, 结束加工时间, 加工程序开始时间, 加工程序结束时间, 待机开始时间,
# 待机结束时间, 机床离线开始时间, 机床离线结束时间, 机床急停状态, 机床主程序名称, 程序运行的状态, 机床当前执行指令, 机床当前执行语句号
# 机床X轴当前位置, 机床Y轴当前位置, 机床Z轴当前位置
machine_power_on_time = fields.Char('机床通电开机时间', readonly=True)
product_counts = fields.Char('机床加工件数', readonly=True)
mode = fields.Char('机床当前操作模式', readonly=True)
start_time = fields.Char('开始加工时间', readonly=True)
end_time = fields.Char('结束加工时间', readonly=True)
program_start_time = fields.Char('加工程序开始时间', readonly=True)
program_end_time = fields.Char('加工程序结束时间', readonly=True)
standby_start_time = fields.Char('待机开始时间', readonly=True)
standby_end_time = fields.Char('待机结束时间', readonly=True)
offline_start_time = fields.Char('机床离线开始时间', readonly=True)
offline_end_time = fields.Char('机床离线结束时间', readonly=True)
emg_status = fields.Char('机床急停状态', readonly=True)
program_name = fields.Char('机床主程序名称', readonly=True)
program_status = fields.Char('程序运行状态', readonly=True)
current_program = fields.Char('机床当前执行指令', readonly=True)
current_program_seq = fields.Char('机床当前执行语句号', readonly=True)
x_abs_pos = fields.Char('机床X轴当前位置(mm)', readonly=True)
y_abs_pos = fields.Char('机床Y轴当前位置(mm)', readonly=True)
z_abs_pos = fields.Char('机床Z轴当前位置(mm)', readonly=True)
# 机床设定进给速度, 机床实际进给速度, 机床设定主轴转速, 机床实际主轴转速, 机床主轴负载, 机床X轴伺服轴负载, 机床Y轴伺服轴负载 tool_num_process_time1 = fields.Char('刀位1', readonly=True, default='0')
# 机床Z轴伺服轴负载, 机床快速移动倍率, 机床进给倍率, 机床X轴机械坐标, 机床Y轴机械坐标, 机床Z轴机械坐标, 机床X轴相对工件坐标 tool_num_process_time2 = fields.Char('刀位2', readonly=True, default='0')
# 机床Y轴相对工件坐标, 机床Z轴相对工件坐标, 机床X轴目标距离, 机床Y轴目标距离, 机床Z轴目标距离 tool_num_process_time3 = fields.Char('刀位3', readonly=True, default='0')
feed_speed_set = fields.Char('机床设定进给速度(mm/min)', readonly=True) tool_num_process_time4 = fields.Char('刀位4', readonly=True, default='0')
act_feed_speed = fields.Char('机床实际进给速度(mm/min)', readonly=True) tool_num_process_time5 = fields.Char('刀位5', readonly=True, default='0')
spindle_speed_set = fields.Char('机床设定主轴转速(r/min)', readonly=True) tool_num_process_time6 = fields.Char('刀位6', readonly=True, default='0')
act_spindle_speed = fields.Char('机床实际主轴转速(r/min)', readonly=True) tool_num_process_time7 = fields.Char('刀位7', readonly=True, default='0')
spindle_load = fields.Char('机床主轴负载(%)', readonly=True) tool_num_process_time8 = fields.Char('刀位8', readonly=True, default='0')
x_axis_load = fields.Char('机床X轴伺服轴负载(%)', readonly=True) tool_num_process_time9 = fields.Char('刀位9', readonly=True, default='0')
y_axis_load = fields.Char('机床Y轴伺服轴负载(%)', readonly=True) tool_num_process_time10 = fields.Char('刀位10', readonly=True, default='0')
z_axis_load = fields.Char('机床Z轴伺服轴负载(%)', readonly=True) tool_num_process_time11 = fields.Char('刀位11', readonly=True, default='0')
rapid_feed = fields.Char('机床快速移动倍率(%)', readonly=True) tool_num_process_time12 = fields.Char('刀位12', readonly=True, default='0')
feed_rate = fields.Char('机床进给倍率(%)', readonly=True) tool_num_process_time13 = fields.Char('刀位13', readonly=True, default='0')
x_mach_coord = fields.Char('机床X轴机械坐标(mm)', readonly=True) tool_num_process_time14 = fields.Char('刀位14', readonly=True, default='0')
y_mach_coord = fields.Char('机床Y轴机械坐标(mm)', readonly=True) tool_num_process_time15 = fields.Char('刀位15', readonly=True, default='0')
z_mach_coord = fields.Char('机床Z轴机械坐标(mm)', readonly=True) tool_num_process_time16 = fields.Char('刀位16', readonly=True, default='0')
x_rel_coord = fields.Char('机床X轴相对工件坐标(mm)', readonly=True) tool_num_process_time17 = fields.Char('刀位17', readonly=True, default='0')
y_rel_coord = fields.Char('机床Y轴相对工件坐标(mm)', readonly=True) tool_num_process_time18 = fields.Char('刀位18', readonly=True, default='0')
z_rel_coord = fields.Char('机床Z轴相对工件坐标(mm)', readonly=True) tool_num_process_time19 = fields.Char('刀位19', readonly=True, default='0')
x_dis_coord = fields.Char('机床X轴目标距离(mm)', readonly=True) tool_num_process_time20 = fields.Char('刀位20', readonly=True, default='0')
y_dis_coord = fields.Char('机床Y轴目标距离(mm)', readonly=True) tool_num_process_time21 = fields.Char('刀位21', readonly=True, default='0')
z_dis_coord = fields.Char('机床Z轴目标距离(mm)', readonly=True) tool_num_process_time22 = fields.Char('刀位22', readonly=True, default='0')
tool_num_process_time23 = fields.Char('刀位23', readonly=True, default='0')
# 故障报警时间, 故障报警信息, 故障消除时间(复原时间) tool_num_process_time24 = fields.Char('刀位24', readonly=True, default='0')
alarm_time = fields.Char('故障报警时间', readonly=True)
alarm_msg = fields.Char('故障报警信息', readonly=True)
clear_time = fields.Char('故障消除时间(复原时间)', readonly=True)
# 当前程序名, 机床累计运行时间, 机床系统日期, 机床系统时间, 当前刀具号, 机床循环时间
class WorkCenterBarcode(models.Model): class WorkCenterBarcode(models.Model):
@@ -290,59 +259,39 @@ class WorkCenterBarcode(models.Model):
button_compensation_state = fields.Boolean(string='是否已经补偿', readonly=True) button_compensation_state = fields.Boolean(string='是否已经补偿', readonly=True)
button_up_all_state = fields.Boolean(string='是否已经全部下发', readonly=True) button_up_all_state = fields.Boolean(string='是否已经全部下发', readonly=True)
machine_tool_id = fields.Many2one('sf.machine_tool.type', string='机床') machine_tool_id = fields.Many2one('sf.machine_tool.type', string='机床')
# machine_tool_name = fields.Char(string='机床名称', default='未知机床', compute='_run_info', readonly=True) machine_tool_name = fields.Char(string='机床名称', default='未知机床', compute='_run_info', readonly=True)
# machine_tool_type_id = fields.Char(string='机床型号', default='未知型号', compute='_run_info', readonly=True) machine_tool_type_id = fields.Char(string='机床型号', default='未知型号', compute='_run_info', readonly=True)
# machine_tool_status = fields.Boolean(string='在线状态', compute='_run_info', readonly=True) machine_tool_status = fields.Boolean(string='在线状态', compute='_run_info', readonly=True)
# machine_tool_run_status = fields.Selection([('0', '关机中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')],
# string='运行状态', compute='_run_info', readonly=True, default='0')
# machine_tool_timestamp = fields.Datetime('时间戳', compute='_run_info', readonly=True)
# machine_tool_time_on = fields.Char('总在线时长', compute='_run_info', readonly=True)
# machine_tool_time_on_now = fields.Char('本次在线时长', compute='_run_info', readonly=True)
# machine_tool_tool_num = fields.Integer('当前刀具', compute='_run_info', readonly=True)
# machine_tool_program = fields.Char('当前程序', compute='_run_info', readonly=True)
# machine_tool_machine_ip = fields.Char('机床IP', compute='_run_info', readonly=True)
# machine_tool_cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')],
# string='切削状态', compute='_run_info', readonly=True, default='0')
# machine_tool_compensation_value_x = fields.Char('x补偿值', compute='_run_info', readonly=True)
# machine_tool_compensation_value_y = fields.Char('y补偿值', compute='_run_info', readonly=True)
machine_tool_name = fields.Char(string='机床名称', default='未知机床', readonly=True)
machine_tool_type_id = fields.Char(string='机床型号', default='未知型号', readonly=True)
machine_tool_status = fields.Boolean(string='在线状态', readonly=True)
machine_tool_run_status = fields.Selection([('0', '关机中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], machine_tool_run_status = fields.Selection([('0', '关机中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')],
string='运行状态', readonly=True, default='0') string='运行状态', compute='_run_info', readonly=True, default='0')
machine_tool_timestamp = fields.Datetime('时间戳', readonly=True) machine_tool_timestamp = fields.Datetime('时间戳', compute='_run_info', readonly=True)
machine_tool_time_on = fields.Char('总在线时长', readonly=True) machine_tool_time_on = fields.Char('总在线时长', compute='_run_info', readonly=True)
machine_tool_time_on_now = fields.Char('本次在线时长', readonly=True) machine_tool_time_on_now = fields.Char('本次在线时长', compute='_run_info', readonly=True)
machine_tool_tool_num = fields.Integer('当前刀具', readonly=True) machine_tool_tool_num = fields.Integer('当前刀具', compute='_run_info', readonly=True)
machine_tool_program = fields.Char('当前程序', readonly=True) machine_tool_program = fields.Char('当前程序', compute='_run_info', readonly=True)
machine_tool_machine_ip = fields.Char('机床IP', readonly=True) machine_tool_machine_ip = fields.Char('机床IP', compute='_run_info', readonly=True)
machine_tool_cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], machine_tool_cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')],
string='切削状态', readonly=True, default='0') string='切削状态', compute='_run_info', readonly=True, default='0')
machine_tool_compensation_value_x = fields.Char('x补偿值', readonly=True) machine_tool_compensation_value_x = fields.Char('x补偿值', compute='_run_info', readonly=True)
machine_tool_compensation_value_y = fields.Char('y补偿值', readonly=True) machine_tool_compensation_value_y = fields.Char('y补偿值', compute='_run_info', readonly=True)
# 工单状态
delivery_records = fields.One2many('delivery.record', 'workorder_id', string="下发记录") delivery_records = fields.One2many('delivery.record', 'workorder_id', string="下发记录")
@api.depends('equipment_id.timestamp') @api.depends('equipment_id.timestamp')
def _run_info(self): def _run_info(self):
# self.machine_tool_name = '1号机床' # self.machine_tool_name = '1号机床'
# self.machine_tool_name = self.equipment_id.name self.machine_tool_name = self.equipment_id.name
# self.machine_tool_type_id = self.equipment_id.type_id.name self.machine_tool_type_id = self.equipment_id.type_id.name
# self.machine_tool_status = self.equipment_id.status self.machine_tool_status = self.equipment_id.status
# self.machine_tool_run_status = self.equipment_id.run_status self.machine_tool_run_status = self.equipment_id.run_status
# self.machine_tool_timestamp = self.equipment_id.timestamp self.machine_tool_timestamp = self.equipment_id.timestamp
# self.machine_tool_time_on = self.equipment_id.time_on self.machine_tool_time_on = self.equipment_id.time_on
# self.machine_tool_time_on_now = self.equipment_id.time_on_now self.machine_tool_time_on_now = self.equipment_id.time_on_now
# self.machine_tool_tool_num = self.equipment_id.tool_num self.machine_tool_tool_num = self.equipment_id.tool_num
# self.machine_tool_program = self.equipment_id.program self.machine_tool_program = self.equipment_id.program
# self.machine_tool_machine_ip = self.equipment_id.machine_ip self.machine_tool_machine_ip = self.equipment_id.machine_ip
# self.machine_tool_cut_status = self.equipment_id.cut_status self.machine_tool_cut_status = self.equipment_id.cut_status
# self.machine_tool_compensation_value_x = self.compensation_value_x self.machine_tool_compensation_value_x = self.compensation_value_x
# self.machine_tool_compensation_value_y = self.compensation_value_y self.machine_tool_compensation_value_y = self.compensation_value_y
pass
def compensation(self): def compensation(self):

View File

@@ -8,14 +8,11 @@ _logger = logging.getLogger(__name__)
class ResBFMConfigSettings(models.TransientModel): class ResBFMConfigSettings(models.TransientModel):
_inherit = 'res.config.settings' _inherit = 'res.config.settings'
# bfm_url = fields.Selection( bfm_url = fields.Selection(
# [("https://bfm.cs.jikimo.com", "开发环境(https://bfm.cs.jikimo.com)"), [("https://bfm.cs.jikimo.com", "开发环境(https://bfm.cs.jikimo.com)"),
# ("https://bfm.t.jikimo.com", "测试环境(https://bfm.t.jikimo.com)"), ("https://bfm.t.jikimo.com", "测试环境(https://bfm.t.jikimo.com)"),
# ("https://bfm.r.jikimo.com", "预发布环境(https://bfm.r.jikimo.com)"), # ("正式环境", "https://bfm.jikimo.com")], string='bfm环境', store=True)
# # ("正式环境", "https://bfm.jikimo.com")], string='bfm环境', store=True) ("https://bfm.jikimo.com", "正式环境(https://bfm.jikimo.com)")], string='bfm环境', store=True)
# ("https://bfm.jikimo.com", "正式环境(https://bfm.jikimo.com)")], string='bfm环境', store=True)
bfm_url_new = fields.Char('业务平台环境路径', placeholder='请输入当前对应的业务平台环境路径')
@api.model @api.model
def get_values(self): def get_values(self):
@@ -25,14 +22,14 @@ class ResBFMConfigSettings(models.TransientModel):
""" """
values = super(ResBFMConfigSettings, self).get_values() values = super(ResBFMConfigSettings, self).get_values()
config = self.env['ir.config_parameter'].sudo() config = self.env['ir.config_parameter'].sudo()
bfm_url_new = config.get_param('bfm_url_new', default='') bfm_url = config.get_param('bfm_url', default='')
values.update( values.update(
bfm_url_new=bfm_url_new, bfm_url=bfm_url,
) )
return values return values
def set_values(self): def set_values(self):
super(ResBFMConfigSettings, self).set_values() super(ResBFMConfigSettings, self).set_values()
ir_config = self.env['ir.config_parameter'].sudo() ir_config = self.env['ir.config_parameter'].sudo()
ir_config.set_param("bfm_url_new", self.bfm_url_new or "") ir_config.set_param("bfm_url", self.bfm_url or "")

View File

@@ -25,10 +25,6 @@
<filter string="人工编程" name="manual_quotation" domain="[('manual_quotation', '=', True)]"/> <filter string="人工编程" name="manual_quotation" domain="[('manual_quotation', '=', True)]"/>
<filter string="自动编程" name="no_manual_quotation" domain="[('manual_quotation', '=', False)]"/> <filter string="自动编程" name="no_manual_quotation" domain="[('manual_quotation', '=', False)]"/>
</xpath> </xpath>
<xpath expr="//field[@name='production_id']" position="before">
<field name="product_tmpl_name"/>
<field name="rfid_code"/>
</xpath>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -5,46 +5,39 @@
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
<field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/> <field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<!-- <xpath expr="//header" position="inside">&ndash;&gt;--> <xpath expr="//header" position="inside">
<!-- <button string="程序下载" name="cnc_file_download" type="object" class="oe_highlight" attrs='{"invisible": ["|",--> <button string="程序下载" name="cnc_file_download" type="object" class="oe_highlight" attrs='{"invisible": ["|",
<!-- ("user_permissions","=",False),("routing_type","!=","CNC加工")]}'/>--> ("user_permissions","=",False),("routing_type","!=","CNC加工")]}'/>
<!-- </xpath>-->
<xpath expr="//page//field[@name='cnc_ids']" position="before">
<group>
<group>
<field name="compensation_value_x"/>
<field name="compensation_value_y"/>
</group>
<div>
<div>
<!-- <field name="button_compensation_state" attrs='{"invisible": ["|",-->
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>-->
<!-- <span>&#32;</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>&#32;</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>&#32;</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>&#32;</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>
</xpath> </xpath>
<xpath expr="//page//field[@name='cnc_ids']" position="before">
<group>
<group>
<field name="compensation_value_x"/>
<field name="compensation_value_y"/>
</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>&#32;</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>&#32;</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>&#32;</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>
</xpath>
</field> </field>
</record> </record>

View File

@@ -9,9 +9,9 @@
<tree> <tree>
<field name="sequence_number"/> <field name="sequence_number"/>
<field name="program_name"/> <field name="program_name"/>
<field name="cnc_id" string="文件"/>
<field name="functional_tool_type_id"/> <field name="functional_tool_type_id"/>
<field name="cutting_tool_name"/> <field name="cutting_tool_name"/>
<field name="tool_state"/>
<field name="cutting_tool_no"/> <field name="cutting_tool_no"/>
<field name="processing_type"/> <field name="processing_type"/>
<field name="margin_x_y"/> <field name="margin_x_y"/>

View File

@@ -19,7 +19,7 @@
<!-- attrs='{"invisible": ["|",("state","!=","progress"), --> <!-- attrs='{"invisible": ["|",("state","!=","progress"), -->
<!-- ("user_permissions","!=",True)]}'/> --> <!-- ("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="是否确认下发此程序" 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"), context="{'default_sf_cnc_processing_id': id}" attrs='{"invisible": ["|",("state","!=","progress"),
("user_permissions","!=",True)]}'/> ("user_permissions","!=",True)]}'/>
<!-- <button string="下发" name="up" type="object" class="btn-primary" confirm="是否确认下发此程序"--> <!-- <button string="下发" name="up" type="object" class="btn-primary" confirm="是否确认下发此程序"-->

View File

@@ -13,138 +13,294 @@
<page string="机床运行状态" attrs="{'invisible': [('equipment_type', '!=', '机床')]}"> <page string="机床运行状态" attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
<group string='状态监控'> <group string='状态监控'>
<group> <group>
<!-- <field name="timestamp"/> --> <field name="timestamp"/>
<field name="signed"/>
<field name="status"/> <field name="status"/>
<field name="run_status"/> <field name="time_on"/>
<field name="run_time"/> <field name="time_on_now"/>
<field name="system_date"/>
</group> </group>
<group> <group>
<field name="run_status"/>
<field name="run_time"/>
<field name="cut_status"/> <field name="cut_status"/>
<field name="cut_time"/>
<!-- <field name="cut_time"/> --> <!-- <field name="cut_time"/> -->
<field name="program"/> <field name="program"/>
<field name="tool_num"/> <field name="tool_num"/>
<field name="spindle_speed"/>
</group> </group>
</group> </group>
<!-- <group string='刀位统计'> -->
<!-- <group> -->
<!-- <group> -->
<!-- <field name="tool_num_process_time1"/> -->
<!-- <field name="tool_num_process_time5"/> -->
<!-- <field name="tool_num_process_time9"/> -->
<!-- <field name="tool_num_process_time13"/> -->
<!-- <field name="tool_num_process_time17"/> -->
<!-- <field name="tool_num_process_time21"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="tool_num_process_time2"/> -->
<!-- <field name="tool_num_process_time6"/> -->
<!-- <field name="tool_num_process_time10"/> -->
<!-- <field name="tool_num_process_time14"/> -->
<!-- <field name="tool_num_process_time18"/> -->
<!-- <field name="tool_num_process_time22"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- <group> -->
<!-- <group> -->
<!-- <field name="tool_num_process_time3"/> -->
<!-- <field name="tool_num_process_time7"/> -->
<!-- <field name="tool_num_process_time11"/> -->
<!-- <field name="tool_num_process_time15"/> -->
<!-- <field name="tool_num_process_time19"/> -->
<!-- <field name="tool_num_process_time23"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="tool_num_process_time4"/> -->
<!-- <field name="tool_num_process_time8"/> -->
<!-- <field name="tool_num_process_time12"/> -->
<!-- <field name="tool_num_process_time16"/> -->
<!-- <field name="tool_num_process_time20"/> -->
<!-- <field name="tool_num_process_time24"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- </group> -->
<!-- <div class="o_address_format"> -->
<!-- <label for="tool_num_process_time1" string="刀位1"/> -->
<!-- <field name="tool_num_process_time1" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time2" string="刀位2"/> -->
<!-- <field name="tool_num_process_time2" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time3" string="刀位3"/> -->
<!-- <field name="tool_num_process_time3" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time4" string="刀位4"/> -->
<!-- <field name="tool_num_process_time4" class="o_form_label"/> -->
<!-- <div></div> -->
<!-- <label for="tool_num_process_time5" string="刀位5"/> -->
<!-- <field name="tool_num_process_time5" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time6" string="刀位6"/> -->
<!-- <field name="tool_num_process_time6" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time7" string="刀位7"/> -->
<!-- <field name="tool_num_process_time7" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time8" string="刀位8"/> -->
<!-- <field name="tool_num_process_time8" class="o_form_label"/> -->
<!-- <div></div> -->
<!-- <label for="tool_num_process_time9" string="刀位9"/> -->
<!-- <field name="tool_num_process_time9" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time10" string="刀位10"/> -->
<!-- <field name="tool_num_process_time10" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time11" string="刀位11"/> -->
<!-- <field name="tool_num_process_time11" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time12" string="刀位12"/> -->
<!-- <field name="tool_num_process_time12" class="o_form_label"/> -->
<!-- <div></div> -->
<!-- <label for="tool_num_process_time13" string="刀位13"/> -->
<!-- <field name="tool_num_process_time13" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time14" string="刀位14"/> -->
<!-- <field name="tool_num_process_time14" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time15" string="刀位15"/> -->
<!-- <field name="tool_num_process_time15" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time16" string="刀位16"/> -->
<!-- <field name="tool_num_process_time16" class="o_form_label"/> -->
<!-- <div></div> -->
<!-- <label for="tool_num_process_time17" string="刀位17"/> -->
<!-- <field name="tool_num_process_time17" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time18" string="刀位18"/> -->
<!-- <field name="tool_num_process_time18" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time19" string="刀位19"/> -->
<!-- <field name="tool_num_process_time19" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time20" string="刀位20"/> -->
<!-- <field name="tool_num_process_time20" class="o_form_label"/> -->
<!-- <div></div> -->
<!-- <label for="tool_num_process_time21" string="刀位21"/> -->
<!-- <field name="tool_num_process_time21" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time22" string="刀位22"/> -->
<!-- <field name="tool_num_process_time22" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time23" string="刀位23"/> -->
<!-- <field name="tool_num_process_time23" class="o_form_label"/> -->
<!-- <span>&amp;nbsp;</span> -->
<!-- <label for="tool_num_process_time24" string="刀位24"/> -->
<!-- <field name="tool_num_process_time24" class="o_form_label"/> -->
<!-- </div> -->
<!-- </group> -->
</page> </page>
<page string="机床运行数据" attrs="{'invisible': [('equipment_type', '!=', '机床')]}"> <page string="机床运行数据" attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
<group string="运行数据"> <!-- <group string="机床配置">--> -->
<group> <group string="ftp相关">
<field name="machine_power_on_time"/> <group>
<field name="product_counts"/> <field name="ftp_num"/>
<field name="mode"/> <field name="ftp_pwd"/>
<field name="start_time"/> <field name="ftp_host"/>
<field name="end_time"/> </group>
<field name="program_start_time"/> <group>
<field name="program_end_time"/> <field name="ftp_port"/>
<field name="standby_start_time"/> <field name="ftp_remote_path"/>
<field name="standby_end_time"/> </group>
<field name="offline_start_time"/>
<field name="offline_end_time"/>
<field name="emg_status"/>
<field name="program_name"/>
<field name="program_status"/>
<field name="current_program"/>
<field name="current_program_seq"/>
<field name="x_abs_pos"/>
<field name="y_abs_pos"/>
<field name="z_abs_pos"/>
</group> </group>
<group> <group string="补偿值相关">
<field name="feed_speed_set"/> <group>
<field name="act_feed_speed"/> <field name="x_compensation_node"/>
<field name="spindle_speed_set"/> </group>
<field name="act_spindle_speed"/> <group>
<field name="spindle_load"/> <field name="y_compensation_node"/>
<field name="x_axis_load"/> </group>
<field name="y_axis_load"/> </group>
<field name="z_axis_load"/> <group string="数采相关">
<field name="rapid_feed"/> <group>
<field name="feed_rate"/> <field name="machine_ip"/>
<field name="x_mach_coord"/> <field name="machine_signed"/>
<field name="y_mach_coord"/> <field name="machine_status"/>
<field name="z_mach_coord"/> <field name="machine_cnc_type"/>
<field name="x_rel_coord"/> <field name="machine_axis_count"/>
<field name="y_rel_coord"/> <field name="machine_run_status"/>
<field name="z_rel_coord"/> <field name="machine_emg_status"/>
<field name="x_dis_coord"/> <field name="machine_cut_status"/>
<field name="y_dis_coord"/> <field name="machine_mode"/>
<field name="z_dis_coord"/> <field name="machine_spindle_load"/>
<field name="machine_x_mach"/>
<field name="machine_x_abs_mach"/>
<field name="machine_x_rel_mach"/>
<field name="machine_x_dis_mach"/>
<field name="machine_x_axis_load"/>
<field name="machine_y_mach"/>
<field name="machine_y_abs_mach"/>
<field name="machine_y_rel_mach"/>
<field name="machine_y_dis_mach"/>
<field name="machine_y_axis_load"/>
<field name="machine_z_mach"/>
<field name="machine_z_abs_mach"/>
</group>
<group>
<field name="machine_z_rel_mach"/>
<field name="machine_z_dis_mach"/>
<field name="machine_z_axis_load"/>
<field name="machine_tool_num"/>
<field name="machine_program"/>
<field name="machine_current_prg"/>
<field name="machine_prg_seq"/>
<field name="machine_spindle_speed_set"/>
<field name="machine_act_spindle_speed"/>
<field name="machine_feed_speed_set"/>
<field name="machine_act_feed_speed"/>
<field name="machine_spindle_feed"/>
<field name="machine_feed_rate"/>
<field name="machine_rapid_feed"/>
<field name="machine_run_time"/>
<field name="machine_cut_time"/>
<field name="machine_keep_alive_time"/>
<field name="machine_circle_time"/>
<field name="machine_product_counts"/>
<field name="machine_system_date"/>
<field name="machine_system_time"/>
<field name="machine_alarm_msg"/>
</group>
</group> </group>
</group>
<!-- <group string="ftp相关"> -->
<!-- <group> -->
<!-- <field name="ftp_num"/> -->
<!-- <field name="ftp_pwd"/> -->
<!-- <field name="ftp_host"/> -->
<!-- </group> --> <!-- </group> -->
<!-- <group> -->
<!-- <field name="ftp_port"/> -->
<!-- <field name="ftp_remote_path"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- <group string="补偿值相关"> -->
<!-- <group> -->
<!-- <field name="x_compensation_node"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="y_compensation_node"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- <group string="数采相关"> -->
<!-- <group> -->
<!-- <field name="machine_ip"/> -->
<!-- <field name="machine_signed"/> -->
<!-- <field name="machine_status"/> -->
<!-- <field name="machine_cnc_type"/> -->
<!-- <field name="machine_axis_count"/> -->
<!-- <field name="machine_run_status"/> -->
<!-- <field name="machine_emg_status"/> -->
<!-- <field name="machine_cut_status"/> -->
<!-- <field name="machine_mode"/> -->
<!-- <field name="machine_spindle_load"/> -->
<!-- <field name="machine_x_mach"/> -->
<!-- <field name="machine_x_abs_mach"/> -->
<!-- <field name="machine_x_rel_mach"/> -->
<!-- <field name="machine_x_dis_mach"/> -->
<!-- <field name="machine_x_axis_load"/> -->
<!-- <field name="machine_y_mach"/> -->
<!-- <field name="machine_y_abs_mach"/> -->
<!-- <field name="machine_y_rel_mach"/> -->
<!-- <field name="machine_y_dis_mach"/> -->
<!-- <field name="machine_y_axis_load"/> -->
<!-- <field name="machine_z_mach"/> -->
<!-- <field name="machine_z_abs_mach"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="machine_z_rel_mach"/> -->
<!-- <field name="machine_z_dis_mach"/> -->
<!-- <field name="machine_z_axis_load"/> -->
<!-- <field name="machine_tool_num"/> -->
<!-- <field name="machine_program"/> -->
<!-- <field name="machine_current_prg"/> -->
<!-- <field name="machine_prg_seq"/> -->
<!-- <field name="machine_spindle_speed_set"/> -->
<!-- <field name="machine_act_spindle_speed"/> -->
<!-- <field name="machine_feed_speed_set"/> -->
<!-- <field name="machine_act_feed_speed"/> -->
<!-- <field name="machine_spindle_feed"/> -->
<!-- <field name="machine_feed_rate"/> -->
<!-- <field name="machine_rapid_feed"/> -->
<!-- <field name="machine_run_time"/> -->
<!-- <field name="machine_cut_time"/> -->
<!-- <field name="machine_keep_alive_time"/> -->
<!-- <field name="machine_circle_time"/> -->
<!-- <field name="machine_product_counts"/> -->
<!-- <field name="machine_system_date"/> -->
<!-- <field name="machine_system_time"/> -->
<!-- <field name="machine_alarm_msg"/> -->
<!-- </group> -->
<!-- </group> -->
</page> </page>
<!-- <page string="刀位配置"> -->
<!-- <group string="刀位配置"> -->
<!-- <group> -->
<!-- <group> -->
<!-- <field name="tool_num1"/> -->
<!-- <field name="tool_num5"/> -->
<!-- <field name="tool_num9"/> -->
<!-- <field name="tool_num13"/> -->
<!-- <field name="tool_num17"/> -->
<!-- <field name="tool_num21"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="tool_num2"/> -->
<!-- <field name="tool_num6"/> -->
<!-- <field name="tool_num10"/> -->
<!-- <field name="tool_num14"/> -->
<!-- <field name="tool_num18"/> -->
<!-- <field name="tool_num22"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- <group> -->
<!-- <group> -->
<!-- <field name="tool_num3"/> -->
<!-- <field name="tool_num7"/> -->
<!-- <field name="tool_num11"/> -->
<!-- <field name="tool_num15"/> -->
<!-- <field name="tool_num19"/> -->
<!-- <field name="tool_num23"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="tool_num4"/> -->
<!-- <field name="tool_num8"/> -->
<!-- <field name="tool_num12"/> -->
<!-- <field name="tool_num16"/> -->
<!-- <field name="tool_num20"/> -->
<!-- <field name="tool_num24"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- </group> -->
<!-- </page> -->
<!-- </notebook> -->
</xpath> </xpath>
</field> </field>
</record> </record>
<!-- 刀具寿命 -->
<!-- <record id="view_cutting_tool_inherited" model="ir.ui.view"> -->
<!-- <field name="name">sf_cutting_tool_extension</field> -->
<!-- <field name="model">sf.cutting_tool.type</field> -->
<!-- <field name="inherit_id" ref="sf_base.form_sf_machine_tool_type"/> -->
<!-- <field name="arch" type="xml"> -->
<!-- <xpath expr="//form//group" position="after"> -->
<!-- <group string='刀具寿命'> -->
<!-- <group> -->
<!-- <field name="total_cut_time"/> -->
<!-- <field name="tool_position"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="predict_life_time"/> -->
<!-- </group> -->
<!-- <div> -->
<!-- <div> -->
<!-- <field name='is_connect_tool_position' invisible='1'/> -->
<!-- <button string="绑定刀位" name="tool_connect_machine" type="object" confirm="是否确认绑定此刀位" -->
<!-- class="btn-primary"/> -->
<!-- attrs='{"invisible": [("is_connect_tool_position","!=", -->
<!-- "False")]}' -->
<!-- <span>&#32;</span> -->
<!-- <button string="解绑刀位" name="tool_unconnect_machine" type="object" confirm="是否解绑此刀位" -->
<!-- class="btn-primary"/> -->
<!-- attrs='{"invisible": [("is_connect_tool_position","!=", -->
<!-- "False")]}' -->
<!-- </div> -->
<!-- </div> -->
<!-- </group> -->
<!-- </xpath> -->
<!-- </field> -->
<!-- </record> -->
</odoo> </odoo>

View File

@@ -14,8 +14,8 @@
<div class="o_setting_left_pane"/> <div class="o_setting_left_pane"/>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<div class="text-muted"> <div class="text-muted">
<label for="bfm_url_new" /> <label for="bfm_url" />
<field name="bfm_url_new" string="业务平台访问地址"/> <field name="bfm_url" string="访问地址"/>
</div> </div>
</div> </div>
<!-- </div> --> <!-- </div> -->

View File

@@ -14,7 +14,7 @@
<!-- <field name="program_ids" domain="[('workorder_id', '=', workorder_id)]"/>--> <!-- <field name="program_ids" domain="[('workorder_id', '=', workorder_id)]"/>-->
</group> </group>
<footer> <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"/> <button string="取消" class="btn-secondary" special="cancel"/>
</footer> </footer>
</form> </form>

View File

@@ -10,21 +10,21 @@ class SfMaintenanceLogs(models.Model):
name = fields.Char(string='名称') name = fields.Char(string='名称')
type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型') type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型')
brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌') brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌')
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='机台号') maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='设备')
maintenance_equipment_oee_id = fields.Many2one('maintenance.equipment.oee', string='设备oee') maintenance_equipment_oee_id = fields.Many2one('maintenance.equipment.oee', string='设备oee')
code_location = fields.Char(string='编码位置') code_location = fields.Char(string='编码位置')
fault_type = fields.Selection( fault_type = fields.Selection(
[('电气类', '电气类'), ('机械类', '机械类'), ('程序类', '程序类'), ('系统类', '系统类')], string='故障类型') [('电气类', '电气类'), ('机械类', '机械类'), ('程序类', '程序类'), ('系统类', '系统类')], string='故障类型')
fault_code = fields.Char(string='故障代码') fault_code = fields.Char(string='故障代码')
fault_alarm_info = fields.Text(string='故障报警信息') fault_alarm_info = fields.Char(string='故障报警信息')
alarm_level = fields.Selection([('一级', '一级(严重)'), ('二级', '二级(中等)'), ('三级', '三级(轻微)')], alarm_level = fields.Selection([('一级', '一级(严重)'), ('二级', '二级(中等)'), ('三级', '三级(轻微)')],
string='报警级别') string='报警级别')
alarm_time = fields.Datetime(string='故障报警时间') alarm_time = fields.Datetime(string='报警时间')
alarm_way = fields.Selection([('文本提示报警', '文本提示报警'), ('声光报警', '声光报警'), ('图文报警', '图文报警')], alarm_way = fields.Selection([('文本提示报警', '文本提示报警'), ('声光报警', '声光报警'), ('图文报警', '图文报警')],
string='报警方式') string='报警方式')
fault_process = fields.Text(string='故障处理方法') fault_process = fields.Text(string='故障处理方法')
operator = fields.Many2one('res.users', string='处理人') operator = fields.Many2one('res.users', string='处理人')
recovery_time = fields.Datetime(string='故障消除时间') recovery_time = fields.Datetime(string='复原时间')
fault_duration = fields.Float(string='故障时长') fault_duration = fields.Float(string='故障时长')
note = fields.Text(string='备注') note = fields.Text(string='备注')
active = fields.Boolean('Active', default=True) active = fields.Boolean('Active', default=True)

View File

@@ -7,23 +7,20 @@ class SfMaintenanceEquipmentOEE(models.Model):
_description = '设备OEE' _description = '设备OEE'
name = fields.Char('设备oee') name = fields.Char('设备oee')
equipment_id = fields.Many2one('maintenance.equipment', '机台号', equipment_id = fields.Many2one('maintenance.equipment', '设备',
domain="[('category_id.equipment_type', '=', '机床'),('state_zc', '=', '已注册')]") domain="[('category_id.equipment_type', '=', '机床'),('state_zc', '=', '已注册')]")
type_id = fields.Many2one('sf.machine_tool.type', '型号', related='equipment_id.type_id') type_id = fields.Many2one('sf.machine_tool.type', '型号', related='equipment_id.type_id')
machine_tool_picture = fields.Binary('设备图片', related='equipment_id.machine_tool_picture') machine_tool_picture = fields.Binary('设备图片', related='equipment_id.machine_tool_picture')
state = fields.Selection( state = fields.Selection(
[("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"), [("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"),
("封存(报废)", "封存(报废)")], ("封存(报废)", "封存(报废)")],
default='正常', string="机床状态", related='equipment_id.state') default='正常', string="机床状态", related='equipment_id.state')
run_time = fields.Float('加工时长(h)') run_time = fields.Float('正常运行总时长(h)')
equipment_time = fields.Float('开机时长(h)') equipment_time = fields.Float('时长(h)')
done_nums = fields.Integer('加工件数') done_nums = fields.Integer('累计加工件数')
utilization_rate = fields.Char('可用') utilization_rate = fields.Char('开动')
fault_time = fields.Float('故障时长') fault_time = fields.Float('故障停机总时长(h)')
fault_nums = fields.Integer('故障次数') fault_nums = fields.Integer('故障次数')
# 故障率
fault_rate = fields.Char('故障率')
# 设备故障日志
sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志', sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志',
related='equipment_id.sf_maintenance_logs_ids') related='equipment_id.sf_maintenance_logs_ids')
oee_logs = fields.One2many('maintenance.equipment.oee.logs', 'equipment_oee_id', string='运行日志') oee_logs = fields.One2many('maintenance.equipment.oee.logs', 'equipment_oee_id', string='运行日志')
@@ -41,52 +38,12 @@ class SfMaintenanceEquipmentOEELog(models.Model):
_name = 'maintenance.equipment.oee.logs' _name = 'maintenance.equipment.oee.logs'
_description = '设备运行日志' _description = '设备运行日志'
equipment_id = fields.Many2one('maintenance.equipment', '机台号') name = fields.Char('运行日志')
equipment_code = fields.Char('设备编码') run_time = fields.Datetime('时间')
name = fields.Char('设备名称', readonly='True') state = fields.Selection([("开机", "开机"), ("关机", "关机"), ("等待", "等待"), ("开始加工", "开始加工"),
machine_tool_picture = fields.Binary('设备图片') ("结束加工", "结束加工"), ("故障", "故障"),
type_id = fields.Many2one('sf.machine_tool.type', '品牌型号')
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
("检修", "检修"), ("保养", "保养")], default="", string="实时状态")
online_time = fields.Char('开机时长')
offline_time = fields.Char('关机时长')
offline_nums = fields.Integer('关机次数')
# 待机时长
idle_time = fields.Char('待机时长')
# 待机率
idle_rate = fields.Char('待机率')
work_time = fields.Char('加工时长')
work_rate = fields.Char('可用率')
fault_time = fields.Char('故障时长')
fault_rate = fields.Char('故障率')
fault_nums = fields.Integer('故障次数')
detail_ids = fields.One2many('maintenance.equipment.oee.log.detail', 'log_id', string='日志详情')
# maintenance_time = fields.Char('维保时长')
# work_nums = fields.Integer('加工件数')
equipment_oee_id = fields.Many2one('maintenance.equipment.oee', '设备OEE')
@api.onchange('equipment_id')
def get_name(self):
self.name = self.equipment_id.name
self.equipment_code = self.equipment_id.code
# 设备运行日志详情
class SfMaintenanceEquipmentOEELogDetail(models.Model):
_name = 'maintenance.equipment.oee.log.detail'
_description = '设备运行日志详情'
sequence = fields.Integer('序号')
time = fields.Datetime('时间')
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
("检修", "检修"), ("保养", "保养")], default="", string="事件/状态") ("检修", "检修"), ("保养", "保养")], default="", string="事件/状态")
production_id = fields.Many2one('mrp.production', '加工') workorder_id = fields.Char('加工')
time = fields.Char('持续时长')
log_id = fields.Many2one('maintenance.equipment.oee.logs', '日志') color = fields.Char('颜色', default=1)
equipment_oee_id = fields.Many2one('maintenance.equipment.oee', '设备OEE')

View File

@@ -67,6 +67,3 @@ access_sf_cutting_tool_type_admin_sf_group_equipment_user,sf_cutting_tool_type_a
access_sf_cutting_tool_type_group_purchase_director_sf_group_equipment_user,sf_cutting_tool_type_group_purchase_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0 access_sf_cutting_tool_type_group_purchase_director_sf_group_equipment_user,sf_cutting_tool_type_group_purchase_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
access_sf_cutting_tool_type_group_sale_director_sf_group_equipment_user,sf_cutting_tool_type_group_sale_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0 access_sf_cutting_tool_type_group_sale_director_sf_group_equipment_user,sf_cutting_tool_type_group_sale_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
access_sf_cutting_tool_type_group_plan_director_sf_group_equipment_user,sf_cutting_tool_type_group_plan_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0 access_sf_cutting_tool_type_group_plan_director_sf_group_equipment_user,sf_cutting_tool_type_group_plan_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
access_maintenance_equipment_oee_logs,maintenance_equipment_oee_logs,model_maintenance_equipment_oee_logs,sf_maintenance.sf_group_equipment_manager,1,1,1,1
access_maintenance_equipment_oee_log_detail,maintenance_equipment_oee_log_detail,model_maintenance_equipment_oee_log_detail,sf_maintenance.sf_group_equipment_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
67
68
69

View File

@@ -14,7 +14,6 @@
<field name="utilization_rate"/> <field name="utilization_rate"/>
<field name="fault_time"/> <field name="fault_time"/>
<field name="fault_nums"/> <field name="fault_nums"/>
<field name="fault_rate"/>
</tree> </tree>
</field> </field>
</record> </record>
@@ -50,19 +49,19 @@
</group> </group>
</group> </group>
<!-- <notebook> --> <notebook>
<!-- <page string="运行日志"> --> <page string="运行日志">
<!-- <field name="oee_logs"> --> <field name="oee_logs">
<!-- <tree create="1" edit="1" delete="1" editable="bottom"> --> <tree create="1" edit="1" delete="1" editable="bottom">
<!-- <field name = 'run_time'/> --> <field name = 'run_time'/>
<!-- <field name = 'state'/> --> <field name = 'state'/>
<!-- <field name = 'workorder_id'/> --> <field name = 'workorder_id'/>
<!-- <field name = 'time'/> --> <field name = 'time'/>
<!-- <field name = 'color' widget="color"/> --> <field name = 'color' widget="color"/>
<!-- </tree> --> </tree>
<!-- </field> --> </field>
<!-- </page> --> </page>
<!-- </notebook> --> </notebook>
</sheet> </sheet>
</form> </form>
</field> </field>

View File

@@ -7,20 +7,22 @@
<field name="model">sf.maintenance.logs</field> <field name="model">sf.maintenance.logs</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="code"/>
<field name="type" optional="hide"/> <field name="type" optional="hide"/>
<field name="brand"/> <field name="brand"/>
<field name="maintenance_equipment_id"/> <field name="maintenance_equipment_id"/>
<field name="code_location" optional="hide"/> <field name="code_location" optional="hide"/>
<field name="fault_type"/>
<field name="fault_code" optional="hide"/> <field name="fault_code" optional="hide"/>
<field name="alarm_time"/>
<field name="fault_alarm_info"/> <field name="fault_alarm_info"/>
<field name="alarm_level" optional="hide"/> <field name="alarm_level" optional="hide"/>
<field name="alarm_time"/>
<field name="alarm_way" optional="hide"/> <field name="alarm_way" optional="hide"/>
<field name="fault_process" optional="hide"/> <field name="fault_process"/>
<field name="operator" optional="hide"/> <field name="operator"/>
<field name="recovery_time"/> <field name="recovery_time"/>
<field name="fault_duration"/> <field name="fault_duration"/>
<field name="note" optional="hide"/> <field name="note"/>
</tree> </tree>
</field> </field>
</record> </record>
@@ -43,32 +45,25 @@
<group> <group>
<group> <group>
<!-- <field name="name"/> --> <field name="name"/>
<!-- <field name="type" required="1" widget="radio" options="{'horizontal': true}"/> --> <field name="type" required="1" widget="radio" options="{'horizontal': true}"/>
<field name="maintenance_equipment_id"/>
<field name="brand"/> <field name="brand"/>
<field name="alarm_time"/> <field name="maintenance_equipment_id"/>
<field name="fault_alarm_info"/> <field name="code_location"/>
<field name="fault_type" required="1" widget="radio" options="{'horizontal': true}"/>
<!-- <field name="code_location"/> --> <field name="fault_code"/>
<!-- <field name="fault_type" required="1" widget="radio" options="{'horizontal': true}"/> --> <field name="fault_process"/>
<!-- <field name="fault_code"/> -->
</group> </group>
<group> <group>
<field name="fault_alarm_info"/>
<field name="alarm_time"/>
<field name="alarm_way" required="1" widget="radio" options="{'horizontal': true}"/>
<field name="operator"/> <field name="operator"/>
<field name="fault_process"/>
<!-- <field name="alarm_way" required="1" widget="radio" options="{'horizontal': true}"/> -->
<field name="recovery_time"/> <field name="recovery_time"/>
<field name="fault_duration"/> <field name="fault_duration"/>
<field name="note"/>
</group> </group>
</group>
<group>
<field name="note"/>
</group> </group>
</sheet> </sheet>
</form> </form>
@@ -105,246 +100,6 @@
</field> </field>
</record> </record>
<!-- 设备运行日志 -->
<record id="view_maintenance_logs_run_tree" model="ir.ui.view">
<field name="name">maintenance.logs.run.tree</field>
<field name="model">maintenance.equipment.oee.logs</field>
<field name="arch" type="xml">
<tree>
<field name="equipment_id"/>
</tree>
</field>
</record>
<record id="view_maintenance_logs_run_form" model="ir.ui.view">
<field name="name">maintenance.logs.run.form</field>
<field name="model">maintenance.equipment.oee.logs</field>
<field name="arch" type="xml">
<!-- <form string="设备运行日志"> -->
<!-- <header> -->
<!-- <field name="equipment_id" readonly="1"/> -->
<!-- </header> -->
<!-- <sheet> -->
<!-- <div class="oe_title"> -->
<!-- <h1> -->
<!-- <field name="start_time" readonly="1"/> -->
<!-- </h1> -->
<!-- </div> -->
<!-- <group> -->
<!-- <group> -->
<!-- <field name="stop_time" readonly="1"/> -->
<!-- <field name="duration" readonly="1"/> -->
<!-- <field name="oee" readonly="1"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <field name="note"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- </sheet> -->
<!-- </form> -->
<form string="设备运行日志">
<!-- <header> -->
<!-- <field name="name" readonly="1"/> -->
<!-- </header> -->
<sheet>
<div class="oe_title">
<h1>
<field name="name"/>
</h1>
</div>
<group>
<group>
<group>
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
<field name="type_id"/>
<field name="state"/>
</group>
</group>
<group>
<group>
<!-- <field name="state" nolabel="1"/> -->
<field name="state" string=""/>
</group>
<group>
<field name="machine_tool_picture" widget="image" nolabel="1"/>
</group>
</group>
</group>
<group>
<group>
<group>
<field name="online_time" readonly="1"/>
<field name="offline_time" readonly="1"/>
<field name="fault_rate" readonly="1"/>
</group>
<group>
<field name="offline_nums" readonly="1"/>
<field name="fault_time" readonly="1"/>
<field name="fault_nums" readonly="1"/>
</group>
</group>
<group>
<group>
<field name="idle_time"/>
<field name="idle_rate"/>
</group>
<group>
<field name="work_time"/>
<field name="work_rate"/>
</group>
</group>
</group>
<notebook>
<page string="24H日志详情">
<!-- 筛选出24小时内的日志 -->
<!-- <field name="detail_ids" domain="[('time','&lt;',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> -->
<field name="detail_ids" domain="[('state','ilike','加工')]">
<tree>
<field name="sequence"/>
<field name="time"/>
<field name="state"/>
<field name="production_id"/>
</tree>
<!-- <form> -->
<!-- <field name="sequence"/> -->
<!-- <field name="time"/> -->
<!-- <field name="state"/> -->
<!-- <field name="production_id"/> -->
<!-- </form> -->
</field>
</page>
<page string="历史日志详情">
<field name="detail_ids">
<tree>
<field name="sequence"/>
<field name="time"/>
<field name="state"/>
<field name="production_id"/>
</tree>
<!-- <form> -->
<!-- <field name="sequence"/> -->
<!-- <field name="time"/> -->
<!-- <field name="state"/> -->
<!-- <field name="production_id"/> -->
<!-- </form> -->
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- <record id="view_maintenance_logs_run_search" model="ir.ui.view"> -->
<!-- <field name="name">maintenance.logs.run.search</field> -->
<!-- <field name="model">maintenance.equipment.oee.logs</field> -->
<!-- <field name="arch" type="xml"> -->
<!-- <search> -->
<!-- <field name="equipment_id"/> -->
<!-- <field name="start_time"/> -->
<!-- <field name="stop_time"/> -->
<!-- <field name="duration"/> -->
<!-- <field name="oee"/> -->
<!-- <field name="note"/> -->
<!-- </search> -->
<!-- </field> -->
<!-- </record> -->
<!-- 设备运行日志详情 -->
<record id="view_maintenance_logs_run_detail_tree" model="ir.ui.view">
<field name="name">maintenance.logs.run.detail.tree</field>
<field name="model">maintenance.equipment.oee.log.detail</field>
<field name="arch" type="xml">
<tree>
<field name="sequence"/>
<field name="time"/>
<field name="state"/>
<field name="production_id"/>
</tree>
</field>
</record>
<record id="view_maintenance_logs_run_detail_form" model="ir.ui.view">
<field name="name">maintenance.logs.run.detail.form</field>
<field name="model">maintenance.equipment.oee.log.detail</field>
<field name="arch" type="xml">
<form string="设备运行日志详情">
<sheet>
<group>
<group>
<field name="state"/>
<field name="production_id"/>
</group>
<group>
<field name="sequence"/>
<field name="time"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!-- <record id="view_maintenance_logs_run_detail_search" model="ir.ui.view"> -->
<!-- <field name="name">maintenance.logs.run.detail.search</field> -->
<!-- <field name="model">maintenance.equipment.oee.logs.detail</field> -->
<!-- <field name="arch" type="xml"> -->
<!-- <search> -->
<!-- <field name="equipment_id"/> -->
<!-- <field name="start_time"/> -->
<!-- <field name="stop_time"/> -->
<!-- <field name="duration"/> -->
<!-- <field name="oee"/> -->
<!-- <field name="note"/> -->
<!-- </search> -->
<!-- </field> -->
<!-- </record> -->
<!-- 设备运行日志详情action -->
<!-- <record id="action_maintenance_logs_run_detail" model="ir.actions.act_window"> -->
<!-- <field name="name">设备运行日志详情</field> -->
<!-- <field name="type">ir.actions.act_window</field> -->
<!-- <field name="res_model">maintenance.equipment.oee.logs.detail</field> -->
<!-- <field name="view_mode">tree,form</field> -->
<!-- <field name="view_id" ref="view_maintenance_logs_run_detail_tree"/> -->
<!-- <field name="help" type="html"> -->
<!-- <p class="oe_view_nocontent_create"> -->
<!-- 设备运行日志详情 -->
<!-- </p> -->
<!-- </field> -->
<!-- -->
<!-- </record> -->
<record id="action_maintenance_logs_run" model="ir.actions.act_window">
<field name="name">设备运行日志</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">maintenance.equipment.oee.logs</field>
<!-- <field name="search_view_id" ref="view_maintenance_logs_run_search"/> -->
<field name="view_mode">tree,form</field>
<!-- <field name="view_mode">form</field> -->
<field name="view_id" ref="view_maintenance_logs_run_tree"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
设备运行日志
</p>
</field>
</record>
<menuitem name="设备运行日志" id="menu_maintenance_logs_run" parent="maintenance.menu_m_request"
sequence="10" action="action_maintenance_logs_run"/>
<!-- Action --> <!-- Action -->

View File

@@ -14,12 +14,9 @@
'data': [ 'data': [
'data/stock_data.xml', 'data/stock_data.xml',
'data/empty_racks_data.xml', 'data/empty_racks_data.xml',
'data/panel_data.xml',
'security/group_security.xml', 'security/group_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'wizard/workpiece_delivery_views.xml', 'wizard/workpiece_delivery_views.xml',
'wizard/rework_wizard_views.xml',
'wizard/production_wizard_views.xml',
'views/mrp_views_menus.xml', 'views/mrp_views_menus.xml',
'views/stock_lot_views.xml', 'views/stock_lot_views.xml',
'views/mrp_production_addional_change.xml', 'views/mrp_production_addional_change.xml',

View File

@@ -8,7 +8,7 @@ from odoo.http import request
class Manufacturing_Connect(http.Controller): class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, @http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*") cors="*")
def get_Work_Info(self, **kw): def get_Work_Info(self, **kw):
""" """
@@ -25,8 +25,7 @@ class Manufacturing_Connect(http.Controller):
{'content': ret, 'name': 'AutoDeviceApi/GetWoInfo'}) {'content': ret, 'name': 'AutoDeviceApi/GetWoInfo'})
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
if 'RfidCode' in ret: if 'RfidCode' in ret:
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search([('rfid_code', '=', ret['RfidCode'])])
[('rfid_code', '=', ret['RfidCode']), ('state', '!=', 'rework')])
if workorder: if workorder:
for item in workorder: for item in workorder:
res['Datas'].append({ res['Datas'].append({
@@ -123,8 +122,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
if 'RfidCode' in ret: if 'RfidCode' in ret:
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
[('routing_type', '=', '装夹预调'), ('rfid_code', '=', ret['RfidCode']), ('state', '!=', 'rework')], [('routing_type', '=', '装夹预调'), ('rfid_code', '=', ret['RfidCode'])], limit=1, order='id asc')
limit=1, order='id asc')
if workorder: if workorder:
for item in workorder: for item in workorder:
if item.material_center_point: if item.material_center_point:
@@ -164,8 +162,7 @@ class Manufacturing_Connect(http.Controller):
routing_type = ret['CraftId'] routing_type = ret['CraftId']
equipment_id = ret["DeviceId"] equipment_id = ret["DeviceId"]
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
[('production_id', '=', production_id), ('routing_type', '=', routing_type), [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
('rfid_code', '!=', False), ('state', '!=', 'rework')], limit=1)
if not workorder: if not workorder:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单不存在'} res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单不存在'}
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
@@ -206,14 +203,12 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': ['工单已结束']} res = {'Succeed': True, 'Datas': ['工单已结束']}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
logging.info('button_Work_End:%s' % ret)
request.env['center_control.interface.log'].sudo().create( request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/FeedBackEnd'}) {'content': ret, 'name': 'AutoDeviceApi/FeedBackEnd'})
production_id = ret['BillId'] production_id = ret['BillId']
routing_type = ret['CraftId'] routing_type = ret['CraftId']
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
[('production_id', '=', production_id), ('routing_type', '=', routing_type), [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
('rfid_code', '!=', False), ('state', '!=', 'rework')], limit=1)
if not workorder: if not workorder:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单不存在'} res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单不存在'}
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
@@ -221,23 +216,21 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单未开始'} res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单未开始'}
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
# workorder.write({'date_finished': datetime.now()}) # workorder.write({'date_finished': datetime.now()})
if ret['IsComplete'] is True: workorder.button_finish()
workorder.write({'date_finished': datetime.now()}) # workorder.process_state = '待解除装夹'
# workorder.sudo().production_id.process_state = '待解除装夹'
# 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,
# if workorder.date_finished: 'state': 'finished'})
# request.env['sf.production.plan'].sudo().search([('production_id', '=', production_id)]).write( production_obj = request.env['mrp.production'].sudo().search([('name', '=', production_id)])
# {'actual_end_time': workorder.date_finished, if production_obj:
# 'state': 'finished'}) production_obj.sudo().work_order_state = '已完成'
# production_obj = request.env['mrp.production'].sudo().search([('name', '=', production_id)]) production_obj.write({'state': 'completed'})
# if production_obj: # request.env['sale.order'].sudo().search(
# production_obj.sudo().work_order_state = '已完成' # [('name', '=', production_obj.origin)]).write({'schedule_status': 'to deliver'})
# production_obj.write({'state': 'done'})
# request.env['sale.order'].sudo().search(
# [('name', '=', production_obj.origin)]).write({'schedule_status': 'to deliver'})
except Exception as e: except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
@@ -260,27 +253,39 @@ class Manufacturing_Connect(http.Controller):
request.env['center_control.interface.log'].sudo().create( request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/PartQualityInspect'}) {'content': ret, 'name': 'AutoDeviceApi/PartQualityInspect'})
production_id = ret['BillId'] production_id = ret['BillId']
# routing_type = ret['CraftId'] routing_type = ret['CraftId']
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
[('production_id', '=', production_id), ('routing_type', '=', 'CNC加工'), [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
('state', 'not in', ['rework', 'done', 'cancel'])], order='sequence asc',
limit=1)
if workorder: if workorder:
# workorder.test_results = ret['Quality'] # workorder.test_results = ret['Quality']
logging.info('制造订单:%s' % workorder.production_id.name) logging.info('制造订单:%s' % workorder.production_id.name)
if 'ReportPaht' in ret: if 'ReportPaht' in ret:
if ret['ReportPaht'].find('.pdf') != -1: download_state = request.env['mrp.workorder'].with_user(
download_state = request.env['mrp.workorder'].with_user( request.env.ref("base.user_admin")).download_reportfile_tmp(workorder,
request.env.ref("base.user_admin")).download_reportfile_tmp(workorder, ret['ReportPaht'])
ret['ReportPaht']) if download_state == 1:
if download_state is True: detection_ret = request.env['mrp.workorder'].with_user(
detection_ret = request.env['mrp.workorder'].with_user( request.env.ref("base.user_admin")).get_detection_file(workorder, ret['ReportPaht'])
request.env.ref("base.user_admin")).get_detection_file(workorder, ret['ReportPaht']) if detection_ret is True:
logging.info('detection_ret:%s' % detection_ret) stock_picking_type = request.env['stock.picking.type'].sudo().search(
if detection_ret is False: [('sequence_code', '=', 'SFP')])
res = {'Succeed': False, 'ErrorCode': 205, 'Error': '检测报告文件读取失败'} if stock_picking_type:
else: stock_picking = request.env['stock.picking'].sudo().search(
res = {'Succeed': False, 'ErrorCode': 204, 'Error': '检测报告文件从FTP拉取失败'} [('product_id', '=', workorder.product_id.id),
('origin', '=', workorder.production_id.origin),
('picking_type_id', '=', stock_picking_type.id)])
if stock_picking:
quality_check = request.env['quality.check'].sudo().search(
[('product_id', '=', workorder.product_id.id),
('picking_id', '=', stock_picking.id)])
if quality_check:
logging.info('质检单:%s' % quality_check.name)
quality_check.write({'report_pdf': workorder.detection_report})
elif download_state == 2:
res = {'Succeed': False, 'ErrorCode': 205,
'Error': 'ReportPaht中的工件号与制造订单%s不匹配请检查ReportPaht是否正确' % workorder.production_id.name}
else:
res = {'Succeed': False, 'ErrorCode': 204, 'Error': '检测报告文件从FTP拉取失败'}
else: else:
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传ReportPaht字段'} res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传ReportPaht字段'}
else: else:
@@ -308,18 +313,18 @@ class Manufacturing_Connect(http.Controller):
if 'RfidCode' in ret: if 'RfidCode' in ret:
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
[('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', 'CNC加工'), ('state', '!=', 'rework')]) [('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', 'CNC加工')])
if workorder: if workorder:
for item in workorder.cmm_ids: for item in workorder.cmm_ids:
if item.program_create_date is not False: if item.program_date is not False:
program_create_date = item.program_create_date.strftime("%Y-%m-%d %H:%M:%S") 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_create_date) program_date_str = request.env['sf.sync.common'].sudo().get_add_time(program_date)
res['Datas'].append({ res['Datas'].append({
'CraftId': workorder.id, 'CraftId': workorder.id,
'CraftKey': workorder.name, 'CraftKey': workorder.name,
'ProgramDate': '' if not item.program_create_date else program_date_str, 'ProgramDate': '' if not item.program_date else program_date_str,
'ProgramPath': item.program_path, 'ProgramPath': item.program_path,
'PostProcessing': item.program_name, 'PostProcessing': item.post_processing_name,
}) })
else: else:
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '暂无工单及对应的CNC程序数据'} res = {'Succeed': False, 'ErrorCode': 203, 'Error': '暂无工单及对应的CNC程序数据'}
@@ -348,7 +353,7 @@ class Manufacturing_Connect(http.Controller):
if 'RfidCode' in ret: if 'RfidCode' in ret:
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
[('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', 'CNC加工'), ('state', '!=', 'rework')]) [('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', 'CNC加工')])
if workorder: if workorder:
for item in workorder.cnc_ids: for item in workorder.cnc_ids:
res['Datas'].append({ res['Datas'].append({
@@ -454,33 +459,25 @@ class Manufacturing_Connect(http.Controller):
if f'RfidCode{i}' in ret: if f'RfidCode{i}' in ret:
rfid_code = ret[f'RfidCode{i}'] rfid_code = ret[f'RfidCode{i}']
logging.info('RfidCode:%s' % rfid_code) logging.info('RfidCode:%s' % rfid_code)
if rfid_code is not None: domain = [
domain = [ ('rfid_code', '=', rfid_code),
('rfid_code', '=', rfid_code), ('routing_type', '=', 'CNC加工')
('routing_type', '=', 'CNC加工'), ('state', '!=', 'rework') ]
] workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc')
workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc') if workorder:
if workorder: for order in workorder:
for order in workorder: if order.production_id.production_line_state == '待上产线':
if order.production_line_state == '待上产线': logging.info(
logging.info( '制造订单产线状态:%s' % order.production_id.production_line_state)
'工单产线状态:%s' % order.production_line_state) order.production_id.write({'production_line_state': '已上产线'})
panel_workorder = request.env['mrp.workorder'].sudo().search( workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search([
[('rfid_code', '=', rfid_code), ('state', '!=', 'rework'), ('rfid_code', '=', rfid_code), ('type', '=', '上产线'),
('processing_panel', '=', order.processing_panel)]) ('production_id', '=', order.production_id.id)])
if panel_workorder: if workpiece_delivery.status == '待下发':
panel_workorder.write({'production_line_state': '已上产线'}) workpiece_delivery.write({'is_manual_work': True})
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( else:
[ res = {'Succeed': False, 'ErrorCode': 204,
('rfid_code', '=', rfid_code), ('type', '=', '上产线'), 'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
('production_id', '=', order.production_id.id),
('workorder_id', '=', order.id),
('workorder_state', '=', 'done')])
if workpiece_delivery.status == '待下发':
workpiece_delivery.write({'is_manual_work': True})
else:
res = {'Succeed': False, 'ErrorCode': 204,
'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
else: else:
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传IsComplete字段'} res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传IsComplete字段'}
else: else:
@@ -517,34 +514,24 @@ class Manufacturing_Connect(http.Controller):
if f'RfidCode{i}' in ret: if f'RfidCode{i}' in ret:
rfid_code = ret[f'RfidCode{i}'] rfid_code = ret[f'RfidCode{i}']
logging.info('RfidCode:%s' % rfid_code) logging.info('RfidCode:%s' % rfid_code)
if rfid_code is not None: domain = [
domain = [ ('rfid_code', '=', rfid_code),
('rfid_code', '=', rfid_code), ('routing_type', '=', 'CNC加工')
('routing_type', '=', 'CNC加工'), ('state', '!=', 'rework') ]
] workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc')
workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc') if workorder:
if workorder: for order in workorder:
for order in workorder: if order.production_id.production_line_state == '已上产线':
if order.production_line_state == '已上产线': logging.info(
logging.info( '制造订单产线状态:%s' % order.production_id.production_line_state)
'工单产线状态:%s' % order.production_line_state) order.production_id.write({'production_line_state': '已下产线'})
panel_workorder = request.env['mrp.workorder'].sudo().search( workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search([
[('rfid_code', '=', rfid_code), ('state', '!=', 'rework'), ('rfid_code', '=', rfid_code), ('type', '=', '下产线'),
('processing_panel', '=', order.processing_panel)]) ('production_id', '=', order.production_id.id)])
if panel_workorder: delivery_Arr.append(workpiece_delivery.id)
panel_workorder.write({'production_line_state': '已下产线'}) else:
workorder.write({'state': 'to be detected'}) res = {'Succeed': False, 'ErrorCode': 204,
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( 'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
[
('rfid_code', '=', rfid_code), ('type', '=', '下产线'),
('production_id', '=', order.production_id.id),
('workorder_id', '=', order.id),
('workorder_state', '=', 'done')])
if workpiece_delivery:
delivery_Arr.append(workpiece_delivery.id)
else:
res = {'Succeed': False, 'ErrorCode': 204,
'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
if delivery_Arr: if delivery_Arr:
logging.info('delivery_Arr:%s' % delivery_Arr) logging.info('delivery_Arr:%s' % delivery_Arr)
delivery_workpiece = request.env['sf.workpiece.delivery'].sudo().search( delivery_workpiece = request.env['sf.workpiece.delivery'].sudo().search(

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="panel_zm" model="sf.processing.panel">
<field name="name">ZM</field>
</record>
<record id="panel_fm" model="sf.processing.panel">
<field name="name">FM</field>
</record>
<record id="panel_yc" model="sf.processing.panel">
<field name="name">YC</field>
</record>
<record id="panel_zc" model="sf.processing.panel">
<field name="name">ZC</field>
</record>
<record id="panel_qc" model="sf.processing.panel">
<field name="name">QC</field>
</record>
<record id="panel_hc" model="sf.processing.panel">
<field name="name">HC</field>
</record>
</data>
</odoo>

View File

@@ -1,16 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<data noupdate="1"> <data noupdate="1">
<record model="ir.cron" id="ir_cron_mrp_production">
<field name="name">返工且编程中的制造订单定时获取Cloud编程单状态</field>
<field name="model_id" ref="model_mrp_production"/>
<field name="state">code</field>
<field name="code">model._cron_get_programming_state()</field>
<field name="interval_number">3</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
</record>
<record id="sequence_routing_workcenter" model="ir.sequence"> <record id="sequence_routing_workcenter" model="ir.sequence">
<field name="name">工序编码规则</field> <field name="name">工序编码规则</field>
<field name="code">mrp.routing.workcenter</field> <field name="code">mrp.routing.workcenter</field>

View File

@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import base64 import base64
import logging import logging
import json
import os
import re import re
import requests import requests
from itertools import groupby from itertools import groupby
@@ -26,60 +24,22 @@ class MrpProduction(models.Model):
work_order_state = fields.Selection([('未排', '未排'), ('已排', '已排'), ('已完成', '已完成')], work_order_state = fields.Selection([('未排', '未排'), ('已排', '已排'), ('已完成', '已完成')],
string='工单状态', default='未排') string='工单状态', default='未排')
detection_result_ids = fields.One2many('sf.detection.result', 'production_id', '检测报告')
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
store=True, compute='_compute_tool_state')
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True)
@api.depends('workorder_ids.tool_state_remark')
def _compute_tool_state_remark(self):
for item in self:
if item.workorder_ids:
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ['rework', 'done', 'cancel'])
if workorder_ids.filtered(lambda a: a.tool_state == '1'):
work_ids = workorder_ids.filtered(lambda a: a.tool_state == '1')
tool_state_remark = ''
for work_id in work_ids:
if tool_state_remark == '':
tool_state_remark = f'{work_id.tool_state_remark}'
else:
tool_state_remark = f"{tool_state_remark}\n{work_id.tool_state_remark}"
item.tool_state_remark = tool_state_remark
else:
item.tool_state_remark = False
@api.depends('workorder_ids.tool_state')
def _compute_tool_state(self):
for item in self:
if item.workorder_ids:
tool_state = item.tool_state
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ['rework', 'done', 'cancel'])
if workorder_ids.filtered(lambda a: a.tool_state == '2'):
item.tool_state = '2'
elif workorder_ids.filtered(lambda a: a.tool_state == '1'):
item.tool_state = '1'
else:
item.tool_state = '0'
if tool_state == '2' and item.tool_state != '2':
item.detection_result_ids.filtered(
lambda a: a.detailed_reason == '无效功能刀具' and a.handle_result == '待处理').write(
{'handle_result': '已处理'})
# state = fields.Selection(selection_add=[ # state = fields.Selection(selection_add=[
# ('pending_scheduling', '待排程'), # ('pending_scheduling', '待排程'),
# ('pending_processing', '待加工'), # ('pending_processing', '待加工'),
# ('completed', '已完工') # ('completed', '已完工')
# ]) # ])
state = fields.Selection([ state = fields.Selection([
('draft', '草稿'), ('draft', 'Draft'),
('confirmed', '待排程'), ('confirmed', 'Confirmed'),
('pending_cam', '加工'), ('progress', '排程'),
('progress', '加工中'), ('pending_cam', '待装夹'),
('rework', ''), ('pending_processing', '待加'),
('pending_era_cam', '待解除装夹'),
('completed', '已完工'),
('to_close', 'To Close'), ('to_close', 'To Close'),
('done', 'Done'), ('done', 'Done'),
('cancel', '报废')], string='State', ('cancel', 'Cancelled')], string='State',
compute='_compute_state', copy=False, index=True, readonly=True, compute='_compute_state', copy=False, index=True, readonly=True,
store=True, tracking=True, store=True, tracking=True,
help=" * Draft: The MO is not confirmed yet.\n" help=" * Draft: The MO is not confirmed yet.\n"
@@ -93,17 +53,13 @@ class MrpProduction(models.Model):
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
programming_no = fields.Char('编程单号') programming_no = fields.Char('编程单号')
work_state = fields.Char('业务状态') work_state = fields.Char('业务状态')
programming_state = fields.Selection( programming_state = fields.Char('编程状态', tracking=True)
[('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'), ('已下发', '已下发')],
string='编程状态',
tracking=True)
glb_file = fields.Binary("glb模型文件") glb_file = fields.Binary("glb模型文件")
production_line_id = fields.Many2one('sf.production.line', string='生产线', tracking=True) production_line_id = fields.Many2one('sf.production.line', string='生产线', tracking=True)
plan_start_processing_time = fields.Datetime('计划开始加工时间') plan_start_processing_time = fields.Datetime('计划开始加工时间')
is_rework = fields.Boolean(string='是否返工', default=False) production_line_state = fields.Selection(
# production_line_state = fields.Selection( [('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
# [('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')], string='上/下产线', default='待上产线', tracking=True)
# string='上/下产线', default='待上产线', tracking=True)
# 工序状态 # 工序状态
# Todo 研究下用法 # Todo 研究下用法
process_state = fields.Selection([ process_state = fields.Selection([
@@ -121,11 +77,11 @@ class MrpProduction(models.Model):
part_drawing = fields.Binary('零件图纸') part_drawing = fields.Binary('零件图纸')
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
is_scrap = fields.Boolean('是否报废', default=False) rework_production = fields.Many2one('mrp.production', string='返工的制造订单')
@api.depends( @api.depends(
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'tool_state', 'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state') 'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state', 'process_state')
def _compute_state(self): def _compute_state(self):
for production in self: for production in self:
if not production.state or not production.product_uom_id: if not production.state or not production.product_uom_id:
@@ -153,40 +109,22 @@ class MrpProduction(models.Model):
production.state = 'progress' production.state = 'progress'
elif any(not float_is_zero(move.quantity_done, elif any(not float_is_zero(move.quantity_done,
precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding) precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding)
for move in production.move_raw_ids if move.product_id): for move in production.move_raw_ids):
production.state = 'progress' production.state = 'progress'
# # 新添加的状态逻辑 # 新添加的状态逻辑
if ( if production.state == 'progress' and production.schedule_state == '已排' and production.process_state == '待装夹':
production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排': # production.state = 'pending_processing'
production.state = 'confirmed'
elif production.state == 'pending_cam' and production.schedule_state == '未排':
production.state = 'confirmed'
elif production.state == 'to_close' and production.schedule_state == '已排':
production.state = 'pending_cam' production.state = 'pending_cam'
if production.state == 'progress' and production.schedule_state == '已排' and production.process_state == '待加工':
if production.state == 'progress': # if production.state == 'pending_cam' and production.process_state == '待加工':
if all(wo_state not in ('progress', 'done', 'rework') for wo_state in production.state = 'pending_processing'
production.workorder_ids.mapped('state')): elif production.state == 'progress' and production.process_state == '待解除装夹':
production.state = 'pending_cam' production.state = 'pending_era_cam'
if production.is_rework is True: elif production.state == 'progress' and production.process_state == '已完工':
production.state = 'rework' production.state = 'completed'
# if production.state == 'pending_cam': elif production.state == 'progress' and production.work_order_state == '已完成':
# if all(wo_state in 'done' for wo_state in production.workorder_ids.mapped('state')): production.state = 'completed'
# production.state = 'done'
if any(
(
wo.test_results == '返工' and wo.state == 'done' and production.programming_state in [
'已编程']) or (
wo.state == 'rework' and production.programming_state == '编程中') or (
wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中',
'已编程'])
for wo in
production.workorder_ids):
production.state = 'rework'
# 如果制造订单的功能刀具为【无效刀】则制造订单状态改为返工
if production.tool_state == '2':
production.state = 'rework'
def action_check(self): def action_check(self):
""" """
@@ -217,67 +155,30 @@ class MrpProduction(models.Model):
for production in self: for production in self:
production.maintenance_count = len(production.request_ids) production.maintenance_count = len(production.request_ids)
# 获取cloud编程单的状态 # 制造订单报废:编程单更新
def _cron_get_programming_state(self): def updateCNC(self):
try: try:
if not self: res = {'production_no': self.name, 'programming_no': self.programming_no,
reproduction = self.env['mrp.production'].search( 'order_no': self.origin}
[('state', '=', 'rework'), ('programming_state', '=', '编程中'), ('is_rework', '=', True)])
else:
reproduction = self
if reproduction:
programming_no_set = set([str(item.programming_no) for item in reproduction])
programming_no = list(programming_no_set)
programming_no_str = ','.join(programming_no)
res = {'programming_no': programming_no_str}
logging.info('res=%s:' % res)
configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/intelligent_programming/get_state'
config_url = configsettings['sf_url'] + url
ret = requests.post(config_url, json=res, data=None, headers=config_header)
ret = ret.json()
result = json.loads(ret['result'])
if result['status'] == 1:
for item in result['programming_list']:
if not self:
for rp in reproduction:
if rp.programming_no == item['programming_no']:
rp.write({'programming_state': '已编程未下发' if item[
'programming_state'] == '已编程' else '编程中'})
else:
return item
else:
raise UserError(ret['message'])
except Exception as e:
logging.info('cron_get_programming_state error:%s' % e)
# 编程单更新
def update_programming_state(self):
try:
res = {'programming_no': self.programming_no,
'manufacturing_type': 'rework' if self.is_scrap is False else 'scrap'}
logging.info('res=%s:' % res) logging.info('res=%s:' % res)
configsettings = self.env['res.config.settings'].get_values() configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key']) config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/intelligent_programming/reset_state_again' url = '/api/intelligent_programming/update_intelligent_programmings'
config_url = configsettings['sf_url'] + url config_url = configsettings['sf_url'] + url
ret = requests.post(config_url, json=res, data=None, headers=config_header) res['token'] = configsettings['token']
ret = requests.post(config_url, json={}, data=res, headers=config_header)
ret = ret.json() ret = ret.json()
result = json.loads(ret['result']) logging.info('updateCNC-ret:%s' % ret)
logging.info('update_programming_state-ret:%s' % result) if ret['status'] == 1:
if result['status'] == 1: self.write({'work_state': '已编程'})
self.write({'is_rework': True})
else: else:
raise UserError(ret['message']) raise UserError(ret['message'])
except Exception as e: except Exception as e:
logging.info('update_programming_state error:%s' % e) logging.info('updateCNC error:%s' % e)
raise UserError("更新程单状态失败,请联系管理员") raise UserError("更新程单失败,请联系管理员")
# cnc程序获取 # cnc程序获取
def fetchCNC(self, production_names): def fetchCNC(self, production_names, scrap_production):
cnc = self.env['mrp.production'].search([('id', '=', self.id)]) cnc = self.env['mrp.production'].search([('id', '=', self.id)])
quick_order = self.env['quick.easy.order'].search( quick_order = self.env['quick.easy.order'].search(
[('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])]) [('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])])
@@ -293,14 +194,15 @@ class MrpProduction(models.Model):
'production_no': production_names, 'production_no': production_names,
'machine_tool_code': '', 'machine_tool_code': '',
'product_name': cnc.product_id.name, 'product_name': cnc.product_id.name,
'remanufacture_type': '', 'remanufacture_type': '' if not scrap_production else scrap_production.workorder_ids.filtered(
lambda b: b.routing_type == "CNC加工").test_results,
'model_code': cnc.product_id.model_code, 'model_code': cnc.product_id.model_code,
'material_code': self.env['sf.production.materials'].search( 'material_code': self.env['sf.production.materials'].search(
[('id', '=', cnc.product_id.materials_id.id)]).materials_no, [('id', '=', cnc.product_id.materials_id.id)]).materials_no,
'material_type_code': self.env['sf.materials.model'].search( 'material_type_code': self.env['sf.materials.model'].search(
[('id', '=', cnc.product_id.materials_type_id.id)]).materials_no, [('id', '=', cnc.product_id.materials_type_id.id)]).materials_no,
'machining_processing_panel': cnc.product_id.model_processing_panel, 'machining_processing_panel': cnc.product_id.model_processing_panel,
'machining_precision': '', 'machining_precision': cnc.product_id.model_machining_precision,
'embryo_long': cnc.product_id.bom_ids.bom_line_ids.product_id.length, 'embryo_long': cnc.product_id.bom_ids.bom_line_ids.product_id.length,
'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height, 'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height,
'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width, 'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
@@ -391,7 +293,15 @@ class MrpProduction(models.Model):
# 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制; # 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制;
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心; # 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
def _create_workorder3(self, item): 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]
for production in self: for production in self:
if not production.bom_id or not production.product_id: if not production.bom_id or not production.product_id:
continue continue
@@ -419,6 +329,20 @@ class MrpProduction(models.Model):
'state': 'pending', 'state': 'pending',
}] }]
if production.product_id.categ_id.type == '成品': 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]),
scrap_production)
else:
production.write({'programming_no': production_programming.programming_no,
'programming_state': '编程中'})
# # 根据加工面板的面数及对应的工序模板生成工单 # # 根据加工面板的面数及对应的工序模板生成工单
i = 0 i = 0
processing_panel_len = len(production.product_id.model_processing_panel.split(',')) processing_panel_len = len(production.product_id.model_processing_panel.split(','))
@@ -431,14 +355,13 @@ class MrpProduction(models.Model):
for route in product_routing_workcenter: for route in product_routing_workcenter:
if route.is_repeat is True: if route.is_repeat is True:
workorders_values.append( workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(k, production, route, item)) self.env['mrp.workorder'].json_workorder_str(k, production, route))
# if i == processing_panel_len and route.routing_type == '解除装夹': if i == processing_panel_len and route.routing_type == '解除装夹':
# workorders_values.append( workorders_values.append(
# self.env['mrp.workorder'].json_workorder_str(k, production, route)) self.env['mrp.workorder'].json_workorder_str(k, production, route))
# 表面工艺工序 # 表面工艺工序
# 获取表面工艺id # 获取表面工艺id
if production.product_id.model_process_parameters_ids: 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 = [] surface_technics_arr = []
# 工序id # 工序id
route_workcenter_arr = [] route_workcenter_arr = []
@@ -453,7 +376,6 @@ class MrpProduction(models.Model):
# 用filter刷选表面工艺id'是否存在工艺类别对象里 # 用filter刷选表面工艺id'是否存在工艺类别对象里
if production_process_category: if production_process_category:
for p in production_process_category: for p in production_process_category:
logging.info('production_process_category:%s' % p.name)
production_process = p.production_process_ids.filtered( production_process = p.production_process_ids.filtered(
lambda pp: pp.id in surface_technics_arr) lambda pp: pp.id in surface_technics_arr)
if production_process: if production_process:
@@ -484,55 +406,31 @@ class MrpProduction(models.Model):
workorders_values.append( workorders_values.append(
self.env['mrp.workorder'].json_workorder_str('', production, route)) self.env['mrp.workorder'].json_workorder_str('', production, route))
production.workorder_ids = workorders_values 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: for workorder in production.workorder_ids:
workorder.duration_expected = workorder._get_duration_expected() workorder.duration_expected = workorder._get_duration_expected()
# 在之前的销售单上重新生成制造订单
def create_production1_values(self, production):
production_values_str = {'origin': production.origin,
'product_id': production.product_id.id,
'product_description_variants': production.product_description_variants,
'product_qty': production.product_qty,
'product_uom_id': production.product_uom_id.id,
'location_src_id': production.location_src_id.id,
'location_dest_id': production.location_dest_id.id,
'bom_id': production.bom_id.id,
'date_deadline': production.date_deadline,
'date_planned_start': production.date_planned_start,
'date_planned_finished': production.date_planned_finished,
'procurement_group_id': False,
'propagate_cancel': production.propagate_cancel,
'orderpoint_id': production.orderpoint_id.id,
'picking_type_id': production.picking_type_id.id,
'company_id': production.company_id.id,
'move_dest_ids': production.move_dest_ids.ids,
'user_id': production.user_id.id}
return production_values_str
# 工单排序 # 工单排序
def _reset_work_order_sequence1(self, k): def _reset_work_order_sequence1(self, k):
for rec in self: for rec in self:
@@ -601,94 +499,57 @@ class MrpProduction(models.Model):
def _reset_work_order_sequence(self): def _reset_work_order_sequence(self):
for rec in self: for rec in self:
workorder_ids = rec.workorder_ids.filtered(lambda item: item.state in ('返工', 'rework')) sequence_list = {}
# 产品模型类型
model_type_id = rec.product_id.product_model_type_id model_type_id = rec.product_id.product_model_type_id
# 产品加工面板 if model_type_id:
model_processing_panel = rec.product_id.model_processing_panel tmpl_num = 1
if not workorder_ids:
sequence_list = {}
if model_type_id:
if model_processing_panel:
tmpl_num = 1
panel_list = model_processing_panel.split(',')
for panel in panel_list:
panel_sequence_list = {}
# 成品工序
product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids
if product_routing_tmpl_ids:
for tmpl_id in product_routing_tmpl_ids:
panel_sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
tmpl_num += 1
sequence_list.update({panel: panel_sequence_list})
# 表面工艺工序
# 模型类型的表面工艺工序模版
surface_tmpl_ids = model_type_id.surface_technics_routing_tmpl_ids
# 产品选择的表面工艺
model_process_parameters_ids = rec.product_id.model_process_parameters_ids
process_dict = {}
if model_process_parameters_ids:
for process_parameters_id in model_process_parameters_ids:
process_id = process_parameters_id.process_id
for surface_tmpl_id in surface_tmpl_ids:
if process_id == surface_tmpl_id.route_workcenter_id.surface_technics_id:
surface_tmpl_name = surface_tmpl_id.route_workcenter_id.name
process_dict.update({int(process_id.category_id.code): '%s-%s' % (
surface_tmpl_name, process_parameters_id.name)})
process_list = sorted(process_dict.keys())
for process_num in process_list:
sequence_list.update({process_dict.get(process_num): tmpl_num})
tmpl_num += 1
# 坯料工序
tmpl_num = 1
embryo_routing_tmpl_ids = model_type_id.embryo_routing_tmpl_ids
if embryo_routing_tmpl_ids:
for tmpl_id in embryo_routing_tmpl_ids:
sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
tmpl_num += 1
else:
raise ValidationError('该产品【加工面板】为空!')
else:
raise ValidationError('该产品没有选择【模版类型】!')
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)
# 当单个面触发返工时,将新生成的工单插入到返工工单下方,并且后面的所以工单工序重排
elif rec.workorder_ids.filtered(lambda item: item.sequence == 0):
# 获取新增的返工工单
work_ids = rec.workorder_ids.filtered(lambda item: item.sequence == 0)
# 获取当前返工面最后一个工单工序
sequence_max = sorted(
rec.workorder_ids.filtered(lambda item: item.processing_panel == work_ids[0].processing_panel),
key=lambda item: item.sequence, reverse=True)[0].sequence
# 对当前返工工单之后的工单工序进行重排
work_order_ids = rec.workorder_ids.filtered(lambda item: item.sequence > sequence_max)
for work_id in work_order_ids:
work_id.sequence = work_id.sequence + 3
# 生成新增的返工工单的工序
# 成品工序 # 成品工序
panel_sequence_list = {}
product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids
if product_routing_tmpl_ids: if product_routing_tmpl_ids:
for tmpl_id in product_routing_tmpl_ids: for tmpl_id in product_routing_tmpl_ids:
sequence_max += 1 sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
panel_sequence_list.update({tmpl_id.route_workcenter_id.name: sequence_max}) tmpl_num += 1
for work_id in work_ids: # 表面工艺工序
if panel_sequence_list.get(work_id.name): # 模型类型的表面工艺工序模版
work_id.sequence = panel_sequence_list[work_id.name] surface_tmpl_ids = model_type_id.surface_technics_routing_tmpl_ids
# 产品选择的表面工艺
model_process_parameters_ids = rec.product_id.model_process_parameters_ids
process_dict = {}
if model_process_parameters_ids:
for process_parameters_id in model_process_parameters_ids:
process_id = process_parameters_id.process_id
for surface_tmpl_id in surface_tmpl_ids:
if process_id == surface_tmpl_id.route_workcenter_id.surface_technics_id:
surface_tmpl_name = surface_tmpl_id.route_workcenter_id.name
process_dict.update({int(process_id.category_id.code): '%s-%s' % (
surface_tmpl_name, process_parameters_id.name)})
process_list = sorted(process_dict.keys())
for process_num in process_list:
sequence_list.update({process_dict.get(process_num): tmpl_num})
tmpl_num += 1
# 坯料工序
tmpl_num = 1
embryo_routing_tmpl_ids = model_type_id.embryo_routing_tmpl_ids
if embryo_routing_tmpl_ids:
for tmpl_id in embryo_routing_tmpl_ids:
sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
tmpl_num += 1
else:
raise ValidationError('该产品没有选择【模版类型】!')
for work in rec.workorder_ids:
if sequence_list.get(work.name):
work.sequence = sequence_list[work.name]
else:
raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name)
# if work.name == '获取CNC加工程序':
# work.button_start()
# #work.fetchCNC()
# work.button_finish()
# 创建工单并进行排序 # 创建工单并进行排序
def _create_workorder(self, item): def _create_workorder(self):
self._create_workorder3(item) self._create_workorder3()
self._reset_work_order_sequence() self._reset_work_order_sequence()
return True return True
@@ -732,9 +593,6 @@ class MrpProduction(models.Model):
}) })
for production in self: for production in self:
logging.info('qty_produced:%s' % production.qty_produced)
if production.qty_produced == 0.0:
production.qty_produced = 1.0
production.write({ production.write({
'date_finished': fields.Datetime.now(), 'date_finished': fields.Datetime.now(),
'product_qty': production.qty_produced, 'product_qty': production.qty_produced,
@@ -763,7 +621,6 @@ class MrpProduction(models.Model):
if any(mo.show_allocation for mo in self): if any(mo.show_allocation for mo in self):
action = self.action_view_reception_report() action = self.action_view_reception_report()
return action return action
logging.info('last-product_qty:%s' % production.product_qty)
return True return True
context = self.env.context.copy() context = self.env.context.copy()
context = {k: v for k, v in context.items() if not k.startswith('default_')} context = {k: v for k, v in context.items() if not k.startswith('default_')}
@@ -787,300 +644,3 @@ class MrpProduction(models.Model):
'view_mode': 'tree,form', 'view_mode': 'tree,form',
}) })
return action return action
# 返工
def button_rework(self):
cloud_programming = None
if self.programming_state in ['已编程']:
cloud_programming = self._cron_get_programming_state()
return {
'name': _('返工'),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'sf.rework.wizard',
'target': 'new',
'context': {
'default_production_id': self.id,
'default_reprogramming_num': cloud_programming['reprogramming_num'],
'default_programming_state': cloud_programming['programming_state'],
'default_is_reprogramming': True if cloud_programming['programming_state'] in ['已下发'] else False
}
}
# 更新程序
def do_update_program(self):
program_production = self
if len(program_production) >= 1:
# same_product_id = None
# is_not_same_product = 0
for item in program_production:
# if same_product_id is None:
# same_product_id = item.product_id
# if item.product_id != same_product_id:
# is_not_same_product += 1
if item.state != "rework" and item.programming_state != "已编程未下发":
raise UserError("请选择状态为返工且已编程未下发的制造订单")
# if is_not_same_product >= 1:
# raise UserError("您选择的记录中含有其他产品的制造订单,请选择同一产品的制造订单")
grouped_program_ids = {k: list(g) for k, g in groupby(program_production, key=lambda x: x.programming_no)}
program_to_production_names = {}
for programming_no, program_production in grouped_program_ids.items():
program_to_production_names[programming_no] = [production.name for production in program_production]
for production in self:
if production.programming_no in program_to_production_names:
productions_not_delivered = self.env['mrp.production'].search(
[('programming_no', '=', production.programming_no), ('programming_state', '=', '已编程未下发')])
rework_workorder = production.workorder_ids.filtered(lambda m: m.state == 'rework')
if rework_workorder:
for rework_item in rework_workorder:
pending_workorder = production.workorder_ids.filtered(
lambda m1: m1.state in [
'pending'] and m1.processing_panel == rework_item.processing_panel and m1.routing_type == 'CNC加工')
if not pending_workorder.cnc_ids:
production.get_new_program(rework_item.processing_panel)
# production.write({'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
productions_not_delivered.write(
{'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
# 从cloud获取重新编程过的最新程序
def get_new_program(self, processing_panel):
try:
res = {'programming_no': self.programming_no, 'processing_panel': processing_panel}
configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/intelligent_programming/get_new_program'
config_url = configsettings['sf_url'] + url
r = requests.post(config_url, json=res, data=None, headers=config_header)
r = r.json()
result = json.loads(r['result'])
if result['status'] == 1:
program_path_tmp_panel = os.path.join('/tmp', result['folder_name'], 'return', processing_panel)
if os.path.exists(program_path_tmp_panel):
files_r = os.listdir(program_path_tmp_panel)
if files_r:
for file_name in files_r:
file_path = os.path.join(program_path_tmp_panel, file_name)
os.remove(file_path)
download_state = self.env['sf.cnc.processing'].download_file_tmp(result['folder_name'],
processing_panel)
if download_state is False:
raise UserError('编程单号为%s的CNC程序文件从FTP拉取失败' % (self.programming_no))
productions = self.env['mrp.production'].search(
[('programming_no', '=', self.programming_no), ('state', 'not in', ('cancel', 'done'))])
if productions:
for production in productions:
panel_workorder = production.workorder_ids.filtered(lambda
pw: pw.processing_panel == processing_panel and pw.routing_type == 'CNC加工' and pw.state not in (
'rework', 'done'))
if panel_workorder:
if panel_workorder.cmm_ids:
panel_workorder.cmm_ids.sudo().unlink()
if panel_workorder.cnc_ids:
panel_workorder.cnc_ids.sudo().unlink()
self.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
production)
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
# processing_panel)
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)
files_panel = os.listdir(program_path_tmp_panel)
if files_panel:
for file in files_panel:
file_extension = os.path.splitext(file)[1]
if file_extension.lower() == '.pdf':
panel_file_path = os.path.join(program_path_tmp_panel, file)
logging.info('panel_file_path:%s' % panel_file_path)
panel_workorder.write(
{'cnc_ids': panel_workorder.cnc_ids.sudo()._json_cnc_processing(processing_panel,
result),
'cmm_ids': panel_workorder.cmm_ids.sudo()._json_cmm_program(processing_panel, result),
'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
logging.info('len(cnc_worksheet):%s' % len(panel_workorder.cnc_worksheet))
pre_workorder = production.workorder_ids.filtered(lambda
ap: ap.routing_type == '装夹预调' and ap.processing_panel == processing_panel and ap.state not in (
'rework', 'done'))
if pre_workorder:
pre_workorder.write(
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
# if production.state == 'rework' and production.programming_state == '已编程未下发':
# production.write(
# {'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
# logging.info('返工含有已编程未下发的程序更新完成:%s' % production.name)
logging.info('更新程序完成:%s' % production.name)
else:
raise UserError(result['message'])
except Exception as e:
logging.info('get_new_program error:%s' % e)
raise UserError("从云平台获取最新程序失败,请联系管理员")
def recreateManufacturing(self):
"""
重新生成制造订单
"""
if self.is_scrap is True:
sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)])
values = self.env['mrp.production'].create_production1_values(self.production_id)
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
self.production_id.company_id).create(
values)
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
productions._create_workorder()
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
(
p.move_dest_ids.procure_method != 'make_to_order' and
not p.move_raw_ids and not p.workorder_ids)).action_confirm()
for production_item in productions:
process_parameter_workorder = self.env['mrp.workorder'].search(
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_item.id),
('is_subcontract', '=', True)])
if process_parameter_workorder:
is_pick = False
consecutive_workorders = []
m = 0
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id)
for i in range(len(sorted_workorders) - 1):
if m == 0:
is_pick = False
if sorted_workorders[i].supplier_id.id == sorted_workorders[i + 1].supplier_id.id and \
sorted_workorders[i].is_subcontract == sorted_workorders[i + 1].is_subcontract and \
sorted_workorders[i].id == sorted_workorders[i + 1].id - 1:
if sorted_workorders[i] not in consecutive_workorders:
consecutive_workorders.append(sorted_workorders[i])
consecutive_workorders.append(sorted_workorders[i + 1])
m += 1
continue
else:
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production_item)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
# 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单
if is_pick is False:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i],
production_item)
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production_item)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production_item)
if is_pick is False and m == 0:
if len(sorted_workorders) == 1:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production_item)
else:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production_item)
for production in productions:
origin_production = production.move_dest_ids and production.move_dest_ids[
0].raw_material_production_id or False
orderpoint = production.orderpoint_id
if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual':
production.message_post(
body=_('This production order has been created from Replenishment Report.'),
message_type='comment',
subtype_xmlid='mail.mt_note')
elif orderpoint:
production.message_post_with_view(
'mail.message_origin_link',
values={'self': production, 'origin': orderpoint},
subtype_id=self.env.ref('mail.mt_note').id)
elif origin_production:
production.message_post_with_view(
'mail.message_origin_link',
values={'self': production, 'origin': origin_production},
subtype_id=self.env.ref('mail.mt_note').id)
'''
创建生产计划
'''
# 工单耗时
workorder_duration = 0
for workorder in productions.workorder_ids:
workorder_duration += workorder.duration_expected
if sale_order:
sale_order.mrp_production_ids |= productions
# sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({
'name': productions.name,
'order_deadline': sale_order.deadline_of_delivery,
'production_id': productions.id,
'date_planned_start': productions.date_planned_start,
'origin': productions.origin,
'product_qty': productions.product_qty,
'product_id': productions.product_id.id,
'state': 'draft',
})
# 在之前的销售单上重新生成制造订单
def create_production1_values(self, production, sale_order):
production_values_str = {'origin': production.origin,
'product_id': production.product_id.id,
'product_description_variants': production.product_description_variants,
'product_qty': production.product_qty,
'product_uom_id': production.product_uom_id.id,
'location_src_id': production.location_src_id.id,
'location_dest_id': production.location_dest_id.id,
'bom_id': production.bom_id.id,
'date_deadline': production.date_deadline,
'date_planned_start': production.date_planned_start,
'date_planned_finished': production.date_planned_finished,
'procurement_group_id': sale_order.id,
'propagate_cancel': production.propagate_cancel,
'orderpoint_id': production.orderpoint_id.id,
'picking_type_id': production.picking_type_id.id,
'company_id': production.company_id.id,
'move_dest_ids': production.move_dest_ids.ids,
'user_id': production.user_id.id}
return production_values_str
class sf_detection_result(models.Model):
_name = 'sf.detection.result'
_description = "检测结果"
production_id = fields.Many2one('mrp.production')
processing_panel = fields.Char('加工面')
routing_type = fields.Selection([
('装夹预调', '装夹预调'),
('CNC加工', 'CNC加工')], string="工序类型")
rework_reason = fields.Selection(
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"),
("operate computer", "操机"),
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因", tracking=True)
detailed_reason = fields.Text('详细原因')
test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")],
string="检测结果", tracking=True)
test_report = fields.Binary('检测报告', readonly=True)
handle_result = fields.Selection([("待处理", "待处理"), ("已处理", "已处理")], default='', string="处理结果",
tracking=True)
# 查看检测报告
def button_look_test_report(self):
return {
'res_model': 'sf.detection.result',
'type': 'ir.actions.act_window',
'res_id': self.id,
'views': [(self.env.ref('sf_manufacturing.sf_test_report_form').id, 'form')],
# 'view_mode': 'form',
# 'context': {
# 'default_id': self.id
# },
'target': 'new'
}
class sf_processing_panel(models.Model):
_name = 'sf.processing.panel'
_description = "加工面"
name = fields.Char('加工面')
active = fields.Boolean('有效', default=True)

View File

@@ -5,49 +5,24 @@ from odoo.addons.resource.models.resource import Intervals
class ResWorkcenter(models.Model): class ResWorkcenter(models.Model):
_name = "mrp.workcenter" _inherit = "mrp.workcenter"
_inherit = ['mrp.workcenter', 'mail.thread']
# 生产线显示 # 生产线显示
production_line_show = fields.Char(string='生产线名称') production_line_show = fields.Char(string='生产线名称')
equipment_id = fields.Many2one('maintenance.equipment', string="设备", tracking=True) equipment_id = fields.Many2one(
'maintenance.equipment', string="设备",
)
production_line_id = fields.Many2one('sf.production.line', string='生产线', production_line_id = fields.Many2one('sf.production.line', string='生产线',
related='equipment_id.production_line_id', store=True) related='equipment_id.production_line_id', store=True)
is_process_outsourcing = fields.Boolean('工艺外协') is_process_outsourcing = fields.Boolean('工艺外协')
users_ids = fields.Many2many("res.users", 'users_workcenter', tracking=True) users_ids = fields.Many2many("res.users", 'users_workcenter')
def write(self, vals):
if 'users_ids' in vals:
old_users = self.users_ids
res = super(ResWorkcenter, self).write(vals)
new_users = self.users_ids
added_users = new_users - old_users
removed_users = old_users - new_users
if added_users or removed_users:
message = "增加 → %s ; 移除 → %s (可操作用户)" % (
# ','.join(added_users.mapped('name')), ','.join(removed_users.mapped('name')))
added_users.mapped('name'), removed_users.mapped('name'))
self.message_post(body=message)
return res
return super(ResWorkcenter, self).write(vals)
name = fields.Char('Work Center', related='resource_id.name', store=True, readonly=False, tracking=True)
time_efficiency = fields.Float('Time Efficiency', related='resource_id.time_efficiency', default=100, store=True,
readonly=False, tracking=True)
default_capacity = fields.Float(
'Capacity', default=1.0,
help="Default number of pieces (in product UoM) that can be produced in parallel (at the same time) at this work center. For example: the capacity is 5 and you need to produce 10 units, then the operation time listed on the BOM will be multiplied by two. However, note that both time before and after production will only be counted once.",
tracking=True)
oee_target = fields.Float(
string='OEE Target', help="Overall Effective Efficiency Target in percentage", default=90, tracking=True)
time_start = fields.Float('Setup Time', tracking=True)
time_stop = fields.Float('Cleanup Time', tracking=True)
costs_hour = fields.Float(string='Cost per hour', help='Hourly processing cost.', default=0.0, tracking=True)
equipment_status = fields.Selection( equipment_status = fields.Selection(
[("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"), ("封存(报废)", "封存(报废)")], [("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"),("空闲", "空闲"),("封存(报废)", "封存(报废)")],
string="设备状态", related='equipment_id.state') string="设备状态", related='equipment_id.state')
# @api.depends('equipment_id') # @api.depends('equipment_id')

View File

@@ -1,5 +1,5 @@
import re import re
import json
import logging import logging
import base64 import base64
import urllib.parse import urllib.parse
@@ -13,15 +13,13 @@ from dateutil.relativedelta import relativedelta
# import subprocess # import subprocess
from odoo import api, fields, models, SUPERUSER_ID, _ from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError
from odoo.addons.sf_mrs_connect.models.ftp_operate import FtpController from odoo.addons.sf_mrs_connect.models.ftp_operate import FtpController
class ResMrpWorkOrder(models.Model): class ResMrpWorkOrder(models.Model):
_inherit = 'mrp.workorder' _inherit = 'mrp.workorder'
_order = 'sequence asc' _order = 'sequence asc,create_date desc'
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, product_tmpl_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True,
string="坯料长度(mm)") string="坯料长度(mm)")
@@ -47,28 +45,9 @@ class ResMrpWorkOrder(models.Model):
('切割', '切割'), ('表面工艺', '表面工艺') ('切割', '切割'), ('表面工艺', '表面工艺')
], string="工序类型") ], string="工序类型")
results = fields.Char('结果') results = fields.Char('结果')
state = fields.Selection([
('pending', '等待其他工单'),
('waiting', '等待组件'),
('ready', '就绪'),
('progress', '进行中'),
('to be detected', "待检测"),
('done', '已完工'),
('rework', '返工'),
('cancel', '取消')], string='Status',
compute='_compute_state', store=True,
default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True)
# state = fields.Selection(selection_add=[('to be detected', "待检测"), ('rework', '返工')], tracking=True)
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
def _compute_working_users(self):
super()._compute_working_users()
for item in self:
if item.state == 'to be detected':
if self.env.user.has_group('sf_base.group_sf_equipment_user'):
item.is_user_working = True
@api.onchange('users_ids') @api.onchange('users_ids')
def get_user_permissions(self): def get_user_permissions(self):
uid = self.env.uid uid = self.env.uid
@@ -155,6 +134,11 @@ class ResMrpWorkOrder(models.Model):
supplier_id = fields.Many2one('res.partner', string='外协供应商') supplier_id = fields.Many2one('res.partner', string='外协供应商')
equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True) equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True)
is_ok = fields.Boolean(string='是否合格')
# 加工人
processing_user_id = fields.Many2one('res.users', string='加工人')
# 检测人
inspection_user_id = fields.Many2one('res.users', string='检测人')
# 保存名称 # 保存名称
save_name = fields.Char(string='检测文件保存名称', compute='_compute_save_name') save_name = fields.Char(string='检测文件保存名称', compute='_compute_save_name')
# 获取数据状态 # 获取数据状态
@@ -177,46 +161,13 @@ class ResMrpWorkOrder(models.Model):
# 加工图纸 # 加工图纸
processing_drawing = fields.Binary(string='加工图纸') processing_drawing = fields.Binary(string='加工图纸')
# 功能刀具状态
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
store=True, compute='_compute_tool_state')
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
@api.depends('cnc_ids.tool_state')
def _compute_tool_state_remark(self):
for item in self:
if item.cnc_ids:
if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
item.tool_state_remark = None
elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
tool_state_remark = []
cnc_ids = item.cnc_ids.filtered(lambda a: a.tool_state == '1')
for cnc_id in cnc_ids:
if cnc_id.cutting_tool_name not in tool_state_remark:
tool_state_remark.append(cnc_id.cutting_tool_name)
item.tool_state_remark = f"{item.processing_panel}缺刀:{tool_state_remark}"
else:
item.tool_state_remark = None
@api.depends('cnc_ids.tool_state')
def _compute_tool_state(self):
for item in self:
if item.cnc_ids:
if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
item.tool_state = '2'
elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
item.tool_state = '1'
else:
item.tool_state = '0'
@api.depends('production_id') @api.depends('production_id')
def _compute_save_name(self): def _compute_save_name(self):
""" """
保存名称 保存名称
""" """
for record in self: for record in self:
tem_name = record.production_id.name.replace('/', '_') record.save_name = record.production_id.name.replace('/', '_')
record.save_name = tem_name + '_' + record.processing_panel
schedule_state = fields.Selection(related='production_id.schedule_state', store=True) schedule_state = fields.Selection(related='production_id.schedule_state', store=True)
# 工件装夹信息 # 工件装夹信息
@@ -245,78 +196,15 @@ class ResMrpWorkOrder(models.Model):
production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id', production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id',
string='生产线', store=True, tracking=True) string='生产线', store=True, tracking=True)
production_line_state = fields.Selection( production_line_state = fields.Selection(related='production_id.production_line_state',
[('待上产线', '待上产线'), ('已上产线', '上产线'), ('已下产线', '已下产线')], string='/下产线', store=True, tracking=True)
string='上/下产线', default='待上产线', tracking=True) detection_report = fields.Binary('检测报告', readonly=True)
detection_report = fields.Binary('检测报告', readonly=False)
is_remanufacture = fields.Boolean(string='重新生成制造订单', default=False) is_remanufacture = fields.Boolean(string='重新生成制造订单', default=False)
is_fetchcnc = fields.Boolean(string='重新获取NC程序', default=False) is_fetchcnc = fields.Boolean(string='重新获取NC程序', default=False)
reason = fields.Selection( reason = fields.Selection(
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"), ("operate computer", "操机"), [("programming", "编程"), ("clamping", "返工"), ("cutter", "刀具"), ("operate computer", "操机"),
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因", tracking=True) ("technology", "工艺"), ("customer redrawing", "客户改图"), ("other", "其他"), ], string="原因", tracking=True)
detailed_reason = fields.Text('详细原因') detailed_reason = fields.Text('详细原因')
is_rework = fields.Boolean(string='是否返工', default=False)
@api.constrains('blocked_by_workorder_ids')
def _check_no_cyclic_dependencies(self):
if self.production_id.state not in ['rework'] and self.state not in ['rework']:
if not self._check_m2m_recursion('blocked_by_workorder_ids'):
raise ValidationError(_("您不能创建周期性的依赖关系."))
def _plan_workorder(self, replan=False):
self.ensure_one()
# Plan workorder after its predecessors
start_date = max(self.production_id.date_planned_start, datetime.now())
for workorder in self.blocked_by_workorder_ids:
if workorder.state in ['done', 'cancel', 'rework']:
continue
workorder._plan_workorder(replan)
start_date = max(start_date, workorder.date_planned_finished)
# Plan only suitable workorders
if self.state not in ['pending', 'waiting', 'ready']:
return
if self.leave_id:
if replan:
self.leave_id.unlink()
else:
return
# Consider workcenter and alternatives
workcenters = self.workcenter_id | self.workcenter_id.alternative_workcenter_ids
best_finished_date = datetime.max
vals = {}
for workcenter in workcenters:
# Compute theoretical duration
if self.workcenter_id == workcenter:
duration_expected = self.duration_expected
else:
duration_expected = self._get_duration_expected(alternative_workcenter=workcenter)
from_date, to_date = workcenter._get_first_available_slot(start_date, duration_expected)
# If the workcenter is unavailable, try planning on the next one
if not from_date:
continue
# Check if this workcenter is better than the previous ones
if to_date and to_date < best_finished_date:
best_start_date = from_date
best_finished_date = to_date
best_workcenter = workcenter
vals = {
'workcenter_id': workcenter.id,
'duration_expected': duration_expected,
}
# If none of the workcenter are available, raise
if best_finished_date == datetime.max:
raise UserError(_('Impossible to plan the workorder. Please check the workcenter availabilities.'))
# Create leave on chosen workcenter calendar
leave = self.env['resource.calendar.leaves'].create({
'name': self.display_name,
'calendar_id': best_workcenter.resource_calendar_id.id,
'date_from': best_start_date,
'date_to': best_finished_date,
'resource_id': best_workcenter.resource_id.id,
'time_type': 'other'
})
vals['leave_id'] = leave.id
self.write(vals)
@api.onchange('rfid_code') @api.onchange('rfid_code')
def _onchange(self): def _onchange(self):
@@ -331,7 +219,7 @@ class ResMrpWorkOrder(models.Model):
sql = """ sql = """
SELECT * SELECT *
FROM mrp_workorder FROM mrp_workorder
WHERE state!='rework' WHERE
to_char(date_planned_start::timestamp + '8 hour','YYYY-MM-DD HH:mm:SS')>= %s to_char(date_planned_start::timestamp + '8 hour','YYYY-MM-DD HH:mm:SS')>= %s
AND to_char(date_planned_finished::timestamp + '8 hour','YYYY-MM-DD HH:mm:SS')<= %s AND to_char(date_planned_finished::timestamp + '8 hour','YYYY-MM-DD HH:mm:SS')<= %s
""" """
@@ -343,6 +231,16 @@ class ResMrpWorkOrder(models.Model):
ids = [t[0] for t in self.env.cr.fetchall()] ids = [t[0] for t in self.env.cr.fetchall()]
return [('id', 'in', ids)] 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') @api.onchange('functional_fixture_id')
def _onchange_functional_fixture_id(self): def _onchange_functional_fixture_id(self):
if self.functional_fixture_id: if self.functional_fixture_id:
@@ -542,7 +440,6 @@ class ResMrpWorkOrder(models.Model):
work.compensation_value_y = eval(self.material_center_point)[1] work.compensation_value_y = eval(self.material_center_point)[1]
# work.process_state = '待加工' # work.process_state = '待加工'
# self.sudo().production_id.process_state = '待加工' # self.sudo().production_id.process_state = '待加工'
# self.sudo().production_id.process_state = '待加工'
self.date_finished = datetime.now() self.date_finished = datetime.now()
workorder.button_finish() workorder.button_finish()
@@ -573,22 +470,8 @@ class ResMrpWorkOrder(models.Model):
else: else:
raise UserError(_("该工单暂未完成,无法进行工件配送")) raise UserError(_("该工单暂未完成,无法进行工件配送"))
def button_rework_pre(self):
return {
'name': _('返工'),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'sf.rework.wizard',
'target': 'new',
'context': {
'default_workorder_id': self.id,
'default_production_id': self.production_id.id,
# 'default_programming_state': self.production_id.programming_state,
'default_routing_type': self.routing_type
}}
# 拼接工单对象属性值 # 拼接工单对象属性值
def json_workorder_str(self, k, production, route, item): def json_workorder_str(self, k, production, route):
# 计算预计时长duration_expected # 计算预计时长duration_expected
if route.routing_type == '切割': if route.routing_type == '切割':
duration_expected = self.env['mrp.routing.workcenter'].sudo().search( duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
@@ -621,7 +504,7 @@ class ResMrpWorkOrder(models.Model):
'processing_panel': k, 'processing_panel': k,
'quality_point_ids': route.route_workcenter_id.quality_point_ids, 'quality_point_ids': route.route_workcenter_id.quality_point_ids,
'routing_type': route.routing_type, 'routing_type': route.routing_type,
# 'work_state': '待发起', 'work_state': '待发起',
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids, 'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,
route.routing_type, route.routing_type,
production.product_id), production.product_id),
@@ -630,10 +513,6 @@ class ResMrpWorkOrder(models.Model):
'date_planned_finished': datetime.now() + timedelta(days=1), 'date_planned_finished': datetime.now() + timedelta(days=1),
'duration_expected': duration_expected, 'duration_expected': duration_expected,
'duration': 0, '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( 'workpiece_delivery_ids': False if not route.routing_type == '装夹预调' else self._json_workpiece_delivery_list(
production) production)
}] }]
@@ -643,16 +522,12 @@ class ResMrpWorkOrder(models.Model):
up_route = self.env['sf.agv.task.route'].search([('route_type', '=', '上产线')], limit=1, order='id asc') up_route = self.env['sf.agv.task.route'].search([('route_type', '=', '上产线')], limit=1, order='id asc')
down_route = self.env['sf.agv.task.route'].search([('route_type', '=', '下产线')], limit=1, order='id asc') down_route = self.env['sf.agv.task.route'].search([('route_type', '=', '下产线')], limit=1, order='id asc')
return [ return [
[0, '', [0, '', {'production_id': production.id, 'type': '上产线', 'route_id': up_route.id,
{'production_id': production.id, 'production_line_id': production.production_line_id.id, 'type': '上产线', 'feeder_station_start_id': up_route.start_site_id.id,
'route_id': up_route.id, 'feeder_station_destination_id': up_route.end_site_id.id}],
'feeder_station_start_id': up_route.start_site_id.id, [0, '', {'production_id': production.id, 'type': '下产线', 'route_id': down_route.id,
'feeder_station_destination_id': up_route.end_site_id.id}], 'feeder_station_start_id': down_route.start_site_id.id,
[0, '', 'feeder_station_destination_id': down_route.end_site_id.id}]]
{'production_id': production.id, 'production_line_id': production.production_line_id.id, 'type': '下产线',
'route_id': down_route.id,
'feeder_station_start_id': down_route.start_site_id.id,
'feeder_station_destination_id': down_route.end_site_id.id}]]
# 拼接工单对象属性值(表面工艺) # 拼接工单对象属性值(表面工艺)
def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id): def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id):
@@ -798,6 +673,119 @@ class ResMrpWorkOrder(models.Model):
# 'target':'new' # 'target':'new'
# } # }
def recreateManufacturingOrWorkerOrder(self):
"""
重新生成制造订单或者重新生成工单
"""
if self.test_results in ['返工', '报废']:
values = self.env['mrp.production'].create_production1_values(self.production_id)
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
self.production_id.company_id).create(
values)
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
productions._create_workorder(is_fetchcnc=self.is_fetchcnc, scrap_production=self.production_id)
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
(
p.move_dest_ids.procure_method != 'make_to_order' and
not p.move_raw_ids and not p.workorder_ids)).action_confirm()
for production_item in productions:
process_parameter_workorder = self.env['mrp.workorder'].search(
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_item.id),
('is_subcontract', '=', True)])
if process_parameter_workorder:
is_pick = False
consecutive_workorders = []
m = 0
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id)
for i in range(len(sorted_workorders) - 1):
if m == 0:
is_pick = False
if sorted_workorders[i].supplier_id.id == sorted_workorders[i + 1].supplier_id.id and \
sorted_workorders[i].is_subcontract == sorted_workorders[i + 1].is_subcontract and \
sorted_workorders[i].id == sorted_workorders[i + 1].id - 1:
if sorted_workorders[i] not in consecutive_workorders:
consecutive_workorders.append(sorted_workorders[i])
consecutive_workorders.append(sorted_workorders[i + 1])
m += 1
continue
else:
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production_item)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
# 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单
if is_pick is False:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i],
production_item)
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production_item)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production_item)
if is_pick is False and m == 0:
if len(sorted_workorders) == 1:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production_item)
else:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production_item)
for production in productions:
origin_production = production.move_dest_ids and production.move_dest_ids[
0].raw_material_production_id or False
orderpoint = production.orderpoint_id
if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual':
production.message_post(
body=_('This production order has been created from Replenishment Report.'),
message_type='comment',
subtype_xmlid='mail.mt_note')
elif orderpoint:
production.message_post_with_view(
'mail.message_origin_link',
values={'self': production, 'origin': orderpoint},
subtype_id=self.env.ref('mail.mt_note').id)
elif origin_production:
production.message_post_with_view(
'mail.message_origin_link',
values={'self': production, 'origin': origin_production},
subtype_id=self.env.ref('mail.mt_note').id)
'''
创建生产计划
'''
# 工单耗时
workorder_duration = 0
for workorder in productions.workorder_ids:
workorder_duration += workorder.duration_expected
sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)])
if sale_order:
sale_order.mrp_production_ids |= productions
# sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({
'name': productions.name,
'order_deadline': sale_order.deadline_of_delivery,
'production_id': productions.id,
'date_planned_start': productions.date_planned_start,
'origin': productions.origin,
'product_qty': productions.product_qty,
'product_id': productions.product_id.id,
'state': 'draft',
})
# if self.test_results == '返工':
# productions = self.production_id
# # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
# # self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
# productions._create_workorder2(self.processing_panel)
# else:
# self.results = '合格'
def json_workorder_str1(self, k, production, route): def json_workorder_str1(self, k, production, route):
workorders_values_str = [0, '', { workorders_values_str = [0, '', {
'product_uom_id': production.product_uom_id.id, 'product_uom_id': production.product_uom_id.id,
@@ -821,152 +809,28 @@ class ResMrpWorkOrder(models.Model):
}] }]
return workorders_values_str return workorders_values_str
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state', # @api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state')
'production_id.tool_state') # def _compute_state(self):
def _compute_state(self): # super(ResMrpWorkOrder, self)._compute_state()
super()._compute_state() # for item in self:
for workorder in self: # print(item.name)
re_work = self.env['mrp.workorder'].search([('production_id', '=', workorder.production_id.id), # print(item.state)
('processing_panel', '=', workorder.processing_panel), # print(item.is_remanufacture)
('is_rework', '=', True), ('state', 'in', ['done', 'rework'])]) # scrap_workorder = self.env['mrp.workorder'].search(
cnc_workorder = self.env['mrp.workorder'].search( # [('production_id', '=', item.production_id.id), ('routing_type', '=', 'CNC加工'),
[('production_id', '=', workorder.production_id.id), # ('state', '=', 'done'), ('test_results', 'in', ['返工', '报废'])])
('processing_panel', '=', workorder.processing_panel), # print(scrap_workorder)
('routing_type', '=', 'CNC加工'), ('state', 'in', ['done', 'rework']), # # if item.routing_type == 'CNC加工' and item.state in ['done'] and item.test_results in ['返工', '报废']:
('test_results', '=', '返工')]) # if item.routing_type == '解除装夹':
cnc_workorder_pending = self.env['mrp.workorder'].search( # if scrap_workorder and item.state not in ['cancel']:
[('production_id', '=', workorder.production_id.id), # item.state = 'cancel'
('processing_panel', '=', workorder.processing_panel), # elif item.routing_type == '表面工艺':
('routing_type', '=', 'CNC加工'), ('state', 'in', ['pending'])]) # if scrap_workorder:
unclamp_workorder = self.env['mrp.workorder'].search( # stock_move = self.env['stock.move'].search(
[('production_id', '=', workorder.production_id.id), # [('origin', '=', item.production_id.name)])
('sequence', '=', workorder.sequence - 1), # stock_move.write({'state': 'cancel'})
('state', 'in', ['done'])]) # item.picking_ids.write({'state': 'cancel'})
if workorder.state not in ['cancel', 'progress', 'rework']: # item.state = 'cancel'
if workorder.production_id.state == 'rework':
if workorder.routing_type == '装夹预调' and workorder.state not in ['done', 'rework',
'cancel']:
# # 有返工工单
# if re_work:
# 新工单
if workorder.is_rework is False:
if workorder.production_id.programming_state == '已编程' and workorder.production_id.is_rework is False:
if re_work or cnc_workorder:
workorder.state = 'ready'
else:
if workorder.production_id.is_rework is True:
if re_work or cnc_workorder:
workorder.state = 'waiting'
elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'rework', 'cancel']:
pre_workorder = self.env['mrp.workorder'].search(
[('production_id', '=', workorder.production_id.id),
('processing_panel', '=', workorder.processing_panel),
('routing_type', '=', '装夹预调'), ('state', '=', 'done')])
if pre_workorder:
if re_work:
workorder.state = 'waiting'
elif workorder.routing_type == '解除装夹' and workorder.state not in ['done', 'rework', 'cancel']:
if cnc_workorder:
if not cnc_workorder_pending:
workorder.state = 'waiting'
# else:
# if workorder.production_id.is_rework is True:
# workorder.state = 'waiting'
elif workorder.production_id.state == 'progress':
if workorder.routing_type == '装夹预调' and workorder.production_id.programming_state == '已编程' and \
workorder.is_rework is False and workorder.state not in [
'done', 'rework',
'cancel']:
if workorder.production_id.is_rework is False:
if re_work or cnc_workorder or unclamp_workorder:
workorder.state = 'ready'
# if (re_work or cnc_workorder) and workorder.production_id.is_rework is False:
# workorder.state = 'ready'
if workorder.routing_type == '表面工艺' and workorder.state not in ['done', 'progress']:
if unclamp_workorder:
workorder.state = 'ready'
# else:
# if workorder.state not in ['cancel', 'rework']:
# workorder.state = 'rework'
if workorder.routing_type == '装夹预调' and workorder.state in ['waiting', 'ready', 'pending']:
workorder_ids = workorder.production_id.workorder_ids
work_bo = True
for wo in workorder_ids.filtered(lambda a: a.routing_type == '装夹预调' and a.state == 'rework'):
if not workorder_ids.filtered(
lambda a: (a.routing_type == '装夹预调' and a.state not in ['rework', 'cancel']
and a.processing_panel == wo.processing_panel)):
work_bo = False
break
if (workorder.production_id.programming_state == '已编程' and work_bo
and not workorder_ids.filtered(lambda a: a.sequence == 0)):
# 当工单对应制造订单的功能刀具状态为 【无效刀】时,先对的第一个装夹预调工单状态设置为 【等待组件】
if workorder.production_id.tool_state in ['1', '2']:
if workorder.state in ['ready']:
workorder.state = 'waiting'
continue
elif workorder.state in ['waiting']:
continue
elif workorder.state == 'pending' and workorder == self.search(
[('production_id', '=', workorder.production_id.id),
('routing_type', '=', '装夹预调'),
('state', 'not in', ['rework', 'done', 'cancel'])],
limit=1,
order="sequence"):
workorder.state = 'waiting'
continue
elif workorder.production_id.tool_state in ['0']:
if workorder_ids.filtered(lambda a: a.state == 'rework'):
if not workorder_ids.filtered(
lambda a: (a.routing_type not in ['装夹预调'] and
a.state not in ['pending', 'done', 'rework', 'cancel'])):
# 查询工序最小的非完工、非返工的装夹预调工单
work_id = self.search(
[('production_id', '=', workorder.production_id.id),
('routing_type', '=', '装夹预调'),
('state', 'not in', ['rework', 'done', 'cancel'])],
limit=1,
order="sequence")
if workorder == work_id:
if workorder.production_id.reservation_state == 'assigned':
workorder.state = 'ready'
elif workorder.production_id.reservation_state != 'assigned':
workorder.state = 'waiting'
continue
if workorder.production_id.tool_state in ['1', '2'] and workorder.state == 'ready':
workorder.state = 'waiting'
continue
# elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'cancel', 'progress',
# 'rework']:
# per_work = self.env['mrp.workorder'].search(
# [('routing_type', '=', '装夹预调'), ('production_id', '=', workorder.production_id.id),
# ('processing_panel', '=', workorder.processing_panel), ('is_rework', '=', True)])
# if per_work:
# workorder.state = 'waiting'
# if workorder.routing_type == 'CNC加工' and workorder.state == 'progress':
# workorder.state = 'to be detected'
# for workorder in self:
# if workorder.is_rework is True and workorder.state == 'done':
# cnc_work = self.env['mrp.workorder'].search([('routing_type','=','CNC加工'),('production_id','=',workorder.production_id.id)])
# if cnc_work:
# cnc_work.state = 'waiting'
# if workorder.state == 'pending':
# if all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
# workorder.state = 'ready' if workorder.production_id.reservation_state == 'assigned' else 'waiting'
# continue
# if workorder.state not in ('waiting', 'ready'):
# continue
# if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
# workorder.state = 'pending'
# continue
# if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'):
# continue
# if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting':
# workorder.state = 'ready'
# elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready':
# workorder.state = 'waiting'
# 重写工单开始按钮方法 # 重写工单开始按钮方法
def button_start(self): def button_start(self):
@@ -986,13 +850,11 @@ class ResMrpWorkOrder(models.Model):
if not cnc_workorder.cnc_ids: if not cnc_workorder.cnc_ids:
raise UserError(_('该制造订单还未下发CNC程序请稍后再试')) raise UserError(_('该制造订单还未下发CNC程序请稍后再试'))
else: else:
if self.production_id.tool_state in ['1', '2']: for item in cnc_workorder.cnc_ids:
if self.production_id.tool_state == '1': functional_cutting_tool = self.env['sf.functional.cutting.tool.entity'].search(
state = '缺刀' [('tool_name_id.name', '=', item.cutting_tool_name)])
else: if not functional_cutting_tool:
state = '无效刀' raise UserError(_('该制造订单的CNC程序为%s没有对应的功能刀具' % item.cutting_tool_name))
raise UserError(
f'制造订单【{self.production_id.name}】功能刀具状态为【{state}】!')
if self.routing_type == '解除装夹': if self.routing_type == '解除装夹':
''' '''
记录开始时间 记录开始时间
@@ -1007,9 +869,10 @@ class ResMrpWorkOrder(models.Model):
('location_dest_id', '=', self.env['stock.location'].search( ('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id), [('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.production_id.name)]) ('origin', '=', self.production_id.name)])
if move_out: purchase = self.env['purchase.order'].search([('origin', '=', self.production_id.name)])
if purchase and move_out:
move_out.write({'state': 'assigned'}) move_out.write({'state': 'assigned'})
self.env['stock.move.line'].create(move_out.get_move_line(self.production_id, self)) self.env['stock.move.line'].create(move_out.get_move_line(purchase, self))
# move_out._action_assign() # move_out._action_assign()
if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress': if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress':
@@ -1076,7 +939,7 @@ class ResMrpWorkOrder(models.Model):
if record.routing_type == '装夹预调': if record.routing_type == '装夹预调':
if not record.material_center_point and record.X_deviation_angle > 0: if not record.material_center_point and record.X_deviation_angle > 0:
raise UserError("请对前置三元检测定位参数进行计算定位") raise UserError("请对前置三元检测定位参数进行计算定位")
if not record.rfid_code and record.is_rework is False: if not record.rfid_code:
raise UserError("请扫RFID码进行绑定") raise UserError("请扫RFID码进行绑定")
record.process_state = '待加工' record.process_state = '待加工'
# record.write({'process_state': '待加工'}) # record.write({'process_state': '待加工'})
@@ -1085,15 +948,6 @@ class ResMrpWorkOrder(models.Model):
record.process_state = '待解除装夹' record.process_state = '待解除装夹'
# record.write({'process_state': '待加工'}) # record.write({'process_state': '待加工'})
record.production_id.process_state = '待解除装夹' record.production_id.process_state = '待解除装夹'
record.production_id.write({'detection_result_ids': [(0, 0, {
'rework_reason': record.reason,
'detailed_reason': record.detailed_reason,
'processing_panel': record.processing_panel,
'routing_type': record.routing_type,
'handle_result': '待处理' if record.test_results == '返工' or record.is_rework is True else '',
'test_results': record.test_results,
'test_report': record.detection_report})],
'is_scrap': True if record.test_results == '报废' else False})
if record.routing_type == '解除装夹': if record.routing_type == '解除装夹':
''' '''
记录结束时间 记录结束时间
@@ -1142,86 +996,76 @@ class ResMrpWorkOrder(models.Model):
record.write({ record.write({
'date_planned_finished': tem_date_planned_finished # 保持原值 '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 ['返工', '报废']: # if record.routing_type == 'CNC加工' and record.test_results in ['返工', '报废']:
# record.production_id.action_cancel() # record.production_id.action_cancel()
# record.production_id.workorder_ids.write({'rfid_code': False, 'rfid_code_old': record.rfid_code}) # record.production_id.workorder_ids.write({'rfid_code': False, 'rfid_code_old': record.rfid_code})
# if record.is_remanufacture is True: # if record.is_remanufacture is True:
# record.recreateManufacturingOrWorkerOrder() # record.recreateManufacturingOrWorkerOrder()
is_production_id = False is_production_id = True
rework_workorder = record.production_id.workorder_ids.filtered(lambda p: p.state == 'rework') for workorder in record.production_id.workorder_ids:
done_workorder = record.production_id.workorder_ids.filtered(lambda p1: p1.state == 'done') if workorder.state != 'done':
if (len(rework_workorder) + len(done_workorder) == len(record.production_id.workorder_ids)) or ( is_production_id = False
len(done_workorder) == len(record.production_id.workorder_ids)):
is_production_id = True
if record.routing_type in ['解除装夹'] or (
record.is_rework is True and record.routing_type in ['装夹预调']) or (
record.test_results in ['返工', '报废'] and record.routing_type in ['CNC加工']):
for workorder in record.production_id.workorder_ids:
if workorder.processing_panel == record.processing_panel:
rfid_code = workorder.rfid_code
workorder.write({'rfid_code_old': rfid_code,
'rfid_code': False})
if workorder.rfid_code:
raise ValidationError(f'{workorder.name}】工单解绑失败,请重新点击完成按钮!!!')
# workorder.rfid_code_old = rfid_code
# workorder.rfid_code = False
logging.info('workorder.rfid_code:%s' % workorder.rfid_code)
if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺']: if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺']:
logging.info('product_qty:%s' % record.production_id.product_qty) for workorder in record.production_id.workorder_ids:
workorder.rfid_code_old = workorder.rfid_code
workorder.rfid_code = None
for move_raw_id in record.production_id.move_raw_ids: for move_raw_id in record.production_id.move_raw_ids:
move_raw_id.quantity_done = move_raw_id.product_uom_qty move_raw_id.quantity_done = move_raw_id.product_uom_qty
record.process_state = '已完工' record.process_state = '已完工'
record.production_id.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( raw_move = self.env['stock.move'].sudo().search(
[('origin', '=', record.production_id.name), [('origin', '=', record.production_id.name), ('procure_method', '=', 'make_to_order'),
('procure_method', 'in', ['make_to_order', 'make_to_stock']),
('state', '!=', 'done')]) ('state', '!=', 'done')])
if raw_move: if raw_move:
raw_move.write({'state': 'done'}) raw_move.write({'state': 'done'})
record.production_id.button_mark_done1() record.production_id.button_mark_done1()
# record.production_id.state = 'done' # self.production_id.state = 'done'
# 将FTP的检测报告文件下载到临时目录 # 将FTP的检测报告文件下载到临时目录
def download_reportfile_tmp(self, workorder, reportpath): def download_reportfile_tmp(self, workorder, reportpath):
logging.info('reportpath/ftp地址:%s' % reportpath) logging.info('reportpath:%s' % reportpath)
logging.info('processing_panel:%s' % workorder.processing_panel) production_no_ftp = reportpath.split('/')
serverdir = os.path.join('/tmp', workorder.production_id.name.replace('/', '_'), 'detection', production_no = workorder.production_id.name.replace('/', '_')
workorder.processing_panel) # ftp地址
ftp_resconfig = self.env['res.config.settings'].get_values() remotepath = os.path.join('/NC', production_no_ftp[1], 'detection')
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), logging.info('ftp地址:%s' % remotepath)
ftp_resconfig['ftp_user'], if reportpath.find(production_no) != -1:
ftp_resconfig['ftp_password']) # 服务器内临时地址
if not ftp.file_exists_1(reportpath): serverdir = os.path.join('/tmp', production_no_ftp[1], 'detection')
logging.info('文件不存在:%s' % reportpath) ftp_resconfig = self.env['res.config.settings'].get_values()
download_state = ftp.download_program_file(reportpath, serverdir) ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']),
logging.info('download_state:%s' % download_state) ftp_resconfig['ftp_user'],
ftp_resconfig['ftp_password'])
download_state = ftp.download_reportfile_tree(remotepath, serverdir, reportpath)
logging.info('download_state:%s' % download_state)
else:
download_state = 2
return download_state return download_state
# 根据中控系统提供的检测文件地址去ftp里对应的制造订单里获取 # 根据中控系统提供的检测文件地址去ftp里对应的制造订单里获取
def get_detection_file(self, workorder, reportPath): def get_detection_file(self, workorder, reportPath):
serverdir = os.path.join('/tmp', workorder.production_id.name.replace('/', '_'), 'detection', # if reportPath.startswith('/'):
workorder.processing_panel) # reportPath = reportPath[4:]
# serverdir = os.path.join('/tmp', reportPath)
serverdir = '/tmp' + reportPath
logging.info('get_detection_file-serverdir:%s' % serverdir) logging.info('get_detection_file-serverdir:%s' % serverdir)
for root, dirs, files in os.walk(serverdir): serverdir_prefix = os.path.dirname(serverdir)
logging.info('serverdir_prefix-serverdir:%s' % serverdir_prefix)
for root, dirs, files in os.walk(serverdir_prefix):
for filename in files: for filename in files:
logging.info('filename:%s' % filename)
logging.info('reportPath:%s' % os.path.basename(reportPath))
if filename == os.path.basename(reportPath): if filename == os.path.basename(reportPath):
report_file_path = os.path.join(root, filename) report_file_path = os.path.join(root, filename)
logging.info('get_detection_file-report_file_path:%s' % report_file_path) logging.info('get_detection_file-report_file_path:%s' % report_file_path)
workorder.detection_report = base64.b64encode(open(report_file_path, 'rb').read()) workorder.detection_report = base64.b64encode(open(report_file_path, 'rb').read())
return True return True
def print_method(self):
"""
解除装夹处调用关联制造订单的关联序列号的打印方法
"""
if self.production_id:
if self.production_id.lot_producing_id:
self.production_id.lot_producing_id.print_single_method()
else:
raise UserError("无关联制造订单或关联序列号,无法打印。请检查!")
class CNCprocessing(models.Model): class CNCprocessing(models.Model):
_name = 'sf.cnc.processing' _name = 'sf.cnc.processing'
@@ -1247,9 +1091,6 @@ class CNCprocessing(models.Model):
production_id = fields.Many2one('mrp.production', string="制造订单") production_id = fields.Many2one('mrp.production', string="制造订单")
button_state = fields.Boolean(string='是否已经下发') button_state = fields.Boolean(string='是否已经下发')
program_path = fields.Char('程序文件路径') program_path = fields.Char('程序文件路径')
program_create_date = fields.Datetime('程序创建日期')
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='刀具状态', default='0')
# mrs下发编程单创建CNC加工 # mrs下发编程单创建CNC加工
def cnc_processing_create(self, cnc_workorder, ret, program_path, program_path_tmp): def cnc_processing_create(self, cnc_workorder, ret, program_path, program_path_tmp):
@@ -1282,28 +1123,24 @@ class CNCprocessing(models.Model):
cnc_workorder.write({'programming_state': '已编程', 'work_state': '已编程'}) cnc_workorder.write({'programming_state': '已编程', 'work_state': '已编程'})
return cnc_processing return cnc_processing
def _json_cnc_processing(self, panel, ret): def _json_cnc_processing(self, obj):
cnc_processing = [] cnc_processing_str = (0, 0, {
if ret is not False: 'sequence_number': obj['sequence_number'],
for item in ret['programming_list']: 'program_name': obj['program_name'],
if item['processing_panel'] == panel and item['ftp_path'].find('.dmi') == -1: 'cutting_tool_name': obj['cutting_tool_name'],
cnc_processing.append((0, 0, { 'cutting_tool_no': obj['cutting_tool_no'],
'sequence_number': item['sequence_number'], 'processing_type': obj['processing_type'],
'program_name': item['program_name'], 'margin_x_y': obj['margin_x_y'],
'cutting_tool_name': item['cutting_tool_name'], 'margin_z': obj['margin_z'],
'cutting_tool_no': item['cutting_tool_no'], 'depth_of_processing_z': obj['depth_of_processing_z'],
'processing_type': item['processing_type'], 'cutting_tool_extension_length': obj['cutting_tool_extension_length'],
'margin_x_y': item['margin_x_y'], 'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
'margin_z': item['margin_z'], 'estimated_processing_time': obj['estimated_processing_time'],
'depth_of_processing_z': item['depth_of_processing_z'], 'program_path': obj['program_path'],
'cutting_tool_extension_length': item['cutting_tool_extension_length'], 'cnc_id': obj['cnc_id'].id,
'cutting_tool_handle_type': item['cutting_tool_handle_type'], 'remark': obj['remark']
'estimated_processing_time': item['estimated_processing_time'], })
'program_path': item['ftp_path'], return cnc_processing_str
'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进行匹配 # 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配
def get_cnc_processing_file(self, serverdir, cnc_processing, program_path): def get_cnc_processing_file(self, serverdir, cnc_processing, program_path):
@@ -1333,16 +1170,14 @@ class CNCprocessing(models.Model):
}) })
return attachment return attachment
# 将FTP的多面的程序单文件下载到临时目录 # 将FTP的nc文件下载到临时目录
def download_file_tmp(self, production_no, processing_panel): def download_file_tmp(self, production_no, processing_panel):
remotepath = os.path.join('/home/ftp/ftp_root/NC', production_no, 'return', processing_panel) remotepath = os.path.join('/NC', production_no, 'return', processing_panel)
serverdir = os.path.join('/tmp', 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_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 = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],
ftp_resconfig['ftp_password']) ftp_resconfig['ftp_password'])
if not ftp.file_exists_1(remotepath): download_state = ftp.download_file_tree(remotepath, serverdir)
logging.info('目录不存在:%s' % remotepath)
download_state = ftp.download_program_file(remotepath, serverdir)
logging.info('download_state:%s' % download_state) logging.info('download_state:%s' % download_state)
return download_state return download_state
@@ -1387,7 +1222,6 @@ class SfWorkOrderBarcodes(models.Model):
_inherit = ["mrp.workorder", "barcodes.barcode_events_mixin"] _inherit = ["mrp.workorder", "barcodes.barcode_events_mixin"]
def on_barcode_scanned(self, barcode): def on_barcode_scanned(self, barcode):
logging.info('Rfid:%s' % barcode)
workorder = self.env['mrp.workorder'].browse(self.ids) workorder = self.env['mrp.workorder'].browse(self.ids)
# workorder_preset = self.env['mrp.workorder'].search( # workorder_preset = self.env['mrp.workorder'].search(
# [('routing_type', '=', '装夹预调'), ('rfid_code', '=', barcode)]) # [('routing_type', '=', '装夹预调'), ('rfid_code', '=', barcode)])
@@ -1420,18 +1254,17 @@ class SfWorkOrderBarcodes(models.Model):
workorder.write(val) workorder.write(val)
self.write(val) self.write(val)
workorder_rfid = self.env['mrp.workorder'].search( 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: if workorder_rfid:
for item in workorder_rfid: for item in workorder_rfid:
item.write({'rfid_code': barcode}) item.write({'rfid_code': barcode})
logging.info("Rfid[%s]绑定成功!!!" % barcode) logging.info("Rfid绑定成功")
else: else:
raise UserError('该Rfid【%s】绑定的是【%s】, 不是托盘!!!' % (barcode, lot.product_id.name)) raise UserError('该Rfid【%s】绑定的是【%s】, 不是托盘!!!' % (barcode, lot.product_id.name))
self.process_state = '待检测' self.process_state = '待检测'
self.date_start = datetime.now() self.date_start = datetime.now()
else: else:
raise UserError('没有找到Rfid为【%s】的托盘信息!!!' % barcode) raise UserError('托盘信息不存在')
# stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)]) # stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)])
# if stock_move_line.product_id.categ_type == '夹具': # if stock_move_line.product_id.categ_type == '夹具':
# workorder.write({ # workorder.write({
@@ -1505,8 +1338,7 @@ class WorkPieceDelivery(models.Model):
[('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型') [('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型')
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration') delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
status = fields.Selection( status = fields.Selection(
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送'), ('已取消', '已取消')], string='状态', [('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', default='待下发',
default='待下发',
tracking=True) tracking=True)
is_cnc_program_down = fields.Boolean('程序是否下发', default=False, tracking=True) is_cnc_program_down = fields.Boolean('程序是否下发', default=False, tracking=True)
is_manual_work = fields.Boolean('人工操作', default=False) is_manual_work = fields.Boolean('人工操作', default=False)
@@ -1749,23 +1581,80 @@ class CMMprogram(models.Model):
_name = 'sf.cmm.program' _name = 'sf.cmm.program'
_description = "CMM程序" _description = "CMM程序"
cmm_id = fields.Many2one('ir.attachment')
sequence_number = fields.Integer('序号') sequence_number = fields.Integer('序号')
program_name = fields.Char('程序名') 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('备注') remark = fields.Text('备注')
workorder_id = fields.Many2one('mrp.workorder', string="工单") workorder_id = fields.Many2one('mrp.workorder', string="工单")
production_id = fields.Many2one('mrp.production', string="制造订单") production_id = fields.Many2one('mrp.production', string="制造订单")
program_path = fields.Char('程序文件路径') program_path = fields.Char('程序文件路径')
program_create_date = fields.Datetime('程序创建日期')
def _json_cmm_program(self, panel, ret): def cmm_program_create(self, ret, program_path, program_path_tmp):
cmm_program = [] cmm_program = None
if ret is not False: for obj in ret['programming_list']:
for item in ret['programming_list']: workorder = self.env['mrp.workorder'].search(
if item['processing_panel'] == panel and item['ftp_path'].find('.dmi') != -1: [('production_id.name', '=', ret['production_order_no'].split(',')[0]),
cmm_program.append((0, 0, { ('processing_panel', '=', obj['processing_panel']),
'sequence_number': 1, ('routing_type', '=', 'CNC加工')])
'program_name': item['program_name'], if obj['program_name'] in program_path:
'program_path': item['ftp_path'], logging.info('obj:%s' % obj['program_name'])
'program_create_date': datetime.strptime(item['program_create_date'], '%Y-%m-%d %H:%M:%S'), 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)
return cmm_program 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

View File

@@ -616,7 +616,7 @@ class ResProductMo(models.Model):
item['model_width'] + model_type.embryo_tolerance) * ( item['model_width'] + model_type.embryo_tolerance) * (
item['model_height'] + model_type.embryo_tolerance), item['model_height'] + model_type.embryo_tolerance),
'product_model_type_id': model_type.id, 'product_model_type_id': model_type.id,
# 'model_processing_panel': 'R', 'model_processing_panel': 'R',
'model_machining_precision': item['model_machining_precision'], 'model_machining_precision': item['model_machining_precision'],
'model_code': item['barcode'], 'model_code': item['barcode'],
'length': item['model_long'], 'length': item['model_long'],
@@ -634,10 +634,9 @@ class ResProductMo(models.Model):
'model_process_parameters_ids': [(6, 0, [])] if not item.get( 'model_process_parameters_ids': [(6, 0, [])] if not item.get(
'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']), 'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']),
'model_remark': item['remark'], 'model_remark': item['remark'],
'single_manufacturing': True,
'default_code': '%s-%s' % (order_number, i), 'default_code': '%s-%s' % (order_number, i),
'manual_quotation': item['manual_quotation'] or False, 'manual_quotation': item['manual_quotation'] or False,
'part_number': item.get('part_number') or '', 'part_number': item['part_number'] or '',
'active': True, 'active': True,
} }
copy_product_id.sudo().write(vals) copy_product_id.sudo().write(vals)

View File

@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import base64 import base64
import qrcode import qrcode
from itertools import groupby
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
import logging import logging
import io import io
@@ -205,18 +204,63 @@ class StockRule(models.Model):
productions_values) productions_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()) self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
''' '''
创建工单 创建工单
''' '''
# productions._create_workorder() productions._create_workorder(is_fetchcnc=False, scrap_production=False)
#
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 \ 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_dest_ids.procure_method != 'make_to_order' and not
p.move_raw_ids and not p.workorder_ids)).action_confirm() 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: for production in productions:
''' '''
创建制造订单时生成序列号 创建制造订单时生成序列号
@@ -262,29 +306,6 @@ class StockRule(models.Model):
'product_id': production.product_id.id, 'product_id': production.product_id.id,
'state': 'draft', '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 return True
@@ -405,7 +426,6 @@ class ProductionLot(models.Model):
def print_single_method(self): def print_single_method(self):
print('self.name========== %s' % self.name)
self.ensure_one() self.ensure_one()
qr_code_data = self.qr_code_image qr_code_data = self.qr_code_image
if not qr_code_data: if not qr_code_data:
@@ -489,10 +509,10 @@ class StockPicking(models.Model):
('location_dest_id', '=', self.env['stock.location'].search( ('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id), [('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.origin)]) ('origin', '=', self.origin)])
# if self.id == move_out.picking_id.id: if self.id == move_out.picking_id.id:
# if move_out.move_line_ids.workorder_id.state not in ['progress']: if move_out.move_line_ids.workorder_id.state not in ['progress']:
# raise UserError( raise UserError(
# _('该出库单里源单据内的单号为%s的工单还未开始,不能进行验证操作!' % move_out.move_line_ids.workorder_id.name)) _('该出库单里源单据内的单号为%s的工单还未开始,不能进行验证操作!' % move_out.move_line_ids.workorder_id.name))
# 入库单验证 # 入库单验证
move_in = self.env['stock.move'].search( move_in = self.env['stock.move'].search(
[('location_dest_id', '=', self.env['stock.location'].search( [('location_dest_id', '=', self.env['stock.location'].search(
@@ -508,17 +528,18 @@ class StockPicking(models.Model):
res = super().button_validate() res = super().button_validate()
if res is True: if res is True:
if self.id == move_out.picking_id.id: 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( move_in = self.env['stock.move'].search(
[('location_dest_id', '=', self.env['stock.location'].search( [('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
('location_id', '=', self.env['stock.location'].search( ('location_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id), [('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.origin)]) ('origin', '=', self.origin)])
production = self.env['mrp.production'].search([('name', '=', self.origin)]) # purchase = self.env['purchase.order'].search([('origin', '=', self.origin)])
if move_in: if move_in:
move_in.write({'state': 'assigned'}) move_in.write({'state': 'assigned'})
self.env['stock.move.line'].create(move_in.get_move_line(production, None)) purchase = self.env['purchase.order'].search([('origin', '=', self.origin)])
self.env['stock.move.line'].create(move_in.get_move_line(purchase, None))
return res return res
@@ -600,7 +621,7 @@ class ReStockMove(models.Model):
'state': 'confirmed', 'state': 'confirmed',
} }
def get_move_line(self, production_id, sorted_workorders): def get_move_line(self, purchase, sorted_workorders):
return { return {
'move_id': self.id, 'move_id': self.id,
'product_id': self.product_id.id, 'product_id': self.product_id.id,
@@ -609,7 +630,7 @@ class ReStockMove(models.Model):
'location_dest_id': self.picking_id.location_dest_id.id, 'location_dest_id': self.picking_id.location_dest_id.id,
'picking_id': self.picking_id.id, 'picking_id': self.picking_id.id,
'reserved_uom_qty': 1.0, 'reserved_uom_qty': 1.0,
'lot_id': production_id.move_line_raw_ids.lot_id.id, 'lot_id': purchase.picking_ids.move_line_ids.lot_id.id,
'company_id': self.company_id.id, 'company_id': self.company_id.id,
# 'workorder_id': '' if not sorted_workorders else sorted_workorders.id, # 'workorder_id': '' if not sorted_workorders else sorted_workorders.id,
# 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id, # 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id,
@@ -680,36 +701,13 @@ 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): def _put_tool_lot(self, company, product, origin):
if product.tracking == "lot" and self.product_id.categ_id.name == '刀具': if product.tracking == "lot" and self.product_id.categ_id.name == '刀具':
if not self.move_line_nosuggest_ids: if not self.move_line_nosuggest_ids:
lot_code = '%s-%s-%s' % ('%s-T-DJWL-%s' % ( lot_names = self.env['stock.lot'].generate_lot_names(
product.cutting_tool_model_id.code.split('-')[0], product.cutting_tool_material_id.code), '%s-%s-%s' % ('%s-T-DJWL-%s' % (
datetime.now().strftime("%Y%m%d"), origin) product.cutting_tool_model_id.code.split('-')[0], product.cutting_tool_material_id.code),
move_line_ids = self.env['stock.move.line'].sudo().search([('lot_name', 'like', lot_code)], limit=1, datetime.now().strftime("%Y%m%d"), origin), 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) move_lines_commands = self._generate_serial_move_line_commands_tool_lot(lot_names)
self.write({'move_line_nosuggest_ids': move_lines_commands}) self.write({'move_line_nosuggest_ids': move_lines_commands})
for item in self.move_line_nosuggest_ids: for item in self.move_line_nosuggest_ids:

View File

@@ -1,9 +1,8 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_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_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_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,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_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_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_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_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 access_sf_model_type_manager,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_manager,1,1,1,0
@@ -29,7 +28,7 @@ access_mrp_workorder_group_sf_mrp_user,mrp_workorder,model_mrp_workorder,sf_base
access_mrp_workorder_manager,mrp_workorder,model_mrp_workorder,sf_base.group_sf_mrp_manager,1,1,1,0 access_mrp_workorder_manager,mrp_workorder,model_mrp_workorder,sf_base.group_sf_mrp_manager,1,1,1,0
access_mrp_workcenter_group_sf_mrp_user,mrp_workcenter,model_mrp_workcenter,sf_base.group_sf_mrp_user,1,0,0,0 access_mrp_workcenter_group_sf_mrp_user,mrp_workcenter,model_mrp_workcenter,sf_base.group_sf_mrp_user,1,0,0,0
access_mrp_workcenter_manager,mrp_workcenter,model_mrp_workcenter,sf_base.group_sf_mrp_manager,1,1,1,0 access_mrp_workcenter_manager,mrp_workcenter,model_mrp_workcenter,sf_base.group_sf_mrp_manager,1,1,1,0
access_mrp_workcenter_productivity_group_sf_equipment_user,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_equipment_user,1,1,1,0 access_mrp_workcenter_productivity_group_sf_mrp_user,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_mrp_user,1,0,0,0
access_mrp_workcenter_productivity_manager,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_mrp_manager,1,1,1,0 access_mrp_workcenter_productivity_manager,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_workpiece_delivery_group_sf_order_user,sf_workpiece_delivery_group_sf_order_user,model_sf_workpiece_delivery,sf_base.group_sf_order_user,1,1,1,0 access_sf_workpiece_delivery_group_sf_order_user,sf_workpiece_delivery_group_sf_order_user,model_sf_workpiece_delivery,sf_base.group_sf_order_user,1,1,1,0
access_sf_workpiece_delivery_group_sf_equipment_user,sf_workpiece_delivery_group_sf_equipment_user,model_sf_workpiece_delivery,sf_base.group_sf_equipment_user,1,1,0,0 access_sf_workpiece_delivery_group_sf_equipment_user,sf_workpiece_delivery_group_sf_equipment_user,model_sf_workpiece_delivery,sf_base.group_sf_equipment_user,1,1,0,0
@@ -141,14 +140,3 @@ access_sf_model_type_group_sf_stock_manager,sf_model_type_group_sf_mrp_manager,m
access_mrp_bom_byproduct_group_sf_stock_user,mrp_bom_byproduct_group_sf_stock_user,mrp.model_mrp_bom_byproduct,sf_base.group_sf_stock_user,1,0,0,0 access_mrp_bom_byproduct_group_sf_stock_user,mrp_bom_byproduct_group_sf_stock_user,mrp.model_mrp_bom_byproduct,sf_base.group_sf_stock_user,1,0,0,0
access_mrp_bom_byproduct_group_sf_stock_manager,mrp_bom_byproduct_group_sf_mrp_manager,mrp.model_mrp_bom_byproduct,sf_base.group_sf_stock_manager,1,0,0,0 access_mrp_bom_byproduct_group_sf_stock_manager,mrp_bom_byproduct_group_sf_mrp_manager,mrp.model_mrp_bom_byproduct,sf_base.group_sf_stock_manager,1,0,0,0
access_sf_rework_wizard_group_sf_order_user,sf_rework_wizard_group_sf_order_user,model_sf_rework_wizard,sf_base.group_sf_order_user,1,1,1,0
access_sf_rework_wizard_group_plan_dispatch,sf_rework_wizard_group_plan_dispatch,model_sf_rework_wizard,sf_base.group_plan_dispatch,1,1,1,0
access_sf_detection_result_group_sf_order_user,sf_detection_result_group_sf_order_user,model_sf_detection_result,sf_base.group_sf_order_user,1,1,1,0
access_sf_detection_result_group_plan_dispatch,sf_detection_result_group_plan_dispatch,model_sf_detection_result,sf_base.group_plan_dispatch,1,1,1,0
access_sf_detection_result_group_sf_equipment_user,sf_detection_result_group_sf_equipment_user,model_sf_detection_result,sf_base.group_sf_equipment_user,1,1,1,0
access_sf_processing_panel_group_sf_order_user,sf_processing_panel_group_sf_order_user,model_sf_processing_panel,sf_base.group_sf_order_user,1,1,1,0
access_sf_production_wizard_group_sf_order_user,sf_production_wizard_group_sf_order_user,model_sf_production_wizard,sf_base.group_sf_order_user,1,1,1,0
access_sf_processing_panel_group_plan_dispatch,sf_processing_panel_group_plan_dispatch,model_sf_processing_panel,sf_base.group_plan_dispatch,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 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
3 access_sf_cnc_processing_manager sf_cnc_processing model_sf_cnc_processing sf_base.group_sf_mrp_manager 1 1 1 0
4 access_sf_cmm_program_group_sf_mrp_user 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
5 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
6 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
7 access_sf_model_type_admin sf_model_type_admin model_sf_model_type base.group_system 1 1 1 0
8 access_sf_model_type_manager sf_model_type model_sf_model_type sf_base.group_sf_mrp_manager 1 1 1 0
28 access_mrp_workorder_manager mrp_workorder model_mrp_workorder sf_base.group_sf_mrp_manager 1 1 1 0
29 access_mrp_workcenter_group_sf_mrp_user mrp_workcenter model_mrp_workcenter sf_base.group_sf_mrp_user 1 0 0 0
30 access_mrp_workcenter_manager mrp_workcenter model_mrp_workcenter sf_base.group_sf_mrp_manager 1 1 1 0
31 access_mrp_workcenter_productivity_group_sf_equipment_user access_mrp_workcenter_productivity_group_sf_mrp_user mrp_workcenter_productivity model_mrp_workcenter_productivity sf_base.group_sf_equipment_user sf_base.group_sf_mrp_user 1 1 0 1 0 0
32 access_mrp_workcenter_productivity_manager mrp_workcenter_productivity model_mrp_workcenter_productivity sf_base.group_sf_mrp_manager 1 1 1 0
33 access_sf_workpiece_delivery_group_sf_order_user sf_workpiece_delivery_group_sf_order_user model_sf_workpiece_delivery sf_base.group_sf_order_user 1 1 1 0
34 access_sf_workpiece_delivery_group_sf_equipment_user sf_workpiece_delivery_group_sf_equipment_user model_sf_workpiece_delivery sf_base.group_sf_equipment_user 1 1 0 0
140
141
142

View File

@@ -1,16 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<data> <data>
<record id="custom_mrp_production_tree_view" model="ir.ui.view"> <record id="custom_mrp_production_tree_view" model="ir.ui.view">
<field name="name">custom.mrp.production.tree</field> <field name="name">custom.mrp.production.tree</field>
<field name="model">mrp.production</field> <field name="model">mrp.production</field>
<field name="inherit_id" ref="mrp.mrp_production_tree_view"/> <field name="inherit_id" ref="mrp.mrp_production_tree_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<!-- <xpath expr="//button[@name='do_unreserve']" position="after">-->
<!-- <button name="do_update_program" type="object" string="更新程序"-->
<!-- groups="sf_base.group_sf_mrp_user"/>-->
<!-- </xpath>-->
<xpath expr="//field[@name='product_id']" position="replace"/> <xpath expr="//field[@name='product_id']" position="replace"/>
<xpath expr="//field[@name='product_qty']" position="replace"/> <xpath expr="//field[@name='product_qty']" position="replace"/>
<xpath expr="//field[@name='product_uom_id']" position="replace"/> <xpath expr="//field[@name='product_uom_id']" position="replace"/>
@@ -67,41 +62,33 @@
<field name="inherit_id" ref="mrp.mrp_production_form_view"/> <field name="inherit_id" ref="mrp.mrp_production_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='state']" position="attributes"> <xpath expr="//field[@name='state']" position="attributes">
<!-- <attribute name="statusbar_visible">draft,confirmed,progress,pending_processing,completed,done --> <!-- <attribute name="statusbar_visible">draft,confirmed,progress,pending_processing,completed,done -->
<!-- </attribute> --> <!-- </attribute> -->
<attribute name="statusbar_visible"> <attribute name="statusbar_visible">progress,pending_cam,pending_processing,pending_era_cam,completed,done
confirmed,pending_cam,progress,done
</attribute> </attribute>
</xpath> </xpath>
<xpath expr="//sheet//group//group[2]//label" position="before"> <xpath expr="//sheet//group//group[2]//label" position="before">
<!-- <field name="process_state"/> --> <!-- <field name="process_state"/> -->
<field name="state" readonly="1"/> <field name="state"/>
<!-- <field name="process_state"/> --> <!-- <field name="process_state"/> -->
</xpath> </xpath>
<xpath expr="//sheet//group//group//div[3]" position="after"> <xpath expr="//sheet//group//group//div[3]" position="after">
<field name="manual_quotation" readonly="1"/>
<field name="programming_no" readonly="1"/> <field name="programming_no" readonly="1"/>
<field name="programming_state" readonly="1"
decoration-success="programming_state == '已编程'"
decoration-warning="programming_state =='编程中'"
decoration-danger="programming_state =='已编程未下发'"/>
<field name="work_state" invisible="1"/> <field name="work_state" invisible="1"/>
<field name="schedule_state" invisible='1'/> <field name="schedule_state" invisible='1'/>
<field name="is_scrap" invisible='1'/> <field name="manual_quotation" readonly="1"/>
<field name="is_rework" invisible='1'/> <field name="programming_state" readonly="1"/>
</xpath> </xpath>
<xpath expr="//field[@name='user_id']" position="before"> <xpath expr="//field[@name='user_id']" position="before">
<field name="plan_start_processing_time" readonly="1"/> <field name="plan_start_processing_time" readonly="1"/>
</xpath> </xpath>
<xpath expr="//field[@name='user_id']" position="after"> <xpath expr="//field[@name='user_id']" position="after">
<field name="production_line_id" readonly="1"/> <field name="production_line_id" readonly="1"/>
<!-- <field name="production_line_state" readonly="1"/>--> <field name="production_line_state" readonly="1"/>
<field name="part_number" string="成品的零件图号"/> <field name="part_number" string="成品的零件图号"/>
<field name="part_drawing"/> <field name="part_drawing"/>
<field name="tool_state"/>
<field name="tool_state_remark" string="备注" attrs="{'invisible': [('tool_state', '!=', '1')]}"/>
<field name="tool_state_remark2" invisible="1"/>
</xpath> </xpath>
<xpath expr="//header//button[@name='action_cancel']" position="replace"> <xpath expr="//header//button[@name='action_cancel']" position="replace">
<button name="action_cancel" type="object" string="取消" data-hotkey="z" <button name="action_cancel" type="object" string="取消" data-hotkey="z"
@@ -118,20 +105,9 @@
<xpath expr="(//header//button[@name='button_mark_done'])[2]" position="replace"> <xpath expr="(//header//button[@name='button_mark_done'])[2]" position="replace">
<button name="button_mark_done" <button name="button_mark_done"
attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}" attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}"
string="验证" type="object" data-hotkey="g" string="验证" type="object" class="oe_highlight" data-hotkey="g"
groups="sf_base.group_sf_mrp_user"/> groups="sf_base.group_sf_mrp_user"/>
</xpath> </xpath>
<xpath expr="(//header//button[@name='button_scrap'])" position="replace">
<button name="button_scrap" invisible="1"/>
<button name="do_update_program" string="更新程序" type="object" groups="sf_base.group_sf_mrp_user"
confirm="是否确认更新程序"
attrs="{'invisible': ['|',('state', '!=', 'rework'),('programming_state', '!=', '已编程未下发')]}"/>
<button name="button_rework" string="返工" type="object" groups="sf_base.group_sf_mrp_user"
attrs="{'invisible': ['|',('state', '!=', 'rework') ,('programming_state', '!=', '已编程')]}"/>
<!-- <button name="%(sf_manufacturing.action_sf_production_wizard)d" string="报废" type="action"-->
<!-- groups="sf_base.group_sf_mrp_user"-->
<!-- attrs="{'invisible': [('is_scrap', '=', False)]}"/>-->
</xpath>
<xpath expr="(//header//button[@name='button_mark_done'])[3]" position="replace"> <xpath expr="(//header//button[@name='button_mark_done'])[3]" position="replace">
<button name="button_mark_done" attrs="{'invisible': [ <button name="button_mark_done" attrs="{'invisible': [
'|', '|',
@@ -161,11 +137,11 @@
attrs="{'invisible': ['|', ('is_planned', '=', False), ('state', '=', 'cancel')]}" attrs="{'invisible': ['|', ('is_planned', '=', False), ('state', '=', 'cancel')]}"
data-hotkey="x" groups="sf_base.group_sf_mrp_user"/> data-hotkey="x" groups="sf_base.group_sf_mrp_user"/>
</xpath> </xpath>
<!-- <xpath expr="//header//button[@name='button_scrap']" position="replace">--> <xpath expr="//header//button[@name='button_scrap']" position="replace">
<!-- <button name="button_scrap" type="object" string="报废"--> <button name="button_scrap" type="object" string="报废"
<!-- attrs="{'invisible': [('state', 'in', ('cancel', 'draft'))]}" data-hotkey="y"--> attrs="{'invisible': [('state', 'in', ('cancel', 'draft'))]}" data-hotkey="y"
<!-- groups="sf_base.group_sf_mrp_user"/>--> groups="sf_base.group_sf_mrp_user"/>
<!-- </xpath>--> </xpath>
<xpath expr="//header//button[@name='action_confirm']" position="replace"> <xpath expr="//header//button[@name='action_confirm']" position="replace">
@@ -278,35 +254,7 @@
</xpath> </xpath>
<xpath expr="//sheet//notebook//page[@name='operations']" position="attributes"> <xpath expr="//sheet//notebook//page[@name='operations']" position="attributes">
<attribute name="attrs">{'invisible': ['|',('schedule_state', '=', '未排'),('workorder_ids', '=', <attribute name="attrs">{'invisible': [('schedule_state', '=', '未排')]}</attribute>
[])]}
</attribute>
</xpath>
<xpath expr="//sheet//notebook//page[@name='operations']" position="after">
<page string="检测结果" attrs="{'invisible': [('detection_result_ids', '=', [])]}">
<field name="detection_result_ids" string="" readonly="1">
<tree sample="1">
<field name="production_id" invisible="1"/>
<field name="processing_panel"/>
<field name="routing_type"/>
<field name="rework_reason"/>
<field name="detailed_reason"/>
<field name="test_results"/>
<field name="handle_result"/>
<field name="test_report" invisible="1"/>
<button name="button_look_test_report" string="查看测试报告" type="object"
attrs="{'invisible': [('test_report', '=', False)]}"
class="btn btn-primary me-1"/>
</tree>
</field>
</page>
</xpath>
<xpath expr="//sheet//notebook//page[@name='components']" position="attributes">
<attribute name="string">投料</attribute>
</xpath>
<xpath expr="//field[@name='components_availability']" position="attributes">
<attribute name="string">投料状态</attribute>
</xpath> </xpath>
</field> </field>
</record> </record>
@@ -329,22 +277,10 @@
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_production_workorder_tree_editable_view"/> <field name="inherit_id" ref="mrp.mrp_production_workorder_tree_editable_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//tree" position="attributes">
<attribute name="default_order">sequence</attribute>
</xpath>
<xpath expr="//field[@name='state']" position="replace">
<field name="state" widget="badge" decoration-warning="state == 'progress'"
decoration-success="state == 'done'" decoration-danger="state in ('cancel','rework')"
decoration-muted="state == 'to be detected'"
decoration-info="state not in ('progress', 'done', 'cancel','rework','to be detected')"
attrs="{'invisible': [('production_state', '=', 'draft')], 'column_invisible': [('parent.state', '=', 'draft')]}"/>
</xpath>
<xpath expr="//tree//button[@name='button_start']" position="replace"> <xpath expr="//tree//button[@name='button_start']" position="replace">
<field name="routing_type" invisible="True"/> <field name="routing_type" invisible="True"/>
<button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始?" <button name="button_start" type="object" string="开始" class="btn-success"
attrs="{'invisible': ['|', '|', '|','|', ('production_state','in', ('draft', 'done', 'cancel')), attrs="{'invisible': ['|', '|', '|','|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False), ('routing_type', '=', 'CNC加工')]}"
('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=',
False), ('routing_type', '=', 'CNC加工')]}"
groups="sf_base.group_sf_mrp_user"/> groups="sf_base.group_sf_mrp_user"/>
</xpath> </xpath>
<xpath expr="//tree//button[@name='button_pending']" position="replace"> <xpath expr="//tree//button[@name='button_pending']" position="replace">
@@ -354,9 +290,8 @@
</xpath> </xpath>
<xpath expr="//tree//button[@name='button_finish']" position="replace"> <xpath expr="//tree//button[@name='button_finish']" position="replace">
<button name="button_finish" type="object" string="Done" class="btn-success" <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)]}" 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>
<xpath expr="//tree//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="replace"> <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" <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="Block"
@@ -374,10 +309,10 @@
<button name="action_open_wizard" type="object" icon="fa-external-link" class="oe_edit_only" <button name="action_open_wizard" type="object" icon="fa-external-link" class="oe_edit_only"
title="Open Work Order" title="Open Work Order"
context="{'default_workcenter_id': workcenter_id}" groups="sf_base.group_sf_mrp_user"/> context="{'default_workcenter_id': workcenter_id}" groups="sf_base.group_sf_mrp_user"/>
<!-- ======= --> <!-- ======= -->
<!-- <button name="button_start" type="object" string="开始" class="btn-success" --> <!-- <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)]}" --> <!-- 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"/> --> <!-- groups="sf_base.group_sf_mrp_user"/> -->
</xpath> </xpath>
<xpath expr="//tree//button[@name='button_pending']" position="replace"> <xpath expr="//tree//button[@name='button_pending']" position="replace">
<button name="button_pending" type="object" string="暂停" class="btn-warning" <button name="button_pending" type="object" string="暂停" class="btn-warning"
@@ -387,7 +322,7 @@
<xpath expr="//tree//button[@name='button_finish']" position="replace"> <xpath expr="//tree//button[@name='button_finish']" position="replace">
<button name="button_finish" type="object" string="完成" class="btn-success" <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加工')]}" 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" confirm="是否确认完成?"/> groups="sf_base.group_sf_mrp_user"/>
</xpath> </xpath>
<xpath expr="//tree//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="replace"> <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="阻塞" <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="阻塞"
@@ -424,9 +359,7 @@
<xpath expr="//header//button[@name='action_cancel']" position="replace"> <xpath expr="//header//button[@name='action_cancel']" position="replace">
<button name="action_cancel" type="object" string="取消" groups="sf_base.group_sf_mrp_user"/> <button name="action_cancel" type="object" string="取消" groups="sf_base.group_sf_mrp_user"/>
</xpath> </xpath>
<xpath expr="//field[@name='state']" position="after">
<field name="tool_state" invisible="1"/>
</xpath>
</field> </field>
</record> </record>
@@ -458,24 +391,6 @@
<field name="model">mrp.production</field> <field name="model">mrp.production</field>
<field name="inherit_id" ref="mrp.view_mrp_production_filter"/> <field name="inherit_id" ref="mrp.view_mrp_production_filter"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//filter[@name='filter_in_progress']" position="before">
<filter string="返工" name="filter_rework" domain="[('state', '=', 'rework')]"/>
</xpath>
<xpath expr="//filter[@name='planning_issues']" position="before">
<separator/>
<filter string="返工且已编程" name="filter_rework_programmed"
domain="[('state', '=', 'rework'),('programming_state', '=', '已编程')]"/>
<filter string="返工且已编程未下发" name="filter_rework_programmed_not_delivered"
domain="[('state', '=', 'rework'),('programming_state', '=', '已编程未下发')]"/>
<separator/>
<filter name="filter_programming" string="编程中"
domain="[('programming_state', '=', '编程中')]"/>
<filter name="filter_programmed" string="已编程"
domain="[('programming_state', '=', '已编程')]"/>
<filter name="filter_programmed_not_delivered" string="已编程未下发"
domain="[('programming_state', '=', '已编程未下发')]"/>
<separator/>
</xpath>
<xpath expr="//search" position="inside"> <xpath expr="//search" position="inside">
<searchpanel class="account_root"> <searchpanel class="account_root">
<field name="state" icon="fa-filter" enable_counters="1"/> <field name="state" icon="fa-filter" enable_counters="1"/>
@@ -561,72 +476,5 @@
</field> </field>
</record> </record>
<record model="ir.ui.view" id="sf_test_report_form">
<field name="name">sf.detection.result</field>
<field name="model">sf.detection.result</field>
<field name="arch" type="xml">
<form>
<group>
<!-- <field name="handle_result"/>-->
<field name="test_report" readonly="1" widget="pdf_viewer"/>
</group>
</form>
</field>
</record>
<record id="action_test_report_form" model="ir.actions.act_window">
<field name="name">检测报告</field>
<field name="res_model">sf.detection.result</field>
<field name="view_mode">form</field>
</record>
<!-- <menuitem action="mrp.mrp_production_action"-->
<!-- id="mrp_production_action"-->
<!-- sequence="1" active="False"/>-->
<!-- &lt;!&ndash; <record id="mrp_production_action_sf" model="ir.actions.act_window">&ndash;&gt;-->
<!-- &lt;!&ndash; <field name="name">Manufacturing Orders</field>&ndash;&gt;-->
<!-- &lt;!&ndash; <field name="type">ir.actions.act_window</field>&ndash;&gt;-->
<!-- &lt;!&ndash; <field name="res_model">mrp.production</field>&ndash;&gt;-->
<!-- &lt;!&ndash; <field name="view_mode">tree,kanban,form,calendar,pivot,graph</field>&ndash;&gt;-->
<!-- &lt;!&ndash; <field name="search_view_id" ref="mrp.view_mrp_production_filter"/>&ndash;&gt;-->
<!-- &lt;!&ndash; &lt;!&ndash; <field name="context">{'search_default_todo': True, 'default_company_id': allowed_company_ids[0]}</field>&ndash;&gt;&ndash;&gt;-->
<!-- &lt;!&ndash; <field name="domain">[('picking_type_id.active', '=', True)]</field>&ndash;&gt;-->
<!-- &lt;!&ndash; </record>&ndash;&gt;-->
<!-- &lt;!&ndash; <menuitem action="mrp_production_action_sf"&ndash;&gt;-->
<!-- &lt;!&ndash; id="menu_mrp_production_action_sf"&ndash;&gt;-->
<!-- &lt;!&ndash; parent="mrp.menu_mrp_manufacturing"&ndash;&gt;-->
<!-- &lt;!&ndash; sequence="2"&ndash;&gt;-->
<!-- &lt;!&ndash; string="制造订单"/>&ndash;&gt;-->
<!-- <record id="mrp_production_action_sf" model="ir.actions.act_window">-->
<!-- <field name="name">Manufacturing Orders</field>-->
<!-- <field name="type">ir.actions.act_window</field>-->
<!-- <field name="res_model">mrp.production</field>-->
<!-- <field name="view_mode">tree,kanban,form,calendar,pivot,graph</field>-->
<!-- <field name="view_id" eval="False"/>-->
<!-- <field name="search_view_id" ref="mrp.view_mrp_production_filter"/>-->
<!-- <field name="context">{'search_default_todo': True, 'default_company_id':-->
<!-- allowed_company_ids[0],'search_default_filter_rework':1,'search_default_filter_programmed':1}-->
<!-- </field>-->
<!-- <field name="domain">[('picking_type_id.active', '=', True)]</field>-->
<!-- &lt;!&ndash; &lt;!&ndash; <field name="help" type="html">&ndash;&gt;,'search_default_filter_rework': 1,&ndash;&gt;-->
<!-- &lt;!&ndash; 'search_default_filter_programming': 1&ndash;&gt;-->
<!-- &lt;!&ndash; <p class="o_view_nocontent_smiling_face">&ndash;&gt;-->
<!-- &lt;!&ndash; No manufacturing order found. Let's create one.&ndash;&gt;-->
<!-- &lt;!&ndash; </p>&ndash;&gt;-->
<!-- &lt;!&ndash; <p>&ndash;&gt;-->
<!-- &lt;!&ndash; Consume <a name="%(product.product_template_action)d" type='action' tabindex="-1">components</a> and&ndash;&gt;-->
<!-- &lt;!&ndash; build finished products using&ndash;&gt;-->
<!-- &lt;!&ndash; <a name="%(mrp_bom_form_action)d" type='action' tabindex="-1">bills of materials</a>&ndash;&gt;-->
<!-- &lt;!&ndash; </p>&ndash;&gt;-->
<!-- &lt;!&ndash; </field>&ndash;&gt;-->
<!-- </record>-->
<!-- <menuitem action="sf_manufacturing.mrp_production_action_sf"-->
<!-- id="mrp_production_action"-->
<!-- parent="mrp.menu_mrp_manufacturing"-->
<!-- sequence="1"/>-->
</data> </data>
</odoo> </odoo>

View File

@@ -24,20 +24,6 @@
</field> </field>
</record> </record>
<record id="custom_model_form_view_inherit" model="ir.ui.view">
<field name="name">custom.model.form.view.inherit</field>
<field name="model">mrp.workcenter</field>
<field name="inherit_id" ref="mrp.mrp_workcenter_view"/>
<field name="arch" type="xml">
<xpath expr='//form//sheet' position="after">
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</xpath>
</field>
</record>
<record id="mrp_workcenter_view_kanban_inherit_workorder" model="ir.ui.view"> <record id="mrp_workcenter_view_kanban_inherit_workorder" model="ir.ui.view">
<field name="name">mrp.workcenter.view.kanban.inherit.mrp.workorder</field> <field name="name">mrp.workcenter.view.kanban.inherit.mrp.workorder</field>
<field name="model">mrp.workcenter</field> <field name="model">mrp.workcenter</field>

View File

@@ -7,6 +7,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="name" position="replace"> <field name="name" position="replace">
<field name="is_subcontract" invisible="1"/> <field name="is_subcontract" invisible="1"/>
<field name="name" decoration-success="is_subcontract" decoration-bf="is_subcontract"/> <field name="name" decoration-success="is_subcontract" decoration-bf="is_subcontract"/>
</field> </field>
<field name="name" position="before"> <field name="name" position="before">
@@ -18,14 +19,6 @@
</field> </field>
<field name="state" position="after"> <field name="state" position="after">
<field name="work_state" optional="hide"/> <field name="work_state" optional="hide"/>
<field name="tool_state" invisible="1"/>
<field name="product_tmpl_name" invisible="1"/>
</field>
<field name="duration" position="replace">
<field name="duration" optional="hide"/>
</field>
<field name="workcenter_id" position="replace">
<field name="workcenter_id" optional="hide"/>
</field> </field>
<field name="product_id" position="after"> <field name="product_id" position="after">
<field name="equipment_id" optional="hide"/> <field name="equipment_id" optional="hide"/>
@@ -37,13 +30,13 @@
<field name="date_planned_start" string="计划开始日期" optional="show"/> <field name="date_planned_start" string="计划开始日期" optional="show"/>
</xpath> </xpath>
<xpath expr="//field[@name='date_planned_finished']" position="replace"> <xpath expr="//field[@name='date_planned_finished']" position="replace">
<field name="date_planned_finished" string="计划结束日期" optional="hide"/> <field name="date_planned_finished" string="计划结束日期" optional="show"/>
</xpath> </xpath>
<xpath expr="//button[@name='button_start']" position="attributes"> <xpath expr="//button[@name='button_start']" position="attributes">
<attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft', <attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',
'done', 'done',
'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')),
('is_user_working', '!=', False),("user_permissions","=",False),("name","=","CNC加工")]} ('is_user_working', '!=', False),("user_permissions","=",False),("name","=","获取CNC加工程序")]}
</attribute> </attribute>
</xpath> </xpath>
<xpath expr="//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="attributes"> <xpath expr="//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="attributes">
@@ -91,7 +84,7 @@
<!-- <field name="target">fullscreen</field>--> <!-- <field name="target">fullscreen</field>-->
<field name="target">current</field> <field name="target">current</field>
<field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field> <field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>
<field name="context">{'search_default_product': 1, 'search_default_workcenter_id': active_id}</field> <field name="context">{'search_default_workcenter_id': active_id}</field>
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_workorder"> <p class="o_view_nocontent_workorder">
没有工单要做! 没有工单要做!
@@ -113,10 +106,6 @@
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/> <field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//header/field[@name='state']" position="replace">
<field name="state" widget="statusbar"
statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/>
</xpath>
<xpath expr="//div[@name='button_box']" position="inside"> <xpath expr="//div[@name='button_box']" position="inside">
<button type="object" name="action_view_surface_technics_picking" class="oe_stat_button" icon="fa-truck" <button type="object" name="action_view_surface_technics_picking" class="oe_stat_button" icon="fa-truck"
groups="base.group_user,sf_base.group_sf_order_user" groups="base.group_user,sf_base.group_sf_order_user"
@@ -125,12 +114,9 @@
</button> </button>
</xpath> </xpath>
<xpath expr="//field[@name='state']" position="before"> <xpath expr="//field[@name='state']" position="before">
<field name='tool_state' invisible="1"/>
<field name='user_permissions' invisible="1"/> <field name='user_permissions' invisible="1"/>
<field name='name' invisible="1"/> <field name='name' invisible="1"/>
<field name='is_rework' invisible="1"/>
<field name='is_delivery' invisible="1"/> <field name='is_delivery' invisible="1"/>
<!-- <field name='is_send_program_again' invisible="1"/>-->
<!-- 工单form页面的开始停工按钮等 --> <!-- 工单form页面的开始停工按钮等 -->
<!-- <button name="button_start" type="object" string="开始" class="btn-success" --> <!-- <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加工', '解除装夹'))]}" --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','ready'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" -->
@@ -142,8 +128,8 @@
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','progress'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" --> <!-- 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="是否确认完工"/> --> <!-- groups="sf_base.group_sf_mrp_user" confirm="是否确认完工"/> -->
<button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始" <button name="button_start" type="object" string="开始" class="btn-success"
attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/> 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" <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)]}"/> attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
<button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工" <button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工"
@@ -165,12 +151,7 @@
<!-- groups="sf_base.group_sf_mrp_user" --> <!-- groups="sf_base.group_sf_mrp_user" -->
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> -->
<button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary" <button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary"
attrs="{'invisible': ['|','|','|','|',('routing_type','!=','装夹预调'),('is_delivery','=',True),('state','!=','done'),('is_rework','=',True),'&amp;',('rfid_code','in',['',False]),('state','=','done')]}"/> attrs="{'invisible': ['|',('routing_type','!=','装夹预调'),('is_delivery','=',True)]}"/>
<button name="button_rework_pre" type="object" string="返工"
class="btn-primary"
attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('state','!=','progress'),('is_rework','=',True)]}"/>
<button name="print_method" type="object" string="打印二维码" class="btn-primary"
attrs="{'invisible': ['|',('routing_type','!=','解除装夹'),('state','!=','done')]}"/>
</xpath> </xpath>
<xpath expr="//page[1]" position="before"> <xpath expr="//page[1]" position="before">
<page string="开料要求" attrs='{"invisible": [("routing_type","!=","切割")]}'> <page string="开料要求" attrs='{"invisible": [("routing_type","!=","切割")]}'>
@@ -189,11 +170,8 @@
</page> </page>
</xpath> </xpath>
<xpath expr="//label[1]" position="before"> <xpath expr="//label[1]" position="before">
<field name='routing_type' readonly="1"/> <field name='routing_type'/>
<field name='process_state' attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> <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>
<xpath expr="//label[1]" position="attributes"> <xpath expr="//label[1]" position="attributes">
<attribute name="string">计划加工时间</attribute> <attribute name="string">计划加工时间</attribute>
@@ -224,18 +202,21 @@
attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/> attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
<field name="processing_panel" readonly="1" <field name="processing_panel" readonly="1"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="equipment_id" readonly="1" <field name="equipment_id"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="production_line_id" <field name="production_line_id"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="production_line_state" readonly="1" <field name="production_line_state"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<!-- <field name="functional_fixture_id" --> <field name="functional_fixture_id"
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> --> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<!-- <field name="functional_fixture_code" force_save="1" --> <field name="functional_fixture_code" force_save="1"
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> --> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<!-- <field name="functional_fixture_type_id" --> <field name="functional_fixture_type_id"
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> --> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<field name="rfid_code" cache="True"
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
</group> </group>
<!-- <group>--> <!-- <group>-->
<!-- <div>--> <!-- <div>-->
@@ -248,6 +229,23 @@
<!-- <field name="processing_panel" readonly="1" attrs="{'invisible': [('routing_type', 'in', ('获取CNC加工程序','装夹','解除装夹',--> <!-- <field name="processing_panel" readonly="1" attrs="{'invisible': [('routing_type', 'in', ('获取CNC加工程序','装夹','解除装夹',-->
<!-- '前置三元定位检测','后置三元质量检测','解除装夹'))]}"/>--> <!-- '前置三元定位检测','后置三元质量检测','解除装夹'))]}"/>-->
</field> </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">--> <!-- <page string="Components" name="components">-->
<xpath expr="//page[1]" position="before"> <xpath expr="//page[1]" position="before">
<!-- <page string="装夹托盘" attrs='{"invisible": [("routing_type","!=","装夹")]}'>--> <!-- <page string="装夹托盘" attrs='{"invisible": [("routing_type","!=","装夹")]}'>-->
@@ -283,26 +281,20 @@
<!-- </group>--> <!-- </group>-->
<group string="托盘"> <group string="托盘">
<field name="tray_serial_number" readonly="1" string="序列号"/> <field name="tray_serial_number" readonly="1" string="序列号"/>
</group>
</group>
<group>
<group>
<field name="tray_product_id" readonly="1" string="名称"/> <field name="tray_product_id" readonly="1" string="名称"/>
<field name="tray_brand_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_type_id" readonly="1" string="类型"/>
<field name="tray_model_id" readonly="1" string="型号"/> <field name="tray_model_id" readonly="1" string="型号"/>
</group> </group>
</group> </group>
<group string="加工图纸">
<!-- 隐藏加工图纸字段名 -->
<field name="processing_drawing" widget="pdf_viewer" string="" readonly="1"/>
</group>
<group string="预调程序信息"> <group string="预调程序信息">
<field name="preset_program_information" colspan="2" nolabel="1" <field name="preset_program_information" colspan="2" nolabel="1"
placeholder="如有预调程序信息请在此处输入....."/> placeholder="如有预调程序信息请在此处输入....."/>
</group> </group>
<group string="加工图纸">
<!-- 隐藏加工图纸字段名 -->
<field name="processing_drawing" widget="pdf_viewer" string=""/>
</group>
</page> </page>
<page string="前置三元检测定位参数" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'> <page string="前置三元检测定位参数" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'>
@@ -472,11 +464,7 @@
<field name="production_line_id" readonly="1"/> <field name="production_line_id" readonly="1"/>
<field name="task_delivery_time" readonly="1"/> <field name="task_delivery_time" readonly="1"/>
<field name="task_completion_time" readonly="1"/> <field name="task_completion_time" readonly="1"/>
<field name="status" readonly="1" widget="badge" <field name="status" readonly="1"/>
decoration-success="status == '已配送'"
decoration-warning="status == '待下发'"
decoration-danger="status == '待配送'"
decoration-info="status== '已取消'"/>
</tree> </tree>
</field> </field>
</page> </page>
@@ -488,18 +476,16 @@
<field name="results" invisible="1"/> <field name="results" invisible="1"/>
<page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'> <page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<group> <group>
<field name="test_results" <field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/>
attrs='{"readonly":[("state","!=","to be detected")],"invisible":[("results","!=",False)]}'/> <field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/>
<!-- <field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/>--> <field name="is_fetchcnc"
<!-- <field name="is_fetchcnc"--> attrs='{"invisible":["|",("test_results","=","合格"),("is_remanufacture","=",False)]}'/>
<!-- attrs='{"invisible":["|",("test_results","=","合格"),("is_remanufacture","=",False)]}'/>-->
<field name="reason" <field name="reason"
attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/> attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/>
<field name="detailed_reason" <field name="detailed_reason" attrs='{"invisible":[("test_results","=","合格")]}'/>
attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/> <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>
<!-- <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>-->
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}' <field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
widget="pdf_viewer" readonly="1"/> widget="pdf_viewer"/>
</group> </group>
<!-- <div class="col-12 col-lg-6 o_setting_box">--> <!-- <div class="col-12 col-lg-6 o_setting_box">-->
<!-- <button type="object" class="oe_highlight" name="recreateManufacturingOrWorkerOrder"--> <!-- <button type="object" class="oe_highlight" name="recreateManufacturingOrWorkerOrder"-->
@@ -510,13 +496,12 @@
</xpath> </xpath>
<xpath expr="//page[1]" position="before"> <xpath expr="//page[1]" position="before">
<page string="CNC程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'> <page string="CNC程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<field name="cnc_ids" widget="one2many" string="工作程序" default_order="sequence_number,id" <field name="cnc_ids" widget="one2many" string="工作程序" default_order="sequence_number,id">
readonly="1"> <tree decoration-success="button_state" decoration-bf="button_state">
<tree>
<field name="sequence_number"/> <field name="sequence_number"/>
<field name="program_name"/> <field name="program_name"/>
<field name="cnc_id" string="文件"/>
<field name="cutting_tool_name"/> <field name="cutting_tool_name"/>
<field name="tool_state"/>
<field name="cutting_tool_no"/> <field name="cutting_tool_no"/>
<field name="processing_type"/> <field name="processing_type"/>
<field name="margin_x_y"/> <field name="margin_x_y"/>
@@ -525,10 +510,8 @@
<field name="cutting_tool_extension_length"/> <field name="cutting_tool_extension_length"/>
<field name="cutting_tool_handle_type"/> <field name="cutting_tool_handle_type"/>
<field name="estimated_processing_time"/> <field name="estimated_processing_time"/>
<field name="program_path"/>
<field name="program_create_date"/>
<field name="remark"/> <field name="remark"/>
<!-- <field name="button_state" invisible="1"/>--> <field name="button_state" invisible="1"/>
</tree> </tree>
</field> </field>
<group> <group>
@@ -536,12 +519,20 @@
</group> </group>
</page> </page>
<page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'> <page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<field name="cmm_ids" widget="one2many" string="CMM程序" readonly="1"> <field name="cmm_ids" widget="one2many" string="CMM程序">
<tree> <tree>
<field name="sequence_number"/> <field name="sequence_number"/>
<field name="program_name"/> <field name="program_name"/>
<field name="program_path"/> <field name="cmm_id" string="文件"/>
<field name="program_create_date"/> <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="remark"/> <field name="remark"/>
</tree> </tree>
</field> </field>
@@ -571,6 +562,9 @@
</div> </div>
</xpath> </xpath>
<xpath expr="//form//sheet//group//group//div[3]" position="after"> <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" <field name="save_name" widget="CopyClipboardChar"
attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/> attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/>
<label for="material_length" string="物料尺寸"/> <label for="material_length" string="物料尺寸"/>
@@ -589,20 +583,6 @@
</field> </field>
</record> </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>
<xpath expr="//filter[@name='progress']" position="after">
<filter string="待检测" name="state" domain="[('state','=','to be detected')]"/>
</xpath>
</field>
</record>
<record id="mrp_workorder_action_schedule" model="ir.actions.act_window"> <record id="mrp_workorder_action_schedule" model="ir.actions.act_window">
<field name="name">工单</field> <field name="name">工单</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
@@ -636,9 +616,7 @@
<field name="status" widget="badge" <field name="status" widget="badge"
decoration-success="status == '已配送'" decoration-success="status == '已配送'"
decoration-warning="status == '待下发'" decoration-warning="status == '待下发'"
decoration-danger="status == '待配送'" decoration-danger="status == '待配送'"/>
decoration-info="status == '已取消'"
/>
<field name="name"/> <field name="name"/>
<field name="production_id"/> <field name="production_id"/>
<field name="type" readonly="1"/> <field name="type" readonly="1"/>
@@ -724,7 +702,7 @@
</search> </search>
</field> </field>
</record> </record>
<record id="sf_workpiece_delivery_act" model="ir.actions.act_window"> <record id="sf_workpiece_delivery_act" model="ir.actions.act_window">
<field name="name">工件配送</field> <field name="name">工件配送</field>
<field name="res_model">sf.workpiece.delivery</field> <field name="res_model">sf.workpiece.delivery</field>
@@ -734,7 +712,7 @@
</field> </field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="domain"> <field name="domain">
[('type','in',['上产线','下产线']),('workorder_state','in',['done','rework']),('is_manual_work','=',false)] [('type','in',['上产线','下产线']),('workorder_state','=','done'),('is_manual_work','=',false)]
</field> </field>
</record> </record>

View File

@@ -100,7 +100,7 @@
<field name="model">sf.maintenance.logs</field> <field name="model">sf.maintenance.logs</field>
<field name="inherit_id" ref="sf_maintenance.view_maintenance_logs_tree"/> <field name="inherit_id" ref="sf_maintenance.view_maintenance_logs_tree"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='type']" position="after"> <xpath expr="//field[@name='code']" position="after">
<field name="production_line_id" optional="hide"/> <field name="production_line_id" optional="hide"/>
</xpath> </xpath>
</field> </field>

View File

@@ -41,8 +41,8 @@
<field name="model">stock.lot</field> <field name="model">stock.lot</field>
<field name="inherit_id" ref="stock.view_production_lot_tree"/> <field name="inherit_id" ref="stock.view_production_lot_tree"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='name']" position="after"> <xpath expr="//field[@name='create_date']" position="after">
<field name="rfid"/> <field name="rfid" invisible="1"/>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -1,3 +1 @@
from . import workpiece_delivery_wizard from . import workpiece_delivery_wizard
from . import rework_wizard
from . import production_wizard

View File

@@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
import logging
from odoo.exceptions import UserError, ValidationError
from datetime import datetime
from odoo import models, api, fields, _
class ProductionWizard(models.TransientModel):
_name = 'sf.production.wizard'
_description = '制造订单向导'
production_id = fields.Many2one('mrp.production', string='制造订单号')
is_reprogramming = fields.Boolean(string='申请重新编程', default=True)
is_remanufacture = fields.Boolean(string='重新生成制造订单', default=True)
def confirm(self):
if self.is_reprogramming is True:
self.production_id.update_programming_state()
self.production_id.action_cancel()

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="sf_production_wizard_form_view">
<field name="name">sf.production.wizard.form.view</field>
<field name="model">sf.production.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<field name="production_id" invisible="True"/>
<div>
重新生成制造订单
<field name="is_remanufacture"/>
</div>
<div>
申请重新编程
<field name="is_reprogramming" attrs='{"invisible": [("is_remanufacture","=",False)]}'/>
</div>
<footer>
<button string="确认" name="confirm" type="object" class="oe_highlight" confirm="是否确认报废"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
<record id="action_sf_production_wizard" model="ir.actions.act_window">
<field name="name">报废</field>
<field name="res_model">sf.production.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>

View File

@@ -1,200 +0,0 @@
# -*- coding: utf-8 -*-
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
import logging
from odoo.exceptions import UserError, ValidationError
from datetime import datetime
from odoo import models, api, fields, _
class ReworkWizard(models.TransientModel):
_name = 'sf.rework.wizard'
_description = '返工向导'
workorder_id = fields.Many2one('mrp.workorder', string='工单')
product_id = fields.Many2one('product.product')
production_id = fields.Many2one('mrp.production', string='制造订单号')
rework_reason = fields.Selection(
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"),
("operate computer", "操机"),
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因")
detailed_reason = fields.Text('详细原因')
routing_type = fields.Selection([
('装夹预调', '装夹预调'),
('CNC加工', 'CNC加工')], string="工序类型")
# 根据工单的加工面来显示
processing_panel_id = fields.Many2many('sf.processing.panel', string="加工面")
is_reprogramming = fields.Boolean(string='申请重新编程', default=False)
is_reprogramming_readonly = fields.Boolean(string='申请重新编程(只读)', default=False)
reprogramming_num = fields.Integer('重新编程次数', default=0)
programming_state = fields.Selection(
[('待编程', '待编程'), ('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'),
('已下发', '已下发')],
string='编程状态')
tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state')
def confirm(self):
if self.routing_type in ['装夹预调', 'CNC加工']:
self.workorder_id.is_rework = True
self.production_id.write({'detection_result_ids': [(0, 0, {
'rework_reason': self.rework_reason,
'detailed_reason': self.detailed_reason,
'processing_panel': self.workorder_id.processing_panel,
'routing_type': self.workorder_id.routing_type,
'handle_result': '待处理' if self.workorder_id.test_results == '返工' or self.workorder_id.is_rework is True else '',
'test_results': '返工' if not self.routing_type == 'CNC加工' else self.workorder_id.test_results,
'test_report': self.workorder_id.detection_report})]})
self.workorder_id.button_finish()
else:
if self.production_id.workorder_ids:
handle_result = self.production_id.detection_result_ids.filtered(
lambda dr: dr.handle_result == '待处理')
if handle_result:
processing_panels_to_handle = set(handle_item.processing_panel for handle_item in handle_result)
processing_panels_choice = set(dr_panel.name for dr_panel in self.processing_panel_id)
# 使用集合的差集操作找出那些待处理结果中有但实际可用加工面中没有的加工面
processing_panels_missing = processing_panels_to_handle - processing_panels_choice
# 存在不一致的加工面
if processing_panels_missing:
processing_panels_str = ','.join(processing_panels_missing)
raise UserError('您还有待处理的检测结果中为%s的加工面未选择' % processing_panels_str)
# processing_panels = set()
# for handle_item in handle_result:
# for dr_panel in self.processing_panel_id:
# if dr_panel.name == handle_item.processing_panel:
# processing_panels.add(dr_panel.name)
# if len(processing_panels) != len(handle_result):
# processing_panels_str = ','.join(processing_panels)
# return UserError(f'您还有待处理的检测结果中为{processing_panels_str}的加工面未选择')
for panel in self.processing_panel_id:
panel_workorder = self.production_id.workorder_ids.filtered(
lambda ap: ap.processing_panel == panel.name and ap.state != 'rework')
if panel_workorder:
panel_workorder.write({'state': 'rework'})
panel_workorder.filtered(
lambda wo: wo.routing_type == '装夹预调').workpiece_delivery_ids.filtered(
lambda wd: wd.status == '待下发').write({'status': '已取消'})
# workpiece = self.env['sf.workpiece.delivery'].search([('status', '=', '待下发'), (
# 'workorder_id', '=',
# panel_workorder.filtered(lambda wd: wd.routing_type == '装夹预调').id)])
product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search(
[('product_model_type_id', '=', self.production_id.product_id.product_model_type_id.id)],
order='sequence asc'
)
workorders_values = []
for route in product_routing_workcenter:
if route.is_repeat is True:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(panel.name,
self.production_id, route, False))
if workorders_values:
self.production_id.write({'workorder_ids': workorders_values, 'is_rework': True})
self.production_id._reset_work_order_sequence()
self.production_id.detection_result_ids.filtered(
lambda ap1: ap1.processing_panel == panel.name and ap1.handle_result == '待处理').write(
{'handle_result': '已处理'})
if self.is_reprogramming is False:
if self.programming_state in ['已编程', '已下发']:
if self.reprogramming_num >= 1 and self.programming_state == '已编程':
self.production_id.get_new_program(panel.name)
if self.reprogramming_num >= 0 and self.programming_state == '已下发':
ret = {'programming_list': []}
cnc_rework = max(
self.production_id.workorder_ids.filtered(
lambda
crw: crw.processing_panel == panel.name and crw.state == 'rework' and crw.routing_type == 'CNC加工'),
key=lambda w: w.create_date
)
if cnc_rework.cnc_ids:
for item_line in cnc_rework.cnc_ids:
vals = {
'sequence_number': item_line.sequence_number,
'program_name': item_line.program_name,
'cutting_tool_name': item_line.cutting_tool_name,
'cutting_tool_no': item_line.cutting_tool_no,
'processing_type': item_line.processing_type,
'margin_x_y': item_line.margin_x_y,
'margin_z': item_line.margin_z,
'depth_of_processing_z': item_line.depth_of_processing_z,
'cutting_tool_extension_length': item_line.cutting_tool_extension_length,
'estimated_processing_time': item_line.estimated_processing_time,
'cutting_tool_handle_type': item_line.cutting_tool_handle_type,
'program_path': item_line.program_path,
'ftp_path': item_line.program_path,
'processing_panel': panel.name,
'program_create_date': datetime.strftime(item_line.program_create_date,
'%Y-%m-%d %H:%M:%S'),
'remark': item_line.remark
}
ret['programming_list'].append(vals)
for cmm_line in cnc_rework.cmm_ids:
vals = {
'sequence_number': cmm_line.sequence_number,
'program_name': cmm_line.program_name,
'program_path': cmm_line.program_path,
'ftp_path': cmm_line.program_path,
'processing_panel': panel.name,
'program_create_date': datetime.strftime(
cmm_line.program_create_date,
'%Y-%m-%d %H:%M:%S')
}
ret['programming_list'].append(vals)
new_cnc_workorder = self.production_id.workorder_ids.filtered(
lambda ap1: ap1.processing_panel == panel.name and ap1.state not in (
'rework', 'done') and ap1.routing_type == 'CNC加工')
if not new_cnc_workorder.cnc_ids:
new_cnc_workorder.write({
'cnc_ids': new_cnc_workorder.cnc_ids.sudo()._json_cnc_processing(panel.name,
ret),
'cmm_ids': new_cnc_workorder.cmm_ids.sudo()._json_cmm_program(panel.name,
ret),
'cnc_worksheet': cnc_rework.cnc_worksheet})
new_pre_workorder = self.production_id.workorder_ids.filtered(lambda
p: p.routing_type == '装夹预调' and p.processing_panel == panel.name and p.state not in (
'rework', 'done'))
if new_pre_workorder:
pre_rework = max(self.production_id.workorder_ids.filtered(
lambda pr: pr.processing_panel == panel.name and pr.state in (
'rework') and pr.routing_type == '装夹预调'),
key=lambda w1: w1.create_date)
new_pre_workorder.write(
{'processing_drawing': pre_rework.processing_drawing})
self.production_id.write({'state': 'progress', 'is_rework': False})
elif self.programming_state in ['待编程', '编程中']:
self.production_id.write(
{'programming_state': '编程中', 'work_state': '编程中', 'is_rework': True})
if self.is_reprogramming is True:
self.production_id.update_programming_state()
self.production_id.write(
{'programming_state': '编程中', 'work_state': '编程中'})
if self.production_id.state == 'progress':
self.production_id.write({'programming_state': '已编程', 'work_state': '已编程'})
if self.reprogramming_num >= 1 and self.programming_state == '已编程':
productions_not_delivered = self.env['mrp.production'].search(
[('programming_no', '=', self.production_id.programming_no),
('programming_state', '=', '已编程未下发')])
if productions_not_delivered:
productions_not_delivered.write(
{'state': 'progress', 'programming_state': '已编程', 'work_state': '已编程',
'is_rework': False})
@api.onchange('production_id')
def onchange_processing_panel_id(self):
for item in self:
domain = [('id', '=', False)]
production_id = item.production_id
if production_id:
if self.env.user.has_group('sf_base.group_sf_order_user'):
panel_ids = []
panel_arr = production_id.product_id.model_processing_panel
for p in production_id.detection_result_ids.filtered(
lambda ap1: ap1.handle_result == '待处理'):
if p.processing_panel not in panel_arr:
panel_arr += ','.join(p.processing_panel)
for item in panel_arr.split(','):
panel = self.env['sf.processing.panel'].search(
[('name', 'ilike', item)])
if panel:
panel_ids.append(panel.id)
domain = {'processing_panel_id': [('id', 'in', panel_ids)]}
return {'domain': domain}

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="sf_rework_wizard_form_view">
<field name="name">sf.rework.wizard.form.view</field>
<field name="model">sf.rework.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<field name="production_id" invisible="True"/>
<field name="workorder_id" invisible="True"/>
<field name="product_id" invisible="True"/>
<field name="tool_state" invisible="True"/>
<field name="routing_type" invisible="True"/>
<group>
<field name="processing_panel_id" options="{'no_create': True}"
attrs='{"invisible": [("routing_type","=","装夹预调")]}' widget="many2many_tags"/>
</group>
<div attrs='{"invisible": [("reprogramming_num","=",0)]}'>
注意: 该制造订单的产品已重复编程过<field
name="reprogramming_num" string=""
readonly="1"
style='color:red;'/>次,且当前编程状态为
<field name="programming_state" string=""
decoration-info="programming_state == '待编程'"
decoration-success="programming_state == '已下发'"
decoration-warning="programming_state =='编程中'"
decoration-danger="programming_state =='已编程'" readonly="1"/>
</div>
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","not in",["已下发"])],"readonly": [("tool_state", "=", "2")]}'>
<span style='font-weight:bold;'>申请重新编程
<field name="is_reprogramming" force_save="1"
attrs='{"readonly": [("tool_state", "=", "2")]}'/>
</span>
</div>
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","in",["已下发"])],"readonly": ["|",("is_reprogramming_readonly","=",False),("tool_state", "=", "2")]}'>
<span style='font-weight:bold;'>申请重新编程
<field name="is_reprogramming_readonly"
attrs='{"readonly": ["|",("is_reprogramming_readonly","=",False),("tool_state", "=", "2")]}'/>
</span>
</div>
<group>
<!-- <field name="is_reprogramming" force_save="1"-->
<!-- attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","not in",["已下发"])]}'/>-->
<!-- <field name="is_reprogramming_readonly" string="申请重新编程"-->
<!-- attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","in",["已下发"])],"readonly": [("is_reprogramming_readonly","=",False)]}'/>-->
<field name="rework_reason"
attrs='{"invisible": [("routing_type","not in",["装夹预调","CNC加工"])],"required": [("routing_type","in",["装夹预调"])]}'/>
<field name="detailed_reason"
attrs='{"invisible": [("routing_type","not in",["装夹预调","CNC加工"])],"required": [("routing_type","in",["装夹预调"])]}'/>
</group>
<footer>
<button string="确认" name="confirm" type="object" class="oe_highlight" confirm="是否确认返工"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
<record id="action_sf_rework_wizard" model="ir.actions.act_window">
<field name="name">返工</field>
<field name="res_model">sf.rework.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>

View File

@@ -24,96 +24,82 @@ class Sf_Mrs_Connect(http.Controller):
ret = json.loads(datas) ret = json.loads(datas)
ret = json.loads(ret['result']) ret = json.loads(ret['result'])
logging.info('下发编程单:%s' % ret) logging.info('下发编程单:%s' % ret)
productions = request.env['mrp.production'].with_user( 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(
request.env.ref("base.user_admin")).search( request.env.ref("base.user_admin")).search(
[('programming_no', '=', ret['programming_no'])]) [('programming_no', '=', cnc_production.programming_no), ('id', '!=', cnc_production.id)])
if productions: if cnc_production.workorder_ids.filtered(lambda a: a.routing_type == 'CNC加工').cnc_ids:
# # 拉取所有加工面的程序文件 is_delete_file = True
for r in ret['processing_panel'].split(','): cnc_production.workorder_ids.filtered(
program_path_tmp_r = os.path.join('/tmp', ret['folder_name'], 'return', r) lambda a1: a1.routing_type == 'CNC加工').cnc_ids.sudo().unlink()
if os.path.exists(program_path_tmp_r): request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(cnc_production)
files_r = os.listdir(program_path_tmp_r) if cnc_program.workorder_ids.filtered(lambda c: c.routing_type == 'CNC加工').cnc_ids:
if files_r: cnc_program.workorder_ids.filtered(
for file_name in files_r: lambda c1: c1.routing_type == 'CNC加工').cnc_ids.sudo().unlink()
file_path = os.path.join(program_path_tmp_r, file_name) request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(cnc_program)
os.remove(file_path) # 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')
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( download_state = request.env['sf.cnc.processing'].with_user(
request.env.ref("base.user_admin")).download_file_tmp( request.env.ref("base.user_admin")).download_file_tmp(
ret['folder_name'], r) ret['folder_name'], r)
if download_state is False: if download_state == 0:
res['status'] = -2 res['status'] = -2
res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no']) res['message'] = '制造订单号为%s的CNC程序文件从FTP拉取失败' % (cnc_production.name)
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
for production in productions: logging.info('创建cnc工单')
if not production.workorder_ids: program_path_tmp = os.path.join('/tmp', ret['folder_name'], 'return', r)
production.product_id.model_processing_panel = ret['processing_panel'] # program_path_tmp = "C://Users//43484//Desktop//机企猫工作文档//其他//model_analysis"
production._create_workorder(ret) files = os.listdir(program_path_tmp)
# else: cnc_processing_arr = []
# for panel in ret['processing_panel'].split(','): for f in files:
# # 查询状态为进行中且工序类型为CNC加工的工单 program_path = os.path.join(program_path_tmp, f)
# cnc_workorder = production.workorder_ids.filtered( logging.info('cnc程序路径 :%s' % program_path)
# lambda ac: ac.routing_type == 'CNC加工' and ac.state not in ['progress', 'done', if f.endswith(".doc"):
# 'cancel'] and ac.processing_panel == panel) # 插入cmm程序数据
# if cnc_workorder: cmm_program = request.env['sf.cmm.program'].with_user(
# if cnc_workorder.cnc_ids: request.env.ref("base.user_admin")).cmm_program_create(ret, program_path, program_path_tmp)
# cnc_workorder.cmm_ids.sudo().unlink() cnc_processing = request.env['sf.cnc.processing'].with_user(
# cnc_workorder.cnc_ids.sudo().unlink() request.env.ref("base.user_admin")).cnc_processing_create(cnc_production, ret, program_path,
# request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan( program_path_tmp)
# production) logging.info('cnc_processing111:%s' % cnc_processing)
# # program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test', if cnc_processing:
# # panel) cnc_processing_arr.append(cnc_processing._json_cnc_processing(cnc_processing))
# program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel) if (cnc_program and cnc_processing_arr) or (not cnc_program and cnc_processing_arr):
# logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel) cnc_production.workorder_ids.filtered(lambda g: g.routing_type == '装夹预调').write(
# files_panel = os.listdir(program_path_tmp_panel) {'processing_drawing': cnc_production.workorder_ids.filtered(
# if files_panel: lambda g1: g1.routing_type == 'CNC加工').cnc_worksheet})
# for file in files_panel: if cnc_program and cnc_processing_arr:
# file_extension = os.path.splitext(file)[1] cnc_program.write({'programming_state': '已编程', 'work_state': '已编程'})
# logging.info('file_extension:%s' % file_extension) cnc_program.workorder_ids.filtered(lambda d: d.routing_type == '装夹预调').write(
# if file_extension.lower() == '.pdf': {'processing_drawing': cnc_production.workorder_ids.filtered(
# panel_file_path = os.path.join(program_path_tmp_panel, file) lambda d1: d1.routing_type == 'CNC加工').cnc_worksheet})
# logging.info('panel_file_path:%s' % panel_file_path) cnc_program.workorder_ids.filtered(lambda b: b.routing_type == 'CNC加工').write(
# cnc_workorder.write( {'cnc_ids': cnc_processing_arr, 'cnc_worksheet': cnc_production.workorder_ids.filtered(
# {'cnc_ids': cnc_workorder.cnc_ids.sudo()._json_cnc_processing(panel, ret), lambda b1: b1.routing_type == 'CNC加工').cnc_worksheet})
# 'cmm_ids': cnc_workorder.cmm_ids.sudo()._json_cmm_program(panel, ret), cnc_program |= cnc_production
# 'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())}) if not cnc_program and cnc_processing_arr:
# pre_workorder = production.workorder_ids.filtered( cnc_program = cnc_production
# lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done', cnc_program_ids = [item.id for item in cnc_program]
# 'cancel'] and ap.processing_panel == panel) workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
# if pre_workorder: [('production_id', 'in', cnc_program_ids)])
# pre_workorder.write( if workpiece_delivery:
# {'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())}) workpiece_delivery.write({'is_cnc_program_down': True})
for panel in ret['processing_panel'].split(','):
# 查询状态为进行中且工序类型为CNC加工的工单
cnc_workorder = productions.workorder_ids.filtered(
lambda ac: ac.routing_type == 'CNC加工' and ac.state not in ['progress', 'done',
'cancel'] and ac.processing_panel == panel)
if cnc_workorder:
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
# panel)
program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel)
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)
files_panel = os.listdir(program_path_tmp_panel)
if files_panel:
for file in files_panel:
file_extension = os.path.splitext(file)[1]
logging.info('file_extension:%s' % file_extension)
if file_extension.lower() == '.pdf':
panel_file_path = os.path.join(program_path_tmp_panel, file)
logging.info('panel_file_path:%s' % panel_file_path)
cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
pre_workorder = productions.workorder_ids.filtered(
lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done',
'cancel'] and ap.processing_panel == panel)
if pre_workorder:
pre_workorder.write(
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
cnc_program_ids = [item.id for item in productions]
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
[('production_id', 'in', cnc_program_ids)])
if workpiece_delivery:
workpiece_delivery.write(
{'is_cnc_program_down': True, 'production_line_id': productions.production_line_id.id})
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
else: else:
res = {'status': 0, 'message': '该制造订单暂未开始'} res = {'status': 0, 'message': '该制造订单暂未开始'}

View File

@@ -21,23 +21,6 @@ class FtpController():
except Exception: except Exception:
logging.info("ftp连接失败") 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): def file_exists(self, path):
# 检查文件是否存在于FTP服务器上 # 检查文件是否存在于FTP服务器上
try: try:
@@ -49,25 +32,8 @@ class FtpController():
logging.error(f"Error checking file: {e}") logging.error(f"Error checking file: {e}")
return False 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): # def detect_encoding(self, s):

View File

@@ -326,8 +326,6 @@ class sfProductionProcess(models.Model):
production_process.name = item['name'] production_process.name = item['name']
production_process.category_id = category.id production_process.category_id = category.id
production_process.remark = item['remark'] production_process.remark = item['remark']
production_process.processing_day = item['processing_day']
production_process.travel_day = item['travel_day']
production_process.active = item['active'] production_process.active = item['active']
else: else:
self.create({ self.create({
@@ -335,8 +333,6 @@ class sfProductionProcess(models.Model):
"category_id": category.id, "category_id": category.id,
"code": item['code'], "code": item['code'],
"remark": item['remark'], "remark": item['remark'],
"processing_day": item['processing_day'],
"travel_day": item['travel_day'],
"active": item['active'], "active": item['active'],
}) })
else: else:
@@ -362,16 +358,12 @@ class sfProductionProcess(models.Model):
"category_id": category.id, "category_id": category.id,
"code": item['code'], "code": item['code'],
"remark": item['remark'], "remark": item['remark'],
"processing_day": item['processing_day'],
"travel_day": item['travel_day'],
"active": item['active'], "active": item['active'],
}) })
else: else:
production_process.name = item['name'] production_process.name = item['name']
production_process.category_id = category.id production_process.category_id = category.id
production_process.remark = item['remark'] production_process.remark = item['remark']
production_process.processing_day = item['processing_day']
production_process.travel_day = item['travel_day']
production_process.active = item['active'] production_process.active = item['active']
else: else:
raise ValidationError("表面工艺认证未通过") raise ValidationError("表面工艺认证未通过")
@@ -1081,9 +1073,6 @@ class sfProductionProcessParameter(models.Model):
[('code', '=', item['process_id_code'])]) [('code', '=', item['process_id_code'])])
if production_process_parameter: if production_process_parameter:
production_process_parameter.name = item['name'] production_process_parameter.name = item['name']
production_process_parameter.process_description = item['process_description']
production_process_parameter.processing_day = item['processing_day']
production_process_parameter.travel_day = item['travel_day']
production_process_parameter.active = item['active'] production_process_parameter.active = item['active']
production_process_parameter.process_id = process.id production_process_parameter.process_id = process.id
production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search( production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search(
@@ -1091,9 +1080,6 @@ class sfProductionProcessParameter(models.Model):
else: else:
self.create({ self.create({
"name": item['name'], "name": item['name'],
"process_description": item['process_description'],
"processing_day": item['processing_day'],
"travel_day": item['travel_day'],
"code": item['code'], "code": item['code'],
"active": item['active'], "active": item['active'],
"process_id": process.id, "process_id": process.id,
@@ -1121,9 +1107,6 @@ class sfProductionProcessParameter(models.Model):
if not production_process_parameter: if not production_process_parameter:
self.create({ self.create({
"name": item['name'], "name": item['name'],
"process_description": item['process_description'],
"processing_day": item['processing_day'],
"travel_day": item['travel_day'],
"code": item['code'], "code": item['code'],
"active": item['active'], "active": item['active'],
"process_id": process.id, "process_id": process.id,
@@ -1132,9 +1115,6 @@ class sfProductionProcessParameter(models.Model):
}) })
else: else:
production_process_parameter.name = item['name'] production_process_parameter.name = item['name']
production_process_parameter.process_description = item['process_description']
production_process_parameter.processing_day = item['processing_day']
production_process_parameter.travel_day = item['travel_day']
production_process_parameter.process_id = process.id production_process_parameter.process_id = process.id
production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search( production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search(
[('materials_no', 'in', item['materials_model_ids_codes'])]) [('materials_no', 'in', item['materials_model_ids_codes'])])

View File

@@ -19,7 +19,7 @@ class sf_production_plan(models.Model):
('done', '已排程'), ('done', '已排程'),
('processing', '加工中'), ('processing', '加工中'),
('finished', '已完成') ('finished', '已完成')
], string='状态', tracking=True) ], string='工单状态', tracking=True)
state_order = fields.Integer(compute='_compute_state_order', store=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' _order = 'state_order asc, write_date desc'
name = fields.Char(string='制造订单') name = fields.Char(string='工单编号')
# active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
# selected = fields.Boolean(default=False) # selected = fields.Boolean(default=False)
# order_number = fields.Char(string='订单号') # order_number = fields.Char(string='订单号')
order_deadline = fields.Datetime(string='订单交期') order_deadline = fields.Datetime(string='订单交期')
@@ -52,7 +52,7 @@ class sf_production_plan(models.Model):
schedule_setting = fields.Selection([ schedule_setting = fields.Selection([
('reverse', '倒排'), ('positive', '顺排')], string='排程设置', default='reverse') ('reverse', '倒排'), ('positive', '顺排')], string='排程设置', default='reverse')
product_id = fields.Many2one('product.product', '关联产品') product_id = fields.Many2one('product.product', '关联产品')
origin = fields.Char(string='销售订单') origin = fields.Char(string='订单')
# # 加工时长 # # 加工时长
# process_time = fields.Float(string='加工时长', digits=(16, 2)) # 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( # return super(sf_production_plan, self.with_context(active_test=False))._search(
# args, offset, limit, order, count, access_rights_uid) # args, offset, limit, order, count, access_rights_uid)
# def archive(self): def archive(self):
# """ """
# 归档 归档
# """ """
# self.write({'active': False}) self.write({'active': False})
#
# def unarchive(self): def unarchive(self):
# """ """
# 取消归档 取消归档
# """ """
# self.write({'active': True}) self.write({'active': True})
@api.model @api.model
def get_import_templates(self): def get_import_templates(self):
@@ -200,23 +200,22 @@ class sf_production_plan(models.Model):
raise ValidationError("未选择生产线") raise ValidationError("未选择生产线")
else: else:
workorder_id_list = record.production_id.workorder_ids.ids workorder_id_list = record.production_id.workorder_ids.ids
if record.production_id: if record.production_id.workorder_ids:
if record.production_id.workorder_ids: for item in record.production_id.workorder_ids:
for item in record.production_id.workorder_ids: if item.name == 'CNC加工':
if item.name == 'CNC加工': item.date_planned_finished = datetime.now() + timedelta(days=100)
item.date_planned_finished = datetime.now() + timedelta(days=100) # item.date_planned_start = record.date_planned_start
# item.date_planned_start = record.date_planned_start item.date_planned_start = self.date_planned_start if self.date_planned_start else datetime.now()
item.date_planned_start = self.date_planned_start if self.date_planned_start else datetime.now() record.sudo().production_id.plan_start_processing_time = item.date_planned_start
record.sudo().production_id.plan_start_processing_time = item.date_planned_start item.date_planned_finished = item.date_planned_start + timedelta(
item.date_planned_finished = item.date_planned_start + timedelta( minutes=record.env['mrp.routing.workcenter'].sudo().search(
minutes=record.env['mrp.routing.workcenter'].sudo().search( [('name', '=', 'CNC加工')]).time_cycle)
[('name', '=', 'CNC加工')]).time_cycle) item.duration_expected = record.env['mrp.routing.workcenter'].sudo().search(
item.duration_expected = record.env['mrp.routing.workcenter'].sudo().search( [('name', '=', 'CNC加工')]).time_cycle
[('name', '=', 'CNC加工')]).time_cycle record.calculate_plan_time_before(item, workorder_id_list)
record.calculate_plan_time_before(item, workorder_id_list) record.calculate_plan_time_after(item, workorder_id_list)
record.calculate_plan_time_after(item, workorder_id_list) record.date_planned_start, record.date_planned_finished = \
record.date_planned_start, record.date_planned_finished = \ item.date_planned_start, item.date_planned_finished
item.date_planned_start, item.date_planned_finished
record.state = 'done' record.state = 'done'
# record.production_id.schedule_state = '已排' # record.production_id.schedule_state = '已排'
record.sudo().production_id.schedule_state = '已排' record.sudo().production_id.schedule_state = '已排'
@@ -232,12 +231,12 @@ class sf_production_plan(models.Model):
# record.production_id.date_planned_start = record.date_planned_start # record.production_id.date_planned_start = record.date_planned_start
# record.production_id.date_planned_finished = record.date_planned_finished # record.production_id.date_planned_finished = record.date_planned_finished
record.sudo().production_id.production_line_id = record.production_line_id.id 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(
record.sudo().production_id.workorder_ids.filtered( lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write(
lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write( {'production_line_id': record.production_line_id.id,
{'production_line_id': record.production_line_id.id, 'plan_start_processing_time': record.date_planned_start})
'plan_start_processing_time': record.date_planned_start}) else:
raise ValidationError("未找到工单")
# record.date_planned_finished = record.date_planned_start + timedelta(days=3) # record.date_planned_finished = record.date_planned_start + timedelta(days=3)
# record.state = 'done' # record.state = 'done'
return { return {

View File

@@ -17,18 +17,18 @@
decoration-danger="state == 'finished'"/> decoration-danger="state == 'finished'"/>
<field name="name"/> <field name="name"/>
<field name="origin"/> <field name="origin"/>
<field name="order_deadline" widget="date"/> <field name="order_deadline"/>
<field name="product_qty"/> <field name="product_qty"/>
<field name="production_line_id"/> <field name="production_line_id"/>
<field name="date_planned_start"/> <field name="date_planned_start"/>
<field name="date_planned_finished"/> <field name="date_planned_finished"/>
<field name="actual_start_time" optional='hide'/> <field name="actual_start_time"/>
<field name="actual_end_time" optional='hide'/> <field name="actual_end_time"/>
<field name="actual_process_time" optional='hide'/> <field name="actual_process_time"/>
<field name="schedule_setting" optional='hide'/> <field name="schedule_setting"/>
<!-- <button name="do_production_schedule" class="btn schedule_done" string="生产排程" type="object" --> <button name="do_production_schedule" class="btn schedule_done" string="生产排程" type="object"
<!-- attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('actual_start_time', '!=', False)]}" --> attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('actual_start_time', '!=', False)]}"
<!-- groups="sf_base.group_plan_dispatch"/> --> groups="sf_base.group_plan_dispatch"/>
<button name="cancel_production_schedule" class="btn schedule_cancel" string="取消排程" type="object" <button name="cancel_production_schedule" class="btn schedule_cancel" string="取消排程" type="object"
attrs="{'invisible': ['|', ('state', '!=', 'done'), ('actual_start_time', '!=', False)]}" attrs="{'invisible': ['|', ('state', '!=', 'done'), ('actual_start_time', '!=', False)]}"
groups="sf_base.group_plan_dispatch"/> groups="sf_base.group_plan_dispatch"/>
@@ -63,12 +63,12 @@
</div> </div>
<group> <group>
<group string="基本信息"> <group string="基本信息">
<!-- <field name="active" invisible="1"/> --> <field name="active" invisible="1"/>
<field name="production_id" widget="many2one_button"/> <field name="production_id" widget="many2one_button"/>
<field name="product_id"/> <field name="product_id"/>
<field name="origin"/> <field name="origin"/>
<field name="product_qty"/> <field name="product_qty"/>
<field name="order_deadline" widget="date"/> <field name="order_deadline"/>
<!-- <field name="process_time"/> --> <!-- <field name="process_time"/> -->
<field name="schedule_setting"/> <field name="schedule_setting"/>
<field name="production_line_id" domain="[('name', 'ilike', 'CNC')]"/> <field name="production_line_id" domain="[('name', 'ilike', 'CNC')]"/>
@@ -152,27 +152,16 @@
<field name="model">sf.production.plan</field> <field name="model">sf.production.plan</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="订单计划"> <search string="订单计划">
<!-- Your other filters go here --> <!-- Your other filters go here -->
<!-- <filter name="archived" string="已归档" domain="[('active','=',False)]"/> --> <filter name="archived" string="已归档" domain="[('active','=',False)]"/>
<!-- <filter name="not archived" string="未归档" domain="[('active','=',True)]"/> --> <filter name="not archived" string="未归档" domain="[('active','=',True)]"/>
<field name="name"/> <field name="name"/>
<field name="product_qty"/> <field name="product_qty"/>
<field name="date_planned_start"/>
<field name="date_planned_finished"/>
<field name="state"/> <field name="state"/>
<filter string="待排程" name="draft" domain="[('state','=','draft')]"/> <searchpanel class="account_root">
<filter string="已排程" name="done" domain="[('state','=','done')]"/> <field name="state" icon="fa-filter"/>
<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> </searchpanel>
</search> </search>
</field> </field>
@@ -199,41 +188,30 @@
<field name="date_planned_start"/> <field name="date_planned_start"/>
<field name="date_planned_finished"/> <field name="date_planned_finished"/>
<field name="state"/> <field name="state"/>
<field name="origin"/>
<field name="order_deadline"/>
<field name="product_id"/>
<templates> <templates>
<div t-name="gantt-popover" class="container-fluid"> <div t-name="gantt-popover" class="container-fluid">
<div class="row g-0"> <div class="row g-0">
<div class="col"> <div class="col">
<ul class="ps-1 mb-0 list-unstyled"> <ul class="ps-1 mb-0 list-unstyled">
<li> <li>
<strong>销售订单号:</strong> <strong>开始时间:</strong>
<t t-out="origin"/> <t t-out="userTimezoneStartDate.format('L LTS')"/>
</li> </li>
<li> <li>
<strong>制造订单号:</strong> <strong>结束时间:</strong>
<t t-out="userTimezoneStopDate.format('L LTS')"/>
</li>
<li>
<strong>名称:</strong>
<t t-out="name"/> <t t-out="name"/>
</li> </li>
<li>
<strong>订单交期:</strong>
<t t-out="order_deadline.format('L LTS')"/>
</li>
<li>
<strong>产品名称:</strong>
<t t-out="product_id[1]"/>
</li>
<li> <li>
<strong>数量:</strong> <strong>数量:</strong>
<t t-out="product_qty"/> <t t-out="product_qty"/>
</li> </li>
<li> <li>
<strong>计划开始时间:</strong> <strong>状态:</strong>
<t t-out="userTimezoneStartDate.format('L LTS')"/> <t t-out="state"/>
</li>
<li>
<strong>计划结束时间:</strong>
<t t-out="userTimezoneStopDate.format('L LTS')"/>
</li> </li>
</ul> </ul>
</div> </div>
@@ -268,8 +246,6 @@
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="res_model">sf.production.plan</field> <field name="res_model">sf.production.plan</field>
<field name="view_mode">tree,gantt,form</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> </record>
<menuitem <menuitem

File diff suppressed because it is too large Load Diff

View File

@@ -158,7 +158,7 @@ class QuickEasyOrder(models.Model):
payload = { payload = {
'file_path': new_file_path, 'file_path': new_file_path,
'dest_path': new_folder_path, 'dest_path': new_folder_path,
'back_url': config['bfm_url_new'] 'back_url': config['bfm_url']
} }
response = requests.post(url, json=payload, headers=headers) response = requests.post(url, json=payload, headers=headers)
if response.status_code == 200: if response.status_code == 200:

View File

@@ -44,6 +44,7 @@ class ReSaleOrder(models.Model):
store=True, readonly=False, precompute=True, check_company=True, tracking=True, store=True, readonly=False, precompute=True, check_company=True, tracking=True,
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
remark = fields.Text('备注') remark = fields.Text('备注')
validity_date = fields.Date( validity_date = fields.Date(
string="Expiration", string="Expiration",
compute='_compute_validity_date', compute='_compute_validity_date',
@@ -112,7 +113,6 @@ class ReSaleOrder(models.Model):
'price_unit': product.list_price, 'price_unit': product.list_price,
'product_uom_qty': item['number'], 'product_uom_qty': item['number'],
'model_glb_file': base64.b64decode(item['model_file']), 'model_glb_file': base64.b64decode(item['model_file']),
'remark': item.get('remark')
} }
return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals) return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
@@ -151,7 +151,6 @@ class ResaleOrderLine(models.Model):
# # without modifying the related product_id when updated. # # without modifying the related product_id when updated.
# domain=[('sale_ok', '=', True), ('categ_type', '=', '成品')]) # domain=[('sale_ok', '=', True), ('categ_type', '=', '成品')])
check_status = fields.Selection(related='order_id.check_status') check_status = fields.Selection(related='order_id.check_status')
remark = fields.Char('备注')
@api.depends('product_template_id') @api.depends('product_template_id')
def _compute_model_glb_file(self): def _compute_model_glb_file(self):
@@ -172,11 +171,6 @@ class ProductTemplate(models.Model):
class RePurchaseOrder(models.Model): class RePurchaseOrder(models.Model):
_inherit = 'purchase.order' _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('备注') remark = fields.Text('备注')
user_id = fields.Many2one( user_id = fields.Many2one(
'res.users', string='买家', index=True, tracking=True, 'res.users', string='买家', index=True, tracking=True,
@@ -221,17 +215,6 @@ class RePurchaseOrder(models.Model):
if len(product_id) != len(line): if len(product_id) != len(line):
raise ValidationError('%s】已存在,请勿重复添加' % product[-1].name) 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): class ResPartnerToSale(models.Model):
_inherit = 'res.partner' _inherit = 'res.partner'
@@ -257,33 +240,33 @@ class ResPartnerToSale(models.Model):
# if obj: # if obj:
# raise UserError('该邮箱已存在,请重新输入') # raise UserError('该邮箱已存在,请重新输入')
# @api.model @api.model
# def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
# if self._context.get('is_customer'): if self._context.get('is_customer'):
# if self.env.user.has_group('sf_base.group_sale_director'): if self.env.user.has_group('sf_base.group_sale_director'):
# domain = [('customer_rank', '>', 0)] domain = [('customer_rank', '>', 0)]
# elif self.env.user.has_group('sf_base.group_sale_salemanager'): elif self.env.user.has_group('sf_base.group_sale_salemanager'):
# customer = self.env['res.partner'].search( customer = self.env['res.partner'].search(
# [('customer_rank', '>', 0), ('user_id', '=', self.env.user.id)]) [('customer_rank', '>', 0), ('user_id', '=', self.env.user.id)])
# if customer: if customer:
# ids = [t.id for t in customer] ids = [t.id for t in customer]
# domain = [('id', 'in', ids)] domain = [('id', 'in', ids)]
# else: else:
# domain = [('id', '=', False)] domain = [('id', '=', False)]
# return self._search(domain, limit=limit, access_rights_uid=name_get_uid) return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
# elif self._context.get('is_supplier') or self.env.user.has_group('sf_base.group_purchase_director'): elif self._context.get('is_supplier') or self.env.user.has_group('sf_base.group_purchase_director'):
# if self.env.user.has_group('sf_base.group_purchase_director'): if self.env.user.has_group('sf_base.group_purchase_director'):
# domain = [('supplier_rank', '>', 0)] domain = [('supplier_rank', '>', 0)]
# elif self.env.user.has_group('sf_base.group_purchase'): elif self.env.user.has_group('sf_base.group_purchase'):
# supplier = self.env['res.partner'].search( supplier = self.env['res.partner'].search(
# [('supplier_rank', '>', 0), ('purchase_user_id', '=', self.env.user.id)]) [('supplier_rank', '>', 0), ('purchase_user_id', '=', self.env.user.id)])
# if supplier: if supplier:
# ids = [t.id for t in supplier] ids = [t.id for t in supplier]
# domain = [('id', 'in', ids)] domain = [('id', 'in', ids)]
# else: else:
# domain = [('id', '=', False)] domain = [('id', '=', False)]
# return self._search(domain, limit=limit, access_rights_uid=name_get_uid) return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
# return super()._name_search(name, args, operator, limit, name_get_uid) return super()._name_search(name, args, operator, limit, name_get_uid)
@api.onchange('user_id') @api.onchange('user_id')
def _get_salesman(self): def _get_salesman(self):

View File

@@ -54,7 +54,7 @@
<record model="ir.rule" id="sale_order_rule_my"> <record model="ir.rule" id="sale_order_rule_my">
<field name="name">销售经理查看自己的订单</field> <field name="name">销售经理查看自己的订单</field>
<field name="model_id" ref="model_sale_order"/> <field name="model_id" ref="model_sale_order"/>
<field name="domain_force">['|','|',('user_id','=',user.id),('user_id', '=', False),('create_uid', '=',user.id)]</field> <field name="domain_force">['|',('user_id','=',user.id),('create_uid', '=',user.id)]</field>
<field name="groups" eval="[(4, ref('sf_base.group_sale_salemanager'))]"/> <field name="groups" eval="[(4, ref('sf_base.group_sale_salemanager'))]"/>
<field name="perm_read" eval="1"/> <field name="perm_read" eval="1"/>
<field name="perm_write" eval="1"/> <field name="perm_write" eval="1"/>
@@ -74,7 +74,7 @@
<record model="ir.rule" id="inventory_purchase_order_rule_my"> <record model="ir.rule" id="inventory_purchase_order_rule_my">
<field name="name">采购岗查看自己的订单</field> <field name="name">采购岗查看自己的订单</field>
<field name="model_id" ref="purchase.model_purchase_order"/> <field name="model_id" ref="purchase.model_purchase_order"/>
<field name="domain_force">['|','|',('user_id','=',user.id),('user_id', '=', False),('create_uid', '=',user.id)]</field> <field name="domain_force">['|',('user_id','=',user.id),('create_uid', '=',user.id)]</field>
<field name="groups" eval="[(4, ref('sf_base.group_purchase'))]"/> <field name="groups" eval="[(4, ref('sf_base.group_purchase'))]"/>
<field name="perm_read" eval="1"/> <field name="perm_read" eval="1"/>
<field name="perm_write" eval="0"/> <field name="perm_write" eval="0"/>

View File

@@ -79,13 +79,6 @@
<xpath expr="//form/header/button[@name='button_done']" position="attributes"> <xpath expr="//form/header/button[@name='button_done']" position="attributes">
<attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute> <attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>
</xpath> </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"> <xpath expr="//field[@name='order_line']" position="attributes">
<attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]} <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
</attribute> </attribute>

View File

@@ -69,9 +69,6 @@
<field name="model_glb_file" widget="Viewer3D" optional="show" <field name="model_glb_file" widget="Viewer3D" optional="show"
string="模型文件" attrs="{'readonly': [('state', 'in', ['draft'])]}"/> string="模型文件" attrs="{'readonly': [('state', 'in', ['draft'])]}"/>
</xpath> </xpath>
<xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after">
<field name="remark"/>
</xpath>
<xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="attributes"> <xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="attributes">
<attribute name="options">{'no_create': True}</attribute> <attribute name="options">{'no_create': True}</attribute>
<attribute name="context">{'is_sale_order_line': True }</attribute> <attribute name="context">{'is_sale_order_line': True }</attribute>

View File

@@ -22,7 +22,6 @@
'views/tool_material_search.xml', 'views/tool_material_search.xml',
'views/fixture_material_search_views.xml', 'views/fixture_material_search_views.xml',
'views/menu_view.xml', 'views/menu_view.xml',
'views/stock.xml',
'data/tool_data.xml', 'data/tool_data.xml',
], ],
'demo': [ 'demo': [

View File

@@ -109,7 +109,6 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': []} res = {'Succeed': True, 'Datas': []}
try: try:
datas = request.httprequest.data datas = request.httprequest.data
logging.info('datas: %s' % datas)
ret = str(datas, 'utf-8') ret = str(datas, 'utf-8')
data_lists = ret.split(",") data_lists = ret.split(",")
data_list = [data.replace('+', '') for data in data_lists] data_list = [data.replace('+', '') for data in data_lists]
@@ -121,7 +120,7 @@ class Manufacturing_Connect(http.Controller):
{'Succeed': False, 'ErrorCode': 201, 'code': data_list[0], 'Error': '没有找到正在组装的组装单!'}) {'Succeed': False, 'ErrorCode': 201, 'code': data_list[0], 'Error': '没有找到正在组装的组装单!'})
tool_assembly.write({ tool_assembly.write({
'after_assembly_tool_loading_length': float(data_list[1] or "0"), # 高度(总长度) 'after_assembly_tool_loading_length': float(data_list[1] or "0"), # 高度(总长度)
'after_assembly_functional_tool_diameter': float(data_list[2] or "0") * 2, # 直径 'after_assembly_functional_tool_diameter': float(data_list[2] or "0"), # 直径
'after_assembly_knife_tip_r_angle': float(data_list[3] or "0") # R角 'after_assembly_knife_tip_r_angle': float(data_list[3] or "0") # R角
}) })
except Exception as e: except Exception as e:

View File

@@ -7,5 +7,4 @@ from . import functional_tool_enroll
from . import fixture_material_search from . import fixture_material_search
from . import fixture_enroll from . import fixture_enroll
from . import temporary_data_processing_methods from . import temporary_data_processing_methods
from . import stock

View File

@@ -313,27 +313,42 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'applicant': None, 'applicant': None,
'sf_functional_tool_assembly_id': None}) 'sf_functional_tool_assembly_id': None})
def create_cam_work_plan(self, cnc_processing): def create_cam_work_plan(self, cnc_processing_ids):
""" """
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划 根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
""" """
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({ for cnc_processing in cnc_processing_ids:
'name': cnc_processing.workorder_id.production_id.name, status = False
'cam_procedure_code': cnc_processing.program_name, if cnc_processing.cutting_tool_name:
'filename': cnc_processing.cnc_id.name, functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search(
'functional_tool_name': cnc_processing.cutting_tool_name, [('name', '=', cnc_processing.cutting_tool_name)])
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no, if functional_tools:
'process_type': cnc_processing.processing_type, for functional_tool in functional_tools:
'margin_x_y': float(cnc_processing.margin_x_y), if functional_tool.on_tool_stock_num == 0:
'margin_z': float(cnc_processing.margin_z), if functional_tool.tool_stock_num == 0 and functional_tool.side_shelf_num == 0:
'finish_depth': float(cnc_processing.depth_of_processing_z), status = True
'extension_length': float(cnc_processing.cutting_tool_extension_length), else:
'shank_model': cnc_processing.cutting_tool_handle_type, status = True
'estimated_processing_time': cnc_processing.estimated_processing_time, if status:
}) knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
logging.info('CAM工单程序用刀计划创建成功') 'name': cnc_processing.workorder_id.production_id.name,
# 创建装刀请求 'cam_procedure_code': cnc_processing.program_name,
knife_plan.apply_for_tooling() 'filename': cnc_processing.cnc_id.name,
'functional_tool_name': cnc_processing.cutting_tool_name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'process_type': cnc_processing.processing_type,
'margin_x_y': float(cnc_processing.margin_x_y),
'margin_z': float(cnc_processing.margin_z),
'finish_depth': float(cnc_processing.depth_of_processing_z),
'extension_length': float(cnc_processing.cutting_tool_extension_length),
'shank_model': cnc_processing.cutting_tool_handle_type,
'estimated_processing_time': cnc_processing.estimated_processing_time,
})
logging.info('CAM工单程序用刀计划创建成功')
# 创建装刀请求
knife_plan.apply_for_tooling()
else:
logging.info('功能刀具【%s】满足CNC用刀需求' % cnc_processing.cutting_tool_name)
def unlink_cam_plan(self, production): def unlink_cam_plan(self, production):
for item in production: for item in production:
@@ -566,15 +581,6 @@ class FunctionalToolAssembly(models.Model):
active = fields.Boolean(string='已归档', default=True) 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): def put_start_preset(self):
self.search([('start_preset_bool', '=', True)]).write({'start_preset_bool': False}) self.search([('start_preset_bool', '=', True)]).write({'start_preset_bool': False})
self.write({ self.write({
@@ -654,20 +660,6 @@ class FunctionalToolAssembly(models.Model):
:return: :return:
""" """
picking_num = fields.Integer('调拨单数量', compute='compute_picking_num', store=True)
@api.depends('assemble_status')
def compute_picking_num(self):
for item in self:
picking_ids = self.env['stock.picking'].sudo().search([('origin', '=', item.assembly_order_code)])
item.picking_num = len(picking_ids)
def open_tool_stock_picking(self):
action = self.env.ref('stock.action_picking_tree_all')
result = action.read()[0]
result['domain'] = [('origin', '=', self.assembly_order_code)]
return result
@api.model_create_multi @api.model_create_multi
def create(self, vals): def create(self, vals):
obj = super(FunctionalToolAssembly, self).create(vals) obj = super(FunctionalToolAssembly, self).create(vals)
@@ -757,9 +749,8 @@ class FunctionalToolDismantle(models.Model):
num = "%03d" % m num = "%03d" % m
return 'GNDJ-CJD-%s-%s' % (datetime, num) return 'GNDJ-CJD-%s-%s' % (datetime, num)
functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True, tracking=True, 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, tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
compute='_compute_functional_tool_num') compute='_compute_functional_tool_num')
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_functional_tool_num', store=True) tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_functional_tool_num', store=True)
@@ -775,18 +766,8 @@ class FunctionalToolDismantle(models.Model):
dismantle_person = fields.Char('拆解人', readonly=True) dismantle_person = fields.Char('拆解人', readonly=True)
image = fields.Binary('图片', readonly=True) image = fields.Binary('图片', readonly=True)
scrap_ids = fields.One2many('stock.scrap', 'functional_tool_dismantle_id', string='报废单号', readonly=True) scrap_id = fields.Char('报废单号', readonly=True)
grinding_id = fields.Char('磨削单号', readonly=True) grinding_id = fields.Char('磨削单号', readonly=True)
picking_id = fields.Many2one('stock.picking', string='刀具物料调拨单')
picking_num = fields.Integer('调拨单数量', default=0, compute='compute_picking_num', store=True)
@api.depends('picking_id')
def compute_picking_num(self):
for item in self:
if item.picking_id:
item.picking_num = 1
else:
item.picking_num = 0
state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解', tracking=True) state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解', tracking=True)
active = fields.Boolean('有效', default=True) active = fields.Boolean('有效', default=True)
@@ -800,14 +781,7 @@ class FunctionalToolDismantle(models.Model):
handle_rfid = fields.Char(string='刀柄Rfid', compute='_compute_functional_tool_num', store=True) handle_rfid = fields.Char(string='刀柄Rfid', compute='_compute_functional_tool_num', store=True)
handle_lot_id = fields.Many2one('stock.lot', string='刀柄序列号', compute='_compute_functional_tool_num', handle_lot_id = fields.Many2one('stock.lot', string='刀柄序列号', compute='_compute_functional_tool_num',
store=True) store=True)
scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False, tracking=True, compute='compute_scrap_boolean', scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False, tracking=True)
store=True)
@api.depends('dismantle_cause')
def compute_scrap_boolean(self):
for item in self:
if item.dismantle_cause not in ['寿命到期报废', '崩刀报废']:
item.scrap_boolean = False
# 整体式 # 整体式
integral_product_id = fields.Many2one('product.product', string='整体式刀具', integral_product_id = fields.Many2one('product.product', string='整体式刀具',
@@ -819,7 +793,7 @@ class FunctionalToolDismantle(models.Model):
integral_lot_id = fields.Many2one('stock.lot', string='整体式刀具批次', compute='_compute_functional_tool_num', integral_lot_id = fields.Many2one('stock.lot', string='整体式刀具批次', compute='_compute_functional_tool_num',
store=True) store=True)
integral_freight_id = fields.Many2one('sf.shelf.location', '整体式刀具目标货位', integral_freight_id = fields.Many2one('sf.shelf.location', '整体式刀具目标货位',
domain="[('product_id', 'in', (integral_product_id, False)),('rotative_Boolean', '=', True)]") domain="[('product_id', 'in', (integral_product_id, False))]")
# 刀片 # 刀片
blade_product_id = fields.Many2one('product.product', string='刀片', compute='_compute_functional_tool_num', blade_product_id = fields.Many2one('product.product', string='刀片', compute='_compute_functional_tool_num',
@@ -829,7 +803,7 @@ class FunctionalToolDismantle(models.Model):
blade_brand_id = fields.Many2one('sf.machine.brand', string='刀片品牌', related='blade_product_id.brand_id') blade_brand_id = fields.Many2one('sf.machine.brand', string='刀片品牌', related='blade_product_id.brand_id')
blade_lot_id = fields.Many2one('stock.lot', string='刀片批次', compute='_compute_functional_tool_num', store=True) blade_lot_id = fields.Many2one('stock.lot', string='刀片批次', compute='_compute_functional_tool_num', store=True)
blade_freight_id = fields.Many2one('sf.shelf.location', '刀片目标货位', blade_freight_id = fields.Many2one('sf.shelf.location', '刀片目标货位',
domain="[('product_id', 'in', (blade_product_id, False)),('rotative_Boolean', '=', True)]") domain="[('product_id', 'in', (blade_product_id, False))]")
# 刀杆 # 刀杆
bar_product_id = fields.Many2one('product.product', string='刀杆', compute='_compute_functional_tool_num', bar_product_id = fields.Many2one('product.product', string='刀杆', compute='_compute_functional_tool_num',
@@ -839,7 +813,7 @@ class FunctionalToolDismantle(models.Model):
bar_brand_id = fields.Many2one('sf.machine.brand', string='刀杆品牌', related='bar_product_id.brand_id') bar_brand_id = fields.Many2one('sf.machine.brand', string='刀杆品牌', related='bar_product_id.brand_id')
bar_lot_id = fields.Many2one('stock.lot', string='刀杆批次', compute='_compute_functional_tool_num', store=True) bar_lot_id = fields.Many2one('stock.lot', string='刀杆批次', compute='_compute_functional_tool_num', store=True)
bar_freight_id = fields.Many2one('sf.shelf.location', '刀杆目标货位', bar_freight_id = fields.Many2one('sf.shelf.location', '刀杆目标货位',
domain="[('product_id', 'in', (bar_product_id, False)),('rotative_Boolean', '=', True)]") domain="[('product_id', 'in', (bar_product_id, False))]")
# 刀盘 # 刀盘
pad_product_id = fields.Many2one('product.product', string='刀盘', compute='_compute_functional_tool_num', pad_product_id = fields.Many2one('product.product', string='刀盘', compute='_compute_functional_tool_num',
@@ -849,7 +823,7 @@ class FunctionalToolDismantle(models.Model):
pad_brand_id = fields.Many2one('sf.machine.brand', string='刀盘品牌', related='pad_product_id.brand_id') pad_brand_id = fields.Many2one('sf.machine.brand', string='刀盘品牌', related='pad_product_id.brand_id')
pad_lot_id = fields.Many2one('stock.lot', string='刀盘批次', compute='_compute_functional_tool_num', store=True) pad_lot_id = fields.Many2one('stock.lot', string='刀盘批次', compute='_compute_functional_tool_num', store=True)
pad_freight_id = fields.Many2one('sf.shelf.location', '刀盘目标货位', pad_freight_id = fields.Many2one('sf.shelf.location', '刀盘目标货位',
domain="[('product_id', 'in', (pad_product_id, False)),('rotative_Boolean', '=', True)]") domain="[('product_id', 'in', (pad_product_id, False))]")
# 夹头 # 夹头
chuck_product_id = fields.Many2one('product.product', string='夹头', compute='_compute_functional_tool_num', chuck_product_id = fields.Many2one('product.product', string='夹头', compute='_compute_functional_tool_num',
@@ -859,7 +833,7 @@ class FunctionalToolDismantle(models.Model):
chuck_brand_id = fields.Many2one('sf.machine.brand', string='夹头品牌', related='chuck_product_id.brand_id') chuck_brand_id = fields.Many2one('sf.machine.brand', string='夹头品牌', related='chuck_product_id.brand_id')
chuck_lot_id = fields.Many2one('stock.lot', string='夹头批次', compute='_compute_functional_tool_num', store=True) chuck_lot_id = fields.Many2one('stock.lot', string='夹头批次', compute='_compute_functional_tool_num', store=True)
chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位', chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位',
domain="[('product_id', 'in', (chuck_product_id, False)),('rotative_Boolean', '=', True)]") domain="[('product_id', 'in', (chuck_product_id, False))]")
@api.onchange('functional_tool_id') @api.onchange('functional_tool_id')
def _onchange_freight(self): def _onchange_freight(self):
@@ -949,50 +923,74 @@ class FunctionalToolDismantle(models.Model):
self.rfid, self.functional_tool_id.current_location)) self.rfid, self.functional_tool_id.current_location))
# 目标重复校验 # 目标重复校验
self.location_duplicate_check() self.location_duplicate_check()
datas = {'scrap': [], 'picking': []} 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')])
if self.handle_rfid: if self.handle_rfid:
lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)]) lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)])
if not lot: if not lot:
raise ValidationError('Rfid为【%s】的刀柄序列号不存在!' % self.handle_rfid) raise ValidationError('Rfid为【%s】的功能刀具序列号不存在!' % self.handle_rfid)
functional_tool_assembly = self.functional_tool_id.functional_tool_name_id
if self.scrap_boolean: if self.scrap_boolean:
# 刀柄报废 入库到Scrap # 刀柄报废 入库到Scrap
datas['scrap'].append({'lot_id': lot}) lot.create_stock_quant(location, location_dest_scrap, functional_tool_assembly.id, code,
lot.tool_material_status = '报废' functional_tool_assembly, functional_tool_assembly.tool_groups_id)
else: else:
# 刀柄不报废 入库到刀具房 # 刀柄不报废 入库到刀具房
datas['picking'].append({'lot_id': lot, 'destination': self.env['sf.shelf.location']}) lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, code,
lot.tool_material_status = '可用' functional_tool_assembly, functional_tool_assembly.tool_groups_id)
# ==============功能刀具[报废]拆解================ # ==============功能刀具[报废]拆解================
if self.dismantle_cause in ['寿命到期报废', '崩刀报废']: if self.dismantle_cause in ['寿命到期报废', '崩刀报废']:
# 除刀柄外物料报废 入库到Scrap # 除刀柄外物料报废 入库到Scrap
if self.integral_product_id: if self.integral_product_id:
datas['scrap'].append({'lot_id': self.integral_lot_id}) self.integral_product_id.dismantle_stock_moves(False, self.integral_lot_id, location,
location_dest_scrap, code)
elif self.blade_product_id: elif self.blade_product_id:
datas['scrap'].append({'lot_id': self.blade_lot_id}) self.blade_product_id.dismantle_stock_moves(False, self.blade_lot_id, location, location_dest_scrap,
code)
if self.bar_product_id: if self.bar_product_id:
datas['scrap'].append({'lot_id': self.bar_lot_id}) self.bar_product_id.dismantle_stock_moves(False, self.bar_lot_id, location, location_dest_scrap,
code)
elif self.pad_product_id: elif self.pad_product_id:
datas['scrap'].append({'lot_id': self.pad_lot_id}) self.pad_product_id.dismantle_stock_moves(False, self.pad_lot_id, location, location_dest_scrap,
code)
if self.chuck_product_id: if self.chuck_product_id:
datas['scrap'].append({'lot_id': self.chuck_lot_id}) self.chuck_product_id.dismantle_stock_moves(False, self.chuck_lot_id, location, location_dest_scrap,
code)
# ===========功能刀具[磨削]拆解==============
# elif self.dismantle_cause in ['刀具需磨削']:
# location_dest = self.env['stock.location'].search([('name', '=', '磨削房')])
# # 除刀柄外物料拆解 入库到具体库位
# if self.integral_product_id:
# self.integral_product_id.dismantle_stock_moves(False, location, location_dest)
# elif self.blade_product_id:
# self.blade_product_id.dismantle_stock_moves(False, location, location_dest)
# if self.bar_product_id:
# self.bar_product_id.dismantle_stock_moves(False, location, location_dest)
# elif self.pad_product_id:
# self.pad_product_id.dismantle_stock_moves(False, location, location_dest)
# if self.chuck_product_id:
# self.chuck_product_id.dismantle_stock_moves(False, location, location_dest)
# ==============功能刀具[更换,磨削]拆解============== # ==============功能刀具[更换,磨削]拆解==============
elif self.dismantle_cause in ['更换为其他刀具', '刀具需磨削']: elif self.dismantle_cause in ['更换为其他刀具', '刀具需磨削']:
# 除刀柄外物料拆解 入库到具体货位 # 除刀柄外物料拆解 入库到具体货位
if self.integral_freight_id: if self.integral_freight_id:
datas['picking'].append({'lot_id': self.integral_lot_id, 'destination': self.integral_freight_id}) self.integral_product_id.dismantle_stock_moves(self.integral_freight_id, self.integral_lot_id, location,
location_dest, code)
elif self.blade_freight_id: elif self.blade_freight_id:
datas['picking'].append({'lot_id': self.blade_lot_id, 'destination': self.blade_freight_id}) self.blade_product_id.dismantle_stock_moves(self.blade_freight_id, self.blade_lot_id, location,
location_dest, code)
if self.bar_freight_id: if self.bar_freight_id:
datas['picking'].append({'lot_id': self.bar_lot_id, 'destination': self.bar_freight_id}) self.bar_product_id.dismantle_stock_moves(self.bar_freight_id, self.bar_lot_id, location,
location_dest, code)
elif self.pad_freight_id: elif self.pad_freight_id:
datas['picking'].append({'lot_id': self.pad_lot_id, 'destination': self.pad_freight_id}) self.pad_product_id.dismantle_stock_moves(self.pad_freight_id, self.pad_lot_id, location,
location_dest, code)
if self.chuck_freight_id: if self.chuck_freight_id:
datas['picking'].append({'lot_id': self.chuck_lot_id, 'destination': self.chuck_freight_id}) self.chuck_product_id.dismantle_stock_moves(self.chuck_freight_id, self.chuck_lot_id, location,
self.create_tool_picking_scrap(datas) location_dest, code)
# ===============创建功能刀具拆解移动记录===== # ===============删除功能刀具的Rfid字段的值 赋值给Rfid(已拆解)字段=====
self.env['stock.move'].create_functional_tool_stock_move(self)
# 修改功能刀具数据
self.functional_tool_id.write({ self.functional_tool_id.write({
'rfid_dismantle': self.functional_tool_id.rfid, 'rfid_dismantle': self.functional_tool_id.rfid,
'rfid': '', 'rfid': '',
@@ -1000,173 +998,37 @@ class FunctionalToolDismantle(models.Model):
}) })
# 修改拆解单的值 # 修改拆解单的值
self.write({ self.write({
'rfid_dismantle': self.rfid,
'dismantle_data': fields.Datetime.now(), 'dismantle_data': fields.Datetime.now(),
'dismantle_person': self.env.user.name, 'dismantle_person': self.env.user.name,
'rfid': '%s(已拆解)' % self.rfid, 'rfid': '',
'state': '已拆解' 'state': '已拆解'
}) })
logging.info('%s】刀具拆解成功!' % self.name) logging.info('%s】刀具拆解成功!' % self.name)
def create_tool_picking_scrap(self, datas):
scrap_data = datas['scrap']
picking_data = datas['picking']
if scrap_data:
for data in scrap_data:
if data:
self.env['stock.scrap'].create_tool_dismantle_stock_scrap(data['lot_id'], self)
if picking_data:
picking_id = self.env['stock.picking'].create_tool_dismantle_picking(self)
self.picking_id = picking_id.id
self.env['stock.move'].create_tool_stock_move({'data': picking_data, 'picking_id': picking_id})
# 将刀具物料出库库单的状态更改为就绪
picking_id.action_confirm()
# 修改刀具物料出库移动历史记录
self.env['stock.move'].write_tool_stock_move_line({'data': picking_data, 'picking_id': picking_id})
# 设置数量,并验证完成
picking_id.action_set_quantities_to_reservation()
picking_id.button_validate()
def action_open_reference1(self): class ProductProduct(models.Model):
self.ensure_one() _inherit = 'product.product'
return {
'res_model': self._name,
'type': 'ir.actions.act_window',
'views': [[False, "form"]],
'res_id': self.id,
}
def open_function_tool_stock_move_line(self): def dismantle_stock_moves(self, shelf_location_id, lot_id, location_id, location_dest_id, code):
action = self.env.ref('sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_act') # 创建功能刀具拆解单产品库存移动记录
result = action.read()[0] stock_move_id = self.env['stock.move'].sudo().create({
result['domain'] = [('functional_tool_dismantle_id', '=', self.id), ('qty_done', '>', 0)] 'name': code,
return result 'product_id': self.id,
def open_tool_stock_picking(self):
action = self.env.ref('stock.action_picking_tree_all')
result = action.read()[0]
result['domain'] = [('origin', '=', self.code)]
return result
class StockPicking(models.Model):
_inherit = 'stock.picking'
def create_tool_dismantle_picking(self, obj):
"""
创建刀具物料入库单
"""
# 获取名称为内部调拨的作业类型
picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '内部调拨')])
location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
location_dest_id = self.env['stock.location'].search([('name', '=', '刀具房')])
if not location_id:
raise ValidationError('缺少名称为【刀具组装位置】的仓库管理地点')
if not location_dest_id:
raise ValidationError('缺少名称为【刀具房】的仓库管理地点')
# 创建刀具物料出库单
picking_id = self.env['stock.picking'].create({
'name': self._get_name_stock1(picking_type_id),
'picking_type_id': picking_type_id.id,
'location_id': location_id.id, 'location_id': location_id.id,
'location_dest_id': location_dest_id.id, 'location_dest_id': location_dest_id.id,
'origin': obj.code
})
return picking_id
class StockMove(models.Model):
_inherit = 'stock.move'
def create_tool_stock_move(self, datas):
picking_id = datas['picking_id']
data = datas['data']
stock_move_ids = []
for res in data:
if res:
# 创建库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': picking_id.name,
'picking_id': picking_id.id,
'product_id': res['lot_id'].product_id.id,
'location_id': picking_id.location_id.id,
'location_dest_id': picking_id.location_dest_id.id,
'product_uom_qty': 1.00,
'reserved_availability': 1.00
})
stock_move_ids.append(stock_move_id)
return stock_move_ids
def write_tool_stock_move_line(self, datas):
picking_id = datas['picking_id']
data = datas['data']
move_line_ids = picking_id.move_line_ids
for move_line_id in move_line_ids:
for res in data:
if move_line_id.lot_id.product_id == res['lot_id'].product_id:
move_line_id.write({
'destination_location_id': res.get('destination').id,
'lot_id': res.get('lot_id').id
})
return True
def create_functional_tool_stock_move(self, dismantle_id):
"""
对功能刀具拆解过程的功能刀具进行库存移动,以及创建移动历史
"""
location_dismantle_id = self.env['stock.location'].search([('name', '=', '拆解')])
if not location_dismantle_id:
raise ValidationError('缺少名称为【拆解】的仓库管理地点')
tool_id = dismantle_id.functional_tool_id
# 创建库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': dismantle_id.code,
'product_id': tool_id.barcode_id.product_id.id,
'location_id': tool_id.current_location_id.id,
'location_dest_id': location_dismantle_id.id,
'product_uom_qty': 1.00, 'product_uom_qty': 1.00,
'state': 'done' 'state': 'done'
}) })
# 创建移动历史记录 # 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({ stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': tool_id.barcode_id.product_id.id, 'product_id': self.id,
'functional_tool_dismantle_id': dismantle_id.id, 'lot_id': lot_id.id,
'lot_id': tool_id.barcode_id.id,
'move_id': stock_move_id.id, 'move_id': stock_move_id.id,
'destination_location_id': shelf_location_id.id,
'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0, 'qty_done': 1.0,
'state': 'done', 'state': 'done',
'functional_tool_type_id': tool_id.sf_cutting_tool_type_id.id,
'diameter': tool_id.functional_tool_diameter,
'knife_tip_r_angle': tool_id.knife_tip_r_angle,
'code': tool_id.code,
'rfid': tool_id.rfid,
'functional_tool_name': tool_id.name,
'tool_groups_id': tool_id.tool_groups_id.id
}) })
return stock_move_id, stock_move_line_id return stock_move_id, stock_move_line_id
class CustomStockScrap(models.Model):
_inherit = 'stock.scrap'
functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', string="功能刀具拆解单")
def create_tool_dismantle_stock_scrap(self, lot, dismantle_id):
location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
scrap_location_id = self.env['stock.location'].search([('name', 'in', ('Scrap', '报废'))])
if not location_id:
raise ValidationError('缺少名称为【刀具组装位置】的仓库管理地点')
if not scrap_location_id:
raise ValidationError('缺少名称为【Scrap】或【Scrap】的仓库管理地点')
stock_scrap_id = self.create({
'product_id': lot.product_id.id,
'lot_id': lot.id,
'location_id': location_id.id,
'scrap_location_id': scrap_location_id.id,
'functional_tool_dismantle_id': dismantle_id.id,
'origin': dismantle_id.code
})
# 完成报废单
stock_scrap_id.action_validate()
return stock_scrap_id

View File

@@ -34,17 +34,15 @@ class FunctionalCuttingToolEntity(models.Model):
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)) functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True, digits=(10, 3))
effective_length = fields.Float(string='有效长(mm)', readonly=True) effective_length = fields.Float(string='有效长(mm)', readonly=True)
tool_room_num = fields.Integer(string='刀具房数量', compute='_compute_num', store=True) tool_room_num = fields.Integer(string='刀具房数量', readonly=True)
line_edge_knife_library_num = fields.Integer(string='线边刀库数量', compute='_compute_num', store=True) line_edge_knife_library_num = fields.Integer(string='线边刀库数量', readonly=True)
machine_knife_library_num = fields.Integer(string='机内刀库数量', compute='_compute_num', store=True) machine_knife_library_num = fields.Integer(string='机内刀库数量', readonly=True)
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True) max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
alarm_value = fields.Integer(string='报警值(min)', readonly=True) alarm_value = fields.Integer(string='报警值(min)', readonly=True)
used_value = fields.Integer(string='已使用值(min)', readonly=True) used_value = fields.Integer(string='已使用值(min)', readonly=True)
functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')], functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')],
string='状态', store=True, default='正常') string='状态', store=True, default='正常')
current_location_id = fields.Many2one('stock.location', string='当前位置', compute='_compute_current_location_id', current_location_id = fields.Many2one('stock.location', string='当前位置', readonly=True)
store=True)
current_shelf_location_id = fields.Many2one('sf.shelf.location', string='当前货位', readonly=True)
current_location = fields.Selection( current_location = fields.Selection(
[('组装后', '组装后'), ('刀具房', '刀具房'), ('线边刀库', '线边刀库'), ('机内刀库', '机内刀库')], [('组装后', '组装后'), ('刀具房', '刀具房'), ('线边刀库', '线边刀库'), ('机内刀库', '机内刀库')],
string='位置', compute='_compute_current_location_id', store=True) string='位置', compute='_compute_current_location_id', store=True)
@@ -53,114 +51,44 @@ class FunctionalCuttingToolEntity(models.Model):
safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools', safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools',
string='功能刀具安全库存', readonly=True) string='功能刀具安全库存', readonly=True)
@api.depends('barcode_id.quant_ids', 'barcode_id.quant_ids.location_id', 'functional_tool_status', @api.depends('barcode_id.quant_ids', 'functional_tool_status')
'current_shelf_location_id')
def _compute_current_location_id(self): def _compute_current_location_id(self):
for record in self: for record in self:
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 == '制造前':
record.current_location = '机内刀库'
else:
record.current_location = quant_id.location_id.name
if record.current_location_id:
record.sudo().get_location_num()
else:
record.current_location_id = False
record.current_location = False
if record.functional_tool_status == '已拆除': if record.functional_tool_status == '已拆除':
record.current_location_id = False record.current_location_id = False
record.current_location = False record.current_location = False
else: record.tool_room_num = 0
if record.barcode_id.quant_ids: record.line_edge_knife_library_num = 0
for quant_id in record.barcode_id.quant_ids: record.machine_knife_library_num = 0
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 = '线边刀库'
else:
record.current_location = '刀具房'
else:
record.current_location_id = False
record.current_location = False
@api.depends('current_location', 'functional_tool_status') def get_location_num(self):
def _compute_num(self):
""" """
计算库存位置数量 计算库存位置数量
""" """
for obj in self: for obj in self:
if obj.functional_tool_status == '已拆除': if obj.current_location_id:
obj.tool_room_num = 0 obj.tool_room_num = 0
obj.line_edge_knife_library_num = 0 obj.line_edge_knife_library_num = 0
obj.machine_knife_library_num = 0 obj.machine_knife_library_num = 0
else: if obj.current_location in ['刀具房']:
if obj.current_location_id: obj.tool_room_num = 1
obj.tool_room_num = 0 elif "线边刀库" in obj.current_location:
obj.line_edge_knife_library_num = 0 obj.line_edge_knife_library_num = 1
obj.machine_knife_library_num = 0 elif "机内刀库" in obj.current_location:
if obj.current_location in ['刀具房']: obj.machine_knife_library_num = 1
obj.tool_room_num = 1
elif "线边刀库" in obj.current_location:
obj.line_edge_knife_library_num = 1
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 @api.model
def _read_group_mrs_cutting_tool_type_id(self, categories, domain, order): def _read_group_mrs_cutting_tool_type_id(self, categories, domain, order):
@@ -253,42 +181,22 @@ class FunctionalCuttingToolEntity(models.Model):
def open_safety_stock(self): def open_safety_stock(self):
action = self.env.ref('sf_tool_management.sf_real_time_distribution_of_functional_tools_view_act') action = self.env.ref('sf_tool_management.sf_real_time_distribution_of_functional_tools_view_act')
result = action.read()[0] result = action.read()[0]
result['domain'] = [('id', '=', self.safe_inventory_id.id)] result['domain'] = [('name', '=', self.name), ('diameter', '=', self.functional_tool_diameter),
('knife_tip_r_angle', '=', self.knife_tip_r_angle),
('coarse_middle_thin', '=', self.coarse_middle_thin)]
return result return result
def cnc_function_tool_use_verify(self):
"""
cnc程序用刀可用校验校验是否是制造订单所缺刀
"""
if self.tool_name_id.name:
cnc_processing_ids = self.env['sf.cnc.processing'].search(
[('tool_state', '=', '1'), ('cutting_tool_name', '=', self.tool_name_id.name)])
production_ids = []
if cnc_processing_ids:
for item in cnc_processing_ids:
if item.workorder_id and item.workorder_id.production_id not in production_ids:
production_ids.append(item.workorder_id.production_id)
if production_ids:
# 对同一制造订单的工单的cnc编程单的功能刀具状态进行变更并调用工单的功能刀具状态计算方法
for production_id in production_ids:
cnc_ids = cnc_processing_ids.filtered(lambda a: a.workorder_id.production_id == production_id)
cnc_ids.sudo().write({'tool_state': '0'})
cnc_ids.workorder_id._compute_tool_state()
def tool_inventory_displacement_out(self): def tool_inventory_displacement_out(self):
""" """
机床当前刀库实时信息接口,功能刀具出库 机床当前刀库实时信息接口,功能刀具出库
""" """
# 获取位置对象 # 获取位置对象
location_inventory_id = self.current_location_id
stock_location_id = self.env['stock.location'].search([('name', '=', '制造前')]) stock_location_id = self.env['stock.location'].search([('name', '=', '制造前')])
# 创建功能刀具该批次/序列号 库存移动和移动历史 # 创建功能刀具该批次/序列号 库存移动和移动历史
self.create_stock_move(stock_location_id, False) self.barcode_id.create_stock_quant(location_inventory_id, stock_location_id,
self.current_location_id = stock_location_id.id self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id,
self.current_shelf_location_id = False self.functional_tool_name_id.tool_groups_id)
# 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): # def _register_functional_tool_groups(self, obj):
@@ -391,13 +299,12 @@ class StockMoveLine(models.Model):
_order = 'date desc' _order = 'date desc'
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单') functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单')
functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', string='功能刀具拆解单')
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True, functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
group_expand='_read_group_functional_tool_type_id') group_expand='_read_group_functional_tool_type_id')
functional_tool_name = fields.Char('刀具名称') functional_tool_name = fields.Char('刀具名称')
diameter = fields.Float(string='刀具直径(mm)') diameter = fields.Float(string='刀具直径(mm)')
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)') knife_tip_r_angle = fields.Float(string='刀尖R角(mm)')
install_tool_time = fields.Datetime("刀具组装时间") install_tool_time = fields.Datetime("刀具组装时间", default=fields.Datetime.now())
code = fields.Char('编码') code = fields.Char('编码')
rfid = fields.Char('Rfid') rfid = fields.Char('Rfid')
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组') tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组')
@@ -407,43 +314,23 @@ class StockMoveLine(models.Model):
names = categories._search([], order=order, access_rights_uid=SUPERUSER_ID) names = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
return categories.browse(names) 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
if self.functional_tool_dismantle_id:
action = self.functional_tool_dismantle_id.action_open_reference1()
return action
elif self.move_id:
action = self.move_id.action_open_reference()
if action['res_model'] != 'stock.move':
return action
return {
'res_model': self._name,
'type': 'ir.actions.act_window',
'views': [[False, "form"]],
'res_id': self.id,
}
class RealTimeDistributionOfFunctionalTools(models.Model): class RealTimeDistributionOfFunctionalTools(models.Model):
_name = 'sf.real.time.distribution.of.functional.tools' _name = 'sf.real.time.distribution.of.functional.tools'
_inherit = ['mail.thread'] _inherit = ['mail.thread']
_description = '功能刀具安全库存' _description = '功能刀具安全库存'
name = fields.Char('名称', compute='_compute_num', store=True) name = fields.Char('名称', readonly=True, compute='_compute_name', store=True)
functional_name_id = fields.Many2one('sf.tool.inventory', string='功能刀具名称', required=True) functional_name_id = fields.Many2one('sf.tool.inventory', string='功能刀具名称', required=True)
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_num', store=True) tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=False, required=True)
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False,
compute='_compute_num', store=True, group_expand='_read_mrs_cutting_tool_type_ids', store=True)
group_expand='_read_mrs_cutting_tool_type_ids') diameter = fields.Float(string='刀具直径(mm)', readonly=False)
diameter = fields.Float(string='具直径(mm)', compute='_compute_num', store=True) knife_tip_r_angle = fields.Float(string='尖R角(mm)', readonly=False)
knife_tip_r_angle = fields.Float(string='尖R角(mm)', compute='_compute_num', store=True) tool_stock_num = fields.Integer(string='具房数量')
tool_stock_num = fields.Integer(string='刀具房数量', compute='_compute_stock_num', store=True) side_shelf_num = fields.Integer(string='线边刀库数量')
side_shelf_num = fields.Integer(string='线边刀库数量', compute='_compute_stock_num', store=True) on_tool_stock_num = fields.Integer(string='机内刀库数量')
on_tool_stock_num = fields.Integer(string='机内刀库数', compute='_compute_stock_num', store=True) tool_stock_total = fields.Integer(string='当前库存', readonly=True)
tool_stock_total = fields.Integer(string='当前库存量', compute='_compute_tool_stock_total', store=True)
min_stock_num = fields.Integer('最低库存量', tracking=True) min_stock_num = fields.Integer('最低库存量', tracking=True)
max_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', batch_replenishment_num = fields.Integer('批次补货量', readonly=True, compute='_compute_batch_replenishment_num',
@@ -484,18 +371,22 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
@api.depends('functional_name_id', 'functional_name_id.diameter', 'functional_name_id.angle', @api.onchange('functional_name_id')
'functional_name_id.functional_cutting_tool_model_id') def _onchange_num(self):
def _compute_num(self):
for item in self: for item in self:
if item.functional_name_id: if item.functional_name_id:
item.tool_groups_id = item.functional_name_id.tool_groups_id.id item.tool_groups_id = item.functional_name_id.tool_groups_id.id
item.sf_cutting_tool_type_id = item.functional_name_id.functional_cutting_tool_model_id.id item.sf_cutting_tool_type_id = item.functional_name_id.functional_cutting_tool_model_id.id
item.diameter = item.functional_name_id.diameter item.diameter = item.functional_name_id.diameter
item.knife_tip_r_angle = item.functional_name_id.angle item.knife_tip_r_angle = item.functional_name_id.angle
item.name = item.functional_name_id.name
@api.depends('functional_name_id')
def _compute_name(self):
for obj in self:
if obj.tool_groups_id:
obj.name = obj.functional_name_id.name
else: else:
item.sudo().name = '' obj.sudo().name = ''
@api.constrains('min_stock_num', 'max_stock_num') @api.constrains('min_stock_num', 'max_stock_num')
def _check_stock_num(self): def _check_stock_num(self):
@@ -512,6 +403,10 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
def _compute_batch_replenishment_num(self): def _compute_batch_replenishment_num(self):
for tool in self: for tool in self:
if tool: 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) tool.sudo().open_batch_replenishment_num(tool)
@@ -530,38 +425,6 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
else: else:
tool.sudo().batch_replenishment_num = 0 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): def create_functional_tool_assembly(self, tool):
""" """
创建功能刀具组装单 创建功能刀具组装单
@@ -582,6 +445,27 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
}) })
tool.sudo().sf_functional_tool_assembly_ids = [(4, functional_tool_assembly.id)] 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): def create_or_edit_safety_stock(self, vals, sf_functional_tool_entity_ids):
""" """
根据传入的信息新增或者更新功能刀具安全库存的信息 根据传入的信息新增或者更新功能刀具安全库存的信息
@@ -603,10 +487,4 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
for vals in vals_list: for vals in vals_list:
vals['status_create'] = False vals['status_create'] = False
records = super(RealTimeDistributionOfFunctionalTools, self).create(vals_list) records = super(RealTimeDistributionOfFunctionalTools, self).create(vals_list)
for item in records:
if item:
record = self.search([('functional_name_id', '=', item.functional_name_id.id)])
if len(record) > 1:
raise ValidationError(
'功能刀具名称为【%s】的安全库存已经存在,请勿重复创建!!!' % item.functional_name_id.name)
return records return records

View File

@@ -37,10 +37,14 @@ class ToolDatasync(models.Model):
def _cron_tool_datasync_all(self): def _cron_tool_datasync_all(self):
try: try:
self.env['sf.tool.material.search'].sudo().sync_enroll_tool_material_all()
self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all() self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all()
self.env['sf.fixture.material.search'].sudo().sync_enroll_fixture_material_all()
self.env['stock.lot'].sudo().sync_enroll_fixture_material_stock_all() self.env['stock.lot'].sudo().sync_enroll_fixture_material_stock_all()
self.env['sf.tool.material.search'].sudo().sync_enroll_tool_material_all()
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() self.env['sf.functional.cutting.tool.entity'].sudo().esync_enroll_functional_tool_entity_all()
logging.info("已全部同步完成!!!") logging.info("已全部同步完成!!!")
# self.env['sf.functional.tool.warning'].sudo().sync_enroll_functional_tool_warning_all() # self.env['sf.functional.tool.warning'].sudo().sync_enroll_functional_tool_warning_all()
@@ -76,7 +80,7 @@ class StockLot(models.Model):
headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create" str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create"
product_ids = self.env['product.product'].sudo().search([('categ_type', '=', '刀具')]).ids product_ids = self.env['product.product'].sudo().search([('categ_type', '=', '刀具')]).ids
objs_all = self.env['stock.lot'].search([('product_id', 'in', product_ids)]) objs_all = self.env['stock.lot'].search([('rfid', '!=', False), ('product_id', 'in', product_ids)])
self._get_sync_stock_lot(objs_all, str_url, token, headers) self._get_sync_stock_lot(objs_all, str_url, token, headers)
def _get_sync_stock_lot(self, objs_all, str_url, token, headers): def _get_sync_stock_lot(self, objs_all, str_url, token, headers):
@@ -86,7 +90,6 @@ class StockLot(models.Model):
for item in objs_all: for item in objs_all:
val = { val = {
'name': item.name, 'name': item.name,
'qty': item.product_qty,
'tool_material_status': item.tool_material_status, 'tool_material_status': item.tool_material_status,
'location': [] if not item.quant_ids else item.quant_ids[-1].location_id.name, 'location': [] if not item.quant_ids else item.quant_ids[-1].location_id.name,
'tool_material_search_id': item.tool_material_search_id.id, 'tool_material_search_id': item.tool_material_search_id.id,
@@ -160,6 +163,8 @@ class ToolMaterial(models.Model):
logging.info("刀具物料同步失败:%s" % e) logging.info("刀具物料同步失败:%s" % e)
class FunctionalCuttingToolEntity(models.Model): class FunctionalCuttingToolEntity(models.Model):
_inherit = 'sf.functional.cutting.tool.entity' _inherit = 'sf.functional.cutting.tool.entity'
_description = '功能刀具列表注册' _description = '功能刀具列表注册'
@@ -194,7 +199,7 @@ class FunctionalCuttingToolEntity(models.Model):
for item in objs_all: for item in objs_all:
val = { val = {
'id': item.id, 'id': item.id,
'code': False if not item.code else item.code.split('-', 1)[1], 'code': item.code,
'name': item.name, 'name': item.name,
'rfid': item.rfid, 'rfid': item.rfid,
'tool_groups_name': item.tool_groups_id.name, 'tool_groups_name': item.tool_groups_id.name,
@@ -230,7 +235,8 @@ class FunctionalCuttingToolEntity(models.Model):
'blade_tip_characteristics_name': item.blade_tip_characteristics_id.name, 'blade_tip_characteristics_name': item.blade_tip_characteristics_id.name,
'handle_type_name': item.handle_type_id.name, 'handle_type_name': item.handle_type_id.name,
'cutting_direction_names': get_cutting_direction_names(item), 'cutting_direction_names': get_cutting_direction_names(item),
'suitable_coolant_names': get_suitable_coolant_names(item) 'suitable_coolant_names': get_suitable_coolant_names(item),
'active': item.active,
} }
functional_tool_list.append(val) functional_tool_list.append(val)
kw = json.dumps(functional_tool_list, ensure_ascii=False) kw = json.dumps(functional_tool_list, ensure_ascii=False)
@@ -245,6 +251,8 @@ class FunctionalCuttingToolEntity(models.Model):
logging.info("功能刀具同步失败:%s" % e) logging.info("功能刀具同步失败:%s" % e)
class FunctionalToolWarning(models.Model): class FunctionalToolWarning(models.Model):
_inherit = 'sf.functional.tool.warning' _inherit = 'sf.functional.tool.warning'
_description = '功能刀具预警注册' _description = '功能刀具预警注册'

View File

@@ -3,7 +3,6 @@ import requests
import logging import logging
from odoo import models, api, fields from odoo import models, api, fields
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from datetime import datetime, timedelta
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
@@ -45,79 +44,71 @@ class SfMaintenanceEquipment(models.Model):
# ==========机床当前刀库实时信息接口========== # ==========机床当前刀库实时信息接口==========
def register_equipment_tool(self): def register_equipment_tool(self):
try: config = self.env['res.config.settings'].get_values()
config = self.env['res.config.settings'].get_values() # token = sf_sync_config['token'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A]
# token = sf_sync_config['token'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A] headers = {'Authorization': config['center_control_Authorization']}
headers = {'Authorization': config['center_control_Authorization']} crea_url = config['center_control_url'] + "/AutoDeviceApi/GetToolInfos"
crea_url = config['center_control_url'] + "/AutoDeviceApi/GetToolInfos" params = {"DeviceId": self.name}
params = {"DeviceId": self.name} r = requests.get(crea_url, params=params, headers=headers)
r = requests.get(crea_url, params=params, headers=headers) ret = r.json()
ret = r.json() logging.info('register_equipment_tool:%s' % ret)
logging.info('register_equipment_tool:%s' % ret) datas = ret['Datas']
datas = ret['Datas'] self.write_maintenance_equipment_tool(datas)
self.write_maintenance_equipment_tool(datas) if ret['Succeed']:
if ret['Succeed']: return "机床当前刀库实时信息指令发送成功"
return "机床当前刀库实时信息指令发送成功" else:
else: raise ValidationError("机床当前刀库实时信息指令发送失败")
raise ValidationError("机床当前刀库实时信息指令发送失败")
except Exception as e:
logging.info("register_equipment_tool()捕获错误信息:%s" % e)
def write_maintenance_equipment_tool(self, datas): def write_maintenance_equipment_tool(self, datas):
try: if datas:
if datas: # 清除设备机床刀位的刀具信息
# 清除设备机床刀位的刀具信息 for obj in self.product_template_ids:
for obj in self.product_template_ids: obj.write({
obj.write({ 'functional_tool_name_id': False,
'functional_tool_name_id': False, 'tool_install_time': None
'tool_install_time': None })
}) for data in datas:
for data in datas: maintenance_equipment_id = self.search([('name', '=', data['DeviceId'])])
maintenance_equipment_id = self.search([('name', '=', data['DeviceId'])]) if maintenance_equipment_id:
if maintenance_equipment_id: tool_id = '%s%s' % (data['ToolId'][0:1], data['ToolId'][1:].zfill(2))
tool_id = '%s%s' % (data['ToolId'][0:1], data['ToolId'][1:].zfill(2)) equipment_tool_id = self.env['maintenance.equipment.tool'].sudo().search(
equipment_tool_id = self.env['maintenance.equipment.tool'].sudo().search( [('equipment_id', '=', maintenance_equipment_id.id), ('code', '=', tool_id)])
[('equipment_id', '=', maintenance_equipment_id.id), ('code', '=', tool_id)]) functional_tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search(
functional_tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search( [('rfid', '=', data['RfidCode'])])
[('rfid', '=', data['RfidCode'])]) if functional_tool_id:
if functional_tool_id: # 查询该功能刀具是否已经装在机床内其他位置,如果是就删除
if len(functional_tool_id) > 1: equipment_tools = self.env['maintenance.equipment.tool'].sudo().search(
functional_tool_id = functional_tool_id[-1] [('functional_tool_name_id', '=', functional_tool_id.id), ('code', '!=', tool_id)])
# 查询该功能刀具是否已经装在机床内其他位置,如果是就删除 if equipment_tools:
equipment_tools = self.env['maintenance.equipment.tool'].sudo().search( for item in equipment_tools:
[('functional_tool_name_id', '=', functional_tool_id.id), ('code', '!=', tool_id)]) item.write({
if equipment_tools: 'functional_tool_name_id': False,
for item in equipment_tools: 'tool_install_time': None
item.write({ })
'functional_tool_name_id': False,
'tool_install_time': None
})
else:
logging.info('Rfid为【%s】的功能刀具不存在!' % data['RfidCode'])
time = None
if data['AddDatetime']:
datatime = str(data['AddDatetime'])
time = fields.Datetime.from_string(datatime[0:10] + ' ' + datatime[11:19])
if equipment_tool_id and functional_tool_id:
tool_install_time = {'Nomal': '正常', 'Warning': '报警'}
equipment_tool_id.write({
'functional_tool_name_id': functional_tool_id.id,
'tool_install_time': time - timedelta(hours=8)
})
if functional_tool_id.current_location != '机内刀库':
# 对功能刀具进行移动到生产线
functional_tool_id.tool_inventory_displacement_out()
functional_tool_id.write({
'max_lifetime_value': data['MaxLife'],
'used_value': data['UseLife'],
'functional_tool_status': tool_install_time.get(data['State'])
})
else: else:
logging.info('获取的%s设备不存在!' % data['DeviceId']) logging.info('Rfid为%s的功能刀具不存在!' % data['RfidCode'])
else: time = None
logging.info('没有获取到【%s】设备的刀具库信息!!!' % self.name) if data['AddDatetime']:
except Exception as e: datatime = str(data['AddDatetime'])
logging.info("write_maintenance_equipment_tool()捕获错误信息:%s" % e) time = fields.Datetime.from_string(datatime[0:10] + ' ' + datatime[11:19])
if equipment_tool_id and functional_tool_id:
tool_install_time = {'Nomal': '正常', 'Warning': '报警'}
equipment_tool_id.write({
'functional_tool_name_id': functional_tool_id.id,
'tool_install_time': time
})
if functional_tool_id.current_location_id.name != '制造前':
# 对功能刀具进行出库到生产线
functional_tool_id.tool_inventory_displacement_out()
functional_tool_id.write({
'max_lifetime_value': data['MaxLife'],
'used_value': data['UseLife'],
'functional_tool_status': tool_install_time.get(data['State'])
})
else:
raise ValidationError('获取的【%s】设备不存在!!!' % data['DeviceId'])
else:
raise ValidationError('没有获取到刀具库信息!!!')
class StockLot(models.Model): class StockLot(models.Model):
@@ -143,6 +134,9 @@ class StockLot(models.Model):
record.tool_material_status = '报废' record.tool_material_status = '报废'
else: else:
record.tool_material_status = '未入库' record.tool_material_status = '未入库'
if record.fixture_material_search_id:
# 注册夹具物料状态到cloud平台
record.enroll_fixture_material_stock()
@api.model @api.model
def name_search(self, name='', args=None, operator='ilike', limit=100): def name_search(self, name='', args=None, operator='ilike', limit=100):

View File

@@ -29,106 +29,13 @@ class CNCprocessing(models.Model):
# else: # else:
# raise ValidationError("MES装刀指令发送失败") # raise ValidationError("MES装刀指令发送失败")
def cnc_tool_checkout(self, cnc_processing_ids):
"""
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
"""
logging.info('开始进行工单cnc程序用刀校验')
logging.info(f'cnc_processing_ids:{cnc_processing_ids}')
if not cnc_processing_ids:
return False
cam_id = self.env['sf.cam.work.order.program.knife.plan']
production_ids = [] # 制造订单集
datas = {'缺刀': {}, '无效刀': {}} # 缺刀/无效刀集
for cnc_processing in cnc_processing_ids:
# ======创建字典: {'缺刀': {'制造订单1': {'加工面1': [], ...}, ...}, '无效刀': {'制造订单1': {'加工面1': [], ...}, ...}}======
production_name = cnc_processing.workorder_id.production_id.name # 制造订单
processing_panel = cnc_processing.workorder_id.processing_panel # 加工面
if production_name not in list(datas['缺刀'].keys()):
datas['缺刀'].update({production_name: {processing_panel: []}})
datas['无效刀'].update({production_name: {processing_panel: []}})
production_ids.append(cnc_processing.workorder_id.production_id)
else:
if processing_panel not in list(datas['缺刀'].get(production_name).keys()):
datas['缺刀'].get(production_name).update({processing_panel: []})
datas['无效刀'].get(production_name).update({processing_panel: []})
# ======================================
if cnc_processing.cutting_tool_name:
tool_name = cnc_processing.cutting_tool_name
# 检验CNC用刀是否是功能刀具清单中的刀具
tool_inventory_id = self.env['sf.tool.inventory'].sudo().search([('name', '=', tool_name)])
if not tool_inventory_id:
if cnc_processing.cutting_tool_name not in datas['无效刀'][production_name][processing_panel]:
datas['无效刀'][production_name][processing_panel].append(cnc_processing.cutting_tool_name)
cnc_processing.tool_state = '2'
logging.info(f'"无效刀"[{production_name}{processing_panel}{cnc_processing.cutting_tool_name}]')
# 跳过本次循环
continue
# 校验CNC用刀在系统是否存在
functional_tools = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('tool_name_id', '=', tool_inventory_id.id), ('functional_tool_status', '=', '正常')])
# 判断线边、机内是否有满足条件的刀
if not functional_tools.filtered(lambda p: p.current_location in ('线边刀库', '机内刀库')):
if cnc_processing.cutting_tool_name not in datas['缺刀'][production_name][processing_panel]:
datas['缺刀'][production_name][processing_panel].append(cnc_processing.cutting_tool_name)
cnc_processing.tool_state = '1'
logging.info(f'"缺刀"[{production_name}{processing_panel}{cnc_processing.cutting_tool_name}]')
# 判断是否有满足条件的刀
if not functional_tools:
# 创建CAM申请装刀记录
cam_id.create_cam_work_plan(cnc_processing)
logging.info('成功调用CAM工单程序用刀计划创建方法')
logging.info(f'datas:{datas}')
for production_id in production_ids:
logging.info(f'production_id: {production_id}')
if production_id:
data1 = datas['无效刀'].get(production_id.name) # data1: {'加工面1': [], ...}
data2 = datas['缺刀'].get(production_id.name) # data2: {'加工面1': [], ...}
# tool_state_remark1 = ''
tool_state_remark2 = ''
# 对无效刀信息进行处理
for key in data1:
if data1.get(key):
# if tool_state_remark1 != '':
# tool_state_remark1 = f'{tool_state_remark1}\n{key}无效刀:{data1.get(key)}'
# else:
# tool_state_remark1 = f'{key}无效刀:{data1.get(key)}'
# 无效刀处理逻辑
# 1、创建制造订单无效刀检测结果记录
logging.info('创建制造订单无效刀检测结果记录!')
production_id.detection_result_ids.create({
'production_id': production_id.id,
'processing_panel': key,
'routing_type': 'CNC加工',
'rework_reason': 'programming', # 原因:编程(programming)
'detailed_reason': '无效功能刀具',
'test_results': '返工',
'handle_result': '待处理'
})
# 修改当前面装夹预调工单的 is_rework 为 True
# work_ids = production_id.workorder_ids.filtered(
# lambda a: a.routing_type == '装夹预调' and a.processing_panel == key and not a.is_rework)
# work_ids.write({'is_rework': True})
# 对缺刀信息进行处理
for key in data2:
if data2.get(key):
if tool_state_remark2 != '':
tool_state_remark2 = f'{tool_state_remark2}\n{key}缺刀:{data2.get(key)}'
else:
tool_state_remark2 = f'{key}缺刀:{data2.get(key)}'
# 将备注信息存入制造订单功能刀具状态的备注字段
logging.info('修改制造订单功能刀具状态的备注字段')
production_id.write({
'tool_state_remark': tool_state_remark2,
# 'tool_state_remark2': tool_state_remark1
})
logging.info('工单cnc程序用刀校验已完成')
@api.model_create_multi @api.model_create_multi
def create(self, vals): def create(self, vals):
obj = super(CNCprocessing, self).create(vals) obj = super(CNCprocessing, self).create(vals)
# 调用CAM工单程序用刀计划创建方法 for item in obj:
self.cnc_tool_checkout(obj) # 调用CAM工单程序用刀计划创建方法
self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(item)
logging.info('成功调用CAM工单程序用刀计划创建方法')
return obj return obj

View File

@@ -1,60 +0,0 @@
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
class StockMoveLine(models.Model):
_inherit = 'stock.move.line'
@api.model_create_multi
def create(self, vals_list):
records = super(StockMoveLine, self).create(vals_list)
move_lines = records.filtered(lambda a: a.product_id.categ_id.name == '功能刀具' and a.state == 'done')
if move_lines: # 校验是否为功能刀具移动历史
self.button_function_tool_use_verify(move_lines)
return records
def button_function_tool_use_verify(self, move_lines):
"""
对所有从【刀具房】到【制造前】的功能刀具进行校验(校验是否为制造订单所缺的刀)
"""
location_id = self.env['stock.location'].search([('name', '=', '刀具房')])
location_dest_id = self.env['stock.location'].search([('name', '=', '制造前')])
line_ids = move_lines.filtered(
lambda a: a.location_id == location_id and a.location_dest_id == location_dest_id)
for line_id in line_ids:
if line_id.lot_id:
self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('barcode_id', '=', line_id.lot_id.id),
('functional_tool_status', '=', '正常')]).cnc_function_tool_use_verify()
class StockPicking(models.Model):
_inherit = 'stock.picking'
def button_validate(self):
res = super().button_validate()
move_lines = self.move_line_ids.filtered(lambda a: a.product_id.categ_id.name == '功能刀具')
if move_lines:
self.env['stock.move.line'].sudo().button_function_tool_use_verify(move_lines)
return res

View File

@@ -25,8 +25,7 @@ class ToolMaterial(models.Model):
have_been_used_num = fields.Integer('在用数量', compute='_compute_number', store=True) have_been_used_num = fields.Integer('在用数量', compute='_compute_number', store=True)
scrap_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') @api.depends('product_id.stock_quant_ids.quantity')
def _compute_number(self): def _compute_number(self):
@@ -47,6 +46,8 @@ class ToolMaterial(models.Model):
record.scrap_num = scrap_num record.scrap_num = scrap_num
record.number = usable_num + have_been_used_num + scrap_num record.number = usable_num + have_been_used_num + scrap_num
@api.model @api.model
def _read_group_cutting_tool_material_id(self, categories, domain, order): def _read_group_cutting_tool_material_id(self, categories, domain, order):
cutting_tool_material_id = categories._search([], order=order, access_rights_uid=SUPERUSER_ID) cutting_tool_material_id = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)

View File

@@ -60,9 +60,13 @@
</button> </button>
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user" <button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
name="open_stock_move_line" name="open_stock_move_line"
icon="fa-list-ul"
type="object"> type="object">
<i class="fa fa-fw o_button_icon fa-exchange"/> <div class="o_field_widget o_stat_info">
<span>出库入库记录</span> <span>
出库入库记录
</span>
</div>
</button> </button>
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user" <button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
name="open_safety_stock" name="open_safety_stock"
@@ -169,10 +173,7 @@
<field name="cut_time" attrs="{'invisible': [('new_former','=','0')]}"/> <field name="cut_time" attrs="{'invisible': [('new_former','=','0')]}"/>
<field name="cut_length" 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="cut_number" attrs="{'invisible': [('new_former','=','0')]}"/>
<field name="current_location_id" string="当前位置" invisible="1"/>
<field name="current_location" string="当前位置"/> <field name="current_location" string="当前位置"/>
<field name="current_shelf_location_id" string="当前货位"
attrs="{'invisible': [('current_shelf_location_id', '=', False)]}"/>
</group> </group>
</group> </group>
</page> </page>
@@ -188,7 +189,6 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="rfid"/> <field name="rfid"/>
<field name="barcode_id"/>
<field name="tool_name_id"/> <field name="tool_name_id"/>
<field name="functional_tool_diameter"/> <field name="functional_tool_diameter"/>
<field name="knife_tip_r_angle"/> <field name="knife_tip_r_angle"/>
@@ -204,8 +204,8 @@
domain="[('functional_tool_status', '!=', '已拆除')]"/> domain="[('functional_tool_status', '!=', '已拆除')]"/>
<filter string="已拆除" name="state_removed" domain="[('functional_tool_status', '=', '已拆除')]"/> <filter string="已拆除" name="state_removed" domain="[('functional_tool_status', '=', '已拆除')]"/>
<searchpanel> <searchpanel>
<field name="current_location" icon="fa-building" enable_counters="1"/>
<field name="functional_tool_status" icon="fa-building" enable_counters="1"/> <field name="functional_tool_status" icon="fa-building" enable_counters="1"/>
<field name="current_location" icon="fa-building" enable_counters="1"/>
<field name="sf_cutting_tool_type_id" icon="fa-building" enable_counters="1"/> <field name="sf_cutting_tool_type_id" icon="fa-building" enable_counters="1"/>
</searchpanel> </searchpanel>
<group expand="0"> <group expand="0">
@@ -472,24 +472,20 @@
<field name="name">功能刀具出入库记录</field> <field name="name">功能刀具出入库记录</field>
<field name="model">stock.move.line</field> <field name="model">stock.move.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="功能刀具出入库记录" create="0" edit="0" delete="0" default_order="id desc" <tree string="功能刀具出入库记录" create="0" edit="0" delete="0">
action="action_open_reference1" type="object">
<field name="reference" string="单据号"/> <field name="reference" string="单据号"/>
<field name="lot_id" invisible="1"/> <field name="lot_id" invisible="1"/>
<field name="rfid"/> <field name="rfid"/>
<field name="functional_tool_name_id" optional="hide"/>
<field name="functional_tool_name" string="功能刀具名称"/> <field name="functional_tool_name" string="功能刀具名称"/>
<field name="diameter"/> <field name="diameter"/>
<field name="knife_tip_r_angle"/> <field name="knife_tip_r_angle"/>
<field name="install_tool_time"/>
<field name="location_id"/> <field name="location_id"/>
<field name="current_location_id"/>
<field name="location_dest_id"/> <field name="location_dest_id"/>
<field name="destination_location_id"/>
<field name="date"/> <field name="date"/>
<field name="qty_done" string="数量"/> <field name="qty_done" string="数量"/>
<field name="functional_tool_type_id" invisible="1"/> <field name="functional_tool_type_id" invisible="True"/>
<field name="functional_tool_name_id" invisible="1"/>
<field name="functional_tool_dismantle_id" invisible="1"/>
<field name="install_tool_time" invisible="1"/>
<!-- <button name="enroll_functional_tool_move" string="安全库存注册" type="object" class="btn-primary"/>--> <!-- <button name="enroll_functional_tool_move" string="安全库存注册" type="object" class="btn-primary"/>-->
</tree> </tree>
</field> </field>
@@ -501,20 +497,21 @@
<field name="model">stock.move.line</field> <field name="model">stock.move.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="reference"/>
<field name="lot_id"/>
<field name="rfid"/> <field name="rfid"/>
<field name="functional_tool_name"/> <field name="functional_tool_name"/>
<field name="diameter"/> <field name="diameter"/>
<field name="knife_tip_r_angle"/> <field name="knife_tip_r_angle"/>
<field name="reference"/> <field name="install_tool_time"/>
<field name="lot_id"/> <field name="location_id"/>
<field name="location_dest_id"/>
<field name="date"/>
<field name="qty_done"/>
<field name="functional_tool_type_id" invisible="True"/>
<searchpanel> <searchpanel>
<field name="functional_tool_type_id" enable_counters="1" icon="fa-building"/> <field name="functional_tool_type_id" enable_counters="1" icon="fa-building"/>
</searchpanel> </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> </search>
</field> </field>
</record> </record>
@@ -528,7 +525,7 @@
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_tree"/> ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_tree"/>
<field name="search_view_id" <field name="search_view_id"
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_search"/> ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_search"/>
<field name="domain">[('rfid', '!=', ''),('functional_tool_name', '!=', '')]</field> <field name="domain">[('functional_tool_name_id', '!=', False)]</field>
</record> </record>
</data> </data>

Some files were not shown because too many files have changed in this diff Show More