fix some bug regarding the groups in xml view

This commit is contained in:
admin.suherdy 2025-11-20 08:49:19 +07:00
parent 3697d7f785
commit c92a3b0291
13 changed files with 485 additions and 486 deletions

View File

@ -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

View File

@ -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',
}

Binary file not shown.

View File

@ -1,2 +1,2 @@
from . import stock_move
from . import stock_move
from . import purchase_order

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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()

View File

@ -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)

View File

@ -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>

View File

@ -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>

View File

@ -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>