diff --git a/website_return_management/README.rst b/website_return_management/README.rst new file mode 100755 index 000000000..41567e563 --- /dev/null +++ b/website_return_management/README.rst @@ -0,0 +1,44 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +Website Return Order Management +=============================== +* Website Return Order Management module for Odoo 15 + +Installation +============ +- https://www.odoo.com/documentation/17.0/administration/install.html +- Install our custom addon + +Company +------- +* 'Cybrosys Techno Solutions `__ + +Credits +------- +* Developer: +(v14) Shijin @ Cybrosys +(v15) Sabeel @ Cybrosys +(v16) Rosmy @ Cybrosys + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com + +Further information +=================== +HTML Description: ``__ diff --git a/website_return_management/__init__.py b/website_return_management/__init__.py new file mode 100644 index 000000000..e069c001a --- /dev/null +++ b/website_return_management/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from . import controllers +from . import models +from . import wizard diff --git a/website_return_management/__manifest__.py b/website_return_management/__manifest__.py new file mode 100644 index 000000000..1b3060eae --- /dev/null +++ b/website_return_management/__manifest__.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +{ + 'name': 'Website Return Order Management', + 'version': '15.0.1.0.0', + 'category': 'Website', + 'summary': 'Sale Order Return Management from Website', + 'description': """Website Return Order Management, Website Return, + Order Return, RMA, Website RMA""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': 'https://www.cybrosys.com', + 'depends': ['website_sale', 'stock', 'sale_management'], + 'data': [ + 'security/ir.model.access.csv', + 'data/ir_sequence.xml', + 'views/website_thankyou_templates.xml', + 'views/portal_templates.xml', + 'views/sale_return_views.xml', + 'views/sale_order_views.xml', + 'views/res_partner_views.xml', + 'views/stock_picking_views.xml', + 'report/website_return_management_reports.xml' + ], + 'assets': { + 'web.assets_frontend': [ + 'website_return_management/static/src/js/sale_return.js' + ] + }, + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/website_return_management/controllers/__init__.py b/website_return_management/controllers/__init__.py new file mode 100644 index 000000000..359c34ded --- /dev/null +++ b/website_return_management/controllers/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from . import portal +from . import website_return_management diff --git a/website_return_management/controllers/portal.py b/website_return_management/controllers/portal.py new file mode 100644 index 000000000..0a8481c43 --- /dev/null +++ b/website_return_management/controllers/portal.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +import base64 +from collections import OrderedDict +from odoo import http +from odoo.http import request +from odoo.exceptions import AccessError, MissingError +from odoo.tools import image_process +from odoo.tools.translate import _ +from odoo.addons.portal.controllers.portal import CustomerPortal + + +class ReturnCustomerPortal(CustomerPortal): + """Class to show return orders on portal pages""" + def _prepare_home_portal_values(self, counters): + """Fetch total count of sale_return records""" + values = super()._prepare_home_portal_values(counters) + if 'return_count' in counters: + values['return_count'] = request.env['sale.return'].search_count([ + ('state', 'in', ['draft', 'confirm', 'done', 'cancel'])]) + return values + + @http.route(['/my/return_orders', + '/my/return_orders/page/'], + type='http', auth="user", website=True) + def portal_my_sale_return(self, page=1, date_begin=None, date_end=None, + sortby=None, filterby=None): + """Return History in my accounts""" + values = self._prepare_portal_layout_values() + sale_return = request.env['sale.return'] + domain = [] + searchbar_sortings = { + 'date': {'label': _('Newest'), 'order': 'create_date desc'}, + 'name': {'label': _('Name'), 'order': 'name'}, + 'sale': {'label': _('Sale Order'), 'order': 'sale_order'}, + } + # default sort by value + if not sortby: + sortby = 'date' + order = searchbar_sortings[sortby]['order'] + if date_begin and date_end: + domain += [('create_date', '>', date_begin), + ('create_date', '<=', date_end)] + searchbar_filters = { + 'all': {'label': _('All'), 'domain': [ + ('state', 'in', ['draft', 'confirm', 'done', 'cancel'])]}, + 'confirm': {'label': _('Confirmed'), 'domain': [ + ('state', '=', 'confirm')]}, + 'cancel': {'label': _('Cancelled'), 'domain': [ + ('state', '=', 'cancel')]}, + 'done': {'label': _('Done'), 'domain': [('state', '=', 'done')]}, + } + # default filter by value + if not filterby: + filterby = 'all' + domain += searchbar_filters[filterby]['domain'] + # pager + pager = request.website.pager( + url="/my/return_orders", + url_args={'date_begin': date_begin, 'date_end': date_end, + 'sortby': sortby}, + total=sale_return.search_count(domain), + page=page, + step=self._items_per_page + ) + # content according to pager and archive selected + orders = sale_return.search(domain, order=order, + limit=self._items_per_page, + offset=pager['offset']) + request.session['my_return_history'] = orders.ids[:100] + values.update({ + 'date': date_begin, + 'orders': orders.sudo(), + 'page_name': 'Sale_Return', + 'default_url': '/my/return_orders', + 'pager': pager, + 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())), + 'searchbar_sortings': searchbar_sortings, + 'sortby': sortby, + }) + return request.render("website_return_management.portal_my_returns", + values) + + @http.route(['/my/return_orders/'], type='http', + auth="public", website=True) + def portal_my_return_detail(self, order_id=None, access_token=None, + report_type=None, download=False, **kw): + """Passing datas for detailed display in my account""" + try: + order_sudo = self._document_check_access('sale.return', order_id, + access_token) + except (AccessError, MissingError): + return request.redirect('/my') + if report_type in ('html', 'pdf', 'text'): + return self._show_report(model=order_sudo, report_type=report_type, + report_ref='website_return_management.' + 'report_sale_returns', + download=download) + values = self._sale_return_get_page_view_values(order_sudo, + access_token, **kw) + return (request.render + ("website_return_management.portal_sale_return_page", values)) + + def _sale_return_get_page_view_values(self, order, access_token, **kwargs): + def resize_to_48(b64source): + """Converting product images""" + if not b64source: + b64source = request.env['ir.binary']._placeholder() + else: + b64source = base64.b64decode(b64source) + return base64.b64encode(image_process(b64source, size=(48, 48))) + values = { + 'orders': order, + 'resize_to_48': resize_to_48, + } + return self._get_page_view_values(order, access_token, values, + 'my_return_history', False, **kwargs) diff --git a/website_return_management/controllers/website_return_management.py b/website_return_management/controllers/website_return_management.py new file mode 100644 index 000000000..08a41ed86 --- /dev/null +++ b/website_return_management/controllers/website_return_management.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from datetime import datetime +from odoo import http, _ +from odoo.http import request +from odoo.addons.website.controllers import main + + +class CustomerRegistration(main.Home): + """Class to manage and create website return orders""" + @http.route('/sale_return', type='json', methods=['POST'], + auth="public", website=True, + csrf=False) + def sale_return(self, **kwargs): + """Controller to create return order""" + product_id = request.env['product.product'].sudo().search([ + ('id', '=', int(kwargs['product']))]) + order = request.env['sale.order'].sudo().search([ + ('id', '=', int(kwargs['order_id']))]) + values = { + 'partner_id': order.partner_id.id, + 'sale_order_id': order.id, + 'product_id': product_id.id, + 'quantity': kwargs['qty'], + 'reason': kwargs['reason'], + 'user_id': request.env.uid, + 'create_date': datetime.now(), + } + stock_picks = request.env['stock.picking'].search([ + ('origin', '=', order.name)]) + moves = (stock_picks.mapped('move_ids_without_package').filtered + (lambda p: p.product_id == product_id)) + if moves: + moves = moves.sorted('product_uom_qty', reverse=True) + values.update({'state': 'draft'}) + ret_order = request.env['sale.return'].create(values) + ret_order.return_confirm() + moves[0].picking_id.return_order_id = ret_order.id + moves[0].picking_id.return_order_picking = False + return True + + @http.route('/order_quantity', auth='public', type='json', + website=True) + def return_quantity(self, **kwargs): + """Check the existing records for total returned quantity""" + current_order = (request.env['sale.order'].sudo().browse + (int(kwargs['current_order']))) + for rec in current_order.order_line.filtered( + lambda ids: ids.product_id.id == int( + kwargs['product_id'])): + return_order = request.env['sale.return'].sudo().search([ + ('sale_order_id', '=', current_order.id), + ('product_id', '=', int(kwargs['product_id'])), + ('state', 'in', ('confirm', 'done'))]) + if return_order: + remaining_qty = rec.qty_delivered - sum( + return_order.mapped('quantity')) + if remaining_qty == 0: + rec.return_qty = True + return remaining_qty + else: + return rec.qty_delivered + + @http.route('/my/request-thank-you', website=True, page=True, + auth='public', csrf=False) + def maintenance_request_thanks(self): + """Thank you page""" + return (request.render + ('website_return_management.customers_request_thank_page')) diff --git a/website_return_management/data/ir_sequence.xml b/website_return_management/data/ir_sequence.xml new file mode 100644 index 000000000..f1035b62d --- /dev/null +++ b/website_return_management/data/ir_sequence.xml @@ -0,0 +1,13 @@ + + + + + + Sale Return + sale.return + RET + 5 + + + + diff --git a/website_return_management/doc/RELEASE_NOTES.md b/website_return_management/doc/RELEASE_NOTES.md new file mode 100755 index 000000000..5e6963a28 --- /dev/null +++ b/website_return_management/doc/RELEASE_NOTES.md @@ -0,0 +1,5 @@ +## Module +#### 16.02.2024 +#### Version 15.0.1.0.0 + +- Initial Commit for Website Return Order Management diff --git a/website_return_management/models/__init__.py b/website_return_management/models/__init__.py new file mode 100644 index 000000000..3716d1331 --- /dev/null +++ b/website_return_management/models/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from . import sale_order +from . import res_partner +from . import sale_return +from . import stock_picking diff --git a/website_return_management/models/res_partner.py b/website_return_management/models/res_partner.py new file mode 100644 index 000000000..3dc7fe6a2 --- /dev/null +++ b/website_return_management/models/res_partner.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from odoo import fields, models + + +class ResPartner(models.Model): + """Inheriting res_partner to show sale_return count""" + _inherit = 'res.partner' + + return_order_count = fields.Integer(compute="_compute_returns", + string='Return Orders', + help="Fetch return order count") + + def _compute_returns(self): + """Function to calculate the return count""" + all_partners = self.with_context(active_test=False).search([ + ('id', 'child_of', self.ids)]) + all_partners.read(['parent_id']) + sale_return_groups = self.env['sale.return'].sudo().read_group( + domain=[('partner_id', '=', all_partners.ids)], + fields=['partner_id'], groupby=['partner_id']) + partners = self.browse() + for group in sale_return_groups: + partner = self.browse(group['partner_id'][0]) + while partner: + if partner in self: + partner.return_order_count += group['partner_id_count'] + partners |= partner + partner = partner.parent_id + (self - partners).return_order_count = 0 + + def action_open_returns(self): + """This function returns an action that displays the sale return + orders from partner.""" + action = (self.env['ir.actions.act_window']._for_xml_id + ('website_return_management.sale_return_action')) + domain = [] + if self.is_company: + domain.append(('partner_id.commercial_partner_id.id', '=', self.id)) + else: + domain.append(('partner_id.id', '=', self.id)) + action['domain'] = domain + action['context'] = {'search_default_customer': 1} + return action diff --git a/website_return_management/models/sale_order.py b/website_return_management/models/sale_order.py new file mode 100644 index 000000000..1ec6219bb --- /dev/null +++ b/website_return_management/models/sale_order.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from odoo import fields, models + + +class SaleOrder(models.Model): + """Inheriting sale_order to add internal link and counts of sale_return""" + _inherit = 'sale.order' + + return_order_count = fields.Integer(compute="_compute_returns", + string='Return Orders', + help="Fetch return order count") + + def _compute_returns(self): + """method to compute return count""" + sale_return_groups = self.env['sale.return'].sudo().read_group( + domain=[('sale_order_id', '=', self.ids)], + fields=['sale_order_id'], groupby=['sale_order_id']) + orders = self.browse() + for group in sale_return_groups: + sale_order = self.browse(group['sale_order_id'][0]) + while sale_order: + if sale_order in self: + sale_order.return_order_count += ( + group)['sale_order_id_count'] + orders |= sale_order + sale_order = False + (self - orders).return_order_count = 0 + + def action_open_returns(self): + """This function returns an action that displays the sale return + orders from sale order""" + action = (self.env['ir.actions.act_window']._for_xml_id + ('website_return_management.sale_return_action')) + domain = [('sale_order_id', '=', self.id)] + action['domain'] = domain + action['context'] = {'search_default_order': 1} + return action + + +class SaleOrderLine(models.Model): + """Inherit sale order line to add a new field""" + _inherit = 'sale.order.line' + + return_qty = fields.Boolean(string="Return Qty", + help="Hide the product from returning") diff --git a/website_return_management/models/sale_return.py b/website_return_management/models/sale_return.py new file mode 100644 index 000000000..2220d8a79 --- /dev/null +++ b/website_return_management/models/sale_return.py @@ -0,0 +1,264 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from odoo import api, fields, models + + +class SaleReturn(models.Model): + _name = 'sale.return' + _inherit = ['portal.mixin'] + _rec_name = "name" + _order = "name" + _description = "Sale Return" + + @api.model + def _get_default_name(self): + """Default value for name field""" + return self.env['ir.sequence'].get('sale.return') + + active = fields.Boolean('Active', default=True, + help="Show Active Record") + name = fields.Char(string="Name", default=_get_default_name, + help="Name Field") + product_id = fields.Many2one('product.product', + string="Product Variant", required=True, + help="defines the product variant that need" + "to be returned") + product_tmpl_id = fields.Many2one('product.template', + related="product_id.product_tmpl_id", + store=True, + string="Product", + help="Product template relation") + sale_order_id = fields.Many2one('sale.order', + string="Sale Order", + required=True, help="Sale order relation") + partner_id = fields.Many2one('res.partner', string="Customer", + help="Res partner relation") + user_id = fields.Many2one('res.users', string="Responsible", + default=lambda self: self.env.user, + help="Res user relation") + create_date = fields.Datetime(string="Create Date", help="Create Date") + quantity = fields.Float(string="Quantity", default=0, + help="Number of quantity") + received_qty = fields.Float(string="Received Quantity", + help="Number of received quantity") + reason = fields.Text("Reason", help="Reason to add") + stock_picking_ids = fields.One2many('stock.picking', + 'return_order_pick_id', + domain="[" + "('return_order_id','=',False)]", + string="Return Picking", + help="Shows the return picking of the " + "corresponding return order") + picking_count = fields.Integer(compute="_compute_delivery", + string='Picking Order', copy=False, + default=0, + store=True, + help="Picking count") + delivery_count = fields.Integer(compute="_compute_delivery", + string='Delivery Order', copy=False, + default=0, + store=True, + help="Delivery Count") + state = fields.Selection([('draft', 'Draft'), + ('confirm', 'Confirm'), ('done', 'Done'), + ('cancel', 'Canceled')], + string='Status', readonly=True, default='draft', + help="State") + source_pick_ids = fields.One2many('stock.picking', + 'return_order_id', + string="Source Delivery", + domain="[('return_order_pick_id'," + "'=',False)]", + help="Shows the delivery orders of the " + "corresponding return order") + note = fields.Text("Note", help="Note field") + to_refund = fields.Boolean(string='Update SO/PO Quantity', + help='Trigger a decrease of the' + ' delivered/received quantity in' + ' the associated Sale ' + 'Order/Purchase Order') + + def return_confirm(self): + """Confirm the sale return""" + if not self.source_pick_ids: + stock_picks = self.env['stock.picking'].search([ + ('origin', '=', self.sale_order_id.name)]) + moves = (stock_picks.mapped('move_ids_without_package').filtered + (lambda p: p.product_id == self.product_id)) + else: + moves = (self.source_pick_ids.mapped + ('move_ids_without_package').filtered + (lambda p: p.product_id == self.product_id)) + if moves: + moves = moves.sorted('product_uom_qty', reverse=True) + return_pick_wizard = (self.env['stock.return.picking'].create + ({'picking_id': moves[0].picking_id.id})) + return_pick_wizard._onchange_picking_id() + return_pick_wizard.product_return_moves.unlink() + lines = {'product_id': self.product_id.id, + "quantity": self.quantity, + 'wizard_id': return_pick_wizard.id, + 'move_id': moves[0].id, 'to_refund': self.to_refund} + self.env['stock.return.picking.line'].create(lines) + return_pick = return_pick_wizard._create_returns() + if return_pick: + return_pick = self.env['stock.picking'].browse(return_pick[0]) + return_pick.update({'note': self.reason}) + return_pick.write({'return_order_id': False, + 'return_order_pick_id': self.id, + 'return_order_picking': True}) + self.write({'state': 'confirm'}) + + def return_cancel(self): + """Cancel the return""" + self.write({'state': 'cancel'}) + if self.source_pick_ids: + for rec in (self.source_pick_ids.filtered(lambda s: + s.state not in + ['done', 'cancel'])): + rec.action_cancel() + + def _get_report_base_filename(self): + """Fetch report name""" + self.ensure_one() + return 'Sale Return - %s' % (self.name) + + def _compute_access_url(self): + """URL accessing""" + super(SaleReturn, self)._compute_access_url() + for order in self: + order.access_url = '/my/return_orders/%s' % order.id + + @api.depends('stock_picking_ids', 'state') + def _compute_delivery(self): + """Function to compute picking and delivery counts""" + for rec in self: + rec.delivery_count = 0 + rec.picking_count = 0 + if rec.source_pick_ids: + rec.delivery_count = len(rec.source_pick_ids) + else: + rec.delivery_count = self.env['stock.picking'].search_count( + [('return_order_id', 'in', self.ids), + ('return_order_picking', '=', False)]) + if rec.stock_picking_ids: + rec.picking_count = len(rec.stock_picking_ids) + else: + rec.picking_count = self.env['stock.picking'].search_count( + [('return_order_pick_id', 'in', self.ids), + ('return_order_picking', '=', True)]) + + def action_view_picking(self): + """Function to view the stock picking transfers""" + action = (self.env["ir.actions.actions"]._for_xml_id + ("stock.action_picking_tree_all")) + pickings = self.mapped('stock_picking_ids') + if not self.stock_picking_ids: + pickings = self.env['stock.picking'].search( + [('return_order_pick_id', '=', self.id), + ('return_order_picking', '=', True)]) + if len(pickings) > 1: + action['domain'] = [('id', 'in', pickings.ids)] + elif pickings: + form_view = [(self.env.ref('stock.view_picking_form').id, 'form')] + if 'views' in action: + action['views'] = form_view + [(state, view) for state, view in + action['views'] + if view != 'form'] + else: + action['views'] = form_view + action['res_id'] = pickings.id + # Prepare the context. + picking_id = (pickings.filtered + (lambda x: x.picking_type_id.code == 'outgoing')) + if picking_id: + picking_id = picking_id[0] + else: + picking_id = pickings[0] + action['context'] = dict(self._context, + default_partner_id=self.partner_id.id, + default_picking_type_id= + picking_id.picking_type_id.id) + return action + + def action_view_delivery(self): + """Function to view the delivery transfers""" + action = (self.env["ir.actions.actions"]._for_xml_id + ("stock.action_picking_tree_all")) + pickings = self.mapped('stock_picking_ids') + if not self.stock_picking_ids: + pickings = self.env['stock.picking'].search( + [('return_order_id', '=', self.id), + ('return_order_picking', '=', False)]) + if len(pickings) > 1: + action['domain'] = [('id', 'in', pickings.ids)] + elif pickings: + form_view = [(self.env.ref('stock.view_picking_form').id, 'form')] + if 'views' in action: + action['views'] = form_view + [(state, view) for state, view in + action['views'] + if view != 'form'] + else: + action['views'] = form_view + action['res_id'] = pickings.id + # Prepare the context. + picking_id = (pickings.filtered(lambda x: + x.picking_type_id.code == 'outgoing')) + if picking_id: + picking_id = picking_id[0] + else: + picking_id = pickings[0] + action['context'] = dict(self._context, + default_partner_id=self.partner_id.id, + default_picking_type_id= + picking_id.picking_type_id.id) + return action + + @api.onchange('sale_order', 'source_pick') + def onchange_sale_order(self): + """All the fields are updated according to the sale order""" + delivery = None + if self.sale_order_id: + self.partner_id = self.sale_order_id.partner_id + + delivery = self.env['stock.picking'].search([ + ('origin', '=', self.sale_order_id.name)]) + if self.source_pick_ids: + delivery = self.source_pick_ids + if delivery: + product_ids = ( + delivery.move_ids_without_package.mapped('product_id').ids) + delivery = delivery.ids + else: + product_ids = self.sale_order_id.order_line.mapped('product_id').ids + + return {'domain': {'source_pick': [('id', 'in', delivery)], + 'product_id': [('id', 'in', product_ids)]}} + + @api.onchange('product_id') + def onchange_product_id(self): + """Return Stock Valuation""" + if self.product_id and self.source_pick_ids: + moves = (self.source_pick_ids.mapped('move_ids_without_package'). + filtered(lambda p: p.product_id == self.product_id)) + if moves: + self.received_qty = sum(moves.mapped('quantity_done')) diff --git a/website_return_management/models/stock_picking.py b/website_return_management/models/stock_picking.py new file mode 100644 index 000000000..bf853b35b --- /dev/null +++ b/website_return_management/models/stock_picking.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Sabeel B (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from odoo import fields, models + + +class StockPicking(models.Model): + """Inheriting stock_picking to add new fields regarding return orders""" + _inherit = 'stock.picking' + + return_order_id = fields.Many2one('sale.return', + string='Return Order', + help="Shows the return order of current" + "transfer") + return_order_pick_id = fields.Many2one('sale.return', + string='Return Order Pick', + help="Shows the return order picking" + "of current return order") + return_order_picking = fields.Boolean(string='Return Order Picking', + help="Helps to identify delivery" + " and return picking, if true" + "the transfer is return picking" + "else delivery") + + def button_validate(self): + """Supering Validate Button function""" + res = super(StockPicking, self).button_validate() + for rec in self: + if rec.return_order_pick_id: + if any(line.state != 'done' for line in + rec.return_order_pick_id.stock_picking_ids): + return res + else: + for line in (rec.return_order_pick_id.sale_order_id. + order_line.filtered( + lambda ids: ids.product_id.id == rec. + return_order_pick_id.product_id.id)): + return_order = self.env[ + 'sale.return'].sudo().search( + [('sale_order_id', '=', + rec.return_order_pick_id.sale_order_id.id), + ('product_id', '=', + rec.return_order_pick_id.product_id.id), + ('state', '=', 'done')]) + if (return_order and ( + sum(return_order.mapped('quantity')) + + rec.return_order_pick_id.quantity) == + line.qty_delivered): + line.return_qty = True + elif (rec.return_order_pick_id.quantity == + line.qty_delivered): + line.return_qty = True + rec.return_order_pick_id.state = 'done' + return res diff --git a/website_return_management/report/website_return_management_reports.xml b/website_return_management/report/website_return_management_reports.xml new file mode 100644 index 000000000..fcc3b4479 --- /dev/null +++ b/website_return_management/report/website_return_management_reports.xml @@ -0,0 +1,77 @@ + + + + + + Sale Return + sale.return + qweb-pdf + website_return_management.report_salereturn + website_return_management.report_salereturn + 'Sale Retun - %s' % object.name + + report + + + + + + + diff --git a/website_return_management/security/ir.model.access.csv b/website_return_management/security/ir.model.access.csv new file mode 100644 index 000000000..dce4d0701 --- /dev/null +++ b/website_return_management/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_sale_return,access.sale.return,model_sale_return,,1,1,1,1 diff --git a/website_return_management/static/description/assets/icons/check.png b/website_return_management/static/description/assets/icons/check.png new file mode 100644 index 000000000..ea0da5029 Binary files /dev/null and b/website_return_management/static/description/assets/icons/check.png differ diff --git a/website_return_management/static/description/assets/icons/chevron.png b/website_return_management/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..f49dd8541 Binary files /dev/null and b/website_return_management/static/description/assets/icons/chevron.png differ diff --git a/website_return_management/static/description/assets/icons/cogs.png b/website_return_management/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/website_return_management/static/description/assets/icons/cogs.png differ diff --git a/website_return_management/static/description/assets/icons/consultation.png b/website_return_management/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/website_return_management/static/description/assets/icons/consultation.png differ diff --git a/website_return_management/static/description/assets/icons/ecom-black.png b/website_return_management/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/website_return_management/static/description/assets/icons/ecom-black.png differ diff --git a/website_return_management/static/description/assets/icons/education-black.png b/website_return_management/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/website_return_management/static/description/assets/icons/education-black.png differ diff --git a/website_return_management/static/description/assets/icons/hotel-black.png b/website_return_management/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/website_return_management/static/description/assets/icons/hotel-black.png differ diff --git a/website_return_management/static/description/assets/icons/icon.png b/website_return_management/static/description/assets/icons/icon.png new file mode 100644 index 000000000..61b0eb171 Binary files /dev/null and b/website_return_management/static/description/assets/icons/icon.png differ diff --git a/website_return_management/static/description/assets/icons/license.png b/website_return_management/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/website_return_management/static/description/assets/icons/license.png differ diff --git a/website_return_management/static/description/assets/icons/lifebuoy.png b/website_return_management/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/website_return_management/static/description/assets/icons/lifebuoy.png differ diff --git a/website_return_management/static/description/assets/icons/logo.png b/website_return_management/static/description/assets/icons/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/website_return_management/static/description/assets/icons/logo.png differ diff --git a/website_return_management/static/description/assets/icons/manufacturing-black.png b/website_return_management/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/website_return_management/static/description/assets/icons/manufacturing-black.png differ diff --git a/website_return_management/static/description/assets/icons/pos-black.png b/website_return_management/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/website_return_management/static/description/assets/icons/pos-black.png differ diff --git a/website_return_management/static/description/assets/icons/puzzle.png b/website_return_management/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/website_return_management/static/description/assets/icons/puzzle.png differ diff --git a/website_return_management/static/description/assets/icons/restaurant-black.png b/website_return_management/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/website_return_management/static/description/assets/icons/restaurant-black.png differ diff --git a/website_return_management/static/description/assets/icons/service-black.png b/website_return_management/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/website_return_management/static/description/assets/icons/service-black.png differ diff --git a/website_return_management/static/description/assets/icons/trading-black.png b/website_return_management/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/website_return_management/static/description/assets/icons/trading-black.png differ diff --git a/website_return_management/static/description/assets/icons/training.png b/website_return_management/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/website_return_management/static/description/assets/icons/training.png differ diff --git a/website_return_management/static/description/assets/icons/update.png b/website_return_management/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/website_return_management/static/description/assets/icons/update.png differ diff --git a/website_return_management/static/description/assets/icons/user.png b/website_return_management/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/website_return_management/static/description/assets/icons/user.png differ diff --git a/website_return_management/static/description/assets/icons/wrench.png b/website_return_management/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/website_return_management/static/description/assets/icons/wrench.png differ diff --git a/website_return_management/static/description/assets/modules/budget_image.png b/website_return_management/static/description/assets/modules/budget_image.png new file mode 100644 index 000000000..b50130c7d Binary files /dev/null and b/website_return_management/static/description/assets/modules/budget_image.png differ diff --git a/website_return_management/static/description/assets/modules/credit_image.png b/website_return_management/static/description/assets/modules/credit_image.png new file mode 100644 index 000000000..3ad04ecfd Binary files /dev/null and b/website_return_management/static/description/assets/modules/credit_image.png differ diff --git a/website_return_management/static/description/assets/modules/employee_image.png b/website_return_management/static/description/assets/modules/employee_image.png new file mode 100644 index 000000000..30ad58232 Binary files /dev/null and b/website_return_management/static/description/assets/modules/employee_image.png differ diff --git a/website_return_management/static/description/assets/modules/export_image.png b/website_return_management/static/description/assets/modules/export_image.png new file mode 100644 index 000000000..492980ad0 Binary files /dev/null and b/website_return_management/static/description/assets/modules/export_image.png differ diff --git a/website_return_management/static/description/assets/modules/gantt_image.png b/website_return_management/static/description/assets/modules/gantt_image.png new file mode 100644 index 000000000..1ae7cfe3b Binary files /dev/null and b/website_return_management/static/description/assets/modules/gantt_image.png differ diff --git a/website_return_management/static/description/assets/modules/quotation_image.png b/website_return_management/static/description/assets/modules/quotation_image.png new file mode 100644 index 000000000..499b1a72f Binary files /dev/null and b/website_return_management/static/description/assets/modules/quotation_image.png differ diff --git a/website_return_management/static/description/assets/screenshots/hero.gif b/website_return_management/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..492359b67 Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/hero.gif differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_1.png b/website_return_management/static/description/assets/screenshots/scrshot_1.png new file mode 100644 index 000000000..f6e921f09 Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_1.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_10.png b/website_return_management/static/description/assets/screenshots/scrshot_10.png new file mode 100644 index 000000000..0a7935d8d Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_10.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_11.png b/website_return_management/static/description/assets/screenshots/scrshot_11.png new file mode 100644 index 000000000..04e05c19c Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_11.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_12.png b/website_return_management/static/description/assets/screenshots/scrshot_12.png new file mode 100644 index 000000000..53adb4195 Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_12.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_13.png b/website_return_management/static/description/assets/screenshots/scrshot_13.png new file mode 100644 index 000000000..254df2ac7 Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_13.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_14.png b/website_return_management/static/description/assets/screenshots/scrshot_14.png new file mode 100644 index 000000000..d9a54793f Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_14.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_2.png b/website_return_management/static/description/assets/screenshots/scrshot_2.png new file mode 100644 index 000000000..a2b065208 Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_2.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_3.png b/website_return_management/static/description/assets/screenshots/scrshot_3.png new file mode 100644 index 000000000..b343fa7b7 Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_3.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_4.png b/website_return_management/static/description/assets/screenshots/scrshot_4.png new file mode 100644 index 000000000..1daf28fcc Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_4.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_5.png b/website_return_management/static/description/assets/screenshots/scrshot_5.png new file mode 100644 index 000000000..0146b1d6f Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_5.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_6.png b/website_return_management/static/description/assets/screenshots/scrshot_6.png new file mode 100644 index 000000000..e32f78dac Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_6.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_7.png b/website_return_management/static/description/assets/screenshots/scrshot_7.png new file mode 100644 index 000000000..b4eb7e50c Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_7.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_8.png b/website_return_management/static/description/assets/screenshots/scrshot_8.png new file mode 100644 index 000000000..012e3d273 Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_8.png differ diff --git a/website_return_management/static/description/assets/screenshots/scrshot_9.png b/website_return_management/static/description/assets/screenshots/scrshot_9.png new file mode 100644 index 000000000..76c5ade43 Binary files /dev/null and b/website_return_management/static/description/assets/screenshots/scrshot_9.png differ diff --git a/website_return_management/static/description/banner.jpg b/website_return_management/static/description/banner.jpg new file mode 100644 index 000000000..021a0557b Binary files /dev/null and b/website_return_management/static/description/banner.jpg differ diff --git a/website_return_management/static/description/icon.png b/website_return_management/static/description/icon.png new file mode 100644 index 000000000..1a411d5aa Binary files /dev/null and b/website_return_management/static/description/icon.png differ diff --git a/website_return_management/static/description/index.html b/website_return_management/static/description/index.html new file mode 100644 index 000000000..1fc72d0e1 --- /dev/null +++ b/website_return_management/static/description/index.html @@ -0,0 +1,832 @@ +
+
+
+
+ +
+
+
+ Community +
+
+ Enterprise +
+ +
+
+
+
+ +
+
+
+
+

+ Website Return Order Management

+
+

+ Manage Sale Order return from Website +

+ +
+
+ +
+
+

+ Explore this module

+ +
+
+
+ +
+
+

+ Overview

+
+

+ This module enables the creation and management of sales order returns on the website. + Authorized individuals have the capability to oversee return orders. + Additionally, portal users can view their return orders through the account portal view +

+
+
+ +
+
+

+ Features

+
+
+
+
+ +

Create Return + Orders From Website

+ Customers can create return order from Portal/My Account and cangenerate return + order in backend by clicking the "Return" button to return item from the current order +
+ +
+ +

Portal Return + Order View

+ Customers can view the list of their return orders from My Account. +
+ +
+ +

Link Return + With Sale Order

+ Easily switch the return orders from sale order by clicking the + return smart button in the sale order. +
+
+
+
+ +

Link Return + Order With Partner +

+ We can see the list of return related to a partner from the + partner form view and easily switch to return order by clicking Return Count smart + button. +
+ +
+ +

Return Order + print

+ Allows to take PDF print of the return order. +
+
+
+
+
+ + +
+
+

+ Screenshots

+
+ +
+
+ +

Return Button on + Order Page on Portal

+
+

+ Goto Portal/ My Account -> Sale order , from the sale order + click Return button. +

+ +
+ +
+
+ +

Return Product Screen

+
+

+ From the product screen you can select the product , + quantity and return reason, after + that you can submit the return using Submit button. +

+ +
+ +
+
+ +

Return Orders in + Portal for View

+
+

+ Customer can see list of RMA orders in Portal / My Account. +

+ +
+ +
+
+ +

Return Orders tree + view in Portal.

+
+

+ The customer can see the basic details and status of the + return order. +

+ +
+ + +
+
+ +

Return Orders + detailed view in Portal.

+
+

+ The customer can see the detailed information of the return + order in portal. +

+ +
+ +
+
+ +

RMA Return Orders - + Backend

+
+

+ Return order tree view, Goto Sales -> Return Orders +

+ +
+ +
+
+ +

Return Orders form + view in backend.

+
+

+ Backend form view of return order. +

+ +
+ +
+
+ +

Delivery Order Tab + and Smart button

+
+

+ Shows all the delivery order's related with Sales order. +

+ +
+ +
+
+ +

Return Process on DO + picking.

+
+

+ Return picking creation from return order using confirm + button. +

+ +
+ +
+
+
+
+ +

Delivery Order Return + Button.

+
+

+ Return picking creation from return button in delivery (Odoo + Standard process). +

+ +
+ +
+ +
+
+ +

Delivery Order Return + Wizard(Odoo Standard).

+
+

+ Odoo default wizard for product return. +

+ +
+ + + +
+
+ +

Return Picking Order + Tab and Smart button)

+
+

+ Shows all the return picking order's related with Return Order. +

+ +
+ + + +
+
+ +

Smart Button on + Customer Form

+
+

+ On customer form smart button showing all return order related to that + customer. +

+ +
+ + + +
+
+ +

Smart Button on Sale + Order Form

+
+

+ On Sale Order form smart button showing all return order related to that + sale order. +

+ +
+ + + +
+
+ +

Return Orders - + Report Sample

+
+

+ Print RMA PDF Report - Print Return Report. +

+ +
+ + + + + +
+
+

+ Suggested Products

+
+ + +
+ + + +
+
+
+

+ Our Services

+
+
+ +
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+
+ + + +
+
+
+

+ Our Industries

+
+
+ +
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+ +
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+ +
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+ +
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+ +
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+ +
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+ +
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+ +
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

+
+
+ +
+
+ + + + + +
+
+
+

+ Need Help?

+
+
+
+ + +
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ + +
diff --git a/website_return_management/static/src/js/sale_return.js b/website_return_management/static/src/js/sale_return.js new file mode 100644 index 000000000..b041193cc --- /dev/null +++ b/website_return_management/static/src/js/sale_return.js @@ -0,0 +1,88 @@ +odoo.define('website_return_management.return', function(require) { + "use strict"; + var publicWidget = require('web.public.widget'); + var ajax = require('web.ajax'); + var rpc = require('web.rpc'); + var core = require('web.core'); + var QWeb = core.qweb; + /** + new component to publicWidget + */ + publicWidget.registry.returnOrderModal = publicWidget.Widget.extend({ + selector: 'div[id="sale_return_modal"]', + events: { + 'click #hidden_box_btn': '_onShowButtonClick', + 'change #product': '_onShowFormSubmit', + 'click #submit': '_onClickFormSubmit', + 'change #qty': '_onChangeQuantity', + }, + _onShowButtonClick: function() { + /** + on-click function to show the modal + */ + $('#hidden_box').modal('show'); + }, + _onShowFormSubmit: function() { + /** + on-click function to show the submit button + */ + var x = $('#submit'); + x.addClass('d-none'); + if ($("#product").val() == 'none') { + if (!x.hasClass('d-none')) { + x.addClass('d-none'); + } + } else { + if (x.hasClass('d-none')) { + x.removeClass('d-none'); + } + } + }, + + _onChangeQuantity: function() { + /** + on-change function to check the quantity + */ + if (!$("#warning_message").hasClass('d-none')) { + $('#warning_message').addClass('d-none'); + $('#submit').prop('disabled', false); +} + else if (!$("#product_null_warning").hasClass('d-none')){ + $('#product_null_warning').addClass('d-none'); + $('#submit').prop('disabled', false); + } + }, + + _onClickFormSubmit: function(ev) { + /** + on-click function to show the submit button + */ + ev.preventDefault(); + var current_order = $('#order_id').val() + var return_qty = $('#qty').val() + var product = $('#product').val() + var reason = $('#return_reason').val() + ajax.jsonRpc('/order_quantity', 'call', { + 'current_order': current_order, 'return_qty': return_qty, + 'product_id': product}) + .then(function(data) { + if (data < return_qty) { + $('#warning_message').removeClass('d-none'); + } + else if (return_qty <= 0){ + $('#product_null_warning').removeClass('d-none'); + $('#submit').prop('disabled', true); + } + else { + // Submit the form if the condition is met + ajax.jsonRpc('/sale_return', 'call', { + 'order_id': current_order, 'qty': return_qty, + 'product': product, 'reason': reason}).then(function(result) { + window.location.href = '/my/request-thank-you'; + }) + } + }); + + }, + }) +}) diff --git a/website_return_management/views/portal_templates.xml b/website_return_management/views/portal_templates.xml new file mode 100644 index 000000000..65730dda4 --- /dev/null +++ b/website_return_management/views/portal_templates.xml @@ -0,0 +1,377 @@ + + + +