1.优化agv配置及接口:新增站点集合对象,agv车辆编号及任务单类型编号字段
2.优化rfid和工单部分需求:点完工按钮,若为工件装夹工单,完工需校验工件坯料、RFID码、前置三元定位是否填写;若未填写,页面弹出对应提示,反之则需要二次确认弹窗 3.新增最初版的快速订单:为了工厂测试下单走流程 4.工单优化:新增检测结果和是否重新生成制造订单字段
This commit is contained in:
@@ -238,7 +238,7 @@ class Manufacturing_Connect(http.Controller):
|
|||||||
workorder = request.env['mrp.workorder'].sudo().search(
|
workorder = request.env['mrp.workorder'].sudo().search(
|
||||||
[('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
|
[('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
|
||||||
if workorder:
|
if workorder:
|
||||||
workorder.test_result = ret['Quality']
|
# workorder.test_results = ret['Quality']
|
||||||
logging.info('制造订单:%s' % workorder.production_id.name)
|
logging.info('制造订单:%s' % workorder.production_id.name)
|
||||||
if 'ReportPaht' in ret:
|
if 'ReportPaht' in ret:
|
||||||
download_state = request.env['mrp.workorder'].with_user(
|
download_state = request.env['mrp.workorder'].with_user(
|
||||||
@@ -261,8 +261,7 @@ class Manufacturing_Connect(http.Controller):
|
|||||||
('picking_id', '=', stock_picking.id)])
|
('picking_id', '=', stock_picking.id)])
|
||||||
if quality_check:
|
if quality_check:
|
||||||
logging.info('质检单:%s' % quality_check.name)
|
logging.info('质检单:%s' % quality_check.name)
|
||||||
quality_check.write({'report_pdf': workorder.detection_report,
|
quality_check.write({'report_pdf': workorder.detection_report})
|
||||||
'report_result': workorder.test_result})
|
|
||||||
elif download_state == 2:
|
elif download_state == 2:
|
||||||
res = {'Succeed': False, 'ErrorCode': 205,
|
res = {'Succeed': False, 'ErrorCode': 205,
|
||||||
'Error': 'ReportPaht中的工件号与制造订单%s不匹配,请检查ReportPaht是否正确' % workorder.production_id.name}
|
'Error': 'ReportPaht中的工件号与制造订单%s不匹配,请检查ReportPaht是否正确' % workorder.production_id.name}
|
||||||
|
|||||||
@@ -96,7 +96,8 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
Y10_axis = fields.Float(default=0)
|
Y10_axis = fields.Float(default=0)
|
||||||
Z10_axis = fields.Float(default=0)
|
Z10_axis = fields.Float(default=0)
|
||||||
X_deviation_angle = fields.Integer(string="X轴偏差度", default=0)
|
X_deviation_angle = fields.Integer(string="X轴偏差度", default=0)
|
||||||
test_result = fields.Char("检测结果")
|
test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], default='合格',
|
||||||
|
string="检测结果")
|
||||||
cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序")
|
cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序")
|
||||||
cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序")
|
cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序")
|
||||||
tray_code = fields.Char(string="托盘编码")
|
tray_code = fields.Char(string="托盘编码")
|
||||||
@@ -141,6 +142,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
production_line_state = fields.Selection(related='production_id.production_line_state',
|
production_line_state = fields.Selection(related='production_id.production_line_state',
|
||||||
string='上/下产线', store=True)
|
string='上/下产线', store=True)
|
||||||
detection_report = fields.Binary('检测报告', readonly=True)
|
detection_report = fields.Binary('检测报告', readonly=True)
|
||||||
|
is_remanufacture = fields.Boolean(string='是否重新生成制造订单', default=True)
|
||||||
|
|
||||||
def get_plan_workorder(self, production_line):
|
def get_plan_workorder(self, production_line):
|
||||||
tomorrow = (date.today() + timedelta(days=+1)).strftime("%Y-%m-%d")
|
tomorrow = (date.today() + timedelta(days=+1)).strftime("%Y-%m-%d")
|
||||||
@@ -444,7 +446,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
"""
|
"""
|
||||||
重新生成制造订单或者重新生成工单
|
重新生成制造订单或者重新生成工单
|
||||||
"""
|
"""
|
||||||
if self.test_result == '报废':
|
if self.test_results == '报废':
|
||||||
values = self.env['mrp.production'].create_production1_values(self.production_id)
|
values = self.env['mrp.production'].create_production1_values(self.production_id)
|
||||||
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
|
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
|
||||||
self.production_id.company_id).create(
|
self.production_id.company_id).create(
|
||||||
@@ -476,7 +478,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
'mail.message_origin_link',
|
'mail.message_origin_link',
|
||||||
values={'self': production, 'origin': origin_production},
|
values={'self': production, 'origin': origin_production},
|
||||||
subtype_id=self.env.ref('mail.mt_note').id)
|
subtype_id=self.env.ref('mail.mt_note').id)
|
||||||
if self.test_result == '返工':
|
if self.test_results == '返工':
|
||||||
productions = self.production_id
|
productions = self.production_id
|
||||||
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
||||||
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||||
|
|||||||
@@ -106,16 +106,12 @@
|
|||||||
<field name='is_delivery' invisible="1"/>
|
<field name='is_delivery' invisible="1"/>
|
||||||
<!-- 工单form页面的开始停工按钮等 -->
|
<!-- 工单form页面的开始停工按钮等 -->
|
||||||
<button name="button_start" type="object" string="开始" class="btn-success"
|
<button name="button_start" type="object" string="开始" class="btn-success"
|
||||||
attrs="{'invisible': ['|', '|', '|', '|','|', ('production_state','in', ('draft', 'done',
|
|
||||||
'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')),
|
|
||||||
('is_user_working', '!=', False),('user_permissions','=',False), ('routing_type', '=', 'CNC加工')]}"
|
|
||||||
groups="sf_base.group_sf_mrp_user"/>
|
groups="sf_base.group_sf_mrp_user"/>
|
||||||
<button name="button_pending" type="object" string="暂停" class="btn-warning"
|
<button name="button_pending" type="object" string="暂停" class="btn-warning"
|
||||||
groups="sf_base.group_sf_mrp_user"
|
groups="sf_base.group_sf_mrp_user"/>
|
||||||
attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"/>
|
|
||||||
<button name="button_finish" type="object" string="完成" class="btn-success"
|
<button name="button_finish" type="object" string="完成" class="btn-success"
|
||||||
groups="sf_base.group_sf_mrp_user" confirm="是否确认完工"
|
groups="sf_base.group_sf_mrp_user" confirm="是否确认完工"/>
|
||||||
attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"/>
|
|
||||||
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="停工"
|
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="停工"
|
||||||
context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
|
context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
|
||||||
groups="sf_base.group_sf_mrp_user"
|
groups="sf_base.group_sf_mrp_user"
|
||||||
@@ -184,7 +180,7 @@
|
|||||||
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
||||||
<field name="functional_fixture_type_id"
|
<field name="functional_fixture_type_id"
|
||||||
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
||||||
<field name="rfid_code" readonly="1" class="customRFID"
|
<field name="rfid_code" readonly="1" class="customRFID"
|
||||||
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
|
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
|
||||||
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
|
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
|
||||||
<script src="/sf_manufacturing/static/src/js/customRFID.js"></script>
|
<script src="/sf_manufacturing/static/src/js/customRFID.js"></script>
|
||||||
@@ -437,16 +433,17 @@
|
|||||||
<field name="results" invisible="1"/>
|
<field name="results" invisible="1"/>
|
||||||
<page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
<page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||||
<group>
|
<group>
|
||||||
<field name="test_result" readonly="1" attrs='{"invisible":[("results","!=",False)]}'/>
|
<field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/>
|
||||||
|
<field name="is_remanufacture" attrs='{"invisible":[("test_results","=","合格")]}'/>
|
||||||
<field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>
|
<field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>
|
||||||
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
|
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
|
||||||
widget="pdf_viewer"/>
|
widget="pdf_viewer"/>
|
||||||
</group>
|
</group>
|
||||||
<div class="col-12 col-lg-6 o_setting_box">
|
<!-- <div class="col-12 col-lg-6 o_setting_box">-->
|
||||||
<button type="object" class="oe_highlight" name="recreateManufacturingOrWorkerOrder"
|
<!-- <button type="object" class="oe_highlight" name="recreateManufacturingOrWorkerOrder"-->
|
||||||
string="检测确认"
|
<!-- string="检测确认"-->
|
||||||
attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>
|
<!-- attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</page>
|
</page>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//page[1]" position="before">
|
<xpath expr="//page[1]" position="before">
|
||||||
|
|||||||
@@ -13,10 +13,11 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003')
|
token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003')
|
||||||
sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6')
|
sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6')
|
||||||
sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com')
|
sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com')
|
||||||
agv_rcms_url = fields.Char(string='avg_rcms访问地址',
|
agv_rcs_url = fields.Char(string='avg_rcs访问地址',
|
||||||
default='http://IP:PORT/rcms/services/rest/hikRpcService/genAgvSchedulingTask')
|
default='http://172.16.10.114:8182/rcms/services/rest/hikRpcService/genAgvSchedulingTask')
|
||||||
agv_rcs_url = fields.Char(string='avg_rcs访问地址', default='http://IP:PORT/xxx/agv/agvCallbackService/agvCallback')
|
|
||||||
wbcode = fields.Char('地码')
|
wbcode = fields.Char('地码')
|
||||||
|
agv_code = fields.Char(string='agv编号')
|
||||||
|
task_type_no = fields.Char('任务单类型编号')
|
||||||
model_parser_url = fields.Char('特征识别路径')
|
model_parser_url = fields.Char('特征识别路径')
|
||||||
ftp_host = fields.Char(string='FTP的ip')
|
ftp_host = fields.Char(string='FTP的ip')
|
||||||
ftp_port = fields.Char(string='FTP端口')
|
ftp_port = fields.Char(string='FTP端口')
|
||||||
@@ -95,8 +96,9 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
token = config.get_param('token', default='')
|
token = config.get_param('token', default='')
|
||||||
sf_secret_key = config.get_param('sf_secret_key', default='')
|
sf_secret_key = config.get_param('sf_secret_key', default='')
|
||||||
sf_url = config.get_param('sf_url', default='')
|
sf_url = config.get_param('sf_url', default='')
|
||||||
agv_rcms_url = config.get_param('agv_rcms_url', default='')
|
|
||||||
agv_rcs_url = config.get_param('agv_rcs_url', default='')
|
agv_rcs_url = config.get_param('agv_rcs_url', default='')
|
||||||
|
agv_code = config.get_param('agv_code', default='')
|
||||||
|
task_type_no = config.get_param('task_type_no', default='')
|
||||||
ftp_host = config.get_param('ftp_host', default='')
|
ftp_host = config.get_param('ftp_host', default='')
|
||||||
ftp_port = config.get_param('ftp_port', default='')
|
ftp_port = config.get_param('ftp_port', default='')
|
||||||
ftp_user = config.get_param('ftp_user', default='')
|
ftp_user = config.get_param('ftp_user', default='')
|
||||||
@@ -106,8 +108,9 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
token=token,
|
token=token,
|
||||||
sf_secret_key=sf_secret_key,
|
sf_secret_key=sf_secret_key,
|
||||||
sf_url=sf_url,
|
sf_url=sf_url,
|
||||||
agv_rcms_url=agv_rcms_url,
|
|
||||||
agv_rcs_url=agv_rcs_url,
|
agv_rcs_url=agv_rcs_url,
|
||||||
|
agv_code=agv_code,
|
||||||
|
task_type_no=task_type_no,
|
||||||
ftp_host=ftp_host,
|
ftp_host=ftp_host,
|
||||||
ftp_port=ftp_port,
|
ftp_port=ftp_port,
|
||||||
ftp_user=ftp_user,
|
ftp_user=ftp_user,
|
||||||
@@ -121,9 +124,18 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
ir_config.set_param("token", self.token or "")
|
ir_config.set_param("token", self.token or "")
|
||||||
ir_config.set_param("sf_secret_key", self.sf_secret_key or "")
|
ir_config.set_param("sf_secret_key", self.sf_secret_key or "")
|
||||||
ir_config.set_param("sf_url", self.sf_url or "")
|
ir_config.set_param("sf_url", self.sf_url or "")
|
||||||
ir_config.set_param("agv_rcms_url", self.agv_rcms_url or "")
|
|
||||||
ir_config.set_param("agv_rcs_url", self.agv_rcs_url or "")
|
ir_config.set_param("agv_rcs_url", self.agv_rcs_url or "")
|
||||||
|
ir_config.set_param("agv_code", self.agv_code or "")
|
||||||
|
ir_config.set_param("task_type_no", self.task_type_no or "")
|
||||||
ir_config.set_param("ftp_host", self.ftp_host or "")
|
ir_config.set_param("ftp_host", self.ftp_host or "")
|
||||||
ir_config.set_param("ftp_port", self.ftp_port or "")
|
ir_config.set_param("ftp_port", self.ftp_port or "")
|
||||||
ir_config.set_param("ftp_user", self.ftp_user or "")
|
ir_config.set_param("ftp_user", self.ftp_user or "")
|
||||||
ir_config.set_param("ftp_password", self.ftp_password or "")
|
ir_config.set_param("ftp_password", self.ftp_password or "")
|
||||||
|
|
||||||
|
|
||||||
|
class ResAgvSite(models.Model):
|
||||||
|
_name = 'res.agv.site'
|
||||||
|
_description = 'agv站点'
|
||||||
|
|
||||||
|
type = fields.Selection([('00', '位置编号'), ('01', '库区编号'), ('02', '货架编号')], '类型')
|
||||||
|
content = fields.Char('内容')
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
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_res_agv_site,access_res_agv_site,model_res_agv_site,base.group_system,1,1,1,1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
|
@@ -1,6 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<data>
|
<data>
|
||||||
|
<record id="view_agv_site_tree" model="ir.ui.view">
|
||||||
|
<field name="name">agv站点集合</field>
|
||||||
|
<field name="model">res.agv.site</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree editable="bottom">
|
||||||
|
<field name="type"/>
|
||||||
|
<field name="content"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_agv_site_form" model="ir.actions.act_window">
|
||||||
|
<field name="name">站点集合</field>
|
||||||
|
<field name="res_model">res.agv.site</field>
|
||||||
|
<field name="view_mode">tree</field>
|
||||||
|
</record>
|
||||||
|
<menuitem id="menu_action_agv_site_form" action="sf_mrs_connect.action_agv_site_form" name="站点集合"
|
||||||
|
sequence="11"/>
|
||||||
|
|
||||||
|
|
||||||
<record id="res_config_settings_view_form_sf_sync" model="ir.ui.view">
|
<record id="res_config_settings_view_form_sf_sync" model="ir.ui.view">
|
||||||
<field name="name">res.config.settings.view.form.inherit.sf_sync</field>
|
<field name="name">res.config.settings.view.form.inherit.sf_sync</field>
|
||||||
<field name="model">res.config.settings</field>
|
<field name="model">res.config.settings</field>
|
||||||
@@ -84,10 +104,22 @@
|
|||||||
<label for="agv_rcs_url" string="访问地址"/>
|
<label for="agv_rcs_url" string="访问地址"/>
|
||||||
<field name="agv_rcs_url"/>
|
<field name="agv_rcs_url"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="text-muted">
|
||||||
|
<label for="task_type_no"/>
|
||||||
|
<field name="task_type_no"/>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted">
|
||||||
|
<label for="agv_code" string="车辆编号"/>
|
||||||
|
<field name="agv_code"/>
|
||||||
|
</div>
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<label for="wbcode"/>
|
<label for="wbcode"/>
|
||||||
<field name="wbcode"/>
|
<field name="wbcode"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mt8">
|
||||||
|
<button type="action" name="%(sf_mrs_connect.action_agv_site_form)d"
|
||||||
|
string="站点集合" class="btn-link" icon="fa-arrow-right"/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from . import sale_order
|
from . import sale_order
|
||||||
from . import quick_easy_order
|
# from . import quick_easy_order
|
||||||
|
from . import quick_easy_order_old
|
||||||
from . import auto_quatotion_common
|
from . import auto_quatotion_common
|
||||||
from . import parser_and_calculate_work_time
|
from . import parser_and_calculate_work_time
|
||||||
from . import preload_datas_functions
|
from . import preload_datas_functions
|
||||||
|
|||||||
326
sf_sale/models/quick_easy_order_old.py
Normal file
326
sf_sale/models/quick_easy_order_old.py
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
import logging
|
||||||
|
import base64
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
import requests
|
||||||
|
from odoo import http
|
||||||
|
from odoo.http import request
|
||||||
|
from OCC.Extend.DataExchange import read_step_file
|
||||||
|
from OCC.Extend.DataExchange import write_stl_file
|
||||||
|
from odoo import models, fields, api
|
||||||
|
from odoo.modules import get_resource_path
|
||||||
|
from odoo.exceptions import ValidationError, UserError
|
||||||
|
from odoo.addons.sf_base.commons.common import Common
|
||||||
|
from . import parser_and_calculate_work_time as pc
|
||||||
|
|
||||||
|
|
||||||
|
class QuickEasyOrder(models.Model):
|
||||||
|
_name = 'quick.easy.order'
|
||||||
|
_description = '简易下单'
|
||||||
|
_order = 'id desc'
|
||||||
|
|
||||||
|
name = fields.Char('订单编号', default=lambda self: self.env['ir.sequence'].next_by_code('quick.easy.order'))
|
||||||
|
model_length = fields.Float('长(mm)', digits=(16, 3))
|
||||||
|
model_width = fields.Float('宽(mm)', digits=(16, 3))
|
||||||
|
model_height = fields.Float('高(mm)', digits=(16, 3))
|
||||||
|
model_volume = fields.Float('体积(mm³)', digits=(16, 3))
|
||||||
|
model_processing_side = fields.Char('加工面', default='A')
|
||||||
|
model_feature = fields.Char('特征')
|
||||||
|
machining_precision = fields.Selection([
|
||||||
|
('0.10', '±0.10mm'),
|
||||||
|
('0.05', '±0.05mm'),
|
||||||
|
('0.03', '±0.03mm'),
|
||||||
|
('0.02', '±0.02mm'),
|
||||||
|
('0.01', '±0.01mm')], string='加工精度', default='0.10')
|
||||||
|
material_id = fields.Many2one('sf.production.materials', '材料')
|
||||||
|
material_model_id = fields.Many2one('sf.materials.model', '型号')
|
||||||
|
# process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||||
|
parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数')
|
||||||
|
quantity = fields.Integer('数量', default=1)
|
||||||
|
unit_price = fields.Float('单价')
|
||||||
|
price = fields.Float('总价')
|
||||||
|
model_file = fields.Binary('glb模型文件')
|
||||||
|
upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件')
|
||||||
|
delivery_time = fields.Date('交货日期')
|
||||||
|
customer_id = fields.Many2one('res.partner', string='客户', default=lambda self: self.env.user.partner_id.id)
|
||||||
|
state = fields.Selection([('草稿', '草稿'), ('待派单', '待派单'),
|
||||||
|
('待接单', '待接单'), ('加工中', '加工中'),
|
||||||
|
('物流中', '物流中'), ('已交付', '已交付')], string='订单状态', default='草稿',
|
||||||
|
readonly=True)
|
||||||
|
model_color_state = fields.Selection([
|
||||||
|
('success', '成功'),
|
||||||
|
('fail', '失败')], string='模型上色状态')
|
||||||
|
processing_time = fields.Integer('加工时长(min)')
|
||||||
|
|
||||||
|
@api.depends('unit_price', 'quantity')
|
||||||
|
def _compute_total_amount(self):
|
||||||
|
for item in self:
|
||||||
|
item.price = item.unit_price * item.quantity
|
||||||
|
|
||||||
|
@api.depends('material_id', 'material_model_id')
|
||||||
|
def _compute_material_model(self):
|
||||||
|
for item in self:
|
||||||
|
materials = self.env['sf.production.materials'].search([], limit=1, order='id desc')
|
||||||
|
item.material_id = materials.id
|
||||||
|
item.material_model_id = self.env['sf.materials.model'].search(
|
||||||
|
[('materials_id', '=', materials.id)],
|
||||||
|
limit=1, order='id desc')
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def create(self, vals):
|
||||||
|
if vals.get('upload_model_file'):
|
||||||
|
logging.info('create-attachment:%s' % vals['upload_model_file'][0])
|
||||||
|
for item in vals['upload_model_file']:
|
||||||
|
print(len(item[2]))
|
||||||
|
if len(item[2]) > 0:
|
||||||
|
logging.info('create-attachment:%s' % int(item[2][0]))
|
||||||
|
attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))])
|
||||||
|
base64_data = base64.b64encode(attachment.datas)
|
||||||
|
base64_datas = base64_data.decode('utf-8')
|
||||||
|
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||||
|
report_path = attachment._full_path(attachment.store_fname)
|
||||||
|
vals['model_file'] = self.transition_glb_file(report_path, model_code)
|
||||||
|
logging.info('create-model_file:%s' % len(vals['model_file']))
|
||||||
|
obj = super(QuickEasyOrder, self).create(vals)
|
||||||
|
self.model_coloring(obj)
|
||||||
|
logging.info('---------开始派单到工厂-------')
|
||||||
|
self.distribute_to_factory(obj)
|
||||||
|
obj.state = '待接单'
|
||||||
|
return obj
|
||||||
|
|
||||||
|
# 将attach的datas内容转为glb文件
|
||||||
|
def transition_glb_file(self, report_path, model_code):
|
||||||
|
shapes = read_step_file(report_path)
|
||||||
|
output_file = os.path.join('/tmp', str(model_code) + '.stl')
|
||||||
|
write_stl_file(shapes, output_file, 'binary', 0.03, 0.5)
|
||||||
|
# 转化为glb
|
||||||
|
output_glb_file = os.path.join('/tmp', str(model_code) + '.glb')
|
||||||
|
util_path = get_resource_path('sf_base', 'static/util')
|
||||||
|
cmd = 'python3 %s/stl2gltf.py %s %s -b' % (util_path, output_file, output_glb_file)
|
||||||
|
os.system(cmd)
|
||||||
|
# 转base64
|
||||||
|
with open(output_glb_file, 'rb') as fileObj:
|
||||||
|
image_data = fileObj.read()
|
||||||
|
base64_data = base64.b64encode(image_data)
|
||||||
|
return base64_data
|
||||||
|
|
||||||
|
# return False
|
||||||
|
|
||||||
|
@api.onchange('upload_model_file')
|
||||||
|
def onchange_model_file(self):
|
||||||
|
for item in self:
|
||||||
|
if len(item.upload_model_file) > 1:
|
||||||
|
raise ValidationError('只允许上传一个文件')
|
||||||
|
if item.upload_model_file:
|
||||||
|
file_attachment_id = item.upload_model_file[0]
|
||||||
|
# 附件路径
|
||||||
|
report_path = file_attachment_id._full_path(file_attachment_id.store_fname)
|
||||||
|
logging.info("模型路径: %s" % report_path)
|
||||||
|
base64_data = base64.b64encode(file_attachment_id.datas)
|
||||||
|
base64_datas = base64_data.decode('utf-8')
|
||||||
|
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||||
|
logging.info("模型编码: %s" % model_code)
|
||||||
|
item.model_file = self.transition_glb_file(report_path, model_code)
|
||||||
|
else:
|
||||||
|
item.model_file = False
|
||||||
|
item.model_feature = False
|
||||||
|
item.model_length = 0
|
||||||
|
item.model_width = 0
|
||||||
|
item.model_height = 0
|
||||||
|
item.model_volume = 0
|
||||||
|
|
||||||
|
def distribute_to_factory(self, obj):
|
||||||
|
"""
|
||||||
|
派单到工厂
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
logging.info('---------派单到工厂-------')
|
||||||
|
res = {'bfm_process_order_list': []}
|
||||||
|
for item in obj:
|
||||||
|
attachment = item.upload_model_file[0]
|
||||||
|
base64_data = base64.b64encode(attachment.datas)
|
||||||
|
base64_datas = base64_data.decode('utf-8')
|
||||||
|
barcode = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||||
|
# logging.info('model_file-size: %s' % len(item.model_file))
|
||||||
|
res['bfm_process_order_list'].append({
|
||||||
|
'model_long': item.model_length,
|
||||||
|
'model_width': item.model_width,
|
||||||
|
'model_height': item.model_height,
|
||||||
|
'model_volume': item.model_volume,
|
||||||
|
'model_machining_precision': item.machining_precision,
|
||||||
|
'model_name': attachment.name,
|
||||||
|
'model_data': base64_datas,
|
||||||
|
'model_file': base64.b64encode(item.model_file).decode('utf-8'),
|
||||||
|
'texture_code': item.material_id.materials_no,
|
||||||
|
'texture_type_code': item.material_model_id.materials_no,
|
||||||
|
# 'surface_process_code': self.env['jikimo.surface.process']._json_surface_process_code(item),
|
||||||
|
'process_parameters_code': self.env[
|
||||||
|
'sf.production.process.parameter']._json_production_process_item_code(
|
||||||
|
item),
|
||||||
|
'price': item.price,
|
||||||
|
'number': item.quantity,
|
||||||
|
'total_amount': item.price,
|
||||||
|
'remark': '',
|
||||||
|
'barcode': barcode
|
||||||
|
})
|
||||||
|
# res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list'])
|
||||||
|
product_id = self.env.ref('sf_dlm.product_template_sf').sudo()
|
||||||
|
self_machining_id = self.env.ref('sf_dlm.product_embryo_sf_self_machining').sudo()
|
||||||
|
outsource_id = self.env.ref('sf_dlm.product_embryo_sf_outsource').sudo()
|
||||||
|
purchase_id = self.env.ref('sf_dlm.product_embryo_sf_purchase').sudo()
|
||||||
|
company_id = self.env.ref('base.main_company').sudo()
|
||||||
|
# user_id = request.env.ref('base.user_admin').sudo()
|
||||||
|
order_id = self.env['sale.order'].sale_order_create(company_id, 'XXXXX', 'XXXXX', 'XXXXX',
|
||||||
|
str(datetime.now()), '现结', '支付宝')
|
||||||
|
i = 1
|
||||||
|
# 给sale_order的default_code字段赋值
|
||||||
|
aa = self.env['sale.order'].sudo().search([('name', '=', order_id.name)])
|
||||||
|
logging.info('---------aa------- %s' % aa.name)
|
||||||
|
aa.default_code = obj.name
|
||||||
|
for item in res['bfm_process_order_list']:
|
||||||
|
product = self.env['product.template'].sudo().product_create(product_id, item, order_id,
|
||||||
|
obj.name, i)
|
||||||
|
bom_data = self.env['mrp.bom'].get_bom(product)
|
||||||
|
logging.info('bom_data:%s' % bom_data)
|
||||||
|
if bom_data:
|
||||||
|
bom = self.env['mrp.bom'].bom_create(product, 'normal', False)
|
||||||
|
bom.bom_create_line_has(bom_data)
|
||||||
|
else:
|
||||||
|
if product.materials_type_id.gain_way == '自加工':
|
||||||
|
# 创建坯料
|
||||||
|
self_machining_embryo = self.env['product.template'].sudo().no_bom_product_create(
|
||||||
|
self_machining_id,
|
||||||
|
item, order_id,
|
||||||
|
'self_machining',
|
||||||
|
i)
|
||||||
|
# 创建坯料的bom
|
||||||
|
self_machining_bom = self.env['mrp.bom'].bom_create(self_machining_embryo, 'normal', False)
|
||||||
|
# 创建坯料里bom的组件
|
||||||
|
self_machining_bom_line = self_machining_bom.bom_create_line(self_machining_embryo)
|
||||||
|
if self_machining_bom_line is False:
|
||||||
|
self.cr.rollback()
|
||||||
|
return UserError('该订单模型的材料型号在您分配的工厂里暂未有原材料,请先配置再进行分配')
|
||||||
|
# 产品配置bom
|
||||||
|
product_bom_self_machining = self.env['mrp.bom'].bom_create(product, 'normal', False)
|
||||||
|
product_bom_self_machining.bom_create_line_has(self_machining_embryo)
|
||||||
|
elif product.materials_type_id.gain_way == '外协':
|
||||||
|
# 创建坯料
|
||||||
|
outsource_embryo = self.env['product.template'].sudo().no_bom_product_create(outsource_id, item,
|
||||||
|
order_id,
|
||||||
|
'subcontract', i)
|
||||||
|
# 创建坯料的bom
|
||||||
|
outsource_bom = self.env['mrp.bom'].bom_create(outsource_embryo, 'subcontract', True)
|
||||||
|
# 创建坯料的bom的组件
|
||||||
|
outsource_bom_line = outsource_bom.with_user(
|
||||||
|
self.env.ref("base.user_admin")).bom_create_line(outsource_embryo)
|
||||||
|
if outsource_bom_line is False:
|
||||||
|
self.cr.rollback()
|
||||||
|
return UserError('该订单模型的材料型号在您分配的工厂里暂未有原材料,请先配置再进行分配')
|
||||||
|
# 产品配置bom
|
||||||
|
product_bom_outsource = self.env['mrp.bom'].bom_create(product, 'normal', False)
|
||||||
|
product_bom_outsource.bom_create_line_has(outsource_embryo)
|
||||||
|
elif product.materials_type_id.gain_way == '采购':
|
||||||
|
purchase_embryo = self.env['product.template'].sudo().no_bom_product_create(purchase_id, item,
|
||||||
|
order_id,
|
||||||
|
'purchase', i)
|
||||||
|
# 产品配置bom
|
||||||
|
product_bom_purchase = self.env['mrp.bom'].bom_create(product, 'normal', False)
|
||||||
|
product_bom_purchase.bom_create_line_has(purchase_embryo)
|
||||||
|
order_id.with_user(self.env.ref("base.user_admin")).sale_order_create_line(product, item)
|
||||||
|
except Exception as e:
|
||||||
|
# self.cr.rollback()
|
||||||
|
return UserError('工厂创建销售订单和产品失败,请联系管理员')
|
||||||
|
|
||||||
|
# 特征识别
|
||||||
|
def feature_recognition(self, report_path, model_code):
|
||||||
|
feature_path = self.env['sf.auto_quatotion.common'].sudo().get_feature_full_path()
|
||||||
|
process_time_db_path = self.env['sf.auto_quatotion.common'].sudo().get_process_time_db_path()
|
||||||
|
ret = self.env['sf.auto_quatotion.common'].sudo().get_auto_quatotion(report_path, feature_path,
|
||||||
|
process_time_db_path,
|
||||||
|
model_code)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# 模型上色
|
||||||
|
def model_coloring(self, order):
|
||||||
|
url = '/api/library_of_models/create'
|
||||||
|
config = self.env['res.config.settings'].get_values()
|
||||||
|
config_header = Common.get_headers(self, config['token'], config['sf_secret_key'])
|
||||||
|
logging.info('order: %s' % order.name)
|
||||||
|
if order:
|
||||||
|
attachment = order.upload_model_file[0]
|
||||||
|
base64_data = base64.b64encode(attachment.datas)
|
||||||
|
base64_datas = base64_data.decode('utf-8')
|
||||||
|
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||||
|
logging.info('model_file-size: %s' % len(order.model_file))
|
||||||
|
logging.info('attachment.datas-size: %s' % len(attachment.datas))
|
||||||
|
vals = {
|
||||||
|
'model_code': model_code,
|
||||||
|
'model_data': base64_data,
|
||||||
|
'model_name': attachment.name,
|
||||||
|
'model_long': order.model_length,
|
||||||
|
'model_width': order.model_width,
|
||||||
|
'model_height': order.model_height,
|
||||||
|
'model_volume': order.model_volume,
|
||||||
|
'model_order_no': order.name,
|
||||||
|
'remark': '订单号:%s 客户:%s' % (order.name, order.customer_id.name)
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
ret = requests.post((config['sf_url'] + url), json={}, data=vals, headers=config_header,
|
||||||
|
timeout=60)
|
||||||
|
ret = ret.json()
|
||||||
|
# result = json.loads(ret['result'])
|
||||||
|
if ret['status'] == 1:
|
||||||
|
order.model_color_state = 'success'
|
||||||
|
else:
|
||||||
|
order.model_color_state = 'fail'
|
||||||
|
raise UserError(ret['message'])
|
||||||
|
except Exception as e:
|
||||||
|
order.model_color_state = 'fail'
|
||||||
|
raise UserError("模型上色失败")
|
||||||
|
|
||||||
|
# 自动报价
|
||||||
|
def _get_price(self, order):
|
||||||
|
url = '/api/automatic_quotes'
|
||||||
|
config = self.env['res.config.settings'].sudo().get_values()
|
||||||
|
config_header = Common.get_headers(self, config['token'], config['sf_secret_key'])
|
||||||
|
logging.info("报价接口..........% s" % order.name)
|
||||||
|
try:
|
||||||
|
if order:
|
||||||
|
vals = {}
|
||||||
|
# mrs合作伙伴token
|
||||||
|
vals['token'] = config['token']
|
||||||
|
vals['accuracy'] = order.machining_precision
|
||||||
|
vals['number'] = order.quantity
|
||||||
|
vals['process_code'] = 0
|
||||||
|
vals['texture_code'] = order.material_model_id.materials_no
|
||||||
|
vals['delivery_days'] = 15
|
||||||
|
if order.model_file:
|
||||||
|
for item in order.upload_model_file:
|
||||||
|
if item.ids[0]:
|
||||||
|
logging.info('create-attachment:%s' % int(item.ids[0]))
|
||||||
|
attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item.ids[0]))])
|
||||||
|
vals['attachment_id'] = attachment.id
|
||||||
|
else:
|
||||||
|
vals['attachment_id'] = ''
|
||||||
|
vals['feature_infos'] = order.model_feature
|
||||||
|
vals['model_long'] = order.model_length
|
||||||
|
vals['model_width'] = order.model_width
|
||||||
|
vals['model_height'] = order.model_height
|
||||||
|
logging.info('vals:%s' % vals)
|
||||||
|
ret = requests.post((config['sf_url'] + url), json={}, data=vals, headers=config_header)
|
||||||
|
result = json.dumps(json.loads(ret.text), ensure_ascii=False, indent=4, separators=(',', ':'))
|
||||||
|
logging.info('报价接口返回:%s' % result)
|
||||||
|
price_result = json.loads(result)
|
||||||
|
# random.randint(0, 10000)
|
||||||
|
order.write({'price': price_result.get('price')})
|
||||||
|
else:
|
||||||
|
raise UserError("订单不存在")
|
||||||
|
except Exception as e:
|
||||||
|
if ret['status'] != 1:
|
||||||
|
raise UserError(e)
|
||||||
|
else:
|
||||||
|
raise UserError("自动报价失败,请联系管理员")
|
||||||
Reference in New Issue
Block a user