mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 04:09:11 +00:00
refactor(customer): replace SQL with query builder in get_customer_ou… (#55209)
This commit is contained in:
@@ -667,85 +667,97 @@ def send_emails(
|
|||||||
|
|
||||||
|
|
||||||
def get_customer_outstanding(customer, company, ignore_outstanding_sales_order=False, cost_center=None):
|
def get_customer_outstanding(customer, company, ignore_outstanding_sales_order=False, cost_center=None):
|
||||||
# Outstanding based on GL Entries
|
from frappe.query_builder import Criterion
|
||||||
cond = ""
|
from frappe.query_builder.functions import Coalesce, IfNull, Sum
|
||||||
|
|
||||||
|
GLEntry = frappe.qb.DocType("GL Entry")
|
||||||
|
gle_query = (
|
||||||
|
frappe.qb.from_(GLEntry)
|
||||||
|
.select(Sum(GLEntry.debit) - Sum(GLEntry.credit))
|
||||||
|
.where(GLEntry.party_type == "Customer")
|
||||||
|
.where(GLEntry.party == customer)
|
||||||
|
.where(GLEntry.company == company)
|
||||||
|
.where(GLEntry.is_cancelled == 0)
|
||||||
|
)
|
||||||
|
|
||||||
if cost_center:
|
if cost_center:
|
||||||
lft, rgt = frappe.get_cached_value("Cost Center", cost_center, ["lft", "rgt"])
|
lft, rgt = frappe.get_cached_value("Cost Center", cost_center, ["lft", "rgt"])
|
||||||
|
CostCenter = frappe.qb.DocType("Cost Center")
|
||||||
|
cost_center_subquery = (
|
||||||
|
frappe.qb.from_(CostCenter)
|
||||||
|
.select(CostCenter.name)
|
||||||
|
.where(CostCenter.lft >= lft)
|
||||||
|
.where(CostCenter.rgt <= rgt)
|
||||||
|
)
|
||||||
|
gle_query = gle_query.where(GLEntry.cost_center.isin(cost_center_subquery))
|
||||||
|
|
||||||
cond = f""" and cost_center in (select name from `tabCost Center` where
|
gle_res = gle_query.run()
|
||||||
lft >= {lft} and rgt <= {rgt})"""
|
outstanding_based_on_gle = flt(gle_res[0][0]) if gle_res and gle_res[0][0] is not None else 0.0
|
||||||
|
|
||||||
outstanding_based_on_gle = frappe.db.sql(
|
outstanding_based_on_so = 0.0
|
||||||
f"""
|
|
||||||
select sum(debit) - sum(credit)
|
|
||||||
from `tabGL Entry` where party_type = 'Customer'
|
|
||||||
and is_cancelled = 0 and party = %s
|
|
||||||
and company=%s {cond}""",
|
|
||||||
(customer, company),
|
|
||||||
)
|
|
||||||
|
|
||||||
outstanding_based_on_gle = flt(outstanding_based_on_gle[0][0]) if outstanding_based_on_gle else 0
|
|
||||||
|
|
||||||
# Outstanding based on Sales Order
|
|
||||||
outstanding_based_on_so = 0
|
|
||||||
|
|
||||||
# if credit limit check is bypassed at sales order level,
|
|
||||||
# we should not consider outstanding Sales Orders, when customer credit balance report is run
|
|
||||||
if not ignore_outstanding_sales_order:
|
if not ignore_outstanding_sales_order:
|
||||||
outstanding_based_on_so = frappe.db.sql(
|
SalesOrder = frappe.qb.DocType("Sales Order")
|
||||||
"""
|
so_query = (
|
||||||
select sum(base_grand_total*(100 - per_billed)/100)
|
frappe.qb.from_(SalesOrder)
|
||||||
from `tabSales Order`
|
.select(Sum(SalesOrder.base_grand_total * (100 - SalesOrder.per_billed) / 100))
|
||||||
where customer=%s and docstatus = 1 and company=%s
|
.where(SalesOrder.customer == customer)
|
||||||
and per_billed < 100 and status != 'Closed'""",
|
.where(SalesOrder.company == company)
|
||||||
(customer, company),
|
.where(SalesOrder.docstatus == 1)
|
||||||
|
.where(SalesOrder.per_billed < 100)
|
||||||
|
.where(SalesOrder.status != "Closed")
|
||||||
)
|
)
|
||||||
|
so_res = so_query.run()
|
||||||
|
outstanding_based_on_so = flt(so_res[0][0]) if so_res and so_res[0][0] is not None else 0.0
|
||||||
|
|
||||||
outstanding_based_on_so = flt(outstanding_based_on_so[0][0]) if outstanding_based_on_so else 0
|
DeliveryNote = frappe.qb.DocType("Delivery Note")
|
||||||
|
DeliveryNoteItem = frappe.qb.DocType("Delivery Note Item")
|
||||||
|
SalesInvoiceItem = frappe.qb.DocType("Sales Invoice Item")
|
||||||
|
|
||||||
# Outstanding based on Delivery Note, which are not created against Sales Order
|
si_subquery = (
|
||||||
outstanding_based_on_dn = 0
|
frappe.qb.from_(SalesInvoiceItem)
|
||||||
|
.select(SalesInvoiceItem.dn_detail, Sum(SalesInvoiceItem.amount).as_("billed_amount"))
|
||||||
unmarked_delivery_note_items = frappe.db.sql(
|
.where(SalesInvoiceItem.docstatus == 1)
|
||||||
"""select
|
.groupby(SalesInvoiceItem.dn_detail)
|
||||||
dn_item.name, dn_item.amount, dn.base_net_total, dn.base_grand_total
|
|
||||||
from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item
|
|
||||||
where
|
|
||||||
dn.name = dn_item.parent
|
|
||||||
and dn.customer=%s and dn.company=%s
|
|
||||||
and dn.docstatus = 1 and dn.status not in ('Closed', 'Stopped')
|
|
||||||
and ifnull(dn_item.against_sales_order, '') = ''
|
|
||||||
and ifnull(dn_item.against_sales_invoice, '') = ''
|
|
||||||
""",
|
|
||||||
(customer, company),
|
|
||||||
as_dict=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not unmarked_delivery_note_items:
|
dn_query = (
|
||||||
return outstanding_based_on_gle + outstanding_based_on_so
|
frappe.qb.from_(DeliveryNote)
|
||||||
|
.join(DeliveryNoteItem)
|
||||||
si_amounts = frappe.db.sql(
|
.on(DeliveryNote.name == DeliveryNoteItem.parent)
|
||||||
"""
|
.left_join(si_subquery)
|
||||||
SELECT
|
.on(DeliveryNoteItem.name == si_subquery.dn_detail)
|
||||||
dn_detail, sum(amount) from `tabSales Invoice Item`
|
.select(
|
||||||
WHERE
|
Sum(
|
||||||
docstatus = 1
|
(
|
||||||
and dn_detail in ({})
|
(DeliveryNoteItem.amount - IfNull(si_subquery.billed_amount, 0.0))
|
||||||
GROUP BY dn_detail""".format(
|
/ DeliveryNote.base_net_total
|
||||||
", ".join(frappe.db.escape(dn_item.name) for dn_item in unmarked_delivery_note_items)
|
)
|
||||||
|
* DeliveryNote.base_grand_total
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.where(DeliveryNote.customer == customer)
|
||||||
|
.where(DeliveryNote.company == company)
|
||||||
|
.where(DeliveryNote.docstatus == 1)
|
||||||
|
.where(DeliveryNote.base_net_total > 0)
|
||||||
|
.where(DeliveryNote.status.notin(["Closed", "Stopped"]))
|
||||||
|
.where(DeliveryNoteItem.amount > IfNull(si_subquery.billed_amount, 0.0))
|
||||||
|
.where(
|
||||||
|
Criterion.any(
|
||||||
|
[DeliveryNoteItem.against_sales_order.isnull(), DeliveryNoteItem.against_sales_order == ""]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
Criterion.any(
|
||||||
|
[
|
||||||
|
DeliveryNoteItem.against_sales_invoice.isnull(),
|
||||||
|
DeliveryNoteItem.against_sales_invoice == "",
|
||||||
|
]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
si_amounts = {si_item[0]: si_item[1] for si_item in si_amounts}
|
dn_res = dn_query.run()
|
||||||
|
outstanding_based_on_dn = flt(dn_res[0][0]) if dn_res and dn_res[0][0] is not None else 0.0
|
||||||
for dn_item in unmarked_delivery_note_items:
|
|
||||||
dn_amount = flt(dn_item.amount)
|
|
||||||
si_amount = flt(si_amounts.get(dn_item.name))
|
|
||||||
|
|
||||||
if dn_amount > si_amount and dn_item.base_net_total:
|
|
||||||
outstanding_based_on_dn += (
|
|
||||||
(dn_amount - si_amount) / dn_item.base_net_total
|
|
||||||
) * dn_item.base_grand_total
|
|
||||||
|
|
||||||
return outstanding_based_on_gle + outstanding_based_on_so + outstanding_based_on_dn
|
return outstanding_based_on_gle + outstanding_based_on_so + outstanding_based_on_dn
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user