[ADD] mrp_subcontracting_purchase: new module
Add a new module to add smart buttons between a subcontracting purchase order and the ressuply component delivery. task-2486811 Part-of: odoo/odoo#75041
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Purchase and Subcontracting Management',
|
||||
'version': '0.1',
|
||||
'category': 'Manufacturing/Purchase',
|
||||
'description': """
|
||||
This bridge module adds some smart buttons between Purchase and Subcontracting
|
||||
""",
|
||||
'depends': ['mrp_subcontracting', 'purchase'],
|
||||
'data': [
|
||||
'views/purchase_order_views.xml',
|
||||
'views/stock_picking_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import stock_picking
|
||||
from . import purchase_order
|
||||
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class PurchaseOrder(models.Model):
|
||||
_inherit = 'purchase.order'
|
||||
|
||||
subcontracting_resupply_picking_count = fields.Integer(
|
||||
"Count of Subcontracting Resupply", compute='_compute_subcontracting_resupply_picking_count',
|
||||
help="Count of Subcontracting Resupply for component")
|
||||
|
||||
@api.depends('order_line.move_ids')
|
||||
def _compute_subcontracting_resupply_picking_count(self):
|
||||
for purchase in self:
|
||||
purchase.subcontracting_resupply_picking_count = len(purchase._get_subcontracting_resupplies())
|
||||
|
||||
def action_view_subcontracting_resupply(self):
|
||||
return self._get_action_view_picking(self._get_subcontracting_resupplies())
|
||||
|
||||
def _get_subcontracting_resupplies(self):
|
||||
moves_subcontracted = self.order_line.move_ids.filtered(lambda m: m.is_subcontract)
|
||||
subcontracted_productions = moves_subcontracted.move_orig_ids.production_id
|
||||
return subcontracted_productions.picking_ids
|
||||
@@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
subcontracting_source_purchase_count = fields.Integer(
|
||||
"Number of subcontracting PO Source", compute='_compute_subcontracting_source_purchase_count',
|
||||
help="Number of subcontracting Purchase Order Source")
|
||||
|
||||
@api.depends('move_lines.move_dest_ids.raw_material_production_id')
|
||||
def _compute_subcontracting_source_purchase_count(self):
|
||||
for picking in self:
|
||||
picking.subcontracting_source_purchase_count = len(picking._get_subcontracting_source_purchase())
|
||||
|
||||
def action_view_subcontracting_source_purchase(self):
|
||||
purchase_order_ids = self._get_subcontracting_source_purchase().ids
|
||||
action = {
|
||||
'res_model': 'purchase.order',
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
if len(purchase_order_ids) == 1:
|
||||
action.update({
|
||||
'view_mode': 'form',
|
||||
'res_id': purchase_order_ids[0],
|
||||
})
|
||||
else:
|
||||
action.update({
|
||||
'name': _("Source PO of %s", self.name),
|
||||
'domain': [('id', 'in', purchase_order_ids)],
|
||||
'view_mode': 'tree,form',
|
||||
})
|
||||
return action
|
||||
|
||||
def _get_subcontracting_source_purchase(self):
|
||||
moves_subcontracted = self.move_lines.move_dest_ids.raw_material_production_id.move_finished_ids.move_dest_ids.filtered(lambda m: m.is_subcontract)
|
||||
return moves_subcontracted.purchase_line_id.order_id
|
||||
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import test_mrp_subcontracting_purchase
|
||||
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import Command
|
||||
|
||||
from odoo.addons.mrp_subcontracting.tests.common import TestMrpSubcontractingCommon
|
||||
|
||||
|
||||
class MrpSubcontractingPurchaseTest(TestMrpSubcontractingCommon):
|
||||
|
||||
def test_count_smart_buttons(self):
|
||||
resupply_sub_on_order_route = self.env['stock.location.route'].search([('name', '=', 'Resupply Subcontractor on Order')])
|
||||
(self.comp1 + self.comp2).write({'route_ids': [Command.link(resupply_sub_on_order_route.id)]})
|
||||
|
||||
# I create a draft Purchase Order for first in move for 10 kg at 50 euro
|
||||
po = self.env['purchase.order'].create({
|
||||
'partner_id': self.subcontractor_partner1.id,
|
||||
'order_line': [Command.create({
|
||||
'name': 'finished',
|
||||
'product_id': self.finished.id,
|
||||
'product_qty': 1.0,
|
||||
'product_uom': self.finished.uom_id.id,
|
||||
'price_unit': 50.0}
|
||||
)],
|
||||
})
|
||||
|
||||
po.button_confirm()
|
||||
|
||||
self.assertEqual(po.subcontracting_resupply_picking_count, 1)
|
||||
action1 = po.action_view_subcontracting_resupply()
|
||||
picking = self.env[action1['res_model']].browse(action1['res_id'])
|
||||
self.assertEqual(picking.subcontracting_source_purchase_count, 1)
|
||||
action2 = picking.action_view_subcontracting_source_purchase()
|
||||
po_action2 = self.env[action2['res_model']].browse(action2['res_id'])
|
||||
self.assertEqual(po_action2, po)
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="purchase_order_form_mrp_subcontracting_purchase" model="ir.ui.view">
|
||||
<field name="name">purchase.order.inherited.form.mrp.subcontracting.purchase</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[hasclass('oe_button_box')]/button[@name='action_view_picking']" position="before">
|
||||
<button
|
||||
class="oe_stat_button" name="action_view_subcontracting_resupply"
|
||||
type="object" icon="fa-truck" attrs="{'invisible': [('subcontracting_resupply_picking_count', '=', 0)]}" groups="stock.group_stock_user">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value"><field name="subcontracting_resupply_picking_count"/></span>
|
||||
<span class="o_stat_text">Resupply</span>
|
||||
</div>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="stock_picking_form_mrp_subcontracting" model="ir.ui.view">
|
||||
<field name="name">stock.picking.inherited.form.mrp.subcontracting</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[hasclass('oe_button_box')]" position="inside">
|
||||
<button
|
||||
class="oe_stat_button" name="action_view_subcontracting_source_purchase"
|
||||
type="object" icon="fa-shopping-cart" attrs="{'invisible': [('subcontracting_source_purchase_count', '=', 0)]}" groups="stock.group_stock_user">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value"><field name="subcontracting_source_purchase_count"/></span>
|
||||
<span class="o_stat_text">Source PO</span>
|
||||
</div>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -118,23 +118,23 @@ class PurchaseOrder(models.Model):
|
||||
return super(PurchaseOrder, self).button_cancel()
|
||||
|
||||
def action_view_picking(self):
|
||||
return self._get_action_view_picking(self.picking_ids)
|
||||
|
||||
def _get_action_view_picking(self, pickings):
|
||||
""" This function returns an action that display existing picking orders of given purchase order ids. When only one found, show the picking immediately.
|
||||
"""
|
||||
self.ensure_one()
|
||||
result = self.env["ir.actions.actions"]._for_xml_id('stock.action_picking_tree_all')
|
||||
# override the context to get rid of the default filtering on operation type
|
||||
result['context'] = {'default_partner_id': self.partner_id.id, 'default_origin': self.name, 'default_picking_type_id': self.picking_type_id.id}
|
||||
pick_ids = self.mapped('picking_ids')
|
||||
# choose the view_mode accordingly
|
||||
if not pick_ids or len(pick_ids) > 1:
|
||||
result['domain'] = "[('id','in',%s)]" % (pick_ids.ids)
|
||||
elif len(pick_ids) == 1:
|
||||
if not pickings or len(pickings) > 1:
|
||||
result['domain'] = [('id', 'in', pickings.ids)]
|
||||
elif len(pickings) == 1:
|
||||
res = self.env.ref('stock.view_picking_form', False)
|
||||
form_view = [(res and res.id or False, 'form')]
|
||||
if 'views' in result:
|
||||
result['views'] = form_view + [(state,view) for state,view in result['views'] if view != 'form']
|
||||
else:
|
||||
result['views'] = form_view
|
||||
result['res_id'] = pick_ids.id
|
||||
result['views'] = form_view + [(state, view) for state, view in result.get('views', []) if view != 'form']
|
||||
result['res_id'] = pickings.id
|
||||
return result
|
||||
|
||||
def _prepare_invoice(self):
|
||||
|
||||
Reference in New Issue
Block a user