[ADD]rma_internal_transfer

This commit is contained in:
ahenriquez
2019-10-08 17:44:24 +02:00
committed by mreficent
parent 111ea0ea86
commit 03aae19397
8 changed files with 426 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
.. image:: https://img.shields.io/badge/license-LGPL--3-blue.png
:target: https://www.gnu.org/licenses/lgpl
:alt: License: LGPL-3
=====================
RMA Internal Transfer
=====================
Sometimes the repair location is not the same as the receiving location
and useres wants to perform this action manual instead of putaway
strategies. In this case an internal tranfer has to be done.
This module just adds a button that eases this task
Usage
=====
In the RMA from view there is a new button "Internal Transfer". The user
just need to change the default location according its needs.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/Eficent/stock-rma/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smash it by providing detailed and welcomed feedback.
Credits
=======
Contributors
------------
* Aaron Henriquez <ahenriquez@eficent.com>
Maintainer
----------
This module is maintained by Eficent.

View File

@@ -0,0 +1,4 @@
# Copyright (C) 2017 Eficent Business and IT Consulting Services S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
from . import wizards

View File

@@ -0,0 +1,16 @@
# Copyright (C) 2017 Eficent Business and IT Consulting Services S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
{
'name': 'RMA Internal Transfer',
'version': '12.0.2.3.0',
'license': 'LGPL-3',
'category': 'RMA',
'summary': 'Internal transfers. Made easy.',
'author': "Eficent, Odoo Community Association (OCA)",
'website': 'https://github.com/Eficent/stock-rma',
'depends': ['rma'],
'data': ['wizards/rma_internal_transfer.xml',
],
'installable': True,
}

View File

@@ -0,0 +1 @@
from . import test_internal_transfer

View File

@@ -0,0 +1,132 @@
# © 2017 Eficent Business and IT Consulting Services S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
from odoo.tests import common
class TestRmaInternalTransfer(common.SavepointCase):
""" Test the routes and the quantities """
@classmethod
def setUpClass(cls):
super(TestRmaInternalTransfer, cls).setUpClass()
cls.rma_make_picking = cls.env['rma_internal_transfer.wizard']
cls.stockpicking = cls.env['stock.picking']
cls.rma_add_stock_move = cls.env['rma_add_stock_move']
cls.rma = cls.env['rma.order']
cls.rma_line = cls.env['rma.order.line']
cls.product_1 = cls.env.ref('product.product_product_25')
cls.partner_id = cls.env.ref('base.res_partner_2')
cls.stock_location = cls.env.ref('stock.stock_location_stock')
wh = cls.env.ref('stock.warehouse0')
cls.product_uom_id = cls.env.ref('uom.product_uom_unit')
cls.stock_rma_location = wh.lot_rma_id
cls.customer_location = cls.env.ref(
'stock.stock_location_customers')
cls.supplier_location = cls.env.ref(
'stock.stock_location_suppliers')
# Customer RMA:
products2move = [(cls.product_1, 3)]
cls.rma_customer_id = cls._create_rma_from_move(
products2move, 'customer', cls.env.ref('base.res_partner_2'),
dropship=False)
cls.rma_customer_id.rma_line_ids._onchange_operation_id()
seq = cls.env['ir.sequence'].search([], limit=1)
cls.env['stock.picking.type'].create({
"name": "TEST INTERNAL",
"sequence_id": seq.id,
"default_location_src_id": cls.stock_rma_location.id,
"default_location_dest_id": cls.stock_rma_location.id,
"warehouse_id": wh.id,
"code": "internal"})
@classmethod
def _create_picking(cls, partner):
return cls.stockpicking.create({
'partner_id': partner.id,
'picking_type_id': cls.env.ref('stock.picking_type_in').id,
'location_id': cls.stock_location.id,
'location_dest_id': cls.supplier_location.id
})
@classmethod
def _prepare_move(cls, product, qty, src, dest, picking_in):
res = {
'partner_id': cls.partner_id.id,
'product_id': product.id,
'name': product.partner_ref,
'state': 'confirmed',
'product_uom': cls.product_uom_id.id or product.uom_id.id,
'product_uom_qty': qty,
'origin': 'Test RMA',
'location_id': src.id,
'location_dest_id': dest.id,
'picking_id': picking_in.id
}
return res
@classmethod
def _create_rma_from_move(cls, products2move, type, partner, dropship,
supplier_address_id=None):
picking_in = cls._create_picking(partner)
moves = []
for item in products2move:
move_values = cls._prepare_move(
item[0], item[1], cls.stock_location,
cls.customer_location, picking_in)
moves.append(cls.env['stock.move'].create(move_values))
# Create the RMA from the stock_move
rma_id = cls.rma.create(
{
'reference': '0001',
'type': type,
'partner_id': partner.id,
'company_id': cls.env.ref('base.main_company').id
})
for move in moves:
if type == 'customer':
wizard = cls.rma_add_stock_move.new(
{'stock_move_id': move.id, 'customer': True,
'active_ids': rma_id.id,
'rma_id': rma_id.id,
'partner_id': move.partner_id.id,
'active_model': 'rma.order',
}
)
wizard.with_context({
'stock_move_id': move.id, 'customer': True,
'active_ids': rma_id.id,
'partner_id': move.partner_id.id,
'active_model': 'rma.order',
}).default_get([str(move.id),
str(cls.partner_id.id)])
data = wizard.with_context(customer=1).\
_prepare_rma_line_from_stock_move(move)
wizard.add_lines()
for operation in move.product_id.rma_customer_operation_id:
operation.in_route_id = False
move.product_id.categ_id.rma_customer_operation_id = False
move.product_id.rma_customer_operation_id = False
wizard._prepare_rma_line_from_stock_move(move)
cls.line = cls.rma_line.create(data)
cls.line.action_rma_to_approve()
cls.line.action_rma_approve()
return rma_id
def test_0_internal_transfer(cls):
wizard = cls.rma_make_picking.with_context({
'active_ids': cls.rma_customer_id.rma_line_ids.ids,
'active_model': 'rma.order.line',
'picking_type': 'internal',
'active_id': cls.rma_customer_id.id
}).create({})
wizard.action_create_picking()
res = cls.rma_customer_id.rma_line_ids.action_view_in_shipments()
cls.assertTrue('res_id' in res,
"Incorrect number of pickings created")

View File

@@ -0,0 +1,4 @@
# Copyright (C) 2017 Eficent Business and IT Consulting Services S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
from . import rma_internal_transfer

View File

@@ -0,0 +1,147 @@
# Copyright (C) 2017 Eficent Business and IT Consulting Services S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
import odoo.addons.decimal_precision as dp
class RmaMakePicking(models.TransientModel):
_name = 'rma_internal_transfer.wizard'
_description = 'Wizard to create pickings from rma lines'
@api.returns('rma.order.line')
def _prepare_item(self, line):
values = {'product_id': line.product_id.id,
'product_qty': line.product_qty,
'uom_id': line.uom_id.id,
'qty_to_receive': line.qty_to_receive,
'qty_to_deliver': line.qty_to_deliver,
'line_id': line.id,
'rma_id': line.rma_id and line.rma_id.id or False,
'wiz_id': self.env.context['active_id'],
}
return values
@api.model
def default_get(self, fields):
"""Default values for wizard, if there is more than one supplier on
lines the supplier field is empty otherwise is the unique line
supplier.
"""
context = self._context.copy()
res = super(RmaMakePicking, self).default_get(fields)
rma_line_obj = self.env['rma.order.line']
rma_line_ids = self.env.context['active_ids'] or []
active_model = self.env.context['active_model']
if not rma_line_ids:
return res
assert active_model == 'rma.order.line', \
'Bad context propagation'
items = []
lines = rma_line_obj.browse(rma_line_ids)
if len(lines.mapped('partner_id')) > 1:
raise ValidationError(
_('Only RMA lines from the same partner can be processed at '
'the same time'))
for line in lines:
items.append([0, 0, self._prepare_item(line)])
types = self.env['stock.picking.type'].search(
[('code', '=', 'internal'),
('warehouse_id.company_id', '=',
line.in_warehouse_id.id)])[:1]
if not types:
raise ValidationError(_('Please define an internal picking type '
'for this warehouse'))
res['location_id'] = lines.mapped('location_id').ids[0]
res['picking_type_id'] = types.id
res['location_dest_id'] = lines.mapped('location_id').ids[0]
res['item_ids'] = items
context.update({'items_ids': items})
return res
item_ids = fields.One2many(
'rma_internal_transfer.wizard.item',
'wiz_id', string='Items')
picking_type_id = fields.Many2one('stock.picking.type', 'Operation Type',
required=True)
location_id = fields.Many2one('stock.location', 'Source Location',
required=True)
location_dest_id = fields.Many2one(
'stock.location', 'Destination Location', required=True)
def find_procurement_group(self):
if self.mapped('item_ids.line_id.rma_id'):
return self.env['procurement.group'].search([
('rma_id', 'in', self.mapped('item_ids.line_id.rma_id').ids)])
else:
return self.env['procurement.group'].search([
('rma_line_id', 'in', self.mapped('item_ids.line_id').ids)])
@api.multi
def action_create_picking(self):
self.ensure_one()
picking_obj = self.env['stock.picking']
type_obj = self.env['stock.picking.type']
user_obj = self.env['res.users']
company_id = user_obj.browse(self._uid).company_id.id
types = type_obj.search([('code', '=', 'internal'),
('warehouse_id.company_id', '=', company_id)])
if not types:
raise UserError(_("Make sure you have at least an internal picking"
"type defined for your company's warehouse."))
picking_type = types[0]
group_id = self.find_procurement_group().id
picking = picking_obj.create({
'picking_type_id': picking_type.id,
'location_dest_id': self.location_dest_id.id,
'location_id': self.location_id.id,
'move_lines': [(0, 0, {
'name': item.line_id.name,
'product_id': item.product_id.id,
'product_uom_qty': item.product_qty,
'product_uom': item.uom_id.id,
'state': 'draft',
'group_id': group_id,
'rma_line_id': item.line_id.id,
}) for item in self.item_ids]
})
return {
'type': 'ir.actions.act_window',
'name': 'Stock Picking',
'res_model': 'stock.picking',
'res_id': picking.id,
'view_mode': 'form',
'view_type': 'form',
}
@api.multi
def action_cancel(self):
return {'type': 'ir.actions.act_window_close'}
class RmaMakePickingItem(models.TransientModel):
_name = "rma_internal_transfer.wizard.item"
_description = "Items to receive"
wiz_id = fields.Many2one(
'rma_internal_transfer.wizard',
string='Wizard', required=True)
line_id = fields.Many2one('rma.order.line',
string='RMA order Line',
readonly=True,
ondelete='cascade')
rma_id = fields.Many2one('rma.order',
related='line_id.rma_id',
string='RMA Group',
readonly=True)
product_id = fields.Many2one('product.product', string='Product',
required=True)
product_qty = fields.Float(
related='line_id.product_qty',
string='Quantity Ordered', copy=False,
digits=dp.get_precision('Product Unit of Measure'))
uom_id = fields.Many2one('uom.uom', string='Unit of Measure')

View File

@@ -0,0 +1,78 @@
<?xml version="1.0"?>
<odoo>
<record id="view_rma_picking_internal" model="ir.ui.view">
<field name="name">Internal Transfer</field>
<field name="model">rma_internal_transfer.wizard</field>
<field name="arch" type="xml">
<form string="Select lines for transfer" name="lines">
<separator string="Select lines for picking"/>
<group name="main">
<group name="locations">
<field name="picking_type_id"/>
<field name="location_id"/>
<field name="location_dest_id"/>
</group>
</group>
<field name="item_ids">
<tree string="RMA Lines" editable="bottom" create="false">
<field name="rma_id" groups="rma.group_rma_groups"/>
<field name="product_id"/>
<field name="product_qty"/>
<field name="uom_id" groups="uom.group_uom"/>
</tree>
</field>
<footer>
<button
string="Confirm"
name="action_create_picking" type="object"
class="oe_highlight"/>
or
<button name="action_cancel"
string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_rma_picking_internal" model="ir.actions.act_window">
<field name="name">Create Internal Transfer</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">rma_internal_transfer.wizard</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="view_id" ref="view_rma_picking_internal"/>
<field name="groups_id" eval="[(4, ref('stock.group_stock_user'))]"/>
<field name="context">{'picking_type': 'internal'}</field>
<field name="binding_model_id" ref="rma.model_rma_order_line"/>
</record>
<record id="view_rma_line_button_form" model="ir.ui.view">
<field name="name">rma.order.line.form</field>
<field name="model">rma.order.line</field>
<field name="inherit_id" ref="rma.view_rma_line_form"/>
<field name="arch" type="xml">
<button name="%(rma.action_rma_picking_out)d" position="after">
<button name="%(action_rma_picking_internal)d" states="approved"
string="Internal Transfer" class="oe_highlight"
type="action"/>
</button>
</field>
</record>
<record id="view_rma_line_supplier_button_form" model="ir.ui.view">
<field name="name">rma.order.line.supplier.form</field>
<field name="model">rma.order.line</field>
<field name="inherit_id" ref="rma.view_rma_line_supplier_button_form"/>
<field name="arch" type="xml">
<button name="%(rma.action_rma_picking_out)d" position="after">
<button name="%(action_rma_picking_internal)d" states="approved"
string="Internal Transfer" class="oe_highlight"
type="action"/>
</button>
</field>
</record>
</odoo>