From c2cb24c60b52f8eb6653649a61866562a83e0917 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Wed, 9 Jul 2025 11:38:40 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E9=9C=80=E6=B1=82=E8=AE=A1=E5=88=92?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_demand_plan/models/sf_demand_plan.py | 3 +-- sf_demand_plan/models/sf_production_demand_plan.py | 12 ++++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/sf_demand_plan/models/sf_demand_plan.py b/sf_demand_plan/models/sf_demand_plan.py index 63371dfd..83e890af 100644 --- a/sf_demand_plan/models/sf_demand_plan.py +++ b/sf_demand_plan/models/sf_demand_plan.py @@ -146,9 +146,8 @@ class SfDemandPlan(models.Model): for line in self: sum_plan_uom_qty = sum(line.line_ids.mapped('plan_uom_qty')) pending_qty = line.product_uom_qty - sum_plan_uom_qty - rounding = line.product_id.uom_id.rounding or 0.01 if float_compare(pending_qty, 0, - precision_rounding=rounding) == -1: + precision_rounding=line.product_id.uom_id.rounding) == -1: line.pending_qty = 0 else: line.pending_qty = pending_qty diff --git a/sf_demand_plan/models/sf_production_demand_plan.py b/sf_demand_plan/models/sf_production_demand_plan.py index a0b5bb92..4daa7ae3 100644 --- a/sf_demand_plan/models/sf_production_demand_plan.py +++ b/sf_demand_plan/models/sf_production_demand_plan.py @@ -28,10 +28,8 @@ class SfProductionDemandPlan(models.Model): ], string='状态', default='30', readonly=True) demand_plan_id = fields.Many2one(comodel_name="sf.demand.plan", string="物料需求", readonly=True) - sale_order_id = fields.Many2one(comodel_name="sale.order", related='demand_plan_id.sale_order_id', - string="销售订单", readonly=True) - sale_order_line_id = fields.Many2one(comodel_name="sale.order.line", related='demand_plan_id.sale_order_line_id', - string="销售订单明细", readonly=True) + sale_order_id = fields.Many2one(comodel_name="sale.order", string="销售订单", readonly=True) + sale_order_line_id = fields.Many2one(comodel_name="sale.order.line", string="销售订单明细", readonly=True) sale_order_line_number = fields.Char(string='销售订单行', compute='_compute_sale_order_line_number', store=True) company_id = fields.Many2one( related='sale_order_id.company_id', @@ -215,9 +213,8 @@ class SfProductionDemandPlan(models.Model): @api.depends('sale_order_line_id.qty_to_deliver') def _compute_qty_to_deliver(self): for line in self: - rounding = line.product_id.uom_id.rounding or 0.01 if float_compare(line.sale_order_line_id.qty_to_deliver, 0, - precision_rounding=rounding) == -1: + precision_rounding=line.product_id.uom_id.rounding) == -1: line.qty_to_deliver = 0 else: line.qty_to_deliver = line.sale_order_line_id.qty_to_deliver @@ -287,9 +284,8 @@ class SfProductionDemandPlan(models.Model): if record.mrp_production_ids and record.mrp_production_ids.move_raw_ids: total_reserved_availability = sum( record.mrp_production_ids.mapped('move_raw_ids.reserved_availability')) - rounding = record.product_id.uom_id.rounding or 0.01 if float_compare(total_reserved_availability, record.plan_uom_qty, - precision_rounding=rounding) >= 0: + precision_rounding=record.product_id.uom_id.rounding) >= 0: record.material_check = '1' # 已齐套 else: record.material_check = '0' # 未齐套 From acb6fd42cae4f322a54ee37c7631c98a1b6cf4e7 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Wed, 9 Jul 2025 16:46:46 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E9=87=87=E8=B4=AD=E6=98=8E=E7=BB=86?= =?UTF-8?q?=E5=8A=A0=E9=9C=80=E6=B1=82=E8=AE=A1=E5=88=92=E6=98=8E=E7=BB=86?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_demand_plan/models/purchase_order.py | 26 ++++--- sf_demand_plan/models/purchase_request.py | 85 ++--------------------- sf_demand_plan/models/sf_demand_plan.py | 10 +++ 3 files changed, 30 insertions(+), 91 deletions(-) diff --git a/sf_demand_plan/models/purchase_order.py b/sf_demand_plan/models/purchase_order.py index 5bc07313..b9802866 100644 --- a/sf_demand_plan/models/purchase_order.py +++ b/sf_demand_plan/models/purchase_order.py @@ -5,38 +5,42 @@ from odoo.tools import float_compare class PurchaseOrder(models.Model): _inherit = 'purchase.order' - demand_plan_line_id = fields.Many2one(comodel_name="sf.production.demand.plan", - string="需求计划明细", readonly=True) - def button_confirm(self): - if self.demand_plan_line_id: + if self.order_line[0].demand_plan_line_id: self = self.with_context( - demand_plan_line_id=self.demand_plan_line_id.id + demand_plan_line_id=self.order_line[0].demand_plan_line_id.id ) res = super(PurchaseOrder, self).button_confirm() return res - @api.depends('origin', 'demand_plan_line_id') + @api.depends('origin') def _compute_purchase_type(self): for purchase in self: if purchase.order_line[0].product_id.categ_id.name == '坯料': if purchase.order_line[0].product_id.materials_type_id.gain_way == '外协': purchase.purchase_type = 'outsourcing' else: - if purchase.demand_plan_line_id.supply_method == 'outsourcing': + if purchase.order_line[0].demand_plan_line_id.supply_method == 'outsourcing': purchase.purchase_type = 'outsourcing' - elif purchase.demand_plan_line_id.supply_method == 'purchase': + elif purchase.order_line[0].demand_plan_line_id.supply_method == 'purchase': purchase.purchase_type = 'outside' + +class PurchaseOrderLine(models.Model): + _inherit = 'purchase.order.line' + + demand_plan_line_id = fields.Many2one(comodel_name="sf.production.demand.plan", + string="需求计划明细", readonly=True) + @api.model def create(self, vals): - res = super(PurchaseOrder, self).create(vals) + res = super(PurchaseOrderLine, self).create(vals) if not res.demand_plan_line_id: - origin = [origin.replace(' ', '') for origin in res.origin.split(',')] + origin = [origin.replace(' ', '') for origin in res.order_id.origin.split(',')] if self.env.context.get('demand_plan_line_id'): res.demand_plan_line_id = self.env.context.get('demand_plan_line_id') - elif 'MO' in res.origin: + elif 'MO' in res.order_id.origin: # 原单据是制造订单 mp_ids = self.env['mrp.production'].sudo().search([('name', 'in', origin)]) if mp_ids: diff --git a/sf_demand_plan/models/purchase_request.py b/sf_demand_plan/models/purchase_request.py index 9cb15518..d1539976 100644 --- a/sf_demand_plan/models/purchase_request.py +++ b/sf_demand_plan/models/purchase_request.py @@ -28,83 +28,8 @@ class PurchaseRequestLine(models.Model): class PurchaseRequestLineMakePurchaseOrder(models.TransientModel): _inherit = "purchase.request.line.make.purchase.order" - def make_purchase_order(self): - res = [] - purchase_obj = self.env["purchase.order"] - po_line_obj = self.env["purchase.order.line"] - purchase = False - - if len(set([item_id.line_id.supply_method for item_id in self.item_ids])) > 1: - raise ValidationError('不同供货方式不可合并创建询价单!') - - for item in self.item_ids: - line = item.line_id - if item.product_qty <= 0.0: - raise UserError(_("Enter a positive quantity.")) - if self.purchase_order_id: - purchase = self.purchase_order_id - if not purchase: - po_data = self._prepare_purchase_order( - line.request_id.picking_type_id, - line.request_id.group_id, - line.company_id, - line.request_id.origin, - ) - po_data['demand_plan_line_id'] = item.line_id.demand_plan_line_id.id - # po_data.update({'related_product':line.related_product.id}) - purchase = purchase_obj.create(po_data) - - # Look for any other PO line in the selected PO with same - # product and UoM to sum quantities instead of creating a new - # po line - domain = self._get_order_line_search_domain(purchase, item) - available_po_lines = po_line_obj.search(domain) - new_pr_line = True - # If Unit of Measure is not set, update from wizard. - if not line.product_uom_id: - line.product_uom_id = item.product_uom_id - # Allocation UoM has to be the same as PR line UoM - alloc_uom = line.product_uom_id - wizard_uom = item.product_uom_id - if available_po_lines and not item.keep_description: - new_pr_line = False - po_line = available_po_lines[0] - po_line.purchase_request_lines = [(4, line.id)] - po_line.move_dest_ids |= line.move_dest_ids - po_line_product_uom_qty = po_line.product_uom._compute_quantity( - po_line.product_uom_qty, alloc_uom - ) - wizard_product_uom_qty = wizard_uom._compute_quantity( - item.product_qty, alloc_uom - ) - all_qty = min(po_line_product_uom_qty, wizard_product_uom_qty) - self.create_allocation(po_line, line, all_qty, alloc_uom) - else: - po_line_data = self._prepare_purchase_order_line(purchase, item) - if item.keep_description: - po_line_data["name"] = item.name - if line.related_product: - po_line_data.update({'related_product': line.related_product.id}) - po_line = po_line_obj.create(po_line_data) - po_line_product_uom_qty = po_line.product_uom._compute_quantity( - po_line.product_uom_qty, alloc_uom - ) - wizard_product_uom_qty = wizard_uom._compute_quantity( - item.product_qty, alloc_uom - ) - all_qty = min(po_line_product_uom_qty, wizard_product_uom_qty) - self.create_allocation(po_line, line, all_qty, alloc_uom) - self._post_process_po_line(item, po_line, new_pr_line) - res.append(purchase.id) - - purchase_requests = self.item_ids.mapped("request_id") - purchase_requests.button_in_progress() - return { - "domain": [("id", "in", res)], - "name": _("RFQ"), - "view_mode": "tree,form", - "res_model": "purchase.order", - "view_id": False, - "context": False, - "type": "ir.actions.act_window", - } + @api.model + def _prepare_purchase_order_line(self, po, item): + ret = super(PurchaseRequestLineMakePurchaseOrder, self)._prepare_purchase_order_line(po, item) + ret['demand_plan_line_id'] = item.line_id.demand_plan_line_id.id + return ret diff --git a/sf_demand_plan/models/sf_demand_plan.py b/sf_demand_plan/models/sf_demand_plan.py index 83e890af..864f8002 100644 --- a/sf_demand_plan/models/sf_demand_plan.py +++ b/sf_demand_plan/models/sf_demand_plan.py @@ -184,6 +184,16 @@ class SfDemandPlan(models.Model): lambda p: p.status in ('50', '60') and p.new_supply_method == 'custom_made') line.readonly_custom_made_type = bool(production_demand_plan) + def write(self, vals): + res = super(SfDemandPlan, self).write(vals) + if 'line_ids' in vals: + for line in self.line_ids: + if not line.sale_order_id: + line.sale_order_id = self.sale_order_id + if not line.sale_order_line_id: + line.sale_order_line_id = self.sale_order_line_id + return res + def name_get(self): result = [] for plan in self: From d02babaf0aaf54a708a0204abd0aa457d858de53 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Wed, 9 Jul 2025 16:57:20 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9C=80=E6=B1=82?= =?UTF-8?q?=E8=AE=A1=E5=88=92=E7=94=9F=E6=88=90=E7=9A=84bom=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E6=97=B6=E9=97=B4=E5=B0=918=E5=B0=8F=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_demand_plan/models/sf_demand_plan.py | 2 +- sf_demand_plan/models/sf_production_demand_plan.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sf_demand_plan/models/sf_demand_plan.py b/sf_demand_plan/models/sf_demand_plan.py index 864f8002..c873dd7b 100644 --- a/sf_demand_plan/models/sf_demand_plan.py +++ b/sf_demand_plan/models/sf_demand_plan.py @@ -197,7 +197,7 @@ class SfDemandPlan(models.Model): def name_get(self): result = [] for plan in self: - result.append((plan.id, plan.sale_order_id.name)) + result.append((plan.id, plan.product_id.name)) return result def button_production_release_plan(self): diff --git a/sf_demand_plan/models/sf_production_demand_plan.py b/sf_demand_plan/models/sf_production_demand_plan.py index 4daa7ae3..4428acce 100644 --- a/sf_demand_plan/models/sf_production_demand_plan.py +++ b/sf_demand_plan/models/sf_production_demand_plan.py @@ -686,9 +686,9 @@ class SfProductionDemandPlan(models.Model): # 复制成品模板上的属性 self.product_id.product_tmpl_id.copy_template(product_template_id) - + future_time = datetime.now() + timedelta(hours=8) # 生成BOM单据编码 - code = f"{self.product_id.default_code}-{bom_type}-{datetime.now().strftime('%Y%m%d%H%M%S')}" + code = f"{self.product_id.default_code}-{bom_type}-{future_time.strftime('%Y%m%d%H%M%S')}" order_id = self.sale_order_id product = self.product_id From 7b4499184d27ed25d3cf306713c9f8081463d91e Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 9 Jul 2025 16:58:20 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=A6=81=E6=AD=A2?= =?UTF-8?q?=E8=B4=9F=E5=BA=93=E5=AD=98=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_warehouse/__manifest__.py | 1 + sf_warehouse/models/__init__.py | 1 + sf_warehouse/models/model.py | 22 +++++++++++++--------- sf_warehouse/models/product.py | 29 +++++++++++++++++++++++++++++ sf_warehouse/views/product.xml | 17 +++++++++++++++++ 5 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 sf_warehouse/models/product.py create mode 100644 sf_warehouse/views/product.xml diff --git a/sf_warehouse/__manifest__.py b/sf_warehouse/__manifest__.py index 456d3b96..28f6434e 100644 --- a/sf_warehouse/__manifest__.py +++ b/sf_warehouse/__manifest__.py @@ -16,6 +16,7 @@ # 'security/sf_stock_security.xml', 'security/ir.model.access.csv', 'wizard/wizard_view.xml', + 'views/product.xml', 'views/view.xml', 'views/shelf_location.xml', 'views/change_stock_move_views.xml', diff --git a/sf_warehouse/models/__init__.py b/sf_warehouse/models/__init__.py index 72b9b610..9035056a 100644 --- a/sf_warehouse/models/__init__.py +++ b/sf_warehouse/models/__init__.py @@ -1,2 +1,3 @@ from . import model from . import sync_common +from . import product diff --git a/sf_warehouse/models/model.py b/sf_warehouse/models/model.py index 2cb35264..74daafb4 100644 --- a/sf_warehouse/models/model.py +++ b/sf_warehouse/models/model.py @@ -471,7 +471,7 @@ class ShelfLocation(models.Model): record.display_rfid = record.product_sn_id.rfid if record.product_sn_id else '' except Exception as e: record.display_rfid = '' - + @api.depends('product_id') def _compute_tool(self): """计算工具 RFID""" @@ -594,7 +594,7 @@ class ShelfLocation(models.Model): _layer_capacity = _cc_code % record.shelf_id.layer_capacity if _layer_capacity == 0: _layer_capacity = record.shelf_id.layer_capacity - else: + else: _layer_capacity = _layer_capacity _layer = _layer+1 _layer_capacity = f"{_layer_capacity:02d}" @@ -634,7 +634,7 @@ class SfShelfLocationLot(models.Model): for item in self: if item.qty_num > item.qty: raise ValidationError('变更数量不能比库存数量大!!!') - + class SfStockMoveLine(models.Model): @@ -899,7 +899,7 @@ class SfStockMoveLine(models.Model): def _compute_current_location_id(self): # 批量获取所有相关记录的picking pickings = self.mapped('picking_id') - + # 构建源picking的移库行与目标位置的映射 origin_location_map = {} for picking in pickings: @@ -907,11 +907,11 @@ class SfStockMoveLine(models.Model): origin_move = picking.move_ids[:1].move_orig_ids[:1] if not origin_move: continue - + origin_picking = origin_move.picking_id if not origin_picking: continue - + # 为每个picking构建lot_id到location的映射 origin_location_map[picking.id] = { move_line.lot_id.id: move_line.destination_location_id @@ -919,17 +919,17 @@ class SfStockMoveLine(models.Model): lambda ml: ml.destination_location_id and ml.lot_id ) } - + # 批量更新current_location_id for record in self: current_picking = record.picking_id if not current_picking: record.current_location_id = False continue - + # 获取当前picking对应的lot_location映射 lot_dest_map = origin_location_map.get(current_picking.id, {}) - + # 查找匹配的lot_id for move_line in current_picking.move_line_ids: if move_line.lot_id and move_line.lot_id.id in lot_dest_map: @@ -1082,6 +1082,10 @@ class SfStockPicking(models.Model): 重写验证方法,当验证时意味着调拨单已经完成,已经移动到了目标货位,所以需要将当前货位的状态改为空闲 """ res = super(SfStockPicking, self).button_validate() + if any(ml.state == 'done' for ml in self.move_line_ids): + # 验证产品库存为负库存问题 + self.move_ids.product_id.verify_product_repertory(self.location_id) + for line in self.move_line_ids: if line: if line.destination_location_id: diff --git a/sf_warehouse/models/product.py b/sf_warehouse/models/product.py new file mode 100644 index 00000000..a0839512 --- /dev/null +++ b/sf_warehouse/models/product.py @@ -0,0 +1,29 @@ +from odoo import models, fields +from odoo.exceptions import ValidationError + + +class SfProductCategory(models.Model): + _inherit = 'product.category' + + negative_inventory_allowed = fields.Boolean('可负库存', default=True) + + +class SfProductTemplate(models.Model): + _inherit = 'product.product' + + def verify_product_repertory(self, location_id): + """ + 验证产品 负库存 + """ + if not location_id: + raise ValidationError('当前位置为空!!') + elif len(location_id) != 1: + raise ValidationError(f'存在多个当前位置{[item.name for item in location_id]}') + elif location_id.usage == 'supplier': + return True + for pp in self: + if not pp.categ_id.negative_inventory_allowed: + sq = pp.stock_quant_ids.filtered(lambda sq: sq.quantity < 0 and sq.location_id == location_id) + if sq: + raise ValidationError( + f'产品{pp.name}的产品类型设置为不可负库存,当前操作会导致产品{pp.name}在库存{location_id.name}上的库存数量为负!!!') diff --git a/sf_warehouse/views/product.xml b/sf_warehouse/views/product.xml new file mode 100644 index 00000000..3844b94c --- /dev/null +++ b/sf_warehouse/views/product.xml @@ -0,0 +1,17 @@ + + + + product.category.property.form.warehouse + product.category + + + + + + + + + + + + \ No newline at end of file From 4d2ab82645f6aee54aa4d857206830b3ea30cb85 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Thu, 10 Jul 2025 08:57:38 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=87=87=E8=B4=AD?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=A0=B9=E6=8D=AE=E4=BE=9B=E8=B4=A7=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=E6=9D=A5=E8=B5=8B=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_dlm/models/stock_rule_inherit.py | 88 ++++++++++++++--------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/sf_dlm/models/stock_rule_inherit.py b/sf_dlm/models/stock_rule_inherit.py index 4d715196..0051a42f 100644 --- a/sf_dlm/models/stock_rule_inherit.py +++ b/sf_dlm/models/stock_rule_inherit.py @@ -6,50 +6,50 @@ from odoo import models, fields, api, _ class StockRuleInherit(models.Model): _inherit = 'stock.rule' - @api.model - def _run_buy(self, procurements): - # 判断补货组的采购类型 - procurements_group = {'standard': [], 'outsourcing': []} - for procurement, rule in procurements: - is_outsourcing = False - product = procurement.product_id - # 获取主 BOM - bom = self.env['mrp.bom'].search([('product_tmpl_id', '=', product.product_tmpl_id.id)], limit=1) - - if bom: - # 遍历 BOM 中的组件(即坯料等) - for line in bom.bom_line_ids: - raw_material = line.product_id - # 检查路线 - for route in raw_material.route_ids: - # print('route.name:', route.name) - if route.name == '按订单补给外包商': - is_outsourcing = True - - if is_outsourcing: - procurements_group['outsourcing'].append((procurement, rule)) - else: - procurements_group['standard'].append((procurement, rule)) - - for key, value in procurements_group.items(): - super(StockRuleInherit, self)._run_buy(value) - - if key == 'outsourcing': - for procurement, rule in value: - supplier = procurement.values.get('supplier') - if supplier: - domain = rule._make_po_get_domain(procurement.company_id, procurement.values, - supplier.partner_id) - logging.info("domain=============: %s", domain) - po = self.env['purchase.order'].sudo().search([ - ('partner_id', '=', supplier.partner_id.id), - ('company_id', '=', procurement.company_id.id), # 保证公司一致 - ('origin', 'like', procurement.origin), # 根据来源匹配 - ('state', '=', 'draft') # 状态为草稿 - ], limit=1) - logging.info("po=: %s", po) - if po: - po.write({'purchase_type': 'outsourcing'}) + # @api.model + # def _run_buy(self, procurements): + # # 判断补货组的采购类型 + # procurements_group = {'standard': [], 'outsourcing': []} + # for procurement, rule in procurements: + # is_outsourcing = False + # product = procurement.product_id + # # 获取主 BOM + # bom = self.env['mrp.bom'].search([('product_tmpl_id', '=', product.product_tmpl_id.id)], limit=1) + # + # if bom: + # # 遍历 BOM 中的组件(即坯料等) + # for line in bom.bom_line_ids: + # raw_material = line.product_id + # # 检查路线 + # for route in raw_material.route_ids: + # # print('route.name:', route.name) + # if route.name == '按订单补给外包商': + # is_outsourcing = True + # + # if is_outsourcing: + # procurements_group['outsourcing'].append((procurement, rule)) + # else: + # procurements_group['standard'].append((procurement, rule)) + # + # for key, value in procurements_group.items(): + # super(StockRuleInherit, self)._run_buy(value) + # + # if key == 'outsourcing': + # for procurement, rule in value: + # supplier = procurement.values.get('supplier') + # if supplier: + # domain = rule._make_po_get_domain(procurement.company_id, procurement.values, + # supplier.partner_id) + # logging.info("domain=============: %s", domain) + # po = self.env['purchase.order'].sudo().search([ + # ('partner_id', '=', supplier.partner_id.id), + # ('company_id', '=', procurement.company_id.id), # 保证公司一致 + # ('origin', 'like', procurement.origin), # 根据来源匹配 + # ('state', '=', 'draft') # 状态为草稿 + # ], limit=1) + # logging.info("po=: %s", po) + # if po: + # po.write({'purchase_type': 'outsourcing'}) # # 首先调用父类的 _run_buy 方法,以保留原有逻辑 # super(StockRuleInherit, self)._run_buy(procurements) From 1f93ba3b42626896d4e053cd02e543374f628478 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Thu, 10 Jul 2025 14:11:31 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9C=AA=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E9=9C=80=E6=B1=82=E8=AE=A1=E5=88=92=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=98=8E=E7=BB=86=E8=A1=8C=E9=97=AE=E9=A2=98,=E6=89=93?= =?UTF-8?q?=E5=8D=B0=E5=88=97=E8=A1=A8=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_demand_plan/models/sale_order.py | 4 +- sf_demand_plan/models/sf_demand_plan.py | 10 +++- .../models/sf_production_demand_plan.py | 18 ++++---- sf_demand_plan/views/demand_plan_info.xml | 40 ++++++++++++++-- .../wizard/sf_demand_plan_print_wizard.py | 46 ++++++++----------- 5 files changed, 76 insertions(+), 42 deletions(-) diff --git a/sf_demand_plan/models/sale_order.py b/sf_demand_plan/models/sale_order.py index fe8966a6..149fadfe 100644 --- a/sf_demand_plan/models/sale_order.py +++ b/sf_demand_plan/models/sale_order.py @@ -11,7 +11,7 @@ class ReSaleOrder(models.Model): groups='mrp.group_mrp_user', store=True) demand_plan_ids = fields.Many2many(comodel_name="sf.demand.plan", - string="需求计划", readonly=True) + string="需求计划", readonly=True) demand_plan_count = fields.Integer( string="需求计划生成计数", @@ -47,9 +47,9 @@ class ReSaleOrder(models.Model): if demand_plan.product_id.machining_drawings_name: filename_url = demand_plan.product_id.machining_drawings_name.rsplit('.', 1)[0] wizard_vals = { - 'demand_plan_id': demand_plan.id, 'model_id': demand_plan.model_id, 'filename_url': filename_url, + 'machining_drawings': product.machining_drawings, 'type': '1', } self.env['sf.demand.plan.print.wizard'].sudo().create(wizard_vals) diff --git a/sf_demand_plan/models/sf_demand_plan.py b/sf_demand_plan/models/sf_demand_plan.py index c873dd7b..7707eec3 100644 --- a/sf_demand_plan/models/sf_demand_plan.py +++ b/sf_demand_plan/models/sf_demand_plan.py @@ -167,7 +167,9 @@ class SfDemandPlan(models.Model): def _compute_state(self): for line in self: status_line = line.line_ids.filtered(lambda p: p.status == '60') - if line.sale_order_id.state == 'cancel': + if not line.line_ids: + line.state = '10' + elif line.sale_order_id.state == 'cancel': line.state = '50' line.line_ids.status = '100' elif len(line.line_ids) == len(status_line): @@ -184,6 +186,12 @@ class SfDemandPlan(models.Model): lambda p: p.status in ('50', '60') and p.new_supply_method == 'custom_made') line.readonly_custom_made_type = bool(production_demand_plan) + @api.constrains('line_ids') + def check_line_ids(self): + for item in self: + if not item.line_ids: + raise ValidationError('计划不能为空!') + def write(self, vals): res = super(SfDemandPlan, self).write(vals) if 'line_ids' in vals: diff --git a/sf_demand_plan/models/sf_production_demand_plan.py b/sf_demand_plan/models/sf_production_demand_plan.py index 4428acce..9f5d17f4 100644 --- a/sf_demand_plan/models/sf_production_demand_plan.py +++ b/sf_demand_plan/models/sf_production_demand_plan.py @@ -56,7 +56,7 @@ class SfProductionDemandPlan(models.Model): custom_made_type = fields.Selection([ ('automation', "自动化产线加工"), ('manual', "人工线下加工"), - ], string='自制类型', compute='_compute_custom_made_type', store=True) + ], string='产线类型', compute='_compute_custom_made_type', store=True) supply_method = fields.Selection([ ('automation', "自动化产线加工"), @@ -360,11 +360,12 @@ class SfProductionDemandPlan(models.Model): return action def button_action_print(self): + model_id = self.mapped('model_id') return { 'res_model': 'sf.demand.plan.print.wizard', 'type': 'ir.actions.act_window', 'name': _("打印"), - 'domain': [('demand_plan_id', 'in', self.ids)], + 'domain': [('model_id', 'in', model_id)], 'views': [[self.env.ref('sf_demand_plan.action_plan_print_tree').id, 'list']], 'target': 'new', } @@ -577,12 +578,13 @@ class SfProductionDemandPlan(models.Model): # programming_no = list(set(programming_mrp_production_ids)) # numbers_str = "、".join(programming_no) # raise ValidationError(f"编程单号:{numbers_str},请去云平台处理") - - def button_delete(self): - self.ensure_one() - if len(self.demand_plan_id.line_ids) == 1: - raise ValidationError(f"最后一条计划,不能删除!") - self.unlink() + @api.model + def unlink(self): + for item in self: + if item.status not in ('10', '20', '30'): + raise ValidationError(u'只能删除状态为【草稿,待确认,需求确认】的需求计划。') + else: + super(SfProductionDemandPlan, item).unlink() def button_batch_release_plan(self): filtered_plan = self.filtered(lambda mo: mo.status == '30') diff --git a/sf_demand_plan/views/demand_plan_info.xml b/sf_demand_plan/views/demand_plan_info.xml index 74d9f213..13718b51 100644 --- a/sf_demand_plan/views/demand_plan_info.xml +++ b/sf_demand_plan/views/demand_plan_info.xml @@ -39,8 +39,8 @@ - - + + @@ -51,6 +51,7 @@ + @@ -69,10 +70,39 @@ class="btn-primary" attrs="{'invisible': [('hide_release_production_order', '=', False)]}" /> -