diff --git a/addons/hr_expense/models/hr_expense_sheet.py b/addons/hr_expense/models/hr_expense_sheet.py index ecd130d16c0..a94a76e1420 100644 --- a/addons/hr_expense/models/hr_expense_sheet.py +++ b/addons/hr_expense/models/hr_expense_sheet.py @@ -684,13 +684,15 @@ class HrExpenseSheet(models.Model): return moves def _do_reverse_moves(self): - draft_moves = self.account_move_ids.filtered(lambda account_move: account_move.state == 'draft') - draft_moves.unlink() - moves = self.account_move_ids - draft_moves - moves._reverse_moves( - default_values_list=[{'invoice_date': fields.Date.context_today(move), 'ref': False} for move in moves], - cancel=True, + self = self.with_context(clean_context(self.env.context)) + moves = self.account_move_ids + draft_moves = moves.filtered(lambda m: m.state == 'draft') + non_draft_moves = moves - draft_moves + non_draft_moves._reverse_moves( + default_values_list=[{'invoice_date': fields.Date.context_today(move), 'ref': False} for move in non_draft_moves], + cancel=True ) + draft_moves.unlink() def _prepare_bills_vals(self): self.ensure_one() diff --git a/addons/sale/models/account_move_line.py b/addons/sale/models/account_move_line.py index 012c0b9d5c8..3c45dc1ffbc 100644 --- a/addons/sale/models/account_move_line.py +++ b/addons/sale/models/account_move_line.py @@ -37,7 +37,7 @@ class AccountMoveLine(models.Model): move_to_reinvoice |= move_line # insert the sale line in the create values of the analytic entries - if move_to_reinvoice: + if move_to_reinvoice.filtered(lambda aml: not aml.move_id.reversed_entry_id): # only if the move line is not a reversal one map_sale_line_per_move = move_to_reinvoice._sale_create_reinvoice_sale_line() for values in values_list: sale_line = map_sale_line_per_move.get(values.get('move_line_id')) @@ -103,7 +103,12 @@ class AccountMoveLine(models.Model): # find the existing sale.line or keep its creation values to process this in batch sale_line = None - if move_line.product_id.expense_policy == 'sales_price' and move_line.product_id.invoice_policy == 'delivery': # for those case only, we can try to reuse one + if ( + move_line.product_id.expense_policy == 'sales_price' + and move_line.product_id.invoice_policy == 'delivery' + and not self.env.context.get('force_split_lines') + ): + # for those case only, we can try to reuse one map_entry_key = (sale_order.id, move_line.product_id.id, price) # cache entry to limit the call to search sale_line = existing_sale_line_cache.get(map_entry_key) if sale_line: # already search, so reuse it. sale_line can be sale.order.line record or index of a "to create values" in `sale_line_values_to_create` diff --git a/addons/sale_expense/models/__init__.py b/addons/sale_expense/models/__init__.py index 8a3abae39bd..06423a29399 100644 --- a/addons/sale_expense/models/__init__.py +++ b/addons/sale_expense/models/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import account_move_line diff --git a/addons/sale_expense/models/account_move_line.py b/addons/sale_expense/models/account_move_line.py index 6006a26667a..1218618aea2 100644 --- a/addons/sale_expense/models/account_move_line.py +++ b/addons/sale_expense/models/account_move_line.py @@ -35,3 +35,23 @@ class AccountMoveLine(models.Model): if self.expense_id: res['product_uom_qty'] = self.expense_id.quantity return res + + def _sale_create_reinvoice_sale_line(self): + expensed_lines = self.filtered('expense_id') + res = super(AccountMoveLine, self - expensed_lines)._sale_create_reinvoice_sale_line() + res.update(super(AccountMoveLine, expensed_lines.with_context({'force_split_lines': True}))._sale_create_reinvoice_sale_line()) + return res + + +class AccountMove(models.Model): + _inherit = 'account.move' + + def _reverse_moves(self, default_values_list=None, cancel=False): + self.expense_sheet_id._sale_expense_reset_sol_quantities() + res = super()._reverse_moves(default_values_list, cancel) + return res + + def button_draft(self): + res = super().button_draft() + self.expense_sheet_id._sale_expense_reset_sol_quantities() + return res diff --git a/addons/sale_expense/models/hr_expense_sheet.py b/addons/sale_expense/models/hr_expense_sheet.py index 768373dbf59..8df9a2d2a98 100644 --- a/addons/sale_expense/models/hr_expense_sheet.py +++ b/addons/sale_expense/models/hr_expense_sheet.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import fields, models, _ @@ -13,6 +12,55 @@ class HrExpenseSheet(models.Model): for sheet in self: sheet.sale_order_count = len(sheet.expense_line_ids.sale_order_id) + def _get_sale_order_lines(self): + """ + This method is used to try to find the sale order lines created by expense sheets. + + :return: sale.order.line + :rtype: recordset + """ + expensed_amls = self.account_move_ids.line_ids.filtered(lambda aml: aml.expense_id.sale_order_id and aml.balance >= 0) + if not expensed_amls: + return self.env['sale.order.line'] + aml_to_so_map = expensed_amls._sale_determine_order() + sale_order_ids = tuple(set(aml_to_so_map[aml.id].id for aml in expensed_amls)) + aml_sol_unit_price_map = dict(expensed_amls.mapped(lambda aml: (aml.id, aml._sale_get_invoice_price(aml_to_so_map[aml.id])))) + product_ids = tuple(expensed_amls.product_id.ids) + quantities = tuple(expensed_amls.mapped('quantity')) + names = tuple(expensed_amls.mapped('name')) + self.env['sale.order.line'].flush_model(['order_id', 'product_id', 'product_uom_qty', 'price_unit', 'name']) + query = """ + SELECT + DISTINCT ON (sol.order_id, sol.product_id, sol.product_uom_qty, sol.price_unit, sol.name) + sol.order_id, sol.product_id, sol.product_uom_qty, sol.price_unit, sol.name, sol.id + FROM sale_order_line AS sol + WHERE sol.is_expense = TRUE + AND sol.order_id IN %s + AND sol.product_id IN %s + AND sol.product_uom_qty IN %s + AND sol.price_unit IN %s + AND sol.name IN %s + ORDER BY sol.order_id, sol.product_id, sol.product_uom_qty, sol.price_unit, sol.name + """ + self.env.cr.execute(query, (sale_order_ids, product_ids, quantities, tuple(set(aml_sol_unit_price_map.values())), names)) + potential_sols_map = { + (row['order_id'], row['product_id'], row['product_uom_qty'], row['price_unit'], row['name']): row['id'] + for row in self.env.cr.dictfetchall() + } + expensed_amls_keys = set(expensed_amls.mapped( + lambda aml: (aml.expense_id.sale_order_id.id, aml.product_id.id, aml.quantity, aml_sol_unit_price_map[aml.id], aml.name) + )) + return self.env['sale.order.line'].browse(sol_id for key, sol_id in potential_sols_map.items() if key in expensed_amls_keys) + + def _sale_expense_reset_sol_quantities(self): + sale_order_lines = self._get_sale_order_lines() + sale_order_lines.write({'qty_delivered': 0.0, 'product_uom_qty': 0.0}) + + def action_reset_expense_sheets(self): + super().action_reset_expense_sheets() + self._sale_expense_reset_sol_quantities() + return True + def action_open_sale_orders(self): self.ensure_one() if self.sale_order_count == 1: diff --git a/addons/sale_expense/tests/test_reinvoice.py b/addons/sale_expense/tests/test_reinvoice.py index cf34306b4a5..57f62630c55 100644 --- a/addons/sale_expense/tests/test_reinvoice.py +++ b/addons/sale_expense/tests/test_reinvoice.py @@ -9,72 +9,106 @@ from odoo.tests import tagged @tagged('-at_install', 'post_install') class TestReInvoice(TestExpenseCommon, TestSaleCommon): - def test_expenses_reinvoice(self): - (self.company_data['product_order_sales_price'] + self.company_data['product_delivery_sales_price']).write({ - 'can_be_expensed': True, + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + cls.company_data.update({ + 'service_order_sales_price': cls.env['product.product'].with_company(cls.company_data['company']).create({ + 'name': 'service_order_sales_price', + 'categ_id': cls.company_data['product_category'].id, + 'standard_price': 235.0, + 'list_price': 280.0, + 'type': 'service', + 'weight': 0.01, + 'uom_id': cls.env.ref('uom.product_uom_unit').id, + 'uom_po_id': cls.env.ref('uom.product_uom_unit').id, + 'default_code': 'FURN_9999', + 'invoice_policy': 'order', + 'expense_policy': 'sales_price', + 'taxes_id': [Command.set([])], + 'supplier_taxes_id': [Command.set([])], + 'can_be_expensed': True, + }), + 'service_delivery_sales_price': cls.env['product.product'].with_company(cls.company_data['company']).create({ + 'name': 'service_order_sales_price', + 'categ_id': cls.company_data['product_category'].id, + 'standard_price': 235.0, + 'list_price': 280.0, + 'type': 'service', + 'weight': 0.01, + 'uom_id': cls.env.ref('uom.product_uom_unit').id, + 'uom_po_id': cls.env.ref('uom.product_uom_unit').id, + 'default_code': 'FURN_9999', + 'invoice_policy': 'order', + 'expense_policy': 'sales_price', + 'taxes_id': [Command.set([])], + 'supplier_taxes_id': [Command.set([])], + 'can_be_expensed': True, + }), }) + def test_expenses_reinvoice(self): + """ + Test that expenses are re-invoiced correctly and that the quantity is updated when it has to. + - Lines are never grouped together (even if reinvoced at sale price and with a re-invoice delivered policy) + - When posting an expense, it creates the corresponding sol with the expense quantity + - The quantities ordered and delivered are reset to 0 when: + - the expense sheet is unposted + - the expense move is reversed + - the expense move is reset to draft + """ # create SO line and confirm SO (with only one line) sale_order = self.env['sale.order'].with_context(mail_notrack=True, mail_create_nolog=True).create({ 'partner_id': self.partner_a.id, 'partner_invoice_id': self.partner_a.id, 'partner_shipping_id': self.partner_a.id, 'order_line': [Command.create({ - 'name': self.company_data['product_order_sales_price'].name, + 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price', + # Using the same name as one of the expense 'product_id': self.company_data['product_order_sales_price'].id, - 'product_uom_qty': 2.0, - 'price_unit': 1000.0, + 'product_uom_qty': 3.0, + 'price_unit': self.company_data['product_order_sales_price'].standard_price, })], }) sale_order.action_confirm() expense_sheet = self.env['hr.expense.sheet'].create({ - 'name': 'First Expense for employee', + 'name': 'Reset expense test', 'employee_id': self.expense_employee.id, 'journal_id': self.company_data['default_journal_purchase'].id, 'accounting_date': '2017-01-01', 'expense_line_ids': [ Command.create({ - 'name': 'expense_1', + 'name': 'expense_1 invoicing=order, expense=sales_price', 'date': '2016-01-01', - 'product_id': self.company_data['product_order_sales_price'].id, - 'total_amount_currency': self.company_data['product_order_sales_price'].list_price, + 'product_id': self.company_data['service_order_sales_price'].id, + 'quantity': 1, 'analytic_distribution': {self.analytic_account_1.id: 100}, 'employee_id': self.expense_employee.id, 'sale_order_id': sale_order.id, }), Command.create({ - 'name': 'expense_2', - 'date': '2016-01-01', - 'product_id': self.company_data['product_delivery_sales_price'].id, - 'total_amount_currency': self.company_data['product_delivery_sales_price'].list_price, + 'name': 'expense_2 invoicing=order, expense=sales_price', + 'date': '2016-01-02', + 'product_id': self.company_data['service_order_sales_price'].id, + 'quantity': 2, + 'employee_id': self.expense_employee.id, + 'sale_order_id': sale_order.id, + }), + Command.create({ + 'name': 'expense_3 invoicing=delivery, expense=sales_price', + 'date': '2016-01-03', + 'product_id': self.company_data['service_delivery_sales_price'].id, + 'quantity': 3, 'analytic_distribution': {self.analytic_account_1.id: 100}, 'employee_id': self.expense_employee.id, 'sale_order_id': sale_order.id, }), Command.create({ - 'name': 'expense_3', - 'date': '2016-01-01', - 'product_id': self.company_data['product_order_sales_price'].id, - 'total_amount_currency': self.company_data['product_order_sales_price'].list_price, - 'analytic_distribution': {self.analytic_account_1.id: 100}, - 'employee_id': self.expense_employee.id, - 'sale_order_id': sale_order.id, - }), - Command.create({ - 'name': 'expense_4', - 'date': '2016-01-01', - 'product_id': self.company_data['product_delivery_sales_price'].id, - 'total_amount_currency': self.company_data['product_delivery_sales_price'].list_price, - 'analytic_distribution': {self.analytic_account_1.id: 100}, - 'employee_id': self.expense_employee.id, - 'sale_order_id': sale_order.id, - }), - Command.create({ - 'name': 'expense_5', - 'date': '2016-01-01', - 'product_id': self.company_data['product_delivery_sales_price'].id, - 'total_amount_currency': self.company_data['product_delivery_sales_price'].list_price, + 'name': 'expense_4 invoicing=delivery, expense=sales_price', + 'date': '2016-01-03', + 'product_id': self.company_data['service_delivery_sales_price'].id, + 'quantity': 4, 'analytic_distribution': {self.analytic_account_1.id: 100}, 'employee_id': self.expense_employee.id, 'sale_order_id': sale_order.id, @@ -85,35 +119,128 @@ class TestReInvoice(TestExpenseCommon, TestSaleCommon): expense_sheet.action_approve_expense_sheets() expense_sheet.action_sheet_move_create() + # We also need to test "duplicates" aka very similar expenses + expense_sheet_copy = self.env['hr.expense.sheet'].create({ + 'name': 'Reset expense test copy', + 'employee_id': self.expense_employee.id, + 'journal_id': self.company_data['default_journal_purchase'].id, + 'accounting_date': '2017-01-01', + 'expense_line_ids': [ + Command.create({ + 'name': 'expense_3 invoicing=delivery, expense=sales_price copy', + 'date': '2016-01-03', + 'product_id': self.company_data['service_delivery_sales_price'].id, + 'quantity': 3, + 'analytic_distribution': {self.analytic_account_1.id: 100}, + 'employee_id': self.expense_employee.id, + 'sale_order_id': sale_order.id, + }), + Command.create({ + 'name': 'expense_4 invoicing=delivery, expense=sales_price copy', + 'date': '2016-01-03', + 'product_id': self.company_data['service_delivery_sales_price'].id, + 'quantity': 4, + 'analytic_distribution': {self.analytic_account_1.id: 100}, + 'employee_id': self.expense_employee.id, + 'sale_order_id': sale_order.id, + }), + ], + }) + + action_data = expense_sheet_copy.action_approve_expense_sheets() + duplicate_wizard = self.env['hr.expense.approve.duplicate'].with_context(action_data['context']).create({}) + duplicate_wizard.action_approve() + expense_sheet_copy.action_sheet_move_create() + #pylint: disable=bad-whitespace self.assertRecordValues(sale_order.order_line, [ - # Original SO line: - { - 'qty_delivered': 0.0, - 'product_uom_qty': 2.0, - 'is_expense': False, - }, - # Expense lines: - { - 'qty_delivered': 1.0, - 'product_uom_qty': 1.0, - 'is_expense': True, - }, - { - 'qty_delivered': 3.0, - 'product_uom_qty': 1.0, - 'is_expense': True, - }, - { - 'qty_delivered': 1.0, - 'product_uom_qty': 1.0, - 'is_expense': True, - }, + {'qty_delivered': 0.0, 'product_uom_qty': 3.0, 'is_expense': False, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 1.0, 'product_uom_qty': 1.0, 'is_expense': True, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 2.0, 'product_uom_qty': 2.0, 'is_expense': True, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 3.0, 'product_uom_qty': 3.0, 'is_expense': True, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 4.0, 'product_uom_qty': 4.0, 'is_expense': True, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 3.0, 'product_uom_qty': 3.0, 'is_expense': True, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 4.0, 'product_uom_qty': 4.0, 'is_expense': True, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price copy'}, ]) - self.assertRecordValues(sale_order.order_line[1:], [ - {'qty_delivered_method': 'analytic'}, - {'qty_delivered_method': 'analytic'}, - {'qty_delivered_method': 'analytic'}, + expense_sheet.action_reset_expense_sheets() # Lines [0-4] quantities are set to 0 + self.assertRecordValues(sale_order.order_line, [ + {'qty_delivered': 0.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 3.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 4.0, 'product_uom_qty': 4.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price copy'}, + ]) + + expense_sheet.action_approve_expense_sheets() + expense_sheet.action_sheet_move_create() # Lines [1-4] are still at 0 but new lines are created (stable limitation) + + self.assertRecordValues(sale_order.order_line, [ + {'qty_delivered': 0.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 3.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 4.0, 'product_uom_qty': 4.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 1.0, 'product_uom_qty': 1.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 2.0, 'product_uom_qty': 2.0, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 3.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 4.0, 'product_uom_qty': 4.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + ]) + + expense_sheet.account_move_ids.button_draft() # Lines [7-11] quantities are set to 0 + self.assertRecordValues(sale_order.order_line, [ + {'qty_delivered': 0.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 3.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 4.0, 'product_uom_qty': 4.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + ]) + + expense_sheet.account_move_ids.action_post() # Lines [7-11] are still at 0 but new lines are created (stable limitation) + self.assertRecordValues(sale_order.order_line, [ + {'qty_delivered': 0.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 3.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 4.0, 'product_uom_qty': 4.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 1.0, 'product_uom_qty': 1.0, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 2.0, 'product_uom_qty': 2.0, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 3.0, 'product_uom_qty': 3.0, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 4.0, 'product_uom_qty': 4.0, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + ]) + + expense_sheet.account_move_ids._reverse_moves() # Lines [7-11] quantities are set to 0 + self.assertRecordValues(sale_order.order_line, [ + {'qty_delivered': 0.0, 'product_uom_qty': 3.0, 'is_expense': False, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 3.0, 'product_uom_qty': 3.0, 'is_expense': True, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 4.0, 'product_uom_qty': 4.0, 'is_expense': True, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price copy'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_1 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_2 invoicing=order, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_3 invoicing=delivery, expense=sales_price'}, + {'qty_delivered': 0.0, 'product_uom_qty': 0.0, 'is_expense': True, 'name': 'expense_employee: expense_4 invoicing=delivery, expense=sales_price'}, ]) def test_expenses_reinvoice_analytic_distribution(self): diff --git a/addons/sale_expense/views/hr_expense_sheet_views.xml b/addons/sale_expense/views/hr_expense_sheet_views.xml index b5021366acb..acfacc25a83 100644 --- a/addons/sale_expense/views/hr_expense_sheet_views.xml +++ b/addons/sale_expense/views/hr_expense_sheet_views.xml @@ -1,6 +1,5 @@ - hr.expense.sheet.view.form.inherit.sale.expense hr.expense.sheet diff --git a/addons/sale_expense/views/hr_expense_views.xml b/addons/sale_expense/views/hr_expense_views.xml index ac1326d8d5a..8d94a080ce0 100644 --- a/addons/sale_expense/views/hr_expense_views.xml +++ b/addons/sale_expense/views/hr_expense_views.xml @@ -72,5 +72,4 @@ [('sale_order_id', '=', active_id)] {'default_sale_order_id': active_id} -