mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-01 20:48:27 +00:00
Co-authored-by: Ravibharathi <131471282+ravibharathi656@users.noreply.github.com> fix: filter overdue purchase order items by company (#54099)
This commit is contained in:
@@ -158,10 +158,7 @@ class EmailDigest(Document):
|
|||||||
context.quote = {"text": quote[0], "author": quote[1]}
|
context.quote = {"text": quote[0], "author": quote[1]}
|
||||||
|
|
||||||
if self.get("purchase_orders_items_overdue"):
|
if self.get("purchase_orders_items_overdue"):
|
||||||
(
|
context.purchase_orders_items_overdue_map = self.get_purchase_orders_items_overdue_list()
|
||||||
context.purchase_order_list,
|
|
||||||
context.purchase_orders_items_overdue_list,
|
|
||||||
) = self.get_purchase_orders_items_overdue_list()
|
|
||||||
|
|
||||||
if not context:
|
if not context:
|
||||||
return None
|
return None
|
||||||
@@ -860,30 +857,42 @@ class EmailDigest(Document):
|
|||||||
return fmt_money(value, currency=self.currency)
|
return fmt_money(value, currency=self.currency)
|
||||||
|
|
||||||
def get_purchase_orders_items_overdue_list(self):
|
def get_purchase_orders_items_overdue_list(self):
|
||||||
fields_po = "distinct `tabPurchase Order Item`.parent as po"
|
po = frappe.qb.DocType("Purchase Order")
|
||||||
fields_poi = (
|
poi = frappe.qb.DocType("Purchase Order Item")
|
||||||
"`tabPurchase Order Item`.parent, `tabPurchase Order Item`.schedule_date, item_code,"
|
|
||||||
"received_qty, qty - received_qty as missing_qty, rate, amount"
|
query = (
|
||||||
|
frappe.qb.from_(poi)
|
||||||
|
.select(
|
||||||
|
poi.parent,
|
||||||
|
poi.schedule_date,
|
||||||
|
poi.item_code,
|
||||||
|
poi.received_qty,
|
||||||
|
(poi.qty - poi.received_qty).as_("missing_qty"),
|
||||||
|
poi.rate,
|
||||||
|
poi.amount,
|
||||||
|
po.currency,
|
||||||
|
)
|
||||||
|
.inner_join(po)
|
||||||
|
.on(po.name == poi.parent)
|
||||||
|
.where(po.status != "Closed")
|
||||||
|
.where(poi.docstatus == 1)
|
||||||
|
.where(poi.schedule_date < today())
|
||||||
|
.where(poi.received_qty < poi.qty)
|
||||||
|
.where(po.company == self.company)
|
||||||
|
.orderby(poi.parent, order=frappe.qb.desc)
|
||||||
|
.orderby(poi.idx)
|
||||||
)
|
)
|
||||||
|
|
||||||
sql_po = f"""select {fields_po} from `tabPurchase Order Item`
|
items_by_parent = frappe._dict()
|
||||||
left join `tabPurchase Order` on `tabPurchase Order`.name = `tabPurchase Order Item`.parent
|
|
||||||
where status<>'Closed' and `tabPurchase Order Item`.docstatus=1 and CURRENT_DATE > `tabPurchase Order Item`.schedule_date
|
|
||||||
and received_qty < qty order by `tabPurchase Order Item`.parent DESC,
|
|
||||||
`tabPurchase Order Item`.schedule_date DESC"""
|
|
||||||
|
|
||||||
sql_poi = f"""select {fields_poi} from `tabPurchase Order Item`
|
for row in query.run(as_dict=True):
|
||||||
left join `tabPurchase Order` on `tabPurchase Order`.name = `tabPurchase Order Item`.parent
|
row.link = get_url_to_form("Purchase Order", row.parent)
|
||||||
where status<>'Closed' and `tabPurchase Order Item`.docstatus=1 and CURRENT_DATE > `tabPurchase Order Item`.schedule_date
|
row.rate = fmt_money(row.rate, 2, row.currency)
|
||||||
and received_qty < qty order by `tabPurchase Order Item`.idx"""
|
row.amount = fmt_money(row.amount, 2, row.currency)
|
||||||
purchase_order_list = frappe.db.sql(sql_po, as_dict=True)
|
|
||||||
purchase_order_items_overdue_list = frappe.db.sql(sql_poi, as_dict=True)
|
|
||||||
|
|
||||||
for t in purchase_order_items_overdue_list:
|
items_by_parent.setdefault(row.parent, []).append(row)
|
||||||
t.link = get_url_to_form("Purchase Order", t.parent)
|
|
||||||
t.rate = fmt_money(t.rate, 2, t.currency)
|
return items_by_parent
|
||||||
t.amount = fmt_money(t.amount, 2, t.currency)
|
|
||||||
return purchase_order_list, purchase_order_items_overdue_list
|
|
||||||
|
|
||||||
|
|
||||||
def send():
|
def send():
|
||||||
|
|||||||
@@ -182,7 +182,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Purchase Order Items Overdue -->
|
<!-- Purchase Order Items Overdue -->
|
||||||
{% if purchase_orders_items_overdue_list %}
|
{% if purchase_orders_items_overdue_map %}
|
||||||
<h4 style="{{ section_head }}" class="text-center">{{ _("Purchase Order Items not received on time") }}</h4>
|
<h4 style="{{ section_head }}" class="text-center">{{ _("Purchase Order Items not received on time") }}</h4>
|
||||||
<div>
|
<div>
|
||||||
<div style="background-color: #fafbfc;">
|
<div style="background-color: #fafbfc;">
|
||||||
@@ -206,43 +206,41 @@
|
|||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{% for po in purchase_order_list %}
|
{% for po, po_items in purchase_orders_items_overdue_map.items() %}
|
||||||
<div style="{{ line_item }}">
|
<div style="{{ line_item }}">
|
||||||
<table style="width: 100%;">
|
<table style="width: 100%;">
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<span style="padding: 3px 7px; margin-right: 7px; font-weight: bold;">{{ po.po }}</span>
|
<span style="padding: 3px 7px; margin-right: 7px; font-weight: bold;">{{ po | e }}</span>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{% for t in purchase_orders_items_overdue_list %}
|
{% for row in po_items %}
|
||||||
{% if t.parent == po.po %}
|
<div >
|
||||||
<div >
|
<table style="width: 100%; table-layout: fixed;">
|
||||||
<table style="width: 100%;">
|
<tr>
|
||||||
<tr>
|
<td style="width: 40%; padding-left: 7px; vertical-align: top;">
|
||||||
<td style="padding-left: 7px;">
|
<a style="{{ link_css }}" href="{{ row.link | e }}">{{ _(row.item_code) | e }}</a>
|
||||||
<a style="width: 40%; {{ link_css }}" href="{{ t.link }}">{{ _(t.item_code) }}</a>
|
</td>
|
||||||
</td>
|
<td style="width: 20%; text-align: right; white-space: nowrap; vertical-align: top;">
|
||||||
<td style="width: 20%; text-align: right">
|
<span style="{{ label_css }}">
|
||||||
<span style="{{ label_css }}">
|
{{ row.missing_qty | e }}
|
||||||
{{ t.missing_qty }}
|
</span>
|
||||||
</span>
|
</td>
|
||||||
</td>
|
<td style="width: 20%; text-align: right; white-space: nowrap; vertical-align: top;">
|
||||||
<td style="width: 20%; text-align: right">
|
<span style="{{ label_css }}">
|
||||||
<span style="{{ label_css }}">
|
{{ row.rate | e }}
|
||||||
{{ t.rate }}
|
</span>
|
||||||
</span>
|
</td>
|
||||||
</td>
|
<td style="width: 20%; text-align: right; white-space: nowrap; vertical-align: top;">
|
||||||
<td style="width: 20%; text-align: right">
|
<span style="{{ label_css }}">
|
||||||
<span style="{{ label_css }}">
|
{{ row.amount | e }}
|
||||||
{{ t.amount }}
|
</span>
|
||||||
</span>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
</table>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -2,8 +2,79 @@
|
|||||||
# See license.txt
|
# See license.txt
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe.utils import add_days, today
|
||||||
|
|
||||||
|
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
|
||||||
from erpnext.tests.utils import ERPNextTestSuite
|
from erpnext.tests.utils import ERPNextTestSuite
|
||||||
|
|
||||||
|
|
||||||
class TestEmailDigest(ERPNextTestSuite):
|
class TestEmailDigest(ERPNextTestSuite):
|
||||||
pass
|
def test_purchase_orders_items_overdue_list_is_filtered_by_company(self):
|
||||||
|
digest = create_email_digest(
|
||||||
|
company="_Test Company",
|
||||||
|
frequency="Daily",
|
||||||
|
purchase_orders_items_overdue=1,
|
||||||
|
name="Test Email Digest PO Company Filter",
|
||||||
|
)
|
||||||
|
backdate = add_days(today(), -1)
|
||||||
|
|
||||||
|
po1 = create_purchase_order(transaction_date=backdate, do_not_save=True)
|
||||||
|
po1.schedule_date = backdate
|
||||||
|
po1.items[0].schedule_date = backdate
|
||||||
|
po1.insert()
|
||||||
|
po1.submit()
|
||||||
|
|
||||||
|
po2 = create_purchase_order(
|
||||||
|
company="_Test Company 1",
|
||||||
|
warehouse="Stores - _TC1",
|
||||||
|
transaction_date=backdate,
|
||||||
|
do_not_save=True,
|
||||||
|
)
|
||||||
|
po2.schedule_date = backdate
|
||||||
|
po2.items[0].schedule_date = backdate
|
||||||
|
po2.insert()
|
||||||
|
po2.submit()
|
||||||
|
|
||||||
|
overdue_items = digest.get_purchase_orders_items_overdue_list()
|
||||||
|
|
||||||
|
self.assertIn(po1.name, overdue_items)
|
||||||
|
self.assertNotIn(po2.name, overdue_items)
|
||||||
|
|
||||||
|
|
||||||
|
def create_email_digest(**args):
|
||||||
|
args = frappe._dict(args)
|
||||||
|
doc = frappe.new_doc("Email Digest")
|
||||||
|
doc.name = args.name or "Test Email Digest"
|
||||||
|
doc.company = args.company or "_Test Company"
|
||||||
|
doc.frequency = args.frequency or "Daily"
|
||||||
|
doc.enabled = args.enabled or 0
|
||||||
|
doc.bank_balance = args.bank_balance or 0
|
||||||
|
doc.credit_balance = args.credit_balance or 0
|
||||||
|
doc.invoiced_amount = args.invoiced_amount or 0
|
||||||
|
doc.payables = args.payables or 0
|
||||||
|
doc.sales_orders_to_bill = args.sales_orders_to_bill or 0
|
||||||
|
doc.purchase_orders_to_bill = args.purchase_orders_to_bill or 0
|
||||||
|
doc.sales_order = args.sales_order or 0
|
||||||
|
doc.purchase_order = args.purchase_order or 0
|
||||||
|
doc.sales_orders_to_deliver = args.sales_orders_to_deliver or 0
|
||||||
|
doc.purchase_orders_to_receive = args.purchase_orders_to_receive or 0
|
||||||
|
doc.sales_invoice = args.sales_invoice or 0
|
||||||
|
doc.purchase_invoice = args.purchase_invoice or 0
|
||||||
|
doc.new_quotations = args.new_quotations or 0
|
||||||
|
doc.pending_quotations = args.pending_quotations or 0
|
||||||
|
doc.issue = args.issue or 0
|
||||||
|
doc.project = args.project or 0
|
||||||
|
doc.purchase_orders_items_overdue = args.purchase_orders_items_overdue or 0
|
||||||
|
doc.calendar_events = args.calendar_events or 0
|
||||||
|
doc.todo_list = args.todo_list or 0
|
||||||
|
doc.notifications = args.notifications or 0
|
||||||
|
doc.add_quote = args.add_quote or 0
|
||||||
|
|
||||||
|
for recipient in args.recipients or ["Administrator"]:
|
||||||
|
doc.append("recipients", {"recipient": recipient})
|
||||||
|
|
||||||
|
if not args.do_not_save:
|
||||||
|
doc.insert()
|
||||||
|
|
||||||
|
return doc
|
||||||
|
|||||||
Reference in New Issue
Block a user