[FIX] project_account, project_hr_expense: prevent double counting in project upgrade report
Issue Description: There is an issue in the project upgrade report where an expense with a related analytic account appears twice. This occurs once as "Expenses" and again as "Vendor Bills". This problem does not manifest on runbot with all apps installed, indicating a specific configuration issue. The installation of the 'project_purchase' module resolves the issue, as the method "_get_already_included_profitability_invoice_line_ids" within both the "project_purchase" and "project_hr_expense" modules performs a check for an 'expense_sheet_id' in account moves. This check helps to exclude these entries from the profitability items, thereby preventing duplication. However, while this solution is effective, it leads to an undesirable addition of the Purchase app to the client's database, which is not acceptable for the client. Relevant code sections: [project_hr_expense](https://github.com/odoo/odoo/blob/1fbcfdf69b503e77e1a931d23dd47df0daf8b2fe/addons/project_hr_expense/models/project_project.py#L70), [project_purchase](https://github.com/odoo/odoo/blob/1fbcfdf69b503e77e1a931d23dd47df0daf8b2fe/addons/project_purchase/models/project_project.py#L138C15-L138C15). Steps to Reproduce: 1. Install Expense, Accounting, Project, Sales, Employees, Contacts apps on base runbot. 2. Create a service product with 'Prepaid/Fixed Price' and ensure 'Create an Order: Project & Task' is selected. 3. Create and confirm a sales order for the service product created in step 2. 4. In the Expenses app, create an employee-paid expense linked to the sales order's analytic account (e.g., Analytic Distribution: Departments > S00074). 5. Follow the process in the Expenses app by clicking on 'Create Report' > 'Submit to Manager' > 'Approve' > 'Post Journal Entries'. 6. Access Project Updates in the Projects app. 7. Observe that in the project profitability cost section, the same expense is listed twice under different labels: once as "Expenses" and once as "Vendor Bills". Proposed Solution: The proposed solution involves modifying the domain of the `_add_purchase_items` function within the `project_account` module, specifically at [this code section](https://github.com/odoo/odoo/blob/763f88e2d45cb7ba107db135eecd0365ba2b8c8b/addons/project_account/models/project_project.py#L14). The enhancement would entail adding a condition to the function's domain to exclude any IDs that are already present in the profitability report. This approach will efficiently prevent the double counting of expenses, ensuring that each expense is represented only once in the project profitability report, thereby maintaining accuracy and consistency in financial tracking. This solution focuses on enhancing the existing functionality with a targeted and efficient modification, ensuring minimal impact on other system components while effectively addressing the issue. opw-3522293 closes odoo/odoo#149623 X-original-commit: 0902d57dd1653018d6ae72554b39e4e01fa4d6d7 Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com> Signed-off-by: Ilya Rudy (ilru) <ilru@odoo.com>
This commit is contained in:
@@ -17,10 +17,12 @@ class Project(models.Model):
|
||||
self._get_costs_items_from_purchase(domain, profitability_items, with_action=with_action)
|
||||
|
||||
def _get_add_purchase_items_domain(self):
|
||||
purchase_order_line_invoice_line_ids = self._get_already_included_profitability_invoice_line_ids()
|
||||
return [
|
||||
('move_type', 'in', ['in_invoice', 'in_refund']),
|
||||
('parent_state', 'in', ['draft', 'posted']),
|
||||
('price_subtotal', '>', 0)
|
||||
('price_subtotal', '>', 0),
|
||||
('id', 'not in', purchase_order_line_invoice_line_ids),
|
||||
]
|
||||
|
||||
def _get_costs_items_from_purchase(self, domain, profitability_items, with_action=True):
|
||||
|
||||
@@ -125,3 +125,41 @@ class TestProjectHrExpenseProfitability(TestProjectProfitabilityCommon, TestProj
|
||||
self.project_profitability_items_empty,
|
||||
'No data should be found since the sheets are not approved yet.',
|
||||
)
|
||||
|
||||
def test_project_profitability_after_expense_sheet_actions(self):
|
||||
expense = self.env["hr.expense"].create(
|
||||
{
|
||||
"name": "Car Travel Expenses",
|
||||
"employee_id": self.expense_employee.id,
|
||||
"product_id": self.product_c.id,
|
||||
"total_amount": 50.00,
|
||||
"company_id": self.project.company_id.id,
|
||||
"analytic_distribution": {self.project.analytic_account_id.id: 100},
|
||||
}
|
||||
)
|
||||
expense_sheet = self.env["hr.expense.sheet"].create(
|
||||
{
|
||||
"name": "Expense for Jannette",
|
||||
"employee_id": self.expense_employee.id,
|
||||
"expense_line_ids": expense,
|
||||
}
|
||||
)
|
||||
|
||||
sequence_per_invoice_type = self.project._get_profitability_sequence_per_invoice_type()
|
||||
self.assertIn('expenses', sequence_per_invoice_type)
|
||||
expense_sequence = sequence_per_invoice_type['expenses']
|
||||
|
||||
expense_sheet.action_submit_sheet()
|
||||
expense_sheet.action_approve_expense_sheets()
|
||||
expense_sheet.action_sheet_move_create()
|
||||
|
||||
self.assertDictEqual(
|
||||
self.project._get_profitability_items(False),
|
||||
{
|
||||
'costs': {
|
||||
'data': [{'id': 'expenses', 'sequence': expense_sequence, 'to_bill': 0.0, 'billed': -expense.untaxed_amount_currency}],
|
||||
'total': {'to_bill': 0.0, 'billed': -expense.untaxed_amount_currency},
|
||||
},
|
||||
'revenues': {'data': [], 'total': {'to_invoice': 0.0, 'invoiced': 0.0}},
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user