mirror of
https://github.com/OCA/rma.git
synced 2025-02-16 17:11:47 +02:00
[ADD] rma: new module
[UPD] Update rma.pot Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: rma-12.0/rma-12.0-rma Translate-URL: https://translation.odoo-community.org/projects/rma-12-0/rma-12-0-rma/
This commit is contained in:
committed by
Pedro M. Baeza
parent
8d3e3c364a
commit
0122a02458
5
rma/wizard/__init__.py
Normal file
5
rma/wizard/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import rma_delivery
|
||||
from . import rma_split
|
||||
from . import stock_picking_return
|
||||
102
rma/wizard/rma_delivery.py
Normal file
102
rma/wizard/rma_delivery.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
import odoo.addons.decimal_precision as dp
|
||||
|
||||
|
||||
class RmaReDeliveryWizard(models.TransientModel):
|
||||
_name = 'rma.delivery.wizard'
|
||||
_description = 'RMA Delivery Wizard'
|
||||
|
||||
rma_count = fields.Integer()
|
||||
type = fields.Selection(
|
||||
selection=[
|
||||
('replace', 'Replace'),
|
||||
('return', 'Return to customer'),
|
||||
],
|
||||
string="Type",
|
||||
required=True,
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
comodel_name="product.product",
|
||||
string="Replace Product",
|
||||
)
|
||||
product_uom_qty = fields.Float(
|
||||
string='Product qty',
|
||||
digits=dp.get_precision('Product Unit of Measure'),
|
||||
)
|
||||
product_uom = fields.Many2one(
|
||||
comodel_name="uom.uom",
|
||||
string="Unit of measure",
|
||||
)
|
||||
scheduled_date = fields.Datetime(
|
||||
required=True,
|
||||
default=fields.Datetime.now(),
|
||||
)
|
||||
warehouse_id = fields.Many2one(
|
||||
comodel_name="stock.warehouse",
|
||||
string='Warehouse',
|
||||
required=True,
|
||||
)
|
||||
|
||||
@api.constrains('product_uom_qty')
|
||||
def _check_product_uom_qty(self):
|
||||
self.ensure_one()
|
||||
rma_ids = self.env.context.get('active_ids')
|
||||
if len(rma_ids) == 1 and self.product_uom_qty <= 0:
|
||||
raise ValidationError(_('Quantity must be greater than 0.'))
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
rma_ids = self.env.context.get('active_ids')
|
||||
rma = self.env['rma'].browse(rma_ids)
|
||||
warehouse_id = self.env['stock.warehouse'].search(
|
||||
[('company_id', '=', rma[0].company_id.id)], limit=1).id
|
||||
delivery_type = self.env.context.get('rma_delivery_type')
|
||||
product_id = False
|
||||
if len(rma) == 1 and delivery_type == 'return':
|
||||
product_id = rma.product_id.id
|
||||
product_uom_qty = 0.0
|
||||
if len(rma) == 1 and rma.remaining_qty > 0.0:
|
||||
product_uom_qty = rma.remaining_qty
|
||||
res.update(
|
||||
rma_count=len(rma),
|
||||
warehouse_id=warehouse_id,
|
||||
type=delivery_type,
|
||||
product_id=product_id,
|
||||
product_uom_qty=product_uom_qty,
|
||||
)
|
||||
return res
|
||||
|
||||
@api.onchange("product_id")
|
||||
def _onchange_product_id(self):
|
||||
domain_product_uom = []
|
||||
if self.product_id:
|
||||
domain_product_uom = [
|
||||
('category_id', '=', self.product_id.uom_id.category_id.id)
|
||||
]
|
||||
if (not self.product_uom
|
||||
or self.product_id.uom_id.id != self.product_uom.id):
|
||||
self.product_uom = self.product_id.uom_id
|
||||
return {'domain': {'product_uom': domain_product_uom}}
|
||||
|
||||
def action_deliver(self):
|
||||
self.ensure_one()
|
||||
rma_ids = self.env.context.get('active_ids')
|
||||
rma = self.env['rma'].browse(rma_ids)
|
||||
if self.type == 'replace':
|
||||
rma.create_replace(
|
||||
self.scheduled_date,
|
||||
self.warehouse_id,
|
||||
self.product_id,
|
||||
self.product_uom_qty,
|
||||
self.product_uom,
|
||||
)
|
||||
elif self.type == 'return':
|
||||
qty = uom = None
|
||||
if self.rma_count == 1:
|
||||
qty, uom = self.product_uom_qty, self.product_uom
|
||||
rma.create_return(self.scheduled_date, qty, uom)
|
||||
50
rma/wizard/rma_delivery_views.xml
Normal file
50
rma/wizard/rma_delivery_views.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<record id="rma_redelivery_wizard_view_form" model="ir.ui.view">
|
||||
<field name="name">rma.delivery.wizard.form</field>
|
||||
<field name="model">rma.delivery.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group>
|
||||
<group>
|
||||
<field name="scheduled_date"/>
|
||||
<field name="warehouse_id"
|
||||
attrs="{'invisible': [('type', '!=', 'replace')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="product_id"
|
||||
attrs="{'invisible': ['|', ('type', '!=', 'replace'), ('rma_count', '>', 1)], 'required': [('type', '=', 'replace'), ('rma_count', '=', 1)]}"/>
|
||||
<label for="product_uom_qty"
|
||||
attrs="{'invisible': [('rma_count', '>', 1)]}"/>
|
||||
<div class="o_row"
|
||||
attrs="{'invisible': [('rma_count', '>', 1)]}">
|
||||
<field name="product_uom_qty"
|
||||
attrs="{'required': [('rma_count', '=', 1)]}"/>
|
||||
<field name="product_uom"
|
||||
groups="uom.group_uom"
|
||||
attrs="{'required': [('rma_count', '=', 1)]}"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<field name="rma_count" invisible="1"/>
|
||||
<field name="type" invisible="1"/>
|
||||
<footer>
|
||||
<button name="action_deliver" string="Deliver" type="object" class="btn-primary"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<act_window id="rma_delivery_wizard_action"
|
||||
name="Return to customer"
|
||||
src_model="rma"
|
||||
res_model="rma.delivery.wizard"
|
||||
view_type="form"
|
||||
view_mode="form"
|
||||
key2="client_action_multi"
|
||||
target="new"
|
||||
multi="True"
|
||||
context="{'rma_delivery_type': 'return'}"/>
|
||||
</odoo>
|
||||
70
rma/wizard/rma_split.py
Normal file
70
rma/wizard/rma_split.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
import odoo.addons.decimal_precision as dp
|
||||
|
||||
|
||||
class RmaReSplitWizard(models.TransientModel):
|
||||
_name = 'rma.split.wizard'
|
||||
_description = 'RMA Split Wizard'
|
||||
|
||||
rma_id = fields.Many2one(
|
||||
comodel_name='rma',
|
||||
string='RMA',
|
||||
)
|
||||
product_uom_qty = fields.Float(
|
||||
string='Quantity to extract',
|
||||
digits=dp.get_precision('Product Unit of Measure'),
|
||||
required=True,
|
||||
help="Quantity to extract to a new RMA."
|
||||
)
|
||||
product_uom = fields.Many2one(
|
||||
comodel_name='uom.uom',
|
||||
string='Unit of measure',
|
||||
required=True,
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
'check_product_uom_qty_positive',
|
||||
'CHECK(product_uom_qty > 0)',
|
||||
'Quantity must be greater than 0.'
|
||||
),
|
||||
]
|
||||
|
||||
@api.model
|
||||
def fields_get(self, allfields=None, attributes=None):
|
||||
res = super().fields_get(allfields, attributes=attributes)
|
||||
rma_id = self.env.context.get('active_id')
|
||||
rma = self.env['rma'].browse(rma_id)
|
||||
res['product_uom']['domain'] = [
|
||||
('category_id', '=', rma.product_uom.category_id.id)
|
||||
]
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
rma_id = self.env.context.get('active_id')
|
||||
rma = self.env['rma'].browse(rma_id)
|
||||
res.update(
|
||||
rma_id=rma.id,
|
||||
product_uom_qty=rma.remaining_qty,
|
||||
product_uom=rma.product_uom.id,
|
||||
)
|
||||
return res
|
||||
|
||||
def action_split(self):
|
||||
self.ensure_one()
|
||||
extracted_rma = self.rma_id.extract_quantity(
|
||||
self.product_uom_qty, self.product_uom)
|
||||
return {
|
||||
'name': _('Extracted RMA'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'rma',
|
||||
'views': [(self.env.ref('rma.rma_view_form').id, 'form')],
|
||||
'res_id': extracted_rma.id,
|
||||
}
|
||||
33
rma/wizard/rma_split_views.xml
Normal file
33
rma/wizard/rma_split_views.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<record id="rma_split_wizard_view_form2" model="ir.ui.view">
|
||||
<field name="name">rma.split.wizard.form</field>
|
||||
<field name="model">rma.split.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group>
|
||||
<group>
|
||||
<label for="product_uom_qty"/>
|
||||
<div class="o_row">
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="product_uom" groups="uom.group_uom"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="action_split" string="Split" type="object" class="btn-primary"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="rma_split_wizard_action" model="ir.actions.act_window">
|
||||
<field name="name">Split RMA</field>
|
||||
<field name="res_model">rma.split.wizard</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
83
rma/wizard/stock_picking_return.py
Normal file
83
rma/wizard/stock_picking_return.py
Normal file
@@ -0,0 +1,83 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class ReturnPicking(models.TransientModel):
|
||||
_inherit = 'stock.return.picking'
|
||||
|
||||
create_rma = fields.Boolean(
|
||||
string="Create RMAs"
|
||||
)
|
||||
picking_type_code = fields.Selection(
|
||||
selection=[
|
||||
('incoming', 'Vendors'),
|
||||
('outgoing', 'Customers'),
|
||||
('internal', 'Internal'),
|
||||
],
|
||||
related='picking_id.picking_type_id.code',
|
||||
store=True,
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
@api.onchange("create_rma")
|
||||
def _onchange_create_rma(self):
|
||||
if self.create_rma:
|
||||
warehouse = self.picking_id.picking_type_id.warehouse_id
|
||||
self.location_id = warehouse.rma_loc_id.id
|
||||
rma_loc = warehouse.search([]).mapped('rma_loc_id')
|
||||
rma_loc_domain = [('id', 'child_of', rma_loc.ids)]
|
||||
else:
|
||||
self.location_id = self.default_get(['location_id'])['location_id']
|
||||
rma_loc_domain = [
|
||||
'|',
|
||||
('id', '=', self.picking_id.location_id.id),
|
||||
('return_location', '=', True),
|
||||
]
|
||||
return {'domain': {'location_id': rma_loc_domain}}
|
||||
|
||||
def create_returns(self):
|
||||
""" Override create_returns method for creating one or more
|
||||
'confirmed' RMAs after return a delivery picking in case
|
||||
'Create RMAs' checkbox is checked in this wizard.
|
||||
New RMAs will be linked to the delivery picking as the origin
|
||||
delivery and also RMAs will be linked to the returned picking
|
||||
as the 'Receipt'.
|
||||
"""
|
||||
if self.create_rma:
|
||||
# set_rma_picking_type is to override the copy() method of stock
|
||||
# picking and change the default picking type to rma picking type
|
||||
self_with_context = self.with_context(set_rma_picking_type=True)
|
||||
res = super(ReturnPicking, self_with_context).create_returns()
|
||||
partner = self.picking_id.partner_id
|
||||
if not partner:
|
||||
raise ValidationError(_(
|
||||
"You must specify the 'Customer' in the "
|
||||
"'Stock Picking' from which RMAs will be created"))
|
||||
picking = self.picking_id
|
||||
returned_picking = self.env['stock.picking'].browse(res['res_id'])
|
||||
if hasattr(picking, 'sale_id') and picking.sale_id:
|
||||
partner_invoice_id = picking.sale_id.partner_invoice_id.id
|
||||
else:
|
||||
partner_invoice_id = partner.address_get(
|
||||
['invoice']).get('invoice', False),
|
||||
for move in returned_picking.move_lines:
|
||||
self.env['rma'].create({
|
||||
'partner_id': partner.id,
|
||||
'partner_invoice_id': partner_invoice_id,
|
||||
'origin': picking.name,
|
||||
'picking_id': picking.id,
|
||||
'move_id': move.origin_returned_move_id.id,
|
||||
'product_id': move.origin_returned_move_id.product_id.id,
|
||||
'product_uom_qty': move.product_uom_qty,
|
||||
'product_uom': move.product_uom.id,
|
||||
'reception_move_id': move.id,
|
||||
'company_id': move.company_id.id,
|
||||
'location_id': move.location_dest_id.id,
|
||||
'state': 'confirmed',
|
||||
})
|
||||
return res
|
||||
else:
|
||||
return super().create_returns()
|
||||
20
rma/wizard/stock_picking_return_views.xml
Normal file
20
rma/wizard/stock_picking_return_views.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<record id="view_stock_return_picking_form" model="ir.ui.view">
|
||||
<field name="name">Return lines inherit RMA</field>
|
||||
<field name="model">stock.return.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_stock_return_picking_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[.//field[@name='product_return_moves']]" position="before">
|
||||
<group name="group_rma">
|
||||
<field name="create_rma"
|
||||
attrs="{'invisible': [('picking_type_code', '!=', 'outgoing')]}"/>
|
||||
<field name="picking_id" invisible="1"/>
|
||||
<field name="picking_type_code" invisible="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user