mirror of
https://github.com/OCA/rma.git
synced 2025-02-16 17:11:47 +02:00
@@ -7,9 +7,9 @@ Return Merchandise Authorization Management
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
|
||||
:target: https://odoo-community.org/page/development-status
|
||||
:alt: Beta
|
||||
:alt: Production/Stable
|
||||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# Copyright 2020 Tecnativa - David Vidal
|
||||
# Copyright 2020 Tecnativa - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
{
|
||||
"name": "Return Merchandise Authorization Management",
|
||||
"summary": "Return Merchandise Authorization (RMA)",
|
||||
"version": "12.0.1.6.1",
|
||||
"development_status": "Beta",
|
||||
"version": "12.0.2.0.0",
|
||||
"development_status": "Production/Stable",
|
||||
"category": "RMA",
|
||||
"website": "https://github.com/OCA/rma",
|
||||
"author": "Tecnativa, Odoo Community Association (OCA)",
|
||||
|
||||
@@ -8,3 +8,9 @@ def migrate(env, version):
|
||||
# Convert Text description field to Html
|
||||
openupgrade.convert_field_to_html(
|
||||
env.cr, "rma", "description", "description")
|
||||
# Put the same shipping address than customer for existing RMAs
|
||||
openupgrade.logged_query(
|
||||
env.cr,
|
||||
"UPDATE rma SET partner_shipping_id = partner_id "
|
||||
"WHERE partner_shipping_id IS NULL"
|
||||
)
|
||||
|
||||
@@ -85,6 +85,13 @@ class Rma(models.Model):
|
||||
index=True,
|
||||
track_visibility='always'
|
||||
)
|
||||
partner_shipping_id = fields.Many2one(
|
||||
string="Shipping Address",
|
||||
comodel_name="res.partner",
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
help="Shipping address for current RMA."
|
||||
)
|
||||
partner_invoice_id = fields.Many2one(
|
||||
string="Invoice Address",
|
||||
comodel_name="res.partner",
|
||||
@@ -416,7 +423,9 @@ class Rma(models.Model):
|
||||
record.access_url = '/my/rmas/{}'.format(record.id)
|
||||
|
||||
# Constrains methods (@api.constrains)
|
||||
@api.constrains('state', 'partner_id', 'partner_invoice_id', 'product_id')
|
||||
@api.constrains(
|
||||
'state', 'partner_id', 'partner_invoice_id',
|
||||
'partner_shipping_id', 'product_id')
|
||||
def _check_required_after_draft(self):
|
||||
""" Check that RMAs are being created or edited with the
|
||||
necessary fields filled out. Only applies to 'Draft' and
|
||||
@@ -444,10 +453,13 @@ class Rma(models.Model):
|
||||
def _onchange_partner_id(self):
|
||||
self.picking_id = False
|
||||
partner_invoice_id = False
|
||||
partner_shipping_id = False
|
||||
if self.partner_id:
|
||||
address = self.partner_id.address_get(['invoice'])
|
||||
address = self.partner_id.address_get(['invoice', 'delivery'])
|
||||
partner_invoice_id = address.get('invoice', False)
|
||||
partner_shipping_id = address.get('delivery', False)
|
||||
self.partner_invoice_id = partner_invoice_id
|
||||
self.partner_shipping_id = partner_shipping_id
|
||||
|
||||
@api.onchange("picking_id")
|
||||
def _onchange_picking_id(self):
|
||||
@@ -718,7 +730,10 @@ class Rma(models.Model):
|
||||
# Validation business methods
|
||||
def _ensure_required_fields(self):
|
||||
""" This method is used to ensure the following fields are not empty:
|
||||
['partner_id', 'partner_invoice_id', 'product_id', 'location_id']
|
||||
[
|
||||
'partner_id', 'partner_invoice_id', 'partner_shipping_id',
|
||||
'product_id', 'location_id'
|
||||
]
|
||||
|
||||
This method is intended to be called on confirm RMA action and is
|
||||
invoked by:
|
||||
@@ -726,8 +741,10 @@ class Rma(models.Model):
|
||||
rma.action_confirm
|
||||
"""
|
||||
ir_translation = self.env['ir.translation']
|
||||
required = ['partner_id', 'partner_invoice_id', 'product_id',
|
||||
'location_id']
|
||||
required = [
|
||||
'partner_id', 'partner_invoice_id', 'partner_shipping_id',
|
||||
'product_id', 'location_id'
|
||||
]
|
||||
for record in self:
|
||||
desc = ""
|
||||
for field in filter(lambda item: not record[item], required):
|
||||
@@ -854,7 +871,7 @@ class Rma(models.Model):
|
||||
def _prepare_picking(self, picking_form):
|
||||
picking_form.company_id = self.company_id
|
||||
picking_form.origin = self.name
|
||||
picking_form.partner_id = self.partner_id
|
||||
picking_form.partner_id = self.partner_shipping_id
|
||||
picking_form.location_dest_id = self.location_id
|
||||
with picking_form.move_ids_without_package.new() as move_form:
|
||||
move_form.product_id = self.product_id
|
||||
@@ -938,7 +955,7 @@ class Rma(models.Model):
|
||||
self._ensure_qty_to_return(qty, uom)
|
||||
group_dict = {}
|
||||
for record in self.filtered('can_be_returned'):
|
||||
key = (record.partner_id.id, record.company_id.id,
|
||||
key = (record.partner_shipping_id.id, record.company_id.id,
|
||||
record.warehouse_id)
|
||||
group_dict.setdefault(key, self.env['rma'])
|
||||
group_dict[key] |= record
|
||||
@@ -987,7 +1004,7 @@ class Rma(models.Model):
|
||||
picking_form.picking_type_id = self.warehouse_id.rma_out_type_id
|
||||
picking_form.company_id = self.company_id
|
||||
picking_form.origin = origin or self.name
|
||||
picking_form.partner_id = self.partner_id
|
||||
picking_form.partner_id = self.partner_shipping_id
|
||||
|
||||
def _prepare_returning_move(self, move_form, scheduled_date,
|
||||
quantity=None, uom=None):
|
||||
@@ -1049,7 +1066,7 @@ class Rma(models.Model):
|
||||
self.procurement_group_id = self.env['procurement.group'].create({
|
||||
'name': self.name,
|
||||
'move_type': 'direct',
|
||||
'partner_id': self.partner_id.id,
|
||||
'partner_id': self.partner_shipping_id.id,
|
||||
}).id
|
||||
values = self._prepare_procurement_values(
|
||||
self.procurement_group_id, scheduled_date, warehouse)
|
||||
@@ -1057,7 +1074,7 @@ class Rma(models.Model):
|
||||
product,
|
||||
qty,
|
||||
uom,
|
||||
self.partner_id.property_stock_customer,
|
||||
self.partner_shipping_id.property_stock_customer,
|
||||
self.product_id.display_name,
|
||||
self.procurement_group_id.name,
|
||||
values,
|
||||
@@ -1075,7 +1092,7 @@ class Rma(models.Model):
|
||||
'group_id': group_id,
|
||||
'date_planned': scheduled_date,
|
||||
'warehouse_id': warehouse,
|
||||
'partner_id': self.partner_id.id,
|
||||
'partner_id': self.partner_shipping_id.id,
|
||||
'rma_id': self.id,
|
||||
'priority': self.priority,
|
||||
}
|
||||
|
||||
@@ -100,13 +100,18 @@ class StockMove(models.Model):
|
||||
partner = original_picking.partner_id
|
||||
if hasattr(original_picking, 'sale_id') and original_picking.sale_id:
|
||||
partner_invoice_id = original_picking.sale_id.partner_invoice_id.id
|
||||
partner_shipping_id = (
|
||||
original_picking.sale_id.partner_shipping_id.id)
|
||||
else:
|
||||
partner_invoice_id = partner.address_get(
|
||||
['invoice']).get('invoice', False),
|
||||
['invoice']).get('invoice', False)
|
||||
partner_shipping_id = partner.address_get(
|
||||
['delivery']).get('delivery', False)
|
||||
return {
|
||||
'user_id': self.env.user.id,
|
||||
'partner_id': partner.id,
|
||||
'partner_invoice_id': partner_invoice_id,
|
||||
'partner_shipping_id': partner_shipping_id,
|
||||
'origin': original_picking.name,
|
||||
'picking_id': original_picking.id,
|
||||
'move_id': self.origin_returned_move_id.id,
|
||||
|
||||
@@ -367,7 +367,7 @@ ul.auto-toc {
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/rma/tree/12.0/rma"><img alt="OCA/rma" src="https://img.shields.io/badge/github-OCA%2Frma-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/rma-12-0/rma-12-0-rma"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/145/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
|
||||
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/rma/tree/12.0/rma"><img alt="OCA/rma" src="https://img.shields.io/badge/github-OCA%2Frma-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/rma-12-0/rma-12-0-rma"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/145/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
|
||||
<p>This module allows you to manage <a class="reference external" href="https://en.wikipedia.org/wiki/Return_merchandise_authorization">Return Merchandise Authorization (RMA)</a>.
|
||||
RMA documents can be created from scratch, from a delivery order or from
|
||||
an incoming email. Product receptions and returning delivery operations
|
||||
|
||||
@@ -52,6 +52,11 @@ class TestRma(SavepointCase):
|
||||
'parent_id': cls.partner.id,
|
||||
'type': 'invoice',
|
||||
})
|
||||
cls.partner_shipping = cls.res_partner.create({
|
||||
'name': 'Partner shipping test',
|
||||
'parent_id': cls.partner.id,
|
||||
'type': 'delivery',
|
||||
})
|
||||
|
||||
def _create_rma(self, partner=None, product=None, qty=None, location=None):
|
||||
rma_form = Form(self.env['rma'])
|
||||
@@ -187,7 +192,8 @@ class TestRma(SavepointCase):
|
||||
rma.action_confirm()
|
||||
self.assertEqual(
|
||||
e.exception.name,
|
||||
"Required field(s):\nCustomer\nInvoice Address\nProduct\nLocation"
|
||||
"Required field(s):\nCustomer\nInvoice Address\n"
|
||||
"Shipping Address\nProduct\nLocation"
|
||||
)
|
||||
with Form(rma) as rma_form:
|
||||
rma_form.partner_id = self.partner
|
||||
@@ -532,7 +538,7 @@ class TestRma(SavepointCase):
|
||||
self.assertNotEqual(pick_1.partner_id, pick_2.partner_id)
|
||||
self.assertEqual(
|
||||
pick_1.partner_id,
|
||||
(rma_1 | rma_2 | rma_3).mapped('partner_id'),
|
||||
(rma_1 | rma_2 | rma_3).mapped('partner_shipping_id'),
|
||||
)
|
||||
self.assertEqual(pick_2.partner_id, rma_4.partner_id)
|
||||
# Each RMA of (rma_1, rma_2 and rma_3) is linked to a different
|
||||
|
||||
@@ -172,6 +172,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id" widget="res_partner_many2one" context="{'search_default_customer':1, 'show_address': 1, 'show_vat': True}" options="{'always_reload': True}"/>
|
||||
<field name="partner_shipping_id"/>
|
||||
<field name="partner_invoice_id"/>
|
||||
<field name="picking_id"
|
||||
options="{'no_create': True}"/>
|
||||
|
||||
@@ -20,6 +20,7 @@ class CustomerPortal(CustomerPortal):
|
||||
wizard_obj = request.env['sale.order.rma.wizard']
|
||||
# Set wizard line vals
|
||||
mapped_vals = {}
|
||||
partner_shipping_id = post.pop("partner_shipping_id", False)
|
||||
for name, value in post.items():
|
||||
row, field_name = name.split('-', 1)
|
||||
mapped_vals.setdefault(row, {}).update({field_name: value})
|
||||
@@ -32,7 +33,8 @@ class CustomerPortal(CustomerPortal):
|
||||
location_id = order.warehouse_id.rma_loc_id.id
|
||||
wizard = wizard_obj.with_context(active_id=order_id).create({
|
||||
'line_ids': line_vals,
|
||||
'location_id': location_id
|
||||
'location_id': location_id,
|
||||
'partner_shipping_id': partner_shipping_id,
|
||||
})
|
||||
rma = wizard.sudo().create_rma()
|
||||
for rec in rma:
|
||||
|
||||
@@ -30,6 +30,30 @@
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
<t
|
||||
t-set="delivery_addresses"
|
||||
t-value="sale_order.partner_id.commercial_partner_id.mapped('child_ids').filtered(lambda x: x.type in ['contact', 'delivery'])"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-primary btn-block mb8"
|
||||
type="button" data-toggle="collapse"
|
||||
data-target="#delivery_address_picker"
|
||||
aria-expanded="false"
|
||||
|
||||
><i class="fa fa-truck" /> Choose a delivery address</button>
|
||||
<div class="col-lg-12 collapse mt8" id="delivery_address_picker">
|
||||
<div data-toggle="buttons" class="row">
|
||||
<label t-attf-class="card mr4 btn btn-light" t-foreach="delivery_addresses" t-as="address">
|
||||
<input class="d-none" type="radio" name="partner_shipping_id" t-att-value="address.id">
|
||||
<strong>
|
||||
<i t-attf-class="text-secondary fa #{address.type == 'delivery' and 'fa-truck' or 'fa-user'}" />
|
||||
<t t-esc="address.name"/>
|
||||
</strong>
|
||||
<pre><h6 t-esc="address.contact_address" /></pre>
|
||||
</input>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<t t-set="data_list" t-value="sale_order.get_delivery_rma_data()"/>
|
||||
<t t-set="operations" t-value="sale_order.env['rma.operation'].search([])"/>
|
||||
<table class="table table-sm" id="request-rma-table">
|
||||
|
||||
@@ -28,6 +28,16 @@ class SaleOrderRmaWizard(models.TransientModel):
|
||||
domain=_domain_location_id,
|
||||
default=lambda r: r.order_id.warehouse_id.rma_loc_id.id,
|
||||
)
|
||||
commercial_partner_id = fields.Many2one(
|
||||
comodel_name="res.partner",
|
||||
related="order_id.partner_id.commercial_partner_id",
|
||||
string="Commercial entity",
|
||||
)
|
||||
partner_shipping_id = fields.Many2one(
|
||||
comodel_name="res.partner",
|
||||
string="Shipping Address",
|
||||
help="Will be used to return the goods when the RMA is completed",
|
||||
)
|
||||
|
||||
def create_rma(self, from_portal=None):
|
||||
self.ensure_one()
|
||||
@@ -151,9 +161,13 @@ class SaleOrderLineRmaWizard(models.TransientModel):
|
||||
|
||||
def _prepare_rma_values(self):
|
||||
self.ensure_one()
|
||||
partner_shipping = (
|
||||
self.wizard_id.partner_shipping_id or
|
||||
self.order_id.partner_shipping_id)
|
||||
return {
|
||||
'partner_id': self.order_id.partner_id.id,
|
||||
'partner_invoice_id': self.order_id.partner_invoice_id.id,
|
||||
'partner_shipping_id': partner_shipping.id,
|
||||
'origin': self.order_id.name,
|
||||
'company_id': self.order_id.company_id.id,
|
||||
'location_id': self.wizard_id.location_id.id,
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
</field>
|
||||
</group>
|
||||
<group>
|
||||
<field name="commercial_partner_id" invisible="1" />
|
||||
<field name="partner_shipping_id" domain="[('id', 'child_of', commercial_partner_id)]" />
|
||||
<field name="location_id"
|
||||
options="{'no_create': True, 'no_open': True}"
|
||||
groups="stock.group_stock_multi_locations"
|
||||
|
||||
Reference in New Issue
Block a user