[FIX] sale{_expense,_expense_margin}: Fix re-invoicing of expenses

This deals with a bug when an expense re-invoiced
with a 'sale_price' expense_policy and 'delivery' invoice_policy

Current bad behaviour:
- When re-invoicing another expense matching the first one's
  price_unit and product the quantities aren't updated properly
- Furthermore, reversing the original move doesn't impact the sale order
- Resetting the expense sheet to draft neither

New correct behaviour:
- When re-invoicing another expense matching the first one's
  they aren't grouped together on the same line, allowing to update
  and reverse the lines independently
- Reversing the original move sets its corresponding sale order line
  quantity and delivered quantity to 0
- Resetting the expense sheet to draft does the same
- Resetting the original move does the same
- Adds clarity to the sale_stock error message, so it's understandable
  from the expense view

task-3458826

Part-of: odoo/odoo#147123
This commit is contained in:
Julien Alardot (jual)
2023-12-21 17:25:01 +00:00
parent 7c577fd34d
commit de027b6e2b
8 changed files with 273 additions and 74 deletions
+8 -6
View File
@@ -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()
+7 -2
View File
@@ -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`
-1
View File
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import account_move_line
@@ -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
+49 -1
View File
@@ -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:
+189 -62
View File
@@ -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):
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="hr_expense_sheet_view_form" model="ir.ui.view">
<field name="name">hr.expense.sheet.view.form.inherit.sale.expense</field>
<field name="model">hr.expense.sheet</field>
@@ -72,5 +72,4 @@
<field name="domain">[('sale_order_id', '=', active_id)]</field>
<field name="context">{'default_sale_order_id': active_id}</field>
</record>
</odoo>