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()) %} + {% } %} +
+ + + + + + + + + + + + + + + + {% 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++; %} + + + + + + + + + + + {% } %} + + + + + + + + + + +
Party TypePartyAdvance ()Invoiced ()Paid ()Credit Note ()Outstanding ()
{%= 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 Days31 to 60 Days61 to 90 Days91 to 120 DaysMore than 120 DaysTotal 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() %}
+
+ + + + + + +"""