Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/销售订单和工单逾期消息推送

# Conflicts:
#	sf_message/__manifest__.py
#	sf_message/data/bussiness_node.xml
This commit is contained in:
jinling.yang
2024-09-27 09:11:56 +08:00
32 changed files with 739 additions and 273 deletions

View File

@@ -6,6 +6,6 @@ import { patch } from "web.utils";
patch(WebClient.prototype, "kolpolok_custom_title_and_favicon.WebClient", { patch(WebClient.prototype, "kolpolok_custom_title_and_favicon.WebClient", {
setup() { setup() {
this._super(); this._super();
this.title.setParts({ zopenerp: "JIKIMO" }); // this.title.setParts({ zopenerp: "JIKIMO" });
}, },
}); });

View File

@@ -38,7 +38,7 @@ class ToolMaterialsBasicParameters(models.Model):
width = fields.Float('宽度(mm)') width = fields.Float('宽度(mm)')
cutting_blade_length = fields.Float('切削刃长(mm)') cutting_blade_length = fields.Float('切削刃长(mm)')
relief_angle = fields.Integer('后角(°)') relief_angle = fields.Integer('后角(°)')
blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20) blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20,default='0')
inscribed_circle_diameter = fields.Float('内接圆直径IC/D(mm)') inscribed_circle_diameter = fields.Float('内接圆直径IC/D(mm)')
install_aperture_diameter = fields.Float('安装孔直径(mm)') install_aperture_diameter = fields.Float('安装孔直径(mm)')
chip_breaker_groove = fields.Selection([('', ''), ('单面', '单面'), ('双面', '双面')], chip_breaker_groove = fields.Selection([('', ''), ('单面', '单面'), ('双面', '双面')],

View File

@@ -159,9 +159,6 @@ td.o_required_modifier {
display:inline; display:inline;
} }
.diameter{ .diameter{
display: flex !important;
justify-content: flex-start !important;
align-items: center !important;
} }
.o_address_format { .o_address_format {
display: flex !important; display: flex !important;

View File

@@ -55,8 +55,7 @@ class StatusChange(models.Model):
logging.info('接口已经执行=============') logging.info('接口已经执行=============')
else: else:
traceback_error = traceback.format_exc() traceback_error = traceback.format_exc()
logging.error("bfm订单状态同步失败:%s request info %s" % traceback_error) logging.error("bfm订单状态同步失败:%s" % traceback_error)
logging.error('/api/get/state/get_order 请求失败{}'.format(ret))
raise UserError('工厂加工同步订单状态到bfm失败') raise UserError('工厂加工同步订单状态到bfm失败')
except UserError as e: except UserError as e:
traceback_error = traceback.format_exc() traceback_error = traceback.format_exc()

View File

@@ -11,7 +11,6 @@
'data': [ 'data': [
'views/hr_employee.xml', 'views/hr_employee.xml',
'views/res_config_settings_views.xml', 'views/res_config_settings_views.xml',
'views/res_users_view.xml',
'data/cron_data.xml', 'data/cron_data.xml',
], ],
'demo': [ 'demo': [

View File

@@ -2,4 +2,3 @@
from . import hr_employee from . import hr_employee
from . import res_config_setting from . import res_config_setting
from . import res_users

View File

@@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
import logging
_logger = logging.getLogger(__name__)
class ResUsers(models.Model):
_inherit = 'res.users'
we_employee_id = fields.Char(string=u'企业微信账号', default="")

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_users_account_form" model="ir.ui.view">
<field name="name">res.users.account.form</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<page name="preferences" position="after">
<page name="account" string="企业微信">
<group>
<field name="we_employee_id"/>
</group>
</page>
</page>
</field>
</record>
</data>
</odoo>

View File

@@ -231,6 +231,95 @@ class Sf_Dashboard_Connect(http.Controller):
res['message'] = '前端请求日志数据失败,原因:%s' % e res['message'] = '前端请求日志数据失败,原因:%s' % e
return json.dumps(res) return json.dumps(res)
@http.route('/api/logs/page_data', type='http', auth='public', methods=['GET', 'POST'],
csrf=False, cors="*")
def logs_page_data(self, **kw):
"""
拿到日志数据返回给大屏展示(支持时间戳分页)
:param kw:
:return:
"""
res = {'status': 1, 'message': '成功', 'data': {}}
logging.info('前端请求日志数据的参数为:%s' % kw)
try:
# 连接数据库
conn = psycopg2.connect(**db_config)
cur = conn.cursor()
# 获取并解析传递的参数
machine_list = ast.literal_eval(kw.get('machine_list', '[]'))
begin_time_str = kw.get('begin_time', '').strip('"')
end_time_str = kw.get('end_time', '').strip('"')
page = int(kw.get('page', 1)) # 默认页码为1
page_size = int(kw.get('page_size', 80)) # 默认每页条数为10
begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
# 计算分页的 offset
offset = (page - 1) * page_size
# 先查询符合条件的总记录数
total_records = 0
for item in machine_list:
count_sql = '''
SELECT COUNT(*)
FROM device_data
WHERE device_name = %s AND time >= %s AND time <= %s;
'''
# 执行总记录数查询
cur.execute(count_sql, (item, begin_time, end_time))
record_count = cur.fetchone()[0] # 获取总记录数
total_records += record_count
# 计算总页数
if total_records > 0:
total_pages = (total_records + page_size - 1) // page_size # 向上取整
else:
total_pages = 0
# 将总页数和总记录数返回到响应中
res['total_records'] = total_records
res['total_pages'] = total_pages
for item in machine_list:
sql = '''
SELECT time, device_state, program_name
FROM device_data
WHERE device_name = %s AND time >= %s AND time <= %s
ORDER BY time DESC
LIMIT %s OFFSET %s;
'''
# 执行SQL命令使用参数绑定
cur.execute(sql, (item, begin_time, end_time, page_size, offset))
results = cur.fetchall()
# 将数据按照 equipment_code 进行分组
if item not in res['data']:
res['data'][item] = []
for result in results:
res['data'][item].append({
'time': result[0].strftime('%Y-%m-%d %H:%M:%S'),
'state': result[1],
'production_name': result[2],
})
return json.dumps(res) # 返回分页数据
except Exception as e:
logging.info('前端请求日志数据失败,原因:%s' % e)
res['status'] = -1
res['message'] = '前端请求日志数据失败,原因:%s' % e
return json.dumps(res)
finally:
if cur:
cur.close()
if conn:
conn.close()
# 返回CNC机床列表 # 返回CNC机床列表
@http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False, @http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
cors="*") cors="*")
@@ -378,7 +467,8 @@ class Sf_Dashboard_Connect(http.Controller):
pass_rate = 1 pass_rate = 1
if pass_nums: if pass_nums:
pass_rate = round( pass_rate = round(
(len(pass_nums) / detection_data if len(plan_data_finish_orders) > 0 else 0), 3) # (len(pass_nums) / detection_data if len(plan_data_finish_orders) > 0 else 0), 3)
(len(pass_nums) / len(plan_data_finish_orders) if len(plan_data_finish_orders) > 0 else 0), 3)
# 返工率 # 返工率
rework_rate = round( rework_rate = round(
@@ -418,8 +508,9 @@ class Sf_Dashboard_Connect(http.Controller):
'plan_data_progress_deviation': plan_data_progress_deviation, 'plan_data_progress_deviation': plan_data_progress_deviation,
'plan_data_rework_counts': plan_data_rework_counts, 'plan_data_rework_counts': plan_data_rework_counts,
'on_time_rate': on_time_rate, 'on_time_rate': on_time_rate,
'detection_data': detection_data, # 'detection_data': detection_data,
'pass_rate': pass_rate 'detection_data': plan_data_finish_counts,
'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts
} }
res['data'][line] = data res['data'][line] = data
@@ -718,7 +809,8 @@ class Sf_Dashboard_Connect(http.Controller):
'material': material, 'material': material,
'dimensions': dimensions, 'dimensions': dimensions,
'order_qty': finish_order.product_qty, 'order_qty': finish_order.product_qty,
'finish_time': finish_order.actual_end_time.strftime('%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' ' 'finish_time': finish_order.actual_end_time.strftime(
'%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' '
} }
done_data.append(line_dict) done_data.append(line_dict)
@@ -802,54 +894,27 @@ class Sf_Dashboard_Connect(http.Controller):
""" """
查询设备的异常情况 查询设备的异常情况
""" """
res = {'status': 1, 'message': '成功', 'data': {}} res = {'status': 1, 'message': '成功', 'data': []}
logging.info('前端请求机床数据的参数为:%s' % kw) logging.info('前端请求机床数据的参数为:%s' % kw)
# 连接数据库
conn = psycopg2.connect(**db_config)
cur = conn.cursor()
try: try:
# 获取请求的机床数据 maintenance_logs_obj = request.env['sf.maintenance.logs'].sudo()
# # 获取请求的机床数据
# machine_list = ast.literal_eval(kw['machine_list']) # machine_list = ast.literal_eval(kw['machine_list'])
# idle_times = []
# idle_dict = {}
# for item in machine_list: # for item in machine_list:
sql = ''' # machine_data = equipment_obj.search([('code', '=', item)])
SELECT DISTINCT ON (alarm_time) alarm_time, alarm_message, system_date, system_time, alarm_repair_time for log in maintenance_logs_obj.search([]):
FROM device_data res['data'].append({
WHERE alarm_time IS NOT NULL 'name': log.name,
ORDER BY alarm_time, time; 'alarm_time': log.alarm_time.strftime('%Y-%m-%d %H:%M:%S'),
'fault_alarm_info': log.fault_alarm_info if log.fault_alarm_info else ' ',
'fault_process': log.fault_process if log.fault_process else ' ',
})
'''
# 执行SQL命令
cur.execute(sql)
result = cur.fetchall()
# print('result', result)
# 将查询结果转换为字典列表
data = []
for row in result:
record = {
'alarm_time': row[0],
'alarm_message': row[1],
'system_date': row[2],
'system_time': row[3],
'alarm_repair_time': row[4]
}
data.append(record)
# 将数据填充到返回结果中
res['data'] = data
# 返回统计结果
return json.dumps(res, ensure_ascii=False)
except Exception as e: except Exception as e:
print(f"An error occurred: {e}") logging.error(f"An error occurred: {e}")
return json.dumps(res)
finally: return json.dumps(res)
cur.close()
conn.close()
# 设备oee # 设备oee
@http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") @http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
@@ -1166,6 +1231,7 @@ class Sf_Dashboard_Connect(http.Controller):
conn = psycopg2.connect(**db_config) conn = psycopg2.connect(**db_config)
# 获取请求的机床数据 # 获取请求的机床数据
machine_list = ast.literal_eval(kw['machine_list']) machine_list = ast.literal_eval(kw['machine_list'])
time_threshold = datetime.now() - timedelta(days=1)
def fetch_result_as_dict(cursor): def fetch_result_as_dict(cursor):
"""辅助函数:将查询结果转为字典""" """辅助函数:将查询结果转为字典"""
@@ -1175,18 +1241,29 @@ class Sf_Dashboard_Connect(http.Controller):
for item in machine_list: for item in machine_list:
with conn.cursor() as cur: with conn.cursor() as cur:
cur.execute(""" cur.execute("""
SELECT * FROM device_data SELECT * FROM device_data
WHERE device_name = %s WHERE device_name = %s
AND device_state != '离线' AND device_state != '离线'
ORDER BY time DESC ORDER BY time DESC
LIMIT 1; LIMIT 1;
""", (item,)) """, (item,))
last_all_time = fetch_result_as_dict(cur) last_all_time = fetch_result_as_dict(cur)
with conn.cursor() as cur:
cur.execute("""
SELECT * FROM device_data
WHERE device_name = %s
AND device_state != '离线' AND time >= %s
ORDER BY time ASC
LIMIT 1;
""", (item, time_threshold))
last_24_time = fetch_result_as_dict(cur)
# 返回数据 # 返回数据
res['data'][item] = { res['data'][item] = {
'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0, 'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0,
'cut_time': last_all_time['process_time'] if last_all_time['process_time'] is not None else 0, 'cut_time': last_all_time['process_time'] if last_all_time['process_time'] is not None else 0,
'power_on_time': last_all_time['power_on_time'] if last_all_time['power_on_time'] is not None else 0 'cut_24_time': last_24_time['process_time'] if last_24_time['process_time'] is not None else 0,
'power_on_time': last_all_time['power_on_time'] if last_all_time['power_on_time'] is not None else 0,
'power_on_24_time': last_24_time['power_on_time'] if last_24_time['power_on_time'] is not None else 0
} }
conn.close() conn.close()

View File

@@ -1,13 +1,14 @@
# -*-coding:utf-8-*- # -*-coding:utf-8-*-
from odoo import fields, models from odoo import fields, models, api
class SfMaintenanceLogs(models.Model): class SfMaintenanceLogs(models.Model):
_name = 'sf.maintenance.logs' _name = 'sf.maintenance.logs'
_description = '设备故障日志' _description = '设备故障日志'
_order = 'alarm_time desc'
code = fields.Char(string='编码') code = fields.Char(string='编码', readonly=True)
name = fields.Char(string='名称') name = fields.Char(string='名称', compute='_compute_name')
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='机台号')
@@ -28,3 +29,13 @@ class SfMaintenanceLogs(models.Model):
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)
@api.depends('code')
def _compute_name(self):
for record in self:
if record.code:
record.name = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).name
record.maintenance_equipment_id = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).id
else:
record.name = ''

View File

@@ -66,11 +66,14 @@ class SfMaintenanceEquipmentOEE(models.Model):
if result['status'] == 1: if result['status'] == 1:
logs_list = result['data'][self.equipment_code] logs_list = result['data'][self.equipment_code]
logs_detail = '' logs_detail = ''
log_state = ''
for log in logs_list: for log in logs_list:
print('loooooooooooooooooooogs', log) if log['state'] != log_state:
production_name = log['production_name'] if log['production_name'] else ' ' print('loooooooooooooooooooogs', log)
logs_detail += '<tr><td>' + log['time'] + '</td><td>' + log[ production_name = log['production_name'] if log['production_name'] else ' '
'state'] + '</td><td>' + production_name + '</td></tr>' logs_detail += '<tr><td>' + log['time'] + '</td><td>' + log[
'state'] + '</td><td>' + production_name + '</td></tr>'
log_state = log['state']
# self.day_logs_detail = '<table><tr><th>时间</th><th>事件/状态</th><th>加工工单</th></tr>' + logs_detail + '</table>' # self.day_logs_detail = '<table><tr><th>时间</th><th>事件/状态</th><th>加工工单</th></tr>' + logs_detail + '</table>'
self.day_logs_detail = ''' self.day_logs_detail = '''
<table border="1" style="border-collapse: collapse; width: 100%; text-align: center;"> <table border="1" style="border-collapse: collapse; width: 100%; text-align: center;">
@@ -119,10 +122,13 @@ class SfMaintenanceEquipmentOEE(models.Model):
if result['status'] == 1: if result['status'] == 1:
logs_list = result['data'][self.equipment_code] logs_list = result['data'][self.equipment_code]
logs_detail = '' logs_detail = ''
log_state = ''
for log in logs_list: for log in logs_list:
production_name = log['production_name'] if log['production_name'] else ' ' if log['state'] != log_state:
logs_detail += '<tr><td>' + log['time'] + '</td><td>' + log[ production_name = log['production_name'] if log['production_name'] else ' '
'state'] + '</td><td>' + production_name + '</td></tr>' logs_detail += '<tr><td>' + log['time'] + '</td><td>' + log[
'state'] + '</td><td>' + production_name + '</td></tr>'
log_state = log['state']
# self.day_logs_detail = '<table><tr><th>时间</th><th>事件/状态</th><th>加工工单</th></tr>' + logs_detail + '</table>' # self.day_logs_detail = '<table><tr><th>时间</th><th>事件/状态</th><th>加工工单</th></tr>' + logs_detail + '</table>'
self.history_logs_detail = ''' self.history_logs_detail = '''
<table border="1" style="border-collapse: collapse; width: 100%; text-align: center;"> <table border="1" style="border-collapse: collapse; width: 100%; text-align: center;">

View File

@@ -55,7 +55,31 @@
<group> <group>
<button name="get_day_logs" type="object" string="查看24H日志" t-attf-style="white-space:nowrap;"/> <button name="get_day_logs" type="object" string="查看24H日志" t-attf-style="white-space:nowrap;"/>
</group> </group>
<field name="day_logs_detail"/> <field name="day_logs_detail" readonly="1" widget="html"/>
<!-- <field name="page_num"/> -->
<!-- <group> -->
<!-- <group> -->
<!-- <button name="previous_day_logs" type="object" string="上一页" t-attf-style="white-space:nowrap;"/> -->
<!-- </group> -->
<!-- <group> -->
<!-- <button name="next_day_logs" type="object" string="下一页" t-attf-style="white-space:nowrap;"/> -->
<!-- </group> -->
<!-- </group> -->
<!-- <field name="day_logs_detail"/> -->
<!-- <field name="day_logs_detail" widget="html" nolabel="1"/> -->
<!-- <field name="day_logs_detail" widget="html" nolabel="1" class="oe_form_field oe_form_field_html"/> -->
<!-- <field name="day_logs_detail" widget="html" nolabel="1" class="oe_form_field oe_form_field_html" options='{"class": "o_form_readonly"}'/> -->
<!-- <field name="day_logs_detail" widget="html" nolabel="1" class="oe_form_field oe_form_field_html" options='{"class": "o_form_readonly", "readonly": true, "style": "width: 100%; height: 400px;"}'/> -->
<!-- <group> -->
<!-- <div class="oe_html_field"> -->
<!-- <div id="pagination_day_logs"> -->
<!-- <button id="prev_page_day_logs" disabled="true">Previous</button> -->
<!-- <button id="next_page_day_logs">Next</button> -->
<!-- </div> -->
<!-- </div> -->
<!-- </group> -->
</page> </page>
<page string="历史日志详情"> <page string="历史日志详情">
<group> <group>

View File

@@ -8,8 +8,8 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="type" optional="hide"/> <field name="type" optional="hide"/>
<field name="brand"/> <!-- <field name="brand"/> -->
<field name="maintenance_equipment_id"/> <field name="name"/>
<field name="code_location" optional="hide"/> <field name="code_location" optional="hide"/>
<field name="fault_code" optional="hide"/> <field name="fault_code" optional="hide"/>
<field name="alarm_time"/> <field name="alarm_time"/>
@@ -37,13 +37,14 @@
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<h1> <h1>
<field name="code" readonly="1"/> <field name="name" readonly="1"/>
</h1> </h1>
</div> </div>
<group> <group>
<group> <group>
<!-- <field name="name"/> -->
<field name="code"/>
<!-- <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="maintenance_equipment_id"/>
<field name="brand"/> <field name="brand"/>
@@ -57,7 +58,6 @@
</group> </group>
<group> <group>
<field name="operator"/> <field name="operator"/>
<field name="fault_process"/> <field name="fault_process"/>
<!-- <field name="alarm_way" required="1" widget="radio" options="{'horizontal': true}"/> --> <!-- <field name="alarm_way" required="1" widget="radio" options="{'horizontal': true}"/> -->
<field name="recovery_time"/> <field name="recovery_time"/>

View File

@@ -156,17 +156,26 @@ class AgvScheduling(models.Model):
if agv_site_state == '空闲': if agv_site_state == '空闲':
# 查询终点接驳站为agv_site_id的AGV路线 # 查询终点接驳站为agv_site_id的AGV路线
task_routes = self.env['sf.agv.task.route'].sudo().search([('end_site_id', '=', agv_site_id)]) task_routes = self.env['sf.agv.task.route'].sudo().search([('end_site_id', '=', agv_site_id)])
agv_scheduling = self.env['sf.agv.scheduling'].sudo().search( agv_schedulings = self.env['sf.agv.scheduling'].sudo().search(
[('state', '=', '待下发'), ('agv_route_type', 'in', task_routes.mapped('route_type'))], [('state', '=', '待下发'), ('agv_route_type', 'in', task_routes.mapped('route_type'))],
order='id asc', order='id asc',
limit=1
) )
task_route = task_routes.filtered( for agv_scheduling in agv_schedulings:
lambda r: r.start_site_id == agv_scheduling.start_site_id and r.start_site_id == agv_scheduling.start_site_id # 找到所有起点接驳站匹配的路线
) start_matched_task_routes = task_routes.filtered(
if task_route: lambda r: r.start_site_id == agv_scheduling.start_site_id
# 下发AGV调度任务并修改接驳站状态为占用 )
agv_scheduling.dispatch_scheduling(task_route) # 如果调度任务有终点接驳站,找到终点接驳站匹配的路线
if agv_scheduling.end_site_id:
matched_task_routes = start_matched_task_routes.filtered(
lambda r: r.end_site_id == agv_scheduling.end_site_id
)
else:
matched_task_routes = start_matched_task_routes
if matched_task_routes:
# 下发AGV调度任务并修改接驳站状态为占用
agv_scheduling.dispatch_scheduling(matched_task_routes[0])
break;
def _delivery_avg(self): def _delivery_avg(self):
config = self.env['res.config.settings'].get_values() config = self.env['res.config.settings'].get_values()

View File

@@ -990,8 +990,8 @@ class MrpProduction(models.Model):
panel_workorder.cmm_ids.sudo().unlink() panel_workorder.cmm_ids.sudo().unlink()
if panel_workorder.cnc_ids: if panel_workorder.cnc_ids:
panel_workorder.cnc_ids.sudo().unlink() panel_workorder.cnc_ids.sudo().unlink()
self.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan( # self.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
production) # production)
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test', # program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
# processing_panel) # processing_panel)
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel) logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)

View File

@@ -42,8 +42,11 @@ class ResProductMo(models.Model):
product_model_type_id = fields.Many2one('sf.model.type', string='产品模型类型') product_model_type_id = fields.Many2one('sf.model.type', string='产品模型类型')
embryo_model_type_id = fields.Many2one('sf.model.type', string='坯料模型类型') embryo_model_type_id = fields.Many2one('sf.model.type', string='坯料模型类型')
materials_id = fields.Many2one('sf.production.materials', string='材料') materials_id = fields.Many2one('sf.production.materials', string='材料')
materials_type_id = fields.Many2one('sf.materials.model', string='材料型号', # materials_type_id = fields.Many2one('sf.materials.model', string='材料型号',
# domain="[('materials_id', '=', materials_id)]")
materials_type_id = fields.Many2one(related='cutting_tool_model_id.material_model_id', string='材料型号',
domain="[('materials_id', '=', materials_id)]") domain="[('materials_id', '=', materials_id)]")
# cutting_tool_model_id.material_model_id
server_product_process_parameters_id = fields.Many2one('sf.production.process.parameter', server_product_process_parameters_id = fields.Many2one('sf.production.process.parameter',
string='表面工艺参数(服务产品)') string='表面工艺参数(服务产品)')
model_process_parameters_ids = fields.Many2many('sf.production.process.parameter', 'process_parameter_rel', model_process_parameters_ids = fields.Many2many('sf.production.process.parameter', 'process_parameter_rel',
@@ -55,43 +58,102 @@ class ResProductMo(models.Model):
cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='型号名称') cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='型号名称')
specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='物料号') specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='物料号')
cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型', # cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型',
# domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
cutting_tool_type_id = fields.Many2one(related='cutting_tool_model_id.cutting_tool_type_id', string='类型',
domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]") domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
# brand_id = fields.Many2one('sf.machine.brand', '品牌')
brand_id = fields.Many2one('sf.machine.brand', '品牌') brand_id = fields.Many2one(related='cutting_tool_model_id.brand_id', string='品牌')
# cutting_tool_model_id.brand_id
tool_length = fields.Float('长度(mm)') # tool_length = fields.Float('长度(mm)')
tool_width = fields.Float('度(mm)') tool_length = fields.Float(related='specification_id.length', string='度(mm)')
# specification_id.length
# tool_width = fields.Float('宽度(mm)')
tool_width = fields.Float(related='specification_id.width', string='宽度(mm)')
# specification_id.width
tool_height = fields.Float('高度(mm)') tool_height = fields.Float('高度(mm)')
tool_thickness = fields.Float('厚度(mm)') # tool_thickness = fields.Float('厚度(mm)')
tool_weight = fields.Float('重量(kg)') tool_thickness = fields.Float(related='specification_id.thickness', string='厚度(mm)')
tool_hardness = fields.Integer('硬度(hrc)') # specification_id.thickness
coating_material = fields.Char('涂层材质') # tool_weight = fields.Float('重量(kg)')
tool_weight = fields.Float(related='specification_id.weight', string='重量(kg)')
# specification_id.weight
# tool_hardness = fields.Integer('硬度(hrc)')
tool_hardness = fields.Integer(related='cutting_tool_model_id.tool_hardness', string='硬度(hrc)')
# cutting_tool_model_id.tool_hardness
# coating_material = fields.Char('涂层材质')
coating_material = fields.Char(related='cutting_tool_model_id.coating_material', string='涂层材质')
# cutting_tool_model_id.coating_material
# 整体式刀具特有字段 # 整体式刀具特有字段
cutting_tool_total_length = fields.Float('总长度(mm)', digits=(6, 1)) # cutting_tool_total_length = fields.Float('总长度(mm)', digits=(6, 1))
cutting_tool_shank_length = fields.Float('柄部长度(mm)', digits=(6, 1)) cutting_tool_total_length = fields.Float(related='specification_id.total_length', string='长度(mm)', digits=(6, 1))
cutting_tool_blade_length = fields.Float('刃部长度(mm)') # specification_id.total_length
cutting_tool_blade_number = fields.Selection( # cutting_tool_shank_length = fields.Float('柄部长度(mm)', digits=(6, 1))
[('0', '0'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8')], cutting_tool_shank_length = fields.Float(related='specification_id.handle_length', string='柄部长度(mm)',
string='刃数(个)', default='0') digits=(6, 1))
# specification_id.handle_length
# cutting_tool_blade_length = fields.Float('刃部长度(mm)')
cutting_tool_blade_length = fields.Float(related='specification_id.blade_length', string='刃部长度(mm)')
# specification_id.blade_length
# cutting_tool_blade_number = fields.Selection(
# [('0', '0'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8')],
# string='刃数(个)', default='0')
cutting_tool_blade_number = fields.Selection(related='specification_id.blade_number', string='刃数(个)')
# specification_id.blade_number
# 整体式刀具新增字段 # 整体式刀具新增字段
cutting_tool_neck_length = fields.Float('颈部长度(mm)', digits=(6, 1)) # cutting_tool_neck_length = fields.Float('颈部长度(mm)', digits=(6, 1))
cutting_tool_neck_diameter = fields.Float('颈部直径(mm)', digits=(6, 1)) cutting_tool_neck_length = fields.Float(related='specification_id.neck_length', string='颈部长度(mm)', digits=(6, 1))
cutting_tool_shank_diameter = fields.Float('柄部直径(mm)', digits=(6, 1)) # specification_id.neck_length
cutting_tool_blade_tip_diameter = fields.Float('刀尖直径(mm)', digits=(6, 1)) # cutting_tool_neck_diameter = fields.Float('颈部直径(mm)', digits=(6, 1))
cutting_tool_blade_tip_taper = fields.Integer('刀尖锥度(°)') cutting_tool_neck_diameter = fields.Float(related='specification_id.neck_diameter', string='颈部直径(mm)',
cutting_tool_blade_helix_angle = fields.Integer('刃部螺旋角(°)') digits=(6, 1))
cutting_tool_blade_type = fields.Char('刃部类型') # specification_id.neck_diameter
cutting_tool_pitch = fields.Float('牙距(mm)') # cutting_tool_shank_diameter = fields.Float('柄部直径(mm)', digits=(6, 1))
cutting_tool_blade_width = fields.Float('刃部宽度(mm)') cutting_tool_shank_diameter = fields.Float(related='specification_id.handle_diameter', string='柄部直径(mm)', digits=(6, 1))
cutting_tool_blade_depth = fields.Float('刃部深度(mm)') # specification_id.handle_diameter
# cutting_tool_blade_tip_diameter = fields.Float('刀尖直径(mm)', digits=(6, 1))
cutting_tool_blade_tip_diameter = fields.Float(related='specification_id.blade_tip_diameter', string='刀尖直径(mm)',
digits=(6, 1))
# specification_id.blade_tip_diameter
# cutting_tool_blade_tip_taper = fields.Integer('刀尖锥度(°)')
cutting_tool_blade_tip_taper = fields.Integer(related='specification_id.blade_tip_taper', string='刀尖锥度(°)')
# specification_id.blade_tip_taper
# cutting_tool_blade_helix_angle = fields.Integer('刃部螺旋角(°)')
cutting_tool_blade_helix_angle = fields.Integer(related='specification_id.blade_helix_angle', string='刃部螺旋角(°)')
# specification_id.blade_helix_angle
# cutting_tool_blade_type = fields.Char('刃部类型')
cutting_tool_blade_type = fields.Char(related='cutting_tool_model_id.blade_type', string='刃部类型')
# cutting_tool_pitch = fields.Float('牙距(mm)')
cutting_tool_pitch = fields.Float(related='specification_id.pitch', string='牙距(mm)')
# specification_id.pitch
# cutting_tool_blade_width = fields.Float('刃部宽度(mm)')
cutting_tool_blade_width = fields.Float(related='specification_id.blade_width', string='刃部宽度(mm)')
# specification_id.blade_width
# cutting_tool_blade_depth = fields.Float('刃部深度(mm)')
cutting_tool_blade_depth = fields.Float(related='specification_id.blade_depth', string='刃部深度(mm)')
# specification_id.blade_depth
cutting_tool_cut_depth = fields.Float('切削深度(mm)') cutting_tool_cut_depth = fields.Float('切削深度(mm)')
cutting_tool_cut_depth_max = fields.Float('最大切削深度(mm)') # cutting_tool_cut_depth_max = fields.Float('最大切削深度(mm)')
cutting_tool_coarse_medium_fine = fields.Selection([('', ''), ('', ''), ('', '')], '粗/中/精') cutting_tool_cut_depth_max = fields.Float(related='specification_id.cut_depth_max', string='最大切削深度(mm)')
cutting_tool_run_out_accuracy_max = fields.Float('端跳精度max', digits=(6, 1)) # specification_id.cut_depth_max
cutting_tool_run_out_accuracy_min = fields.Float('端跳精度min', digits=(6, 1)) # cutting_tool_coarse_medium_fine = fields.Selection([('粗', '粗'), ('中', '中'), ('精', '精')], '粗/中/精')
cutting_tool_blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20) cutting_tool_coarse_medium_fine = fields.Selection(related='cutting_tool_model_id.integral_coarse_medium_fine', string='粗/中/精')
cutting_tool_blade_tip_r_size = fields.Float('刀尖R角(mm)') # cutting_tool_model_id.integral_coarse_medium_fine
# cutting_tool_run_out_accuracy_max = fields.Float('端跳精度max', digits=(6, 1))
cutting_tool_run_out_accuracy_max = fields.Char(related='cutting_tool_model_id.integral_run_out_accuracy_max', string='端跳精度max', digits=(6, 1))
# cutting_tool_model_id.integral_run_out_accuracy_max
# cutting_tool_run_out_accuracy_min = fields.Float('端跳精度min', digits=(6, 1))
cutting_tool_run_out_accuracy_min = fields.Char(related='cutting_tool_model_id.integral_run_out_accuracy_min',
string='端跳精度min', digits=(6, 1))
# cutting_tool_model_id.integral_run_out_accuracy_min
# cutting_tool_blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20)
cutting_tool_blade_tip_working_size = fields.Char(related='specification_id.blade_tip_working_size',
string='刀尖倒角度(°)', size=20)
# specification_id.blade_tip_working_size
# cutting_tool_blade_tip_r_size = fields.Float('刀尖R角(mm)')
cutting_tool_blade_tip_r_size = fields.Float(related='specification_id.tip_r_size',
string='刀尖R角(mm)')
# specification_id.tip_r_size
fit_blade_shape_id = fields.Many2one('maintenance.equipment.image', fit_blade_shape_id = fields.Many2one('maintenance.equipment.image',
'适配刀片形状', domain=[('type', '=', '刀片形状')]) '适配刀片形状', domain=[('type', '=', '刀片形状')])
suitable_machining_method_ids = fields.Many2many('maintenance.equipment.image', suitable_machining_method_ids = fields.Many2many('maintenance.equipment.image',
@@ -429,44 +491,97 @@ class ResProductMo(models.Model):
# if not self.cutting_direction_ids: # if not self.cutting_direction_ids:
# raise ValidationError("请选择走刀方向") # raise ValidationError("请选择走刀方向")
cutting_speed_ids = fields.One2many('sf.cutting.speed', 'product_template_id', string='切削速度Vc') # cutting_speed_ids = fields.One2many('sf.cutting.speed', 'product_template_id', string='切削速度Vc')
cutting_speed_ids = fields.One2many(related='cutting_tool_model_id.cutting_speed_ids',
string='切削速度Vc')
# cutting_tool_model_id.cutting_speed_ids
feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'product_template_id', string='每齿走刀量fz') feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'product_template_id', string='每齿走刀量fz')
cutting_tool_diameter = fields.Float('刀具直径(mm)') cutting_tool_diameter = fields.Float('刀具直径(mm)')
cutting_tool_rear_angle = fields.Integer('后角(°)') # cutting_tool_rear_angle = fields.Integer('后角(°)')
cutting_tool_main_included_angle = fields.Integer('主偏角(°)') cutting_tool_rear_angle = fields.Integer(related='specification_id.relief_angle',
string='后角(°)')
# specification_id.relief_angle
# cutting_tool_main_included_angle = fields.Integer('主偏角(°)')
cutting_tool_main_included_angle = fields.Integer(related='specification_id.main_included_angle',
string='主偏角(°)')
# specification_id.main_included_angle
# 适用夹头型号可以多选 # 适用夹头型号可以多选
cutting_tool_chuck_id = fields.Many2one( cutting_tool_chuck_id = fields.Many2one(
'sf.cutting_tool.standard.library', 'sf.cutting_tool.standard.library',
domain="[('cutting_tool_type', '=', '夹头')]", domain="[('cutting_tool_type', '=', '夹头')]",
string='适用夹头型号') string='适用夹头型号')
# 刀片参数 # 刀片参数
cutting_tool_cut_blade_length = fields.Float('切削刃长(mm)') # cutting_tool_cut_blade_length = fields.Float('切削刃长(mm)')
cutting_tool_blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20) cutting_tool_cut_blade_length = fields.Float(related='specification_id.cutting_blade_length',
cutting_tool_top_angle = fields.Integer('顶角(°)') string='切削刃长(mm)')
cutting_tool_inscribed_circle_diameter = fields.Float('内接圆直径(mm)') # specification_id.cutting_blade_length
cutting_tool_install_aperture_diameter = fields.Float('安装孔直径(mm)') # cutting_tool_blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20)
cutting_tool_chip_breaker_groove = fields.Selection([('', ''), ('单面', '单面'), ('双面', '双面')], cutting_tool_blade_tip_circular_arc_radius = fields.Char(related='specification_id.blade_tip_circular_arc_radius',
string='有无断屑槽') string='刀尖圆弧半径(mm)')
cutting_tool_chip_breaker_type_code = fields.Char('断屑槽型代号') # specification_id.blade_tip_circular_arc_radius
cutting_tool_bladed_teeth_model = fields.Selection( # cutting_tool_top_angle = fields.Integer('顶角(°)')
[('', ''), ('V牙型', 'V牙型'), ('米制全牙型', '米制全牙型'), ('美制全牙型', '美制全牙型'), cutting_tool_top_angle = fields.Integer(related='specification_id.top_angle',
('惠氏全牙型', '惠氏全牙型'), ('BSPT全牙型', 'BSPT全牙型'), ('NPT全牙型', 'NPT全牙型'), string='顶角(°)')
('UNJ全牙型', 'UNJ全牙型'), ('DIN405圆牙型', 'DIN405圆牙型'), ('ACME梯形', 'ACME梯形'), # specification_id.top_angle
('石油管螺纹刀片', '石油管螺纹刀片'), ('矮牙ACME梯形', '矮牙ACME梯形'), # cutting_tool_inscribed_circle_diameter = fields.Float('内接圆直径(mm)')
('Trapeze30° 103', 'Trapeze30° 103')], string='刀片牙型', default='') cutting_tool_inscribed_circle_diameter = fields.Float(related='specification_id.inscribed_circle_diameter',
cutting_tool_blade_blade_number = fields.Selection( string='内接圆直径(mm)')
[('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), # specification_id.inscribed_circle_diameter
('7', '7'), ('8', '8'), ('9', '9'), ('10', '10')], # cutting_tool_install_aperture_diameter = fields.Float('安装孔直径(mm)')
string='刀片的刃数(个)') cutting_tool_install_aperture_diameter = fields.Float(related='specification_id.install_aperture_diameter',
string='安装孔直径(mm)')
# specification_id.install_aperture_diameter
# cutting_tool_chip_breaker_groove = fields.Selection([('无', '无'), ('单面', '单面'), ('双面', '双面')],
# string='有无断屑槽')
cutting_tool_chip_breaker_groove = fields.Selection(related='specification_id.chip_breaker_groove',
string='有无断屑槽')
# specification_id.chip_breaker_groove
# cutting_tool_chip_breaker_type_code = fields.Char('断屑槽型代号')
cutting_tool_chip_breaker_type_code = fields.Char(related='specification_id.chip_breaker_type_code',
string='断屑槽型代号')
# specification_id.chip_breaker_type_code
# cutting_tool_bladed_teeth_model = fields.Selection(
# [('无', '无'), ('V牙型', 'V牙型'), ('米制全牙型', '米制全牙型'), ('美制全牙型', '美制全牙型'),
# ('惠氏全牙型', '惠氏全牙型'), ('BSPT全牙型', 'BSPT全牙型'), ('NPT全牙型', 'NPT全牙型'),
# ('UNJ全牙型', 'UNJ全牙型'), ('DIN405圆牙型', 'DIN405圆牙型'), ('ACME梯形', 'ACME梯形'),
# ('石油管螺纹刀片', '石油管螺纹刀片'), ('矮牙ACME梯形', '矮牙ACME梯形'),
# ('Trapeze30° 103', 'Trapeze30° 103')], string='刀片牙型', default='无')
cutting_tool_bladed_teeth_model = fields.Selection(related='specification_id.blade_teeth_model',
string='断屑槽型代号')
# specification_id.blade_teeth_model
# cutting_tool_blade_blade_number = fields.Selection(
# [('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'),
# ('7', '7'), ('8', '8'), ('9', '9'), ('10', '10')],
# string='刀片的刃数(个)')
cutting_tool_blade_blade_number = fields.Selection(related='specification_id.blade_blade_number',
string='刀片的刃数(个)')
# specification_id.blade_blade_number
cutting_tool_thread_model = fields.Selection([('', ''), ('外螺纹', '外螺纹'), ('内螺纹', '内螺纹')], # cutting_tool_thread_model = fields.Selection([('无', '无'), ('外螺纹', '外螺纹'), ('内螺纹', '内螺纹')],
string='螺纹类型') # string='螺纹类型')
cutting_tool_thread_num = fields.Float('每英寸螺纹数(tpi)') cutting_tool_thread_model = fields.Selection(related='specification_id.thread_model',
cutting_tool_blade_tip_height_tolerance = fields.Char('刀尖高度公差(mm)', size=20) string='螺纹类型')
cutting_tool_inscribed_circle_tolerance = fields.Char('内接圆公差(mm)', size=20) # specification_id.thread_model
cutting_tool_thickness_tolerance = fields.Char('厚度公差(mm)', size=20) # cutting_tool_thread_num = fields.Float('每英寸螺纹数(tpi)')
cutting_tool_thread_num = fields.Float(related='specification_id.thread_num',
cutting_tool_jump_accuracy = fields.Char('径跳精度(mm)') string='每英寸螺纹数(tpi)')
# specification_id.thread_num
# cutting_tool_blade_tip_height_tolerance = fields.Char('刀尖高度公差(mm)', size=20)
cutting_tool_blade_tip_height_tolerance = fields.Char(related='specification_id.blade_tip_height_tolerance',
string='刀尖高度公差(mm)')
# specification_id.blade_tip_height_tolerance
# cutting_tool_inscribed_circle_tolerance = fields.Char('内接圆公差(mm)', size=20)
cutting_tool_inscribed_circle_tolerance = fields.Char(related='specification_id.inscribed_circle_tolerance',
string='内接圆公差(mm)')
# specification_id.inscribed_circle_tolerance
# cutting_tool_thickness_tolerance = fields.Char('厚度公差(mm)', size=20)
cutting_tool_thickness_tolerance = fields.Char(related='specification_id.thickness_tolerance',
string='厚度公差(mm)')
# specification_id.thickness_tolerance
# cutting_tool_jump_accuracy = fields.Char('径跳精度(mm)')
cutting_tool_jump_accuracy = fields.Char(related='specification_id.run_out_accuracy',
string='径跳精度(mm)')
# specification_id.run_out_accuracy
cutting_tool_working_hardness = fields.Integer('加工硬度(hrc)') cutting_tool_working_hardness = fields.Integer('加工硬度(hrc)')
cutting_tool_cutter_bar_ids = fields.Many2many( cutting_tool_cutter_bar_ids = fields.Many2many(
'sf.cutting_tool.standard.library', 'sf.cutting_tool.standard.library',
@@ -485,55 +600,153 @@ class ResProductMo(models.Model):
string='适用刀盘型号' # 使用空列表作为默认值 string='适用刀盘型号' # 使用空列表作为默认值
) )
# 刀杆/参数 # 刀杆/参数
cutting_tool_knife_head_height = fields.Float('刀头高度(mm)') # cutting_tool_knife_head_height = fields.Float('刀头高度(mm)')
cutting_tool_knife_head_width = fields.Float('刀头宽度(mm)') cutting_tool_knife_head_height = fields.Float(related='specification_id.knife_head_height',
cutting_tool_knife_head_length = fields.Float('刀头度(mm)') string='刀头度(mm)')
cutting_tool_blade_diameter = fields.Float('刃径/刃部直径(mm)') # specification_id.knife_head_height
cutting_tool_cutter_arbor_diameter = fields.Float('刀杆直径(mm)') # cutting_tool_knife_head_width = fields.Float('刀头宽度(mm)')
cutting_tool_min_machining_aperture = fields.Integer('最小加工孔径(mm)') cutting_tool_knife_head_width = fields.Float(related='specification_id.knife_head_width',
cutting_tool_install_blade_tip_num = fields.Integer('可装刀片数/齿数(个)') string='刀头宽度(mm)')
cutting_tool_installing_structure = fields.Char('安装结构', size=20) # cutting_tool_knife_head_length = fields.Float('刀头长度(mm)')
cutting_tool_blade_id = fields.Many2one( cutting_tool_knife_head_length = fields.Float(related='specification_id.knife_head_length',
'sf.cutting_tool.standard.library', string='刀头长度(mm)')
domain="[('cutting_tool_type', '=', '刀片')]", # cutting_tool_blade_diameter = fields.Float('刃径/刃部直径(mm)')
string='适用刀片型号' # 使用空列表作为默认值 cutting_tool_blade_diameter = fields.Float(related='specification_id.blade_diameter',
) string='刃径/刃部直径(mm)')
cutting_tool_tool_shim = fields.Char('适配刀垫型号', size=50) # specification_id.blade_diameter
cutting_tool_cotter_pin = fields.Char('适配销钉型号', size=50) # cutting_tool_cutter_arbor_diameter = fields.Float('刀杆直径(mm)')
cutting_tool_pressing_plate = fields.Char('适配压板型号', size=50) cutting_tool_cutter_arbor_diameter = fields.Float(related='specification_id.cutter_arbor_diameter',
cutting_tool_screw = fields.Char('适配螺钉型号', size=50) string='刀杆直径(mm)')
cutting_tool_wrench = fields.Char('适配扳手型号') # specification_id.cutter_arbor_diameter
cutting_tool_is_cooling_hole = fields.Boolean('有无冷却孔', default=False) # cutting_tool_min_machining_aperture = fields.Integer('最小加工孔径(mm)')
cutting_tool_locating_slot_code = fields.Char('定位槽代号', size=20) cutting_tool_min_machining_aperture = fields.Integer(related='specification_id.min_machining_aperture',
string='最小加工孔径(mm)')
# specification_id.min_machining_aperture
# cutting_tool_install_blade_tip_num = fields.Integer('可装刀片数/齿数(个)')
cutting_tool_install_blade_tip_num = fields.Integer(related='specification_id.install_blade_tip_num',
string='可装刀片数/齿数(个)')
# specification_id.install_blade_tip_num
# cutting_tool_installing_structure = fields.Char('安装结构', size=20)
cutting_tool_installing_structure = fields.Char(related='specification_id.installing_structure',
string='安装结构')
# specification_id.installing_structure
# cutting_tool_blade_id = fields.Many2one(
# 'sf.cutting_tool.standard.library',
# domain="[('cutting_tool_type', '=', '刀片')]",
# string='适用刀片型号' # 使用空列表作为默认值
# )
cutting_tool_blade_id = fields.Many2one(related='specification_id.blade_id',
domain="[('cutting_tool_type', '=', '刀片')]",
string='适用刀片型号')
# specification_id.blade_id
# cutting_tool_tool_shim = fields.Char('适配刀垫型号', size=50)
cutting_tool_tool_shim = fields.Char(related='specification_id.tool_shim',
string='适配刀垫型号')
# specification_id.tool_shim
# cutting_tool_cotter_pin = fields.Char('适配销钉型号', size=50)
cutting_tool_cotter_pin = fields.Char(related='specification_id.cotter_pin',
string='适配销钉型号')
# cutting_tool_pressing_plate = fields.Char('适配压板型号', size=50)
cutting_tool_pressing_plate = fields.Char(related='specification_id.pressing_plate',
string='适配压板型号')
# cutting_tool_screw = fields.Char('适配螺钉型号', size=50)
cutting_tool_screw = fields.Char(related='specification_id.screw',
string='适配螺钉型号')
# specification_id.screw
# cutting_tool_wrench = fields.Char('适配扳手型号')
cutting_tool_wrench = fields.Char(related='specification_id.spanner',
string='适配扳手型号')
# specification_id.spanner
# cutting_tool_is_cooling_hole = fields.Boolean('有无冷却孔', default=False)
cutting_tool_is_cooling_hole = fields.Boolean(related='specification_id.is_cooling_hole',
string='有无冷却孔')
# specification_id.is_cooling_hole
# cutting_tool_locating_slot_code = fields.Char('定位槽代号', size=20)
cutting_tool_locating_slot_code = fields.Char(related='specification_id.locating_slot_code',
string='定位槽代号')
# specification_id.locating_slot_code
# 刀盘参数 # 刀盘参数
cutting_tool_cutter_head_diameter = fields.Float('刀盘直径(mm)') # cutting_tool_cutter_head_diameter = fields.Float('刀盘直径(mm)')
cutting_tool_interface_diameter = fields.Float('接口直径(mm)') cutting_tool_cutter_head_diameter = fields.Float(related='specification_id.cutter_head_diameter',
string='刀盘直径(mm)')
# specification_id.cutter_head_diameter
# cutting_tool_interface_diameter = fields.Float('接口直径(mm)')
cutting_tool_interface_diameter = fields.Float(related='specification_id.interface_diameter',
string='接口直径(mm)')
# specification_id.interface_diameter
# 刀柄参数 # 刀柄参数
cutting_tool_clamping_diameter_max = fields.Float('最大夹持直径') # cutting_tool_clamping_diameter_max = fields.Float('最大夹持直径')
cutting_tool_clamping_diameter_min = fields.Float('最小夹持直径') cutting_tool_clamping_diameter_max = fields.Float(related='specification_id.max_clamping_diameter',
cutting_tool_flange_length = fields.Float('法兰柄长(mm)') string='最大夹持直径')
cutting_tool_flange_diameter = fields.Float('法兰直径(mm)') # specification_id.max_clamping_diameter
cutting_tool_is_safety_lock = fields.Boolean('有无安全锁', default=False) # cutting_tool_clamping_diameter_min = fields.Float('最小夹持直径')
cutting_tool_is_high_speed_cutting = fields.Boolean('可高速切削', default=False) cutting_tool_clamping_diameter_min = fields.Float(related='specification_id.min_clamping_diameter',
cutting_tool_change_time = fields.Integer('换刀时间(s)') string='最小夹持直径')
cutting_tool_clamping_way = fields.Char('夹持方式') # specification_id.min_clamping_diameter
cutting_tool_fit_chuck_size = fields.Char('适配夹头尺寸') # cutting_tool_flange_length = fields.Float('法兰柄长(mm)')
cutting_tool_taper_shank_model = fields.Char('锥柄型号') cutting_tool_flange_length = fields.Float(related='specification_id.flange_shank_length',
string='法兰柄长(mm)')
# cutting_tool_flange_diameter = fields.Float('法兰直径(mm)')
cutting_tool_flange_diameter = fields.Float(related='specification_id.flange_diameter',
string='法兰直径(mm)')
# cutting_tool_is_safety_lock = fields.Boolean('有无安全锁', default=False)
cutting_tool_is_safety_lock = fields.Boolean(related='specification_id.is_safe_lock',
string='有无安全锁')
# cutting_tool_is_high_speed_cutting = fields.Boolean('可高速切削', default=False)
cutting_tool_is_high_speed_cutting = fields.Boolean(related='specification_id.is_quick_cutting',
string='可高速切削')
# cutting_tool_change_time = fields.Integer('换刀时间(s)')
cutting_tool_change_time = fields.Integer(related='specification_id.tool_changing_time',
string='换刀时间(s)')
# cutting_tool_clamping_way = fields.Char('夹持方式')
cutting_tool_clamping_way = fields.Char(related='specification_id.clamping_mode',
string='夹持方式')
# cutting_tool_fit_chuck_size = fields.Char('适配夹头尺寸')
cutting_tool_fit_chuck_size = fields.Char(related='specification_id.fit_chuck_size',
string='适配夹头尺寸')
# cutting_tool_taper_shank_model = fields.Char('锥柄型号')
cutting_tool_taper_shank_model = fields.Char(related='specification_id.taper_shank_model',
string='锥柄型号')
cutting_tool_standard_speed = fields.Integer('标准转速(n/min)') cutting_tool_standard_speed = fields.Integer('标准转速(n/min)')
cutting_tool_speed_max = fields.Integer('最大转速(n/min)') # cutting_tool_speed_max = fields.Integer('最大转速(n/min)')
cutting_tool_speed_max = fields.Integer(related='specification_id.max_rotate_speed',
string='最大转速(n/min)')
# specification_id.max_rotate_speed
cutting_tool_cooling_type = fields.Char('冷却类型') cutting_tool_cooling_type = fields.Char('冷却类型')
cutting_tool_dynamic_balance_class = fields.Char('动平衡等级') cutting_tool_dynamic_balance_class = fields.Char('动平衡等级')
cutting_tool_fit_nut_model = fields.Char('适用锁紧螺母型号') # cutting_tool_fit_nut_model = fields.Char('适用锁紧螺母型号')
cutting_tool_fit_nut_model = fields.Char(related='specification_id.nut',
string='适用锁紧螺母型号')
# specification_id.nut
# 夹头参数 # 夹头参数
cutting_tool_taper = fields.Integer('锥度(°)') # cutting_tool_taper = fields.Integer('锥度(°)')
cutting_tool_top_diameter = fields.Float('顶部直径') cutting_tool_taper = fields.Integer(related='specification_id.taper',
cutting_tool_outer_diameter = fields.Float('外径(mm)') string='锥度(°)')
cutting_tool_inner_diameter = fields.Float('内径(mm)') # specification_id.taper
cooling_suit_type_ids = fields.Char('适用冷却套型号') # cutting_tool_top_diameter = fields.Float('顶部直径')
cutting_tool_max_load_capacity = fields.Float('最大负载能力(kg)') cutting_tool_top_diameter = fields.Float(related='specification_id.top_diameter',
cutting_tool_er_size_model = fields.Char('尺寸型号') string='顶部直径')
# specification_id.top_diameter
# cutting_tool_outer_diameter = fields.Float('外径(mm)')
# specification_id.outer_diameter
cutting_tool_outer_diameter = fields.Float(related='specification_id.outer_diameter',
string='外径(mm)')
# cutting_tool_inner_diameter = fields.Float('内径(mm)')
cutting_tool_inner_diameter = fields.Float(related='specification_id.inner_diameter',
string='内径(mm)')
# specification_id.inner_diameter
# cooling_suit_type_ids = fields.Char('适用冷却套型号')
cooling_suit_type_ids = fields.Char(related='specification_id.cooling_jacket',
string='适用冷却套型号')
# specification_id.cooling_jacket
# cutting_tool_max_load_capacity = fields.Float('最大负载能力(kg)')
cutting_tool_max_load_capacity = fields.Float(related='specification_id.max_load_capacity',
string='最大负载能力(kg)')
# specification_id.max_load_capacity
# cutting_tool_er_size_model = fields.Char('尺寸型号')
cutting_tool_er_size_model = fields.Char(related='specification_id.er_size_model',
string='尺寸型号')
# specification_id.er_size_model
# cutting_tool_handle_ids = fields.Many2many( # cutting_tool_handle_ids = fields.Many2many(
# 'sf.cutting_tool.standard.library', # 'sf.cutting_tool.standard.library',
# relation='product_cutting_tool_library_chuck_handle_rel', # relation='product_cutting_tool_library_chuck_handle_rel',
@@ -543,11 +756,15 @@ class ResProductMo(models.Model):
# string='适用刀柄型号' # string='适用刀柄型号'
# ) # )
cutting_tool_handle_id = fields.Many2one( # cutting_tool_handle_id = fields.Many2one(
'sf.cutting_tool.standard.library', # 'sf.cutting_tool.standard.library',
domain="[('cutting_tool_type', '=', '刀柄')]", # domain="[('cutting_tool_type', '=', '刀柄')]",
string='适用刀柄型号' # string='适用刀柄型号'
) # )
cutting_tool_handle_id = fields.Many2one(related='cutting_tool_model_id.handle_id',
domain="[('cutting_tool_type', '=', '刀柄')]",
string='适用刀柄型号')
# cutting_tool_model_id.handle_id
# 注册状态 # 注册状态
register_state = fields.Selection([('未注册', '未注册'), ('已注册', '已注册'), ('注册失败', '注册失败')], register_state = fields.Selection([('未注册', '未注册'), ('已注册', '已注册'), ('注册失败', '注册失败')],

View File

@@ -48,6 +48,7 @@
<field name="name">工单已下发通知</field> <field name="name">工单已下发通知</field>
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
</record> </record>
<record id="bussiness_mrp_workorder_pre_overdue_warning" model="jikimo.message.bussiness.node"> <record id="bussiness_mrp_workorder_pre_overdue_warning" model="jikimo.message.bussiness.node">
<field name="name">装夹预调工单逾期预警</field> <field name="name">装夹预调工单逾期预警</field>
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
@@ -85,5 +86,6 @@
<field name="name">表面工艺工单已逾期</field> <field name="name">表面工艺工单已逾期</field>
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
</record> </record>
</data> </data>
</odoo> </odoo>

View File

@@ -9,10 +9,7 @@ class SFMessagefunctionalToolAssembly(models.Model):
@api.model_create_multi @api.model_create_multi
def create(self, vals): def create(self, vals):
result = super(SFMessagefunctionalToolAssembly, self).create(vals) result = super(SFMessagefunctionalToolAssembly, self).create(vals)
is_cam = False
for obj in result: for obj in result:
if obj.loading_task_source == '0' and obj.assemble_status == '0': if obj.loading_task_source == '0' and obj.assemble_status == '0':
is_cam = True obj.add_queue('功能刀具组装')
if is_cam:
self.add_queue('功能刀具组装')
return result return result

View File

@@ -8,11 +8,12 @@ class SFMessagefunctionalToolDismantle(models.Model):
@api.model @api.model
def create(self, vals): def create(self, vals):
# 判断是否为web页面创建请求
is_web_request = self.env.context.get('is_web_request', False)
result = super(SFMessagefunctionalToolDismantle, self).create(vals) result = super(SFMessagefunctionalToolDismantle, self).create(vals)
is_dismantle = False if is_web_request:
return result
for obj in result: for obj in result:
if obj.dismantle_cause in ['寿命到期报废', '崩刀报废']and obj.state=='待拆解': if obj.dismantle_cause in ['寿命到期报废', '崩刀报废'] and obj.state == '待拆解':
is_dismantle = True obj.add_queue('功能刀具寿命到期')
if is_dismantle:
self.add_queue('功能刀具寿命到期')
return result return result

View File

@@ -1,17 +1,35 @@
import logging
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from urllib.parse import urlencode
class SFMessagePurchase(models.Model): class SFMessagePurchase(models.Model):
_name = 'purchase.order' _name = 'purchase.order'
_inherit = ['purchase.order', 'jikimo.message.dispatch'] _inherit = ['purchase.order', 'jikimo.message.dispatch']
@api.model_create_multi def _get_message(self, message_queue_ids):
def create(self, vals_list): contents = []
res = super(SFMessagePurchase, self).create(vals_list) for message_queue_id in message_queue_ids:
if res: if message_queue_id.message_template_id.name == '坯料采购提醒':
try: content = message_queue_id.message_template_id.content
res.add_queue('坯料采购提醒') url = self.request_url(int(message_queue_id.res_id))
except Exception as e: purchase_order_line = self.env['purchase.order'].search([('id', '=', int(message_queue_id.res_id))])
logging.info('add_queue error:%s' % e) content = content.replace('{{name}}', purchase_order_line.name).replace(
return res '{{request_url}}', url)
contents.append(content)
return contents
def request_url(self, id):
we_config_info = self.env['we.config'].sudo().search([], limit=1)
redirect_domain = self.env['we.app'].sudo().search([('id', '=', we_config_info.odoo_app_id.id)]).redirect_domain
full_url = 'https://%s/' % redirect_domain
action_id = self.env.ref('purchase.purchase_form_action').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_website_payment')]).id
# 查询参数
params = {'id': id, 'menu_id': menu_id, 'action': action_id,
'model': 'purchase.order',
'view_type': 'form'}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = full_url + "web#" + query_string
return full_url

View File

@@ -23,6 +23,18 @@ class SFMessageSale(models.Model):
if res is True: if res is True:
try: try:
self.add_queue('确认接单') self.add_queue('确认接单')
picking_ids = self.mrp_production_ids
purchase_order_id = []
if picking_ids:
for picking_id in picking_ids:
purchase_order_ids = (
picking_id.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id |
picking_id.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id).ids
purchase_order_id.extend(purchase_order_ids)
if purchase_order_id:
purchase_order_list = self.env['purchase.order'].search([('id', 'in', purchase_order_id)])
for purchase_order_info in purchase_order_list:
purchase_order_info.add_queue('坯料采购提醒')
except Exception as e: except Exception as e:
logging.info('add_queue error:%s' % e) logging.info('add_queue error:%s' % e)
return res return res

View File

@@ -1,13 +1,67 @@
import re
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from urllib.parse import urlencode
class SFMessageStockPicking(models.Model): class SFMessageStockPicking(models.Model):
_name = 'stock.picking' _name = 'stock.picking'
_description = "库存调拨" _description = "库存调拨"
_inherit = ['stock.picking', 'jikimo.message.dispatch'] _inherit = ['stock.picking', 'jikimo.message.dispatch']
def button_validate(self): @api.model_create_multi
res = super(SFMessageStockPicking, self).button_validate() def create(self, vals):
if self.location_id.name == '进货' and self.location_dest_id.name == '刀具房': result = super(SFMessageStockPicking, self).create(vals)
self.add_queue('调拨入库') for obj in result:
return res if obj.location_id.name == '进货' and obj.location_dest_id.name == '刀具房':
obj.add_queue('调拨入库')
return result
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
def _compute_state(self):
super(SFMessageStockPicking, self)._compute_state()
for record in self:
if record.state == 'assigned' and record.check_in == 'PC':
record.add_queue('坯料发料提醒')
def _get_message(self, message_queue_ids):
contents = []
product_id = []
for message_queue_id in message_queue_ids:
i = 0
if message_queue_id.message_template_id.name == '坯料发料提醒':
content = message_queue_id.message_template_id.content
stock_picking_line = self.env['stock.picking'].search([('id', '=', int(message_queue_id.res_id))])
mrp_production_info = self.env['mrp.production'].search(
[('name', '=', stock_picking_line.origin)])
mrp_production_list = self.env['mrp.production'].search(
[('product_id', '=', mrp_production_info.product_id.id)])
for mrp_production_line in mrp_production_list:
picking_ids = mrp_production_line.picking_ids
for picking_id in picking_ids:
if picking_id.state == 'assigned' and picking_id.check_in == 'PC':
i += 1
if i > 0 and mrp_production_info.product_id.id not in product_id:
url = self.request_url()
content = content.replace('{{product_id}}', mrp_production_info.product_id.name).replace(
'{{number}}', str(i)).replace('{{request_url}}', url)
product_id.append(mrp_production_info.product_id.id)
contents.append(content)
return contents
else:
res = super(SFMessageStockPicking, self)._get_message(message_queue_id)
return res
def request_url(self):
we_config_info = self.env['we.config'].sudo().search([], limit=1)
redirect_domain = self.env['we.app'].sudo().search([('id', '=', we_config_info.odoo_app_id.id)]).redirect_domain
full_url = 'https://%s/' % redirect_domain
action_id = self.env.ref('stock.stock_picking_type_action').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id
# 查询参数
params = {'menu_id': menu_id, 'action': action_id, 'model': 'stock.picking',
'view_type': 'kanban'}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = full_url + "web#" + query_string
return full_url

View File

@@ -13,4 +13,5 @@ class SfMessageTemplate(models.Model):
res.append('sf.functional.tool.assembly') res.append('sf.functional.tool.assembly')
res.append('sf.functional.tool.dismantle') res.append('sf.functional.tool.dismantle')
res.append('purchase.order') res.append('purchase.order')
res.append('mrp.workorder')
return res return res

View File

@@ -1,6 +1,77 @@
from odoo import models, fields, api, _ from odoo import models, fields, api, _
import logging, json
import requests
from odoo.addons.sf_base.commons.common import Common
from urllib.parse import urlencode
_logger = logging.getLogger(__name__)
class SFMessageWork(models.Model): class SFMessageWork(models.Model):
_name = 'mrp.workorder' _name = 'mrp.workorder'
_inherit = ['mrp.workorder', 'jikimo.message.dispatch'] _inherit = ['mrp.workorder', 'jikimo.message.dispatch']
@api.depends('production_availability', 'blocked_by_workorder_ids.state')
def _compute_state(self):
super(SFMessageWork, self)._compute_state()
for workorder in self:
if workorder.state == 'ready' and workorder.routing_type == '装夹预调':
jikimo_message_queue = self.env['jikimo.message.queue'].sudo().search(
[('res_id', '=', workorder.id), ("message_status", "=", "pending")])
if not jikimo_message_queue:
workorder.add_queue('工单已下发通知')
def _get_message(self, message_queue_ids):
contents = []
product_id = []
for message_queue_id in message_queue_ids:
if message_queue_id.message_template_id.name == '工单已下发通知':
content = message_queue_id.message_template_id.content
mrp_workorder_line = self.env['mrp.workorder'].search([('id', '=', int(message_queue_id.res_id))])
mrp_workorder_list = self.env['mrp.workorder'].search(
[('product_id', '=', mrp_workorder_line.product_id.id), ('state', '=', 'ready'),
('routing_type', '=', '装夹预调')])
if len(mrp_workorder_list) > 0 and mrp_workorder_line.product_id.id not in product_id:
url = self.request_url()
content = content.replace('{{product_id}}', mrp_workorder_line.product_id.name).replace(
'{{number}}', str(len(mrp_workorder_list))).replace(
'{{request_url}}', url)
product_id.append(mrp_workorder_line.product_id.id)
contents.append(content)
return contents
@api.depends('cnc_ids.tool_state')
def _compute_tool_state(self):
# 将self的id与tool_state进行保存
tool_state_dict = {record.id: record.tool_state for record in self}
res = super(SFMessageWork, self)._compute_tool_state()
data = {'name': []}
for record in self:
if tool_state_dict[record.id] != '2' and record.tool_state == '2':
data['name'].append(record.production_id.programming_no)
if data['name']:
# 请求cloud接口发送微信消息推送
configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/message/invalid_tool_state'
config_url = configsettings['sf_url'] + url
data['token'] = configsettings['token']
ret = requests.post(config_url, json=data, headers=config_header)
ret = ret.json()
_logger.info('无效用刀异常消息推送接口:%s' % ret)
return res
def request_url(self):
we_config_info = self.env['we.config'].sudo().search([], limit=1)
redirect_domain = self.env['we.app'].sudo().search([('id', '=', we_config_info.odoo_app_id.id)]).redirect_domain
full_url = 'https://%s/' % redirect_domain
action_id = self.env.ref('sf_manufacturing.mrp_workorder_action_tablet').id
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_stock_dropshipping')]).id
# 查询参数
params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder',
'view_type': 'list', 'active_id': 1}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = full_url + "web#" + query_string
return full_url

View File

@@ -62,8 +62,8 @@ class Sf_Mrs_Connect(http.Controller):
if cnc_workorder_has.cnc_ids: if cnc_workorder_has.cnc_ids:
cnc_workorder_has.cmm_ids.sudo().unlink() cnc_workorder_has.cmm_ids.sudo().unlink()
cnc_workorder_has.cnc_ids.sudo().unlink() cnc_workorder_has.cnc_ids.sudo().unlink()
request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan( # request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(
production) # production)
cnc_workorder_has.write( cnc_workorder_has.write(
{'cnc_ids': cnc_workorder_has.cnc_ids.sudo()._json_cnc_processing(panel, ret), {'cnc_ids': cnc_workorder_has.cnc_ids.sudo()._json_cnc_processing(panel, ret),
'cmm_ids': cnc_workorder_has.cmm_ids.sudo()._json_cmm_program(panel, ret)}) 'cmm_ids': cnc_workorder_has.cmm_ids.sudo()._json_cmm_program(panel, ret)})

View File

@@ -175,7 +175,7 @@ class ResConfigSettings(models.TransientModel):
new_price = res_order_lines_map.get(str(index)) new_price = res_order_lines_map.get(str(index))
if order_line: if order_line:
# 修改单价 # 修改单价
order_line.write({'remark': new_price*order_line.product_uom_qty}) order_line.write({'remark': round(new_price*order_line.product_uom_qty,2)})
order_price = self.env['order.price'].sudo().search([('sale_order_id', '=',need_change_sale_order.id )]) order_price = self.env['order.price'].sudo().search([('sale_order_id', '=',need_change_sale_order.id )])
if not order_price: if not order_price:
self.env['order.price'].sudo().create({'sale_order_id':need_change_sale_order.id}) self.env['order.price'].sudo().create({'sale_order_id':need_change_sale_order.id})

View File

@@ -2676,7 +2676,8 @@ class CuttingToolBasicParameters(models.Model):
'interface_diameter': cutter_head_item['interface_diameter'], 'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'], 'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_length'], 'blade_length': cutter_head_item['blade_length'],
'cutting_depth': cutter_head_item['cutting_depth_max'], 'cutting_blade_length': cutter_head_item['cutting_blade_length'],
'cut_depth_max': cutter_head_item['cutting_depth_max'],
'main_included_angle': cutter_head_item['edge_angle'], 'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'], 'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[ 'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
@@ -2698,7 +2699,8 @@ class CuttingToolBasicParameters(models.Model):
'interface_diameter': cutter_head_item['interface_diameter'], 'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'], 'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_length'], 'blade_length': cutter_head_item['blade_length'],
'cutting_depth': cutter_head_item['cutting_depth_max'], 'cutting_blade_length': cutter_head_item['cutting_blade_length'],
'cut_depth_max': cutter_head_item['cutting_depth_max'],
'main_included_angle': cutter_head_item['edge_angle'], 'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'], 'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[ 'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
@@ -3031,7 +3033,8 @@ class CuttingToolBasicParameters(models.Model):
'interface_diameter': cutter_head_item['interface_diameter'], 'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'], 'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_length'], 'blade_length': cutter_head_item['blade_length'],
'cutting_depth': cutter_head_item['cutting_depth_max'], 'cutting_blade_length': cutter_head_item['cutting_blade_length'],
'cut_depth_max': cutter_head_item['cutting_depth_max'],
'main_included_angle': cutter_head_item['edge_angle'], 'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'], 'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[ 'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
@@ -3053,7 +3056,8 @@ class CuttingToolBasicParameters(models.Model):
'interface_diameter': cutter_head_item['interface_diameter'], 'interface_diameter': cutter_head_item['interface_diameter'],
'total_length': cutter_head_item['total_length'], 'total_length': cutter_head_item['total_length'],
'blade_length': cutter_head_item['blade_length'], 'blade_length': cutter_head_item['blade_length'],
'cutting_depth': cutter_head_item['cutting_depth_max'], 'cutting_blade_length': cutter_head_item['cutting_blade_length'],
'cut_depth_max': cutter_head_item['cutting_depth_max'],
'main_included_angle': cutter_head_item['edge_angle'], 'main_included_angle': cutter_head_item['edge_angle'],
'installing_structure': cutter_head_item['mounting_structure'], 'installing_structure': cutter_head_item['mounting_structure'],
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[ 'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[

View File

@@ -1,7 +1,4 @@
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_static_resource_datasync,sf_static_resource_datasync,model_sf_static_resource_datasync,base.group_user,1,1,1,1 access_sf_static_resource_datasync,sf_static_resource_datasync,model_sf_static_resource_datasync,base.group_user,1,1,1,1
access_order_price,order.price,model_order_price,base.group_user,1,1,1,1 access_order_price,order.price,model_order_price,sf_base.group_sale_director,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sf_static_resource_datasync sf_static_resource_datasync model_sf_static_resource_datasync base.group_user 1 1 1 1
3 access_order_price order.price model_order_price base.group_user sf_base.group_sale_director 1 1 1 1
4

View File

@@ -8,7 +8,7 @@
<menuitem sequence="22" name="销售订单bfm对比" id="menu_sale_order_bfm_price" <menuitem sequence="22" name="销售订单bfm对比" id="menu_sale_order_bfm_price"
action="order_price_tree_act" action="order_price_tree_act"
parent="sale.sale_order_menu" parent="sale.sale_order_menu"
groups="base.group_user" groups="sf_base.group_sale_director"
/> />
<record id="view_order_price_tree" model="ir.ui.view"> <record id="view_order_price_tree" model="ir.ui.view">

View File

@@ -321,9 +321,12 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
# 获取编程单号 # 获取编程单号
programming_no = cnc_processing.workorder_id.production_id.programming_no programming_no = cnc_processing.workorder_id.production_id.programming_no
if not self.env['sf.cam.work.order.program.knife.plan'].sudo().search( logging.info(f'编程单号:{programming_no}')
[('programming_no', '=', programming_no), cam_id = self.env['sf.cam.work.order.program.knife.plan'].sudo().search(
('functional_tool_name', '=', cnc_processing.cutting_tool_name)]): [('programming_no', '=', programming_no),
('functional_tool_name', '=', cnc_processing.cutting_tool_name)])
logging.info(f'CAM装刀计划{cam_id}')
if not cam_id:
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({ knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
'name': cnc_processing.workorder_id.production_id.name, 'name': cnc_processing.workorder_id.production_id.name,
'programming_no': programming_no, 'programming_no': programming_no,

View File

@@ -84,7 +84,7 @@ class jikimo_bom(models.Model):
if option.name == '整体式刀具': if option.name == '整体式刀具':
domain = ['&'] + domain + [ domain = ['&'] + domain + [
'|', '&',
# 刀具直径 # 刀具直径
('cutting_tool_blade_diameter', '=', self.tool_inventory_id.diameter), ('cutting_tool_blade_diameter', '=', self.tool_inventory_id.diameter),

View File

@@ -1046,7 +1046,7 @@
<field name="res_model">sf.functional.tool.dismantle</field> <field name="res_model">sf.functional.tool.dismantle</field>
<field name="view_mode">tree,form,search</field> <field name="view_mode">tree,form,search</field>
<field name="search_view_id" ref="sf_functional_tool_dismantle_search"/> <field name="search_view_id" ref="sf_functional_tool_dismantle_search"/>
<field name="context">{'search_default_no_dismantle_state':1}</field> <field name="context">{'search_default_no_dismantle_state':1,'is_web_request':True}</field>
</record> </record>
</data> </data>
</odoo> </odoo>