diff --git a/.travis.yml b/.travis.yml index 55ef59e0..e82ce9ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ python: - "2.7" addons: + postgresql: "9.6" apt: packages: - expect-dev # provides unbuffer utility diff --git a/account_move_line_rma_order_line/README.rst b/account_move_line_rma_order_line/README.rst new file mode 100644 index 00000000..d8f62172 --- /dev/null +++ b/account_move_line_rma_order_line/README.rst @@ -0,0 +1,66 @@ +.. image:: https://img.shields.io/badge/license-AGPLv3-blue.svg + :target: https://www.gnu.org/licenses/agpl.html + :alt: License: AGPL-3 + +========================== +Account Move Line RMA Line +========================== + +This module will add the RMA order line to journal items. + +The ultimate goal is to establish the RMA order line as one of the key +fields to reconcile the Goods Received Not Invoiced accrual account. + + +Usage +===== + +The RMA order line will be automatically copied to the journal items. + +* When a supplier invoice is created referencing RMA orders, the + RMA order line will be copied to the corresponding journal item. + +* When a stock move is validated and generates a journal entry, the RMA + order line is copied to the account move line. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/92/9.0 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Jordi Ballester Alomar +* Aarón Henríquez Quintana + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_move_line_rma_order_line/__init__.py b/account_move_line_rma_order_line/__init__.py new file mode 100644 index 00000000..b33ed7e3 --- /dev/null +++ b/account_move_line_rma_order_line/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. (www.eficent.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import models diff --git a/account_move_line_rma_order_line/__manifest__.py b/account_move_line_rma_order_line/__manifest__.py new file mode 100644 index 00000000..922a0749 --- /dev/null +++ b/account_move_line_rma_order_line/__manifest__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. (www.eficent.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +{ + "name": "Account Move Line Rma Order Line", + "summary": "Introduces the rma order line to the journal items", + "version": "10.0.1.0.0", + "author": "Eficent, " + "Odoo Community Association (OCA)", + "website": "http://www.github.com/OCA/account-financial-tools", + "category": "Generic", + "depends": ["account_accountant", "rma_account"], + "license": "AGPL-3", + "data": [ + "security/account_security.xml", + "views/account_move_view.xml", + ], + 'installable': True, +} diff --git a/account_move_line_rma_order_line/models/__init__.py b/account_move_line_rma_order_line/models/__init__.py new file mode 100644 index 00000000..ce392315 --- /dev/null +++ b/account_move_line_rma_order_line/models/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. (www.eficent.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import account_move +from . import account_invoice +from . import stock_move diff --git a/account_move_line_rma_order_line/models/account_invoice.py b/account_move_line_rma_order_line/models/account_invoice.py new file mode 100644 index 00000000..87309049 --- /dev/null +++ b/account_move_line_rma_order_line/models/account_invoice.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. (www.eficent.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import api, models + + +class AccountInvoice(models.Model): + + _inherit = 'account.invoice' + + @api.model + def invoice_line_move_line_get(self): + res = super(AccountInvoice, self).invoice_line_move_line_get() + + invoice_line_model = self.env['account.invoice.line'] + for move_line_dict in res: + if 'invl_id' in move_line_dict: + line = invoice_line_model.browse(move_line_dict['invl_id']) + move_line_dict['rma_line_id'] = line.rma_line_id.id + + return res + + @api.model + def line_get_convert(self, line, part): + res = super(AccountInvoice, self).line_get_convert(line, part) + if line.get('rma_line_id', False): + res['rma_line_id'] = line.get('rma_line_id') + return res diff --git a/account_move_line_rma_order_line/models/account_move.py b/account_move_line_rma_order_line/models/account_move.py new file mode 100644 index 00000000..059d6783 --- /dev/null +++ b/account_move_line_rma_order_line/models/account_move.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. (www.eficent.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class AccountMoveLine(models.Model): + + _inherit = 'account.move.line' + + rma_line_id = fields.Many2one('rma.order.line', + 'Rma Order Line', + ondelete='set null', index=True) diff --git a/account_move_line_rma_order_line/models/stock_move.py b/account_move_line_rma_order_line/models/stock_move.py new file mode 100644 index 00000000..bdf0310d --- /dev/null +++ b/account_move_line_rma_order_line/models/stock_move.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. (www.eficent.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import api, models + + +class StockMove(models.Model): + _inherit = "stock.move" + + @api.multi + def _prepare_account_move_line(self, qty, cost, + credit_account_id, debit_account_id): + res = super(StockMove, self)._prepare_account_move_line( + qty, cost, credit_account_id, debit_account_id) + for line in res: + if line[2]["account_id"] != self.product_id.categ_id.\ + property_stock_valuation_account_id.id: + line[2]['rma_line_id'] = self.rma_line_id.id + return res diff --git a/account_move_line_rma_order_line/security/account_security.xml b/account_move_line_rma_order_line/security/account_security.xml new file mode 100644 index 00000000..a26966e7 --- /dev/null +++ b/account_move_line_rma_order_line/security/account_security.xml @@ -0,0 +1,10 @@ + + + + + Rma Order Line in Journal Items + + + + + diff --git a/account_move_line_rma_order_line/tests/__init__.py b/account_move_line_rma_order_line/tests/__init__.py new file mode 100644 index 00000000..f3dc4c5f --- /dev/null +++ b/account_move_line_rma_order_line/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent - Jordi Ballester Alomar +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import test_account_move_line_rma_order_line diff --git a/account_move_line_rma_order_line/tests/test_account_move_line_rma_order_line.py b/account_move_line_rma_order_line/tests/test_account_move_line_rma_order_line.py new file mode 100644 index 00000000..429c5eff --- /dev/null +++ b/account_move_line_rma_order_line/tests/test_account_move_line_rma_order_line.py @@ -0,0 +1,254 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. (www.eficent.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo.tests import common + + +class TestAccountMoveLineRmaOrderLine(common.SavepointCase): + + @classmethod + def setUpClass(cls): + super(TestAccountMoveLineRmaOrderLine, cls).setUpClass() + cls.rma_model = cls.env['rma.order'] + cls.rma_line_model = cls.env['rma.order.line'] + cls.rma_add_stock_move = cls.env['rma_add_stock_move'] + cls.rma_make_picking = cls.env['rma_make_picking.wizard'] + cls.invoice_model = cls.env['account.invoice'] + cls.stock_picking_model = cls.env['stock.picking'] + cls.invoice_line_model = cls.env['account.invoice.line'] + cls.product_model = cls.env['product.product'] + cls.product_ctg_model = cls.env['product.category'] + cls.acc_type_model = cls.env['account.account.type'] + cls.account_model = cls.env['account.account'] + cls.aml_model = cls.env['account.move.line'] + cls.res_users_model = cls.env['res.users'] + + cls.partner1 = cls.env.ref('base.res_partner_1') + cls.location_stock = cls.env.ref('stock.stock_location_stock') + cls.company = cls.env.ref('base.main_company') + cls.group_rma_user = cls.env.ref('rma.group_rma_customer_user') + cls.group_account_invoice = cls.env.ref( + 'account.group_account_invoice') + cls.group_account_manager = cls.env.ref( + 'account.group_account_manager') + cls.stock_location = cls.env.ref('stock.stock_location_stock') + wh = cls.env.ref('stock.warehouse0') + cls.stock_rma_location = wh.lot_rma_id + cls.customer_location = cls.env.ref( + 'stock.stock_location_customers') + cls.supplier_location = cls.env.ref( + 'stock.stock_location_suppliers') + # Create account for Goods Received Not Invoiced + acc_type = cls._create_account_type('equity', 'other') + name = 'Goods Received Not Invoiced' + code = 'grni' + cls.account_grni = cls._create_account( + acc_type, name, code, cls.company) + + # Create account for Cost of Goods Sold + acc_type = cls._create_account_type('expense', 'other') + name = 'Cost of Goods Sold' + code = 'cogs' + cls.account_cogs = cls._create_account( + acc_type, name, code, cls.company) + # Create account for Inventory + acc_type = cls._create_account_type('asset', 'other') + name = 'Inventory' + code = 'inventory' + cls.account_inventory = cls._create_account( + acc_type, name, code, cls.company) + # Create Product + cls.product = cls._create_product() + cls.product_uom_id = cls.env.ref('product.product_uom_unit') + # Create users + cls.rma_user = cls._create_user( + 'rma_user', [cls.group_rma_user, + cls.group_account_invoice], cls.company) + cls.account_invoice = cls._create_user( + 'account_invoice', [cls.group_account_invoice], cls.company) + cls.account_manager = cls._create_user( + 'account_manager', [cls.group_account_manager], cls.company) + + @classmethod + def _create_user(cls, login, groups, company): + """ Create a user.""" + group_ids = [group.id for group in groups] + user = \ + cls.res_users_model.with_context( + {'no_reset_password': True}).create({ + 'name': 'Test User', + 'login': login, + 'password': 'demo', + 'email': 'test@yourcompany.com', + 'company_id': company.id, + 'company_ids': [(4, company.id)], + 'groups_id': [(6, 0, group_ids)] + }) + return user.id + + @classmethod + def _create_account_type(cls, name, atype): + acc_type = cls.acc_type_model.create({ + 'name': name, + 'type': atype + }) + return acc_type + + @classmethod + def _create_account(cls, acc_type, name, code, company): + """Create an account.""" + account = cls.account_model.create({ + 'name': name, + 'code': code, + 'user_type_id': acc_type.id, + 'company_id': company.id + }) + return account + + @classmethod + def _create_product(cls): + """Create a Product.""" + # group_ids = [group.id for group in groups] + product_ctg = cls.product_ctg_model.create({ + 'name': 'test_product_ctg', + 'property_stock_valuation_account_id': cls.account_inventory.id, + 'property_valuation': 'real_time', + 'property_stock_account_input_categ_id': cls.account_grni.id, + 'property_stock_account_output_categ_id': cls.account_cogs.id, + }) + product = cls.product_model.create({ + 'name': 'test_product', + 'categ_id': product_ctg.id, + 'type': 'product', + 'standard_price': 1.0, + 'list_price': 1.0, + }) + return product + + @classmethod + def _create_picking(cls, partner): + return cls.stock_picking_model.create({ + 'partner_id': partner.id, + 'picking_type_id': cls.env.ref('stock.picking_type_in').id, + 'location_id': cls.stock_location.id, + 'location_dest_id': cls.supplier_location.id + }) + + @classmethod + def _prepare_move(cls, product, qty, src, dest, picking_in): + res = { + 'partner_id': cls.partner1.id, + 'product_id': product.id, + 'name': product.partner_ref, + 'state': 'confirmed', + 'product_uom': cls.product_uom_id.id or product.uom_id.id, + 'product_uom_qty': qty, + 'origin': 'Test RMA', + 'location_id': src.id, + 'location_dest_id': dest.id, + 'picking_id': picking_in.id + } + return res + + @classmethod + def _create_rma(cls, products2move, partner): + picking_in = cls._create_picking(partner) + moves = [] + for item in products2move: + move_values = cls._prepare_move( + item[0], item[1], cls.stock_location, + cls.customer_location, picking_in) + moves.append(cls.env['stock.move'].create(move_values)) + + rma_id = cls.rma_model.create( + { + 'reference': '0001', + 'type': 'customer', + 'partner_id': partner.id, + 'company_id': cls.env.ref('base.main_company').id + }) + for move in moves: + wizard = cls.rma_add_stock_move.with_context( + {'stock_move_id': move.id, 'customer': True, + 'active_ids': rma_id.id, + 'active_model': 'rma.order', + } + ).create({}) + data = wizard._prepare_rma_line_from_stock_move(move) + wizard.add_lines() + + if move.product_id.rma_customer_operation_id: + move.product_id.rma_customer_operation_id.in_route_id = False + move.product_id.categ_id.rma_customer_operation_id = False + move.product_id.rma_customer_operation_id = False + wizard._prepare_rma_line_from_stock_move(move) + cls.line = cls.rma_line_model.create(data) + return rma_id + + def _get_balance(self, domain): + """ + Call read_group method and return the balance of particular account. + """ + aml_rec = self.aml_model.read_group( + domain, ['debit', 'credit', 'account_id'], ['account_id']) + if aml_rec: + return aml_rec[0].get('debit', 0) - aml_rec[0].get('credit', 0) + else: + return 0.0 + + def _check_account_balance(self, account_id, rma_line=None, + expected_balance=0.0): + """ + Check the balance of the account + """ + domain = [('account_id', '=', account_id)] + if rma_line: + domain.extend([('rma_line_id', '=', rma_line.id)]) + + balance = self._get_balance(domain) + if rma_line: + self.assertEqual(balance, expected_balance, + 'Balance is not %s for rma Line %s.' + % (str(expected_balance), rma_line.name)) + + def test_rma_invoice(self): + """Test that the rma line moves from the rma order to the + account move line and to the invoice line. + """ + products2move = [(self.product, 1), ] + rma = self._create_rma(products2move, self.partner1) + rma_line = rma.rma_line_ids[0] + rma_line.action_rma_approve() + wizard = self.rma_make_picking.with_context({ + 'active_id': 1, + 'active_ids': rma.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'picking_type': 'incoming', + }).create({}) + procurements = wizard._create_picking() + group_ids = set([proc.group_id.id for proc in procurements if + proc.group_id]) + domain = [('group_id', 'in', list(group_ids))] + picking = self.stock_picking_model.search(domain) + picking.action_assign() + picking.do_transfer() + + expected_balance = -1.0 + self._check_account_balance(self.account_cogs.id, + rma_line=rma_line, + expected_balance=expected_balance) + + invoice = self.invoice_model.create({ + 'partner_id': self.partner1.id, + 'rma_id': rma.id, + 'account_id': rma.partner_id.property_account_payable_id.id, + }) + invoice.signal_workflow('invoice_open') + + for aml in invoice.move_id.line_ids: + if aml.product_id == rma_line.product_id and aml.invoice_id: + self.assertEqual( + aml.rma_line_id, rma_line, + 'Rma Order line has not been copied from the invoice to ' + 'the account move line.') diff --git a/account_move_line_rma_order_line/views/account_move_view.xml b/account_move_line_rma_order_line/views/account_move_view.xml new file mode 100644 index 00000000..1cd45d6d --- /dev/null +++ b/account_move_line_rma_order_line/views/account_move_view.xml @@ -0,0 +1,66 @@ + + + + + account.move.line.form + account.move.line + + + + + + + + + + account.move.line.form2 + account.move.line + + + + + + + + + + account.move.line.tree + account.move.line + + + + + + + + + + Journal Items + account.move.line + + + + + + + + + + + account.move.form + account.move + + + + + + + + + diff --git a/oca_dependencies.txt b/oca_dependencies.txt index 4b355cf7..18c5041f 100644 --- a/oca_dependencies.txt +++ b/oca_dependencies.txt @@ -1,5 +1,5 @@ stock-logistics-workflow manufacture operating-unit +account-analytic pidgeon https://github.com/acsone/account-analytic.git 10.0-purchase_analytic-cpi -pmis https://github.com/eficent/pmis 10.0 diff --git a/rma/__manifest__.py b/rma/__manifest__.py index 0327427b..1c5cee38 100644 --- a/rma/__manifest__.py +++ b/rma/__manifest__.py @@ -19,6 +19,8 @@ 'data/rma_sequence.xml', 'data/stock_data.xml', 'data/rma_operation.xml', + 'report/rma_report.xml', + 'report/rma_report_templates.xml', 'views/rma_order_view.xml', 'views/rma_operation_view.xml', 'views/rma_order_line_view.xml', diff --git a/rma/data/stock_data.xml b/rma/data/stock_data.xml index e3b4c2e8..f121c565 100644 --- a/rma/data/stock_data.xml +++ b/rma/data/stock_data.xml @@ -95,7 +95,6 @@ Customer → Supplier move - make_to_stock @@ -107,7 +106,6 @@ Supplier → Customer move - make_to_stock diff --git a/rma/models/procurement.py b/rma/models/procurement.py index accbb27c..4681d586 100644 --- a/rma/models/procurement.py +++ b/rma/models/procurement.py @@ -10,22 +10,23 @@ class ProcurementOrder(models.Model): rma_line_id = fields.Many2one( comodel_name='rma.order.line', string='RMA line', - ondelete="set null", + ondelete="set null", copy=False ) - @api.model + @api.multi def _get_stock_move_values(self): res = super(ProcurementOrder, self)._get_stock_move_values() - if self.rma_line_id: - line = self.rma_line_id - res['rma_line_id'] = line.id - # Propagate partner_dest_id for proper drop-shipment reports. - if procurement.partner_dest_id: - res['partner_id'] = procurement.partner_dest_id.id - dest_loc = self.env["stock.location"].browse([ - res["location_dest_id"]])[0] - if dest_loc.usage == "internal": - res["price_unit"] = line.price_unit + for procurement in self: + if self.rma_line_id: + line = self.rma_line_id + res['rma_line_id'] = line.id + # Propagate partner_dest_id for proper drop-shipment reports. + if procurement.partner_dest_id: + res['partner_id'] = procurement.partner_dest_id.id + dest_loc = self.env["stock.location"].browse([ + res["location_dest_id"]])[0] + if dest_loc.usage == "internal": + res["price_unit"] = line.price_unit return res @@ -34,9 +35,9 @@ class ProcurementGroup(models.Model): rma_id = fields.Many2one( comodel_name='rma.order', string='RMA', - ondelete="set null", + ondelete="set null", copy=False ) rma_line_id = fields.Many2one( comodel_name='rma.order.line', string='RMA line', - ondelete="set null", + ondelete="set null", copy=False, ) diff --git a/rma/models/rma_operation.py b/rma/models/rma_operation.py index 2c24165f..c9c4d3d5 100644 --- a/rma/models/rma_operation.py +++ b/rma/models/rma_operation.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import api, fields, models @@ -24,6 +24,14 @@ class RmaOperation(models.Model): def _default_supplier_location_id(self): return self.env.ref('stock.stock_location_suppliers') or False + @api.model + def _default_routes(self): + op_type = self.env.context.get('default_type') + if op_type == 'customer': + return self.env.ref('rma.route_rma_customer') + elif op_type == 'supplier': + return self.env.ref('rma.route_rma_supplier') + name = fields.Char('Description', required=True) code = fields.Char('Code', required=True) active = fields.Boolean(string='Active', default=True) @@ -36,15 +44,21 @@ class RmaOperation(models.Model): ('received', 'Based on Received Quantities')], string="Delivery Policy", default='no') in_route_id = fields.Many2one( - 'stock.location.route', string='Inbound Route', - domain=[('rma_selectable', '=', True)]) + comodel_name='stock.location.route', string='Inbound Route', + domain=[('rma_selectable', '=', True)], + default=_default_routes, + ) out_route_id = fields.Many2one( - 'stock.location.route', string='Outbound Route', - domain=[('rma_selectable', '=', True)]) + comodel_name='stock.location.route', string='Outbound Route', + domain=[('rma_selectable', '=', True)], + default=_default_routes, + ) customer_to_supplier = fields.Boolean( - 'The customer will send to the supplier', default=False) + string='The customer will send to the supplier', + ) supplier_to_customer = fields.Boolean( - 'The supplier will send to the customer', default=False) + string='The supplier will send to the customer', + ) in_warehouse_id = fields.Many2one( comodel_name='stock.warehouse', string='Inbound Warehouse', default=_default_warehouse_id) @@ -56,5 +70,7 @@ class RmaOperation(models.Model): type = fields.Selection([ ('customer', 'Customer'), ('supplier', 'Supplier')], string="Used in RMA of this type", required=True) - rma_line_ids = fields.One2many('rma.order.line', 'operation_id', - 'RMA lines') + rma_line_ids = fields.One2many( + comodel_name='rma.order.line', inverse_name='operation_id', + string='RMA lines', + ) diff --git a/rma/models/rma_order.py b/rma/models/rma_order.py index 6616333c..5e95d040 100644 --- a/rma/models/rma_order.py +++ b/rma/models/rma_order.py @@ -2,8 +2,7 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from odoo import api, fields, models, _ -from odoo.exceptions import UserError +from odoo import api, fields, models from datetime import datetime @@ -20,18 +19,14 @@ class RmaOrder(models.Model): @api.multi def _compute_in_shipment_count(self): for rec in self: - rec.in_shipment_count = len(rec.rma_line_ids.mapped( - 'move_ids').filtered( - lambda m: m.location_dest_id.usage == 'internal').mapped( - 'picking_id')) + rec.in_shipment_count = sum( + set(rec.rma_line_ids.mapped('in_shipment_count'))) @api.multi def _compute_out_shipment_count(self): for rec in self: - rec.out_shipment_count = len(rec.rma_line_ids.mapped( - 'move_ids').filtered( - lambda m: m.location_id.usage == 'internal').mapped( - 'picking_id')) + rec.out_shipment_count = sum( + set(rec.rma_line_ids.mapped('out_shipment_count'))) @api.multi def _compute_supplier_line_count(self): @@ -73,16 +68,6 @@ class RmaOrder(models.Model): required=True, default=lambda self: self.env.user.company_id) - @api.constrains("partner_id", "rma_line_ids") - def _check_partner_id(self): - if self.rma_line_ids and self.partner_id != self.mapped( - "rma_line_ids.partner_id"): - raise UserError(_( - "Group partner and RMA's partner must be the same.")) - if len(self.mapped("rma_line_ids.partner_id")) > 1: - raise UserError(_( - "All grouped RMA's should have same partner.")) - @api.model def create(self, vals): if (self.env.context.get('supplier') or diff --git a/rma/models/rma_order_line.py b/rma/models/rma_order_line.py index 9b17d5ff..7c426b5f 100644 --- a/rma/models/rma_order_line.py +++ b/rma/models/rma_order_line.py @@ -13,6 +13,7 @@ ops = {'=': operator.eq, class RmaOrderLine(models.Model): _name = "rma.order.line" _inherit = ['mail.thread'] + _order = 'create_date desc, id desc' @api.model def _get_default_type(self): @@ -47,18 +48,27 @@ class RmaOrderLine(models.Model): @api.multi def _compute_in_shipment_count(self): for line in self: - moves = line.mapped('move_ids').filtered( - lambda m: m.location_dest_id.usage == 'internal') - pickings = moves.mapped('picking_id') - line.in_shipment_count = len(pickings) + picking_ids = [] + for move in line.move_ids: + if move.location_dest_id.usage == 'internal': + picking_ids.append(move.picking_id.id) + else: + if line.customer_to_supplier: + picking_ids.append(move.picking_id.id) + shipments = list(set(picking_ids)) + line.in_shipment_count = len(shipments) @api.multi def _compute_out_shipment_count(self): + picking_ids = [] for line in self: - moves = line.mapped('move_ids').filtered( - lambda m: m.location_dest_id.usage != 'internal') - pickings = moves.mapped('picking_id') - line.out_shipment_count = len(pickings) + for move in line.move_ids: + if move.location_dest_id.usage in ('supplier', 'customer'): + if (not line.customer_to_supplier or + line.supplier_to_customer): + picking_ids.append(move.picking_id.id) + shipments = list(set(picking_ids)) + line.out_shipment_count = len(shipments) @api.multi def _get_rma_move_qty(self, states, direction='in'): @@ -72,9 +82,8 @@ class RmaOrderLine(models.Model): for move in rec.move_ids.filtered( lambda m: m.state in states and op(m.location_id.usage, rec.type)): - qty += product_obj._compute_qty_obj( - move.product_uom, move.product_uom_qty, - rec.uom_id) + qty += product_obj._compute_quantity( + move.product_uom_qty, rec.uom_id) return qty @api.multi @@ -85,10 +94,10 @@ class RmaOrderLine(models.Model): rec.qty_to_receive = 0.0 if rec.receipt_policy == 'ordered': rec.qty_to_receive = \ - rec.product_qty - rec.qty_incoming -rec.qty_received + rec.product_qty - rec.qty_received elif rec.receipt_policy == 'delivered': rec.qty_to_receive = \ - rec.qty_delivered - rec.qty_incoming - rec.qty_received + rec.qty_delivered - rec.qty_received @api.multi @api.depends('move_ids', 'move_ids.state', @@ -106,8 +115,12 @@ class RmaOrderLine(models.Model): @api.depends('move_ids', 'move_ids.state', 'type') def _compute_qty_incoming(self): for rec in self: - qty = rec._get_rma_move_qty( - ('draft', 'confirmed', 'assigned'), direction='in') + if rec.supplier_to_customer: + qty = rec._get_rma_move_qty( + ('draft', 'confirmed', 'assigned'), direction='out') + else: + qty = rec._get_rma_move_qty( + ('draft', 'confirmed', 'assigned'), direction='in') rec.qty_incoming = qty @api.multi @@ -121,8 +134,12 @@ class RmaOrderLine(models.Model): @api.depends('move_ids', 'move_ids.state', 'type') def _compute_qty_outgoing(self): for rec in self: - qty = rec._get_rma_move_qty( - ('draft', 'confirmed', 'assigned'), direction='out') + if rec.supplier_to_customer: + qty = rec._get_rma_move_qty( + ('draft', 'confirmed', 'assigned'), direction='in') + else: + qty = rec._get_rma_move_qty( + ('draft', 'confirmed', 'assigned'), direction='out') rec.qty_outgoing = qty @api.multi @@ -158,6 +175,13 @@ class RmaOrderLine(models.Model): rec.procurement_count = len(rec.procurement_ids.filtered( lambda p: p.state == 'exception')) + @api.multi + def _compute_rma_line_count(self): + for rec in self.filtered(lambda r: r.type == 'customer'): + rec.rma_line_count = len(rec.supplier_rma_line_ids) + for rec in self.filtered(lambda r: r.type == 'supplier'): + rec.rma_line_count = len(rec.customer_rma_id) + delivery_address_id = fields.Many2one( comodel_name='res.partner', string='Partner delivery address', default=_default_delivery_address, @@ -168,14 +192,17 @@ class RmaOrderLine(models.Model): rma_id = fields.Many2one( comodel_name='rma.order', string='RMA Group', track_visibility='onchange', readonly=True, + copy=False ) name = fields.Char( string='Reference', required=True, default='/', readonly=True, states={'draft': [('readonly', False)]}, + copy=False, help='Add here the supplier RMA #. Otherwise an internal code is' ' assigned.', ) description = fields.Text(string='Description') + conditions = fields.Html(string='Terms and conditions') origin = fields.Char( string='Source Document', readonly=True, states={'draft': [('readonly', False)]}, @@ -194,9 +221,11 @@ class RmaOrderLine(models.Model): ) assigned_to = fields.Many2one( comodel_name='res.users', track_visibility='onchange', + default=lambda self: self.env.uid, ) requested_by = fields.Many2one( comodel_name='res.users', track_visibility='onchange', + default=lambda self: self.env.uid, ) partner_id = fields.Many2one( comodel_name='res.partner', required=True, store=True, @@ -227,7 +256,7 @@ class RmaOrderLine(models.Model): required=True, readonly=True, states={'draft': [('readonly', False)]}, ) - price_unit = fields.Monetary( + price_unit = fields.Float( string='Price Unit', readonly=True, states={'draft': [('readonly', False)]}, ) @@ -310,14 +339,25 @@ class RmaOrderLine(models.Model): default=_default_location_id, ) customer_rma_id = fields.Many2one( - 'rma.order.line', string='Customer RMA line', ondelete='cascade') + 'rma.order.line', string='Customer RMA line', ondelete='cascade', + copy=False) supplier_rma_line_ids = fields.One2many( 'rma.order.line', 'customer_rma_id') + rma_line_count = fields.Integer( + compute='_compute_rma_line_count', + string='# of RMA lines associated', + ) supplier_address_id = fields.Many2one( - 'res.partner', readonly=True, + comodel_name='res.partner', readonly=True, states={'draft': [('readonly', False)]}, string='Supplier Address', - help="This address of the supplier in case of Customer RMA operation " + help="Address of the supplier in case of Customer RMA operation " + "dropship.") + customer_address_id = fields.Many2one( + comodel_name='res.partner', readonly=True, + states={'draft': [('readonly', False)]}, + string='Customer Address', + help="Address of the customer in case of Supplier RMA operation " "dropship.") qty_to_receive = fields.Float( string='Qty To Receive', @@ -361,6 +401,9 @@ class RmaOrderLine(models.Model): string="Under Warranty?", readonly=True, states={'draft': [('readonly', False)]}, ) + create_date = fields.Datetime(string='Creation Date', readonly=True, + index=True, + help="Date on which RMA order is created.") @api.multi def _prepare_rma_line_from_stock_move(self, sm, lot=False): @@ -377,13 +420,13 @@ class RmaOrderLine(models.Model): operation = self.env['rma.operation'].search( [('type', '=', self.type)], limit=1) if not operation: - raise ValidationError("Please define an operation first.") + raise ValidationError(_("Please define an operation first.")) if not operation.in_route_id or not operation.out_route_id: route = self.env['stock.location.route'].search( [('rma_selectable', '=', True)], limit=1) if not route: - raise ValidationError("Please define an RMA route.") + raise ValidationError(_("Please define an RMA route.")) if not operation.in_warehouse_id or not operation.out_warehouse_id: warehouse = self.env['stock.warehouse'].search( @@ -391,7 +434,8 @@ class RmaOrderLine(models.Model): ('lot_rma_id', '!=', False)], limit=1) if not warehouse: raise ValidationError( - "Please define a warehouse with a default RMA location.") + _("Please define a warehouse with a default RMA " + "location.")) data = { 'product_id': sm.product_id.id, @@ -455,7 +499,6 @@ class RmaOrderLine(models.Model): self.write({'state': 'to_approve'}) for rec in self: if rec.product_id.rma_approval_policy == 'one_step': - rec.write({'assigned_to': self.env.uid}) rec.action_rma_approve() return True @@ -493,15 +536,18 @@ class RmaOrderLine(models.Model): result = {} if not self.product_id: return result - self.product_qty = 1 self.uom_id = self.product_id.uom_id.id self.price_unit = self.product_id.standard_price + if not self.type: + self.type = self._get_default_type() if self.type == 'customer': self.operation_id = self.product_id.rma_customer_operation_id or \ self.product_id.categ_id.rma_customer_operation_id else: self.operation_id = self.product_id.rma_supplier_operation_id or \ self.product_id.categ_id.rma_supplier_operation_id + if self.lot_id.product_id != self.product_id: + self.lot_id = False return result @api.onchange('operation_id') @@ -528,16 +574,6 @@ class RmaOrderLine(models.Model): elif self.type == 'customer' and self.supplier_to_customer: self.delivery_policy = 'no' - @api.onchange('product_id') - def _onchange_product_id(self): - self.uom_id = self.product_id.uom_id - if self.lot_id.product_id != self.product_id: - self.lot_id = False - if self.product_id: - return {'domain': { - 'lot_id': [('product_id', '=', self.product_id.id)]}} - return {'domain': {'lot_id': []}} - @api.onchange("lot_id") def _onchange_lot_id(self): product = self.lot_id.product_id @@ -545,6 +581,16 @@ class RmaOrderLine(models.Model): self.product_id = product self.uom_id = product.uom_id + @api.onchange("in_warehouse_id") + def _onchange_in_warehouse_id(self): + if self.in_warehouse_id and self._get_default_type() == 'customer': + self.location_id = self.in_warehouse_id.lot_rma_id + + @api.onchange("out_warehouse_id") + def _onchange_out_warehouse_id(self): + if self.out_warehouse_id and self._get_default_type() == 'supplier': + self.location_id = self.out_warehouse_id.lot_rma_id + @api.multi def action_view_in_shipments(self): action = self.env.ref('stock.action_picking_tree_all') @@ -554,6 +600,10 @@ class RmaOrderLine(models.Model): for move in line.move_ids: if move.location_dest_id.usage == 'internal': picking_ids.append(move.picking_id.id) + else: + if line.customer_to_supplier: + picking_ids.append(move.picking_id.id) + shipments = list(set(picking_ids)) # choose the view_mode accordingly if len(shipments) != 1: @@ -573,7 +623,8 @@ class RmaOrderLine(models.Model): for line in self: for move in line.move_ids: if move.location_dest_id.usage in ('supplier', 'customer'): - picking_ids.append(move.picking_id.id) + if not line.customer_to_supplier: + picking_ids.append(move.picking_id.id) shipments = list(set(picking_ids)) # choose the view_mode accordingly if len(shipments) != 1: @@ -601,3 +652,33 @@ class RmaOrderLine(models.Model): result['views'] = [(res and res.id or False, 'form')] result['res_id'] = procurements[0] return result + + @api.multi + def action_view_rma_lines(self): + if self.type == 'customer': + # from customer we link to supplier rma + action = self.env.ref( + 'rma.action_rma_supplier_lines') + rma_lines = self.supplier_rma_line_ids + res = self.env.ref('rma.view_rma_line_supplier_form', False) + else: + # from supplier we link to customer rma + action = self.env.ref( + 'rma.action_rma_customer_lines') + rma_lines = self.customer_rma_id + res = self.env.ref('rma.view_rma_line_form', False) + result = action.read()[0] + # choose the view_mode accordingly + if rma_lines and len(rma_lines) != 1: + result['domain'] = "[('id', 'in', " + \ + str(rma_lines.ids) + ")]" + elif len(rma_lines) == 1: + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = rma_lines.id + return result + + @api.constrains("partner_id", "rma_id") + def _check_partner_id(self): + if self.rma_id and self.partner_id != self.rma_id.partner_id: + raise ValidationError(_( + "Group partner and RMA's partner must be the same.")) diff --git a/rma/models/stock.py b/rma/models/stock.py index 06a16f1b..513adbf5 100644 --- a/rma/models/stock.py +++ b/rma/models/stock.py @@ -26,7 +26,7 @@ class StockMove(models.Model): _inherit = "stock.move" rma_line_id = fields.Many2one('rma.order.line', string='RMA line', - ondelete='restrict') + ondelete='restrict', copy=False) @api.model def create(self, vals): @@ -37,9 +37,8 @@ class StockMove(models.Model): vals['rma_line_id'] = procurement.rma_line_id.id return super(StockMove, self).create(vals) - @api.model - def _prepare_picking_assign(self, move): - res = super(StockMove, self)._prepare_picking_assign(move) - if move.rma_line_id: - res['partner_id'] = move.rma_line_id.partner_id.id or False + def _get_new_picking_values(self): + res = super(StockMove, self)._get_new_picking_values() + if self.rma_line_id: + res['partner_id'] = self.rma_line_id.partner_id.id or False return res diff --git a/rma/models/stock_warehouse.py b/rma/models/stock_warehouse.py index 23c02c8f..6eb56127 100644 --- a/rma/models/stock_warehouse.py +++ b/rma/models/stock_warehouse.py @@ -58,8 +58,8 @@ class StockWarehouse(models.Model): def _rma_types_available(self): self.ensure_one() rma_types = self._get_rma_types() - for type in rma_types: - if not type: + for rtype in rma_types: + if not rtype: return False return True @@ -74,21 +74,22 @@ class StockWarehouse(models.Model): 'name': 'RMA', 'usage': 'internal', 'location_id': wh.lot_stock_id.id, + 'company_id': wh.company_id.id, }) # RMA types if not wh._rma_types_available(): wh._create_rma_picking_types() else: - for type in wh._get_rma_types(): - if type: - type.active = True + for rtype in wh._get_rma_types(): + if rtype: + rtype.active = True # RMA rules: wh._create_or_update_rma_pull() else: for wh in self: - for type in wh._get_rma_types(): - if type: - type.active = False + for rtype in wh._get_rma_types(): + if rtype: + rtype.active = False # Unlink rules: self.mapped('rma_customer_in_pull_id').unlink() self.mapped('rma_customer_out_pull_id').unlink() diff --git a/rma/report/rma_report.xml b/rma/report/rma_report.xml new file mode 100644 index 00000000..07a2a110 --- /dev/null +++ b/rma/report/rma_report.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/rma/report/rma_report_templates.xml b/rma/report/rma_report_templates.xml new file mode 100644 index 00000000..4f9e06bc --- /dev/null +++ b/rma/report/rma_report_templates.xml @@ -0,0 +1,103 @@ + + + + + + + diff --git a/rma/security/ir.model.access.csv b/rma/security/ir.model.access.csv index 291e1e5d..e899b9c9 100644 --- a/rma/security/ir.model.access.csv +++ b/rma/security/ir.model.access.csv @@ -8,4 +8,4 @@ access_rma_line_manager,rma.order.line,model_rma_order_line,group_rma_manager,1, access_rma_operation_manager,access_rma_operation,model_rma_operation,group_rma_manager,1,1,1,1 access_rma_operation_customer_user,access_rma_operation,model_rma_operation,group_rma_customer_user,1,0,0,0 access_rma_operation_supplier_user,access_rma_operation,model_rma_operation,group_rma_supplier_user,1,0,0,0 -access_stock_config_settings,access_stock_config_settings,model_stock_config_settings,stock.group_stock_manager,1,1,1,1 +access_rma_order_line_user,access_rma_order_line,model_rma_order_line,base.group_user,1,0,0,0 diff --git a/rma/security/rma.xml b/rma/security/rma.xml index b9b3ae95..be125f13 100644 --- a/rma/security/rma.xml +++ b/rma/security/rma.xml @@ -1,48 +1,47 @@ - - + + + RMA + + 30 + - - RMA - - 30 - + + RMA Customer User + + + º - - RMA Customer User - - - + + RMA Supplier User + + + - - RMA Supplier User - - - + + RMA Manager + + + + - - RMA Manager - - - - + + Addresses in RMA + + - - Addresses in RMA - - - + + RMA Groups + + - - - - - - - - - + + + + + + - diff --git a/rma/static/description/icon.png b/rma/static/description/icon.png new file mode 100644 index 00000000..ce758c20 Binary files /dev/null and b/rma/static/description/icon.png differ diff --git a/rma/tests/__init__.py b/rma/tests/__init__.py index dfa77946..1c2b27c0 100644 --- a/rma/tests/__init__.py +++ b/rma/tests/__init__.py @@ -2,5 +2,3 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from . import test_rma -from . import test_supplier_rma -from . import test_rma_dropship diff --git a/rma/tests/test_rma.py b/rma/tests/test_rma.py index 03f37fba..d4f2264f 100644 --- a/rma/tests/test_rma.py +++ b/rma/tests/test_rma.py @@ -6,166 +6,156 @@ from odoo.tests import common from odoo.exceptions import ValidationError -class TestRma(common.TransactionCase): - +class TestRma(common.SavepointCase): """ Test the routes and the quantities """ - def setUp(self): - super(TestRma, self).setUp() + @classmethod + def setUpClass(cls): + super(TestRma, cls).setUpClass() - self.rma_make_picking = self.env['rma_make_picking.wizard'] - self.make_supplier_rma = self.env["rma.order.line.make.supplier.rma"] - self.rma_add_stock_move = self.env['rma_add_stock_move'] - self.stockpicking = self.env['stock.picking'] - self.rma = self.env['rma.order'] - self.rma_line = self.env['rma.order.line'] - self.rma_op = self.env['rma.operation'] - self.rma_cust_replace_op_id = self.env.ref( + cls.rma_make_picking = cls.env['rma_make_picking.wizard'] + cls.make_supplier_rma = cls.env["rma.order.line.make.supplier.rma"] + cls.rma_add_stock_move = cls.env['rma_add_stock_move'] + cls.stockpicking = cls.env['stock.picking'] + cls.udpate_qty = cls.env['stock.change.product.qty'] + cls.rma = cls.env['rma.order'] + cls.rma_line = cls.env['rma.order.line'] + cls.rma_op = cls.env['rma.operation'] + cls.rma_cust_replace_op_id = cls.env.ref( 'rma.rma_operation_customer_replace') - self.rma_sup_replace_op_id = self.env.ref( + cls.rma_sup_replace_op_id = cls.env.ref( 'rma.rma_operation_supplier_replace') - self.product_id = self.env.ref('product.product_product_4') - self.product_1 = self.env.ref('product.product_product_25') - self.product_2 = self.env.ref('product.product_product_7') - self.product_3 = self.env.ref('product.product_product_11') - self.uom_unit = self.env.ref('product.product_uom_unit') + cls.product_id = cls.env.ref('product.product_product_4') + cls.product_1 = cls.env.ref('product.product_product_25') + cls.product_2 = cls.env.ref('product.product_product_8') + cls.product_3 = cls.env.ref('product.product_product_9') + cls.uom_unit = cls.env.ref('product.product_uom_unit') # assign an operation - self.product_id.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_1.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_2.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_3.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.partner_id = self.env.ref('base.res_partner_12') - self.stock_location = self.env.ref('stock.stock_location_stock') - wh = self.env.ref('stock.warehouse0') - self.stock_rma_location = wh.lot_rma_id - self.customer_location = self.env.ref( + cls.product_1.write( + {'rma_customer_operation_id': cls.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': cls.rma_sup_replace_op_id.id}) + cls.product_2.write( + {'rma_customer_operation_id': cls.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': cls.rma_sup_replace_op_id.id}) + cls.product_3.write( + {'rma_customer_operation_id': cls.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': cls.rma_sup_replace_op_id.id}) + cls.partner_id = cls.env.ref('base.res_partner_12') + cls.stock_location = cls.env.ref('stock.stock_location_stock') + wh = cls.env.ref('stock.warehouse0') + cls.stock_rma_location = wh.lot_rma_id + cls.customer_location = cls.env.ref( 'stock.stock_location_customers') - self.supplier_location = self.env.ref( + cls.supplier_location = cls.env.ref( 'stock.stock_location_suppliers') - self.product_uom_id = self.env.ref('product.product_uom_unit') - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_customer_id = self._create_rma_from_move( - products2move, 'customer', self.partner_id, + cls.product_uom_id = cls.env.ref('product.product_uom_unit') + # Customer RMA: + products2move = [(cls.product_1, 3), (cls.product_2, 5), + (cls.product_3, 2)] + cls.rma_customer_id = cls._create_rma_from_move( + products2move, 'customer', cls.env.ref('base.res_partner_2'), + dropship=False) + # Dropship: + cls.rma_droship_id = cls._create_rma_from_move( + products2move, 'customer', cls.env.ref('base.res_partner_2'), + dropship=True, + supplier_address_id=cls.env.ref('base.res_partner_3')) + # Supplier RMA: + cls.rma_supplier_id = cls._create_rma_from_move( + products2move, 'supplier', cls.env.ref('base.res_partner_1'), dropship=False) - def _create_picking(self, partner): - return self.stockpicking.create({ + @classmethod + def _create_picking(cls, partner): + return cls.stockpicking.create({ 'partner_id': partner.id, - 'picking_type_id': self.env.ref('stock.picking_type_in').id, - 'location_id': self.stock_location.id, - 'location_dest_id': self.supplier_location.id + 'picking_type_id': cls.env.ref('stock.picking_type_in').id, + 'location_id': cls.stock_location.id, + 'location_dest_id': cls.supplier_location.id }) - def _create_rma_from_move(self, products2move, type, partner, dropship, + @classmethod + def _create_rma_from_move(cls, products2move, rtype, partner, dropship, supplier_address_id=None): - picking_in = self._create_picking(partner) + picking_in = cls._create_picking(partner) moves = [] - if type == 'customer': + if rtype == 'customer': for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.stock_location, - self.customer_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) + move_values = cls._prepare_move( + item[0], item[1], cls.stock_location, + cls.customer_location, picking_in) + moves.append(cls.env['stock.move'].create(move_values)) else: for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.supplier_location, - self.stock_rma_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) + move_values = cls._prepare_move( + item[0], item[1], cls.supplier_location, + cls.stock_rma_location, picking_in) + moves.append(cls.env['stock.move'].create(move_values)) # Create the RMA from the stock_move - rma_id = self.rma.create( + rma_id = cls.rma.create( { 'reference': '0001', - 'type': type, + 'type': rtype, 'partner_id': partner.id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': cls.env.ref('base.main_company').id }) for move in moves: - if type == 'customer': - wizard = self.rma_add_stock_move.new( + if rtype == 'customer': + wizard = cls.rma_add_stock_move.with_context( {'stock_move_id': move.id, 'customer': True, 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, 'active_model': 'rma.order', } - ) - wizard.with_context({ - 'stock_move_id': move.id, 'customer': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }).default_get([str(move.id), - str(self.partner_id.id)]) - data = wizard.with_context(customer=1).\ - _prepare_rma_line_from_stock_move(move) + ).create({}) + data = wizard._prepare_rma_line_from_stock_move(move) wizard.add_lines() - data['partner_id'] = move.partner_id.id - for operation in move.product_id.rma_customer_operation_id: - operation.in_route_id = False + + if move.product_id.rma_customer_operation_id: + move.product_id.rma_customer_operation_id.in_route_id = \ + False move.product_id.categ_id.rma_customer_operation_id = False move.product_id.rma_customer_operation_id = False wizard._prepare_rma_line_from_stock_move(move) else: - wizard = self.rma_add_stock_move.new( + wizard = cls.rma_add_stock_move.with_context( {'stock_move_id': move.id, 'supplier': True, 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, 'active_model': 'rma.order', } - ) - wizard.with_context( - {'stock_move_id': move.id, 'supplier': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }).default_get([str(move.id), - str(self.partner_id.id)]) + ).create({}) wizard._prepare_rma_line_from_stock_move(move) wizard.add_lines() - wizard = self.rma_add_stock_move.new( + wizard = cls.rma_add_stock_move.with_context( {'stock_move_id': move.id, 'supplier': True, 'active_ids': [], - 'partner_id': move.partner_id.id, 'active_model': 'rma.order', } - ) + ).create({}) wizard.add_lines() - wizard = self.rma_add_stock_move.new( + wizard = cls.rma_add_stock_move.with_context( {'stock_move_id': move.id, 'supplier': True, 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, 'active_model': 'rma.order', } - ) + ).create({}) data = wizard._prepare_rma_line_from_stock_move(move) - data['partner_id'] = move.partner_id.id - for operation in move.product_id.rma_customer_operation_id: - operation.in_route_id = False + if move.product_id.rma_customer_operation_id: + move.product_id.rma_customer_operation_id.in_route_id = \ + False move.product_id.rma_customer_operation_id = False wizard.add_lines() if dropship: data.update(customer_to_supplier=dropship, supplier_address_id=supplier_address_id.id) - data['partner_id'] = move.partner_id.id - data['rma_id'] = rma_id.id - self.line = self.rma_line.create(data) + cls.line = cls.rma_line.create(data) # approve the RMA Line - self.rma_line.action_rma_to_approve() - self.line.action_rma_approve() + cls.line.action_rma_to_approve() + cls.line.action_rma_approve() rma_id._get_default_type() rma_id._compute_in_shipment_count() rma_id._compute_out_shipment_count() @@ -177,20 +167,16 @@ class TestRma(common.TransactionCase): rma_id.partner_id.action_open_partner_rma() rma_id.partner_id._compute_rma_line_count() - # approve the RMA - for line in rma_id.rma_line_ids: - line.action_rma_to_approve() - line.action_rma_approve() return rma_id - def _prepare_move(self, product, qty, src, dest, picking_in): - + @classmethod + def _prepare_move(cls, product, qty, src, dest, picking_in): res = { - 'partner_id': self.partner_id.id, + 'partner_id': cls.partner_id.id, 'product_id': product.id, 'name': product.partner_ref, 'state': 'confirmed', - 'product_uom': self.product_uom_id.id or product.uom_id.id, + 'product_uom': cls.product_uom_id.id or product.uom_id.id, 'product_uom_qty': qty, 'origin': 'Test RMA', 'location_id': src.id, @@ -199,23 +185,29 @@ class TestRma(common.TransactionCase): } return res - def test_rma_order_line(self): - partner2 = self.env.ref('base.res_partner_2') - picking_in = self._create_picking(partner2) + def update_product_qty(cls, product, qty=10.0): + up_wiz = cls.udpate_qty.create({ + 'product_id': product.id, + 'new_quantity': qty, + 'location_id': cls.stock_location.id, + }) + up_wiz.change_product_qty() + return True + + def test_01_rma_order_line(self): + picking_in = self._create_picking(self.env.ref('base.res_partner_2')) moves_1 = [] move_values = self._prepare_move(self.product_1, 3, self.stock_location, self.customer_location, picking_in) moves_1.append(self.env['stock.move'].create(move_values)) - wizard_1 = self.rma_add_stock_move.new( + wizard_1 = self.rma_add_stock_move.with_context( {'supplier': True, 'stock_move_id': [(6, 0, [m.id for m in moves_1])], 'active_ids': self.rma_customer_id.id, 'active_model': 'rma.order', - 'partner_id': self.partner_id.id, - 'move_ids': [(6, 0, [m.id for m in moves_1])] } - ) + ).create({'move_ids': [(6, 0, [m.id for m in moves_1])]}) wizard_1.add_lines() for line in self.rma_customer_id.rma_line_ids: @@ -232,6 +224,20 @@ class TestRma(common.TransactionCase): new_line = self.rma_line.new(data) new_line._onchange_reference_move_id() + # check assert if call reference_move_id onchange + self.assertEquals(new_line.product_id, + line.reference_move_id.product_id) + self.assertEquals(new_line.product_qty, + line.reference_move_id.product_uom_qty) + self.assertEquals(new_line.location_id.location_id, + line.reference_move_id.location_id) + self.assertEquals(new_line.origin, + line.reference_move_id.picking_id.name) + self.assertEquals(new_line.delivery_address_id, + line.reference_move_id.picking_partner_id) + self.assertEquals(new_line.qty_to_receive, + line.reference_move_id.product_uom_qty) + line.action_rma_to_approve() line.action_rma_draft() line.action_rma_done() @@ -244,6 +250,10 @@ class TestRma(common.TransactionCase): new_line = self.rma_line.new(data) new_line._onchange_operation_id() + # check assert if call operation_id onchange + self.assertEquals(new_line.operation_id.receipt_policy, + line.receipt_policy) + data = {'customer_to_supplier': line.customer_to_supplier} new_line = self.rma_line.new(data) new_line._onchange_receipt_policy() @@ -257,28 +267,28 @@ class TestRma(common.TransactionCase): line.action_view_procurements() self.rma_customer_id.action_view_supplier_lines() with self.assertRaises(ValidationError): - line.rma_id.partner_id = partner2.id + line.rma_id.partner_id = self.partner_id.id self.rma_customer_id.rma_line_ids[0].\ - partner_id = partner2.id + partner_id = self.partner_id.id self.rma_customer_id.action_view_supplier_lines() - def test_customer_rma(self): + def test_02_customer_rma(self): wizard = self.rma_make_picking.with_context({ 'active_ids': self.rma_customer_id.rma_line_ids.ids, 'active_model': 'rma.order.line', 'picking_type': 'incoming', 'active_id': 1 - }).create({'rma_id': self.rma_customer_id.id}) - wizard.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - 'active_id': 1 - }).default_get({}) - procurements = wizard._create_picking() - for proc in procurements: - proc._get_stock_move_values() + }).create({}) + # Before creating the picking: + for line in self.rma_customer_id.rma_line_ids: + if line.product_id == self.product_1: + self.assertEquals(line.qty_to_receive, 3.0) + if line.product_id == self.product_2: + self.assertEquals(line.qty_to_receive, 5.0) + if line.product_id == self.product_3: + self.assertEquals(line.qty_to_receive, 2.0) + procurements = wizard._create_picking() group_ids = set([proc.group_id.id for proc in procurements if proc.group_id]) domain = [('group_id', 'in', list(group_ids))] @@ -288,64 +298,47 @@ class TestRma(common.TransactionCase): moves = picking.move_lines self.assertEquals(len(moves), 3, "Incorrect number of moves created") + # After creating the picking: for line in self.rma_customer_id.rma_line_ids: # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") + self.assertEquals(line.qty_received, 0, "Wrong qty received") + self.assertEquals(line.qty_to_deliver, 0, "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 0, "Wrong qty outgoing") + self.assertEquals(line.qty_delivered, 0, "Wrong qty delivered") # product specific + # qty to receive should not consider qty incoming if line.product_id == self.product_1: - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_to_receive, 3, + self.assertEquals(line.qty_incoming, 3.0) + self.assertEquals(line.qty_to_receive, 3.0, "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty incoming") if line.product_id == self.product_2: - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_to_receive, 5, + self.assertEquals(line.qty_incoming, 5.0) + self.assertEquals(line.qty_to_receive, 5.0, "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty incoming") if line.product_id == self.product_3: - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_to_receive, 2, + self.assertEquals(line.qty_to_receive, 2.0, "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty incoming") - picking.action_assign() - picking.force_assign() - picking.do_new_transfer() - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_received, 0, - "Wrong qty to_receive") -# self.assertEquals(line.qty_incoming, 5, -# "Wrong qty incoming") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to received") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty incoming") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to received") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty incoming") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to received") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty incoming") + self.assertEquals(line.qty_incoming, 2.0) + # Validate the picking: + picking.action_assign() + picking.do_transfer() + for line in self.rma_customer_id.rma_line_ids: + self.assertEquals(line.qty_to_receive, 0, "Wrong qty to_receive") + self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") + self.assertEquals(line.qty_outgoing, 0, "Wrong qty outgoing") + self.assertEquals(line.qty_delivered, 0, "Wrong qty delivered") + if line.product_id == self.product_1: + self.assertEquals(line.qty_received, 3.0) + self.assertEquals(line.qty_to_deliver, 3.0) + if line.product_id == self.product_2: + self.assertEquals(line.qty_received, 5.0) + self.assertEquals(line.qty_to_deliver, 5.0) + if line.product_id == self.product_3: + self.assertEquals(line.qty_received, 2.0) + self.assertEquals(line.qty_to_deliver, 2.0) + + # Create delivery: wizard = self.rma_make_picking.with_context({ 'active_id': 1, 'active_ids': self.rma_customer_id.rma_line_ids.ids, @@ -359,67 +352,252 @@ class TestRma(common.TransactionCase): pickings = self.stockpicking.search(domain) self.assertEquals(len(pickings), 2, "Incorrect number of pickings created") - picking_out = pickings[0] + picking_out = pickings[1] moves = picking_out.move_lines self.assertEquals(len(moves), 3, "Incorrect number of moves created") for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_received, 0, - "Wrong qty receive") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") + self.assertEquals(line.qty_to_receive, 0, "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") + self.assertEquals(line.qty_delivered, 0, "Wrong qty delivered") if line.product_id == self.product_1: - self.assertEquals(line.qty_to_deliver, 0, + self.assertEquals(line.qty_to_deliver, 3.0, "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") + self.assertEquals(line.qty_received, 3.0) + self.assertEquals(line.qty_outgoing, 3.0) if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to received") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty incoming") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") + self.assertEquals(line.qty_to_deliver, 5.0, + "Wrong qty to deliver") + self.assertEquals(line.qty_received, 5.0) + self.assertEquals(line.qty_outgoing, 5.0) if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to received") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty incoming") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") + self.assertEquals(line.qty_to_deliver, 2.0, + "Wrong qty to deliver") + self.assertEquals(line.qty_received, 2.0) + self.assertEquals(line.qty_outgoing, 2.0) + + # Validate delivery: picking_out.action_assign() - picking_out.do_new_transfer() - for line in self.rma_customer_id.rma_line_ids[0]: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty incoming") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") + picking_out.do_transfer() + for line in self.rma_customer_id.rma_line_ids: + self.assertEquals(line.qty_to_receive, 0, "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") + self.assertEquals(line.qty_to_deliver, 0, "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 0, "Wrong qty outgoing") if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to received") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to delivered") + self.assertEquals(line.qty_received, 3.0) + self.assertEquals(line.qty_delivered, 3.0) if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") + self.assertEquals(line.qty_received, 5.0) + self.assertEquals(line.qty_delivered, 5.0) if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") + self.assertEquals(line.qty_received, 2.0) + self.assertEquals(line.qty_delivered, 2.0) self.line.action_rma_done() - self.assertEquals(self.line.state, 'done', - "Wrong State") + self.assertEquals(self.line.state, 'done', "Wrong State") + + # Dummy call to action_view methods. self.rma_customer_id.action_view_in_shipments() self.rma_customer_id.action_view_out_shipments() self.rma_customer_id.action_view_lines() + # Check counts: + self.assertEquals(self.rma_customer_id.out_shipment_count, 1) + self.assertEquals(self.rma_customer_id.in_shipment_count, 1) + + # DROPSHIP + def test_03_dropship(self): + # Before receiving or creating the delivery from supplier rma: + for line in self.rma_droship_id.rma_line_ids: + if line.product_id == self.product_1: + self.assertEquals(line.qty_to_supplier_rma, 3.0) + if line.product_id == self.product_2: + self.assertEquals(line.qty_to_supplier_rma, 5.0) + if line.product_id == self.product_3: + self.assertEquals(line.qty_to_supplier_rma, 2.0) + + # TODO: receive dropship + + # Create supplier rma: + wizard = self.make_supplier_rma.with_context({ + 'active_ids': self.rma_droship_id.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'active_id': 1 + }).create({}) + res = wizard.make_supplier_rma() + supplier_rma = self.rma.browse(res['res_id']) + for line in supplier_rma.rma_line_ids: + line.action_rma_to_approve() + line.action_rma_approve() + + for line in self.rma_droship_id.rma_line_ids: + self.assertEquals(line.qty_to_supplier_rma, 0.0) + if line.product_id == self.product_1: + self.assertEquals(line.qty_to_receive, 3.0) + self.assertEquals(line.qty_in_supplier_rma, 3.0) + if line.product_id == self.product_2: + self.assertEquals(line.qty_to_receive, 5.0) + self.assertEquals(line.qty_in_supplier_rma, 5.0) + if line.product_id == self.product_3: + self.assertEquals(line.qty_to_receive, 2.0) + self.assertEquals(line.qty_in_supplier_rma, 2.0) + + # Create deliveries from supplier rma: + wizard = self.rma_make_picking.with_context({ + 'active_id': 1, + 'active_ids': supplier_rma.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'picking_type': 'outgoing', + }).create({}) + procurements = wizard._create_picking() + group_ids = set([proc.group_id.id for proc in procurements if + proc.group_id]) + domain = [('group_id', 'in', list(group_ids))] + picking = self.stockpicking.search(domain) + self.assertEquals(len(picking), 1, + "Incorrect number of pickings created") + moves = picking.move_lines + self.assertEquals(len(moves), 3, + "Incorrect number of moves created") + for line in supplier_rma.rma_line_ids: + # common qtys for all products + self.assertEquals(line.qty_to_receive, 0, "Wrong qty to receive") + self.assertEquals(line.qty_received, 0, "Wrong qty received") + self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") + self.assertEquals(line.qty_delivered, 0, "Wrong qty delivered") + # product specific + if line.product_id == self.product_1: + self.assertEquals( + line.qty_to_deliver, 3.0, "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 3.0) + if line.product_id == self.product_2: + self.assertEquals(line.qty_outgoing, 5.0) + if line.product_id == self.product_3: + self.assertEquals(line.qty_outgoing, 2.0) + + for line in self.rma_droship_id.rma_line_ids: + line.action_rma_done() + self.assertEquals(line.state, 'done', "Wrong State") + + # Check counts: + self.assertEquals(self.rma_droship_id.out_shipment_count, 0) + self.assertEquals(supplier_rma.out_shipment_count, 1) + self.assertEquals(supplier_rma.in_shipment_count, 0) + + # Supplier RMA + def test_04_supplier_rma(self): + # Update quantities: + self.update_product_qty(self.product_1) + self.update_product_qty(self.product_2) + self.update_product_qty(self.product_3) + # Check correct RMA type: + self.assertEqual(self.rma_supplier_id.type, 'supplier') + for line in self.rma_supplier_id.rma_line_ids: + self.assertEqual(line.type, 'supplier') + # Create delivery: + wizard = self.rma_make_picking.with_context({ + 'active_ids': self.rma_supplier_id.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'picking_type': 'outgoing', + 'active_id': 1 + }).create({}) + procurements = wizard._create_picking() + group_ids = set([proc.group_id.id for proc in procurements if + proc.group_id]) + domain = [('group_id', 'in', list(group_ids))] + picking = self.stockpicking.search(domain) + self.assertEquals(len(picking), 1, + "Incorrect number of pickings created") + moves = picking.move_lines + self.assertEquals(len(moves), 3, + "Incorrect number of moves created") + for line in self.rma_supplier_id.rma_line_ids: + # common qtys for all products + self.assertEquals(line.qty_received, 0, "Wrong qty received") + self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") + self.assertEquals(line.qty_delivered, 0, "Wrong qty delivered") + # product specific + if line.product_id == self.product_1: + self.assertEquals( + line.qty_to_deliver, 3.0, "Wrong qty to deliver") + self.assertEquals(line.qty_to_receive, 3.0) + self.assertEquals(line.qty_outgoing, 3.0) + if line.product_id == self.product_2: + self.assertEquals(line.qty_to_receive, 5.0) + self.assertEquals(line.qty_outgoing, 5.0) + if line.product_id == self.product_3: + self.assertEquals(line.qty_to_receive, 2.0) + self.assertEquals(line.qty_outgoing, 2.0) + + # Validate Delivery: + picking.action_assign() + picking.do_transfer() + for line in self.rma_supplier_id.rma_line_ids: + self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") + self.assertEquals(line.qty_received, 0, "Wrong qty received") + if line.product_id == self.product_1: + self.assertEquals(line.qty_delivered, 3.0) + self.assertEquals(line.qty_to_receive, 3.0) + if line.product_id == self.product_2: + self.assertEquals(line.qty_delivered, 5.0) + self.assertEquals(line.qty_to_receive, 5.0) + if line.product_id == self.product_3: + self.assertEquals(line.qty_delivered, 2.0) + self.assertEquals(line.qty_to_receive, 2.0) + + # Create incoming shipment + wizard = self.rma_make_picking.with_context({ + 'active_id': 1, + 'active_ids': self.rma_supplier_id.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'picking_type': 'incoming', + }).create({}) + procurements = wizard._create_picking() + group_ids = set([proc.group_id.id for proc in procurements if + proc.group_id]) + domain = [ + ('group_id', 'in', list(group_ids)), + ('picking_type_code', '=', 'incoming')] + pickings = self.stockpicking.search(domain) + self.assertEquals(len(pickings), 1, + "Incorrect number of pickings created") + picking_out = pickings[0] + moves = picking_out.move_lines + self.assertEquals(len(moves), 3, + "Incorrect number of moves created") + for line in self.rma_supplier_id.rma_line_ids: + if line.product_id == self.product_1: + self.assertEquals( + line.qty_to_receive, 3.0, "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 3.0) + self.assertEquals(line.qty_delivered, 3.0) + if line.product_id == self.product_2: + self.assertEquals(line.qty_incoming, 5.0) + self.assertEquals(line.qty_delivered, 5.0) + if line.product_id == self.product_3: + self.assertEquals(line.qty_incoming, 2.0) + self.assertEquals(line.qty_delivered, 2.0) + + # Validate incoming shipment: + picking_out.action_assign() + picking_out.do_transfer() + for line in self.rma_supplier_id.rma_line_ids[0]: + self.assertEquals(line.qty_to_receive, 0, "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") + self.assertEquals(line.qty_to_deliver, 0, "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 0, "Wrong qty outgoing") + if line.product_id == self.product_1: + self.assertEquals(line.qty_received, 3.0) + self.assertEquals(line.qty_delivered, 3.0) + if line.product_id == self.product_2: + self.assertEquals(line.qty_received, 5.0) + self.assertEquals(line.qty_delivered, 5.0) + if line.product_id == self.product_3: + self.assertEquals(line.qty_received, 2.0) + self.assertEquals(line.qty_delivered, 2.0) + for line in self.rma_supplier_id.rma_line_ids: + line.action_rma_done() + self.assertEquals(line.state, 'done', "Wrong State") + + # Check counts: + self.assertEquals(self.rma_supplier_id.out_shipment_count, 1) + self.assertEquals(self.rma_supplier_id.in_shipment_count, 1) diff --git a/rma/tests/test_rma_dropship.py b/rma/tests/test_rma_dropship.py deleted file mode 100644 index 683c72a0..00000000 --- a/rma/tests/test_rma_dropship.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from . import test_rma - - -class TestRmaDropship(test_rma.TestRma): - - def setUp(self): - super(TestRmaDropship, self).setUp() - self.product_id.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_1.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_2.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_3.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_droship_id = self._create_rma_from_move( - products2move, 'customer', self.env.ref('base.res_partner_12'), - dropship=True, - supplier_address_id=self.env.ref('base.res_partner_3')) - - def test_dropship(self): - wizard = self.make_supplier_rma.with_context({ - 'active_ids': self.rma_droship_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({'partner_id': self.partner_id.id, - 'supplier_rma_id': self.rma_droship_id.id, - }) - - res = wizard.make_supplier_rma() - supplier_rma = self.rma.browse(res['res_id']) - for line in supplier_rma.rma_line_ids: - line.action_rma_to_approve() - line.action_rma_approve() - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': supplier_rma.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in supplier_rma.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_received, 0, - "Wrong qty receive") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - - for line in self.rma_droship_id.rma_line_ids[0]: - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 3, - "Wrong qty in supplier rma") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 5, - "Wrong qty in supplier rma") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 2, - "Wrong qty in supplier rma") - for line in self.rma_droship_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") diff --git a/rma/tests/test_supplier_rma.py b/rma/tests/test_supplier_rma.py deleted file mode 100644 index 1c3fd67f..00000000 --- a/rma/tests/test_supplier_rma.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from . import test_rma - - -class TestSupplierRma(test_rma.TestRma): - - def setUp(self): - super(TestSupplierRma, self).setUp() - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_supplier_id = self._create_rma_from_move( - products2move, 'supplier', self.env.ref('base.res_partner_1'), - dropship=False) - - def test_supplier_rma(self): - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'outgoing', - 'active_id': 1 - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 3, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 2, - "Wrong qty outgoing") - - picking.action_assign() - picking.do_new_transfer() - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - if line.product_id == self.product_2: - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - if line.product_id == self.product_3: - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - pickings = self.stockpicking.search(domain) - self.assertEquals(len(pickings), 2, - "Incorrect number of pickings created") - picking_out = pickings[0] - moves = picking_out.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - picking_out.action_assign() - picking_out.do_new_transfer() - for line in self.rma_supplier_id.rma_line_ids[0]: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 6, - "Wrong qty outgoing") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") - for line in self.rma_supplier_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") diff --git a/rma/views/product_view.xml b/rma/views/product_view.xml index bb35950b..5515d3bd 100644 --- a/rma/views/product_view.xml +++ b/rma/views/product_view.xml @@ -7,12 +7,14 @@ product.category - - + - - - + + @@ -25,8 +27,12 @@ - - + + diff --git a/rma/views/rma_order_line_view.xml b/rma/views/rma_order_line_view.xml index 4fdc9328..1e2c3101 100644 --- a/rma/views/rma_order_line_view.xml +++ b/rma/views/rma_order_line_view.xml @@ -8,6 +8,7 @@ + @@ -30,6 +31,7 @@ + @@ -90,6 +92,13 @@ +

@@ -101,6 +110,23 @@ + + + + + + + + + + + + + + - - - - - - - - - - - - @@ -132,27 +144,36 @@ - + - + + + + - - + - - - + domain="['|', ('parent_id', '=', partner_id), + ('id', '=', partner_id)]" + context="{'show_address': 1}" + options="{'always_reload': 1}" + groups='rma.group_rma_delivery_invoice_address'/> + + + @@ -177,6 +198,7 @@ + @@ -200,7 +222,7 @@ rma.order.line.form rma.order.line -
+
- +

@@ -259,11 +283,28 @@ + + + + + + + + + + + + + + - - - - - - - - - - - - @@ -293,37 +320,39 @@ - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + - + @@ -343,6 +372,7 @@ + @@ -373,8 +403,17 @@ + + + + + + + + + diff --git a/rma/views/rma_order_view.xml b/rma/views/rma_order_view.xml index 955082f6..cdcbea47 100644 --- a/rma/views/rma_order_view.xml +++ b/rma/views/rma_order_view.xml @@ -279,14 +279,14 @@ id="menu_rma_act_customer" sequence="50" parent="menu_customer_rma" - groups="rma.group_rma_customer_user" + groups="rma.group_rma_groups" action="action_rma_customer"/> 1: raise ValidationError( - _('Only RMA lines from the same supplier address can be ' + _('Only RMA lines from the same supplier can be ' 'processed at the same time')) + res['partner_id'] = suppliers.id res['item_ids'] = items return res @@ -81,7 +79,6 @@ class RmaLineMakeSupplierRma(models.TransientModel): raise ValidationError(_('Enter a supplier.')) return { 'partner_id': self.partner_id.id, - 'delivery_address_id': self.partner_id.id, 'type': 'supplier', 'company_id': company.id, } @@ -108,8 +105,9 @@ class RmaLineMakeSupplierRma(models.TransientModel): 'partner_id': self.partner_id.id, 'type': 'supplier', 'origin': item.line_id.rma_id.name, - 'delivery_address_id': - item.line_id.delivery_address_id.id, + 'customer_address_id': + item.line_id.delivery_address_id.id or + item.line_id.partner_id.id, 'product_id': item.line_id.product_id.id, 'customer_rma_id': item.line_id.id, 'product_qty': item.product_qty, @@ -151,27 +149,18 @@ class RmaLineMakeSupplierRma(models.TransientModel): rma_line_data = self._prepare_supplier_rma_line(rma, item) rma_line = rma_line_obj.create(rma_line_data) if rma: - return { - 'name': _('Supplier RMA'), - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'rma.order', - 'view_id': False, - 'res_id': rma.id, - 'context': {'supplier': True, 'customer': False}, - 'type': 'ir.actions.act_window' - } + action = self.env.ref('rma.action_rma_supplier') + result = action.read()[0] + res = self.env.ref('rma.view_rma_supplier_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = rma.id else: - return { - 'name': _('Supplier RMA Line'), - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'rma.order.line', - 'view_id': False, - 'res_id': rma_line.id, - 'context': {'supplier': True, 'customer': False}, - 'type': 'ir.actions.act_window' - } + action = self.env.ref('rma.action_rma_supplier_lines') + result = action.read()[0] + res = self.env.ref('rma.view_rma_line_supplier_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = rma_line.id + return result class RmaLineMakeRmaOrderItem(models.TransientModel): diff --git a/rma/wizards/rma_order_line_make_supplier_rma_view.xml b/rma/wizards/rma_order_line_make_supplier_rma_view.xml index 59f0cbf6..d34d2eaa 100644 --- a/rma/wizards/rma_order_line_make_supplier_rma_view.xml +++ b/rma/wizards/rma_order_line_make_supplier_rma_view.xml @@ -64,7 +64,7 @@ - Create Supplier RMA Group + Create Supplier RMA client_action_multi @@ -80,7 +80,7 @@
diff --git a/rma/wizards/stock_config_settings.py b/rma/wizards/stock_config_settings.py index 43058526..d48dcf8d 100644 --- a/rma/wizards/stock_config_settings.py +++ b/rma/wizards/stock_config_settings.py @@ -13,5 +13,11 @@ class StockConfigSettings(models.TransientModel): "(Example: services companies)"), (1, 'Display 3 fields on rma: partner, invoice address, delivery ' 'address') - ], "Addresses", - implied_group='rma.group_rma_delivery_invoice_address') + ], "Addresses", implied_group='rma.group_rma_delivery_invoice_address') + + group_rma_lines = fields.Selection([ + (0, "Do not group RMA lines"), + (1, 'Group RMA lines in one RMA group') + ], "Grouping", + implied_group='rma.group_rma_groups', + ) diff --git a/rma/wizards/stock_config_settings.xml b/rma/wizards/stock_config_settings.xml index 4df67cfa..38949374 100644 --- a/rma/wizards/stock_config_settings.xml +++ b/rma/wizards/stock_config_settings.xml @@ -9,6 +9,7 @@ +
diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index de09e3f6..fe16373f 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -4,7 +4,7 @@ { 'name': 'RMA Account', - 'version': '9.0.1.0.0', + 'version': '10.0.2.0.0', 'license': 'LGPL-3', 'category': 'RMA', 'summary': 'Integrates RMA with Invoice Processing', @@ -18,9 +18,9 @@ 'views/rma_operation_view.xml', 'views/rma_order_line_view.xml', 'views/invoice_view.xml', + 'views/rma_account_menu.xml', 'wizards/rma_add_invoice.xml', 'wizards/rma_refund.xml', ], 'installable': True, - 'auto_install': True, } diff --git a/rma_account/data/rma_operation.xml b/rma_account/data/rma_operation.xml index 2e1fb478..66a05de7 100644 --- a/rma_account/data/rma_operation.xml +++ b/rma_account/data/rma_operation.xml @@ -17,6 +17,7 @@ no customer +
@@ -26,6 +27,7 @@ no ordered supplier + diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index ec0a109c..b8026884 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -3,6 +3,7 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import api, fields, models +from odoo.tools.float_utils import float_compare class AccountInvoice(models.Model): @@ -14,9 +15,56 @@ class AccountInvoice(models.Model): rmas = self.mapped('invoice_line_ids.rma_line_ids') inv.rma_count = len(rmas) + def _prepare_invoice_line_from_rma_line(self, line): + qty = line.qty_to_refund + if float_compare( + qty, 0.0, precision_rounding=line.uom_id.rounding) <= 0: + qty = 0.0 + # Todo fill taxes from somewhere + invoice_line = self.env['account.invoice.line'] + data = { + 'purchase_line_id': line.id, + 'name': line.name, + 'origin': line.origin, + 'uom_id': line.uom_id.id, + 'product_id': line.product_id.id, + 'account_id': invoice_line.with_context( + {'journal_id': self.journal_id.id, + 'type': 'in_invoice'})._default_account(), + 'price_unit': line.company_id.currency_id.with_context( + date=self.date_invoice).compute( + line.price_unit, self.currency_id, round=False), + 'quantity': qty, + 'discount': 0.0, + 'account_analytic_id': line.analytic_account_id.id, + 'rma_line_id': line.id, + } + return data + + @api.onchange('add_rma_line_id') + def on_change_add_rma_line_id(self): + if not self.add_rma_line_id: + return {} + new_line = self.env['account.invoice.line'] + if self.add_rma_line_id not in ( + self.invoice_line_ids.mapped('rma_line_id')): + data = self._prepare_invoice_line_from_rma_line( + self.add_rma_line_id) + new_line = new_line.new(data) + new_line._set_additional_fields(self) + self.invoice_line_ids += new_line + self.add_rma_line_id = False + return {} + rma_count = fields.Integer( compute=_compute_rma_count, string='# of RMA') + add_rma_line_id = fields.Many2one( + comodel_name='rma.order.line', + string="Add from RMA line", + ondelete="set null", + help="Create a refund in based on an existing rma_line") + @api.multi def action_view_rma_supplier(self): action = self.env.ref('rma.action_rma_supplier_lines') @@ -78,13 +126,20 @@ class AccountInvoiceLine(models.Model): if self.env.context.get('rma'): for inv in self: if inv.invoice_id.reference: - res.append((inv.id, "%s %s %s qty:%s" % ( - inv.invoice_id.number, inv.invoice_id.reference, - inv.product_id.name, inv.quantity))) + res.append( + (inv.id, + "INV:%s | REF:%s | ORIG:%s | PART:%s | QTY:%s" % ( + inv.invoice_id.number or '', + inv.origin or '', + inv.invoice_id.reference or "", + inv.product_id.name, inv.quantity))) elif inv.invoice_id.number: - res.append((inv.id, "%s %s qty:%s" % ( - inv.invoice_id.number or '', - inv.product_id.name, inv.quantity))) + res.append( + (inv.id, + "INV:%s | ORIG:%s | PART:%s | QTY:%s" % ( + inv.invoice_id.number or '', + inv.origin or '', + inv.product_id.name, inv.quantity))) else: res.append(super(AccountInvoiceLine, inv).name_get()[0]) return res @@ -101,11 +156,12 @@ class AccountInvoiceLine(models.Model): compute=_compute_rma_count, string='# of RMA') rma_line_ids = fields.One2many( comodel_name='rma.order.line', inverse_name='invoice_line_id', - string="RMA", readonly=True, + string="RMA", readonly=True, copy=False, help="This will contain the RMA lines for the invoice line") rma_line_id = fields.Many2one( comodel_name='rma.order.line', string="RMA line refund", + copy=False, ondelete="set null", help="This will contain the rma line that originated the refund line") diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index 7b710b47..51a76710 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -69,8 +69,6 @@ class RmaOrder(models.Model): self.rma_line_ids += new_lines self.date_rma = fields.Datetime.now() - self.delivery_address_id = self.add_invoice_id.partner_id.id - self.invoice_address_id = self.add_invoice_id.partner_id.id self.add_invoice_id = False return {} diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 50fcdf00..c8c1433f 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -82,6 +82,21 @@ class RmaOrderLine(models.Model): digits=dp.get_precision('Product Unit of Measure'), readonly=True, compute=_compute_qty_refunded, store=True) + @api.onchange('product_id', 'partner_id') + def _onchange_product_id(self): + """Domain for invoice_line_id is computed here to make it dynamic.""" + res = super(RmaOrderLine, self)._onchange_product_id() + if not res.get('domain'): + res['domain'] = {} + domain = [ + '|', + ('invoice_id.partner_id', '=', self.partner_id.id), + ('invoice_id.partner_id', 'child_of', self.partner_id.id)] + if self.product_id: + domain.append(('product_id', '=', self.product_id.id)) + res['domain']['invoice_line_id'] = domain + return res + @api.multi def _prepare_rma_line_from_inv_line(self, line): self.ensure_one() @@ -149,7 +164,7 @@ class RmaOrderLine(models.Model): def _check_invoice_partner(self): for rec in self: if (rec.invoice_line_id and - rec.invoice_line_id.invoice_id.partner_id != + rec.invoice_line_id.invoice_id.commercial_partner_id != rec.partner_id): raise ValidationError(_( "RMA customer and originating invoice line customer " @@ -165,9 +180,8 @@ class RmaOrderLine(models.Model): @api.onchange('operation_id') def _onchange_operation_id(self): result = super(RmaOrderLine, self)._onchange_operation_id() - if not self.operation_id: - return result - self.refund_policy = self.operation_id.refund_policy + if self.operation_id: + self.refund_policy = self.operation_id.refund_policy or 'no' return result @api.multi @@ -207,3 +221,16 @@ class RmaOrderLine(models.Model): result['views'] = [(res and res.id or False, 'form')] result['res_id'] = invoice_ids[0] return result + + @api.multi + def name_get(self): + res = [] + if self.env.context.get('rma'): + for rma in self: + res.append((rma.id, "%s %s qty:%s" % ( + rma.name, + rma.product_id.name, + rma.product_qty))) + return res + else: + return super(RmaOrderLine, self).name_get() diff --git a/rma_account/tests/__init__.py b/rma_account/tests/__init__.py index dfa77946..c68d3d34 100644 --- a/rma_account/tests/__init__.py +++ b/rma_account/tests/__init__.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2018 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from . import test_rma -from . import test_supplier_rma -from . import test_rma_dropship + +from . import test_rma_account diff --git a/rma_account/tests/test_rma.py b/rma_account/tests/test_rma.py deleted file mode 100644 index 7d1cebc5..00000000 --- a/rma_account/tests/test_rma.py +++ /dev/null @@ -1,415 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.tests import common -from openerp import fields - - -class TestRma(common.TransactionCase): - - """ Test the routes and the quantities """ - - def setUp(self): - super(TestRma, self).setUp() - - self.rma_make_picking = self.env['rma_make_picking.wizard'] - self.make_supplier_rma = self.env["rma.order.line.make.supplier.rma"] - self.rma_add_stock_move = self.env['rma_add_stock_move'] - self.stockpicking = self.env['stock.picking'] - self.rma = self.env['rma.order'] - self.rma_line = self.env['rma.order.line'] - self.rma_op = self.env['rma.operation'] - self.rma_cust_replace_op_id = self.env.ref( - 'rma.rma_operation_customer_replace') - self.rma_sup_replace_op_id = self.env.ref( - 'rma.rma_operation_supplier_replace') - self.product_id = self.env.ref('product.product_product_4') - self.product_id.product_tmpl_id.categ_id.\ - property_stock_account_input_categ_id =\ - self.env.ref('account.data_account_type_receivable').id - self.product_id.product_tmpl_id.categ_id.\ - property_stock_account_output_categ_id =\ - self.env.ref('account.data_account_type_expenses').id - self.product_1 = self.env.ref('product.product_product_25') - self.product_2 = self.env.ref('product.product_product_7') - self.product_3 = self.env.ref('product.product_product_11') - self.uom_unit = self.env.ref('product.product_uom_unit') - # assign an operation - self.product_1.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_2.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_3.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.partner_id = self.env.ref('base.res_partner_12') - self.stock_location = self.env.ref('stock.stock_location_stock') - wh = self.env.ref('stock.warehouse0') - self.stock_rma_location = wh.lot_rma_id - self.customer_location = self.env.ref( - 'stock.stock_location_customers') - self.supplier_location = self.env.ref( - 'stock.stock_location_suppliers') - self.product_uom_id = self.env.ref('product.product_uom_unit') - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_customer_id = self._create_rma_from_move( - products2move, 'customer', self.env.ref('base.res_partner_2'), - dropship=False) - - def _create_picking(self, partner): - return self.stockpicking.create({ - 'partner_id': partner.id, - 'picking_type_id': self.env.ref('stock.picking_type_in').id, - 'location_id': self.stock_location.id, - 'location_dest_id': self.supplier_location.id - }) - - def _create_rma_from_move(self, products2move, type, partner, dropship, - supplier_address_id=None): - picking_in = self._create_picking(partner) - - moves = [] - if type == 'customer': - for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.stock_location, - self.customer_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) - else: - for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.supplier_location, - self.stock_rma_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) - # Create the RMA from the stock_move - rma_id = self.rma.create( - { - 'reference': '0001', - 'type': type, - 'partner_id': partner.id, - 'company_id': self.env.ref('base.main_company').id - }) - rma_id._compute_invoice_refund_count() - rma_id._compute_invoice_count() - - data = {'add_invoice_id': self._create_invoice().id} - new_line = self.rma.new(data) - new_line.on_change_invoice() - - rma_id.action_view_invoice_refund() - rma_id.action_view_invoice() - - for move in moves: - if type == 'customer': - wizard = self.rma_add_stock_move.new( - {'stock_move_id': move.id, 'customer': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - } - ) - wizard.with_context({ - 'stock_move_id': move.id, 'customer': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }) - data = wizard.with_context(customer=1).\ - _prepare_rma_line_from_stock_move(move) - data['partner_id'] = move.partner_id.id - else: - wizard = self.rma_add_stock_move.new( - {'stock_move_id': move.id, 'supplier': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - } - ) - wizard.with_context( - {'stock_move_id': move.id, 'supplier': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }) - data = wizard._prepare_rma_line_from_stock_move(move) - data['partner_id'] = move.partner_id.id - if dropship: - data.update(customer_to_supplier=dropship, - supplier_address_id=supplier_address_id.id) - data['partner_id'] = move.partner_id.id - data['rma_id'] = rma_id.id - self.line = self.rma_line.create(data) - # approve the RMA Line - self.line._compute_refund_count() - self.rma_line.action_rma_to_approve() - - self.line.action_rma_approve() - self.line.action_view_invoice() - self.line.action_view_refunds() - - # approve the RMA -# rma_id.action_rma_to_approve() -# rma_id.action_rma_approve() - return rma_id - - def _prepare_move(self, product, qty, src, dest, picking_in): - res = { - 'partner_id': self.partner_id.id, - 'product_id': product.id, - 'name': product.partner_ref, - 'state': 'confirmed', - 'product_uom': self.product_uom_id.id or product.uom_id.id, - 'product_uom_qty': qty, - 'origin': 'Test RMA', - 'location_id': src.id, - 'location_dest_id': dest.id, - 'picking_id': picking_in.id - } - return res - - def test_rma_refund(self): - - self.rma_refund_item = self.env['rma.refund.item'] - self.rma_refund = self.env['rma.refund'] - - self.product_id.income =\ - self.env.ref('account.data_account_type_receivable').id - self.product_id.expense =\ - self.env.ref('account.data_account_type_expenses').id - - for line in self.rma_customer_id.rma_line_ids: - line.refund_policy = 'ordered' - - refund = self.rma_refund.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({'description': 'Test Reason', - 'date_invoice': fields.datetime.now() - }) - self.rma_refund_item.create({ - 'line_id': self.rma_customer_id.rma_line_ids[0].id, - 'rma_id': self.rma_customer_id.id, - 'product_id': self.product_id.id, - 'name': 'Test RMA Refund', - 'product_qty': self.rma_customer_id.rma_line_ids[0].product_qty, - 'wiz_id': refund.id - }) - refund.invoice_refund() - - data = {'invoice_line_id': self._create_invoice().invoice_line_ids.id} - new_line = self.rma_line.new(data) - new_line._onchange_invoice_line_id() - self.rma_customer_id.action_view_invoice_refund() - self.rma_customer_id.action_view_invoice() - - def test_on_change_invoice_rma(self): - - wizard = self.env['rma_add_invoice'].with_context({ - 'active_ids': self.rma_customer_id.ids, - 'active_model': 'rma.order', - 'active_id': self.rma_customer_id.id - }).create({'partner_id': self.partner_id.id, - 'rma_id': self.rma_customer_id.id, - 'invoice_line_ids': - [(6, 0, [self._create_invoice().invoice_line_ids.id])], - }) - wizard.default_get([str(self._create_invoice().id), - str(self._create_invoice().invoice_line_ids.id), - str(self.partner_id.id)]) - wizard.add_lines() - self.rma_customer_id.action_view_invoice_refund() - self.rma_customer_id.action_view_invoice() - self.rma_customer_id.rma_line_ids[0].\ - invoice_id = self._create_invoice().id - self.rma_customer_id.action_view_invoice() - self.rma_customer_id.add_invoice_id = self._create_invoice().id - for line in self.rma_customer_id.rma_line_ids: - line.invoice_id.action_view_rma_supplier() - line.invoice_id.action_view_rma_customer() - - def _create_invoice(self): - self.Account = self.env['account.account'] - self.AccountInvoice = self.env['account.invoice'] - self.AccountInvoiceLine = self.env['account.invoice.line'] - - self.account_receivable =\ - self.env.ref('account.data_account_type_receivable') - self.account_expenses =\ - self.env.ref('account.data_account_type_expenses') - invoice_account = self.Account.\ - search([('user_type_id', '=', self.account_receivable.id)], limit=1 - ).id - invoice_line_account = self.Account.\ - search([('user_type_id', '=', self.account_expenses.id)], limit=1 - ).id - - invoice = self.AccountInvoice.create({ - 'partner_id': self.partner_id.id, - 'account_id': invoice_account, - 'type': 'in_invoice', - }) - - invoice_line = self.AccountInvoiceLine.create({ - 'product_id': self.product_1.id, - 'quantity': 1.0, - 'price_unit': 100.0, - 'invoice_id': invoice.id, - 'uom_id': 1, - 'name': 'product that cost 100', - 'account_id': invoice_line_account, - }) - invoice._compute_rma_count() - invoice_line._compute_rma_count() - invoice.action_view_rma_customer() - invoice.action_view_rma_supplier() - return invoice - - def test_customer_rma(self): - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - 'active_id': 1 - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_customer_id.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty incoming") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty incoming") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty incoming") - picking.action_assign() - picking.do_transfer() - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_to_receive, 0, - "Wrong qty to_receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to_deliver") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to_deliver") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to_deliver") - - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'outgoing', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - pickings = self.stockpicking.search(domain) - self.assertEquals(len(pickings), 2, - "Incorrect number of pickings created") - picking_out = pickings[1] - moves = picking_out.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_to_receive, 0, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 3, - "Wrong qty outgoing") - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 2, - "Wrong qty outgoing") - picking_out.action_assign() - picking_out.do_transfer() - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_to_receive, 0, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 3, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") - self.line.action_rma_done() - self.assertEquals(self.line.state, 'done', - "Wrong State") diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py new file mode 100644 index 00000000..97a40072 --- /dev/null +++ b/rma_account/tests/test_rma_account.py @@ -0,0 +1,211 @@ +# -*- coding: utf-8 -*- +# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo.tests import common + + +class TestRmaAccount(common.SingleTransactionCase): + + @classmethod + def setUpClass(cls): + super(TestRmaAccount, cls).setUpClass() + + cls.rma_obj = cls.env['rma.order'] + cls.rma_line_obj = cls.env['rma.order.line'] + cls.rma_op_obj = cls.env['rma.operation'] + cls.rma_add_invoice_wiz = cls.env['rma_add_invoice'] + cls.rma_refund_wiz = cls.env['rma.refund'] + cls.acc_obj = cls.env['account.account'] + cls.inv_obj = cls.env['account.invoice'] + cls.invl_obj = cls.env['account.invoice.line'] + cls.product_obj = cls.env['product.product'] + cls.partner_obj = cls.env['res.partner'] + + cls.rma_route_cust = cls.env.ref('rma.route_rma_customer') + receivable_type = cls.env.ref('account.data_account_type_receivable') + payable_type = cls.env.ref('account.data_account_type_payable') + cls.cust_refund_op = cls.env.ref( + 'rma_account.rma_operation_customer_refund') + + # Create partners + customer1 = cls.partner_obj.create({'name': 'Customer 1'}) + supplier1 = cls.partner_obj.create({'name': 'Supplier 1'}) + + # Create RMA group and operation: + cls.rma_group_customer = cls.rma_obj.create({ + 'partner_id': customer1.id, + 'type': 'customer', + }) + cls.rma_group_supplier = cls.rma_obj.create({ + 'partner_id': supplier1.id, + 'type': 'supplier', + }) + cls.operation_1 = cls.rma_op_obj.create({ + 'code': 'TEST', + 'name': 'Refund and receive', + 'type': 'customer', + 'receipt_policy': 'ordered', + 'refund_policy': 'ordered', + 'in_route_id': cls.rma_route_cust.id, + 'out_route_id': cls.rma_route_cust.id, + }) + + # Create products + cls.product_1 = cls.product_obj.create({ + 'name': 'Test Product 1', + 'type': 'product', + 'list_price': 100.0, + 'rma_customer_operation_id': cls.cust_refund_op.id, + }) + cls.product_2 = cls.product_obj.create({ + 'name': 'Test Product 2', + 'type': 'product', + 'list_price': 150.0, + 'rma_customer_operation_id': cls.operation_1.id, + }) + cls.product_3 = cls.product_obj.create({ + 'name': 'Test Product 3', + 'type': 'product', + }) + cls.product_4 = cls.product_obj.create({ + 'name': 'Test Product 4', + 'type': 'product', + }) + + # Create Invoices: + customer_account = cls.acc_obj. search( + [('user_type_id', '=', receivable_type.id)], limit=1).id + cls.inv_customer = cls.inv_obj.create({ + 'partner_id': customer1.id, + 'account_id': customer_account, + 'type': 'out_invoice', + }) + cls.inv_line_1 = cls.invl_obj.create({ + 'name': cls.product_1.name, + 'product_id': cls.product_1.id, + 'quantity': 12.0, + 'price_unit': 100.0, + 'invoice_id': cls.inv_customer.id, + 'uom_id': cls.product_1.uom_id.id, + 'account_id': customer_account, + }) + cls.inv_line_2 = cls.invl_obj.create({ + 'name': cls.product_2.name, + 'product_id': cls.product_2.id, + 'quantity': 15.0, + 'price_unit': 150.0, + 'invoice_id': cls.inv_customer.id, + 'uom_id': cls.product_2.uom_id.id, + 'account_id': customer_account, + }) + + supplier_account = cls.acc_obj.search( + [('user_type_id', '=', payable_type.id)], limit=1).id + cls.inv_supplier = cls.inv_obj.create({ + 'partner_id': supplier1.id, + 'account_id': supplier_account, + 'type': 'in_invoice', + }) + cls.inv_line_3 = cls.invl_obj.create({ + 'name': cls.product_3.name, + 'product_id': cls.product_3.id, + 'quantity': 17.0, + 'price_unit': 250.0, + 'invoice_id': cls.inv_supplier.id, + 'uom_id': cls.product_3.uom_id.id, + 'account_id': supplier_account, + }) + cls.inv_line_4 = cls.invl_obj.create({ + 'name': cls.product_4.name, + 'product_id': cls.product_4.id, + 'quantity': 9.0, + 'price_unit': 300.0, + 'invoice_id': cls.inv_supplier.id, + 'uom_id': cls.product_4.uom_id.id, + 'account_id': supplier_account, + }) + + def test_01_add_from_invoice_customer(self): + """Test wizard to create RMA from a customer invoice.""" + add_inv = self.rma_add_invoice_wiz.with_context({ + 'customer': True, + 'active_ids': self.rma_group_customer.id, + 'active_model': 'rma.order', + }).create({ + 'invoice_line_ids': + [(6, 0, self.inv_customer.invoice_line_ids.ids)], + }) + add_inv.add_lines() + self.assertEqual(len(self.rma_group_customer.rma_line_ids), 2) + for t in self.rma_group_supplier.rma_line_ids.mapped('type'): + self.assertEqual(t, 'customer') + rma_1 = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_1) + self.assertEqual(rma_1.operation_id, self.cust_refund_op) + rma_2 = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_2) + self.assertEqual(rma_2.operation_id, self.operation_1) + + def test_02_add_from_invoice_supplier(self): + """Test wizard to create RMA from a vendor bill.""" + add_inv = self.rma_add_invoice_wiz.with_context({ + 'supplier': True, + 'active_ids': self.rma_group_supplier.id, + 'active_model': 'rma.order', + }).create({ + 'invoice_line_ids': + [(6, 0, self.inv_supplier.invoice_line_ids.ids)], + }) + add_inv.add_lines() + self.assertEqual(len(self.rma_group_supplier.rma_line_ids), 2) + for t in self.rma_group_supplier.rma_line_ids.mapped('type'): + self.assertEqual(t, 'supplier') + + def test_03_rma_refund_operation(self): + """Test RMA quantities using refund operations.""" + # Received refund_policy: + rma_1 = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_1) + self.assertEqual(rma_1.refund_policy, 'received') + self.assertEqual(rma_1.qty_to_refund, 0.0) + # TODO: receive and check qty_to_refund is 12.0 + # Ordered refund_policy: + rma_2 = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_2) + rma_2._onchange_operation_id() + self.assertEqual(rma_2.refund_policy, 'ordered') + self.assertEqual(rma_2.qty_to_refund, 15.0) + + def test_04_rma_create_refund(self): + """Generate a Refund from a customer RMA.""" + rma = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_2) + rma.action_rma_to_approve() + rma.action_rma_approve() + self.assertEqual(rma.refund_count, 0) + self.assertEqual(rma.qty_to_refund, 15.0) + self.assertEqual(rma.qty_refunded, 0.0) + make_refund = self.rma_refund_wiz.with_context({ + 'customer': True, + 'active_ids': rma.ids, + 'active_model': 'rma.order.line', + }).create({ + 'description': 'Test refund', + }) + make_refund.invoice_refund() + rma.refund_line_ids.invoice_id.invoice_validate() + self.assertEqual(rma.refund_count, 1) + self.assertEqual(rma.qty_to_refund, 0.0) + self.assertEqual(rma.qty_refunded, 15.0) + + def test_05_fill_rma_from_inv_line(self): + """Test filling a RMA (line) from a invoice line.""" + rma = self.rma_line_obj.new({ + 'partner_id': self.inv_customer.partner_id.id, + 'invoice_line_id': self.inv_line_1.id, + }) + self.assertFalse(rma.product_id) + rma._onchange_invoice_line_id() + self.assertEqual(rma.product_id, self.product_1) + self.assertEqual(rma.product_qty, 12.0) diff --git a/rma_account/tests/test_rma_dropship.py b/rma_account/tests/test_rma_dropship.py deleted file mode 100644 index abe07221..00000000 --- a/rma_account/tests/test_rma_dropship.py +++ /dev/null @@ -1,108 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.addons.rma.tests import test_rma - - -class TestRmaDropship(test_rma.TestRma): - - def setUp(self): - super(TestRmaDropship, self).setUp() - self.product_id.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_1.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_2.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_3.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_droship_id = self._create_rma_from_move( - products2move, 'customer', self.env.ref('base.res_partner_2'), - dropship=True, - supplier_address_id=self.env.ref('base.res_partner_3')) - - def test_dropship(self): - wizard = self.make_supplier_rma.with_context({ - 'active_ids': self.rma_droship_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({}) - res = wizard.make_supplier_rma() - supplier_rma = self.rma.browse(res['res_id']) - for line in supplier_rma.rma_line_ids: - line.action_rma_to_approve() - line.action_rma_approve() - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': supplier_rma.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in supplier_rma.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty outgoing") - - for line in self.rma_droship_id.rma_line_ids: - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 3, - "Wrong qty in supplier rma") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 5, - "Wrong qty in supplier rma") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 2, - "Wrong qty in supplier rma") - for line in self.rma_droship_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") diff --git a/rma_account/tests/test_supplier_rma.py b/rma_account/tests/test_supplier_rma.py deleted file mode 100644 index 321b46e1..00000000 --- a/rma_account/tests/test_supplier_rma.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.addons.rma.tests import test_rma - - -class TestSupplierRma(test_rma.TestRma): - - def setUp(self): - super(TestSupplierRma, self).setUp() - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_supplier_id = self._create_rma_from_move( - products2move, 'supplier', self.env.ref('base.res_partner_1'), - dropship=False) - - def test_supplier_rma(self): - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'outgoing', - 'active_id': 1 - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 3, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 2, - "Wrong qty outgoing") - - picking.action_assign() - picking.do_transfer() - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_delivered, 3, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - if line.product_id == self.product_2: - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - if line.product_id == self.product_3: - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - pickings = self.stockpicking.search(domain) - self.assertEquals(len(pickings), 2, - "Incorrect number of pickings created") - picking_out = pickings[1] - moves = picking_out.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 3, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - picking_out.action_assign() - picking_out.do_transfer() - for line in self.rma_supplier_id.rma_line_ids[0]: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 6, - "Wrong qty deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 6, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") - for line in self.rma_supplier_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") diff --git a/rma_account/views/invoice_view.xml b/rma_account/views/invoice_view.xml index c1097905..c9a4be2f 100644 --- a/rma_account/views/invoice_view.xml +++ b/rma_account/views/invoice_view.xml @@ -62,6 +62,48 @@ + + account.invoice.supplier.rma + account.invoice + + + + + + + + + + + + + account.invoice.customer.rma + account.invoice + + + + + + + + + + + Invoice Line account.invoice.line diff --git a/rma_account/views/rma_account_menu.xml b/rma_account/views/rma_account_menu.xml new file mode 100644 index 00000000..7388a537 --- /dev/null +++ b/rma_account/views/rma_account_menu.xml @@ -0,0 +1,39 @@ + + + + + + Customer RMA + rma.order.line + [('type','=', 'customer')] + {"search_default_to_refund":1} + form + tree,form + + + + Supplier RMA + rma.order.line + [('type','=', 'supplier')] + {"search_default_to_refund":1, "supplier":1} + form + tree,form + + + + + + + + diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index e6906401..d228871a 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -17,8 +17,8 @@ @@ -33,6 +33,8 @@
@@ -50,21 +52,23 @@ + + + options="{'no_create': True}"/> @@ -76,6 +80,8 @@ @@ -90,12 +96,17 @@ rma.order.line.select rma.order.line - + - - - + + + + + + + + diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index db087c61..4a6c2306 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -90,10 +90,6 @@ class RmaAddInvoice(models.TransientModel): def _get_rma_data(self): data = { 'date_rma': fields.Datetime.now(), - 'delivery_address_id': - self.invoice_line_ids[0].invoice_id.partner_id.id, - 'invoice_address_id': - self.invoice_line_ids[0].invoice_id.partner_id.id } return data diff --git a/rma_account/wizards/rma_add_invoice.xml b/rma_account/wizards/rma_add_invoice.xml index c0d9e412..7f9b85a7 100644 --- a/rma_account/wizards/rma_add_invoice.xml +++ b/rma_account/wizards/rma_add_invoice.xml @@ -14,7 +14,7 @@ diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 1efb7b6e..69c666fb 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -4,7 +4,7 @@ from odoo import _, api, fields, models from odoo.exceptions import ValidationError -from odoo.tools.safe_eval import safe_eval as eval +from odoo.tools.safe_eval import safe_eval as seval import odoo.addons.decimal_precision as dp @@ -19,16 +19,17 @@ class RmaRefund(models.TransientModel): @api.returns('rma.order.line') def _prepare_item(self, line): - values = {'product_id': line.product_id.id, - 'name': line.name, - 'product_qty': line.product_qty, - 'uom_id': line.uom_id.id, - 'qty_to_refund': line.qty_to_refund, - 'refund_policy': line.refund_policy, - 'invoice_address_id': line.invoice_address_id.id, - 'line_id': line.id, - 'rma_id': line.rma_id.id, - 'wiz_id': self.env.context['active_id']} + values = { + 'product_id': line.product_id.id, + 'name': line.name, + 'product_qty': line.product_qty, + 'uom_id': line.uom_id.id, + 'qty_to_refund': line.qty_to_refund, + 'refund_policy': line.refund_policy, + 'invoice_address_id': line.invoice_address_id.id, + 'line_id': line.id, + 'rma_id': line.rma_id.id, + } return values @api.model @@ -97,7 +98,7 @@ class RmaRefund(models.TransientModel): new_invoice.type in ['out_refund', 'out_invoice']) \ else 'action_invoice_tree2' result = self.env.ref('account.%s' % action).read()[0] - invoice_domain = eval(result['domain']) + invoice_domain = seval(result['domain']) invoice_domain.append(('id', '=', new_invoice.id)) result['domain'] = invoice_domain return result @@ -204,5 +205,6 @@ class RmaRefundItem(models.TransientModel): readonly=True) refund_policy = fields.Selection(selection=[ ('no', 'Not required'), ('ordered', 'Based on Ordered Quantities'), + ('delivered', 'Based on Delivered Quantities'), ('received', 'Based on Received Quantities')], string="Refund Policy") diff --git a/rma_account_analytic/__manifest__.py b/rma_account_analytic/__manifest__.py index e81582ed..624123ae 100644 --- a/rma_account_analytic/__manifest__.py +++ b/rma_account_analytic/__manifest__.py @@ -10,8 +10,8 @@ "license": "LGPL-3", "website": "http://www.eficent.com", "category": "Analytic", - "depends": ["rma_account", "rma_analytic", "stock_analytic_account"], + "depends": ["rma_account", "rma_analytic"], "data": [ ], - 'installable': True, + 'installable': False, } diff --git a/rma_account_analytic/models/invoice.py b/rma_account_analytic/models/invoice.py index 1ce84637..6a0d81f7 100644 --- a/rma_account_analytic/models/invoice.py +++ b/rma_account_analytic/models/invoice.py @@ -5,7 +5,7 @@ from odoo import _, api, exceptions, models -class AccountInvocieLine(models.Model): +class AccountInvoiceLine(models.Model): _inherit = "account.invoice.line" @api.constrains('analytic_account_id') diff --git a/rma_analytic/__manifest__.py b/rma_analytic/__manifest__.py index b573cd2e..032c09ee 100644 --- a/rma_analytic/__manifest__.py +++ b/rma_analytic/__manifest__.py @@ -10,10 +10,10 @@ "license": "LGPL-3", "website": "http://www.eficent.com", "category": "Analytic", - "depends": ["rma", "analytic", "procurement_analytic", - 'stock_analytic_account'], + "depends": ["rma", "procurement_analytic", "stock_analytic"], "data": [ "views/rma_order_line_view.xml" ], 'installable': True, + } diff --git a/rma_analytic/models/procurement.py b/rma_analytic/models/procurement.py index f3203d42..3582ed23 100644 --- a/rma_analytic/models/procurement.py +++ b/rma_analytic/models/procurement.py @@ -9,10 +9,10 @@ class ProcurementOrder(models.Model): _inherit = "procurement.order" - @api.constrains('analytic_account_id') + @api.constrains('account_analytic_id') def check_analytic(self): for order in self: - if (order.analytic_account_id != + if (order.account_analytic_id != order.rma_line_id.analytic_account_id): raise exceptions.ValidationError( _("The analytic account in the procurement it's not the " diff --git a/rma_analytic/models/rma_order_line.py b/rma_analytic/models/rma_order_line.py index 3b9f20d0..8d125ce4 100644 --- a/rma_analytic/models/rma_order_line.py +++ b/rma_analytic/models/rma_order_line.py @@ -2,7 +2,7 @@ # © 2018 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). -from odoo import fields, models +from odoo import api, fields, models class RmaOrderLine(models.Model): @@ -13,3 +13,14 @@ class RmaOrderLine(models.Model): comodel_name='account.analytic.account', string='Analytic Account', ) + + @api.multi + def _prepare_rma_line_from_inv_line(self, line): + res = super( + RmaOrderLine, self + )._prepare_rma_line_from_inv_line(line) + if line.account_analytic_id: + res.update( + analytic_account_id=line.account_analytic_id.id + ) + return res diff --git a/rma_analytic/tests/test_rma_analytic.py b/rma_analytic/tests/test_rma_analytic.py index fdff1c61..80f5e8c3 100644 --- a/rma_analytic/tests/test_rma_analytic.py +++ b/rma_analytic/tests/test_rma_analytic.py @@ -7,26 +7,244 @@ from odoo.addons.rma.tests import test_rma class TestRmaAnalytic(test_rma.TestRma): - def setUp(self): - super(TestRmaAnalytic, self).setUp() - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_ana_id = self._create_rma_from_move( - products2move, 'supplier', self.env.ref('base.res_partner_1'), - dropship=False) + @classmethod + def setUpClass(cls): + super(TestRmaAnalytic, cls).setUpClass() + cls.rma_add_invoice_wiz = cls.env["rma_add_invoice"] + cls.rma_refund_wiz = cls.env["rma.refund"] + products2move = [ + (cls.product_1, 3), + (cls.product_2, 5), + (cls.product_3, 2), + ] + cls.rma_add_invoice_wiz = cls.env["rma_add_invoice"] + cls.rma_ana_id = cls._create_rma_from_move( + products2move, + "supplier", + cls.env.ref("base.res_partner_2"), + dropship=False, + ) + receivable_type = cls.env.ref( + "account.data_account_type_receivable" + ) + # Create Invoices: + customer_account = ( + cls.env["account.account"] + .search( + [("user_type_id", "=", receivable_type.id)], limit=1 + ) + .id + ) + cls.inv_customer = cls.env["account.invoice"].create( + { + "partner_id": cls.partner_id.id, + "account_id": customer_account, + "type": "out_invoice", + } + ) + cls.anal = cls.env["account.analytic.account"].create( + {"name": "Name"} + ) + cls.inv_line_1 = cls.env["account.invoice.line"].create( + { + "name": cls.partner_id.name, + "product_id": cls.product_1.id, + "quantity": 12.0, + "price_unit": 100.0, + "account_analytic_id": cls.anal.id, + "invoice_id": cls.inv_customer.id, + "uom_id": cls.product_1.uom_id.id, + "account_id": customer_account, + } + ) - def _prepare_move(self, product, qty, src, dest, picking_in): - res = super(TestRmaAnalytic, self)._prepare_move( - product, qty, src, dest, picking_in) - analytic_1 = self.env['account.analytic.account'].create({ - 'name': 'Test account #1', - }) - res.update({'analytic_account_id': analytic_1.id}) + @classmethod + def _prepare_move(cls, product, qty, src, dest, picking_in): + res = super(TestRmaAnalytic, cls)._prepare_move( + product, qty, src, dest, picking_in + ) + analytic_1 = cls.env["account.analytic.account"].create( + {"name": "Test account #1"} + ) + res.update({"analytic_account_id": analytic_1.id}) return res + @classmethod + def _create_rma_analytic(cls, products2move, partner): + picking_in = cls._create_picking(partner) + moves = [] + for item in products2move: + move_values = cls._prepare_anal_move( + item[0], + item[1], + cls.stock_location, + cls.customer_location, + picking_in, + cls.analytic_1, + ) + moves.append(cls.env["stock.move"].create(move_values)) + + rma_id = cls.rma_model.create( + { + "reference": "0001", + "type": "customer", + "partner_id": partner.id, + "company_id": cls.env.ref("base.main_company").id, + } + ) + for move in moves: + wizard = cls.rma_add_stock_move.with_context( + { + "stock_move_id": move.id, + "customer": True, + "active_ids": rma_id.id, + "active_model": "rma.order", + } + ).create({}) + data = wizard._prepare_rma_line_from_stock_move(move) + wizard.add_lines() + + if move.product_id.rma_customer_operation_id: + move.product_id.rma_customer_operation_id.in_route_id = False + move.product_id.categ_id.rma_customer_operation_id = False + move.product_id.rma_customer_operation_id = False + wizard._prepare_rma_line_from_stock_move(move) + cls.line = cls.rma_line_model.create(data) + return rma_id + def test_analytic(self): for line in self.rma_ana_id.rma_line_ids: for move in line.move_ids: self.assertEqual( - line.analytic_account_id, move.analytic_account_id, - "the analytic account is not propagated") + line.analytic_account_id, + move.analytic_account_id, + "the analytic account is not propagated", + ) + + def test_invoice_analytic(self): + """Test wizard to create RMA from a customer invoice.""" + rma_line = ( + self.env["rma.order.line"] + .with_context(customer=True) + .new( + { + "partner_id": self.partner_id.id, + "product_id": self.product_1.id, + "operation_id": self.env.ref( + "rma.rma_operation_customer_replace" + ).id, + "in_route_id": self.env.ref( + "rma.route_rma_customer" + ), + "out_route_id": self.env.ref( + "rma.route_rma_customer" + ), + "in_warehouse_id": self.env.ref( + "stock.warehouse0" + ), + "out_warehouse_id": self.env.ref( + "stock.warehouse0" + ), + "location_id": self.env.ref( + "stock.stock_location_stock" + ), + "type": "customer", + "invoice_line_id": self.inv_line_1.id, + "uom_id": self.product_1.uom_id.id, + } + ) + ) + rma_line._onchange_invoice_line_id() + self.assertEqual( + rma_line.analytic_account_id, + self.inv_line_1.account_analytic_id, + ) + + def test_invoice_analytic02(self): + self.product_1.rma_customer_operation_id = self.env.ref( + "rma.rma_operation_customer_replace" + ).id + rma_order = ( + self.env["rma.order"] + .with_context(customer=True) + .create( + { + "name": "RMA", + "partner_id": self.partner_id.id, + "type": "customer", + "rma_line_ids": [], + } + ) + ) + add_inv = self.rma_add_invoice_wiz.with_context( + { + "customer": True, + "active_ids": [rma_order.id], + "active_model": "rma.order", + } + ).create( + { + "invoice_line_ids": [ + (6, 0, self.inv_customer.invoice_line_ids.ids) + ] + } + ) + add_inv.add_lines() + + self.assertEqual( + rma_order.mapped("rma_line_ids.analytic_account_id"), + self.inv_line_1.account_analytic_id, + ) + + def test_refund_analytic(self): + self.product_1.rma_customer_operation_id = self.env.ref( + "rma_account.rma_operation_customer_refund" + ).id + rma_line = ( + self.env["rma.order.line"] + .with_context(customer=True) + .create( + { + "partner_id": self.partner_id.id, + "product_id": self.product_1.id, + "operation_id": self.env.ref( + "rma_account.rma_operation_customer_refund" + ).id, + "in_route_id": self.env.ref( + "rma.route_rma_customer" + ).id, + "out_route_id": self.env.ref( + "rma.route_rma_customer" + ).id, + "in_warehouse_id": self.env.ref( + "stock.warehouse0" + ).id, + "out_warehouse_id": self.env.ref( + "stock.warehouse0" + ).id, + "location_id": self.env.ref( + "stock.stock_location_stock" + ).id, + "type": "customer", + "invoice_line_id": self.inv_line_1.id, + "delivery_policy": "no", + "receipt_policy": "ordered", + "uom_id": self.product_1.uom_id.id, + } + ) + ) + rma_line._onchange_invoice_line_id() + rma_line.action_rma_to_approve() + rma_line.action_rma_approve() + make_refund = self.rma_refund_wiz.with_context( + { + "customer": True, + "active_ids": rma_line.ids, + "active_model": "rma.order.line", + } + ).create({"description": "Test refund"}) + make_refund.invoice_refund() + self.assertEqual( + rma_line.mapped("analytic_account_id"), + rma_line.mapped("refund_line_ids.account_analytic_id"), + ) diff --git a/rma_analytic/wizards/__init__.py b/rma_analytic/wizards/__init__.py index c9b61ef7..99d25291 100644 --- a/rma_analytic/wizards/__init__.py +++ b/rma_analytic/wizards/__init__.py @@ -4,3 +4,5 @@ from . import rma_add_stock_move from . import rma_make_picking +from . import rma_add_invoice +from . import rma_refund diff --git a/rma_analytic/wizards/rma_add_invoice.py b/rma_analytic/wizards/rma_add_invoice.py new file mode 100644 index 00000000..02c81c1f --- /dev/null +++ b/rma_analytic/wizards/rma_add_invoice.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import models + + +class RmaAddInvoice(models.TransientModel): + _inherit = "rma_add_invoice" + + def _prepare_rma_line_from_inv_line(self, line): + res = super( + RmaAddInvoice, self + )._prepare_rma_line_from_inv_line(line) + if line.account_analytic_id: + res.update( + analytic_account_id=line.account_analytic_id.id + ) + return res diff --git a/rma_analytic/wizards/rma_make_picking.py b/rma_analytic/wizards/rma_make_picking.py index 30561b4e..daf68fdd 100644 --- a/rma_analytic/wizards/rma_make_picking.py +++ b/rma_analytic/wizards/rma_make_picking.py @@ -6,7 +6,7 @@ from odoo import models, api class RmaMakePicking(models.TransientModel): - _name = 'rma_make_picking.wizard' + _inherit = 'rma_make_picking.wizard' _description = 'Wizard to create pickings from rma lines' @api.model @@ -14,5 +14,5 @@ class RmaMakePicking(models.TransientModel): procurement_data = super(RmaMakePicking, self)._get_procurement_data( item, group, qty, picking_type) procurement_data.update( - analytic_account_id=item.line_id.analytic_account_id.id) + account_analytic_id=item.line_id.analytic_account_id.id) return procurement_data diff --git a/rma_analytic/wizards/rma_refund.py b/rma_analytic/wizards/rma_refund.py new file mode 100644 index 00000000..583c562e --- /dev/null +++ b/rma_analytic/wizards/rma_refund.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import api, models + + +class RmaRefund(models.TransientModel): + _inherit = "rma.refund" + + @api.model + def prepare_refund_line(self, item, refund): + res = super(RmaRefund, self).prepare_refund_line(item, refund) + if item.line_id.analytic_account_id: + res.update( + account_analytic_id=item.line_id.analytic_account_id.id + ) + return res diff --git a/rma_operating_unit/__manifest__.py b/rma_operating_unit/__manifest__.py index a9def047..4f5a245d 100644 --- a/rma_operating_unit/__manifest__.py +++ b/rma_operating_unit/__manifest__.py @@ -10,7 +10,7 @@ "license": "LGPL-3", "website": "http://www.eficent.com", "category": "Operating Units", - "depends": ["rma", "operating_unit"], + "depends": ["rma", "stock_operating_unit"], "data": [ "security/rma_security.xml", "views/rma_order_view.xml", diff --git a/rma_operating_unit/models/rma_order.py b/rma_operating_unit/models/rma_order.py index 923724d1..167d3b82 100644 --- a/rma_operating_unit/models/rma_order.py +++ b/rma_operating_unit/models/rma_order.py @@ -11,7 +11,7 @@ class RmaOrder(models.Model): _inherit = "rma.order" @api.multi - @api.constrains('rma_line_ids', 'rma_line_ids.operating_unit_id') + @api.constrains('rma_line_ids', 'operating_unit_id') def _check_operating_unit(self): for rma in self: bad_lines = rma.rma_line_ids.filtered( diff --git a/rma_operating_unit/tests/test_rma_operating_unit.py b/rma_operating_unit/tests/test_rma_operating_unit.py index 94f3bf2e..8fd9bb3b 100644 --- a/rma_operating_unit/tests/test_rma_operating_unit.py +++ b/rma_operating_unit/tests/test_rma_operating_unit.py @@ -70,7 +70,6 @@ class TestRmaOperatingUnit(common.TransactionCase): rma_order = self.rma_model.sudo(uid).create({ 'operating_unit_id': operating_unit.id, 'partner_id': self.partner.id, - 'user_id': uid, }) return rma_order diff --git a/rma_operating_unit/views/rma_order_line_view.xml b/rma_operating_unit/views/rma_order_line_view.xml index abe557ad..4e88e3cd 100644 --- a/rma_operating_unit/views/rma_order_line_view.xml +++ b/rma_operating_unit/views/rma_order_line_view.xml @@ -32,6 +32,9 @@ + + [('type','=','supplier'),('out_warehouse_id.operating_unit_id', '=', operating_unit_id)] + @@ -43,13 +46,16 @@ + + [('type','=','customer'),('in_warehouse_id.operating_unit_id', '=', operating_unit_id)] + rma.order.line.select rma.order.line - + diff --git a/rma_operating_unit/wizards/rma_add_stock_move.py b/rma_operating_unit/wizards/rma_add_stock_move.py index 01eff5da..b3beff1f 100644 --- a/rma_operating_unit/wizards/rma_add_stock_move.py +++ b/rma_operating_unit/wizards/rma_add_stock_move.py @@ -35,3 +35,4 @@ class RmaAddStockMove(models.TransientModel): raise ValidationError(_( "Please define a warehouse with a default RMA location")) res.update(warehouse_id=warehouse.id) + return res diff --git a/rma_purchase/__init__.py b/rma_purchase/__init__.py index 4105ff51..9f7a36d7 100644 --- a/rma_purchase/__init__.py +++ b/rma_purchase/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + from . import models from . import wizards diff --git a/rma_purchase/__manifest__.py b/rma_purchase/__manifest__.py index f91228b4..2f704907 100644 --- a/rma_purchase/__manifest__.py +++ b/rma_purchase/__manifest__.py @@ -1,18 +1,23 @@ # -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + { 'name': 'RMA Purchase', - 'version': '9.0.1.0.0', + 'version': '10.0.2.0.0', 'category': 'RMA', 'summary': 'RMA from PO', 'license': 'LGPL-3', 'author': 'Eficent, Odoo Community Association (OCA)', 'website': 'http://www.github.com/OCA/rma', 'depends': ['rma_account', 'purchase'], - 'data': ['views/rma_order_view.xml', - 'views/rma_order_line_view.xml', - 'wizards/rma_add_purchase.xml'], + 'data': [ + 'wizards/rma_order_line_make_purchase_order_view.xml', + 'security/ir.model.access.csv', + 'views/rma_operation_view.xml', + 'views/rma_order_view.xml', + 'views/rma_order_line_view.xml', + 'wizards/rma_add_purchase.xml', + ], 'installable': True, - 'auto_install': True, } diff --git a/rma_purchase/models/__init__.py b/rma_purchase/models/__init__.py index 5c53c7a9..8facb465 100644 --- a/rma_purchase/models/__init__.py +++ b/rma_purchase/models/__init__.py @@ -3,4 +3,6 @@ from . import rma_order from . import rma_order_line +from . import purchase_order from . import purchase_order_line +from . import rma_operation diff --git a/rma_purchase/models/purchase_order.py b/rma_purchase/models/purchase_order.py new file mode 100644 index 00000000..59999e78 --- /dev/null +++ b/rma_purchase/models/purchase_order.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import api, models + + +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + @api.model + def new(self, vals): + """Allows to propose a line based on the RMA information.""" + res = super(PurchaseOrder, self).new(vals) + rma_line_id = self.env.context.get('rma_line_id') + if rma_line_id: + rma_line = self.env['rma.order.line'].browse(rma_line_id) + line = self.env['purchase.order.line'].new({ + 'product_id': rma_line.product_id.id, + }) + line.onchange_product_id() + line.update({ + 'product_qty': rma_line.qty_to_purchase, + 'product_uom': rma_line.uom_id.id, + }) + res.order_line = line + # TODO: maybe this line is not needed in v10: + res.date_planned = res._compute_date_planned() + return res diff --git a/rma_purchase/models/purchase_order_line.py b/rma_purchase/models/purchase_order_line.py index c67d0e3c..ef795ce4 100644 --- a/rma_purchase/models/purchase_order_line.py +++ b/rma_purchase/models/purchase_order_line.py @@ -1,13 +1,21 @@ # -*- coding: utf-8 -*- -# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from odoo import api, models +from odoo import api, fields, models class PurchaseOrderLine(models.Model): _inherit = "purchase.order.line" + # TODO: to be removed on migration to v10: + # This is needed because odoo misspelled `store` in v9 :facepalm: + state = fields.Selection(related='order_id.state', store=True) + + rma_line_id = fields.Many2one( + comodel_name='rma.order.line', string='RMA', copy=False + ) + @api.model def name_search(self, name='', args=None, operator='ilike', limit=100): """Allows to search by PO reference.""" @@ -32,9 +40,14 @@ class PurchaseOrderLine(models.Model): res = [] if self.env.context.get('rma'): for purchase in self: + invoices = self.env['account.invoice.line'].search( + [('purchase_line_id', '=', purchase.id)]) if purchase.order_id.name: - res.append((purchase.id, "%s %s qty:%s" % ( + res.append((purchase.id, "%s %s %s qty:%s" % ( purchase.order_id.name, + " ".join(str(x) for x in [ + inv.number for inv in invoices.mapped( + 'invoice_id')]), purchase.product_id.name, purchase.product_qty))) else: res.append( @@ -42,3 +55,10 @@ class PurchaseOrderLine(models.Model): return res else: return super(PurchaseOrderLine, self).name_get() + + @api.model + def create(self, vals): + rma_line_id = self.env.context.get('rma_line_id') + if rma_line_id: + vals['rma_line_id'] = rma_line_id + return super(PurchaseOrderLine, self).create(vals) diff --git a/rma_purchase/models/rma_operation.py b/rma_purchase/models/rma_operation.py new file mode 100644 index 00000000..e57e62ae --- /dev/null +++ b/rma_purchase/models/rma_operation.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class RmaOperation(models.Model): + _inherit = 'rma.operation' + + purchase_policy = fields.Selection( + selection=[('no', 'Not required'), + ('ordered', 'Based on Ordered Quantities'), + ('delivered', 'Based on Delivered Quantities')], + string="Purchase Policy", default='no', + ) + + @api.multi + @api.constrains('purchase_policy') + def _check_purchase_policy(self): + if self.filtered( + lambda r: r.purchase_policy != 'no' and r.type != 'supplier'): + raise ValidationError(_( + 'Purchase Policy can only apply to supplier operations')) diff --git a/rma_purchase/models/rma_order_line.py b/rma_purchase/models/rma_order_line.py index b2cf3e50..6e4d5def 100644 --- a/rma_purchase/models/rma_order_line.py +++ b/rma_purchase/models/rma_order_line.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import api, fields, models, _ from odoo.exceptions import ValidationError @@ -12,12 +12,9 @@ class RmaOrderLine(models.Model): @api.multi def _compute_purchase_count(self): for rec in self: - purchase_list = [] - for procurement_id in rec.procurement_ids: - if procurement_id.purchase_id and \ - procurement_id.purchase_id.id: - purchase_list.append(procurement_id.purchase_id.id) - rec.purchase_count = len(list(set(purchase_list))) + purchase_line_count = self.env['purchase.order.line'].search( + [('rma_line_id', '=', rec.id)]) + rec.purchase_count = len(purchase_line_count.mapped('order_id')) @api.multi @api.depends('procurement_ids.purchase_line_id') @@ -31,10 +28,18 @@ class RmaOrderLine(models.Model): rec.purchase_order_line_ids = [(6, 0, purchase_list)] @api.multi - @api.depends('procurement_ids.purchase_line_id') - def _compute_qty_purchased(self): + @api.depends('procurement_ids.purchase_line_id', + 'manual_purchase_line_ids', + 'manual_purchase_line_ids.state', 'qty_delivered') + def _compute_qty_purchase(self): for rec in self: rec.qty_purchased = rec._get_rma_purchased_qty() + if rec.purchase_policy == 'ordered': + rec.qty_to_purchase = rec.product_qty - rec.qty_purchased + elif rec.purchase_policy == 'delivered': + rec.qty_to_purchase = rec.qty_delivered - rec.qty_purchased + else: + rec.qty_to_purchase = 0.0 purchase_count = fields.Integer( compute='_compute_purchase_count', string='# of Purchases', @@ -55,12 +60,36 @@ class RmaOrderLine(models.Model): column1='rma_order_line_id', column2='purchase_order_line_id', string='Purchase Order Lines', compute='_compute_purchase_order_lines', ) + purchase_policy = fields.Selection( + selection=[('no', 'Not required'), + ('ordered', 'Based on Ordered Quantities'), + ('delivered', 'Based on Delivered Quantities')], + string="Purchase Policy", default='no', + required=True, + ) + manual_purchase_line_ids = fields.One2many( + comodel_name='purchase.order.line', + inverse_name='rma_line_id', + string='Manual Purchase Order Lines', + readonly=True, copy=False) + qty_to_purchase = fields.Float( + string='Qty To Purchase', copy=False, + digits=dp.get_precision('Product Unit of Measure'), + readonly=True, compute='_compute_qty_purchase', store=True, + ) qty_purchased = fields.Float( string='Qty Purchased', copy=False, digits=dp.get_precision('Product Unit of Measure'), - readonly=True, compute='_compute_qty_purchased', store=True, + readonly=True, compute='_compute_qty_purchase', store=True, ) + @api.onchange('operation_id') + def _onchange_operation_id(self): + res = super(RmaOrderLine, self)._onchange_operation_id() + if self.operation_id: + self.purchase_policy = self.operation_id.purchase_policy or 'no' + return res + @api.multi def _prepare_rma_line_from_po_line(self, line): self.ensure_one() @@ -144,20 +173,24 @@ class RmaOrderLine(models.Model): def action_view_purchase_order(self): action = self.env.ref('purchase.purchase_rfq') result = action.read()[0] - order_ids = [] - for procurement_id in self.procurement_ids: - order_ids.append(procurement_id.purchase_id.id) - result['domain'] = [('id', 'in', order_ids)] + orders = self.mapped('procurement_ids.purchase_id') + orders += self.mapped('manual_purchase_line_ids.order_id') + result['domain'] = [('id', 'in', orders.ids)] return result @api.multi def _get_rma_purchased_qty(self): self.ensure_one() qty = 0.0 + if self.type == 'customer': + return qty + uom_obj = self.env['product.uom'] for procurement_id in self.procurement_ids: purchase_line = procurement_id.purchase_line_id - if self.type == 'supplier': - qty += purchase_line.product_qty - else: - qty = 0.0 + qty += purchase_line.product_qty + + for line in self.manual_purchase_line_ids.filtered( + lambda p: p.state not in ('draft', 'sent', 'cancel')): + qty += uom_obj._compute_quantity( + self.uom_id.id, line.product_qty, line.product_uom.id) return qty diff --git a/rma_purchase/security/ir.model.access.csv b/rma_purchase/security/ir.model.access.csv new file mode 100755 index 00000000..e37a8852 --- /dev/null +++ b/rma_purchase/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_purchase_order_supplier_user,access_purchase_order,purchase.model_purchase_order,rma.group_rma_supplier_user,1,0,0,0 +access_purchase_order_line_supplier_user,access_purchase_order_line,purchase.model_purchase_order_line,rma.group_rma_supplier_user,1,0,0,0 diff --git a/rma_purchase/tests/__init__.py b/rma_purchase/tests/__init__.py index dfa77946..81a8e98e 100644 --- a/rma_purchase/tests/__init__.py +++ b/rma_purchase/tests/__init__.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2018 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from . import test_rma -from . import test_supplier_rma -from . import test_rma_dropship + +from . import test_rma_purchase diff --git a/rma_purchase/tests/test_rma.py b/rma_purchase/tests/test_rma.py deleted file mode 100644 index bc3ad89d..00000000 --- a/rma_purchase/tests/test_rma.py +++ /dev/null @@ -1,475 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.tests import common -from openerp import fields - - -class TestRma(common.TransactionCase): - - """ Test the routes and the quantities """ - - def setUp(self): - super(TestRma, self).setUp() - - self.rma_make_picking = self.env['rma_make_picking.wizard'] - self.make_supplier_rma = self.env["rma.order.line.make.supplier.rma"] - self.rma_add_stock_move = self.env['rma_add_stock_move'] - self.stockpicking = self.env['stock.picking'] - self.rma = self.env['rma.order'] - self.rma_line = self.env['rma.order.line'] - self.rma_op = self.env['rma.operation'] - self.rma_cust_replace_op_id = self.env.ref( - 'rma.rma_operation_customer_replace') - self.rma_sup_replace_op_id = self.env.ref( - 'rma.rma_operation_supplier_replace') - self.product_id = self.env.ref('product.product_product_4') - self.product_id.product_tmpl_id.categ_id.\ - property_stock_account_input_categ_id =\ - self.env.ref('account.data_account_type_receivable').id - self.product_id.product_tmpl_id.categ_id.\ - property_stock_account_output_categ_id =\ - self.env.ref('account.data_account_type_expenses').id - self.product_1 = self.env.ref('product.product_product_25') - self.product_2 = self.env.ref('product.product_product_7') - self.product_3 = self.env.ref('product.product_product_11') - self.uom_unit = self.env.ref('product.product_uom_unit') - self.valuation_account = self.env.ref( - 'l10n_generic_coa.1_conf_cas') - self.stock_input_account = self.env.ref( - 'l10n_generic_coa.1_current_liabilities') - self.stock_output_account = self.env.ref( - 'l10n_generic_coa.1_conf_a_expense') - # assign an operation - self.product_1.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_2.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_3.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.partner_id = self.env.ref('base.res_partner_12') - self.stock_location = self.env.ref('stock.stock_location_stock') - wh = self.env.ref('stock.warehouse0') - self.stock_rma_location = wh.lot_rma_id - self.customer_location = self.env.ref( - 'stock.stock_location_customers') - self.supplier_location = self.env.ref( - 'stock.stock_location_suppliers') - self.product_uom_id = self.env.ref('product.product_uom_unit') - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_customer_id = self._create_rma_from_move( - products2move, 'customer', self.env.ref('base.res_partner_2'), - dropship=False) - - def _create_picking(self, partner): - return self.stockpicking.create({ - 'partner_id': partner.id, - 'picking_type_id': self.env.ref('stock.picking_type_in').id, - 'location_id': self.stock_location.id, - 'location_dest_id': self.supplier_location.id - }) - - def _create_rma_from_move(self, products2move, type, partner, dropship, - supplier_address_id=None): - picking_in = self._create_picking(partner) - - moves = [] - if type == 'customer': - for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.stock_location, - self.customer_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) - else: - for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.supplier_location, - self.stock_rma_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) - # Create the RMA from the stock_move - rma_id = self.rma.create( - { - 'reference': '0001', - 'type': type, - 'partner_id': partner.id, - 'company_id': self.env.ref('base.main_company').id - }) - rma_id._compute_invoice_refund_count() - rma_id._compute_invoice_count() - - data = {'add_invoice_id': self._create_invoice().id} - new_line = self.rma.new(data) - new_line.on_change_invoice() - - rma_id.action_view_invoice_refund() - rma_id.action_view_invoice() - - for move in moves: - if type == 'customer': - wizard = self.rma_add_stock_move.new( - {'stock_move_id': move.id, 'customer': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - } - ) - wizard.with_context({ - 'stock_move_id': move.id, 'customer': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }) - data = wizard.with_context(customer=1).\ - _prepare_rma_line_from_stock_move(move) - data['partner_id'] = move.partner_id.id - else: - wizard = self.rma_add_stock_move.new( - {'stock_move_id': move.id, 'supplier': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - } - ) - wizard.with_context( - {'stock_move_id': move.id, 'supplier': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }) - data = wizard._prepare_rma_line_from_stock_move(move) - data['partner_id'] = move.partner_id.id - if dropship: - data.update(customer_to_supplier=dropship, - supplier_address_id=supplier_address_id.id) - data['partner_id'] = move.partner_id.id - data['rma_id'] = rma_id.id - self.line = self.rma_line.create(data) - # approve the RMA Line - self.rma_line.action_rma_to_approve() - - self.line.action_rma_approve() - self.line.action_view_invoice() - self.line.action_view_refunds() - - # approve the RMA -# rma_id.action_rma_to_approve() -# rma_id.action_rma_approve() - return rma_id - - def _prepare_move(self, product, qty, src, dest, picking_in): - res = { - 'partner_id': self.partner_id.id, - 'product_id': product.id, - 'name': product.partner_ref, - 'state': 'confirmed', - 'product_uom': self.product_uom_id.id or product.uom_id.id, - 'product_uom_qty': qty, - 'origin': 'Test RMA', - 'location_id': src.id, - 'location_dest_id': dest.id, - 'picking_id': picking_in.id - } - return res - - def test_rma_refund(self): - - self.rma_refund_item = self.env['rma.refund.item'] - self.rma_refund = self.env['rma.refund'] - - self.product_categ = self.env.ref('product.product_category_5') - self.product_categ.update({ - 'property_valuation': 'real_time', - 'property_stock_valuation_account_id': self.valuation_account.id, - 'property_stock_account_input_categ_id': - self.stock_input_account.id, - 'property_stock_account_output_categ_id': - self.stock_output_account.id, - }) - self.product_id.update({ - 'categ_id': self.product_categ.id, - }) - for line in self.rma_customer_id.rma_line_ids: - line.refund_policy = 'ordered' - - refund = self.rma_refund.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({'description': 'Test Reason', - 'date_invoice': fields.datetime.now() - }) - self.rma_refund_item.create({ - 'line_id': self.rma_customer_id.rma_line_ids[0].id, - 'rma_id': self.rma_customer_id.id, - 'product_id': self.product_id.id, - 'name': 'Test RMA Refund', - 'product_qty': self.rma_customer_id.rma_line_ids[0].product_qty, - 'wiz_id': refund.id - }) - refund.invoice_refund() - - def test_rma_add_invoice_wizard(self): - - wizard = self.env['rma_add_invoice'].with_context({ - 'active_ids': self.rma_customer_id.ids, - 'active_model': 'rma.order', - 'active_id': self.rma_customer_id.id - }).create({'partner_id': self.partner_id.id, - 'rma_id': self.rma_customer_id.id, - 'invoice_line_ids': - [(6, 0, [self._create_invoice().invoice_line_ids.id])], - }) - wizard.add_lines() - - def _create_invoice(self): - self.Account = self.env['account.account'] - self.AccountInvoice = self.env['account.invoice'] - self.AccountInvoiceLine = self.env['account.invoice.line'] - - self.account_receivable =\ - self.env.ref('account.data_account_type_receivable') - self.account_expenses =\ - self.env.ref('account.data_account_type_expenses') - invoice_account = self.Account.\ - search([('user_type_id', '=', self.account_receivable.id)], limit=1 - ).id - invoice_line_account = self.Account.\ - search([('user_type_id', '=', self.account_expenses.id)], limit=1 - ).id - - invoice = self.AccountInvoice.create({ - 'partner_id': self.partner_id.id, - 'account_id': invoice_account, - 'type': 'in_invoice', - }) - - invoice_line = self.AccountInvoiceLine.create({ - 'product_id': self.product_1.id, - 'quantity': 1.0, - 'price_unit': 100.0, - 'invoice_id': invoice.id, - 'uom_id': 1, - 'name': 'product that cost 100', - 'account_id': invoice_line_account, - }) - invoice._compute_rma_count() - invoice_line._compute_rma_count() - invoice.action_view_rma_customer() - invoice.action_view_rma_supplier() - return invoice - - def test_rma_make_picking(self): - - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - 'active_id': 1 - }).create({}) - - wizard.action_create_picking() - data = {'purchase_order_line_id': - self._create_purchase_order().order_line.id} - new_line = self.rma_line.new(data) - new_line._onchange_purchase_order_line_id() - - self.rma_customer_id._compute_po_count() - self.rma_customer_id._compute_origin_po_count() - - self.rma_customer_id.action_view_purchase_order() - self.rma_customer_id.action_view_origin_purchase_order() - - self.rma_customer_id.rma_line_ids[0]._compute_purchase_count() - self.rma_customer_id.rma_line_ids[0]._compute_purchase_order_lines() - self.rma_customer_id.rma_line_ids[0].action_view_purchase_order() - self.rma_customer_id.rma_line_ids[0]._get_rma_purchased_qty() - - def test_rma_add_purchase_wizard(self): - wizard = self.env['rma_add_purchase'].with_context({ - 'active_ids': self.rma_customer_id.ids, - 'active_model': 'rma.order', - 'active_id': self.rma_customer_id.id - }).create({'partner_id': self.partner_id.id, - 'rma_id': self.rma_customer_id.id, - 'purchase_id': self._create_purchase_order().id, - 'purchase_line_ids': - [(6, 0, [self._create_purchase_order().order_line.id])], - }) - wizard.default_get([str(self._create_purchase_order().id), - str(self._create_purchase_order().order_line.id), - str(self.partner_id.id)]) - wizard.add_lines() - - def _create_purchase_order(self): - purchase_order_id = self.env["purchase.order"].create({ - "partner_id": self.partner_id.id, - "order_line": [ - (0, 0, { - "product_id": self.product_id.id, - "name": self.product_id.name, - "product_qty": 5, - "price_unit": 100, - "product_uom": self.product_id.uom_id.id, - "date_planned": fields.datetime.now(), - }), - ], - }) - self.env["purchase.order.line"].\ - name_search(name=self.product_id.name, operator='ilike', - args=[('id', 'in', purchase_order_id.order_line.ids)]) - self.env["purchase.order.line"].\ - _name_search(name=self.product_id.name, operator='ilike', - args=[('id', 'in', purchase_order_id.order_line.ids)]) - return purchase_order_id - - def test_customer_rma(self): - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - 'active_id': 1 - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_customer_id.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty incoming") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty incoming") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty incoming") - picking.action_assign() - picking.do_transfer() - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_to_receive, 0, - "Wrong qty to_receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to_deliver") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to_deliver") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to_deliver") - - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'outgoing', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - pickings = self.stockpicking.search(domain) - procurements[0].purchase_id = self._create_purchase_order().id - wizard._get_action(pickings, procurements) - self.assertEquals(len(pickings), 2, - "Incorrect number of pickings created") - picking_out = pickings[1] - moves = picking_out.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_to_receive, 0, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 3, - "Wrong qty outgoing") - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 2, - "Wrong qty outgoing") - picking_out.action_assign() - picking_out.do_transfer() - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_to_receive, 0, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 3, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") - self.line.action_rma_done() - self.assertEquals(self.line.state, 'done', - "Wrong State") diff --git a/rma_purchase/tests/test_rma_dropship.py b/rma_purchase/tests/test_rma_dropship.py deleted file mode 100644 index abe07221..00000000 --- a/rma_purchase/tests/test_rma_dropship.py +++ /dev/null @@ -1,108 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.addons.rma.tests import test_rma - - -class TestRmaDropship(test_rma.TestRma): - - def setUp(self): - super(TestRmaDropship, self).setUp() - self.product_id.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_1.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_2.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_3.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_droship_id = self._create_rma_from_move( - products2move, 'customer', self.env.ref('base.res_partner_2'), - dropship=True, - supplier_address_id=self.env.ref('base.res_partner_3')) - - def test_dropship(self): - wizard = self.make_supplier_rma.with_context({ - 'active_ids': self.rma_droship_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({}) - res = wizard.make_supplier_rma() - supplier_rma = self.rma.browse(res['res_id']) - for line in supplier_rma.rma_line_ids: - line.action_rma_to_approve() - line.action_rma_approve() - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': supplier_rma.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in supplier_rma.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty outgoing") - - for line in self.rma_droship_id.rma_line_ids: - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 3, - "Wrong qty in supplier rma") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 5, - "Wrong qty in supplier rma") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 2, - "Wrong qty in supplier rma") - for line in self.rma_droship_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") diff --git a/rma_purchase/tests/test_rma_purchase.py b/rma_purchase/tests/test_rma_purchase.py new file mode 100644 index 00000000..d2e157f9 --- /dev/null +++ b/rma_purchase/tests/test_rma_purchase.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo.tests import common +from odoo.fields import Datetime + + +class TestRmaPurchase(common.SingleTransactionCase): + + @classmethod + def setUpClass(cls): + super(TestRmaPurchase, cls).setUpClass() + + cls.rma_obj = cls.env['rma.order'] + cls.rma_line_obj = cls.env['rma.order.line'] + cls.rma_op_obj = cls.env['rma.operation'] + cls.rma_add_purchase_wiz = cls.env['rma_add_purchase'] + cls.po_obj = cls.env['purchase.order'] + cls.pol_obj = cls.env['purchase.order.line'] + cls.product_obj = cls.env['product.product'] + cls.partner_obj = cls.env['res.partner'] + + cls.rma_route_cust = cls.env.ref('rma.route_rma_customer') + + # Create supplier + supplier1 = cls.partner_obj.create({'name': 'Supplier 1'}) + + # Create products + cls.product_1 = cls.product_obj.create({ + 'name': 'Test Product 1', + 'type': 'product', + }) + cls.product_2 = cls.product_obj.create({ + 'name': 'Test Product 2', + 'type': 'product', + }) + + # Create PO: + cls.po = cls.po_obj.create({ + 'partner_id': supplier1.id, + }) + cls.pol_1 = cls.pol_obj.create({ + 'name': cls.product_1.name, + 'order_id': cls.po.id, + 'product_id': cls.product_1.id, + 'product_qty': 20.0, + 'product_uom': cls.product_1.uom_id.id, + 'price_unit': 100.0, + 'date_planned': Datetime.now(), + }) + cls.pol_2 = cls.pol_obj.create({ + 'name': cls.product_2.name, + 'order_id': cls.po.id, + 'product_id': cls.product_2.id, + 'product_qty': 18.0, + 'product_uom': cls.product_2.uom_id.id, + 'price_unit': 150.0, + 'date_planned': Datetime.now(), + }) + + # Create RMA group: + cls.rma_group = cls.rma_obj.create({ + 'partner_id': supplier1.id, + 'type': 'supplier', + }) + + def test_01_add_from_purchase_order(self): + """Test wizard to create supplier RMA from Purchase Orders.""" + self.assertEqual(self.rma_group.origin_po_count, 0) + add_purchase = self.rma_add_purchase_wiz.with_context({ + 'supplier': True, + 'active_ids': self.rma_group.id, + 'active_model': 'rma.order', + }).create({ + 'purchase_id': self.po.id, + 'purchase_line_ids': [(6, 0, self.po.order_line.ids)], + }) + add_purchase.add_lines() + self.assertEqual(len(self.rma_group.rma_line_ids), 2) + for t in self.rma_group.rma_line_ids.mapped('type'): + self.assertEqual(t, 'supplier') + self.assertEqual(self.rma_group.origin_po_count, 1) + + def test_02_fill_rma_from_po_line(self): + """Test filling a RMA (line) from a Purchase Order line.""" + rma = self.rma_line_obj.new({ + 'partner_id': self.po.partner_id.id, + 'purchase_order_line_id': self.pol_1.id, + 'type': 'supplier', + }) + self.assertFalse(rma.product_id) + rma._onchange_purchase_order_line_id() + self.assertEqual(rma.product_id, self.product_1) + self.assertEqual(rma.product_qty, 20.0) diff --git a/rma_purchase/tests/test_supplier_rma.py b/rma_purchase/tests/test_supplier_rma.py deleted file mode 100644 index 8fca8b14..00000000 --- a/rma_purchase/tests/test_supplier_rma.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.addons.rma.tests import test_rma - - -class TestSupplierRma(test_rma.TestRma): - - def setUp(self): - super(TestSupplierRma, self).setUp() - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_supplier_id = self._create_rma_from_move( - products2move, 'supplier', self.env.ref('base.res_partner_1'), - dropship=False) - - def test_supplier_rma(self): - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'outgoing', - 'active_id': 1 - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 3, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 2, - "Wrong qty outgoing") - - picking.action_assign() - picking.do_new_transfer() - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - if line.product_id == self.product_2: - self.assertEquals(line.qty_outgoing, 5, - "Wrong qty outgoing") - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - if line.product_id == self.product_3: - self.assertEquals(line.qty_outgoing, 2, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - pickings = self.stockpicking.search(domain) - self.assertEquals(len(pickings), 2, - "Incorrect number of pickings created") - picking_out = pickings[1] - moves = picking_out.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - picking_out.action_assign() - picking_out.do_new_transfer() - for line in self.rma_supplier_id.rma_line_ids[0]: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty deliver") - self.assertEquals(line.qty_outgoing, 6, - "Wrong qty outgoing") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") - for line in self.rma_supplier_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") diff --git a/rma_purchase/views/rma_operation_view.xml b/rma_purchase/views/rma_operation_view.xml new file mode 100644 index 00000000..9f4b5a86 --- /dev/null +++ b/rma_purchase/views/rma_operation_view.xml @@ -0,0 +1,28 @@ + + + + + + rma.operation.tree - rma_purchase + rma.operation + + + + + + + + + + rma.operation.form - rma_purchase + rma.operation + + + + + + + + + diff --git a/rma_purchase/views/rma_order_line_view.xml b/rma_purchase/views/rma_order_line_view.xml index f3b7d0af..7c36678e 100644 --- a/rma_purchase/views/rma_order_line_view.xml +++ b/rma_purchase/views/rma_order_line_view.xml @@ -1,6 +1,28 @@ + + Purchase Order + purchase.order + form + current + form,tree + + + + rma.order.line.supplier.form + rma.order.line + + +
+
+
+
+ rma.order.line.supplier.form rma.order.line @@ -25,9 +47,13 @@
+ + + + diff --git a/rma_purchase/wizards/__init__.py b/rma_purchase/wizards/__init__.py index 716f361c..cb29e684 100644 --- a/rma_purchase/wizards/__init__.py +++ b/rma_purchase/wizards/__init__.py @@ -4,3 +4,4 @@ from . import rma_make_picking from . import rma_add_purchase +from . import rma_order_line_make_purchase_order diff --git a/rma_purchase/wizards/rma_order_line_make_purchase_order.py b/rma_purchase/wizards/rma_order_line_make_purchase_order.py new file mode 100644 index 00000000..448aad31 --- /dev/null +++ b/rma_purchase/wizards/rma_order_line_make_purchase_order.py @@ -0,0 +1,147 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). + +import odoo.addons.decimal_precision as dp +from odoo import _, api, exceptions, fields, models +from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT +from datetime import datetime + + +class RmaLineMakePurchaseOrder(models.TransientModel): + _name = "rma.order.line.make.purchase.order" + _description = "Make Purchases Order from RMA Line" + + partner_id = fields.Many2one( + comodel_name='res.partner', string='Customer', required=False, + domain=[('customer', '=', True)]) + item_ids = fields.One2many( + comodel_name='rma.order.line.make.purchase.order.item', + inverse_name='wiz_id', string='Items') + purchase_order_id = fields.Many2one( + comodel_name='purchase.order', string='Purchases Order', + required=False, domain=[('state', '=', 'draft')]) + + @api.model + def _prepare_item(self, line): + return { + 'line_id': line.id, + 'rma_line_id': line.id, + 'product_id': line.product_id.id, + 'name': line.product_id.name, + 'product_qty': line.qty_to_purchase, + 'rma_id': line.rma_id.id, + 'product_uom_id': line.uom_id.id, + } + + @api.model + def default_get(self, fields): + res = super(RmaLineMakePurchaseOrder, self).default_get( + fields) + rma_line_obj = self.env['rma.order.line'] + rma_line_ids = self.env.context['active_ids'] or [] + active_model = self.env.context['active_model'] + + if not rma_line_ids: + return res + assert active_model == 'rma.order.line', 'Bad context propagation' + + items = [] + lines = rma_line_obj.browse(rma_line_ids) + for line in lines: + items.append([0, 0, self._prepare_item(line)]) + customers = lines.mapped('partner_id') + if len(customers) == 1: + res['partner_id'] = customers.id + else: + raise exceptions.Warning( + _('Only RMA lines from the same partner can be processed at ' + 'the same time')) + res['item_ids'] = items + return res + + @api.model + def _prepare_purchase_order(self, item): + if not self.partner_id: + raise exceptions.Warning( + _('Enter a supplier.')) + supplier = self.partner_id + data = { + 'origin': '', + 'partner_id': supplier.id, + 'company_id': item.line_id.company_id.id, + } + return data + + @api.model + def _prepare_purchase_order_line(self, po, item): + product = item.product_id + vals = { + 'name': product.name, + 'order_id': po.id, + 'product_id': product.id, + 'price_unit': item.line_id.price_unit, + 'date_planned': datetime.today().strftime( + DEFAULT_SERVER_DATETIME_FORMAT), + 'product_uom': product.uom_po_id.id, + 'product_qty': item.product_qty, + 'rma_line_id': item.line_id.id + } + if item.free_of_charge: + vals['price_unit'] = 0.0 + return vals + + @api.multi + def create_purchase_order(self): + res = [] + purchase_obj = self.env['purchase.order'] + po_line_obj = self.env['purchase.order.line'] + purchase = False + + for item in self.item_ids: + if item.product_qty <= 0.0: + raise exceptions.Warning( + _('Enter a positive quantity.')) + + if self.purchase_order_id: + purchase = self.purchase_order_id + if not purchase: + po_data = self._prepare_purchase_order(item) + purchase = purchase_obj.create(po_data) + + po_line_data = self._prepare_purchase_order_line(purchase, item) + po_line_obj.create(po_line_data) + res.append(purchase.id) + + return { + 'domain': "[('id','in', ["+','.join(map(str, res))+"])]", + 'name': _('Request for Quotation'), + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'purchase.order', + 'view_id': False, + 'context': False, + 'type': 'ir.actions.act_window' + } + + +class RmaLineMakePurchaseOrderItem(models.TransientModel): + _name = "rma.order.line.make.purchase.order.item" + _description = "RMA Line Make Purchase Order Item" + + wiz_id = fields.Many2one( + comodel_name='rma.order.line.make.purchase.order', string='Wizard') + line_id = fields.Many2one( + comodel_name='rma.order.line', string='RMA Line') + rma_id = fields.Many2one( + comodel_name='rma.order', related='line_id.rma_id', + string='RMA Order') + product_id = fields.Many2one( + comodel_name='product.product', string='Product') + name = fields.Char(string='Description') + product_qty = fields.Float( + string='Quantity to purchase', + digits=dp.get_precision('Product Unit of Measure'),) + product_uom_id = fields.Many2one( + comodel_name='product.uom', string='UoM') + free_of_charge = fields.Boolean(string='Free of Charge') diff --git a/rma_purchase/wizards/rma_order_line_make_purchase_order_view.xml b/rma_purchase/wizards/rma_order_line_make_purchase_order_view.xml new file mode 100644 index 00000000..d5475da4 --- /dev/null +++ b/rma_purchase/wizards/rma_order_line_make_purchase_order_view.xml @@ -0,0 +1,61 @@ + + + + RMA Line Make Purchase Order + rma.order.line.make.purchase.order + form + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + Create RFQ + ir.actions.act_window + rma.order.line.make.purchase.order + form + form + + new + + +
+ diff --git a/rma_purchase_analytic/models/purchase_order_line.py b/rma_purchase_analytic/models/purchase_order_line.py index 4d42752b..044600f9 100644 --- a/rma_purchase_analytic/models/purchase_order_line.py +++ b/rma_purchase_analytic/models/purchase_order_line.py @@ -8,10 +8,10 @@ from odoo import _, api, exceptions, models class PurchaseOrderLine(models.Model): _inherit = "purchase.order.line" - @api.constrains('analytic_account_id') + @api.constrains('account_analytic_id') def check_analytic(self): - for line in self: - if (line.analytic_account_id != + for line in self.filtered(lambda p: p.rma_line_id): + if (line.account_analytic_id != line.rma_line_id.analytic_account_id): raise exceptions.ValidationError( _("The analytic account in the PO line it's not the same" diff --git a/rma_purchase_analytic/wizards/rma_add_purchase.py b/rma_purchase_analytic/wizards/rma_add_purchase.py index db0459f1..9bce48e3 100644 --- a/rma_purchase_analytic/wizards/rma_add_purchase.py +++ b/rma_purchase_analytic/wizards/rma_add_purchase.py @@ -13,3 +13,16 @@ class RmaAddPurchase(models.TransientModel): data = super(RmaAddPurchase, self)._prepare_rma_line_from_po_line(line) data.update(analytic_account_id=line.analytic_account_id.id) return data + + +class RmaLineMakePurchaseOrder(models.TransientModel): + _inherit = "rma.order.line.make.purchase.order" + _description = "Make Purchases Order from RMA Line" + + @api.model + def _prepare_purchase_order_line(self, po, item): + res = super( + RmaLineMakePurchaseOrder, self)._prepare_purchase_order_line( + po, item) + res['account_analytic_id'] = item.line_id.analytic_account_id.id + return res diff --git a/rma_purchase_operating_unit/README.rst b/rma_purchase_operating_unit/README.rst new file mode 100644 index 00000000..f6f45939 --- /dev/null +++ b/rma_purchase_operating_unit/README.rst @@ -0,0 +1,28 @@ +.. image:: https://img.shields.io/badge/license-LGPLv3-blue.svg + :target: https://www.gnu.org/licenses/lgpl.html + :alt: License: LGPL-3 + +================================= +RMA Purchase with Operating Units +================================= + +This module introduces the following features: + +* Adds the operating unit to the quotation + +Usage +===== + +* No changes + + +Contributors +------------ + +* Aaron Henriquez + + +Maintainer +---------- + +This module is maintained by Eficent. diff --git a/rma_purchase_operating_unit/__init__.py b/rma_purchase_operating_unit/__init__.py new file mode 100644 index 00000000..5f13e3ea --- /dev/null +++ b/rma_purchase_operating_unit/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import wizards diff --git a/rma_purchase_operating_unit/__manifest__.py b/rma_purchase_operating_unit/__manifest__.py new file mode 100644 index 00000000..ab2ed568 --- /dev/null +++ b/rma_purchase_operating_unit/__manifest__.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +{ + "name": "Analytic Account in RMA purchase", + "version": "10.0.1.0.0", + "author": "Eficent," + "Odoo Community Association (OCA)", + "license": "LGPL-3", + "website": "http://www.eficent.com", + "category": "Analytic", + "depends": ["rma_operating_unit", "rma_purchase"], + "data": [ + ], + 'installable': True, +} diff --git a/rma_purchase_operating_unit/wizards/__init__.py b/rma_purchase_operating_unit/wizards/__init__.py new file mode 100644 index 00000000..4ae587e0 --- /dev/null +++ b/rma_purchase_operating_unit/wizards/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2018 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from . import rma_line_make_purchase_order diff --git a/rma_purchase_operating_unit/wizards/rma_line_make_purchase_order.py b/rma_purchase_operating_unit/wizards/rma_line_make_purchase_order.py new file mode 100644 index 00000000..9a26dc4c --- /dev/null +++ b/rma_purchase_operating_unit/wizards/rma_line_make_purchase_order.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# © 2018 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import api, models + + +class RmaLineMakePurchaseOrder(models.TransientModel): + _inherit = "rma.order.line.make.purchase.order" + + @api.model + def _prepare_purchase_order(self, item): + res = super(RmaLineMakePurchaseOrder, self)._prepare_purchase_order(item) + res.update(operating_unit_id=item.line_id.operating_unit_id.id) + return res diff --git a/rma_quality_control_issue/models/qc_issue.py b/rma_quality_control_issue/models/qc_issue.py index dbbe05e1..fbe17f17 100644 --- a/rma_quality_control_issue/models/qc_issue.py +++ b/rma_quality_control_issue/models/qc_issue.py @@ -2,7 +2,7 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import api, fields, models +from odoo import api, fields, models class QualityControlIssue(models.Model): diff --git a/rma_quality_control_issue/models/rma_order.py b/rma_quality_control_issue/models/rma_order.py index d6b4fbc4..5c929c18 100644 --- a/rma_quality_control_issue/models/rma_order.py +++ b/rma_quality_control_issue/models/rma_order.py @@ -2,7 +2,7 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import fields, models +from odoo import fields, models class RmaOrderLine(models.Model): diff --git a/rma_quality_control_issue/tests/test_rma.py b/rma_quality_control_issue/tests/test_rma.py index 06585094..8b1fc3f4 100644 --- a/rma_quality_control_issue/tests/test_rma.py +++ b/rma_quality_control_issue/tests/test_rma.py @@ -2,7 +2,7 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp.tests import common +from odoo.tests import common class TestRma(common.TransactionCase): diff --git a/rma_quality_control_issue/wizard/qc_issue_make_supplier_rma.py b/rma_quality_control_issue/wizard/qc_issue_make_supplier_rma.py index 8a86c27f..d519b5a6 100644 --- a/rma_quality_control_issue/wizard/qc_issue_make_supplier_rma.py +++ b/rma_quality_control_issue/wizard/qc_issue_make_supplier_rma.py @@ -2,9 +2,9 @@ # Copyright 2016 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). -import openerp.addons.decimal_precision as dp -from openerp import api, fields, models, _ -from openerp.exceptions import ValidationError +import odoo.addons.decimal_precision as dp +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError class QcIssueMakeSupplierRma(models.TransientModel): diff --git a/rma_repair/models/mrp_repair.py b/rma_repair/models/mrp_repair.py index 8bcf4673..2b122cec 100644 --- a/rma_repair/models/mrp_repair.py +++ b/rma_repair/models/mrp_repair.py @@ -2,7 +2,7 @@ # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import fields, models +from odoo import fields, models class MrpRepair(models.Model): diff --git a/rma_repair/models/rma_operation.py b/rma_repair/models/rma_operation.py index 730e5ce2..8925b44e 100644 --- a/rma_repair/models/rma_operation.py +++ b/rma_repair/models/rma_operation.py @@ -2,7 +2,7 @@ # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import fields, models +from odoo import fields, models class RmaOperation(models.Model): diff --git a/rma_repair/models/rma_order.py b/rma_repair/models/rma_order.py index 7dd90913..bda4ad7d 100644 --- a/rma_repair/models/rma_order.py +++ b/rma_repair/models/rma_order.py @@ -2,7 +2,7 @@ # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import api, fields, models +from odoo import api, fields, models class RmaOrder(models.Model): diff --git a/rma_repair/models/rma_order_line.py b/rma_repair/models/rma_order_line.py index 62f801c3..7986caa1 100644 --- a/rma_repair/models/rma_order_line.py +++ b/rma_repair/models/rma_order_line.py @@ -2,8 +2,8 @@ # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import api, fields, models -from openerp.addons import decimal_precision as dp +from odoo import api, fields, models +from odoo.addons import decimal_precision as dp class RmaOrderLine(models.Model): diff --git a/rma_repair/tests/test_rma.py b/rma_repair/tests/test_rma.py index c98dace3..630c0365 100644 --- a/rma_repair/tests/test_rma.py +++ b/rma_repair/tests/test_rma.py @@ -2,7 +2,7 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp.tests import common +from odoo.tests import common class TestRma(common.TransactionCase): diff --git a/rma_repair/wizards/rma_order_line_make_repair.py b/rma_repair/wizards/rma_order_line_make_repair.py index ebb830db..291ffc77 100644 --- a/rma_repair/wizards/rma_order_line_make_repair.py +++ b/rma_repair/wizards/rma_order_line_make_repair.py @@ -2,9 +2,9 @@ # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). -import openerp.addons.decimal_precision as dp -from openerp import _, api, fields, models -from openerp.exceptions import ValidationError +import odoo.addons.decimal_precision as dp +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError class RmaLineMakeRepair(models.TransientModel): diff --git a/rma_sale/__manifest__.py b/rma_sale/__manifest__.py index 88bc95c9..31ace02d 100644 --- a/rma_sale/__manifest__.py +++ b/rma_sale/__manifest__.py @@ -4,19 +4,21 @@ { 'name': 'RMA Sale', - 'version': '10.0.1.0.0', + 'version': '10.0.2.0.0', 'license': 'LGPL-3', 'category': 'RMA', 'summary': 'Links RMA with Sales Orders', 'author': "Eficent, Odoo Community Association (OCA)", 'website': 'http://www.github.com/OCA/rma', - 'depends': ['rma', 'rma_account', 'sale_stock'], - 'data': ['views/rma_order_view.xml', - 'views/rma_operation_view.xml', - 'views/sale_order_view.xml', - 'wizards/rma_order_line_make_sale_order_view.xml', - 'wizards/rma_add_sale.xml', - 'views/rma_order_line_view.xml'], + 'depends': ['rma_account', 'sale_stock'], + 'data': [ + 'data/rma_operation.xml', + 'views/rma_order_view.xml', + 'views/rma_operation_view.xml', + 'views/sale_order_view.xml', + 'wizards/rma_order_line_make_sale_order_view.xml', + 'wizards/rma_add_sale.xml', + 'views/rma_order_line_view.xml', + ], 'installable': True, - 'auto_install': True, } diff --git a/rma_sale/data/rma_operation.xml b/rma_sale/data/rma_operation.xml new file mode 100644 index 00000000..b0fcfd39 --- /dev/null +++ b/rma_sale/data/rma_operation.xml @@ -0,0 +1,28 @@ + + + + + Sale after receive + SL-C + received + ordered + no + no + customer + + + + + + Advanced Refund + AR-C + received + ordered + no + received + customer + + + + + diff --git a/rma_sale/models/rma_operation.py b/rma_sale/models/rma_operation.py index a00f9a8d..8f2ed4e5 100644 --- a/rma_sale/models/rma_operation.py +++ b/rma_sale/models/rma_operation.py @@ -7,7 +7,7 @@ from odoo import fields, models class RmaOperation(models.Model): _inherit = 'rma.operation' - sale_type = fields.Selection([ + sale_policy = fields.Selection([ ('no', 'Not required'), ('ordered', 'Based on Ordered Quantities'), ('received', 'Based on Received Quantities')], string="Sale Policy", default='no') diff --git a/rma_sale/models/rma_order_line.py b/rma_sale/models/rma_order_line.py index f344ffee..ef72c913 100644 --- a/rma_sale/models/rma_order_line.py +++ b/rma_sale/models/rma_order_line.py @@ -9,26 +9,24 @@ from odoo.addons import decimal_precision as dp class RmaOrderLine(models.Model): _inherit = "rma.order.line" - @api.depends('sale_line_ids', 'sale_type', 'sales_count', - 'sale_line_ids.state') - @api.multi + @api.depends('sale_line_ids', 'sale_policy', 'sales_count', + 'sale_line_ids.state', 'qty_received', 'product_qty') def _compute_qty_to_sell(self): for rec in self: - if rec.sale_type == 'no': - rec.qty_to_sell = 0.0 - elif rec.sale_type == 'ordered': - qty = self._get_rma_sold_qty() - rec.qty_to_sell = self.product_qty - qty - elif rec.sale_type == 'received': - qty = self._get_rma_sold_qty() - rec.qty_to_sell = self.qty_received - qty + if rec.sale_policy == 'ordered': + qty = rec._get_rma_sold_qty() + rec.qty_to_sell = rec.product_qty - qty + elif rec.sale_policy == 'received': + qty = rec._get_rma_sold_qty() + rec.qty_to_sell = rec.qty_received - qty else: rec.qty_to_sell = 0.0 - @api.depends('sale_line_ids', 'sale_type', 'sales_count', + @api.depends('sale_line_ids', 'sale_policy', 'sales_count', 'sale_line_ids.state') def _compute_qty_sold(self): - self.qty_sold = self._get_rma_sold_qty() + for rec in self: + rec.qty_sold = rec._get_rma_sold_qty() @api.multi def _compute_sales_count(self): @@ -59,13 +57,35 @@ class RmaOrderLine(models.Model): digits=dp.get_precision('Product Unit of Measure'), readonly=True, compute=_compute_qty_sold, store=True) - sale_type = fields.Selection(selection=[ + sale_policy = fields.Selection(selection=[ ('no', 'Not required'), ('ordered', 'Based on Ordered Quantities'), ('received', 'Based on Received Quantities')], string="Sale Policy", default='no', required=True) sales_count = fields.Integer( compute=_compute_sales_count, string='# of Sales') + @api.onchange('product_id', 'partner_id') + def _onchange_product_id(self): + """Domain for sale_line_id is computed here to make it dynamic.""" + res = super(RmaOrderLine, self)._onchange_product_id() + if not res.get('domain'): + res['domain'] = {} + domain = [ + '|', + ('order_id.partner_id', '=', self.partner_id.id), + ('order_id.partner_id', 'child_of', self.partner_id.id)] + if self.product_id: + domain.append(('product_id', '=', self.product_id.id)) + res['domain']['sale_line_id'] = domain + return res + + @api.onchange('operation_id') + def _onchange_operation_id(self): + res = super(RmaOrderLine, self)._onchange_operation_id() + if self.operation_id: + self.sale_policy = self.operation_id.sale_policy or 'no' + return res + @api.multi def _prepare_rma_line_from_sale_order_line(self, line): self.ensure_one() diff --git a/rma_sale/models/sale_order_line.py b/rma_sale/models/sale_order_line.py index 84041190..a6e5cdfe 100644 --- a/rma_sale/models/sale_order_line.py +++ b/rma_sale/models/sale_order_line.py @@ -33,9 +33,13 @@ class SaleOrderLine(models.Model): if self.env.context.get('rma'): for sale in self: if sale.order_id.name: - res.append((sale.id, "%s %s qty:%s" % ( - sale.order_id.name, - sale.product_id.name, sale.product_uom_qty))) + res.append( + (sale.id, "SO:%s | INV: %s, | PART:%s | QTY:%s" % ( + sale.order_id.name, + " ".join(str(x) for x in [ + inv.number + for inv in sale.order_id.invoice_ids]), + sale.product_id.name, sale.product_uom_qty))) else: res.append(super(SaleOrderLine, sale).name_get()[0]) return res @@ -43,7 +47,8 @@ class SaleOrderLine(models.Model): return super(SaleOrderLine, self).name_get() rma_line_id = fields.Many2one( - comodel_name='rma.order.line', string='RMA', ondelete='restrict') + comodel_name='rma.order.line', string='RMA', ondelete='restrict', + copy=False) @api.multi def _prepare_order_line_procurement(self, group_id=False): diff --git a/rma_sale/tests/__init__.py b/rma_sale/tests/__init__.py index dfa77946..83ee6fd7 100644 --- a/rma_sale/tests/__init__.py +++ b/rma_sale/tests/__init__.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from . import test_rma -from . import test_supplier_rma -from . import test_rma_dropship + +from . import test_rma_sale diff --git a/rma_sale/tests/test_rma.py b/rma_sale/tests/test_rma.py deleted file mode 100644 index fca5f716..00000000 --- a/rma_sale/tests/test_rma.py +++ /dev/null @@ -1,470 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.tests import common -from openerp import fields - - -class TestRma(common.TransactionCase): - - """ Test the routes and the quantities """ - - def setUp(self): - super(TestRma, self).setUp() - - self.rma_make_picking = self.env['rma_make_picking.wizard'] - self.make_supplier_rma = self.env["rma.order.line.make.supplier.rma"] - self.rma_add_stock_move = self.env['rma_add_stock_move'] - self.stockpicking = self.env['stock.picking'] - self.rma = self.env['rma.order'] - self.rma_line = self.env['rma.order.line'] - self.rma_op = self.env['rma.operation'] - self.rma_cust_replace_op_id = self.env.ref( - 'rma.rma_operation_customer_replace') - self.rma_sup_replace_op_id = self.env.ref( - 'rma.rma_operation_supplier_replace') - self.product_id = self.env.ref('product.product_product_4') - self.product_1 = self.env.ref('product.product_product_25') - self.product_2 = self.env.ref('product.product_product_7') - self.product_3 = self.env.ref('product.product_product_11') - self.uom_unit = self.env.ref('product.product_uom_unit') - # assign an operation - self.product_1.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_2.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_3.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.partner_id = self.env.ref('base.res_partner_12') - self.stock_location = self.env.ref('stock.stock_location_stock') - wh = self.env.ref('stock.warehouse0') - self.stock_rma_location = wh.lot_rma_id - self.customer_location = self.env.ref( - 'stock.stock_location_customers') - self.supplier_location = self.env.ref( - 'stock.stock_location_suppliers') - self.product_uom_id = self.env.ref('product.product_uom_unit') - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_customer_id = self._create_rma_from_move( - products2move, 'customer', self.env.ref('base.res_partner_2'), - dropship=False) - - def _create_picking(self, partner): - return self.stockpicking.create({ - 'partner_id': partner.id, - 'picking_type_id': self.env.ref('stock.picking_type_in').id, - 'location_id': self.stock_location.id, - 'location_dest_id': self.supplier_location.id - }) - - def _create_rma_from_move(self, products2move, type, partner, dropship, - supplier_address_id=None): - picking_in = self._create_picking(partner) - - moves = [] - if type == 'customer': - for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.stock_location, - self.customer_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) - else: - for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.supplier_location, - self.stock_rma_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) - # Create the RMA from the stock_move - rma_id = self.rma.create( - { - 'reference': '0001', - 'type': type, - 'partner_id': partner.id, - 'company_id': self.env.ref('base.main_company').id - }) - for move in moves: - if type == 'customer': - wizard = self.rma_add_stock_move.new( - {'stock_move_id': move.id, 'customer': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - } - ) - wizard.with_context({ - 'stock_move_id': move.id, 'customer': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }) - - data = wizard._prepare_rma_line_from_stock_move(move) - data['partner_id'] = move.partner_id.id - wizard.add_lines() - - else: - wizard = self.rma_add_stock_move.new( - {'stock_move_id': move.id, 'supplier': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - } - ) - wizard.with_context( - {'stock_move_id': move.id, 'supplier': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }) - - data = wizard._prepare_rma_line_from_stock_move(move) - data['partner_id'] = move.partner_id.id - wizard.add_lines() - if dropship: - data.update(customer_to_supplier=dropship, - supplier_address_id=supplier_address_id.id) - data['partner_id'] = move.partner_id.id - data['rma_id'] = rma_id.id - self.line = self.rma_line.create(data) - # approve the RMA Line - self.rma_line.action_rma_to_approve() - self.line.action_rma_approve() - rma_id._compute_in_shipment_count() - rma_id._compute_out_shipment_count() - rma_id._compute_supplier_line_count() - rma_id._compute_line_count() - rma_id.action_view_in_shipments() - rma_id.action_view_out_shipments() - rma_id.action_view_lines() - - rma_id.partner_id.action_open_partner_rma() - rma_id.partner_id._compute_rma_line_count() - # approve the RMA -# rma_id.action_rma_to_approve() -# rma_id.action_rma_approve() - return rma_id - - def _prepare_move(self, product, qty, src, dest, picking_in): - res = { - 'partner_id': self.partner_id.id, - 'product_id': product.id, - 'name': product.partner_ref, - 'state': 'confirmed', - 'product_uom': self.product_uom_id.id or product.uom_id.id, - 'product_uom_qty': qty, - 'origin': 'Test RMA', - 'location_id': src.id, - 'location_dest_id': dest.id, - 'picking_id': picking_in.id - } - return res - - def test_add_sale(self): - wizard = self.env['rma_add_sale'].with_context({ - 'active_ids': self.rma_customer_id.ids, - 'active_model': 'rma.order', - 'active_id': self.rma_customer_id.id - }).create({'partner_id': self.partner_id.id, - 'rma_id': self.rma_customer_id.id, - 'sale_id': self._create_sale_order().id, - 'sale_line_ids': - [(6, 0, [self._create_sale_order().order_line.id])], - }) - wizard.default_get([str(self._create_sale_order().id), - str(self._create_sale_order().order_line.id), - str(self.partner_id.id)]) - wizard.add_lines() - - for line in self.rma_customer_id.rma_line_ids: - line._compute_qty_to_sell() - line.sale_type = 'ordered' - line._compute_qty_to_sell() - line.sale_type = 'received' - line._compute_qty_to_sell() - line._compute_qty_sold() - line._compute_sales_count() - - data = {'sale_line_id': self._create_sale_order().order_line.id} - new_line = self.rma_line.new(data) - new_line._onchange_sale_line_id() - - line.action_view_sale_order() - self.rma_customer_id.\ - _get_line_domain(self.rma_customer_id, - self.rma_customer_id.rma_line_ids[3]) - self.rma_customer_id._compute_sales_count() - self.rma_customer_id.action_view_sale_order() - - def test_rma_order_line_make_sale_order(self): - - self.rma_sale_order_item =\ - self.env['rma.order.line.make.sale.order.item'] - self.rma_sale_order = self.env['rma.order.line.make.sale.order'] - - self.product_id.income =\ - self.env.ref('account.data_account_type_receivable').id - self.product_id.expense =\ - self.env.ref('account.data_account_type_expenses').id - - sale_order = self.rma_sale_order.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({'sale_order_id': self._create_sale_order().id, - 'partner_id': self.partner_id.id, - }) - self.rma_sale_order_item.create({ - 'line_id': self.rma_customer_id.rma_line_ids[0].id, - 'rma_id': self.rma_customer_id.id, - 'product_id': self.product_id.id, - 'name': 'Test RMA Refund', - 'product_qty': self.rma_customer_id.rma_line_ids[0].product_qty, - 'wiz_id': sale_order.id - }) - for line in sale_order.item_ids: - line.product_qty = self.rma_customer_id.rma_line_ids[0].product_qty - sale_order.make_sale_order() - sale_order.write({'sale_order_id': False}) - sale_order.make_sale_order() - - def test_rma_refund(self): - - self.rma_refund_item = self.env['rma.refund.item'] - self.rma_refund = self.env['rma.refund'] - - self.product_id.income =\ - self.env.ref('account.data_account_type_receivable').id - self.product_id.expense =\ - self.env.ref('account.data_account_type_expenses').id - - self.product_id.product_tmpl_id.categ_id.\ - property_stock_account_input_categ_id =\ - self.env.ref('account.data_account_type_receivable').id - self.product_id.product_tmpl_id.categ_id.\ - property_stock_account_output_categ_id =\ - self.env.ref('account.data_account_type_expenses').id - - for line in self.rma_customer_id.rma_line_ids: - line.refund_policy = 'ordered' - - refund = self.rma_refund.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({'description': 'Test Reason', - 'date_invoice': fields.datetime.now() - }) - self.rma_refund_item.create({ - 'line_id': self.rma_customer_id.rma_line_ids[0].id, - 'rma_id': self.rma_customer_id.id, - 'product_id': self.product_id.id, - 'name': 'Test RMA Refund', - 'product_qty': self.rma_customer_id.rma_line_ids[0].product_qty, - 'wiz_id': refund.id - }) - - def _create_sale_order(self): - self.sale_order_id = self.env['sale.order'].create({ - 'partner_id': self.partner_id.id, - 'partner_invoice_id': self.partner_id.id, - 'partner_shipping_id': self.partner_id.id, - 'order_line': [(0, 0, { - 'name': self.product_id.name, - 'product_id': self.product_id.id, - 'product_uom_qty': - self.rma_customer_id.rma_line_ids[0].product_qty, - 'price_unit': 100.00, - })] - }) - self.env["sale.order.line"].\ - name_search(name=self.product_id.name, operator='ilike', - args=[('id', 'in', self.sale_order_id.order_line.ids)]) - self.env["sale.order.line"].\ - _name_search(name=self.product_id.name, operator='ilike', - args=[('id', 'in', self.sale_order_id.order_line.ids) - ]) - self.sale_order_id.order_line._prepare_order_line_procurement() - return self.sale_order_id - - def test_rma_order_line(self): - for line in self.rma_customer_id.rma_line_ids: - line.with_context({'default_rma_id': line.rma_id.id - })._default_warehouse_id() - line._default_location_id() - line.with_context({'partner_id': line.rma_id.partner_id.id - })._default_delivery_address() - line._compute_in_shipment_count() - line._compute_out_shipment_count() - line._compute_procurement_count() - - data = {'reference_move_id': line.reference_move_id.id} - new_line = self.rma_line.new(data) - new_line._onchange_reference_move_id() - - line.action_rma_to_approve() - line.action_rma_draft() - line.action_rma_done() - - data = {'product_id': line.product_id.id} - new_line = self.rma_line.new(data) - new_line._onchange_product_id() - - data = {'operation_id': line.operation_id.id} - new_line = self.rma_line.new(data) - new_line._onchange_operation_id() - - data = {'customer_to_supplier': line.customer_to_supplier} - new_line = self.rma_line.new(data) - new_line._onchange_receipt_policy() - - data = {'lot_id': line.lot_id.id} - new_line = self.rma_line.new(data) - new_line._onchange_lot_id() - - line.action_view_in_shipments() - line.action_view_out_shipments() - line.action_view_procurements() - - def test_customer_rma(self): - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - 'active_id': 1 - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_customer_id.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - picking.action_assign() - picking.do_new_transfer() - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_received, 0, - "Wrong qty receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to_deliver") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to_deliver") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to_deliver") - - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'outgoing', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - pickings = self.stockpicking.search(domain) - self.assertEquals(len(pickings), 2, - "Incorrect number of pickings created") - picking_out = pickings[1] - moves = picking_out.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_received, 0, - "Wrong qty receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 6, - "Wrong qty outgoing") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 10, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 4, - "Wrong qty outgoing") - picking_out.action_assign() - picking_out.do_new_transfer() - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_received, 0, - "Wrong qty receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty deliver") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to received") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to received") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to delivered") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to received") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to delivered") - self.line.action_rma_done() - self.assertEquals(self.line.state, 'done', - "Wrong State") diff --git a/rma_sale/tests/test_rma_dropship.py b/rma_sale/tests/test_rma_dropship.py deleted file mode 100644 index 9c99a538..00000000 --- a/rma_sale/tests/test_rma_dropship.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from . import test_rma - - -class TestRmaDropship(test_rma.TestRma): - - def setUp(self): - super(TestRmaDropship, self).setUp() - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_droship_id = self._create_rma_from_move( - products2move, 'customer', self.env.ref('base.res_partner_2'), - dropship=True, - supplier_address_id=self.env.ref('base.res_partner_3')) - - def test_dropship(self): - wizard = self.make_supplier_rma.with_context({ - 'active_ids': self.rma_droship_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({}) - res = wizard.make_supplier_rma() - supplier_rma = self.rma.browse(res['res_id']) - for line in supplier_rma.rma_line_ids: - line.action_rma_to_approve() - line.action_rma_approve() - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': supplier_rma.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in supplier_rma.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty outgoing") - - for line in self.rma_droship_id.rma_line_ids: - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 3, - "Wrong qty in supplier rma") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 5, - "Wrong qty in supplier rma") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 2, - "Wrong qty in supplier rma") - for line in self.rma_droship_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") diff --git a/rma_sale/tests/test_rma_sale.py b/rma_sale/tests/test_rma_sale.py new file mode 100644 index 00000000..75a17c9b --- /dev/null +++ b/rma_sale/tests/test_rma_sale.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo.tests import common + + +class TestRmaSale(common.SingleTransactionCase): + + @classmethod + def setUpClass(cls): + super(TestRmaSale, cls).setUpClass() + + cls.rma_obj = cls.env['rma.order'] + cls.rma_line_obj = cls.env['rma.order.line'] + cls.rma_op_obj = cls.env['rma.operation'] + cls.rma_add_sale_wiz = cls.env['rma_add_sale'] + cls.rma_make_sale_wiz = cls.env['rma.order.line.make.sale.order'] + cls.so_obj = cls.env['sale.order'] + cls.sol_obj = cls.env['sale.order.line'] + cls.product_obj = cls.env['product.product'] + cls.partner_obj = cls.env['res.partner'] + + cls.rma_route_cust = cls.env.ref('rma.route_rma_customer') + + # Create customer + customer1 = cls.partner_obj.create({'name': 'Customer 1'}) + + # Create products + cls.product_1 = cls.product_obj.create({ + 'name': 'Test Product 1', + 'type': 'product', + 'list_price': 100.0, + }) + cls.product_2 = cls.product_obj.create({ + 'name': 'Test Product 2', + 'type': 'product', + 'list_price': 150.0, + }) + + # Create SO: + cls.so = cls.so_obj.create({ + 'partner_id': customer1.id, + 'partner_invoice_id': customer1.id, + 'partner_shipping_id': customer1.id, + 'order_line': [ + (0, 0, { + 'name': cls.product_1.name, + 'product_id': cls.product_1.id, + 'product_uom_qty': 20.0, + 'product_uom': cls.product_1.uom_id.id, + 'price_unit': cls.product_1.list_price + }), + (0, 0, { + 'name': cls.product_2.name, + 'product_id': cls.product_2.id, + 'product_uom_qty': 18.0, + 'product_uom': cls.product_2.uom_id.id, + 'price_unit': cls.product_2.list_price + }), + ], + 'pricelist_id': cls.env.ref('product.list0').id, + }) + + # Create RMA group and operation: + cls.rma_group = cls.rma_obj.create({ + 'partner_id': customer1.id, + }) + cls.operation_1 = cls.rma_op_obj.create({ + 'code': 'TEST', + 'name': 'Sale afer receive', + 'type': 'customer', + 'receipt_policy': 'ordered', + 'sale_policy': 'received', + 'in_route_id': cls.rma_route_cust.id, + 'out_route_id': cls.rma_route_cust.id, + }) + cls.operation_2 = cls.rma_op_obj.create({ + 'code': 'TEST', + 'name': 'Receive and Sale', + 'type': 'customer', + 'receipt_policy': 'ordered', + 'sale_policy': 'ordered', + 'in_route_id': cls.rma_route_cust.id, + 'out_route_id': cls.rma_route_cust.id, + }) + + def test_01_add_from_sale_order(self): + """Test wizard to create RMA from Sales Orders.""" + add_sale = self.rma_add_sale_wiz.with_context({ + 'customer': True, + 'active_ids': self.rma_group.id, + 'active_model': 'rma.order', + }).create({ + 'sale_id': self.so.id, + 'sale_line_ids': [(6, 0, self.so.order_line.ids)], + }) + add_sale.add_lines() + self.assertEqual(len(self.rma_group.rma_line_ids), 2) + + def test_02_rma_sale_operation(self): + """Test RMA quantities using sale operations.""" + # Received sale_policy: + rma_1 = self.rma_group.rma_line_ids.filtered( + lambda r: r.product_id == self.product_1) + rma_1.write({ + 'operation_id': self.operation_1.id, + }) + rma_1._onchange_operation_id() + self.assertEqual(rma_1.sale_policy, 'received') + self.assertEqual(rma_1.qty_to_sell, 0.0) + # TODO: receive and check qty_to_sell is 20.0 + # Ordered sale_policy: + rma_2 = self.rma_group.rma_line_ids.filtered( + lambda r: r.product_id == self.product_2) + rma_2.write({ + 'operation_id': self.operation_2.id, + }) + rma_2._onchange_operation_id() + self.assertEqual(rma_2.sale_policy, 'ordered') + self.assertEqual(rma_2.qty_to_sell, 18.0) + + def test_03_rma_create_sale(self): + """Generate a Sales Order from a customer RMA.""" + rma = self.rma_group.rma_line_ids.filtered( + lambda r: r.product_id == self.product_2) + self.assertEqual(rma.sales_count, 0) + self.assertEqual(rma.qty_to_sell, 18.0) + self.assertEqual(rma.qty_sold, 0.0) + make_sale = self.rma_make_sale_wiz.with_context({ + 'customer': True, + 'active_ids': rma.id, + 'active_model': 'rma.order.line', + }).create({ + 'partner_id': rma.partner_id.id, + }) + make_sale.make_sale_order() + self.assertEqual(rma.sales_count, 1) + rma.sale_line_ids.order_id.action_confirm() + self.assertEqual(rma.qty_to_sell, 0.0) + self.assertEqual(rma.qty_sold, 18.0) + + def test_04_fill_rma_from_so_line(self): + """Test filling a RMA (line) from a Sales Order line.""" + so_line = self.so.order_line.filtered( + lambda r: r.product_id == self.product_1) + rma = self.rma_line_obj.new({ + 'partner_id': self.so.partner_id.id, + 'sale_line_id': so_line.id, + }) + self.assertFalse(rma.product_id) + rma._onchange_sale_line_id() + self.assertEqual(rma.product_id, self.product_1) + self.assertEqual(rma.product_qty, 20.0) diff --git a/rma_sale/tests/test_supplier_rma.py b/rma_sale/tests/test_supplier_rma.py deleted file mode 100644 index 64a1e1ff..00000000 --- a/rma_sale/tests/test_supplier_rma.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from . import test_rma - - -class TestSupplierRma(test_rma.TestRma): - - def setUp(self): - super(TestSupplierRma, self).setUp() - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_supplier_id = self._create_rma_from_move( - products2move, 'supplier', self.env.ref('base.res_partner_1'), - dropship=False) - - def test_supplier_rma(self): - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'outgoing', - 'active_id': 1 - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 3, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 2, - "Wrong qty outgoing") - - picking.action_assign() - picking.do_transfer() - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_delivered, 3, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - if line.product_id == self.product_2: - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - if line.product_id == self.product_3: - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - pickings = self.stockpicking.search(domain) - self.assertEquals(len(pickings), 2, - "Incorrect number of pickings created") - picking_out = pickings[1] - moves = picking_out.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 3, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_delivered, 5, - "Wrong qty deliver") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_delivered, 2, - "Wrong qty deliver") - picking_out.action_assign() - picking_out.do_transfer() - for line in self.rma_supplier_id.rma_line_ids[0]: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty receive") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 6, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 10, - "Wrong qty delivered") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 4, - "Wrong qty delivered") - for line in self.rma_supplier_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") diff --git a/rma_sale/views/rma_operation_view.xml b/rma_sale/views/rma_operation_view.xml index cd97ee1d..7b5664b5 100644 --- a/rma_sale/views/rma_operation_view.xml +++ b/rma_sale/views/rma_operation_view.xml @@ -8,7 +8,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/rma_sale/views/rma_order_line_view.xml b/rma_sale/views/rma_order_line_view.xml index d3d4199f..e417c30e 100644 --- a/rma_sale/views/rma_order_line_view.xml +++ b/rma_sale/views/rma_order_line_view.xml @@ -1,6 +1,5 @@ - rma.order.line.form @@ -11,7 +10,7 @@ @@ -19,10 +18,7 @@ + options="{'no_create': True}"/> @@ -31,7 +27,7 @@ - + + groups="sales_team.group_sale_salesman_all_leads"> @@ -66,7 +62,7 @@ - + @@ -82,24 +78,24 @@
-
-
-
- - rma.order.line.supplier.form - rma.order.line - - -
-
-
+ + rma.order.line.select - rma_sale + rma.order.line + + + + + + + + + +
diff --git a/rma_sale/wizards/rma_order_line_make_sale_order.py b/rma_sale/wizards/rma_order_line_make_sale_order.py index dee5fb73..695b4a10 100644 --- a/rma_sale/wizards/rma_order_line_make_sale_order.py +++ b/rma_sale/wizards/rma_order_line_make_sale_order.py @@ -30,7 +30,6 @@ class RmaLineMakeSaleOrder(models.TransientModel): 'product_qty': line.qty_to_sell, 'rma_id': line.rma_id.id, 'out_warehouse_id': line.out_warehouse_id.id, - 'out_route_id': line.out_route_id.id, 'product_uom_id': line.uom_id.id, } @@ -61,7 +60,9 @@ class RmaLineMakeSaleOrder(models.TransientModel): return res @api.model - def _prepare_sale_order(self, out_warehouse, company): + def _prepare_sale_order(self, line): + out_warehouse = line.out_warehouse_id + company = line.company_id if not self.partner_id: raise exceptions.Warning( _('Enter a customer.')) @@ -81,8 +82,8 @@ class RmaLineMakeSaleOrder(models.TransientModel): 'name': product.name, 'order_id': so.id, 'product_id': product.id, + 'route_id': item.line_id.out_route_id.id, 'product_uom': product.uom_po_id.id, - 'route_id': item.out_route_id.id, 'product_uom_qty': item.product_qty, 'rma_line_id': item.line_id.id } @@ -106,8 +107,7 @@ class RmaLineMakeSaleOrder(models.TransientModel): if self.sale_order_id: sale = self.sale_order_id if not sale: - po_data = self._prepare_sale_order(line.out_warehouse_id, - line.company_id) + po_data = self._prepare_sale_order(line) sale = sale_obj.create(po_data) so_line_data = self._prepare_sale_order_line(sale, item) @@ -148,6 +148,3 @@ class RmaLineMakeSaleOrderItem(models.TransientModel): out_warehouse_id = fields.Many2one( comodel_name='stock.warehouse', string='Outbound Warehouse') free_of_charge = fields.Boolean(string='Free of Charge') - out_route_id = fields.Many2one( - comodel_name='stock.location.route', string='Outbound Route', - domain=[('rma_selectable', '=', True)]) diff --git a/rma_sale/wizards/rma_order_line_make_sale_order_view.xml b/rma_sale/wizards/rma_order_line_make_sale_order_view.xml index 395e6275..ae970c80 100644 --- a/rma_sale/wizards/rma_order_line_make_sale_order_view.xml +++ b/rma_sale/wizards/rma_order_line_make_sale_order_view.xml @@ -1,7 +1,7 @@ - + RMA Line Make Sale Order @@ -14,7 +14,7 @@ /> + context="{'partner_id': partner_id}"/> - +
@@ -71,5 +71,5 @@ - + diff --git a/rma_sale_analytic/wizards/rma_order_line_make_sale_order.py b/rma_sale_analytic/wizards/rma_order_line_make_sale_order.py index d7a3990d..7ec362df 100644 --- a/rma_sale_analytic/wizards/rma_order_line_make_sale_order.py +++ b/rma_sale_analytic/wizards/rma_order_line_make_sale_order.py @@ -9,9 +9,9 @@ class RmaLineMakeSaleOrder(models.TransientModel): _inherit = "rma.order.line.make.sale.order" @api.model - def _prepare_sale_order_line(self, so, item): - sale_line = super( - RmaLineMakeSaleOrder, self)._prepare_sale_order_line(so, item) - sale_line.update( - analytic_account_id=item.line_id.analytic_account_id.id) - return sale_line + def _prepare_sale_order(self, line): + res = super( + RmaLineMakeSaleOrder, self)._prepare_sale_order(line) + res.update( + project_id=line.analytic_account_id.id) + return res diff --git a/rma_sale_operating_unit/README.rst b/rma_sale_operating_unit/README.rst new file mode 100644 index 00000000..5324c1e4 --- /dev/null +++ b/rma_sale_operating_unit/README.rst @@ -0,0 +1,28 @@ +.. image:: https://img.shields.io/badge/license-LGPLv3-blue.svg + :target: https://www.gnu.org/licenses/lgpl.html + :alt: License: LGPL-3 + +============================= +RMA Sale with Operating Units +============================= + +This module introduces the following features: + +* Adds the operating unit to the quotation + +Usage +===== + +* No changes + + +Contributors +------------ + +* Aaron Henriquez + + +Maintainer +---------- + +This module is maintained by Eficent. diff --git a/rma_sale_operating_unit/__init__.py b/rma_sale_operating_unit/__init__.py new file mode 100644 index 00000000..5f13e3ea --- /dev/null +++ b/rma_sale_operating_unit/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import wizards diff --git a/rma_sale_operating_unit/__manifest__.py b/rma_sale_operating_unit/__manifest__.py new file mode 100644 index 00000000..7a7a39e7 --- /dev/null +++ b/rma_sale_operating_unit/__manifest__.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +{ + "name": "Analytic Account in RMA sale", + "version": "10.0.1.0.0", + "author": "Eficent," + "Odoo Community Association (OCA)", + "license": "LGPL-3", + "website": "http://www.eficent.com", + "category": "Analytic", + "depends": ["rma_sale_analytic", "rma_operating_unit"], + "data": [ + ], + 'installable': True, +} diff --git a/rma_sale_operating_unit/wizards/__init__.py b/rma_sale_operating_unit/wizards/__init__.py new file mode 100644 index 00000000..7d47d32f --- /dev/null +++ b/rma_sale_operating_unit/wizards/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2018 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from . import rma_order_line_make_sale_order diff --git a/rma_sale_operating_unit/wizards/rma_order_line_make_sale_order.py b/rma_sale_operating_unit/wizards/rma_order_line_make_sale_order.py new file mode 100644 index 00000000..a4400ece --- /dev/null +++ b/rma_sale_operating_unit/wizards/rma_order_line_make_sale_order.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# © 2018 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import models, api + + +class RmaLineMakeSaleOrder(models.TransientModel): + _inherit = "rma.order.line.make.sale.order" + + @api.model + def _prepare_sale_order(self, line): + sale_line = super( + RmaLineMakeSaleOrder, self)._prepare_sale_order(line) + sale_line.update(operating_unit_id=line.operating_unit_id.id) + team = self.env['crm.team'].search( + [('operating_unit_id', '=', line.operating_unit_id.id)], limit=1) + sale_line.update(team_id=team.id) + return sale_line