diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index de488aebcbf..9ee30acbb77 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -4305,6 +4305,31 @@ class TestSalesInvoice(IntegrationTestCase): doc = frappe.get_doc("Project", project.name) self.assertEqual(doc.total_billed_amount, si.grand_total) + def test_total_billed_amount_with_different_projects(self): + # This test case is for checking the scenario where project is set at document level and for **some** child items only, not all + from copy import copy + + si = create_sales_invoice(do_not_submit=True) + + project = frappe.new_doc("Project") + project.company = "_Test Company" + project.project_name = "Test Total Billed Amount" + project.save() + + si.project = project.name + si.items.append(copy(si.items[0])) + si.items.append(copy(si.items[0])) + si.items[0].project = project.name + si.items[1].project = project.name + # Not setting project on last item + si.items[1].insert() + si.items[2].insert() + si.submit() + + project.reload() + self.assertIsNone(si.items[2].project) + self.assertEqual(project.total_billed_amount, 300) + def test_pos_returns_with_party_account_currency(self): from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_sales_return diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 5706edcda63..959b34f77a3 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -322,17 +322,31 @@ class Project(Document): self.total_sales_amount = total_sales_amount and total_sales_amount[0][0] or 0 def update_billed_amount(self): - # nosemgrep + self.total_billed_amount = self.get_billed_amount_from_parent() + self.get_billed_amount_from_child() + + def get_billed_amount_from_parent(self): total_billed_amount = frappe.db.sql( """select sum(base_net_amount) - from `tabSales Invoice Item` si_item, `tabSales Invoice` si - where si_item.parent = si.name - and if(si_item.project, si_item.project, si.project) = %s - and si.docstatus=1""", + from `tabSales Invoice` si join `tabSales Invoice Item` si_item on si_item.parent = si.name + where si_item.project is null + and si.project is not null + and si.project = %s + and si.docstatus = 1""", self.name, ) - self.total_billed_amount = total_billed_amount and total_billed_amount[0][0] or 0 + return total_billed_amount and total_billed_amount[0][0] or 0 + + def get_billed_amount_from_child(self): + total_billed_amount = frappe.db.sql( + """select sum(base_net_amount) + from `tabSales Invoice Item` + where project = %s + and docstatus = 1""", + self.name, + ) + + return total_billed_amount and total_billed_amount[0][0] or 0 def after_rename(self, old_name, new_name, merge=False): if old_name == self.copied_from: