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_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py index babda164..072cd222 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): """ 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 c127132c..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: diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index c202fc71..aea42c6f 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -289,6 +289,54 @@ 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: + 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: @@ -516,7 +564,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"/> -