From 07daace4cd4139e1aa4e4c5fe247b2474d1c0b25 Mon Sep 17 00:00:00 2001 From: Nikul-OSI Date: Wed, 29 Mar 2023 15:35:52 +0530 Subject: [PATCH] [MIG] osi_vendor_product_return: Migrated to v16 --- osi_vendor_product_return/README.rst | 34 + osi_vendor_product_return/__init__.py | 4 + osi_vendor_product_return/__manifest__.py | 26 + .../data/vendor_product_return_seq_view.xml | 13 + osi_vendor_product_return/models/__init__.py | 7 + osi_vendor_product_return/models/account.py | 16 + .../models/return_reason.py | 11 + osi_vendor_product_return/models/stock.py | 16 + .../models/vendor_product_return.py | 615 ++++++++++++++++++ .../report/product_return_report.xml | 14 + .../report/report_productreturn.xml | 135 ++++ .../security/ir.model.access.csv | 6 + .../security/security_view.xml | 9 + .../static/description/icon.png | Bin 0 -> 28332 bytes .../views/account_invoice_view.xml | 18 + .../views/return_reason_view.xml | 30 + .../views/stock_view.xml | 18 + .../views/vendor_product_return_view.xml | 244 +++++++ .../odoo/addons/osi_vendor_product_return | 1 + setup/osi_vendor_product_return/setup.py | 6 + 20 files changed, 1223 insertions(+) create mode 100644 osi_vendor_product_return/README.rst create mode 100644 osi_vendor_product_return/__init__.py create mode 100644 osi_vendor_product_return/__manifest__.py create mode 100644 osi_vendor_product_return/data/vendor_product_return_seq_view.xml create mode 100644 osi_vendor_product_return/models/__init__.py create mode 100644 osi_vendor_product_return/models/account.py create mode 100644 osi_vendor_product_return/models/return_reason.py create mode 100644 osi_vendor_product_return/models/stock.py create mode 100644 osi_vendor_product_return/models/vendor_product_return.py create mode 100644 osi_vendor_product_return/report/product_return_report.xml create mode 100644 osi_vendor_product_return/report/report_productreturn.xml create mode 100644 osi_vendor_product_return/security/ir.model.access.csv create mode 100644 osi_vendor_product_return/security/security_view.xml create mode 100644 osi_vendor_product_return/static/description/icon.png create mode 100644 osi_vendor_product_return/views/account_invoice_view.xml create mode 100644 osi_vendor_product_return/views/return_reason_view.xml create mode 100644 osi_vendor_product_return/views/stock_view.xml create mode 100644 osi_vendor_product_return/views/vendor_product_return_view.xml create mode 120000 setup/osi_vendor_product_return/odoo/addons/osi_vendor_product_return create mode 100644 setup/osi_vendor_product_return/setup.py diff --git a/osi_vendor_product_return/README.rst b/osi_vendor_product_return/README.rst new file mode 100644 index 000000000..4860712b0 --- /dev/null +++ b/osi_vendor_product_return/README.rst @@ -0,0 +1,34 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +===================== +Vendor Product Return +===================== + +This module will manage Product return to Vendor process after Quality Control +and creates Vendor Refund invoice. + +Configuration +============= + +* Checked Vendor RMA Management security right to user. + +Usage +===== + +* Create a product return from Purchase > Product Return. +* Provide source location and checked if you want to create bill refund and + confirm it. +* It will create refund vendor bills and out picking to vendor. + + +Credits +======= + +* Open Source Integrators + +Contributors +------------ + +* Bhavesh Odedra diff --git a/osi_vendor_product_return/__init__.py b/osi_vendor_product_return/__init__.py new file mode 100644 index 000000000..1d44b429a --- /dev/null +++ b/osi_vendor_product_return/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2017 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/osi_vendor_product_return/__manifest__.py b/osi_vendor_product_return/__manifest__.py new file mode 100644 index 000000000..f90aeeecb --- /dev/null +++ b/osi_vendor_product_return/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright (C) 2017 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Vendor Product Return", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "Open Source Integrators", + "maintainer": "Open Source Integrators", + "website": "https://github.com/ursais/osi-addons", + "category": "Purchases", + "depends": ["purchase", "stock", "account"], + "data": [ + "security/security_view.xml", + "security/ir.model.access.csv", + "data/vendor_product_return_seq_view.xml", + "views/stock_view.xml", + "views/account_invoice_view.xml", + "views/return_reason_view.xml", + "views/vendor_product_return_view.xml", + "report/product_return_report.xml", + "report/report_productreturn.xml", + ], + "application": True, + "installable": True, +} diff --git a/osi_vendor_product_return/data/vendor_product_return_seq_view.xml b/osi_vendor_product_return/data/vendor_product_return_seq_view.xml new file mode 100644 index 000000000..ba6b7c791 --- /dev/null +++ b/osi_vendor_product_return/data/vendor_product_return_seq_view.xml @@ -0,0 +1,13 @@ + + + + + + Vendor Product Return + vendor.product.return + PR + 4 + + + + diff --git a/osi_vendor_product_return/models/__init__.py b/osi_vendor_product_return/models/__init__.py new file mode 100644 index 000000000..c0aa72c30 --- /dev/null +++ b/osi_vendor_product_return/models/__init__.py @@ -0,0 +1,7 @@ +# Copyright (C) 2017 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import account +from . import stock +from . import return_reason +from . import vendor_product_return diff --git a/osi_vendor_product_return/models/account.py b/osi_vendor_product_return/models/account.py new file mode 100644 index 000000000..48f2c9345 --- /dev/null +++ b/osi_vendor_product_return/models/account.py @@ -0,0 +1,16 @@ +# Copyright (C) 2017 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountMove(models.Model): + + _inherit = "account.move" + + is_return_supplier = fields.Boolean(string="Return to Supplier") + vendor_return_id = fields.Many2one( + "vendor.product.return", + string="Vendor Return Reference", + readonly=True, + ) diff --git a/osi_vendor_product_return/models/return_reason.py b/osi_vendor_product_return/models/return_reason.py new file mode 100644 index 000000000..76a94505a --- /dev/null +++ b/osi_vendor_product_return/models/return_reason.py @@ -0,0 +1,11 @@ +# Copyright (C) 2017 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ReturnReason(models.Model): + _name = "return.reason" + _description = "Return Reason code" + + name = fields.Char(required=True, copy=False, index=True) diff --git a/osi_vendor_product_return/models/stock.py b/osi_vendor_product_return/models/stock.py new file mode 100644 index 000000000..3c6af4ee2 --- /dev/null +++ b/osi_vendor_product_return/models/stock.py @@ -0,0 +1,16 @@ +# Copyright (C) 2017 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class StockPicking(models.Model): + + _inherit = "stock.picking" + + is_return_supplier = fields.Boolean(string="Return to Supplier") + vendor_return_id = fields.Many2one( + "vendor.product.return", + string="Vendor Return Reference", + readonly=True, + ) diff --git a/osi_vendor_product_return/models/vendor_product_return.py b/osi_vendor_product_return/models/vendor_product_return.py new file mode 100644 index 000000000..476bacf94 --- /dev/null +++ b/osi_vendor_product_return/models/vendor_product_return.py @@ -0,0 +1,615 @@ +# Copyright (C) 2017 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class VendorProductReturn(models.Model): + _name = "vendor.product.return" + _description = "Vendor Product Return" + + @api.depends("return_line.last_price_unit") + def _compute_amount_all(self): + """Compute the total amounts of the Return.""" + for return_order in self: + amount_total = sum( + line.last_price_unit * line.quantity + for line in return_order.return_line + ) + return_order.amount_total = amount_total + + @api.depends("delivery_picking_ids") + def _compute_picking_count(self): + for rec in self: + rec.picking_count = len(rec.delivery_picking_ids.ids) + + @api.depends("vendor_refunds_ids") + def _compute_vendor_refund_count(self): + for rec in self: + rec.vendor_refund_count = len(rec.vendor_refunds_ids.ids) + + name = fields.Char( + string="Return Reference", + required=True, + copy=False, + readonly=True, + index=True, + default="New", + ) + state = fields.Selection( + [("draft", "Draft"), ("done", "Done")], + default="draft", + tracking=True, + ) + partner_id = fields.Many2one( + "res.partner", + string="Vendor", + required=True, + domain=[("supplier_rank", ">", 0)], + readonly=True, + states={"draft": [("readonly", False)]}, + ) + reference = fields.Char( + "Vendor RMA Number", + readonly=True, + states={"draft": [("readonly", False)]}, + ) + order_date = fields.Datetime( + required=True, + readonly=True, + states={"draft": [("readonly", False)]}, + default=fields.Datetime.now, + ) + is_create_refund = fields.Boolean( + "Create Refund", + default=True, + readonly=True, + states={"draft": [("readonly", False)]}, + ) + reason_return_id = fields.Many2one( + "return.reason", + "Reason for Return", + readonly=True, + states={"draft": [("readonly", False)]}, + ondelete="restrict", + ) + source_location_id = fields.Many2one( + "stock.location", + string="Source Location", + required=True, + domain=[("active", "=", True), ("usage", "=", "internal")], + readonly=True, + states={"draft": [("readonly", False)]}, + ) + destination_location_id = fields.Many2one( + "stock.location", + string="Destination Location", + required=True, + domain=[("active", "=", True), ("usage", "=", "supplier")], + readonly=True, + states={"draft": [("readonly", False)]}, + ) + company_id = fields.Many2one( + "res.company", + string="Company", + required=True, + default=lambda self: self.env.company, + readonly=True, + states={"draft": [("readonly", False)]}, + ) + return_line = fields.One2many( + "vendor.product.return.line", + "return_id", + string="Return Lines", + readonly=True, + states={"draft": [("readonly", False)]}, + ) + amount_total = fields.Monetary( + string="Total", + store=True, + readonly=True, + compute="_compute_amount_all", + # tracking=True + ) + currency_id = fields.Many2one( + "res.currency", + related="company_id.currency_id", + string="Currency", + readonly=True, + required=False, + ) + delivery_picking_ids = fields.One2many( + "stock.picking", + "vendor_return_id", + string="Delivery", + readonly=True, + states={"draft": [("readonly", False)]}, + ) + picking_count = fields.Integer(compute="_compute_picking_count", string="Delivery") + vendor_refunds_ids = fields.One2many( + "account.move", + "vendor_return_id", + string="Vendor Refunds Bill", + readonly=True, + states={"draft": [("readonly", False)]}, + ) + vendor_refund_count = fields.Integer( + compute="_compute_vendor_refund_count", string="Bill" + ) + + @api.model + def create(self, vals): + if vals.get("name", "New") == "New": + vals["name"] = ( + self.env["ir.sequence"].next_by_code("vendor.product.return") or "New" + ) + return super(VendorProductReturn, self).create(vals) + + def _get_picking_type_id(self): + warehouse_id = self.env["stock.warehouse"].search( + [("company_id", "=", self.company_id.id)] + ) + picking_type_id = self.env["stock.picking.type"].search( + [ + ("code", "=", "outgoing"), + ("warehouse_id", "in", warehouse_id.ids), + ], + limit=1, + ) + return picking_type_id.id + + @api.model + def _prepare_picking(self): + return { + "picking_type_id": self._get_picking_type_id(), + "partner_id": self.partner_id.id, + "date": self.order_date, + "is_return_supplier": True, + "location_id": self.source_location_id.id, + "location_dest_id": self.destination_location_id.id, + "vendor_return_id": self.id, + } + + def _product_qty_by_location(self, product, warehouse_stock_location): + # update context with source location + ctx = dict(self._context) + ctx.update({"location": warehouse_stock_location}) + + # get product quantity on hand + qty = product._compute_quantities_dict( + self._context.get("lot_id"), + self._context.get("owner_id"), + self._context.get("package_id"), + self._context.get("from_date"), + self._context.get("to_date"), + ) + + qty_wh = 0.0 + + if product.id in qty: + qty_wh = qty[product.id]["qty_available"] + + return qty_wh + + def _create_picking(self): + picking = False + for return_product in self: + + # check quantity based on source location + for line in return_product.return_line: + # get quantity on hand based on source location + qty = self._product_qty_by_location( + line.product_id, return_product.source_location_id.id + ) + if qty <= 0.0 and not line.product_id.type == "consu": + raise ValidationError( + _( + "Not enough quantity on hand to return." + "\n Product Name = %(name)s" + "\n Quantity On Hand = %(qty)s" + "\n Return Quantity = %(quantity)s" + ) + % { + "name": line.product_id.name, + "qty": qty, + "quantity": line.quantity, + } + ) + + # check product type + if any( + [ + ptype in ["product", "consu"] + for ptype in return_product.return_line.mapped("product_id.type") + ] + ): + + # prepare picking values + res = return_product._prepare_picking() + res.update({"origin": return_product.name}) + + # create stock picking Delivery order + picking = self.env["stock.picking"].create(res) + + # create stock moves + return_product.return_line.filtered( + lambda r: r.product_id.type in ["product", "consu"] + )._create_stock_moves(picking, return_product) + picking.action_assign() + + return picking + + def _get_journal(self): + + journal_pool = self.env["account.journal"] + company_id = self.env.company.id + + # set journal domain + journal_domain = [ + ("type", "=", "purchase"), + ("company_id", "=", company_id), + ] + + # search purchase refund journal + journal = journal_pool.search(journal_domain, limit=1) + + return journal.id + + def _prepare_invoice_dict(self, partner): + + # get journal + journal_id = self._get_journal() + + # prepare dict + inv_dict = { + "partner_id": partner.id, + "invoice_date": fields.Date.context_today(self), + "payment_reference": "none", + "move_type": "in_refund", + "journal_id": journal_id, + "user_id": self.env.user.id, + "is_return_supplier": True, + "ref": self.reference, + "vendor_return_id": self.id, + } + + return inv_dict + + def _create_vendor_bill(self): + for return_product in self: + # browse partner record + partner = return_product.partner_id + + # prepare invoice dict + inv_dict = self._prepare_invoice_dict(partner) + inv_dict.update({"invoice_origin": return_product.name}) + + # create vendor bill + vendor_bill = self.env["account.move"].create(inv_dict) + + inv_line_list = [] + for line in return_product.return_line: + + # set vendor bill line description + description = "" + if line.product_id.default_code: + description = "[" + line.product_id.default_code + "] " + + description += line.product_id.name + + # set account + accounts = line.product_id.product_tmpl_id.get_product_accounts( + vendor_bill.fiscal_position_id + ) + + account = accounts["stock_input"] + + if not account: + raise ValidationError( + _( + """Please update Product stock input account or + Product's category stock input account.""" + ) + ) + + # set invoice line dict + inv_line_list.append( + ( + 0, + 0, + { + "product_id": line.product_id.id, + "quantity": line.quantity, + "name": description, + "account_id": account.id, + "product_uom_id": line.uom_id.id, + "move_id": vendor_bill.id, + "analytic_distribution": line.analytic_distribution, + # "analytic_account_id": line.account_analytic_id.id, + "price_unit": abs(line.last_price_unit), + }, + ) + ) + + # update vendor bill line if its there + if inv_line_list: + vendor_bill.write({"invoice_line_ids": inv_line_list}) + + # Put the reason in the chatter + subject = _("Product Return to Vendor bill refund") + body = return_product.reason_return_id.display_name + vendor_bill.message_post(body=body, subject=subject) + + return True + + def create_delivery_order(self): + for return_product in self: + if not return_product.return_line.ids: + raise ValidationError( + _("You can not confirm return without return lines.") + ) + + # create delivery order + return_product._create_picking() + + # check condition for creating refund + if return_product.is_create_refund: + # create vendor refund bill + return_product._create_vendor_bill() + + # set state equal to done + return_product.write({"state": "done"}) + + return True + + def action_picking_view(self): + pickings = self.mapped("delivery_picking_ids") + action = self.env.ref("stock.action_picking_tree_ready").read()[0] + if len(pickings) > 1: + action["domain"] = [("id", "in", pickings.ids)] + elif len(pickings) == 1: + action["views"] = [(self.env.ref("stock.view_picking_form").id, "form")] + action["res_id"] = pickings.ids[0] + else: + action = {"type": "ir.actions.act_window_close"} + return action + + def action_refunds_bill_view(self): + bills = self.mapped("vendor_refunds_ids") + action = self.env.ref("account.action_move_in_refund_type").read()[0] + if len(bills) > 1: + action["domain"] = [("id", "in", bills.ids)] + elif len(bills) == 1: + action["views"] = [(self.env.ref("account.view_move_form").id, "form")] + action["res_id"] = bills.ids[0] + else: + action = {"type": "ir.actions.act_window_close"} + return action + + +class VendorProductReturnLine(models.Model): + _name = "vendor.product.return.line" + _inherit = "analytic.mixin" + _description = "Vendor Product Return Line" + + @api.depends("quantity", "last_price_unit") + def _compute_amount(self): + """Compute the amounts of the Return line.""" + for line in self: + line.update({"price_total": line.last_price_unit * line.quantity}) + + return_id = fields.Many2one("vendor.product.return", string="return_product ID") + product_id = fields.Many2one("product.product", string="Product", required=True) + tracking = fields.Selection( + [("serial", "Serial"), ("lot", "Lot"), ("none", "None")], + default="none", + related="product_id.tracking", + string="Tracking", + ) + quantity = fields.Float(default=1.0) + uom_id = fields.Many2one("uom.uom", string="Unit of Measure") + price_unit = fields.Float("Std Cost", digits="Product Price") + last_price_unit = fields.Float("Unit Price", digits="Product Price") + company_id = fields.Many2one( + "res.company", + related="return_id.company_id", + string="Company", + store=True, + readonly=True, + ) + qty_done = fields.Float("Done Qty") + price_total = fields.Monetary( + compute="_compute_amount", + string="Sub Total", + readonly=True, + store=True, + ) + currency_id = fields.Many2one( + related="return_id.currency_id", + store=True, + string="Currency", + readonly=True, + ) + + @api.onchange("product_id") + def _onchange_product(self): + if self.product_id: + # restrict to source location + if not self.return_id.source_location_id: + self.product_id = False + warning = { + "title": _("Warning!"), + "message": _("You must first select a source location!"), + } + return {"warning": warning} + + # set UoM and Standard Price + self.uom_id = self.product_id.uom_po_id.id + self.price_unit = self.product_id.standard_price + + # set stock move pool + move_obj = self.env["stock.move"] + + # last vendor price for product + # check vendor has last stock move + vendor_stock_moves_id = move_obj.search( + [ + ("partner_id", "=", self.return_id.partner_id.id), + ("state", "=", "done"), + ("product_id", "=", self.product_id.id), + ], + order="id desc", + limit=1, + ) + if vendor_stock_moves_id: + self.last_price_unit = vendor_stock_moves_id.price_unit + else: + # check last product price in other vendors + vendor_stock_moves_id = move_obj.search( + [ + ("state", "=", "done"), + ("product_id", "=", self.product_id.id), + ], + order="id desc", + limit=1, + ) + if vendor_stock_moves_id: + self.last_price_unit = vendor_stock_moves_id.price_unit + + # check Unit Price is equal to zero then update with product cost price + if self.last_price_unit == 0.0: + self.last_price_unit = self.product_id.standard_price + + def _create_stock_moves(self, picking, return_product): + # set variables + moves = self.env["stock.move"] + done = moves.browse() + + for line in self: + # prepare stock move values + template = { + "name": line.product_id.name or "", + "product_id": line.product_id.id, + "product_uom": line.uom_id.id, + "product_uom_qty": line.quantity, + "date": line.return_id.order_date, + "location_id": line.return_id.source_location_id.id, + "location_dest_id": line.return_id.destination_location_id.id, + "picking_id": picking.id, + "partner_id": line.return_id.partner_id.id, + "move_dest_ids": False, + "state": "draft", + "company_id": line.return_id.company_id.id, + "price_unit": line.last_price_unit, + "picking_type_id": line.return_id._get_picking_type_id(), + "group_id": False, + "origin": return_product.name, + } + + done += moves.create(template) + + return done + + def open_pack_return_operation(self): + # copy context + context = self._context + ctx = context.copy() + assert len(self) == 1 + # get form view id + form_view_id = self.env.ref( + "osi_vendor_product_return.view_pack_operation_return_lot_form" + ).id + # set variable + if self.tracking == "serial": + only_create = True + else: + only_create = False + ctx.update({"only_create": only_create}) + # search stock pack return operation id + res_id = self.env["stock.pack.return.operation"].search( + [("return_line_id", "=", self.id)], limit=1 + ) + res_id = res_id.id + return { + "name": _("Lot Details"), + "type": "ir.actions.act_window", + "view_type": "form", + "res_model": "stock.pack.return.operation", + "views": [[form_view_id, "form"]], + "view_mode": "form", + "target": "new", + "res_id": res_id, + "context": ctx, + } + + +class StockPackReturnOperation(models.Model): + _name = "stock.pack.return.operation" + _description = "Stock Pack Return Operation" + + product_qty = fields.Float("Quantity") + qty_done = fields.Float("Quantity") + product_id = fields.Many2one("product.product", string="Product") + product_uom_id = fields.Many2one("uom.uom", string="UoM") + return_operation_line = fields.One2many( + "stock.pack.return.operation.line", + "stock_pack_return_id", + string="Pack Return Operation", + ) + state = fields.Selection( + [("progress", "In Progress"), ("done", "Done")], + default="progress", + ) + return_line_id = fields.Many2one( + "vendor.product.return.line", string="Return Line ID" + ) + + @api.onchange("return_operation_line") + def _onchange_packlots(self): + + # update Done quantity + self.qty_done = sum([x.qty_done for x in self.return_operation_line]) + + @api.model + def default_get(self, fields): + + context = self._context + + # call super method + res = super(StockPackReturnOperation, self).default_get(fields) + + # update return_product values + for line in self.env["vendor.product.return.line"].browse( + context.get("active_ids", []) + ): + res.update( + { + "product_qty": line.quantity - line.qty_done, + "qty_done": line.qty_done, + "product_id": line.product_id and line.product_id.id, + "product_uom_id": line.uom_id and line.uom_id.id, + "return_line_id": line.id, + } + ) + return res + + def save(self): + + # update return line Done quantity + self.return_line_id.write( + {"qty_done": sum([x.qty_done for x in self.return_operation_line])} + ) + + return True + + +class StockPackReturnOperationLine(models.Model): + _name = "stock.pack.return.operation.line" + _description = "Stock Pack Return Operation Line" + + qty_done = fields.Float("Done", default=1.0) + production_lot_id = fields.Many2one("stock.lot", string="Lot/Serial Number") + stock_pack_return_id = fields.Many2one( + "stock.pack.return.operation", string="Stock Pack Operation" + ) diff --git a/osi_vendor_product_return/report/product_return_report.xml b/osi_vendor_product_return/report/product_return_report.xml new file mode 100644 index 000000000..7fd08690c --- /dev/null +++ b/osi_vendor_product_return/report/product_return_report.xml @@ -0,0 +1,14 @@ + + + + + Vendor Product Return + vendor.product.return + qweb-pdf + osi_vendor_product_return.report_productreturn + osi_vendor_product_return.report_productreturn + + report + + + diff --git a/osi_vendor_product_return/report/report_productreturn.xml b/osi_vendor_product_return/report/report_productreturn.xml new file mode 100644 index 000000000..77712e38c --- /dev/null +++ b/osi_vendor_product_return/report/report_productreturn.xml @@ -0,0 +1,135 @@ + + + + + + diff --git a/osi_vendor_product_return/security/ir.model.access.csv b/osi_vendor_product_return/security/ir.model.access.csv new file mode 100644 index 000000000..371cad5ee --- /dev/null +++ b/osi_vendor_product_return/security/ir.model.access.csv @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_vendor_product_return,access_vendor_product_return,model_vendor_product_return,base.group_user,1,1,1,1 +access_vendor_product_return_line,access_vendor_product_return_line,model_vendor_product_return_line,base.group_user,1,1,1,1 +access_stock_pack_return_operation,access_stock_pack_return_operation,model_stock_pack_return_operation,base.group_user,1,1,1,1 +access_stock_pack_return_operation_line,access_stock_pack_return_operation_line,model_stock_pack_return_operation_line,base.group_user,1,1,1,1 +access_return_reason,access_return_reason,model_return_reason,base.group_user,1,1,1,1 diff --git a/osi_vendor_product_return/security/security_view.xml b/osi_vendor_product_return/security/security_view.xml new file mode 100644 index 000000000..5c602a87d --- /dev/null +++ b/osi_vendor_product_return/security/security_view.xml @@ -0,0 +1,9 @@ + + + + + Vendor RMA Management + + + + diff --git a/osi_vendor_product_return/static/description/icon.png b/osi_vendor_product_return/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..85d01763f361c30600d58dc27612405c1827fa00 GIT binary patch literal 28332 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 XbJh3;7b);{a{ydLTe<9sW!V1%857^I literal 0 HcmV?d00001 diff --git a/osi_vendor_product_return/views/account_invoice_view.xml b/osi_vendor_product_return/views/account_invoice_view.xml new file mode 100644 index 000000000..22a47f520 --- /dev/null +++ b/osi_vendor_product_return/views/account_invoice_view.xml @@ -0,0 +1,18 @@ + + + + view.account.move.return.supplier.view + account.move + form + + + + + + + + diff --git a/osi_vendor_product_return/views/return_reason_view.xml b/osi_vendor_product_return/views/return_reason_view.xml new file mode 100644 index 000000000..379d601ce --- /dev/null +++ b/osi_vendor_product_return/views/return_reason_view.xml @@ -0,0 +1,30 @@ + + + + + + return.reason.tree + return.reason + + + + + + + + + + Return Reason + return.reason + tree + + + + + + diff --git a/osi_vendor_product_return/views/stock_view.xml b/osi_vendor_product_return/views/stock_view.xml new file mode 100644 index 000000000..08f8f9fe8 --- /dev/null +++ b/osi_vendor_product_return/views/stock_view.xml @@ -0,0 +1,18 @@ + + + + view.picking.return.supplier + stock.picking + form + + + + + + + + diff --git a/osi_vendor_product_return/views/vendor_product_return_view.xml b/osi_vendor_product_return/views/vendor_product_return_view.xml new file mode 100644 index 000000000..464906b0c --- /dev/null +++ b/osi_vendor_product_return/views/vendor_product_return_view.xml @@ -0,0 +1,244 @@ + + + + + + stock.pack.operation.return.lots.form + stock.pack.return.operation + + +
+ + + + + + + + + + + + +
+
+
+
+
+ + + + product.return.form + vendor.product.return + +
+
+
+ +
+ + +
+
+

+ +

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