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 # Subcontracting Inventory Move First
## Overview ## 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. 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 ## Features
- Create "Resupply Subcontract" inventory moves directly in the inventory module - Create "Resupply Subcontract" inventory moves directly in the inventory module
- Link these moves to purchase orders after creation - Link these moves to purchase orders after creation
- Smart button on purchase orders to view linked inventory moves - Smart button on purchase orders to view linked inventory moves
- Maintain data consistency between moves and purchase orders - Maintain data consistency between moves and purchase orders
- Update source document field in inventory moves and related stock pickings to show purchase order number - 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 - Proper handling of purchase order cancellation to unlink moves
## Usage ## Usage
### Creating Subcontracting Inventory Moves First ### Creating Subcontracting Inventory Moves First
1. Navigate to Inventory > Operations > Transfers 1. Navigate to Inventory > Operations > Transfers
2. Create a new transfer with operation type "Resupply Subcontractor" 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 3. The inventory move will be created without being linked to a purchase order initially
### Linking to Purchase Orders ### Linking to Purchase Orders
1. Go to the purchase order you want to link 1. Go to the purchase order you want to link
2. Click the "Link Subcontracting Moves" button 2. Click the "Link Subcontracting Moves" button
3. Select the appropriate inventory moves from the list 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 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 5. The moves will be linked to the purchase order and source document fields updated
### Viewing Linked Moves ### Viewing Linked Moves
1. On any purchase order form, the smart button "Subcontracting Moves" will show the count of 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 2. Click the button to view and manage all linked inventory moves
## Technical Details ## Technical Details
- The module adds a `purchase_order_id` field to `stock.move` to track links to purchase orders - 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 - 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 - 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 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 - 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 - Proper handling of purchase order cancellation to unlink moves without errors
## Compatibility ## Compatibility
- Compatible with Odoo 18.0 - Compatible with Odoo 18.0
- Works alongside standard subcontracting workflow - Works alongside standard subcontracting workflow
- Depends on: mrp_subcontracting, purchase, stock, mrp_subcontracting_purchase - Depends on: mrp_subcontracting, purchase, stock, mrp_subcontracting_purchase

View File

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

View File

@ -1,104 +1,104 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details. # Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models, api from odoo import fields, models, api
class StockMove(models.Model): class StockMove(models.Model):
_inherit = 'stock.move' _inherit = 'stock.move'
# Field to link inventory move to a purchase order # Field to link inventory move to a purchase order
purchase_order_id = fields.Many2one( purchase_order_id = fields.Many2one(
'purchase.order', 'purchase.order',
string='Linked Purchase Order', string='Linked Purchase Order',
ondelete='set null', ondelete='set null',
help='Purchase order linked to this subcontracting inventory move' help='Purchase order linked to this subcontracting inventory move'
) )
# Computed field to show count of linked purchase orders for smart button # Computed field to show count of linked purchase orders for smart button
linked_purchase_order_count = fields.Integer( linked_purchase_order_count = fields.Integer(
string='Linked Purchase Orders Count', string='Linked Purchase Orders Count',
compute='_compute_linked_purchase_order_count' compute='_compute_linked_purchase_order_count'
) )
@api.depends('purchase_order_id') @api.depends('purchase_order_id')
def _compute_linked_purchase_order_count(self): def _compute_linked_purchase_order_count(self):
for move in self: for move in self:
move.linked_purchase_order_count = 1 if move.purchase_order_id else 0 move.linked_purchase_order_count = 1 if move.purchase_order_id else 0
def action_view_linked_purchase_order(self): def action_view_linked_purchase_order(self):
"""Action to view the linked purchase order from the inventory move""" """Action to view the linked purchase order from the inventory move"""
self.ensure_one() self.ensure_one()
if self.purchase_order_id: if self.purchase_order_id:
return { return {
'name': 'Linked Purchase Order', 'name': 'Linked Purchase Order',
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
'view_mode': 'form', 'view_mode': 'form',
'res_model': 'purchase.order', 'res_model': 'purchase.order',
'res_id': self.purchase_order_id.id, 'res_id': self.purchase_order_id.id,
'target': 'current', 'target': 'current',
} }
return { return {
'name': 'Create Purchase Order', 'name': 'Create Purchase Order',
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
'view_mode': 'form', 'view_mode': 'form',
'res_model': 'purchase.order', 'res_model': 'purchase.order',
'context': { 'context': {
'default_order_line': [(0, 0, { 'default_order_line': [(0, 0, {
'product_id': self.product_id.id, 'product_id': self.product_id.id,
'product_qty': self.product_uom_qty, 'product_qty': self.product_uom_qty,
'product_uom': self.product_uom.id, 'product_uom': self.product_uom.id,
})], })],
}, },
'target': 'current', 'target': 'current',
} }
def _action_confirm(self, merge=True, merge_into=False): def _action_confirm(self, merge=True, merge_into=False):
"""Override to handle our custom subcontracting flow""" """Override to handle our custom subcontracting flow"""
# Call the super method first to maintain standard functionality # Call the super method first to maintain standard functionality
result = super()._action_confirm(merge=merge, merge_into=merge_into) result = super()._action_confirm(merge=merge, merge_into=merge_into)
# For moves that are subcontracting related but not linked to purchase orders yet # 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 # we want to allow them to exist in the system without creating manufacturing orders immediately
for move in self: for move in self:
if move.is_subcontract and not move.purchase_order_id: if move.is_subcontract and not move.purchase_order_id:
# This is a move created first without a purchase order - allow it to exist # 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 # 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 # Prevent creating MOs for moves that are not linked to a purchase order yet
continue continue
return result return result
def _action_assign(self): def _action_assign(self):
"""Override to handle custom subcontracting flow""" """Override to handle custom subcontracting flow"""
# For moves that are subcontracting but not linked to purchase orders yet, # For moves that are subcontracting but not linked to purchase orders yet,
# we may want to handle them differently # we may want to handle them differently
subcontract_moves_without_po = self.filtered(lambda m: m.is_subcontract and not m.purchase_order_id) subcontract_moves_without_po = self.filtered(lambda m: m.is_subcontract and not m.purchase_order_id)
other_moves = self - subcontract_moves_without_po other_moves = self - subcontract_moves_without_po
# Process other moves normally # Process other moves normally
if other_moves: if other_moves:
super(StockMove, other_moves)._action_assign() super(StockMove, other_moves)._action_assign()
# For subcontract moves without PO, we can decide how to handle them # For subcontract moves without PO, we can decide how to handle them
# For now, just call the super method # For now, just call the super method
if subcontract_moves_without_po: if subcontract_moves_without_po:
super(StockMove, subcontract_moves_without_po)._action_assign() super(StockMove, subcontract_moves_without_po)._action_assign()
return True return True
def write(self, values): def write(self, values):
"""Override write to handle purchase order linking""" """Override write to handle purchase order linking"""
# If we're linking a purchase order to a move, update the reverse link # If we're linking a purchase order to a move, update the reverse link
if 'purchase_order_id' in values: if 'purchase_order_id' in values:
purchase_order = self.env['purchase.order'].browse(values['purchase_order_id']) purchase_order = self.env['purchase.order'].browse(values['purchase_order_id'])
if purchase_order.exists(): if purchase_order.exists():
# Add this move to the purchase order's subcontracting moves # Add this move to the purchase order's subcontracting moves
for move in self: for move in self:
if move.is_subcontract and move not in purchase_order.subcontracting_move_ids: if move.is_subcontract and move not in purchase_order.subcontracting_move_ids:
# Add to the existing list of moves # Add to the existing list of moves
current_moves = purchase_order.subcontracting_move_ids.ids current_moves = purchase_order.subcontracting_move_ids.ids
current_moves.append(move.id) current_moves.append(move.id)
purchase_order.write({'subcontracting_move_ids': [(6, 0, current_moves)]}) purchase_order.write({'subcontracting_move_ids': [(6, 0, current_moves)]})
return super().write(values) return super().write(values)

View File

@ -1,58 +1,58 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<!-- Inherit the purchase order form view to add smart button and subcontracting moves section --> <!-- 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"> <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="name">purchase.order.form.inherit.subcontracting.inventory.move.first</field>
<field name="model">purchase.order</field> <field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/> <field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside"> <xpath expr="//div[@name='button_box']" position="inside">
<!-- Smart button to view linked subcontracting moves --> <!-- Smart button to view linked subcontracting moves -->
<button name="action_view_subcontracting_moves" <button name="action_view_subcontracting_moves"
type="object" type="object"
class="oe_stat_button" class="oe_stat_button"
icon="fa-truck" icon="fa-truck"
invisible="subcontracting_move_count == 0"> invisible="subcontracting_move_count == 0">
<field name="subcontracting_move_count" widget="statinfo" string="Subcontracting Moves"/> <field name="subcontracting_move_count" widget="statinfo" string="Subcontracting Moves"/>
</button> </button>
<!-- Button to link existing subcontracting moves --> <!-- Button to link existing subcontracting moves -->
<button name="action_link_subcontracting_moves" <button name="action_link_subcontracting_moves"
type="object" type="object"
class="oe_stat_button" class="oe_stat_button"
icon="fa-link" icon="fa-link"
invisible="state not in ['draft', 'sent', 'to approve']"> invisible="state not in ['draft', 'sent', 'to approve']">
<div>Link Subcontracting Moves</div> <div>Link Subcontracting Moves</div>
</button> </button>
</xpath> </xpath>
<!-- Add subcontracting moves section in the form body --> <!-- Add subcontracting moves section in the form body -->
<xpath expr="//notebook" position="inside"> <xpath expr="//notebook" position="inside">
<page string="Subcontracting Moves" <page string="Subcontracting Moves"
invisible="subcontracting_move_count == 0"> invisible="subcontracting_move_count == 0">
<field name="subcontracting_move_ids" <field name="subcontracting_move_ids"
nolabel="1" nolabel="1"
readonly="1"/> readonly="1"/>
</page> </page>
</xpath> </xpath>
</field> </field>
</record> </record>
<!-- Add menu item for viewing subcontracting inventory moves --> <!-- Add menu item for viewing subcontracting inventory moves -->
<record id="action_subcontracting_moves_tree" model="ir.actions.act_window"> <record id="action_subcontracting_moves_tree" model="ir.actions.act_window">
<field name="name">Subcontracting Inventory Moves</field> <field name="name">Subcontracting Inventory Moves</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="res_model">stock.move</field> <field name="res_model">stock.move</field>
<field name="view_mode">list,form</field> <field name="view_mode">list,form</field>
<field name="domain">[('location_dest_id.name', '=', 'Subcontracting Location')]</field> <field name="domain">[('location_dest_id.name', '=', 'Subcontracting Location')]</field>
<field name="context">{'search_default_location_dest_id_name': 'Subcontracting Location'}</field> <field name="context">{'search_default_location_dest_id_name': 'Subcontracting Location'}</field>
</record> </record>
<!-- Add menu item to the Purchase menu --> <!-- Add menu item to the Purchase menu -->
<menuitem id="menu_subcontracting_moves" <menuitem id="menu_subcontracting_moves"
name="Subcontracting Moves" name="Subcontracting Moves"
action="action_subcontracting_moves_tree" action="action_subcontracting_moves_tree"
parent="purchase.menu_purchase_root" parent="purchase.menu_purchase_root"
sequence="15"/> sequence="15"/>
</odoo> </odoo>

View File

@ -1,45 +1,45 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<!-- Server action to link selected subcontracting move to purchase order --> <!-- Server action to link selected subcontracting move to purchase order -->
<record id="action_link_subcontracting_move_to_po" model="ir.actions.server"> <record id="action_link_subcontracting_move_to_po" model="ir.actions.server">
<field name="name">Link to Purchase Order</field> <field name="name">Link to Purchase Order</field>
<field name="model_id" ref="stock.model_stock_move"/> <field name="model_id" ref="stock.model_stock_move"/>
<field name="binding_model_id" ref="stock.model_stock_move"/> <field name="binding_model_id" ref="stock.model_stock_move"/>
<field name="state">code</field> <field name="state">code</field>
<field name="code"> <field name="code">
if records: if records:
# Get the active purchase order from context # Get the active purchase order from context
po_id = env.context.get('default_purchase_order_id') or env.context.get('active_id') po_id = env.context.get('default_purchase_order_id') or env.context.get('active_id')
if po_id: if po_id:
po = env['purchase.order'].browse(po_id) po = env['purchase.order'].browse(po_id)
for record in records: for record in records:
po.link_selected_subcontracting_move(record.id) po.link_selected_subcontracting_move(record.id)
# Close the wizard window # Close the wizard window
action = {'type': 'ir.actions.act_window_close'} action = {'type': 'ir.actions.act_window_close'}
</field> </field>
</record> </record>
<!-- Custom list view for linking subcontracting moves to purchase orders --> <!-- Custom list view for linking subcontracting moves to purchase orders -->
<record id="view_stock_move_link_subcontracting_tree" model="ir.ui.view"> <record id="view_stock_move_link_subcontracting_tree" model="ir.ui.view">
<field name="name">stock.move.link.subcontracting.tree</field> <field name="name">stock.move.link.subcontracting.tree</field>
<field name="model">stock.move</field> <field name="model">stock.move</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<list string="Subcontracting Moves to Link" create="false" edit="false" delete="false"> <list string="Subcontracting Moves to Link" create="false" edit="false" delete="false">
<header> <header>
<button name="%(action_link_subcontracting_move_to_po)d" <button name="%(action_link_subcontracting_move_to_po)d"
type="action" type="action"
string="Link to Purchase Order" string="Link to Purchase Order"
class="btn-primary" class="btn-primary"
context="{'default_purchase_order_id': context.get('default_purchase_order_id')}"/> context="{'default_purchase_order_id': context.get('default_purchase_order_id')}"/>
</header> </header>
<field name="name"/> <field name="name"/>
<field name="product_id"/> <field name="product_id"/>
<field name="product_uom_qty"/> <field name="product_uom_qty"/>
<field name="product_uom" groups="uom.group_uom"/> <field name="product_uom" groups="uom.group_uom"/>
<field name="state"/> <field name="state"/>
<field name="date"/> <field name="date"/>
<field name="location_dest_id"/> <field name="location_dest_id"/>
</list> </list>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@ -1,43 +1,41 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<!-- Inherit the stock move form view to add purchase order linking field --> <!-- 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"> <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="name">stock.move.form.inherit.subcontracting.inventory.move.first</field>
<field name="model">stock.move</field> <field name="model">stock.move</field>
<field name="inherit_id" ref="stock.view_move_form"/> <field name="inherit_id" ref="stock.view_move_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//group[@name='origin_grp']" position="after"> <xpath expr="//group[@name='origin_grp']" position="after">
<group name="subcontracting_purchase_link" string="Subcontracting Purchase Link" <group name="subcontracting_purchase_link" string="Subcontracting Purchase Link"
invisible="not is_subcontract"> invisible="not is_subcontract">
<field name="purchase_order_id" <field name="purchase_order_id"
invisible="not is_subcontract" invisible="not is_subcontract"
domain="[('state', 'in', ['draft', 'sent', 'to approve'])]"/> domain="[('state', 'in', ['draft', 'sent', 'to approve'])]"/>
<field name="linked_purchase_order_count" invisible="1"/> <field name="linked_purchase_order_count" invisible="1"/>
</group> </group>
</xpath> </xpath>
</field> </field>
</record> </record>
<!-- Inherit the stock move tree view to show purchase order column --> <!-- 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"> <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="name">stock.move.tree.inherit.subcontracting.inventory.move.first</field>
<field name="model">stock.move</field> <field name="model">stock.move</field>
<field name="inherit_id" ref="stock.view_move_tree"/> <field name="inherit_id" ref="stock.view_move_tree"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="product_uom_qty" position="after"> <xpath expr="//field[@name='product_uom_qty']" position="after">
<field name="purchase_order_id" <field name="purchase_order_id" invisible="not is_subcontract"/>
invisible="not is_subcontract" </xpath>
groups="purchase.group_purchase_user"/> </field>
</field> </record>
</field>
</record> <!-- Add action to link moves to purchase orders -->
<record id="action_view_linked_purchase_order" model="ir.actions.server">
<!-- Add action to link moves to purchase orders --> <field name="name">View Linked Purchase Order</field>
<record id="action_view_linked_purchase_order" model="ir.actions.server"> <field name="model_id" ref="stock.model_stock_move"/>
<field name="name">View Linked Purchase Order</field> <field name="binding_model_id" ref="stock.model_stock_move"/>
<field name="model_id" ref="stock.model_stock_move"/> <field name="state">code</field>
<field name="binding_model_id" ref="stock.model_stock_move"/> <field name="code">action = record.action_view_linked_purchase_order()</field>
<field name="state">code</field> </record>
<field name="code">action = record.action_view_linked_purchase_order()</field> </odoo>
</record>
</odoo>