diff --git a/jikimo_purchase_request/models/purchase_request.py b/jikimo_purchase_request/models/purchase_request.py index 4b5f86ba..9e610612 100644 --- a/jikimo_purchase_request/models/purchase_request.py +++ b/jikimo_purchase_request/models/purchase_request.py @@ -1,4 +1,5 @@ import re +import ast from odoo import models, fields, api @@ -20,6 +21,13 @@ class PurchaseRequest(models.Model): if pr.state != 'draft' and pr.rule_new_add: pr.rule_new_add = False + def action_view_purchase_order(self): + action = super(PurchaseRequest, self).action_view_purchase_order() + origin_context = ast.literal_eval(action['context']) + if 'search_default_draft' in origin_context: + origin_context.pop('search_default_draft') + action['context'] = origin_context + return action class PurchaseRequestLine(models.Model): _inherit = 'purchase.request.line' diff --git a/jikimo_purchase_request_tier_validation/__init__.py b/jikimo_purchase_request_tier_validation/__init__.py new file mode 100644 index 00000000..cde864ba --- /dev/null +++ b/jikimo_purchase_request_tier_validation/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/jikimo_purchase_request_tier_validation/__manifest__.py b/jikimo_purchase_request_tier_validation/__manifest__.py new file mode 100644 index 00000000..403297ab --- /dev/null +++ b/jikimo_purchase_request_tier_validation/__manifest__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +{ + 'name': "机企猫 采购审批流程", + + 'summary': """ + Short (1 phrase/line) summary of the module's purpose, used as + subtitle on modules listing or apps.openerp.com""", + + 'description': """ + Long description of module's purpose + """, + + 'author': "My Company", + 'website': "https://www.yourcompany.com", + + # Categories can be used to filter modules in modules listing + # Check https://github.com/odoo/odoo/blob/16.0/odoo/addons/base/data/ir_module_category_data.xml + # for the full list + 'category': 'Uncategorized', + 'version': '0.1', + + # any module necessary for this one to work correctly + 'depends': ['purchase_request_tier_validation'], + + # always loaded + 'data': [ + ], +} diff --git a/jikimo_purchase_request_tier_validation/models/__init__.py b/jikimo_purchase_request_tier_validation/models/__init__.py new file mode 100644 index 00000000..5305644d --- /dev/null +++ b/jikimo_purchase_request_tier_validation/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models \ No newline at end of file diff --git a/jikimo_purchase_request_tier_validation/models/models.py b/jikimo_purchase_request_tier_validation/models/models.py new file mode 100644 index 00000000..0070a4c7 --- /dev/null +++ b/jikimo_purchase_request_tier_validation/models/models.py @@ -0,0 +1,24 @@ +from odoo import models, fields, api, _ +from odoo.exceptions import ValidationError +import logging + +_logger = logging.getLogger(__name__) + + +class PurchaseRequest(models.Model): + _inherit = 'purchase.request' + + + def _validate_tier(self, tiers=False): + res = super(PurchaseRequest, self)._validate_tier(tiers) + + # 检查是否所有审批都已通过 + all_approved = all( + tier_review.status == 'approved' + for tier_review in self.review_ids + ) + + if self.review_ids and all_approved: # 确保有审批记录 + self.state = 'approved' + + return res diff --git a/jikimo_purchase_tier_validation/__manifest__.py b/jikimo_purchase_tier_validation/__manifest__.py index 4d676d8f..ed0cecb7 100644 --- a/jikimo_purchase_tier_validation/__manifest__.py +++ b/jikimo_purchase_tier_validation/__manifest__.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- { - 'name': "机企猫 采购审批流程", + 'name': "机企猫 采购申请审批流程", 'summary': """ - Short (1 phrase/line) summary of the module's purpose, used as - subtitle on modules listing or apps.openerp.com""", + 采购申请审批流程""", 'description': """ - Long description of module's purpose - """, + 采购申请审批流程""", 'author': "My Company", 'website': "https://www.yourcompany.com", diff --git a/sf_base/models/base.py b/sf_base/models/base.py index d7a71e1e..54a1fe1f 100644 --- a/sf_base/models/base.py +++ b/sf_base/models/base.py @@ -421,3 +421,4 @@ class EmbryoRedundancy(models.Model): width = fields.Float('宽度(mm)', required=True) height = fields.Float('高度(mm)', required=True) active = fields.Boolean('有效', default=True) + remark = fields.Char('描述') diff --git a/sf_base/views/base_view.xml b/sf_base/views/base_view.xml index bd6f103b..ccac31c9 100644 --- a/sf_base/views/base_view.xml +++ b/sf_base/views/base_view.xml @@ -645,6 +645,7 @@ + diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 15715be4..52c5f463 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -5,6 +5,8 @@ import logging import json import os import re +import traceback + import requests from itertools import groupby from collections import defaultdict, namedtuple @@ -257,14 +259,46 @@ class MrpProduction(models.Model): ], string='工序状态', default='待装夹') # 零件图号 - part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True) + part_number = fields.Char('零件图号', compute='_compute_part_info', store=True) # 上传零件图纸 part_drawing = fields.Binary('零件图纸', related='product_id.machining_drawings', readonly=True) quality_standard = fields.Binary('质检标准', related='product_id.quality_standard', readonly=True) - part_name = fields.Char(string='零件名称', related='product_id.part_name', readonly=True) + part_name = fields.Char(string='零件名称', compute='_compute_part_info', store=True) + @api.depends('product_id') + def _compute_part_info(self): + try: + for production_id in self: + if production_id.product_id.categ_id.type == '成品': + production_id.part_number = production_id.product_id.part_number + production_id.part_name = production_id.product_id.part_name + elif production_id.product_id.categ_id.type == '坯料': + product_name = '' + match = re.search(r'(S\d{5}-\d)', production_id.product_id.name) + # 如果匹配成功,提取结果 + if match: + product_name = match.group(0) + if production_id.sale_order_id: + sale_order = production_id.sale_order_id + else: + sale_order_name = '' + match = re.search(r'(S\d+)', production_id.product_id.name) + if match: + sale_order_name = match.group(0) + sale_order = self.env['sale.order'].sudo().search( + [('name', '=', sale_order_name)]) + logging.info("product_name is :%s" % product_name) + filtered_order_line = sale_order.order_line.filtered( + lambda production: re.search(f'{product_name}$', production.product_id.name) + ) + if filtered_order_line: + production_id.part_number = filtered_order_line.part_number + production_id.part_name = filtered_order_line.part_name + except Exception as e: + traceback_error = traceback.format_exc() + logging.error("制造订单零件图号 零件名称获取失败:%s" % traceback_error) # 判断制造的产品类型 production_product_type = fields.Selection([ diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index b8ea6eec..ea2923bd 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -1533,7 +1533,7 @@ class ResMrpWorkOrder(models.Model): # workorder.rfid_code_old = rfid_code # workorder.rfid_code = False logging.info('workorder.rfid_code:%s' % workorder.rfid_code) - # if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺', '切割']: + if is_production_id is True: logging.info('product_qty:%s' % record.production_id.product_qty) for move_raw_id in record.production_id.move_raw_ids: @@ -1548,6 +1548,17 @@ class ResMrpWorkOrder(models.Model): # if raw_move: # raw_move.write({'state': 'done'}) if record.production_id.state != 'rework': + # 如果工单包含了外协工序,需要预留数量 + if self.move_raw_ids.move_orig_ids.subcontract_workorder_id: + location_id = self.move_raw_ids.location_id + quant = self.move_raw_ids.lot_ids.quant_ids.filtered(lambda q: q.location_id.id == location_id.id) + if quant.reserved_quantity == 0: + self.env['stock.quant']._update_reserved_quantity( + self.move_raw_ids.product_id, + location_id, + quant.quantity, + lot_id=quant.lot_id, + ) record.production_id.button_mark_done1() # record.production_id.state = 'done' diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index 0528d65d..3554967c 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -173,7 +173,6 @@ class ResProductMo(models.Model): '压紧方式', domain=[('type', '=', '压紧方式')]) name = fields.Char('产品名称', compute='_compute_tool_name', store=True, required=False) - @api.constrains('seller_ids') def _check_seller_ids(self): @@ -896,8 +895,9 @@ class ResProductMo(models.Model): 'model_long': self.format_float(item['model_long'] + embryo_redundancy_id.long), 'model_width': self.format_float(item['model_width'] + embryo_redundancy_id.width), 'model_height': self.format_float(item['model_height'] + embryo_redundancy_id.height), - 'model_volume': self.format_float(item['blank_volume']), - 'model_area': self.format_float(item['blank_area']), + 'model_volume': self.format_float((item['model_long'] + embryo_redundancy_id.long) * ( + item['model_width'] + embryo_redundancy_id.width) * ( + item['model_height'] + embryo_redundancy_id.height)), 'product_model_type_id': model_type.id, 'model_processing_panel': item['processing_panel_detail'], 'model_machining_precision': item['model_machining_precision'], @@ -1114,9 +1114,9 @@ class ResProductMo(models.Model): image_data = fileObj.read() base64_data = base64.b64encode(image_data) return base64_data - + # 增加产品表面积 - + class ResProductFixture(models.Model): diff --git a/sf_manufacturing/models/purchase_order.py b/sf_manufacturing/models/purchase_order.py index 3d71b6c7..044b68e1 100644 --- a/sf_manufacturing/models/purchase_order.py +++ b/sf_manufacturing/models/purchase_order.py @@ -59,18 +59,15 @@ class PurchaseOrder(models.Model): production_id = self.env['mrp.production'].search([('origin', 'in', origins)]) purchase.production_count = len(production_id) - # def button_confirm(self): - # super().button_confirm() - # workorders = self.env['mrp.workorder'].search([('purchase_id', '=', self.id), ('state', '!=', 'cancel')]) - # for workorder in workorders: - # if workorder.routing_type == '表面工艺' and workorder.is_subcontract is True: - # move_out = workorder.move_subcontract_workorder_ids[1] - # for mo in move_out: - # if mo.state != 'done': - # mo.write({'state': 'assigned', 'production_id': False}) - # if not mo.move_line_ids: - # self.env['stock.move.line'].create(mo.get_move_line(workorder.production_id, workorder)) - # return True + def button_confirm(self): + for record in self: + for line in record.order_line: + if line.product_qty <= 0: + raise UserError('请对【产品】中的【数量】进行输入') + if line.price_unit <= 0: + raise UserError('请对【产品】中的【单价】进行输入') + return super(PurchaseOrder, self).button_confirm() + origin_sale_id = fields.Many2one('sale.order', string='销售订单号', store=True, compute='_compute_origin_sale_id') origin_sale_ids = fields.Many2many('sale.order', string='销售订单号(多个)', store=True, diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index 245c1b11..1f1e45b6 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -564,6 +564,18 @@ class StockPicking(models.Model): sale_order_id = fields.Many2one('sale.order', '销售单号', compute='_compute_move_ids', store=True) picking_type_sequence_code = fields.Char(related='picking_type_id.sequence_code') + part_numbers = fields.Char(string="零件图号", compute='_compute_part_info', store=True, index=True) + part_names = fields.Char(string="零件名称", compute='_compute_part_info', store=True, index=True) + + @api.depends('move_ids_without_package.part_number', 'move_ids_without_package.part_name') + def _compute_part_info(self): + for picking in self: + # 聚合所有关联行的 part_number 和 part_name + part_numbers = picking.move_ids_without_package.mapped('part_number') + part_names = picking.move_ids_without_package.mapped('part_name') + picking.part_numbers = ','.join(filter(None, part_numbers)) + picking.part_names = ','.join(filter(None, part_names)) + @api.depends('move_ids', 'move_ids.product_id') def _compute_move_ids(self): for item in self: @@ -678,7 +690,8 @@ class StockPicking(models.Model): # 如果当前工单是是制造订单的最后一个工艺外协工单 if workorder == next((workorder for workorder in reversed(sorted_workorders) if workorder.is_subcontract), None): - move_dest_id = item.move_raw_ids[0].id + if item.move_raw_ids: + move_dest_id = item.move_raw_ids[0].id else: # 从sorted_workorders中找到上一工单的move if len(sorted_workorders) > 1: @@ -714,6 +727,7 @@ class StockPicking(models.Model): moves_out._action_confirm() moves_out._assign_picking_post_process(new=new_picking) + @api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id') def _compute_state(self): super(StockPicking, self)._compute_state() @@ -837,6 +851,7 @@ class ReStockMove(models.Model): # 'route_ids': False if not route else [(4, route.id)], 'date_deadline': datetime.now(), 'picking_type_id': picking_type_id, + # 'is_subcontract': True, } return move_values @@ -1106,6 +1121,13 @@ class ReStockMove(models.Model): if self.state != 'assigned': self.state = 'assigned' return self.action_show_details() + + def _prepare_move_line_vals(self, quantity=None, reserved_quant=None): + res = super(ReStockMove, self)._prepare_move_line_vals(quantity, reserved_quant) + if self.subcontract_workorder_id: + if self.subcontract_workorder_id.production_id.move_raw_ids.move_line_ids: + res['lot_id'] = self.subcontract_workorder_id.production_id.move_raw_ids.move_line_ids[0].lot_id.id + return res class ReStockQuant(models.Model): diff --git a/sf_manufacturing/views/sale_order_views.xml b/sf_manufacturing/views/sale_order_views.xml index 7bda0168..8366a972 100644 --- a/sf_manufacturing/views/sale_order_views.xml +++ b/sf_manufacturing/views/sale_order_views.xml @@ -18,7 +18,7 @@ - + diff --git a/sf_manufacturing/views/stock_picking_view.xml b/sf_manufacturing/views/stock_picking_view.xml index 3cb877a9..f5b1941b 100644 --- a/sf_manufacturing/views/stock_picking_view.xml +++ b/sf_manufacturing/views/stock_picking_view.xml @@ -68,14 +68,8 @@ context="{'group_by': 'retrospect_ref'}"/> - - + + @@ -97,7 +91,8 @@ True - diff --git a/sf_message/models/sf_message_workorder.py b/sf_message/models/sf_message_workorder.py index 42b03139..5b73565e 100644 --- a/sf_message/models/sf_message_workorder.py +++ b/sf_message/models/sf_message_workorder.py @@ -191,7 +191,8 @@ class SFMessageWork(models.Model): def write(self, vals): res = super(SFMessageWork, self).write(vals) - if ('leave_id' in vals and vals['leave_id'] is False or 'date_planned_start' in vals and vals['date_planned_start'] is False) \ - and self.schedule_state != '未排': - self.add_queue('计划数据异常跟踪') + for record in self: + if ('leave_id' in vals and vals['leave_id'] is False or 'date_planned_start' in vals and vals['date_planned_start'] is False) \ + and record.schedule_state != '未排': + record.add_queue('计划数据异常跟踪') return res diff --git a/sf_mrs_connect/models/sync_common.py b/sf_mrs_connect/models/sync_common.py index cd0d8405..652ec3eb 100644 --- a/sf_mrs_connect/models/sync_common.py +++ b/sf_mrs_connect/models/sync_common.py @@ -3214,6 +3214,7 @@ class EmbryoRedundancySync(models.Model): embryo_redundancy.width = item['width'] embryo_redundancy.height = item['height'] embryo_redundancy.active = item['active'] + embryo_redundancy.remark = item['remark'] else: self.env['sf.embryo.redundancy'].sudo().create({ "name": item['name'], @@ -3222,4 +3223,5 @@ class EmbryoRedundancySync(models.Model): "width": item['width'], "height": item['height'], "active": item['active'], + "remark": item['remark'], }) \ No newline at end of file