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