# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import fields, models, api class PurchaseOrder(models.Model): _inherit = 'purchase.order' # Field to link purchase order to inventory moves subcontracting_move_ids = fields.Many2many( 'stock.move', string='Subcontracting Inventory Moves', relation='purchase_order_stock_move_subcontract_rel', column1='purchase_order_id', column2='stock_move_id', help='Inventory moves linked to this purchase order for subcontracting' ) # Computed field to show count of linked inventory moves for smart button subcontracting_move_count = fields.Integer( string='Subcontracting Moves Count', compute='_compute_subcontracting_move_count' ) @api.depends('subcontracting_move_ids') def _compute_subcontracting_move_count(self): for order in self: order.subcontracting_move_count = len(order.subcontracting_move_ids) def action_link_subcontracting_moves(self): """Action to link existing inventory moves to this purchase order""" self.ensure_one() return { 'name': 'Link Subcontracting Inventory Moves', 'type': 'ir.actions.act_window', 'view_mode': 'list', 'res_model': 'stock.move', 'domain': [ ('location_dest_id.name', '=', 'Subcontracting Location'), ('purchase_order_id', '=', False), ('state', 'in', ['done']), ], 'target': 'new', 'context': { 'default_purchase_order_id': self.id, }, 'views': [ (self.env.ref('subcontracting_inventory_move_first.view_stock_move_link_subcontracting_tree').id, 'list') ], 'limit': 1, } def action_view_subcontracting_moves(self): """Action to view linked subcontracting inventory moves""" self.ensure_one() action = { 'name': 'Subcontracting Inventory Moves', 'type': 'ir.actions.act_window', 'view_mode': 'list,form', 'res_model': 'stock.move', 'domain': [('id', 'in', self.subcontracting_move_ids.ids)], 'context': {'create': False} } if len(self.subcontracting_move_ids) == 1: action['views'] = [(False, 'form')] action['res_id'] = self.subcontracting_move_ids.id return action def link_selected_subcontracting_move(self, move_id): """Method to link a selected subcontracting move to this purchase order""" self.ensure_one() move = self.env['stock.move'].browse(move_id) if move and move.exists() and not move.purchase_order_id: # Link the move to this purchase order move.write({ 'purchase_order_id': self.id, 'origin': self.name # Update source document to purchase order number }) # Also update the related stock.picking if it exists if move.picking_id: move.picking_id.write({ 'origin': self.name, # Note: stock.picking doesn't have a purchase_order_id field, so we can't link it directly }) # Also add to the Many2many field current_moves = self.subcontracting_move_ids.ids current_moves.append(move.id) self.write({'subcontracting_move_ids': [(6, 0, current_moves)]}) return True return False @api.model_create_multi def create(self, vals_list): """Override create to handle linking with inventory moves if provided""" # Create the purchase orders first using the parent method orders = super().create(vals_list) # Process subcontracting moves linking for each created order for order, vals in zip(orders, vals_list): subcontracting_move_ids = vals.get('subcontracting_move_ids') # If subcontracting moves were provided, link them if subcontracting_move_ids: # Process the commands in the Many2many field for command in subcontracting_move_ids: if command[0] == 6: # Replace all move_ids = command[2] moves = self.env['stock.move'].browse(move_ids) moves.write({'purchase_order_id': order.id}) elif command[0] == 4: # Add one move_id = command[1] move = self.env['stock.move'].browse(move_id) move.write({'purchase_order_id': order.id}) return orders def write(self, vals): """Override write to handle linking/unlinking of inventory moves""" # Handle subcontracting moves linking/unlinking if 'subcontracting_move_ids' in vals: # Get current linked moves before the update old_moves = self.subcontracting_move_ids # Call super to update the record result = super().write(vals) # Update the purchase_order_id on the linked moves for order in self: # Unlink old moves that are no longer linked moves_to_unlink = old_moves - order.subcontracting_move_ids moves_to_unlink.write({'purchase_order_id': False}) # Link new moves moves_to_link = order.subcontracting_move_ids - old_moves moves_to_link.write({'purchase_order_id': order.id}) else: result = super().write(vals) return result def button_confirm(self): """Override to handle subcontracting moves when confirming purchase order""" # First call the original confirm method result = super().button_confirm() # For each linked subcontracting move, potentially trigger additional actions for order in self: for move in order.subcontracting_move_ids: # When the purchase order is confirmed, we may want to update the move's state # or trigger the standard subcontracting flow for these moves if move.state in ['draft', 'waiting']: # Confirm the linked moves if they're not already confirmed if move.state == 'draft': move._action_confirm() # Assign them if needed if move.state in ['confirmed', 'waiting']: move._action_assign() return result def button_cancel(self): """Override to handle subcontracting moves when cancelling purchase order""" # For each linked subcontracting move, we may need to unlink or update them for order in self: # Unlink moves if needed based on business requirements # Here we'll keep the moves but remove the purchase order link order.subcontracting_move_ids.write({'purchase_order_id': False}) # Then call the original cancel method return super().button_cancel()