fix some bug regarding the groups in xml view
This commit is contained in:
parent
3697d7f785
commit
c92a3b0291
84
README.md
84
README.md
@ -1,43 +1,43 @@
|
||||
# Subcontracting Inventory Move First
|
||||
|
||||
## Overview
|
||||
This module extends the standard Odoo subcontracting workflow to allow creating inventory moves first and then linking them to purchase orders, rather than the standard flow where purchase orders create inventory moves.
|
||||
|
||||
## Features
|
||||
- Create "Resupply Subcontract" inventory moves directly in the inventory module
|
||||
- Link these moves to purchase orders after creation
|
||||
- Smart button on purchase orders to view linked inventory moves
|
||||
- Maintain data consistency between moves and purchase orders
|
||||
- Update source document field in inventory moves and related stock pickings to show purchase order number
|
||||
- Proper handling of purchase order cancellation to unlink moves
|
||||
|
||||
## Usage
|
||||
|
||||
### Creating Subcontracting Inventory Moves First
|
||||
1. Navigate to Inventory > Operations > Transfers
|
||||
2. Create a new transfer with operation type "Resupply Subcontractor"
|
||||
3. The inventory move will be created without being linked to a purchase order initially
|
||||
|
||||
### Linking to Purchase Orders
|
||||
1. Go to the purchase order you want to link
|
||||
2. Click the "Link Subcontracting Moves" button
|
||||
3. Select the appropriate inventory moves from the list
|
||||
4. Click the "Link to Purchase Order" button at the top of the list view to confirm linking
|
||||
5. The moves will be linked to the purchase order and source document fields updated
|
||||
|
||||
### Viewing Linked Moves
|
||||
1. On any purchase order form, the smart button "Subcontracting Moves" will show the count of linked moves
|
||||
2. Click the button to view and manage all linked inventory moves
|
||||
|
||||
## Technical Details
|
||||
- The module adds a `purchase_order_id` field to `stock.move` to track links to purchase orders
|
||||
- The module adds a `subcontracting_move_ids` field to `purchase.order` to track linked moves
|
||||
- Business logic ensures data consistency when linking/unlinking moves and orders
|
||||
- When linking moves to purchase orders, the source document field is updated to show the purchase order number
|
||||
- When linking moves to purchase orders, the source document field in related stock pickings is also updated
|
||||
- Proper handling of purchase order cancellation to unlink moves without errors
|
||||
|
||||
## Compatibility
|
||||
- Compatible with Odoo 18.0
|
||||
- Works alongside standard subcontracting workflow
|
||||
# Subcontracting Inventory Move First
|
||||
|
||||
## Overview
|
||||
This module extends the standard Odoo subcontracting workflow to allow creating inventory moves first and then linking them to purchase orders, rather than the standard flow where purchase orders create inventory moves.
|
||||
|
||||
## Features
|
||||
- Create "Resupply Subcontract" inventory moves directly in the inventory module
|
||||
- Link these moves to purchase orders after creation
|
||||
- Smart button on purchase orders to view linked inventory moves
|
||||
- Maintain data consistency between moves and purchase orders
|
||||
- Update source document field in inventory moves and related stock pickings to show purchase order number
|
||||
- Proper handling of purchase order cancellation to unlink moves
|
||||
|
||||
## Usage
|
||||
|
||||
### Creating Subcontracting Inventory Moves First
|
||||
1. Navigate to Inventory > Operations > Transfers
|
||||
2. Create a new transfer with operation type "Resupply Subcontractor"
|
||||
3. The inventory move will be created without being linked to a purchase order initially
|
||||
|
||||
### Linking to Purchase Orders
|
||||
1. Go to the purchase order you want to link
|
||||
2. Click the "Link Subcontracting Moves" button
|
||||
3. Select the appropriate inventory moves from the list
|
||||
4. Click the "Link to Purchase Order" button at the top of the list view to confirm linking
|
||||
5. The moves will be linked to the purchase order and source document fields updated
|
||||
|
||||
### Viewing Linked Moves
|
||||
1. On any purchase order form, the smart button "Subcontracting Moves" will show the count of linked moves
|
||||
2. Click the button to view and manage all linked inventory moves
|
||||
|
||||
## Technical Details
|
||||
- The module adds a `purchase_order_id` field to `stock.move` to track links to purchase orders
|
||||
- The module adds a `subcontracting_move_ids` field to `purchase.order` to track linked moves
|
||||
- Business logic ensures data consistency when linking/unlinking moves and orders
|
||||
- When linking moves to purchase orders, the source document field is updated to show the purchase order number
|
||||
- When linking moves to purchase orders, the source document field in related stock pickings is also updated
|
||||
- Proper handling of purchase order cancellation to unlink moves without errors
|
||||
|
||||
## Compatibility
|
||||
- Compatible with Odoo 18.0
|
||||
- Works alongside standard subcontracting workflow
|
||||
- Depends on: mrp_subcontracting, purchase, stock, mrp_subcontracting_purchase
|
||||
@ -1,26 +1,26 @@
|
||||
{
|
||||
'name': 'Subcontracting Inventory Move First',
|
||||
'version': '18.0.1.0.0',
|
||||
'category': 'Manufacturing/Manufacturing',
|
||||
'summary': 'Allow creating inventory moves first and then linking to purchase orders in subcontracting',
|
||||
'author' : "Suherdy Yacob",
|
||||
'description': """
|
||||
This module extends the standard subcontracting workflow to allow creating
|
||||
inventory moves first and then linking them to purchase orders,
|
||||
rather than the standard flow where purchase orders create inventory moves.
|
||||
""",
|
||||
'depends': [
|
||||
'mrp_subcontracting',
|
||||
'purchase',
|
||||
'stock',
|
||||
'mrp_subcontracting_purchase',
|
||||
],
|
||||
'data': [
|
||||
'views/stock_move_views.xml',
|
||||
'views/stock_move_link_views.xml',
|
||||
'views/purchase_order_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'license': 'LGPL-3',
|
||||
{
|
||||
'name': 'Subcontracting Inventory Move First',
|
||||
'version': '18.0.1.0.0',
|
||||
'category': 'Manufacturing/Manufacturing',
|
||||
'summary': 'Allow creating inventory moves first and then linking to purchase orders in subcontracting',
|
||||
'author' : "Suherdy Yacob",
|
||||
'description': """
|
||||
This module extends the standard subcontracting workflow to allow creating
|
||||
inventory moves first and then linking them to purchase orders,
|
||||
rather than the standard flow where purchase orders create inventory moves.
|
||||
""",
|
||||
'depends': [
|
||||
'mrp_subcontracting',
|
||||
'purchase',
|
||||
'stock',
|
||||
'mrp_subcontracting_purchase',
|
||||
],
|
||||
'data': [
|
||||
'views/stock_move_views.xml',
|
||||
'views/stock_move_link_views.xml',
|
||||
'views/purchase_order_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
BIN
__pycache__/__init__.cpython-310.pyc
Normal file
BIN
__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
@ -1,2 +1,2 @@
|
||||
from . import stock_move
|
||||
from . import stock_move
|
||||
from . import purchase_order
|
||||
BIN
models/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
models/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/purchase_order.cpython-310.pyc
Normal file
BIN
models/__pycache__/purchase_order.cpython-310.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
models/__pycache__/stock_move.cpython-310.pyc
Normal file
BIN
models/__pycache__/stock_move.cpython-310.pyc
Normal file
Binary file not shown.
@ -1,172 +1,173 @@
|
||||
# -*- 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
|
||||
def create(self, vals):
|
||||
"""Override create to handle linking with inventory moves if provided"""
|
||||
# Extract subcontracting moves from vals if they exist
|
||||
subcontracting_move_ids = vals.get('subcontracting_move_ids')
|
||||
|
||||
# Create the purchase order first
|
||||
purchase_order = super().create(vals)
|
||||
|
||||
# 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': purchase_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': purchase_order.id})
|
||||
|
||||
return purchase_order
|
||||
|
||||
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
|
||||
# -*- 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()
|
||||
@ -1,104 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, api
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
# Field to link inventory move to a purchase order
|
||||
purchase_order_id = fields.Many2one(
|
||||
'purchase.order',
|
||||
string='Linked Purchase Order',
|
||||
ondelete='set null',
|
||||
help='Purchase order linked to this subcontracting inventory move'
|
||||
)
|
||||
|
||||
# Computed field to show count of linked purchase orders for smart button
|
||||
linked_purchase_order_count = fields.Integer(
|
||||
string='Linked Purchase Orders Count',
|
||||
compute='_compute_linked_purchase_order_count'
|
||||
)
|
||||
|
||||
@api.depends('purchase_order_id')
|
||||
def _compute_linked_purchase_order_count(self):
|
||||
for move in self:
|
||||
move.linked_purchase_order_count = 1 if move.purchase_order_id else 0
|
||||
|
||||
def action_view_linked_purchase_order(self):
|
||||
"""Action to view the linked purchase order from the inventory move"""
|
||||
self.ensure_one()
|
||||
if self.purchase_order_id:
|
||||
return {
|
||||
'name': 'Linked Purchase Order',
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'purchase.order',
|
||||
'res_id': self.purchase_order_id.id,
|
||||
'target': 'current',
|
||||
}
|
||||
return {
|
||||
'name': 'Create Purchase Order',
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'purchase.order',
|
||||
'context': {
|
||||
'default_order_line': [(0, 0, {
|
||||
'product_id': self.product_id.id,
|
||||
'product_qty': self.product_uom_qty,
|
||||
'product_uom': self.product_uom.id,
|
||||
})],
|
||||
},
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def _action_confirm(self, merge=True, merge_into=False):
|
||||
"""Override to handle our custom subcontracting flow"""
|
||||
# Call the super method first to maintain standard functionality
|
||||
result = super()._action_confirm(merge=merge, merge_into=merge_into)
|
||||
|
||||
# For moves that are subcontracting related but not linked to purchase orders yet
|
||||
# we want to allow them to exist in the system without creating manufacturing orders immediately
|
||||
for move in self:
|
||||
if move.is_subcontract and not move.purchase_order_id:
|
||||
# This is a move created first without a purchase order - allow it to exist
|
||||
# We don't want to trigger the standard subcontracting flow here
|
||||
# Prevent creating MOs for moves that are not linked to a purchase order yet
|
||||
continue
|
||||
|
||||
return result
|
||||
|
||||
def _action_assign(self):
|
||||
"""Override to handle custom subcontracting flow"""
|
||||
# For moves that are subcontracting but not linked to purchase orders yet,
|
||||
# we may want to handle them differently
|
||||
subcontract_moves_without_po = self.filtered(lambda m: m.is_subcontract and not m.purchase_order_id)
|
||||
other_moves = self - subcontract_moves_without_po
|
||||
|
||||
# Process other moves normally
|
||||
if other_moves:
|
||||
super(StockMove, other_moves)._action_assign()
|
||||
|
||||
# For subcontract moves without PO, we can decide how to handle them
|
||||
# For now, just call the super method
|
||||
if subcontract_moves_without_po:
|
||||
super(StockMove, subcontract_moves_without_po)._action_assign()
|
||||
|
||||
return True
|
||||
|
||||
def write(self, values):
|
||||
"""Override write to handle purchase order linking"""
|
||||
# If we're linking a purchase order to a move, update the reverse link
|
||||
if 'purchase_order_id' in values:
|
||||
purchase_order = self.env['purchase.order'].browse(values['purchase_order_id'])
|
||||
if purchase_order.exists():
|
||||
# Add this move to the purchase order's subcontracting moves
|
||||
for move in self:
|
||||
if move.is_subcontract and move not in purchase_order.subcontracting_move_ids:
|
||||
# Add to the existing list of moves
|
||||
current_moves = purchase_order.subcontracting_move_ids.ids
|
||||
current_moves.append(move.id)
|
||||
purchase_order.write({'subcontracting_move_ids': [(6, 0, current_moves)]})
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, api
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
# Field to link inventory move to a purchase order
|
||||
purchase_order_id = fields.Many2one(
|
||||
'purchase.order',
|
||||
string='Linked Purchase Order',
|
||||
ondelete='set null',
|
||||
help='Purchase order linked to this subcontracting inventory move'
|
||||
)
|
||||
|
||||
# Computed field to show count of linked purchase orders for smart button
|
||||
linked_purchase_order_count = fields.Integer(
|
||||
string='Linked Purchase Orders Count',
|
||||
compute='_compute_linked_purchase_order_count'
|
||||
)
|
||||
|
||||
@api.depends('purchase_order_id')
|
||||
def _compute_linked_purchase_order_count(self):
|
||||
for move in self:
|
||||
move.linked_purchase_order_count = 1 if move.purchase_order_id else 0
|
||||
|
||||
def action_view_linked_purchase_order(self):
|
||||
"""Action to view the linked purchase order from the inventory move"""
|
||||
self.ensure_one()
|
||||
if self.purchase_order_id:
|
||||
return {
|
||||
'name': 'Linked Purchase Order',
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'purchase.order',
|
||||
'res_id': self.purchase_order_id.id,
|
||||
'target': 'current',
|
||||
}
|
||||
return {
|
||||
'name': 'Create Purchase Order',
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'purchase.order',
|
||||
'context': {
|
||||
'default_order_line': [(0, 0, {
|
||||
'product_id': self.product_id.id,
|
||||
'product_qty': self.product_uom_qty,
|
||||
'product_uom': self.product_uom.id,
|
||||
})],
|
||||
},
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def _action_confirm(self, merge=True, merge_into=False):
|
||||
"""Override to handle our custom subcontracting flow"""
|
||||
# Call the super method first to maintain standard functionality
|
||||
result = super()._action_confirm(merge=merge, merge_into=merge_into)
|
||||
|
||||
# For moves that are subcontracting related but not linked to purchase orders yet
|
||||
# we want to allow them to exist in the system without creating manufacturing orders immediately
|
||||
for move in self:
|
||||
if move.is_subcontract and not move.purchase_order_id:
|
||||
# This is a move created first without a purchase order - allow it to exist
|
||||
# We don't want to trigger the standard subcontracting flow here
|
||||
# Prevent creating MOs for moves that are not linked to a purchase order yet
|
||||
continue
|
||||
|
||||
return result
|
||||
|
||||
def _action_assign(self):
|
||||
"""Override to handle custom subcontracting flow"""
|
||||
# For moves that are subcontracting but not linked to purchase orders yet,
|
||||
# we may want to handle them differently
|
||||
subcontract_moves_without_po = self.filtered(lambda m: m.is_subcontract and not m.purchase_order_id)
|
||||
other_moves = self - subcontract_moves_without_po
|
||||
|
||||
# Process other moves normally
|
||||
if other_moves:
|
||||
super(StockMove, other_moves)._action_assign()
|
||||
|
||||
# For subcontract moves without PO, we can decide how to handle them
|
||||
# For now, just call the super method
|
||||
if subcontract_moves_without_po:
|
||||
super(StockMove, subcontract_moves_without_po)._action_assign()
|
||||
|
||||
return True
|
||||
|
||||
def write(self, values):
|
||||
"""Override write to handle purchase order linking"""
|
||||
# If we're linking a purchase order to a move, update the reverse link
|
||||
if 'purchase_order_id' in values:
|
||||
purchase_order = self.env['purchase.order'].browse(values['purchase_order_id'])
|
||||
if purchase_order.exists():
|
||||
# Add this move to the purchase order's subcontracting moves
|
||||
for move in self:
|
||||
if move.is_subcontract and move not in purchase_order.subcontracting_move_ids:
|
||||
# Add to the existing list of moves
|
||||
current_moves = purchase_order.subcontracting_move_ids.ids
|
||||
current_moves.append(move.id)
|
||||
purchase_order.write({'subcontracting_move_ids': [(6, 0, current_moves)]})
|
||||
|
||||
return super().write(values)
|
||||
@ -1,58 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Inherit the purchase order form view to add smart button and subcontracting moves section -->
|
||||
<record id="view_purchase_order_form_inherit_subcontracting_inventory_move_first" model="ir.ui.view">
|
||||
<field name="name">purchase.order.form.inherit.subcontracting.inventory.move.first</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<!-- Smart button to view linked subcontracting moves -->
|
||||
<button name="action_view_subcontracting_moves"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-truck"
|
||||
invisible="subcontracting_move_count == 0">
|
||||
<field name="subcontracting_move_count" widget="statinfo" string="Subcontracting Moves"/>
|
||||
</button>
|
||||
|
||||
<!-- Button to link existing subcontracting moves -->
|
||||
<button name="action_link_subcontracting_moves"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-link"
|
||||
invisible="state not in ['draft', 'sent', 'to approve']">
|
||||
<div>Link Subcontracting Moves</div>
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
<!-- Add subcontracting moves section in the form body -->
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Subcontracting Moves"
|
||||
invisible="subcontracting_move_count == 0">
|
||||
<field name="subcontracting_move_ids"
|
||||
nolabel="1"
|
||||
readonly="1"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Add menu item for viewing subcontracting inventory moves -->
|
||||
<record id="action_subcontracting_moves_tree" model="ir.actions.act_window">
|
||||
<field name="name">Subcontracting Inventory Moves</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">stock.move</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="domain">[('location_dest_id.name', '=', 'Subcontracting Location')]</field>
|
||||
<field name="context">{'search_default_location_dest_id_name': 'Subcontracting Location'}</field>
|
||||
</record>
|
||||
|
||||
<!-- Add menu item to the Purchase menu -->
|
||||
<menuitem id="menu_subcontracting_moves"
|
||||
name="Subcontracting Moves"
|
||||
action="action_subcontracting_moves_tree"
|
||||
parent="purchase.menu_purchase_root"
|
||||
sequence="15"/>
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Inherit the purchase order form view to add smart button and subcontracting moves section -->
|
||||
<record id="view_purchase_order_form_inherit_subcontracting_inventory_move_first" model="ir.ui.view">
|
||||
<field name="name">purchase.order.form.inherit.subcontracting.inventory.move.first</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<!-- Smart button to view linked subcontracting moves -->
|
||||
<button name="action_view_subcontracting_moves"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-truck"
|
||||
invisible="subcontracting_move_count == 0">
|
||||
<field name="subcontracting_move_count" widget="statinfo" string="Subcontracting Moves"/>
|
||||
</button>
|
||||
|
||||
<!-- Button to link existing subcontracting moves -->
|
||||
<button name="action_link_subcontracting_moves"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-link"
|
||||
invisible="state not in ['draft', 'sent', 'to approve']">
|
||||
<div>Link Subcontracting Moves</div>
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
<!-- Add subcontracting moves section in the form body -->
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Subcontracting Moves"
|
||||
invisible="subcontracting_move_count == 0">
|
||||
<field name="subcontracting_move_ids"
|
||||
nolabel="1"
|
||||
readonly="1"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Add menu item for viewing subcontracting inventory moves -->
|
||||
<record id="action_subcontracting_moves_tree" model="ir.actions.act_window">
|
||||
<field name="name">Subcontracting Inventory Moves</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">stock.move</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="domain">[('location_dest_id.name', '=', 'Subcontracting Location')]</field>
|
||||
<field name="context">{'search_default_location_dest_id_name': 'Subcontracting Location'}</field>
|
||||
</record>
|
||||
|
||||
<!-- Add menu item to the Purchase menu -->
|
||||
<menuitem id="menu_subcontracting_moves"
|
||||
name="Subcontracting Moves"
|
||||
action="action_subcontracting_moves_tree"
|
||||
parent="purchase.menu_purchase_root"
|
||||
sequence="15"/>
|
||||
|
||||
</odoo>
|
||||
@ -1,45 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Server action to link selected subcontracting move to purchase order -->
|
||||
<record id="action_link_subcontracting_move_to_po" model="ir.actions.server">
|
||||
<field name="name">Link to Purchase Order</field>
|
||||
<field name="model_id" ref="stock.model_stock_move"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_move"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Get the active purchase order from context
|
||||
po_id = env.context.get('default_purchase_order_id') or env.context.get('active_id')
|
||||
if po_id:
|
||||
po = env['purchase.order'].browse(po_id)
|
||||
for record in records:
|
||||
po.link_selected_subcontracting_move(record.id)
|
||||
# Close the wizard window
|
||||
action = {'type': 'ir.actions.act_window_close'}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Custom list view for linking subcontracting moves to purchase orders -->
|
||||
<record id="view_stock_move_link_subcontracting_tree" model="ir.ui.view">
|
||||
<field name="name">stock.move.link.subcontracting.tree</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Subcontracting Moves to Link" create="false" edit="false" delete="false">
|
||||
<header>
|
||||
<button name="%(action_link_subcontracting_move_to_po)d"
|
||||
type="action"
|
||||
string="Link to Purchase Order"
|
||||
class="btn-primary"
|
||||
context="{'default_purchase_order_id': context.get('default_purchase_order_id')}"/>
|
||||
</header>
|
||||
<field name="name"/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="product_uom" groups="uom.group_uom"/>
|
||||
<field name="state"/>
|
||||
<field name="date"/>
|
||||
<field name="location_dest_id"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Server action to link selected subcontracting move to purchase order -->
|
||||
<record id="action_link_subcontracting_move_to_po" model="ir.actions.server">
|
||||
<field name="name">Link to Purchase Order</field>
|
||||
<field name="model_id" ref="stock.model_stock_move"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_move"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Get the active purchase order from context
|
||||
po_id = env.context.get('default_purchase_order_id') or env.context.get('active_id')
|
||||
if po_id:
|
||||
po = env['purchase.order'].browse(po_id)
|
||||
for record in records:
|
||||
po.link_selected_subcontracting_move(record.id)
|
||||
# Close the wizard window
|
||||
action = {'type': 'ir.actions.act_window_close'}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Custom list view for linking subcontracting moves to purchase orders -->
|
||||
<record id="view_stock_move_link_subcontracting_tree" model="ir.ui.view">
|
||||
<field name="name">stock.move.link.subcontracting.tree</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Subcontracting Moves to Link" create="false" edit="false" delete="false">
|
||||
<header>
|
||||
<button name="%(action_link_subcontracting_move_to_po)d"
|
||||
type="action"
|
||||
string="Link to Purchase Order"
|
||||
class="btn-primary"
|
||||
context="{'default_purchase_order_id': context.get('default_purchase_order_id')}"/>
|
||||
</header>
|
||||
<field name="name"/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="product_uom" groups="uom.group_uom"/>
|
||||
<field name="state"/>
|
||||
<field name="date"/>
|
||||
<field name="location_dest_id"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@ -1,43 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Inherit the stock move form view to add purchase order linking field -->
|
||||
<record id="view_stock_move_form_inherit_subcontracting_inventory_move_first" model="ir.ui.view">
|
||||
<field name="name">stock.move.form.inherit.subcontracting.inventory.move.first</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="inherit_id" ref="stock.view_move_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[@name='origin_grp']" position="after">
|
||||
<group name="subcontracting_purchase_link" string="Subcontracting Purchase Link"
|
||||
invisible="not is_subcontract">
|
||||
<field name="purchase_order_id"
|
||||
invisible="not is_subcontract"
|
||||
domain="[('state', 'in', ['draft', 'sent', 'to approve'])]"/>
|
||||
<field name="linked_purchase_order_count" invisible="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Inherit the stock move tree view to show purchase order column -->
|
||||
<record id="view_stock_move_tree_inherit_subcontracting_inventory_move_first" model="ir.ui.view">
|
||||
<field name="name">stock.move.tree.inherit.subcontracting.inventory.move.first</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="inherit_id" ref="stock.view_move_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_uom_qty" position="after">
|
||||
<field name="purchase_order_id"
|
||||
invisible="not is_subcontract"
|
||||
groups="purchase.group_purchase_user"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Add action to link moves to purchase orders -->
|
||||
<record id="action_view_linked_purchase_order" model="ir.actions.server">
|
||||
<field name="name">View Linked Purchase Order</field>
|
||||
<field name="model_id" ref="stock.model_stock_move"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_move"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = record.action_view_linked_purchase_order()</field>
|
||||
</record>
|
||||
</odoo>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Inherit the stock move form view to add purchase order linking field -->
|
||||
<record id="view_stock_move_form_inherit_subcontracting_inventory_move_first" model="ir.ui.view">
|
||||
<field name="name">stock.move.form.inherit.subcontracting.inventory.move.first</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="inherit_id" ref="stock.view_move_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[@name='origin_grp']" position="after">
|
||||
<group name="subcontracting_purchase_link" string="Subcontracting Purchase Link"
|
||||
invisible="not is_subcontract">
|
||||
<field name="purchase_order_id"
|
||||
invisible="not is_subcontract"
|
||||
domain="[('state', 'in', ['draft', 'sent', 'to approve'])]"/>
|
||||
<field name="linked_purchase_order_count" invisible="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Inherit the stock move tree view to show purchase order column -->
|
||||
<record id="view_stock_move_tree_inherit_subcontracting_inventory_move_first" model="ir.ui.view">
|
||||
<field name="name">stock.move.tree.inherit.subcontracting.inventory.move.first</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="inherit_id" ref="stock.view_move_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='product_uom_qty']" position="after">
|
||||
<field name="purchase_order_id" invisible="not is_subcontract"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Add action to link moves to purchase orders -->
|
||||
<record id="action_view_linked_purchase_order" model="ir.actions.server">
|
||||
<field name="name">View Linked Purchase Order</field>
|
||||
<field name="model_id" ref="stock.model_stock_move"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_move"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = record.action_view_linked_purchase_order()</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user