diff --git a/rma_sale/__manifest__.py b/rma_sale/__manifest__.py index 08c51723..5d7dbe7b 100644 --- a/rma_sale/__manifest__.py +++ b/rma_sale/__manifest__.py @@ -20,6 +20,7 @@ "views/rma_views.xml", "views/sale_views.xml", "views/sale_portal_template.xml", + "views/res_config_settings_views.xml", "wizard/sale_order_rma_wizard_views.xml", ], } diff --git a/rma_sale/controllers/sale_portal.py b/rma_sale/controllers/sale_portal.py index 5c77c0c9..32f46b2c 100644 --- a/rma_sale/controllers/sale_portal.py +++ b/rma_sale/controllers/sale_portal.py @@ -20,10 +20,16 @@ class CustomerPortal(CustomerPortal): wizard_obj = request.env['sale.order.rma.wizard'] # Set wizard line vals mapped_vals = {} + custom_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}) + try: + row, field_name = name.split('-', 1) + mapped_vals.setdefault(row, {}).update({field_name: value}) + # Catch possible form custom fields to add them to the RMA + # description values + except ValueError: + custom_vals.update({name: value}) # If no operation is filled, no RMA will be created line_vals = [ (0, 0, vals) for vals in mapped_vals.values() @@ -31,10 +37,20 @@ class CustomerPortal(CustomerPortal): # Create wizard an generate rmas order = order_obj.browse(order_id).sudo() location_id = order.warehouse_id.rma_loc_id.id + # Add custom fields text + custom_description = "" + if custom_vals: + custom_description = r"---" + custom_description += ( + r"".join( + ["{}: {}".format(x, y) for x, y in custom_vals.items()] + ) + ) wizard = wizard_obj.with_context(active_id=order_id).create({ 'line_ids': line_vals, 'location_id': location_id, 'partner_shipping_id': partner_shipping_id, + 'custom_description': custom_description, }) rma = wizard.sudo().create_rma(from_portal=True) for rec in rma: @@ -47,3 +63,28 @@ class CustomerPortal(CustomerPortal): else: route = "/my/rmas?sale_id=%d" % order_id return request.redirect(route) + + @http.route( + ["/my/requestrma/"], + type="http", auth="public", website=True + ) + def request_sale_rma(self, order_id, access_token=None, **kw): + """Request RMA on a single page""" + try: + order_sudo = self._document_check_access( + "sale.order", order_id, access_token=access_token + ) + except (AccessError, MissingError): + return request.redirect("/my") + if order_sudo.state in ("draft", "sent", "cancel"): + return request.redirect("/my") + values = { + "sale_order": order_sudo, + "page_name": "request_rma", + "default_url": order_sudo.get_portal_url(), + "token": access_token, + "partner_id": order_sudo.partner_id.id, + } + if order_sudo.company_id: + values["res_company"] = order_sudo.company_id + return request.render("rma_sale.request_rma_single_page", values) diff --git a/rma_sale/models/__init__.py b/rma_sale/models/__init__.py index 0090dd37..16972d9b 100644 --- a/rma_sale/models/__init__.py +++ b/rma_sale/models/__init__.py @@ -1,5 +1,6 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). - +from . import res_company +from . import res_config_settings from . import rma from . import sale from . import stock_move diff --git a/rma_sale/models/res_company.py b/rma_sale/models/res_company.py new file mode 100644 index 00000000..737bcfcc --- /dev/null +++ b/rma_sale/models/res_company.py @@ -0,0 +1,13 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + show_full_page_sale_rma = fields.Boolean( + string="Full page RMA creation", + help="From the frontend sale order page go to a single RMA page " + "creation instead of the usual popup", + ) diff --git a/rma_sale/models/res_config_settings.py b/rma_sale/models/res_config_settings.py new file mode 100644 index 00000000..5b809adb --- /dev/null +++ b/rma_sale/models/res_config_settings.py @@ -0,0 +1,12 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + show_full_page_sale_rma = fields.Boolean( + related="company_id.show_full_page_sale_rma", + readonly=False, + ) diff --git a/rma_sale/views/res_config_settings_views.xml b/rma_sale/views/res_config_settings_views.xml new file mode 100644 index 00000000..4d5ceeea --- /dev/null +++ b/rma_sale/views/res_config_settings_views.xml @@ -0,0 +1,24 @@ + + + + + res.config.settings + + + + + + + + + + + + When we hit the RMA request button from the portal sale page, open in a single page instead of a popup. + + + + + + + diff --git a/rma_sale/views/sale_portal_template.xml b/rma_sale/views/sale_portal_template.xml index a9d197f2..a17adf67 100644 --- a/rma_sale/views/sale_portal_template.xml +++ b/rma_sale/views/sale_portal_template.xml @@ -1,145 +1,156 @@ + + + + + + Request RMAs + × + + + + + You're about to perform an RMA request. Our team will process it an will reach you once it's validated. Keep in mind that: + + Select the product quantity and the requested operation + Use the comment button to add relevant information regarding the RMA, like returned serial numbers or a description of the issue + If no requested operation is set, the RMA won't be correctly fulfilled + You can only return as much product units as you received for this order + The limit will decrease when the units in other RMAs are confirmed + You can send a message in every RMA sent + + + + + Choose a delivery address + + + + + + + + + + + + + + + + + + + Product + Quantity + Delivery + Requested operation + + + + + + + + + + + + + + + + + + + + + + + + + + --- + + + + + + + + + + + + + + + + + + + + + + + + - - Request RMAs - + + + Request RMAs + + + + + Request RMAs + + - + - - - - Request RMAs - × - - - - - You're about to perform an RMA request. Our team will process it an will reach you once it's validated. Keep in mind that: - - Select the product quantity and the requested operation - Use the comment button to add relevant information regarding the RMA, like returned serial numbers or a description of the issue - If no requested operation is set, the RMA won't be correctly fulfilled - You can only return as much product units as you received for this order - The limit will decrease when the units in other RMAs are confirmed - You can send a message in every RMA sent - - - - - Choose a delivery address - - - - - - - - - - - - - - - - - - - Product - Quantity - Delivery - Requested operation - - - - - - - - - - - - - - - - - - - - - - - - - - --- - - - - - - - - - - - - - - - - - - - - - - - + @@ -177,4 +188,44 @@ + + + + + + + + + RMA request for order + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rma_sale/wizard/sale_order_rma_wizard.py b/rma_sale/wizard/sale_order_rma_wizard.py index d6ca3ad0..f6910529 100644 --- a/rma_sale/wizard/sale_order_rma_wizard.py +++ b/rma_sale/wizard/sale_order_rma_wizard.py @@ -38,6 +38,9 @@ class SaleOrderRmaWizard(models.TransientModel): string="Shipping Address", help="Will be used to return the goods when the RMA is completed", ) + custom_description = fields.Text( + help="Values coming from portal RMA request form custom fields", + ) def create_rma(self, from_portal=None): self.ensure_one() @@ -172,6 +175,9 @@ class SaleOrderLineRmaWizard(models.TransientModel): partner_shipping = ( self.wizard_id.partner_shipping_id or self.order_id.partner_shipping_id) + description = ( + (self.description or '') + (self.wizard_id.custom_description or '') + ) return { 'partner_id': self.order_id.partner_id.id, 'partner_invoice_id': self.order_id.partner_invoice_id.id, @@ -186,5 +192,5 @@ class SaleOrderLineRmaWizard(models.TransientModel): 'product_uom_qty': self.quantity, 'product_uom': self.uom_id.id, 'operation_id': self.operation_id.id, - 'description': self.description, + 'description': description, }