diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
index 45373741f39c..e711ae0de2bb 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
@@ -49,6 +49,7 @@
"column_break_21",
"start_date",
"section_break_33",
+ "pdf_name",
"subject",
"column_break_28",
"cc_to",
@@ -273,7 +274,7 @@
"fieldname": "help_text",
"fieldtype": "HTML",
"label": "Help Text",
- "options": "
\n
Note
\n\n- \nYou can use Jinja tags in Subject and Body fields for dynamic values.\n
- \n All fields in this doctype are available under the doc object and all fields for the customer to whom the mail will go to is available under the customer object.\n
\n Examples
\n\n\n - Subject:
Statement Of Accounts for {{ customer.name }}
\n - Body:
\nHello {{ customer.name }},
PFA your Statement Of Accounts from {{ doc.from_date }} to {{ doc.to_date }}.
\n
\n"
+ "options": "
\nNote
\n\n- \nYou can use Jinja tags in Subject and Body fields for dynamic values.\n
- \n All fields in this doctype are available under the doc object and all fields for the customer to whom the mail will go to is available under the customer object.\n
\n Examples
\n\n\n - Subject:
Statement Of Accounts for {{ customer.customer_name }}
\n - Body:
\nHello {{ customer.customer_name }},
PFA your Statement Of Accounts from {{ doc.from_date }} to {{ doc.to_date }}.
\n
\n"
},
{
"fieldname": "subject",
@@ -368,10 +369,15 @@
"fieldname": "based_on_payment_terms",
"fieldtype": "Check",
"label": "Based On Payment Terms"
+ },
+ {
+ "fieldname": "pdf_name",
+ "fieldtype": "Data",
+ "label": "PDF Name"
}
],
"links": [],
- "modified": "2023-06-23 10:13:15.051950",
+ "modified": "2023-08-28 12:59:53.071334",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index 6cd601f663d3..e1f329522051 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -26,7 +26,13 @@ def validate(self):
if not self.subject:
self.subject = "Statement Of Accounts for {{ customer.customer_name }}"
if not self.body:
- self.body = "Hello {{ customer.name }},
PFA your Statement Of Accounts from {{ doc.from_date }} to {{ doc.to_date }}."
+ if self.report == "General Ledger":
+ body_str = " from {{ doc.from_date }} to {{ doc.to_date }}."
+ else:
+ body_str = " until {{ doc.posting_date }}."
+ self.body = "Hello {{ customer.customer_name }},
PFA your Statement Of Accounts" + body_str
+ if not self.pdf_name:
+ self.pdf_name = "{{ customer.customer_name }}"
validate_template(self.subject)
validate_template(self.body)
@@ -57,11 +63,6 @@ def get_report_pdf(doc, consolidated=True):
filters = get_common_filters(doc)
- if doc.report == "General Ledger":
- filters.update(get_gl_filters(doc, entry, tax_id, presentation_currency))
- else:
- filters.update(get_ar_filters(doc, entry))
-
if doc.report == "General Ledger":
col, res = get_soa(filters)
for x in [0, -2, -1]:
@@ -69,8 +70,11 @@ def get_report_pdf(doc, consolidated=True):
if len(res) == 3:
continue
else:
+ filters.update(get_ar_filters(doc, entry))
ar_res = get_ar_soa(filters)
col, res = ar_res[0], ar_res[1]
+ if not res:
+ continue
statement_dict[entry.customer] = get_html(doc, filters, entry, col, res, ageing)
@@ -139,6 +143,7 @@ def get_ar_filters(doc, entry):
return {
"report_date": doc.posting_date if doc.posting_date else None,
"customer": entry.customer,
+ "customer_name": entry.customer_name if entry.customer_name else None,
"payment_terms_template": doc.payment_terms_template if doc.payment_terms_template else None,
"sales_partner": doc.sales_partner if doc.sales_partner else None,
"sales_person": doc.sales_person if doc.sales_person else None,
@@ -362,16 +367,20 @@ def download_statements(document_name):
@frappe.whitelist()
-def send_emails(document_name, from_scheduler=False):
+def send_emails(document_name, from_scheduler=False, posting_date=None):
doc = frappe.get_doc("Process Statement Of Accounts", document_name)
report = get_report_pdf(doc, consolidated=False)
if report:
for customer, report_pdf in report.items():
- attachments = [{"fname": customer + ".pdf", "fcontent": report_pdf}]
+ context = get_context(customer, doc)
+ filename = frappe.render_template(doc.pdf_name, context)
+ attachments = [{"fname": filename + ".pdf", "fcontent": report_pdf}]
recipients, cc = get_recipients_and_cc(customer, doc)
- context = get_context(customer, doc)
+ if not recipients:
+ continue
+
subject = frappe.render_template(doc.subject, context)
message = frappe.render_template(doc.body, context)
@@ -390,7 +399,7 @@ def send_emails(document_name, from_scheduler=False):
)
if doc.enable_auto_email and from_scheduler:
- new_to_date = getdate(today())
+ new_to_date = getdate(posting_date or today())
if doc.frequency == "Weekly":
new_to_date = add_days(new_to_date, 7)
else:
@@ -399,8 +408,11 @@ def send_emails(document_name, from_scheduler=False):
doc.add_comment(
"Comment", "Emails sent on: " + frappe.utils.format_datetime(frappe.utils.now())
)
- doc.db_set("to_date", new_to_date, commit=True)
- doc.db_set("from_date", new_from_date, commit=True)
+ if doc.report == "General Ledger":
+ doc.db_set("to_date", new_to_date, commit=True)
+ doc.db_set("from_date", new_from_date, commit=True)
+ else:
+ doc.db_set("posting_date", new_to_date, commit=True)
return True
else:
return False
@@ -410,7 +422,8 @@ def send_emails(document_name, from_scheduler=False):
def send_auto_email():
selected = frappe.get_list(
"Process Statement Of Accounts",
- filters={"to_date": format_date(today()), "enable_auto_email": 1},
+ filters={"enable_auto_email": 1},
+ or_filters={"to_date": format_date(today()), "posting_date": format_date(today())},
)
for entry in selected:
send_emails(entry.name, from_scheduler=True)
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html
index 259526f8c43a..647600a9fea0 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html
@@ -8,9 +8,24 @@
}
+
+
+
{{ _(report.report_name) }}
- {{ filters.customer }}
+ {{ filters.customer_name }}
{% if (filters.tax_id) %}
@@ -341,4 +356,9 @@ {{ _("Ageing Report based on ") }} {{ ageing.ageing_base
{% endif %}
+ {% if terms_and_conditions %}
+
+ {{ terms_and_conditions }}
+
+ {% endif %}
{{ _("Printed On ") }}{{ frappe.utils.now() }}
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py
index c281040aaf2d..fb0d8d152f00 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py
@@ -1,9 +1,42 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-# import frappe
import unittest
+import frappe
+from frappe.utils import add_days, getdate, today
+
+from erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts import (
+ send_emails,
+)
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+
class TestProcessStatementOfAccounts(unittest.TestCase):
- pass
+ def setUp(self):
+ self.si = create_sales_invoice()
+ self.process_soa = create_process_soa()
+
+ def test_auto_email_for_process_soa_ar(self):
+ send_emails(self.process_soa.name, from_scheduler=True)
+ self.process_soa.load_from_db()
+ self.assertEqual(self.process_soa.posting_date, getdate(add_days(today(), 7)))
+
+ def tearDown(self):
+ frappe.delete_doc_if_exists("Process Statement Of Accounts", "Test Process SOA")
+
+
+def create_process_soa():
+ frappe.delete_doc_if_exists("Process Statement Of Accounts", "Test Process SOA")
+ process_soa = frappe.new_doc("Process Statement Of Accounts")
+ soa_dict = {
+ "name": "Test Process SOA",
+ "company": "_Test Company",
+ }
+ process_soa.update(soa_dict)
+ process_soa.set("customers", [{"customer": "_Test Customer"}])
+ process_soa.enable_auto_email = 1
+ process_soa.frequency = "Weekly"
+ process_soa.report = "Accounts Receivable"
+ process_soa.save()
+ return process_soa