Merge pull request #38319 from frappe/mergify/bp/version-15-hotfix/pr-38298
perf: optimize update_purchase_cost method (backport #38298)
This commit is contained in:
commit
2d6b2f7ae3
@ -525,7 +525,11 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if self.update_stock == 1:
|
if self.update_stock == 1:
|
||||||
self.repost_future_sle_and_gle()
|
self.repost_future_sle_and_gle()
|
||||||
|
|
||||||
self.update_project()
|
if (
|
||||||
|
frappe.db.get_single_value("Buying Settings", "project_update_frequency") == "Each Transaction"
|
||||||
|
):
|
||||||
|
self.update_project()
|
||||||
|
|
||||||
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
||||||
self.update_advance_tax_references()
|
self.update_advance_tax_references()
|
||||||
|
|
||||||
@ -1260,7 +1264,10 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if self.update_stock == 1:
|
if self.update_stock == 1:
|
||||||
self.repost_future_sle_and_gle()
|
self.repost_future_sle_and_gle()
|
||||||
|
|
||||||
self.update_project()
|
if (
|
||||||
|
frappe.db.get_single_value("Buying Settings", "project_update_frequency") == "Each Transaction"
|
||||||
|
):
|
||||||
|
self.update_project()
|
||||||
self.db_set("status", "Cancelled")
|
self.db_set("status", "Cancelled")
|
||||||
|
|
||||||
unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
||||||
@ -1279,13 +1286,21 @@ class PurchaseInvoice(BuyingController):
|
|||||||
self.update_advance_tax_references(cancel=1)
|
self.update_advance_tax_references(cancel=1)
|
||||||
|
|
||||||
def update_project(self):
|
def update_project(self):
|
||||||
project_list = []
|
projects = frappe._dict()
|
||||||
for d in self.items:
|
for d in self.items:
|
||||||
if d.project and d.project not in project_list:
|
if d.project:
|
||||||
project = frappe.get_doc("Project", d.project)
|
if self.docstatus == 1:
|
||||||
project.update_purchase_costing()
|
projects[d.project] = projects.get(d.project, 0) + d.base_net_amount
|
||||||
project.db_update()
|
elif self.docstatus == 2:
|
||||||
project_list.append(d.project)
|
projects[d.project] = projects.get(d.project, 0) - d.base_net_amount
|
||||||
|
|
||||||
|
pj = frappe.qb.DocType("Project")
|
||||||
|
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)
|
||||||
|
|
||||||
def validate_supplier_invoice(self):
|
def validate_supplier_invoice(self):
|
||||||
if self.bill_date:
|
if self.bill_date:
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"po_required",
|
"po_required",
|
||||||
"pr_required",
|
"pr_required",
|
||||||
"blanket_order_allowance",
|
"blanket_order_allowance",
|
||||||
|
"project_update_frequency",
|
||||||
"column_break_12",
|
"column_break_12",
|
||||||
"maintain_same_rate",
|
"maintain_same_rate",
|
||||||
"set_landed_cost_based_on_purchase_invoice_rate",
|
"set_landed_cost_based_on_purchase_invoice_rate",
|
||||||
@ -172,6 +173,14 @@
|
|||||||
"fieldname": "blanket_order_allowance",
|
"fieldname": "blanket_order_allowance",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Blanket Order Allowance (%)"
|
"label": "Blanket Order Allowance (%)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Each Transaction",
|
||||||
|
"description": "How often should Project be updated of Total Purchase Cost ?",
|
||||||
|
"fieldname": "project_update_frequency",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Update frequency of Project",
|
||||||
|
"options": "Each Transaction\nManual"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-cog",
|
"icon": "fa fa-cog",
|
||||||
@ -179,7 +188,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-10-25 14:03:32.520418",
|
"modified": "2023-11-24 10:55:51.287327",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Buying Settings",
|
"name": "Buying Settings",
|
||||||
|
@ -351,5 +351,6 @@ erpnext.patches.v15_0.rename_depreciation_amount_based_on_num_days_in_month_to_d
|
|||||||
erpnext.patches.v15_0.set_reserved_stock_in_bin
|
erpnext.patches.v15_0.set_reserved_stock_in_bin
|
||||||
erpnext.patches.v14_0.create_accounting_dimensions_in_supplier_quotation
|
erpnext.patches.v14_0.create_accounting_dimensions_in_supplier_quotation
|
||||||
erpnext.patches.v14_0.update_zero_asset_quantity_field
|
erpnext.patches.v14_0.update_zero_asset_quantity_field
|
||||||
|
execute:frappe.db.set_single_value("Buying Settings", "project_update_frequency", "Each Transaction")
|
||||||
# below migration patch should always run last
|
# below migration patch should always run last
|
||||||
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
|
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
|
||||||
|
@ -68,6 +68,10 @@ frappe.ui.form.on("Project", {
|
|||||||
frm.events.create_duplicate(frm);
|
frm.events.create_duplicate(frm);
|
||||||
}, __("Actions"));
|
}, __("Actions"));
|
||||||
|
|
||||||
|
frm.add_custom_button(__('Update Total Purchase Cost'), () => {
|
||||||
|
frm.events.update_total_purchase_cost(frm);
|
||||||
|
}, __("Actions"));
|
||||||
|
|
||||||
frm.trigger("set_project_status_button");
|
frm.trigger("set_project_status_button");
|
||||||
|
|
||||||
|
|
||||||
@ -92,6 +96,22 @@ frappe.ui.form.on("Project", {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
update_total_purchase_cost: function(frm) {
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.projects.doctype.project.project.recalculate_project_total_purchase_cost",
|
||||||
|
args: {project: frm.doc.name},
|
||||||
|
freeze: true,
|
||||||
|
freeze_message: __('Recalculating Purchase Cost against this Project...'),
|
||||||
|
callback: function(r) {
|
||||||
|
if (r && !r.exc) {
|
||||||
|
frappe.msgprint(__('Total Purchase Cost has been updated'));
|
||||||
|
frm.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
set_project_status_button: function(frm) {
|
set_project_status_button: function(frm) {
|
||||||
frm.add_custom_button(__('Set Project Status'), () => {
|
frm.add_custom_button(__('Set Project Status'), () => {
|
||||||
let d = new frappe.ui.Dialog({
|
let d = new frappe.ui.Dialog({
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from email_reply_parser import EmailReplyParser
|
from email_reply_parser import EmailReplyParser
|
||||||
from frappe import _
|
from frappe import _, qb
|
||||||
from frappe.desk.reportview import get_match_cond
|
from frappe.desk.reportview import get_match_cond
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.query_builder import Interval
|
from frappe.query_builder import Interval
|
||||||
from frappe.query_builder.functions import Count, CurDate, Date, UnixTimestamp
|
from frappe.query_builder.functions import Count, CurDate, Date, Sum, UnixTimestamp
|
||||||
from frappe.utils import add_days, flt, get_datetime, get_time, get_url, nowtime, today
|
from frappe.utils import add_days, flt, get_datetime, get_time, get_url, nowtime, today
|
||||||
from frappe.utils.user import is_website_user
|
from frappe.utils.user import is_website_user
|
||||||
|
|
||||||
@ -249,12 +249,7 @@ class Project(Document):
|
|||||||
self.per_gross_margin = (self.gross_margin / flt(self.total_billed_amount)) * 100
|
self.per_gross_margin = (self.gross_margin / flt(self.total_billed_amount)) * 100
|
||||||
|
|
||||||
def update_purchase_costing(self):
|
def update_purchase_costing(self):
|
||||||
total_purchase_cost = frappe.db.sql(
|
total_purchase_cost = calculate_total_purchase_cost(self.name)
|
||||||
"""select sum(base_net_amount)
|
|
||||||
from `tabPurchase Invoice Item` where project = %s and docstatus=1""",
|
|
||||||
self.name,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.total_purchase_cost = total_purchase_cost and total_purchase_cost[0][0] or 0
|
self.total_purchase_cost = total_purchase_cost and total_purchase_cost[0][0] or 0
|
||||||
|
|
||||||
def update_sales_amount(self):
|
def update_sales_amount(self):
|
||||||
@ -695,3 +690,29 @@ def get_holiday_list(company=None):
|
|||||||
|
|
||||||
def get_users_email(doc):
|
def get_users_email(doc):
|
||||||
return [d.email for d in doc.users if frappe.db.get_value("User", d.user, "enabled")]
|
return [d.email for d in doc.users if frappe.db.get_value("User", d.user, "enabled")]
|
||||||
|
|
||||||
|
|
||||||
|
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))
|
||||||
|
.where((pitem.project == project) & (pitem.docstatus == 1))
|
||||||
|
.run(as_list=True)
|
||||||
|
)
|
||||||
|
return total_purchase_cost
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def recalculate_project_total_purchase_cost(project: str | None = None):
|
||||||
|
if project:
|
||||||
|
total_purchase_cost = calculate_total_purchase_cost(project)
|
||||||
|
frappe.db.set_value(
|
||||||
|
"Project",
|
||||||
|
project,
|
||||||
|
"total_purchase_cost",
|
||||||
|
(total_purchase_cost and total_purchase_cost[0][0] or 0),
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user