diff --git a/sf_bf_connect/controllers/controllers.py b/sf_bf_connect/controllers/controllers.py
index 8c901610..607aa5c2 100644
--- a/sf_bf_connect/controllers/controllers.py
+++ b/sf_bf_connect/controllers/controllers.py
@@ -111,11 +111,12 @@ class Sf_Bf_Connect(http.Controller):
res['message'] = '该订单模型的材料型号在您分配的工厂里暂未设置获取方式和供应商,请先配置再进行分配'
request.cr.rollback()
return json.JSONEncoder().encode(res)
- # 产品配置bom
- product_bom_purchase = request.env['mrp.bom'].with_user(
- request.env.ref("base.user_admin")).bom_create(product, 'normal', False)
- product_bom_purchase.with_user(request.env.ref("base.user_admin")).bom_create_line_has(
- purchase_embryo)
+ else:
+ # 产品配置bom
+ product_bom_purchase = request.env['mrp.bom'].with_user(
+ request.env.ref("base.user_admin")).bom_create(product, 'normal', False)
+ product_bom_purchase.with_user(request.env.ref("base.user_admin")).bom_create_line_has(
+ purchase_embryo)
order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item)
i += 1
res['factory_order_no'] = order_id.name
diff --git a/sf_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py
index e42bb1c7..86d18009 100644
--- a/sf_manufacturing/controllers/controllers.py
+++ b/sf_manufacturing/controllers/controllers.py
@@ -511,7 +511,6 @@ class Manufacturing_Connect(http.Controller):
rfid_code = ret[f'RfidCode{i}']
logging.info('RfidCode:%s' % rfid_code)
domain = [
- ('feeder_station_start_id.name', '=', ret['DeviceId']),
('workorder_id.rfid_code', '=', rfid_code),
('status', '=', '待下发'),
('type', '=', '下产线')
diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py
index a96f3383..405fd1d5 100644
--- a/sf_manufacturing/models/mrp_production.py
+++ b/sf_manufacturing/models/mrp_production.py
@@ -166,26 +166,30 @@ class MrpProduction(models.Model):
if quick_order:
programme_way = 'manual operation'
try:
- res = {'model_code': '' if not cnc.product_id.model_code else cnc.product_id.model_code,
- 'production_no': cnc.name,
- 'machine_tool_code': "",
- 'material_code': self.env['sf.production.materials'].search(
- [('id', '=', cnc.product_id.materials_id.id)]).materials_no,
- 'material_type_code': self.env['sf.materials.model'].search(
- [('id', '=', cnc.product_id.materials_type_id.id)]).materials_no,
- 'machining_processing_panel': cnc.product_id.model_processing_panel,
- 'machining_precision': cnc.product_id.model_machining_precision,
- 'embryo_long': cnc.product_id.bom_ids.bom_line_ids.product_id.length,
- 'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height,
- 'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
- 'order_no': cnc.origin,
- 'model_order_no': cnc.product_id.default_code,
- 'user': cnc.env.user.name,
- 'programme_way': programme_way,
- 'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
- cnc.product_id.model_file).decode('utf-8')
- }
- logging.info('res:%s' % res)
+ res = {
+ 'production_no': cnc.name,
+ 'machine_tool_code': '',
+ 'model_code': cnc.product_id.model_code,
+ 'material_code': self.env['sf.production.materials'].search(
+ [('id', '=', cnc.product_id.materials_id.id)]).materials_no,
+ 'material_type_code': self.env['sf.materials.model'].search(
+ [('id', '=', cnc.product_id.materials_type_id.id)]).materials_no,
+ 'machining_processing_panel': cnc.product_id.model_processing_panel,
+ 'machining_precision': cnc.product_id.model_machining_precision,
+ 'embryo_long': cnc.product_id.bom_ids.bom_line_ids.product_id.length,
+ 'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height,
+ 'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
+ 'order_no': cnc.origin,
+ 'model_order_no': cnc.product_id.default_code,
+ 'user': cnc.env.user.name,
+ 'programme_way': programme_way,
+ 'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
+ cnc.product_id.model_file).decode('utf-8')
+ }
+ # 打印出除了 model_file 之外的所有键值对
+ for key, value in res.items():
+ if key != 'model_file':
+ logging.info('%s: %s' % (key, value))
configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/intelligent_programming/create'
@@ -263,14 +267,15 @@ class MrpProduction(models.Model):
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
def _create_workorder3(self):
- programming_no = None
- product_id_new = None
+ # production_names = [production.name for production in self if production.product_id.categ_id.type == '成品']
+ # programming_no = None
+ # product_first = None
for production in self:
if not production.bom_id or not production.product_id:
continue
workorders_values = []
- if product_id_new is None:
- product_id_new = production.product_id
+ # if product_first is None:
+ # product_first = production.product_id
product_qty = production.product_uom_id._compute_quantity(production.product_qty,
production.bom_id.product_uom_id)
@@ -295,14 +300,15 @@ class MrpProduction(models.Model):
'state': 'pending',
}]
if production.product_id.categ_id.type == '成品':
- if programming_no is None:
- production.fetchCNC()
- programming_no = production.programming_no
- else:
- if production.product_id == product_id_new:
- if not production.programming_no:
- production.write({'programming_no': programming_no, 'programming_state': '编程中'})
-
+ production.fetchCNC()
+ # 第二期同一个产品多个制造订单对应一个编程单和模型库
+ # if programming_no is None:
+ # production.fetchCNC(production_names)
+ # programming_no = production.programming_no
+ # else:
+ # if production.product_id == product_first:
+ # if not production.programming_no:
+ # production.write({'programming_no': programming_no, 'programming_state': '编程中'})
# 根据加工面板的面数及对应的工序模板生成工单
i = 0
processing_panel_len = len(production.product_id.model_processing_panel.split(','))
diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py
index 704b0ec5..e10db743 100644
--- a/sf_manufacturing/models/mrp_workorder.py
+++ b/sf_manufacturing/models/mrp_workorder.py
@@ -493,9 +493,15 @@ class ResMrpWorkOrder(models.Model):
return workorders_values_str
def _json_workpiece_delivery_list(self, production):
+ up_route = self.env['sf.agv.task.route'].search([('route_type', '=', '上产线')], limit=1, order='id asc')
+ down_route = self.env['sf.agv.task.route'].search([('route_type', '=', '下产线')], limit=1, order='id asc')
return [
- [0, '', {'production_id': production.id, 'type': '上产线'}],
- [0, '', {'production_id': production.id, 'type': '下产线'}]]
+ [0, '', {'production_id': production.id, 'type': '上产线', 'route_id': up_route.id,
+ 'feeder_station_start_id': up_route.start_site_id.id,
+ 'feeder_station_destination_id': up_route.end_site_id.id}],
+ [0, '', {'production_id': production.id, 'type': '下产线', 'route_id': down_route.id,
+ 'feeder_station_start_id': down_route.start_site_id.id,
+ 'feeder_station_destination_id': down_route.end_site_id.id}]]
# 拼接工单对象属性值(表面工艺)
def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id):
@@ -827,16 +833,13 @@ class ResMrpWorkOrder(models.Model):
raise UserError("请对前置三元检测定位参数进行计算定位")
if not record.rfid_code:
raise UserError("请扫RFID码进行绑定")
- record.workpiece_delivery_ids[0].write({'status': '待下发'})
record.process_state = '待加工'
# record.write({'process_state': '待加工'})
record.production_id.process_state = '待加工'
-
if record.routing_type == 'CNC加工':
record.process_state = '待解除装夹'
# record.write({'process_state': '待加工'})
record.production_id.process_state = '待解除装夹'
-
if record.routing_type == '解除装夹':
'''
记录结束时间
@@ -904,13 +907,17 @@ class ResMrpWorkOrder(models.Model):
# 根据中控系统提供的检测文件地址去ftp里对应的制造订单里获取
def get_detection_file(self, workorder, reportPath):
- if reportPath.startswith('/'):
- reportPath = reportPath[4:]
- serverdir = os.path.join('/tmp', reportPath)
+ # if reportPath.startswith('/'):
+ # reportPath = reportPath[4:]
+ # serverdir = os.path.join('/tmp', reportPath)
+ serverdir = '/tmp' + reportPath
logging.info('get_detection_file-serverdir:%s' % serverdir)
serverdir_prefix = os.path.dirname(serverdir)
+ logging.info('serverdir_prefix-serverdir:%s' % serverdir_prefix)
for root, dirs, files in os.walk(serverdir_prefix):
for filename in files:
+ logging.info('filename:%s' % filename)
+ logging.info('reportPath:%s' % os.path.basename(reportPath))
if filename == os.path.basename(reportPath):
report_file_path = os.path.join(root, filename)
logging.info('get_detection_file-report_file_path:%s' % report_file_path)
@@ -945,6 +952,8 @@ class CNCprocessing(models.Model):
# mrs下发编程单创建CNC加工
def cnc_processing_create(self, cnc_workorder, ret, program_path, program_path_tmp):
+ # 注释代码为第二期同一产品多个编程单需求
+ # cnc_processing = None
for obj in ret['programming_list']:
workorder = self.env['mrp.workorder'].search([('production_id.name', '=', ret['production_order_no']),
('processing_panel', '=', obj['processing_panel']),
@@ -979,10 +988,28 @@ class CNCprocessing(models.Model):
item.is_cnc_program_down = True
if item.workorder_id.state == 'waiting':
item.workorder_id.state = 'ready'
+ # return cnc_processing
# cnc_workorder.time_ids.date_end = datetime.now()
# cnc_workorder.button_finish()
+ def _json_cnc_processing(self, obj):
+ cnc_processing_str = [0, 0, {
+ 'sequence_number': obj['sequence_number'],
+ 'program_name': obj['program_name'],
+ 'cutting_tool_name': obj['cutting_tool_name'],
+ 'cutting_tool_no': obj['cutting_tool_no'],
+ 'processing_type': obj['processing_type'],
+ 'margin_x_y': obj['margin_x_y'],
+ 'margin_z': obj['margin_z'],
+ 'depth_of_processing_z': obj['depth_of_processing_z'],
+ 'cutting_tool_extension_length': obj['cutting_tool_extension_length'],
+ 'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
+ 'estimated_processing_time': obj['estimated_processing_time'],
+ 'remark': obj['remark']
+ }]
+ return cnc_processing_str
+
# 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配
def get_cnc_processing_file(self, serverdir, cnc_processing, program_path):
logging.info('serverdir:%s' % serverdir)
@@ -1014,7 +1041,6 @@ class CNCprocessing(models.Model):
# 将FTP的nc文件下载到临时目录
def download_file_tmp(self, production_no, processing_panel):
remotepath = os.path.join('/NC', production_no, 'return', processing_panel)
- serverdir = os.path.join('/tmp', production_no, 'return', processing_panel)
ftp_resconfig = self.env['res.config.settings'].get_values()
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],
ftp_resconfig['ftp_password'])
@@ -1236,8 +1262,8 @@ class WorkPieceDelivery(models.Model):
same_route_id = item.route_id.id
if item.route_id.id != same_route_id:
is_not_route += 1
- else:
- raise UserError('请选择【任务路线】再进行配送')
+ # else:
+ # raise UserError('请选择【任务路线】再进行配送')
if production_type != item.type:
raise UserError('请选择类型为%s的制造订单进行配送' % production_type)
if down_status != item.status:
@@ -1280,7 +1306,7 @@ class WorkPieceDelivery(models.Model):
'default_type': production_type,
}}
else:
- if self.type == '运送空料架':
+ if production_type == '运送空料架':
raise UserError("您所选择的【任务路线】的【终点接驳站】已占用,请在该接驳站空闲时进行配送")
else:
raise UserError(
@@ -1317,30 +1343,33 @@ class WorkPieceDelivery(models.Model):
feeder_station_destination = None
route_id = None
for item in self:
- delivery_Arr.append(item.name)
+ if route_id is None:
+ route_id = item.route_id.id
+ if feeder_station_start is None:
+ feeder_station_start = item.feeder_station_start_id
+ if feeder_station_destination is None:
+ feeder_station_destination = item.feeder_station_destination_id
if item.type in ['上产线', '下产线']:
- if route_id is None:
- route_id = item.route_id.id
- if feeder_station_start is None:
- feeder_station_start = item.feeder_station_start_id.name
- if feeder_station_destination is None:
- feeder_station_destination = item.feeder_station_destination_id.name
item.route_id = route_id
+ item.feeder_station_start_id = feeder_station_start.id
+ item.feeder_station_destination_id = feeder_station_destination.id
+ delivery_Arr.append(item.name)
else:
self = self.create(
{'name': self.env['ir.sequence'].next_by_code('sf.workpiece.delivery'),
'route_id': self.route_id.id,
'feeder_station_start_id': self.feeder_station_start_id.id,
'feeder_station_destination_id': self.feeder_station_destination_id.id})
+ delivery_Arr.append(self.name)
delivery_str = ','.join(map(str, delivery_Arr))
if feeder_station_start is not None:
positionCode_Arr.append({
- 'positionCode': feeder_station_start,
+ 'positionCode': feeder_station_start.name,
'code': '00'
})
if feeder_station_destination is not None:
positionCode_Arr.append({
- 'positionCode': feeder_station_destination,
+ 'positionCode': feeder_station_destination.name,
'code': '00'
})
res = {'reqCode': delivery_str, 'reqTime': '', 'clientCode': '', 'tokenCode': '',
diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py
index 4d07ae1c..3e91e6a3 100644
--- a/sf_manufacturing/models/product_template.py
+++ b/sf_manufacturing/models/product_template.py
@@ -7,6 +7,8 @@ import os
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
from odoo.modules import get_resource_path
+
+
from OCC.Extend.DataExchange import read_step_file
from OCC.Extend.DataExchange import write_stl_file
@@ -179,6 +181,12 @@ class ResProductMo(models.Model):
# ('standard_library_id', '=', self.cutting_tool_model_id.id)],
# }
+ # def name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
+ # # if self._context.get('is_sale_order_line'):
+ # # domain = [('sale_ok', '=', True), ('categ_type', '=', '成品')]
+ # # return self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
+ # return super(product.template, self)._name_search(name, args, operator, limit, name_get_uid)
+
@api.onchange('specification_id')
def _onchange_specification(self):
if self.specification_id:
diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv
index 1798ba27..22cff848 100644
--- a/sf_manufacturing/security/ir.model.access.csv
+++ b/sf_manufacturing/security/ir.model.access.csv
@@ -30,7 +30,7 @@ access_mrp_workcenter_group_sf_mrp_user,mrp_workcenter,model_mrp_workcenter,sf_b
access_mrp_workcenter_manager,mrp_workcenter,model_mrp_workcenter,sf_base.group_sf_mrp_manager,1,1,1,0
access_mrp_workcenter_productivity_group_sf_mrp_user,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_mrp_user,1,0,0,0
access_mrp_workcenter_productivity_manager,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_mrp_manager,1,1,1,0
-access_sf_workpiece_delivery_group_sf_order_user,sf_workpiece_delivery_group_sf_order_user,model_sf_workpiece_delivery,sf_base.group_sf_order_user,1,1,0,0
+access_sf_workpiece_delivery_group_sf_order_user,sf_workpiece_delivery_group_sf_order_user,model_sf_workpiece_delivery,sf_base.group_sf_order_user,1,1,1,0
access_sf_workpiece_delivery_group_sf_equipment_user,sf_workpiece_delivery_group_sf_equipment_user,model_sf_workpiece_delivery,sf_base.group_sf_equipment_user,1,1,0,0
access_sf_workpiece_delivery_manager,sf_workpiece_delivery,model_sf_workpiece_delivery,sf_base.group_sf_mrp_manager,1,1,0,0
diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml
index 7fdf390d..dce2a68a 100644
--- a/sf_manufacturing/views/mrp_workorder_view.xml
+++ b/sf_manufacturing/views/mrp_workorder_view.xml
@@ -145,7 +145,6 @@
-
@@ -266,13 +265,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -446,7 +445,8 @@
-
+
@@ -457,7 +457,7 @@
-
+
@@ -607,12 +607,14 @@
decoration-danger="status == '待配送'"/>
-
-
+
+
+
-
+
diff --git a/sf_manufacturing/wizard/workpiece_delivery_wizard.py b/sf_manufacturing/wizard/workpiece_delivery_wizard.py
index bebe9e44..fdf64bf9 100644
--- a/sf_manufacturing/wizard/workpiece_delivery_wizard.py
+++ b/sf_manufacturing/wizard/workpiece_delivery_wizard.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
+import logging
from odoo.exceptions import UserError, ValidationError
from datetime import datetime
from odoo import models, api, fields, _
@@ -44,7 +45,11 @@ class WorkpieceDeliveryWizard(models.TransientModel):
def recognize_production(self):
# production_ids = []
# delivery_ids = []
- if len(self.production_ids) > 4:
+ # aa = self.production_ids.workorder_ids.filtered(
+ # lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.filtered(
+ # lambda c: c.rfid_code == self.rfid_code)
+ # logging.info('aa:%s' % aa)
+ if len(self.production_ids) == 4:
raise UserError('只能配送四个制造订单')
else:
if self.rfid_code:
diff --git a/sf_mrs_connect/models/ftp_operate.py b/sf_mrs_connect/models/ftp_operate.py
index 98e6d504..3a09a305 100644
--- a/sf_mrs_connect/models/ftp_operate.py
+++ b/sf_mrs_connect/models/ftp_operate.py
@@ -24,6 +24,7 @@ class FtpController():
def file_exists(self, path):
# 检查文件是否存在于FTP服务器上
try:
+ logging.info("dirname:%s" % os.path.dirname(path))
self.ftp.cwd(os.path.dirname(path))
files = self.ftp.nlst()
return os.path.basename(path) in files
@@ -31,6 +32,11 @@ class FtpController():
logging.error(f"Error checking file: {e}")
return False
+ # # 检测字符串的编码
+ # def detect_encoding(self, s):
+ # result = chardet.detect(s)
+ # return result['encoding']
+
# 下载目录下的文件
def download_file_tree(self, target_dir, serverdir):
if not os.path.exists(serverdir):
@@ -84,6 +90,9 @@ class FtpController():
return 1
except Exception:
return 0
+ finally:
+ self.ftp.quit()
+ logging.info("ftp已关闭")
# 下载指定目录下的指定文件
def download_file(self, serverfile, remotefile):
diff --git a/sf_plan/models/custom_plan.py b/sf_plan/models/custom_plan.py
index 60618f1d..b2f04edd 100644
--- a/sf_plan/models/custom_plan.py
+++ b/sf_plan/models/custom_plan.py
@@ -229,6 +229,11 @@ class sf_production_plan(models.Model):
record.env['mrp.production'].sudo().browse(i).schedule_state = '已排'
# record.production_id.date_planned_start = record.date_planned_start
# record.production_id.date_planned_finished = record.date_planned_finished
+ record.production_id.production_line_id = record.production_line_id.id
+ record.production_id.workorder_ids.filtered(
+ lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write(
+ {'production_line_id': record.production_line_id.id,
+ 'plan_start_processing_time': record.date_planned_start})
else:
raise ValidationError("未找到工单")
# record.date_planned_finished = record.date_planned_start + timedelta(days=3)
diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py
index 64c64b52..e2597a58 100644
--- a/sf_sale/models/sale_order.py
+++ b/sf_sale/models/sale_order.py
@@ -85,7 +85,8 @@ class ReSaleOrder(models.Model):
self.check_status = 'pending'
def get_customer(self):
- partner_tag = self.env['res.partner.category'].sudo().search([('name', '=', '业务平台')], limit=1, order='id asc')
+ partner_tag = self.env['res.partner.category'].sudo().search([('name', '=', '业务平台')], limit=1,
+ order='id asc')
if not partner_tag:
partner_tag = self.env['res.partner.category'].sudo().create({'name': '平台客户'})
customer = self.env['res.partner'].search([('name', '=', '业务平台')], limit=1, order='id asc')
@@ -139,9 +140,19 @@ class ResaleOrderLine(models.Model):
_inherit = 'sale.order.line'
model_glb_file = fields.Binary('模型的glb文件')
+ # product_template_id = fields.Many2one(
+ # string="产品",
+ # comodel_name='product.template',
+ # compute='_compute_product_template_id',
+ # readonly=False,
+ # search='_search_product_template_id',
+ # # previously related='product_id.product_tmpl_id'
+ # # not anymore since the field must be considered editable for product configurator logic
+ # # without modifying the related product_id when updated.
+ # domain=[('sale_ok', '=', True), ('categ_type', '=', '成品')])
check_status = fields.Selection(related='order_id.check_status')
- @api.onchange('product_id')
+ @api.onchange('product_template_id')
def _compute_model_glb_file(self):
for line in self:
if line.product_template_id:
diff --git a/sf_sale/views/sale_order_view.xml b/sf_sale/views/sale_order_view.xml
index f998887a..d8f06f64 100644
--- a/sf_sale/views/sale_order_view.xml
+++ b/sf_sale/views/sale_order_view.xml
@@ -117,6 +117,10 @@
+
+
+ {'no_create': True}
+ {'is_sale_order_line': True }
{'readonly': [('state', 'in', ['cancel','sale'])]}