Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化加工质检

# Conflicts:
#	sf_message/models/sf_message_maintenance_logs.py
This commit is contained in:
jinling.yang
2024-10-23 11:56:16 +08:00
22 changed files with 279 additions and 49 deletions

View File

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

View File

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

View File

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

View File

@@ -14,12 +14,25 @@ class TestJikimoWorkorderExceptionNotify(TestJikimoWorkorderExceptionNotifyCommo
('model', '=', 'jikimo.workorder.exception')
]))
self.assertTrue(self.env['jikimo.message.template'].search([
('name', '=', '加工失败'),
('name', '=', '工单加工失败提醒'),
('model', '=', 'jikimo.workorder.exception')
]))
def test_create_message_queue_yc0001(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0001',
'exception_content': '无CNC程序'
})
def test_create_message_queue(self):
message_record = self.env['jikimo.message.queue'].search([
('res_id', '=', exception_record.id),
('model', '=', 'jikimo.workorder.exception'),
('message_status', '=', 'pending')
])
self.assertFalse(message_record)
def test_create_message_queue_yc0002(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0002',
@@ -44,6 +57,44 @@ class TestJikimoWorkorderExceptionNotify(TestJikimoWorkorderExceptionNotifyCommo
])
self.assertTrue(message_record)
def test_create_message_queue_yc0003(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0003',
'exception_content': '无定位数据'
})
bussiness_node = self.env['jikimo.message.bussiness.node'].search([
('name', '=', '无定位数据'),
('model', '=', 'jikimo.workorder.exception')
])
message_template = self.env['jikimo.message.template'].search([
('bussiness_node_id', '=', bussiness_node.id),
('model', '=', 'jikimo.workorder.exception')
])
message_record = self.env['jikimo.message.queue'].search([
('res_id', '=', exception_record.id),
('model', '=', 'jikimo.workorder.exception'),
('message_status', '=', 'pending'),
('message_template_id', '=', message_template.id)
])
self.assertTrue(message_record)
def test_create_message_queue_yc0004(self):
exception_record = self.env['jikimo.workorder.exception'].create({
'workorder_id': self.workorder.id,
'exception_code': 'YC0004',
'exception_content': '无CNC程序'
})
message_record = self.env['jikimo.message.queue'].search([
('res_id', '=', exception_record.id),
('model', '=', 'jikimo.workorder.exception'),
('message_status', '=', 'pending')
])
self.assertFalse(message_record)
def test_get_message(self):
exception_record = self.env['jikimo.workorder.exception'].create({

View File

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

View File

@@ -1272,6 +1272,7 @@ class Sf_Dashboard_Connect(http.Controller):
time_threshold = datetime.now() - timedelta(days=1)
alarm_last_24_time = 0.0
alarm_all_time = 0.0
def fetch_result_as_dict(cursor):
"""辅助函数:将查询结果转为字典"""
@@ -1332,6 +1333,35 @@ class Sf_Dashboard_Connect(http.Controller):
alarm_last_24_time += float(result[0])
else:
alarm_last_24_time += 0.0
alarm_all_nums = []
with conn.cursor() as cur:
cur.execute("""
SELECT DISTINCT ON (alarm_start_time) alarm_time, alarm_start_time
FROM device_data
WHERE device_name = %s
AND alarm_start_time IS NOT NULL;
""", (item,))
results = cur.fetchall()
for result in results:
alarm_all_nums.append(result[1])
if result[0]:
if float(result[0]) >= 1000:
continue
alarm_all_time += float(result[0])
else:
alarm_all_time += 0.0
# with conn.cursor() as cur:
# cur.execute("""
# SELECT * FROM device_data
# WHERE device_name = %s
# AND total_count IS NOT NULL
# ORDER BY time ASC
# LIMIT 1;
# """, (item, ))
# total_count = fetch_result_as_dict(cur)
# 返回数据
res['data'][item] = {
'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0,
@@ -1343,6 +1373,9 @@ class Sf_Dashboard_Connect(http.Controller):
'alarm_last_24_nums': len(list(set(alarm_last_24_nums))),
'idle_count': idle_count,
'first_online_time': first_online_duration,
'alarm_all_time': alarm_all_time,
'alarm_all_nums': len(list(set(alarm_all_nums)))
# 'total_count': total_count['total_count'] if total_count else 0
}
conn.close()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -225,6 +225,9 @@ class ResMrpWorkOrder(models.Model):
material_height = fields.Float(string='')
# 零件图号
part_number = fields.Char(related='production_id.part_number', string='零件图号')
machining_drawings = fields.Binary('2D加工图纸', related='production_id.part_drawing', readonly=True)
quality_standard = fields.Binary('质检标准', related='production_id.quality_standard', readonly=True)
# 工序状态
process_state = fields.Selection([
('待装夹', '待装夹'),

View File

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

View File

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

View File

@@ -98,9 +98,11 @@
<field name="production_line_id" readonly="1"/>
<!-- <field name="production_line_state" readonly="1"/>-->
<field name="part_number" string="成品的零件图号"/>
<field name="part_drawing"/>
<field name="part_drawing" widget="adaptive_viewer"/>
<field name="quality_standard" widget="adaptive_viewer"/>
<field name="tool_state"/>
<field name="tool_state_remark" string="备注" attrs="{'invisible': [('tool_state', '!=', '1')]}"/>
<field name="deadline_of_delivery" readonly="1"/>
<field name="tool_state_remark2" invisible="1"/>
</xpath>
<xpath expr="//header//button[@name='action_cancel']" position="replace">

View File

@@ -268,6 +268,8 @@
<field name="material_height" class="o_address_zip"/>
</div>
<field name="part_number" string="成品的零件图号"/>
<field name="machining_drawings" widget="adaptive_viewer" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
<field name="quality_standard" widget="adaptive_viewer" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
</xpath>
<xpath expr="//label[1]" position="attributes">
<attribute name="string">计划加工时间</attribute>

View File

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

View File

@@ -1,3 +1,4 @@
import logging
import re
from odoo import models, fields, api, _
from urllib.parse import urlencode
@@ -40,9 +41,10 @@ class SFMessageStockPicking(models.Model):
('picking_type_id.sequence_code', '=', 'OUT')])
if stock_picking_out and len(stock_picking_out) > 0:
content = message_queue_id.message_template_id.content
url = self.request_url()
url = self.request_url1(stock_picking_out.id)
content = content.replace('{{name}}', stock_picking_out.name).replace(
'{{sale_order_name}}', stock_picking_out.origin).replace('{{request_url}}', url)
logging.info('订单发货提醒: %s' % content)
return content
def _get_message(self, message_queue_ids):
@@ -96,3 +98,16 @@ class SFMessageStockPicking(models.Model):
# 拼接URL
full_url = url + "/web#" + query_string
return full_url
def request_url1(self, id):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('stock.action_picking_tree_all').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id
# 查询参数
params = {'id': id, 'menu_id': menu_id, 'action': action_id, 'model': 'stock.picking',
'view_type': 'form'}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + query_string
return full_url

View File

@@ -12,7 +12,7 @@ class SFMessageWork(models.Model):
_name = 'mrp.workorder'
_inherit = ['mrp.workorder', 'jikimo.message.dispatch']
@api.depends('production_availability', 'blocked_by_workorder_ids.state')
@api.depends('production_availability', 'blocked_by_workorder_ids.state', 'production_id.tool_state')
def _compute_state(self):
super(SFMessageWork, self)._compute_state()
for workorder in self:
@@ -154,6 +154,6 @@ class SFMessageWork(models.Model):
getattr(item, queue_method_name)(*args)
def _recover_time_warning_func(self):
workorder_done = self.env['mrp.workorder'].search([("state", "=", "done")])
workorder_done = self.env['mrp.workorder'].search([("state", "in", ["done", "rework", "cancel"])])
workorder_overdue = workorder_done.filtered(lambda x: x.delivery_warning in ['overdue', 'warning'])
workorder_overdue.write({'delivery_warning': 'normal'})

View File

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

View File

@@ -118,6 +118,8 @@
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="replace">
<field name="name" widget="section_and_note_text" optional="show"
string="参数说明(长/宽/高/体积/精度/材质)"/>
<field name="is_incoming_material" optional="hide"/>
<field name="incoming_size" optional="hide"/>
</xpath>
<field name="user_id" position="attributes">
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
@@ -162,6 +164,11 @@
<xpath expr="//button[@name='action_cancel']" position="attributes">
<attribute name="string">拒绝接单</attribute>
</xpath>
<!--新增带料字段-->
<xpath expr="//field[@name='order_line']/form//group//group//field[@name='analytic_distribution']" position="after">
<field name="is_incoming_material"/>
<field name="incoming_size" attrs="{'invisible': [('is_incoming_material', '=', False)],'readonly':1}"/>
</xpath>
</field>
</record>
@@ -265,7 +272,6 @@
</field>
</field>
</record>
<record id="sale.product_template_action" model="ir.actions.act_window">
<field name="context">{"search_default_categ_id":1,
"search_default_filter_to_sell":1,"sale_multi_pricelist_product_template": 1}

View File

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