mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-19 09:35:03 +00:00
* fix: Calculate gross margin on update of project costing from invoices (#43876)
* fix: Calculate gross margin on update of project costing from invoices
* chore: linter issues
(cherry picked from commit 0bba6442c0)
# Conflicts:
# erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
* fix: merge conflict
---------
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
This commit is contained in:
@@ -1593,7 +1593,11 @@ class PurchaseInvoice(BuyingController):
|
||||
for proj, value in projects.items():
|
||||
res = frappe.qb.from_(pj).select(pj.total_purchase_cost).where(pj.name == proj).for_update().run()
|
||||
current_purchase_cost = res and res[0][0] or 0
|
||||
frappe.db.set_value("Project", proj, "total_purchase_cost", current_purchase_cost + value)
|
||||
# frappe.db.set_value("Project", proj, "total_purchase_cost", current_purchase_cost + value)
|
||||
project_doc = frappe.get_doc("Project", proj)
|
||||
project_doc.total_purchase_cost = current_purchase_cost + value
|
||||
project_doc.calculate_gross_margin()
|
||||
project_doc.db_update()
|
||||
|
||||
def validate_supplier_invoice(self):
|
||||
if self.bill_date:
|
||||
|
||||
@@ -505,7 +505,8 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Project",
|
||||
"options": "Project",
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
@@ -974,7 +975,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-07-19 12:12:42.449298",
|
||||
"modified": "2024-10-28 15:06:19.246141",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
|
||||
@@ -1734,9 +1734,11 @@ class SalesInvoice(SellingController):
|
||||
)
|
||||
|
||||
def update_project(self):
|
||||
if self.project:
|
||||
project = frappe.get_doc("Project", self.project)
|
||||
unique_projects = list(set([d.project for d in self.get("items") if d.project]))
|
||||
for p in unique_projects:
|
||||
project = frappe.get_doc("Project", p)
|
||||
project.update_billed_amount()
|
||||
project.calculate_gross_margin()
|
||||
project.db_update()
|
||||
|
||||
def verify_payment_amount_is_positive(self):
|
||||
|
||||
@@ -812,7 +812,8 @@
|
||||
"fieldname": "project",
|
||||
"fieldtype": "Link",
|
||||
"label": "Project",
|
||||
"options": "Project"
|
||||
"options": "Project",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:parent.update_stock == 1",
|
||||
@@ -927,7 +928,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-05-23 16:36:18.970862",
|
||||
"modified": "2024-10-28 15:06:40.980995",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
||||
@@ -93,14 +93,14 @@ class Project(Document):
|
||||
|
||||
def validate(self):
|
||||
if not self.is_new():
|
||||
self.copy_from_template()
|
||||
self.copy_from_template() # nosemgrep
|
||||
self.send_welcome_email()
|
||||
self.update_costing()
|
||||
self.update_percent_complete()
|
||||
self.validate_from_to_dates("expected_start_date", "expected_end_date")
|
||||
self.validate_from_to_dates("actual_start_date", "actual_end_date")
|
||||
|
||||
def copy_from_template(self):
|
||||
def copy_from_template(self): # nosemgrep
|
||||
"""
|
||||
Copy tasks from template
|
||||
"""
|
||||
@@ -205,7 +205,7 @@ class Project(Document):
|
||||
self.db_update()
|
||||
|
||||
def after_insert(self):
|
||||
self.copy_from_template()
|
||||
self.copy_from_template() # nosemgrep
|
||||
if self.sales_order:
|
||||
frappe.db.set_value("Sales Order", self.sales_order, "project", self.name)
|
||||
|
||||
@@ -324,9 +324,13 @@ class Project(Document):
|
||||
self.total_sales_amount = total_sales_amount and total_sales_amount[0][0] or 0
|
||||
|
||||
def update_billed_amount(self):
|
||||
# nosemgrep
|
||||
total_billed_amount = frappe.db.sql(
|
||||
"""select sum(base_net_total)
|
||||
from `tabSales Invoice` where project = %s and docstatus=1""",
|
||||
"""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""",
|
||||
self.name,
|
||||
)
|
||||
|
||||
@@ -676,31 +680,8 @@ def update_project_sales_billing():
|
||||
return
|
||||
|
||||
# Else simply fallback to Daily
|
||||
exists_query = "(SELECT 1 from `tab{doctype}` where docstatus = 1 and project = `tabProject`.name)"
|
||||
project_map = {}
|
||||
for project_details in frappe.db.sql(
|
||||
"""
|
||||
SELECT name, 1 as order_exists, null as invoice_exists from `tabProject` where
|
||||
exists {order_exists}
|
||||
union
|
||||
SELECT name, null as order_exists, 1 as invoice_exists from `tabProject` where
|
||||
exists {invoice_exists}
|
||||
""".format(
|
||||
order_exists=exists_query.format(doctype="Sales Order"),
|
||||
invoice_exists=exists_query.format(doctype="Sales Invoice"),
|
||||
),
|
||||
as_dict=True,
|
||||
):
|
||||
project = project_map.setdefault(
|
||||
project_details.name, frappe.get_doc("Project", project_details.name)
|
||||
)
|
||||
if project_details.order_exists:
|
||||
project.update_sales_amount()
|
||||
if project_details.invoice_exists:
|
||||
project.update_billed_amount()
|
||||
|
||||
for project in project_map.values():
|
||||
project.save()
|
||||
for project in frappe.get_all("Project", filters={"status": ["!=", "Cancelled"]}):
|
||||
frappe.get_doc("Project", project.name).save()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@@ -751,7 +732,6 @@ def get_users_email(doc):
|
||||
def calculate_total_purchase_cost(project: str | None = None):
|
||||
if project:
|
||||
pitem = qb.DocType("Purchase Invoice Item")
|
||||
frappe.qb.DocType("Purchase Invoice Item")
|
||||
total_purchase_cost = (
|
||||
qb.from_(pitem)
|
||||
.select(Sum(pitem.base_net_amount))
|
||||
|
||||
Reference in New Issue
Block a user