Allow customising income report dates

This commit is contained in:
RunasSudo 2025-02-09 21:16:06 +11:00
parent 064f50e668
commit 12f1c85a81
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
2 changed files with 57 additions and 15 deletions

View File

@ -1,6 +1,6 @@
/* /*
DrCr: Web-based double-entry bookkeeping framework DrCr: Web-based double-entry bookkeeping framework
Copyright (C) 20222024 Lee Yingtong Li (RunasSudo) Copyright (C) 20222025 Lee Yingtong Li (RunasSudo)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU Affero General Public License as published by
@ -56,7 +56,7 @@ export class ReportingWorkflow {
transactionsForStage: Map<ReportingStage, Transaction[]> = new Map(); transactionsForStage: Map<ReportingStage, Transaction[]> = new Map();
reportsForStage: Map<ReportingStage, DrcrReport[]> = new Map(); reportsForStage: Map<ReportingStage, DrcrReport[]> = new Map();
async generate(session: ExtendedDatabase, dt?: string) { async generate(session: ExtendedDatabase, dt?: string, dtStart?: string) {
// ------------------------ // ------------------------
// TransactionsFromDatabase // TransactionsFromDatabase
@ -152,9 +152,23 @@ export class ReportingWorkflow {
// AccumulatedSurplusToEquity // AccumulatedSurplusToEquity
{ {
// Compute balances at end of last financial year // Compute balances at period start for TransactionsFromDatabase
const last_eofy_date = dayjs(db.metadata.eofy_date).subtract(1, 'year'); let dayBeforePeriodStart;
const balancesLastEofy = await totalBalancesAtDate(session, last_eofy_date.format('YYYY-MM-DD')); if (dtStart) {
dayBeforePeriodStart = dayjs(dtStart).subtract(1, 'day');
} else {
dayBeforePeriodStart = dayjs(db.metadata.eofy_date).subtract(1, 'year');
}
const balancesAtPeriodStart = await totalBalancesAtDate(session, dayBeforePeriodStart.format('YYYY-MM-DD'));
// Add balances at period start for OrdinaryAPITransactions
for (const transaction of this.transactionsForStage.get(ReportingStage.OrdinaryAPITransactions)!) {
if (!dayjs(transaction.dt).isAfter(dayBeforePeriodStart)) {
for (const posting of transaction.postings) {
balancesAtPeriodStart.set(posting.account, (balancesAtPeriodStart.get(posting.account) ?? 0) + asCost(posting.quantity, posting.commodity));
}
}
}
// Get income and expense accounts // Get income and expense accounts
const incomeAccounts = await getAccountsForKind(session, 'drcr.income'); const incomeAccounts = await getAccountsForKind(session, 'drcr.income');
@ -165,29 +179,29 @@ export class ReportingWorkflow {
// Prepare transactions // Prepare transactions
const transactions = []; const transactions = [];
for (const account of pandlAccounts) { for (const account of pandlAccounts) {
if (balancesLastEofy.has(account)) { if (balancesAtPeriodStart.has(account)) {
const balanceLastEofy = balancesLastEofy.get(account)!; const balanceAtPeriodStart = balancesAtPeriodStart.get(account)!;
if (balanceLastEofy === 0) { if (balanceAtPeriodStart === 0) {
continue; continue;
} }
transactions.push(new Transaction( transactions.push(new Transaction(
null, null,
last_eofy_date.format(DT_FORMAT), dayBeforePeriodStart.format(DT_FORMAT),
'Accumulated surplus/deficit', 'Accumulated surplus/deficit',
[ [
{ {
id: null, id: null,
description: null, description: null,
account: account, account: account,
quantity: -balanceLastEofy, quantity: -balanceAtPeriodStart,
commodity: db.metadata.reporting_commodity commodity: db.metadata.reporting_commodity
}, },
{ {
id: null, id: null,
description: null, description: null,
account: 'Accumulated surplus (deficit)', account: 'Accumulated surplus (deficit)',
quantity: balanceLastEofy, quantity: balanceAtPeriodStart,
commodity: db.metadata.reporting_commodity commodity: db.metadata.reporting_commodity
}, },
] ]

View File

@ -1,6 +1,6 @@
<!-- <!--
DrCr: Web-based double-entry bookkeeping framework DrCr: Web-based double-entry bookkeeping framework
Copyright (C) 20222024 Lee Yingtong Li (RunasSudo) Copyright (C) 20222025 Lee Yingtong Li (RunasSudo)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU Affero General Public License as published by
@ -57,25 +57,53 @@
<!-- Report display --> <!-- Report display -->
<template> <template>
<DynamicReportComponent :report="report" /> <DynamicReportComponent :report="report">
<div class="my-2 py-2 flex">
<div class="grow flex gap-x-2 items-baseline">
<input type="date" class="bordered-field" v-model="dtStart">
<span>to</span>
<input type="date" class="bordered-field" v-model="dt">
</div>
</div>
</DynamicReportComponent>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref, watch } from 'vue';
import dayjs from 'dayjs';
import { Computed, DynamicReport, Section, Spacer, Subtotal } from './base.ts'; import { Computed, DynamicReport, Section, Spacer, Subtotal } from './base.ts';
import { db } from '../db.ts'; import { db } from '../db.ts';
import { ExtendedDatabase } from '../dbutil.ts';
import DynamicReportComponent from '../components/DynamicReportComponent.vue'; import DynamicReportComponent from '../components/DynamicReportComponent.vue';
import { ReportingStage, ReportingWorkflow } from '../reporting.ts'; import { ReportingStage, ReportingWorkflow } from '../reporting.ts';
const report = ref(null as IncomeStatementReport | null); const report = ref(null as IncomeStatementReport | null);
const dt = ref(null as string | null);
const dtStart = ref(null as string | null);
async function load() { async function load() {
const session = await db.load(); const session = await db.load();
dt.value = db.metadata.eofy_date;
dtStart.value = dayjs(db.metadata.eofy_date).subtract(1, 'year').add(1, 'day').format('YYYY-MM-DD');
await updateReport(session);
}
async function updateReport(session: ExtendedDatabase) {
const reportingWorkflow = new ReportingWorkflow(); const reportingWorkflow = new ReportingWorkflow();
await reportingWorkflow.generate(session); await reportingWorkflow.generate(session, dt.value!, dtStart.value!);
report.value = reportingWorkflow.getReportAtStage(ReportingStage.InterimIncomeStatement, IncomeStatementReport) as IncomeStatementReport; report.value = reportingWorkflow.getReportAtStage(ReportingStage.InterimIncomeStatement, IncomeStatementReport) as IncomeStatementReport;
} }
// Update report when dates etc. changed
watch([dt, dtStart], async () => {
const session = await db.load();
updateReport(session);
});
load(); load();
</script> </script>