Merge pull request #53934 from Shllokkk/financial-statements-print-formats

feat: Financial Statements print format introduction
This commit is contained in:
Khushi Rawat
2026-05-08 12:05:24 +05:30
committed by GitHub
12 changed files with 1019 additions and 4 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1,224 @@
{% include "accounts/report/financial_statements.html" %} {%
const report_columns = report
.get_columns_for_print()
.filter(col => !col.hidden);
if (report_columns.length > 8) {
frappe.throw(
__("Too many columns. Export the report and print it using a spreadsheet application.")
);
}
%}
<style>
body, html {
margin-top: 10px;
padding: 0;
width: 100%;
height: auto;
font-family: Inter, sans-serif;
font-size: 14px;
line-height: 21px;
color: #171717;
}
.title-letter-spacing {
font-size: 15px;
font-weight: 600;
color: #171717;
}
.financial-statements-important td { font-weight: bold; }
.financial-statements-blank-row td { height: 20px; }
.report-meta {
margin: 10px 0 14px;
padding: 8px 10px;
display: flex;
justify-content: space-between;
font-size: 14px;
}
.report-meta .left,
.report-meta .right {
display: flex;
flex-direction: column;
}
.report-meta strong {
color: #7c7c7c;
font-weight: 500;
}
.report-subtitle {
margin: 10px 0 14px;
}
.text-center { text-align: center; }
.text-right {
text-align: right;
font-variant-numeric: tabular-nums;
}
.text-left { text-align: left; }
.text-bold { font-weight: 700; }
.report-table table {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
}
.report-table th,
.report-table td {
padding: 6px 8px;
font-size: 14px;
border-top: 1px solid #ededed;
border-bottom: 1px solid #ededed;
}
.report-table thead th {
background: #f8f8f8;
font-weight: 500;
color: #7c7c7c;
}
.report-table tbody td {
vertical-align: top;
word-wrap: break-word;
}
.report-table thead th:first-child {
border-left: 1px solid #ededed;
}
.report-table thead th:last-child {
border-right: 1px solid #ededed;
}
.report-table tbody tr:last-child td {
border-bottom: none;
}
@media print {
@page {
size: A4;
margin-top: 10mm;
}
thead { display: table-header-group; }
tr { page-break-inside: avoid; }
}
</style>
<div>
<div class="text-center" style="margin-bottom: 12px;">
<div class="title-letter-spacing">
{%= __(report.report_name) %}
</div>
</div>
{% if (subtitle && subtitle.trim()) { %}
<div class="report-subtitle">
{{ subtitle }}
</div>
{% } else { %}
<div class="report-meta">
<div class="left">
<div>
<strong>{%= __("Company") %}:</strong> {%= filters.company %}
</div>
<div>
<strong>{%= __("Currency") %}:</strong>
{%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
</div>
</div>
<div class="right text-right">
<div>
<strong>{%= __("Period Based On") %}:</strong>
{%= filters.filter_based_on %}
</div>
{% if (filters.filter_based_on === "Fiscal Year") { %}
<div>
<strong>{%= __("Start Year") %}:</strong> {%= filters.from_fiscal_year %}
</div>
<div>
<strong>{%= __("End Year") %}:</strong> {%= filters.to_fiscal_year %}
</div>
{% } else if (filters.filter_based_on === "Date Range") { %}
<div>
<strong>{%= __("Start Date") %}:</strong>
{%= frappe.datetime.str_to_user(filters.period_start_date) %}
</div>
<div>
<strong>{%= __("End Date") %}:</strong>
{%= frappe.datetime.str_to_user(filters.period_end_date) %}
</div>
{% } %}
</div>
</div>
{% } %}
<div class="report-table">
<table>
<thead>
<tr>
{% for (let i = 0, l = report_columns.length; i < l; i++) { %}
{%
const col = report_columns[i];
const align = i === 0 ? "text-left" : "text-right";
%}
<th class="{%= align %}">
{%= col.label %}
</th>
{% } %}
</tr>
</thead>
<tbody>
{% for (let j = 0, k = data.length; j < k; j++) { %}
{%
const row = data[j];
let row_class = "";
if (!(row.parent_account || row.parent_section)) {
row_class = "financial-statements-important";
}
if (!(row.account_name || row.section)) {
row_class += " financial-statements-blank-row";
}
%}
<tr class="{%= row_class %}">
{% for (let i = 0, l = report_columns.length; i < l; i++) { %}
{%
const col = report_columns[i];
const value = row[col.fieldname];
const align = i === 0 ? "text-left" : "text-right";
%}
<td class="{%= align %}">
{% if (i === 0) { %}
<span style="padding-left: {%= cint(row.indent) * 2 %}em">
{%= String(row.account_name || row.section || "").replace(/^['"]|['"]$/g, "") %}
</span>
{% } else if (!is_null(value)) { %}
{%= frappe.format(value, col, {}, row) %}
{% } %}
</td>
{% } %}
</tr>
{% } %}
</tbody>
</table>
</div>
<p class="text-right text-muted">
{%= __("Printed on {0}", [
frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string())
]) %}
</p>
</div>

View File

@@ -1 +1,224 @@
{% include "accounts/report/financial_statements.html" %} {%
const report_columns = report
.get_columns_for_print()
.filter(col => !col.hidden);
if (report_columns.length > 8) {
frappe.throw(
__("Too many columns. Export the report and print it using a spreadsheet application.")
);
}
%}
<style>
body, html {
margin-top: 10px;
padding: 0;
width: 100%;
height: auto;
font-family: Inter, sans-serif;
font-size: 14px;
line-height: 21px;
color: #171717;
}
.title-letter-spacing {
font-size: 15px;
font-weight: 600;
color: #171717;
}
.financial-statements-important td { font-weight: bold; }
.financial-statements-blank-row td { height: 20px; }
.report-meta {
margin: 10px 0 14px;
padding: 8px 10px;
display: flex;
justify-content: space-between;
font-size: 14px;
}
.report-meta .left,
.report-meta .right {
display: flex;
flex-direction: column;
}
.report-meta strong {
color: #7c7c7c;
font-weight: 500;
}
.report-subtitle {
margin: 10px 0 14px;
}
.text-center { text-align: center; }
.text-right {
text-align: right;
font-variant-numeric: tabular-nums;
}
.text-left { text-align: left; }
.text-bold { font-weight: 700; }
.report-table table {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
}
.report-table th,
.report-table td {
padding: 6px 8px;
font-size: 14px;
border-top: 1px solid #ededed;
border-bottom: 1px solid #ededed;
}
.report-table thead th {
background: #f8f8f8;
font-weight: 500;
color: #7c7c7c;
}
.report-table tbody td {
vertical-align: top;
word-wrap: break-word;
}
.report-table thead th:first-child {
border-left: 1px solid #ededed;
}
.report-table thead th:last-child {
border-right: 1px solid #ededed;
}
.report-table tbody tr:last-child td {
border-bottom: none;
}
@media print {
@page {
size: A4;
margin-top: 10mm;
}
thead { display: table-header-group; }
tr { page-break-inside: avoid; }
}
</style>
<div>
<div class="text-center" style="margin-bottom: 12px;">
<div class="title-letter-spacing">
{%= __(report.report_name) %}
</div>
</div>
{% if (subtitle && subtitle.trim()) { %}
<div class="report-subtitle">
{{ subtitle }}
</div>
{% } else { %}
<div class="report-meta">
<div class="left">
<div>
<strong>{%= __("Company") %}:</strong> {%= filters.company %}
</div>
<div>
<strong>{%= __("Currency") %}:</strong>
{%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
</div>
</div>
<div class="right text-right">
<div>
<strong>{%= __("Period Based On") %}:</strong>
{%= filters.filter_based_on %}
</div>
{% if (filters.filter_based_on === "Fiscal Year") { %}
<div>
<strong>{%= __("Start Year") %}:</strong> {%= filters.from_fiscal_year %}
</div>
<div>
<strong>{%= __("End Year") %}:</strong> {%= filters.to_fiscal_year %}
</div>
{% } else if (filters.filter_based_on === "Date Range") { %}
<div>
<strong>{%= __("Start Date") %}:</strong>
{%= frappe.datetime.str_to_user(filters.period_start_date) %}
</div>
<div>
<strong>{%= __("End Date") %}:</strong>
{%= frappe.datetime.str_to_user(filters.period_end_date) %}
</div>
{% } %}
</div>
</div>
{% } %}
<div class="report-table">
<table>
<thead>
<tr>
{% for (let i = 0, l = report_columns.length; i < l; i++) { %}
{%
const col = report_columns[i];
const align = i === 0 ? "text-left" : "text-right";
%}
<th class="{%= align %}">
{%= col.label %}
</th>
{% } %}
</tr>
</thead>
<tbody>
{% for (let j = 0, k = data.length; j < k; j++) { %}
{%
const row = data[j];
let row_class = "";
if (!(row.parent_account || row.parent_section)) {
row_class = "financial-statements-important";
}
if (!(row.account_name || row.section)) {
row_class += " financial-statements-blank-row";
}
%}
<tr class="{%= row_class %}">
{% for (let i = 0, l = report_columns.length; i < l; i++) { %}
{%
const col = report_columns[i];
const value = row[col.fieldname];
const align = i === 0 ? "text-left" : "text-right";
%}
<td class="{%= align %}">
{% if (i === 0) { %}
<span style="padding-left: {%= cint(row.indent) * 2 %}em">
{%= String(row.account_name || row.section || "").replace(/^['"]|['"]$/g, "") %}
</span>
{% } else if (!is_null(value)) { %}
{%= frappe.format(value, col, {}, row) %}
{% } %}
</td>
{% } %}
</tr>
{% } %}
</tbody>
</table>
</div>
<p class="text-right text-muted">
{%= __("Printed on {0}", [
frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string())
]) %}
</p>
</div>

View File

@@ -1 +1,224 @@
{% include "accounts/report/financial_statements.html" %} {%
const report_columns = report
.get_columns_for_print()
.filter(col => !col.hidden);
if (report_columns.length > 8) {
frappe.throw(
__("Too many columns. Export the report and print it using a spreadsheet application.")
);
}
%}
<style>
body, html {
margin-top: 10px;
padding: 0;
width: 100%;
height: auto;
font-family: Inter, sans-serif;
font-size: 14px;
line-height: 21px;
color: #171717;
}
.title-letter-spacing {
font-size: 15px;
font-weight: 600;
color: #171717;
}
.financial-statements-important td { font-weight: bold; }
.financial-statements-blank-row td { height: 20px; }
.report-meta {
margin: 10px 0 14px;
padding: 8px 10px;
display: flex;
justify-content: space-between;
font-size: 14px;
}
.report-meta .left,
.report-meta .right {
display: flex;
flex-direction: column;
}
.report-meta strong {
color: #7c7c7c;
font-weight: 500;
}
.report-subtitle {
margin: 10px 0 14px;
}
.text-center { text-align: center; }
.text-right {
text-align: right;
font-variant-numeric: tabular-nums;
}
.text-left { text-align: left; }
.text-bold { font-weight: 700; }
.report-table table {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
}
.report-table th,
.report-table td {
padding: 6px 8px;
font-size: 14px;
border-top: 1px solid #ededed;
border-bottom: 1px solid #ededed;
}
.report-table thead th {
background: #f8f8f8;
font-weight: 500;
color: #7c7c7c;
}
.report-table tbody td {
vertical-align: top;
word-wrap: break-word;
}
.report-table thead th:first-child {
border-left: 1px solid #ededed;
}
.report-table thead th:last-child {
border-right: 1px solid #ededed;
}
.report-table tbody tr:last-child td {
border-bottom: none;
}
@media print {
@page {
size: A4;
margin-top: 10mm;
}
thead { display: table-header-group; }
tr { page-break-inside: avoid; }
}
</style>
<div>
<div class="text-center" style="margin-bottom: 12px;">
<div class="title-letter-spacing">
{%= __(report.report_name) %}
</div>
</div>
{% if (subtitle && subtitle.trim()) { %}
<div class="report-subtitle">
{{ subtitle }}
</div>
{% } else { %}
<div class="report-meta">
<div class="left">
<div>
<strong>{%= __("Company") %}:</strong> {%= filters.company %}
</div>
<div>
<strong>{%= __("Currency") %}:</strong>
{%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
</div>
</div>
<div class="right text-right">
<div>
<strong>{%= __("Period Based On") %}:</strong>
{%= filters.filter_based_on %}
</div>
{% if (filters.filter_based_on === "Fiscal Year") { %}
<div>
<strong>{%= __("Start Year") %}:</strong> {%= filters.from_fiscal_year %}
</div>
<div>
<strong>{%= __("End Year") %}:</strong> {%= filters.to_fiscal_year %}
</div>
{% } else if (filters.filter_based_on === "Date Range") { %}
<div>
<strong>{%= __("Start Date") %}:</strong>
{%= frappe.datetime.str_to_user(filters.period_start_date) %}
</div>
<div>
<strong>{%= __("End Date") %}:</strong>
{%= frappe.datetime.str_to_user(filters.period_end_date) %}
</div>
{% } %}
</div>
</div>
{% } %}
<div class="report-table">
<table>
<thead>
<tr>
{% for (let i = 0, l = report_columns.length; i < l; i++) { %}
{%
const col = report_columns[i];
const align = i === 0 ? "text-left" : "text-right";
%}
<th class="{%= align %}">
{%= col.label %}
</th>
{% } %}
</tr>
</thead>
<tbody>
{% for (let j = 0, k = data.length; j < k; j++) { %}
{%
const row = data[j];
let row_class = "";
if (!(row.parent_account || row.parent_section)) {
row_class = "financial-statements-important";
}
if (!(row.account_name || row.section)) {
row_class += " financial-statements-blank-row";
}
%}
<tr class="{%= row_class %}">
{% for (let i = 0, l = report_columns.length; i < l; i++) { %}
{%
const col = report_columns[i];
const value = row[col.fieldname];
const align = i === 0 ? "text-left" : "text-right";
%}
<td class="{%= align %}">
{% if (i === 0) { %}
<span style="padding-left: {%= cint(row.indent) * 2 %}em">
{%= String(row.account_name || row.section || "").replace(/^['"]|['"]$/g, "") %}
</span>
{% } else if (!is_null(value)) { %}
{%= frappe.format(value, col, {}, row) %}
{% } %}
</td>
{% } %}
</tr>
{% } %}
</tbody>
</table>
</div>
<p class="text-right text-muted">
{%= __("Printed on {0}", [
frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string())
]) %}
</p>
</div>

View File

@@ -1 +1,215 @@
{% include "accounts/report/financial_statements.html" %} {%
const report_columns = report
.get_columns_for_print()
.filter(col => !col.hidden);
if (report_columns.length > 8) {
frappe.throw(
__("Too many columns. Export the report and print it using a spreadsheet application.")
);
}
%}
<style>
body, html {
margin-top: 10px;
padding: 0;
width: 100%;
height: auto;
font-family: Inter, sans-serif;
font-size: 14px;
line-height: 21px;
color: #171717;
}
.title-letter-spacing {
font-size: 15px;
font-weight: 600;
color: #171717;
}
.financial-statements-important td { font-weight: bold; }
.financial-statements-blank-row td { height: 20px; }
.report-meta {
margin: 10px 0 14px;
padding: 8px 10px;
display: flex;
justify-content: space-between;
font-size: 14px;
}
.report-meta .left,
.report-meta .right {
display: flex;
flex-direction: column;
}
.report-meta strong {
color: #7c7c7c;
font-weight: 500;
}
.report-subtitle {
margin: 10px 0 14px;
}
.text-center { text-align: center; }
.text-right {
text-align: right;
font-variant-numeric: tabular-nums;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.text-left { text-align: left; }
.text-bold { font-weight: 700; }
.report-table table {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
}
.report-table th,
.report-table td {
padding: 6px 8px;
font-size: 14px;
border-top: 1px solid #ededed;
border-bottom: 1px solid #ededed;
}
.report-table thead th {
background: #f8f8f8;
font-weight: 500;
color: #7c7c7c;
}
.report-table tbody td.text-left {
vertical-align: top;
word-wrap: break-word;
}
.report-table thead th:first-child {
border-left: 1px solid #ededed;
}
.report-table thead th:last-child {
border-right: 1px solid #ededed;
}
.report-table tbody tr:last-child td {
border-bottom: none;
}
@media print {
@page {
size: A4;
margin-top: 10mm;
}
thead { display: table-header-group; }
tr { page-break-inside: avoid; }
}
</style>
<div>
<div class="text-center" style="margin-bottom: 12px;">
<div class="title-letter-spacing">
{%= __(report.report_name) %}
</div>
</div>
{% if (subtitle && subtitle.trim()) { %}
<div class="report-subtitle">
{{ subtitle }}
</div>
{% } else { %}
<div class="report-meta">
<div class="left">
<div>
<strong>{%= __("Company") %}:</strong> {%= filters.company %}
</div>
<div>
<strong>{%= __("Currency") %}:</strong>
{%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
</div>
</div>
<div class="right text-right">
<div>
<strong>{%= __("From Date") %}:</strong>
{%= frappe.datetime.str_to_user(filters.from_date) %}
</div>
<div>
<strong>{%= __("To Date") %}:</strong>
{%= frappe.datetime.str_to_user(filters.to_date) %}
</div>
</div>
</div>
{% } %}
<div class="report-table">
<table>
<thead>
<tr>
{% for (let i = 0, l = report_columns.length; i < l; i++) { %}
{%
const col = report_columns[i];
const align = i === 0 ? "text-left" : "text-right";
const styling = i === 0 ? "" : "width: 9em";
%}
<th class="{%= align %}" style= "{%= styling%}">
{%= col.label %}
</th>
{% } %}
</tr>
</thead>
<tbody>
{% for (let j = 0, k = data.length; j < k; j++) { %}
{%
const row = data[j];
let row_class = "";
if (!(row.parent_account || row.parent_section)) {
row_class = "financial-statements-important";
}
if (!(row.account_name || row.section)) {
row_class += " financial-statements-blank-row";
}
%}
<tr class="{%= row_class %}">
{% for (let i = 0, l = report_columns.length; i < l; i++) { %}
{%
const col = report_columns[i];
const value = row[col.fieldname];
const align = i === 0 ? "text-left" : "text-right";
%}
<td class="{%= align %}">
{% if (i === 0) { %}
<span style="padding-left: {%= cint(row.indent) * 2 %}em">
{%= String(row.account_name || row.section || "").replace(/^['"]|['"]$/g, "") %}
</span>
{% } else if (!is_null(value)) { %}
{%= frappe.format(value, col, {}, row) %}
{% } %}
</td>
{% } %}
</tr>
{% } %}
</tbody>
</table>
</div>
<p class="text-right text-muted">
{%= __("Printed on {0}", [
frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string())
]) %}
</p>
</div>