diff --git a/sf_base/models/basic_parameters_fixture.py b/sf_base/models/basic_parameters_fixture.py
index e9469355..868114e8 100644
--- a/sf_base/models/basic_parameters_fixture.py
+++ b/sf_base/models/basic_parameters_fixture.py
@@ -13,7 +13,7 @@ class BasicParametersFixture(models.Model):
diameter = fields.Float('直径(mm)', digits=(16, 2))
# '零点卡盘' 字段
- weight = fields.Float('重量(mm)', digits=(16, 2))
+ weight = fields.Float('重量(kg)', digits=(16, 2))
orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
clamping_diameter = fields.Float('装夹直径(mm)', digits=(16, 2))
clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数')
diff --git a/sf_base/views/fixture_view.xml b/sf_base/views/fixture_view.xml
index 0e86738d..07dadd33 100644
--- a/sf_base/views/fixture_view.xml
+++ b/sf_base/views/fixture_view.xml
@@ -171,7 +171,7 @@
-
+
@@ -197,7 +197,7 @@
-
+
@@ -220,7 +220,7 @@
-
+
@@ -248,7 +248,7 @@
-
+
@@ -278,7 +278,7 @@
-
+
@@ -307,7 +307,7 @@
-
+
@@ -335,7 +335,7 @@
-
+
diff --git a/sf_bf_connect/models/process_status.py b/sf_bf_connect/models/process_status.py
index 705aca4c..9c939edd 100644
--- a/sf_bf_connect/models/process_status.py
+++ b/sf_bf_connect/models/process_status.py
@@ -1,7 +1,8 @@
from datetime import datetime
import logging
import requests
-from odoo import fields, models
+from odoo.exceptions import UserError
+from odoo import fields, models, _
_logger = logging.getLogger(__name__)
@@ -14,6 +15,17 @@ class StatusChange(models.Model):
def action_confirm(self):
# 在原有方法执行前记录日志和执行其他操作
logging.info('函数已经执行=============')
+ server_product_none = []
+ for order in self.order_line:
+ for item in order.product_template_id.model_process_parameters_ids:
+ if item.gain_way == '外协':
+ server_product = self.env['product.template'].search(
+ [('server_product_process_parameters_id', '=', item.id),
+ ('detailed_type', '=', 'service')])
+ if not server_product:
+ server_product_none.append(item.name)
+ if server_product_none:
+ raise UserError(_("请先至【产品】中创建【表面工艺参数】为%s的服务产品", ", ".join(server_product_none)))
# 使用super()来调用原始方法(在本例中为'sale.order'模型的'action_confirm'方法)
res = super(StatusChange, self).action_confirm()
@@ -202,12 +214,12 @@ class FinishStatusChange(models.Model):
[('id', 'child_of', self.picking_type_id.warehouse_id.view_location_id.id),
('usage', '!=', 'supplier')])
if self.env['stock.move'].search([
- ('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']),
- ('product_qty', '>', 0),
- ('location_id', 'in', wh_location_ids),
- ('move_orig_ids', '=', False),
- ('picking_id', 'not in', self.ids),
- ('product_id', 'in', lines.product_id.ids)], limit=1):
+ ('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']),
+ ('product_qty', '>', 0),
+ ('location_id', 'in', wh_location_ids),
+ ('move_orig_ids', '=', False),
+ ('picking_id', 'not in', self.ids),
+ ('product_id', 'in', lines.product_id.ids)], limit=1):
action = self.action_view_reception_report()
action['context'] = {'default_picking_ids': self.ids}
return action
diff --git a/sf_dlm/models/product_supplierinfo.py b/sf_dlm/models/product_supplierinfo.py
index 05191b44..a46f4856 100644
--- a/sf_dlm/models/product_supplierinfo.py
+++ b/sf_dlm/models/product_supplierinfo.py
@@ -122,7 +122,7 @@ class ResMrpBomMo(models.Model):
# 查bom的原材料
def get_raw_bom(self, product):
raw_bom = self.env['product.product'].search(
- [('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)])
+ [('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)],limit=1)
return raw_bom
diff --git a/sf_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py
index babda164..f3597093 100644
--- a/sf_manufacturing/controllers/controllers.py
+++ b/sf_manufacturing/controllers/controllers.py
@@ -145,7 +145,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('get_qcCheck error:%s' % e)
return json.JSONEncoder().encode(res)
- @http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ @http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def button_Work_START(self, **kw):
"""
@@ -193,7 +193,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('button_Work_START error:%s' % e)
return json.JSONEncoder().encode(res)
- @http.route('/AutoDeviceApi/FeedBackEnd', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ @http.route('/AutoDeviceApi/FeedBackEnd', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def button_Work_End(self, **kw):
"""
@@ -244,7 +244,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('button_Work_End error:%s' % e)
return json.JSONEncoder().encode(res)
- @http.route('/AutoDeviceApi/PartQualityInspect', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ @http.route('/AutoDeviceApi/PartQualityInspect', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def PartQualityInspect(self, **kw):
"""
@@ -290,7 +290,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('PartQualityInspect error:%s' % e)
return json.JSONEncoder().encode(res)
- @http.route('/AutoDeviceApi/CMMProgDolod', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ @http.route('/AutoDeviceApi/CMMProgDolod', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def CMMProgDolod(self, **kw):
"""
@@ -330,7 +330,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('CMMProgDolod error:%s' % e)
return json.JSONEncoder().encode(res)
- @http.route('/AutoDeviceApi/NCProgDolod', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ @http.route('/AutoDeviceApi/NCProgDolod', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def NCProgDolod(self, **kw):
"""
@@ -429,7 +429,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('LocationChange error:%s' % e)
return json.JSONEncoder().encode(res)
- @http.route('/AutoDeviceApi/AGVToProduct', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ @http.route('/AutoDeviceApi/AGVToProduct', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def AGVToProduct(self, **kw):
"""
@@ -490,7 +490,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('AGVToProduct error:%s' % e)
return json.JSONEncoder().encode(res)
- @http.route('/AutoDeviceApi/AGVDownProduct', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ @http.route('/AutoDeviceApi/AGVDownProduct', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def AGVDownProduct(self, **kw):
"""
diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py
index 8dc02132..ff2fde3a 100644
--- a/sf_manufacturing/models/mrp_production.py
+++ b/sf_manufacturing/models/mrp_production.py
@@ -185,8 +185,8 @@ class MrpProduction(models.Model):
production.workorder_ids):
production.state = 'rework'
# 如果制造订单的功能刀具为【无效刀】则制造订单状态改为返工
- if production.tool_state == '2':
- production.state = 'rework'
+ # if production.tool_state == '2':
+ # production.state = 'rework'
def action_check(self):
"""
@@ -905,7 +905,6 @@ class MrpProduction(models.Model):
# production.write(
# {'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
# logging.info('返工含有已编程未下发的程序更新完成:%s' % production.name)
- logging.info('更新程序完成:%s' % production.name)
else:
raise UserError(result['message'])
diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py
index 8f045703..ed4786cd 100644
--- a/sf_manufacturing/models/mrp_workorder.py
+++ b/sf_manufacturing/models/mrp_workorder.py
@@ -131,7 +131,9 @@ class ResMrpWorkOrder(models.Model):
is_subcontract = fields.Boolean(string='是否外协')
surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数")
picking_ids = fields.Many2many('stock.picking', string='外协出入库单')
+ # purchase_id = fields.Many2one('purchase.order', string='外协采购单')
surface_technics_picking_count = fields.Integer("外协出入库", compute='_compute_surface_technics_picking_ids')
+ surface_technics_purchase_count = fields.Integer("外协采购", compute='_compute_surface_technics_purchase_ids')
@api.depends('name', 'production_id.name')
def _compute_surface_technics_picking_ids(self):
@@ -153,6 +155,43 @@ class ResMrpWorkOrder(models.Model):
action['context'] = dict(self._context, default_origin=self.name)
return action
+ @api.depends('state', 'production_id.name')
+ def _compute_surface_technics_purchase_ids(self):
+ for order in self:
+ if order.routing_type == '表面工艺':
+ production_programming = self.env['mrp.production'].search(
+ [('programming_no', '=', order.production_id.programming_no)], order='name asc')
+ production_list = [production.name for production in production_programming]
+ purchase = self.env['purchase.order'].search([('origin', '=', ','.join(production_list))])
+ for line in purchase.order_line:
+ if line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id and line.product_qty == len(
+ production_programming):
+ # server_product = self.env['product.template'].search(
+ # [('server_product_process_parameters_id', '=', pp.id),
+ # ('detailed_type', '=', 'service')])
+ # purchase_order_line = self.env['purchase.order.line'].search(
+ # [('product_id', '=', server_product.id), ('product_qty', '=', len(production_programming))])
+ # if purchase_order_line:
+ order.surface_technics_purchase_count = len(purchase)
+ else:
+ order.surface_technics_purchase_count = 0
+
+ def action_view_surface_technics_purchase(self):
+ self.ensure_one()
+ production_programming = self.env['mrp.production'].search(
+ [('programming_no', '=', self.production_id.programming_no)], order='name asc')
+ production_list = [production.name for production in production_programming]
+ purchase_orders = self.env['purchase.order'].search([('origin', '=', ','.join(production_list))])
+ result = {
+ "type": "ir.actions.act_window",
+ "res_model": "purchase.order",
+ "res_id": purchase_orders.id,
+ # "domain": [['id', 'in', self.purchase_id]],
+ "name": _("Purchase Orders"),
+ 'view_mode': 'form',
+ }
+ return result
+
supplier_id = fields.Many2one('res.partner', string='外协供应商')
equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True)
# 保存名称
@@ -885,7 +924,22 @@ class ResMrpWorkOrder(models.Model):
# workorder.state = 'ready'
if workorder.routing_type == '表面工艺' and workorder.state not in ['done', 'progress']:
if unclamp_workorder:
- workorder.state = 'ready'
+ if workorder.is_subcontract is False:
+ workorder.state = 'ready'
+ else:
+ production_programming = self.env['mrp.production'].search(
+ [('programming_no', '=', self.production_id.programming_no)], order='name asc')
+ production_list = [production.name for production in production_programming]
+ purchase_orders = self.env['purchase.order'].search(
+ [('origin', '=', ','.join(production_list))])
+ for line in purchase_orders.order_line:
+ if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id and line.product_qty == len(
+ production_programming):
+ if purchase_orders.state == 'purchase':
+ workorder.state = 'ready'
+ else:
+ workorder.state = 'waiting'
+
# else:
# if workorder.state not in ['cancel', 'rework']:
# workorder.state = 'rework'
@@ -1110,28 +1164,13 @@ class ResMrpWorkOrder(models.Model):
picking_out = record.env['stock.move.line'].search(
[('picking_id', '=', record.picking_ids[0].id)])
logging.info('picking_out:%s' % picking_out.picking_id.name)
- if picking_out:
- order_line_ids = []
- logging.info('surface_technics_parameters_id:%s' % record.surface_technics_parameters_id.name)
- server_product = self.env['product.template'].search(
- [('server_product_process_parameters_id', '=', record.surface_technics_parameters_id.id),
- ('detailed_type', '=', 'service')])
- logging.info('server_product:%s' % server_product.name)
- if server_product:
- order_line_ids.append((0, 0, {
- 'product_id': server_product.product_variant_id.id,
- 'product_qty': 1,
- 'product_uom': server_product.uom_id.id
- }))
- self.env['purchase.order'].sudo().create({
- 'partner_id': server_product.seller_ids.partner_id.id,
- 'origin': record.production_id.name,
- 'state': 'draft',
- 'order_line': order_line_ids,
- })
- else:
- raise UserError(
- '请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name)
+ # if picking_out:
+ # order_line_ids = []
+ # logging.info('surface_technics_parameters_id:%s' % record.surface_technics_parameters_id.name)
+ #
+ # else:
+ # raise UserError(
+ # '请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name)
tem_date_planned_finished = record.date_planned_finished
tem_date_finished = record.date_finished
logging.info('routing_type:%s' % record.routing_type)
diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py
index 4d05de81..41392409 100644
--- a/sf_manufacturing/models/product_template.py
+++ b/sf_manufacturing/models/product_template.py
@@ -5,8 +5,10 @@ import base64
import hashlib
import os
from odoo import models, fields, api, _
-from odoo.exceptions import ValidationError
+from odoo.exceptions import ValidationError, UserError
from odoo.modules import get_resource_path
+
+
from OCC.Extend.DataExchange import read_step_file
from OCC.Extend.DataExchange import write_stl_file
@@ -106,6 +108,15 @@ class ResProductMo(models.Model):
name = fields.Char('产品名称', compute='_compute_tool_name', store=True, required=False)
+ @api.constrains('seller_ids')
+ def _check_seller_ids(self):
+ if self.categ_type == '表面工艺':
+ if self.seller_ids:
+ if self.seller_ids[0].price == 0.0:
+ raise UserError("请在该产品【采购】中的【价格】进行输入")
+ else:
+ raise UserError("请在【采购】中输入供应商信息")
+
@api.depends('cutting_tool_model_id', 'specification_id')
def _compute_tool_name(self):
for item in self:
@@ -113,6 +124,10 @@ class ResProductMo(models.Model):
name = '%s%s' % (item.cutting_tool_model_id.name, item.specification_id.name)
item.name = name
+ def _get_process_parameters_product(self, production_process):
+ return self.env['product.template'].search(
+ [('server_product_process_parameters_id', '=', production_process.id)]).seller_ids[0]
+
@api.onchange('cutting_tool_model_id')
def _onchange_cutting_tool_model_id(self):
for item in self:
@@ -640,6 +655,10 @@ class ResProductMo(models.Model):
'part_number': item.get('part_number') or '',
'active': True,
}
+ tax_id = self.env['account.tax'].sudo().search(
+ [('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')])
+ if tax_id:
+ vals.update({'taxes_id':[(6,0,[int(tax_id)])]})
copy_product_id.sudo().write(vals)
product_id.product_tmpl_id.active = False
return copy_product_id
@@ -800,7 +819,7 @@ class ResProductFixture(models.Model):
diameter = fields.Float('直径(mm)', digits=(16, 2))
# '零点卡盘' 字段
- weight = fields.Float('重量(mm)', digits=(16, 2))
+ weight = fields.Float('重量(kg)', digits=(16, 2))
orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
clamping_diameter = fields.Float('装夹直径(mm)', digits=(16, 2))
clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数')
@@ -947,6 +966,7 @@ class SfMaintenanceEquipmentAndProductTemplate(models.Model):
raise ValidationError("机床基坐标获取失败")
+
class SfMaintenanceEquipmentTool(models.Model):
_name = 'maintenance.equipment.tool'
_description = '机床刀位'
diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py
index d902997f..76248171 100644
--- a/sf_manufacturing/models/stock.py
+++ b/sf_manufacturing/models/stock.py
@@ -217,6 +217,23 @@ class StockRule(models.Model):
(
p.move_dest_ids.procure_method != 'make_to_order' and not
p.move_raw_ids and not p.workorder_ids)).action_confirm()
+ # 处理 根据制造订单生成的采购单坯料入库时到原材料库,手动将原材料位置该为坯料存货区
+ for production in productions:
+ if production.picking_ids:
+ product_type_id = production.picking_ids[0].move_ids[0].product_id.categ_id
+ if product_type_id.name == '坯料':
+ location_id = self.env['stock.location'].search([('name', '=', '坯料存货区')])
+ if not location_id:
+ logging.info(f'没有搜索到【坯料存货区】: {location_id}')
+ break
+ for picking_id in production.picking_ids:
+ if picking_id.picking_type_id.name == '内部调拨':
+ if picking_id.location_dest_id.product_type != product_type_id:
+ picking_id.location_dest_id = location_id.id
+ elif picking_id.picking_type_id.name == '生产发料':
+ if picking_id.location_id.product_type != product_type_id:
+ picking_id.location_id = location_id.id
+
for production in productions:
'''
创建制造订单时生成序列号
@@ -272,6 +289,61 @@ class StockRule(models.Model):
product_id_to_production_names[product_id] = [production.name for production in all_production]
for production_item in productions:
if production_item.product_id.id in product_id_to_production_names:
+ if production_item.product_id.model_process_parameters_ids:
+ is_purchase = False
+ sorted_process_parameters = sorted(production_item.product_id.model_process_parameters_ids,
+ key=lambda w: w.id)
+
+ consecutive_process_parameters = []
+ m = 0
+ for i in range(len(sorted_process_parameters) - 1):
+ if m == 0:
+ is_purchase = False
+ if self.env['product.template']._get_process_parameters_product(
+ sorted_process_parameters[i]).partner_id == self.env[
+ 'product.template']._get_process_parameters_product(sorted_process_parameters[
+ i + 1]).partner_id and \
+ sorted_process_parameters[i].gain_way == '外协':
+ if sorted_process_parameters[i] not in consecutive_process_parameters:
+ consecutive_process_parameters.append(sorted_process_parameters[i])
+ consecutive_process_parameters.append(sorted_process_parameters[i + 1])
+ m += 1
+ continue
+ else:
+ if m == len(consecutive_process_parameters) - 1 and m != 0:
+ self.env['purchase.order'].get_purchase_order(consecutive_process_parameters,
+ production_item,
+ product_id_to_production_names)
+ if sorted_process_parameters[i] in consecutive_process_parameters:
+ is_purchase = True
+ consecutive_process_parameters = []
+ m = 0
+ # 当前面的连续外协采购单生成再生成当前外协采购单
+ if is_purchase is False:
+ self.env['purchase.order'].get_purchase_order(consecutive_process_parameters,
+ production_item,
+ product_id_to_production_names)
+ if m == len(consecutive_process_parameters) - 1 and m != 0:
+ self.env['purchase.order'].get_purchase_order(consecutive_process_parameters,
+ production_item,
+ product_id_to_production_names)
+ if sorted_process_parameters[i] in consecutive_process_parameters:
+ is_purchase = True
+ consecutive_process_parameters = []
+ m = 0
+ if m == len(consecutive_process_parameters) - 1 and m != 0:
+ self.env['purchase.order'].get_purchase_order(consecutive_process_parameters,
+ production_item,
+ product_id_to_production_names)
+ if is_purchase is False and m == 0:
+ if len(sorted_process_parameters) == 1:
+ self.env['purchase.order'].get_purchase_order(sorted_process_parameters,
+ production_item,
+ product_id_to_production_names)
+ else:
+ self.env['purchase.order'].get_purchase_order(sorted_process_parameters[i],
+ production_item,
+ product_id_to_production_names)
# # 同一个产品多个制造订单对应一个编程单和模型库
# # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递
if not production_item.programming_no:
@@ -498,7 +570,7 @@ class StockPicking(models.Model):
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
('location_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id),
- ('origin', '=', self.origin)])
+ ('origin', '=', self.origin), ('picking_id', '=', self.id)])
if self.location_id == move_in.location_id and self.location_dest_id == move_in.location_dest_id:
if move_out.origin == move_in.origin:
if move_out.picking_id.state != 'done':
diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml
index 3f44c961..69aed55e 100644
--- a/sf_manufacturing/views/mrp_production_addional_change.xml
+++ b/sf_manufacturing/views/mrp_production_addional_change.xml
@@ -122,7 +122,7 @@
groups="sf_base.group_sf_mrp_user"/>
-
+
@@ -285,7 +285,7 @@
-
+
@@ -568,7 +568,7 @@
diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml
index 805dcb1f..0c4fcd38 100644
--- a/sf_manufacturing/views/mrp_workorder_view.xml
+++ b/sf_manufacturing/views/mrp_workorder_view.xml
@@ -118,6 +118,17 @@
statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/>
+