diff --git a/rmax_custom/public/js/branch_user_restrict.js b/rmax_custom/public/js/branch_user_restrict.js
index 7c9dad4..b2f2dc3 100644
--- a/rmax_custom/public/js/branch_user_restrict.js
+++ b/rmax_custom/public/js/branch_user_restrict.js
@@ -50,6 +50,7 @@
"Stock Sales Report",
"Collection Report",
"Branch Receivables",
+ "Accounts Receivable Summary",
"Stock Balance",
"Simple Stock Report",
"Stock Ledger",
@@ -339,6 +340,32 @@
}
}
+ // === AUTO-SET BRANCH FILTER ON AR SUMMARY ===
+ function set_ar_summary_branch_filter() {
+ if (!is_restricted_user()) return;
+ var route = frappe.get_route();
+ if (!route || route[0] !== "query-report" || route[1] !== "Accounts Receivable Summary") return;
+
+ var branch = frappe.defaults.get_user_default("Branch");
+ if (!branch) return;
+
+ var attempts = 0;
+ var interval = setInterval(function () {
+ attempts++;
+ if (attempts > 40) { clearInterval(interval); return; }
+
+ var report = frappe.query_report;
+ if (!report || !report.get_filter) return;
+
+ var branch_filter = report.get_filter("branch");
+ if (!branch_filter) { clearInterval(interval); return; }
+
+ clearInterval(interval);
+ report.set_filter_value("branch", branch);
+ report.refresh();
+ }, 300);
+ }
+
// === APPLY ALL RESTRICTIONS ===
function apply_all() {
if (!is_restricted_user()) return;
@@ -347,6 +374,7 @@
fix_logo_href();
add_dashboard_nav();
hide_cost_columns_in_reports();
+ set_ar_summary_branch_filter();
}
// === ENFORCE ON EVERY PAGE CHANGE ===
diff --git a/rmax_custom/rmax_custom/page/rmax_dashboard/rmax_dashboard.js b/rmax_custom/rmax_custom/page/rmax_dashboard/rmax_dashboard.js
index 0540e73..02a0f4c 100644
--- a/rmax_custom/rmax_custom/page/rmax_dashboard/rmax_dashboard.js
+++ b/rmax_custom/rmax_custom/page/rmax_dashboard/rmax_dashboard.js
@@ -181,6 +181,7 @@ function render_branch_dashboard(data) {
html += action_card('bar-chart-2', 'Stock Sales Report', 'Sales analysis', 'report', 'Stock Sales Report');
html += action_card('dollar-sign', 'Collection Report', 'Payment collections', 'report', 'Collection Report');
html += action_card('credit-card', 'Branch Receivables', 'Outstanding receivables', 'report', 'Branch Receivables');
+ html += action_card('activity', 'AR Summary', 'Party-wise aging', 'report', 'Accounts Receivable Summary');
html += action_card('layers', 'Stock Balance', 'Current stock levels', 'report', 'Stock Balance');
html += action_card('box', 'Simple Stock Report', 'Stock as on date', 'report', 'Simple Stock Report');
html += action_card('book-open', 'Stock Ledger', 'Stock transactions', 'report', 'Stock Ledger');
@@ -219,6 +220,7 @@ function render_stock_dashboard(data) {
html += action_card('package', 'Purchase Receipt', 'Receive goods', 'list', 'Purchase Receipt');
html += action_card('list', 'Item', 'Manage items', 'list', 'Item');
html += action_card('layers', 'Stock Balance', 'Current stock levels', 'report', 'Stock Balance');
+ html += action_card('box', 'Simple Stock Report', 'Stock as on date', 'report', 'Simple Stock Report');
html += action_card('book-open', 'Stock Ledger', 'Stock transactions', 'report', 'Stock Ledger');
html += action_card('tag', 'Item Groups', 'Browse item groups', 'list', 'Item Group');
html += action_card('alert-triangle', 'Report Damage', 'Create damage slip', 'new', 'Damage Slip');
diff --git a/rmax_custom/setup.py b/rmax_custom/setup.py
index fdf620e..1a0b90e 100644
--- a/rmax_custom/setup.py
+++ b/rmax_custom/setup.py
@@ -294,6 +294,15 @@ def after_migrate():
message=frappe.get_traceback(),
)
+ # Custom print format for Accounts Receivable Summary report
+ try:
+ setup_ar_summary_print_format()
+ except Exception:
+ frappe.log_error(
+ title="rmax_custom: AR summary print format setup failed",
+ message=frappe.get_traceback(),
+ )
+
# Roles allowed to tick custom_allow_duplicate_vat on Customer (permlevel 1)
VAT_DUPLICATE_OVERRIDE_ROLES = ("Sales Manager", "Sales Master Manager", "System Manager")
@@ -867,3 +876,187 @@ def clear_default_letter_head():
"UPDATE `tabLetter Head` SET `is_default` = 0 WHERE `name` LIKE 'RMAX%'"
)
frappe.db.commit()
+
+
+def setup_ar_summary_print_format():
+ """Create a Jinja Print Format for Accounts Receivable Summary report."""
+ if not frappe.db.exists("Report", "Accounts Receivable Summary"):
+ return
+
+ pf_name = "RMAX AR Summary"
+ html = _get_ar_summary_print_html()
+
+ if frappe.db.exists("Print Format", pf_name):
+ frappe.db.set_value("Print Format", pf_name, "html", html, update_modified=False)
+ else:
+ pf = frappe.get_doc({
+ "doctype": "Print Format",
+ "name": pf_name,
+ "print_format_for": "Report",
+ "report": "Accounts Receivable Summary",
+ "doc_type": "Sales Invoice",
+ "print_format_type": "JS",
+ "standard": "No",
+ "module": "Rmax Custom",
+ "html": html,
+ })
+ pf.insert(ignore_permissions=True)
+
+ frappe.db.commit()
+
+
+def _get_ar_summary_print_html():
+ return r"""
+
+
+
+ Accounts Receivable Summary
+
+
+
+
+
+
+ {% if (filters.company) { %}{%= filters.company %}{% } %}
+
+Accounts Receivable Summary
+
+ {% if (filters.report_date) { %}
+ As of {%= frappe.datetime.str_to_user(filters.report_date) %}
+ {% } else { %}
+ As of {%= frappe.datetime.str_to_user(frappe.datetime.get_today()) %}
+ {% } %}
+
+
+
+
+
+
+ | Party Type |
+ Party |
+ Advance () |
+ Invoiced () |
+ Paid () |
+ Credit Note () |
+ Outstanding () |
+
+
+
+ {% var row_idx = 0; %}
+ {% var t_adv=0, t_inv=0, t_paid=0, t_cn=0, t_out=0, t_r1=0, t_r2=0, t_r3=0, t_r4=0, t_r5=0; %}
+
+ {% for (var i = 0; i < data.length; i++) { %}
+ {% var row = data[i]; %}
+ {% if (!row.party && !row.customer_name) { continue; } %}
+
+ {% var adv = flt(row.advance || 0); %}
+ {% var invoiced = flt(row.invoiced || 0); %}
+ {% var paid = flt(row.paid || 0); %}
+ {% var cn = flt(row.credit_note || 0); %}
+ {% var outstanding= flt(row.outstanding || 0); %}
+ {% var r1 = flt(row.range1 || 0); %}
+ {% var r2 = flt(row.range2 || 0); %}
+ {% var r3 = flt(row.range3 || 0); %}
+ {% var r4 = flt(row.range4 || 0); %}
+ {% var r5 = flt(row.range5 || 0); %}
+
+ {% t_adv+=adv; t_inv+=invoiced; t_paid+=paid; t_cn+=cn; t_out+=outstanding; %}
+ {% t_r1+=r1; t_r2+=r2; t_r3+=r3; t_r4+=r4; t_r5+=r5; %}
+
+ {% var cls = (row_idx % 2 === 0) ? "row-even" : "row-odd"; %}
+ {% row_idx++; %}
+
+
+ | {%= row.party_type || "" %} |
+ {%= row.customer_name || row.party || "" %} |
+ {%= adv ? format_currency(adv, " ").replace(/[^\d,.\-]/g, "").trim() : "-" %} |
+ {%= format_currency(invoiced, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(paid, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= cn ? format_currency(cn, " ").replace(/[^\d,.\-]/g, "").trim() : "-" %} |
+ {%= format_currency(outstanding, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+
+ {% } %}
+
+
+ | Total |
+ {%= format_currency(t_adv, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(t_inv, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(t_paid, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(t_cn, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(t_out, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+
+
+
+
+
+
+
+ Ageing Summary
+ {% if (filters.ageing_based_on) { %}(Based On: {%= filters.ageing_based_on %}){% } %}
+
+
+
+
+ | Less than 30 Days |
+ 31 to 60 Days |
+ 61 to 90 Days |
+ 91 to 120 Days |
+ More than 120 Days |
+ Total Outstanding |
+
+
+
+
+ | {%= format_currency(t_r1, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(t_r2, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(t_r3, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(t_r4, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(t_r5, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+ {%= format_currency(t_out, " ").replace(/[^\d,.\-]/g, "").trim() %} |
+
+
+
+
+
+
+
+
+
+
+"""