Merge pull request #32895 from rohitwaghchaure/fixed-performance-issue-for-purchase-receipt

fix: Purchase Receipt timeout error
This commit is contained in:
rohitwaghchaure 2022-11-10 22:41:54 +05:30 committed by GitHub
commit 8ae9c1d192
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 102 additions and 35 deletions

View File

@ -1463,6 +1463,7 @@ class PurchaseInvoice(BuyingController):
def update_billing_status_in_pr(self, update_modified=True): def update_billing_status_in_pr(self, update_modified=True):
updated_pr = [] updated_pr = []
po_details = []
for d in self.get("items"): for d in self.get("items"):
if d.pr_detail: if d.pr_detail:
billed_amt = frappe.db.sql( billed_amt = frappe.db.sql(
@ -1480,7 +1481,10 @@ class PurchaseInvoice(BuyingController):
) )
updated_pr.append(d.purchase_receipt) updated_pr.append(d.purchase_receipt)
elif d.po_detail: elif d.po_detail:
updated_pr += update_billed_amount_based_on_po(d.po_detail, update_modified) po_details.append(d.po_detail)
if po_details:
updated_pr += update_billed_amount_based_on_po(po_details, update_modified)
for pr in set(updated_pr): for pr in set(updated_pr):
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billing_percentage from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billing_percentage

View File

@ -6,7 +6,9 @@ import frappe
from frappe import _, throw from frappe import _, throw
from frappe.desk.notifications import clear_doctype_notifications from frappe.desk.notifications import clear_doctype_notifications
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
from frappe.query_builder.functions import CombineDatetime
from frappe.utils import cint, flt, getdate, nowdate from frappe.utils import cint, flt, getdate, nowdate
from pypika import functions as fn
import erpnext import erpnext
from erpnext.accounts.utils import get_account_currency from erpnext.accounts.utils import get_account_currency
@ -750,48 +752,38 @@ class PurchaseReceipt(BuyingController):
def update_billing_status(self, update_modified=True): def update_billing_status(self, update_modified=True):
updated_pr = [self.name] updated_pr = [self.name]
po_details = []
for d in self.get("items"): for d in self.get("items"):
if d.get("purchase_invoice") and d.get("purchase_invoice_item"): if d.get("purchase_invoice") and d.get("purchase_invoice_item"):
d.db_set("billed_amt", d.amount, update_modified=update_modified) d.db_set("billed_amt", d.amount, update_modified=update_modified)
elif d.purchase_order_item: elif d.purchase_order_item:
updated_pr += update_billed_amount_based_on_po(d.purchase_order_item, update_modified) po_details.append(d.purchase_order_item)
if po_details:
updated_pr += update_billed_amount_based_on_po(po_details, update_modified)
for pr in set(updated_pr): for pr in set(updated_pr):
pr_doc = self if (pr == self.name) else frappe.get_doc("Purchase Receipt", pr) pr_doc = self if (pr == self.name) else frappe.get_cached_doc("Purchase Receipt", pr)
update_billing_percentage(pr_doc, update_modified=update_modified) update_billing_percentage(pr_doc, update_modified=update_modified)
self.load_from_db() self.load_from_db()
def update_billed_amount_based_on_po(po_detail, update_modified=True): def update_billed_amount_based_on_po(po_details, update_modified=True):
# Billed against Sales Order directly po_billed_amt_details = get_billed_amount_against_po(po_details)
billed_against_po = frappe.db.sql(
"""select sum(amount) from `tabPurchase Invoice Item`
where po_detail=%s and (pr_detail is null or pr_detail = '') and docstatus=1""",
po_detail,
)
billed_against_po = billed_against_po and billed_against_po[0][0] or 0
# Get all Purchase Receipt Item rows against the Purchase Order Item row # Get all Purchase Receipt Item rows against the Purchase Order Items
pr_details = frappe.db.sql( pr_details = get_purchase_receipts_against_po_details(po_details)
"""select pr_item.name, pr_item.amount, pr_item.parent
from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr pr_items = [pr_detail.name for pr_detail in pr_details]
where pr.name=pr_item.parent and pr_item.purchase_order_item=%s pr_items_billed_amount = get_billed_amount_against_pr(pr_items)
and pr.docstatus=1 and pr.is_return = 0
order by pr.posting_date asc, pr.posting_time asc, pr.name asc""",
po_detail,
as_dict=1,
)
updated_pr = [] updated_pr = []
for pr_item in pr_details: for pr_item in pr_details:
billed_against_po = flt(po_billed_amt_details.get(pr_item.purchase_order_item))
# Get billed amount directly against Purchase Receipt # Get billed amount directly against Purchase Receipt
billed_amt_agianst_pr = frappe.db.sql( billed_amt_agianst_pr = flt(pr_items_billed_amount.get(pr_item.name, 0))
"""select sum(amount) from `tabPurchase Invoice Item`
where pr_detail=%s and docstatus=1""",
pr_item.name,
)
billed_amt_agianst_pr = billed_amt_agianst_pr and billed_amt_agianst_pr[0][0] or 0
# Distribute billed amount directly against PO between PRs based on FIFO # Distribute billed amount directly against PO between PRs based on FIFO
if billed_against_po and billed_amt_agianst_pr < pr_item.amount: if billed_against_po and billed_amt_agianst_pr < pr_item.amount:
@ -803,6 +795,9 @@ def update_billed_amount_based_on_po(po_detail, update_modified=True):
billed_amt_agianst_pr += billed_against_po billed_amt_agianst_pr += billed_against_po
billed_against_po = 0 billed_against_po = 0
po_billed_amt_details[pr_item.purchase_order_item] = billed_against_po
if pr_item.billed_amt != billed_amt_agianst_pr:
frappe.db.set_value( frappe.db.set_value(
"Purchase Receipt Item", "Purchase Receipt Item",
pr_item.name, pr_item.name,
@ -816,6 +811,74 @@ def update_billed_amount_based_on_po(po_detail, update_modified=True):
return updated_pr return updated_pr
def get_purchase_receipts_against_po_details(po_details):
# Get Purchase Receipts against Purchase Order Items
purchase_receipt = frappe.qb.DocType("Purchase Receipt")
purchase_receipt_item = frappe.qb.DocType("Purchase Receipt Item")
query = (
frappe.qb.from_(purchase_receipt)
.inner_join(purchase_receipt_item)
.on(purchase_receipt.name == purchase_receipt_item.parent)
.select(
purchase_receipt_item.name,
purchase_receipt_item.parent,
purchase_receipt_item.amount,
purchase_receipt_item.billed_amt,
purchase_receipt_item.purchase_order_item,
)
.where(
(purchase_receipt_item.purchase_order_item.isin(po_details))
& (purchase_receipt.docstatus == 1)
& (purchase_receipt.is_return == 0)
)
.orderby(CombineDatetime(purchase_receipt.posting_date, purchase_receipt.posting_time))
.orderby(purchase_receipt.name)
)
return query.run(as_dict=True)
def get_billed_amount_against_pr(pr_items):
# Get billed amount directly against Purchase Receipt
if not pr_items:
return {}
purchase_invoice_item = frappe.qb.DocType("Purchase Invoice Item")
query = (
frappe.qb.from_(purchase_invoice_item)
.select(fn.Sum(purchase_invoice_item.amount).as_("billed_amt"), purchase_invoice_item.pr_detail)
.where((purchase_invoice_item.pr_detail.isin(pr_items)) & (purchase_invoice_item.docstatus == 1))
.groupby(purchase_invoice_item.pr_detail)
).run(as_dict=1)
return {d.pr_detail: flt(d.billed_amt) for d in query}
def get_billed_amount_against_po(po_items):
# Get billed amount directly against Purchase Order
if not po_items:
return {}
purchase_invoice_item = frappe.qb.DocType("Purchase Invoice Item")
query = (
frappe.qb.from_(purchase_invoice_item)
.select(fn.Sum(purchase_invoice_item.amount).as_("billed_amt"), purchase_invoice_item.po_detail)
.where(
(purchase_invoice_item.po_detail.isin(po_items))
& (purchase_invoice_item.docstatus == 1)
& (purchase_invoice_item.pr_detail.isnull())
)
.groupby(purchase_invoice_item.po_detail)
).run(as_dict=1)
return {d.po_detail: flt(d.billed_amt) for d in query}
def update_billing_percentage(pr_doc, update_modified=True): def update_billing_percentage(pr_doc, update_modified=True):
# Reload as billed amount was set in db directly # Reload as billed amount was set in db directly
pr_doc.load_from_db() pr_doc.load_from_db()