diff --git a/src/pages/accounting/AccountingReportsPage.tsx b/src/pages/accounting/AccountingReportsPage.tsx
index 2f0ef71..dc9c79b 100644
--- a/src/pages/accounting/AccountingReportsPage.tsx
+++ b/src/pages/accounting/AccountingReportsPage.tsx
@@ -676,7 +676,7 @@ export default function AccountingReportsPage({ association }: { association?: {
)}
{active === "pnl" && pnlMonthView && (
-
+
)}
{active === "trial-balance" && (
@@ -853,6 +853,14 @@ function isBuildPeriods(from: string, to: string, gran: ISGran): { key: string;
return out;
}
+/** First day of the fiscal year that contains `to`, given an "MM-DD" FY start. */
+function isFyStartFor(to: string, fyStart: string): string {
+ const [mm, dd] = (fyStart || "01-01").split("-").map(Number);
+ const ty = Number(to.slice(0, 4));
+ const candidate = `${ty}-${isPad2(mm || 1)}-${isPad2(dd || 1)}`;
+ return to >= candidate ? candidate : `${ty - 1}-${isPad2(mm || 1)}-${isPad2(dd || 1)}`;
+}
+
/** Period key a given YYYY-MM-DD date falls into, for the chosen granularity. */
function isPeriodKey(date: string, gran: ISGran): string {
if (gran === "month") return date.slice(0, 7);
@@ -898,22 +906,31 @@ function isGroupAccts(accts: ISAcct[], periods: { key: string }[]): ISGroup[] {
return groups;
}
-function IncomeStatementReport({ companyId, companyName, from, to, currency, logoUrl }: {
- companyId: string; companyName: string; from: string; to: string; currency: string; logoUrl?: string | null;
+function IncomeStatementReport({ companyId, companyName, from, to, fiscalYearStart, currency, logoUrl }: {
+ companyId: string; companyName: string; from: string; to: string; fiscalYearStart?: string; currency: string; logoUrl?: string | null;
}) {
const [gran, setGran] = useState("month");
+ // The point of the monthly P&L is a column per period. If the page Period is a
+ // single month (the default), there'd be just one column — so widen the start
+ // to the fiscal year containing `to`, giving every month of the FY-to-date.
+ // A multi-month selected range is respected as-is.
+ const effFrom = useMemo(
+ () => (from.slice(0, 7) === to.slice(0, 7) ? isFyStartFor(to, fiscalYearStart || "01-01") : from),
+ [from, to, fiscalYearStart],
+ );
+
const { data: glLines = [], isLoading } = useQuery({
- queryKey: ["income-statement-gl", companyId, from, to],
+ queryKey: ["income-statement-gl", companyId, effFrom, to],
enabled: !!companyId,
queryFn: () => fetchAllGLLines(
companyId, to,
"id,debit,credit,accounts!inner(id,name,code,type,category),journal_entries!inner(company_id,date)",
- from,
+ effFrom,
),
});
- const periods = useMemo(() => isBuildPeriods(from, to, gran), [from, to, gran]);
+ const periods = useMemo(() => isBuildPeriods(effFrom, to, gran), [effFrom, to, gran]);
const model = useMemo(() => {
const accts = new Map();
@@ -942,7 +959,7 @@ function IncomeStatementReport({ companyId, companyName, from, to, currency, log
return { incomeGroups, expenseGroups, incTot, expTot, net, hasRows: income.length > 0 || expense.length > 0 };
}, [glLines, periods, gran]);
- const subtitle = `${fmtDate(from)} – ${fmtDate(to)}, By ${gran[0].toUpperCase()}${gran.slice(1)}, Accrual basis`;
+ const subtitle = `${fmtDate(effFrom)} – ${fmtDate(to)}, By ${gran[0].toUpperCase()}${gran.slice(1)}, Accrual basis`;
const { hasRows } = model;
const exportPdf = async () => {
@@ -995,7 +1012,7 @@ function IncomeStatementReport({ companyId, companyName, from, to, currency, log
},
});
drawBrandedFooter(doc);
- doc.save(`profit-loss-${gran}-${from}-to-${to}.pdf`);
+ doc.save(`profit-loss-${gran}-${effFrom}-to-${to}.pdf`);
};
const exportCsv = () => {
@@ -1019,7 +1036,7 @@ function IncomeStatementReport({ companyId, companyName, from, to, currency, log
const blob = new Blob([lines.join("\n")], { type: "text/csv" });
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
- a.download = `profit-loss-${gran}-${from}-to-${to}.csv`;
+ a.download = `profit-loss-${gran}-${effFrom}-to-${to}.csv`;
a.click();
URL.revokeObjectURL(a.href);
};