Compare commits

...

4 Commits

5 changed files with 76 additions and 20 deletions

View File

@ -62,6 +62,11 @@ From the main menu, click *Trial balance*. The trial balance now correctly shows
If we click *Balance sheet* from the main menu, the report will show zero balances for assets, liabilities and equity. This is because we have not configured *Cash on Hand* as an asset or *Opening Balances* as equity. We will do so now.
<table><tr>
<td></td>
<td>An account is not shown on the balance sheet or income statement, unless it is configured in the chart of accounts.</td>
</tr></table>
From the main menu, click *Chart of accounts*. The dropdown box at the top of the page is pre-populated with *Asset*. Select the checkbox next to *Cash on Hand*, and click *Add type*. The table updates to show that *Cash on Hand* is now configured as an asset account. Select the checkbox next to *Opening Balances*. Change the dropdown box from *Asset* to *Equity*, and click *Add type*. The table now shows:
&nbsp;|Account|Associated types
@ -95,6 +100,11 @@ Now add another transaction from the journal page:
If we now click *Balance sheet* from the main menu, a warning is displayed ‘Total assets do not equal total liabilities and equity.’ As the warning goes on to note, this is because the *Sales* account has not been configured.
<table><tr>
<td></td>
<td>If accounts with nonzero balances are not configured in the chart of accounts, the balance sheet may fail to balance.</td>
</tr></table>
Configure the *Sales* account as an income account in the chart of accounts.
Now, from the main menu, click *Income statement*. The income statement report is displayed:
@ -207,13 +217,20 @@ The statement lines page displays all previously imported statement lines.
To import a new statement, click *Import statement* on the statement lines page. This opens the statement importer. Supported formats are OFX (1.x/2.x) and CSV. A CSV file must contain the headers *Date* (YYYY-MM-DD), *Description*, *Amount*. When the statement lines are imported and eventually reconciled, they will be posted as transactions to the *Source account* specified on the statement importer. Increases to account balances will be converted to debits, and decreases will be converted to credits (note that this terminology is consistent with the accounting convention, but opposite to that conventionally shown on bank statements).
When a statement line is initially imported, it will be shown on the statement lines page as *Unclassified*. Click *Unclassified* to open the statement line reconciliation dropdown box, to select the corresponding account to charge the transaction to (e.g. an income or expense account). Reconciling a statement line will create a transaction in the journal (see [Journal](#journal)), and link the journal transaction with the statement line.
When a statement line is initially imported, it will be shown on the statement lines page as *Unclassified*. Unclassified statement lines will be automatically posted to the *Unreconciled Statement Line Debits* or *Unreconciled Statement Line Credits* account by default. It is recommended to configure these as income and expense accounts (see [Chart of accounts](#chart-of-accounts)).
<table><tr>
<td></td>
<td>It is recommended to configure <i>Unreconciled Statement Line Debits</i> as an income account, and <i>Unreconciled Statement Line Credits</i> as an expense account.</td>
</tr></table>
To reconcile a statement line, click *Unclassified* to open the statement line reconciliation dropdown box, and select the corresponding account to charge the transaction to (e.g. an income or expense account). Reconciling a statement line will create a transaction in the journal (see [Journal](#journal)), and link the journal transaction with the statement line.
If a statement line has already been reconciled, the statement lines page will display the name of the corresponding account. Clicking the pencil icon next to the name of the corresponding account will open the transaction editor for the corresponding journal transaction.
It is not currently possible to reconcile a single statement line to more than one corresponding account using multiple postings. It is suggested to first reconcile the statement line to one account, then open the transaction editor and edit the postings as required.
If there is a transfer between two accounts and both statements have been imported, there will be one imported statement line per account. To reconcile both statement lines as a single transfer between the two accounts, select the checkboxes to the left of the statement lines, and click *Reconcile selected as transfer*.
If there is a transfer between two accounts and both statements have been imported, there will be one imported statement line per account. To reconcile both statement lines as a single transfer between the two accounts, select the checkboxes to the left of the statement lines, and click *Reconcile selected as transfer*. The date and description of the resulting transaction will be that of the top-most selected statement line.
## Balance assertions
@ -225,6 +242,16 @@ The balance assertions page displays all existing balance assertions. The status
The chart of accounts page allows for accounts to be configured as particular types of accounts (asset, liability, equity, income, expense). To add a type to an account, select the checkbox to the left of the account name, choose the account type from the dropdown box, and click *Add type*. To remove a type from an account, select the checkbox to the left of the account name, choose the account type from the dropdown box, and click *Remove type*.
<table><tr>
<td></td>
<td>An account is not shown on the balance sheet or income statement, unless it is configured in the chart of accounts.</td>
</tr></table>
<table><tr>
<td></td>
<td>If accounts with nonzero balances are not configured in the chart of accounts, the balance sheet may fail to balance.</td>
</tr></table>
# 6. General reports
Functionality for generating common accounting reports is grouped within the ‘General reports’ panel of the main menu.
@ -251,6 +278,16 @@ If the compare unit is set to ‘months’, the report will be generated for the
For comparative balance sheet reports, *Current Year Earnings* and *Retained Earnings* will show financial year-to-date figures in each requested period.
<table><tr>
<td></td>
<td>An account is not shown on the balance sheet, unless it is configured in the chart of accounts as an asset, liability or equity (see <a href="#chart-of-accounts">Chart of accounts</a>).</td>
</tr></table>
<table><tr>
<td></td>
<td>If accounts with nonzero balances are not configured in the chart of accounts, the balance sheet may fail to balance.</td>
</tr></table>
## Income statement
The income statement report displays the balances of income and equity accounts (see [Chart of accounts](#chart-of-accounts)) for the period between two requested dates. The dates default to the financial year specified at database creation.
@ -262,3 +299,8 @@ If the compare unit is set to ‘years’, the start and end dates of the report
If the compare unit is set to ‘months’, the start and end dates of the report will each be shifted backwards by 1 calendar month for each comparison period. If the selected period is longer than 1 calendar month, the resulting report will include overlapping transactions in consecutive periods. If the selected period is shorter than 1 calendar month, the resulting report will have disjoint periods. The selected period should usually be set to 1 calendar month. If the specified start or end date exceeds the number of days in a previous month, the relevant date for that month will be set to the last day of the calendar month. For example, if the dates are set to 1–29 May and ‘Compare 3 months’ is requested, the report will be generated for 1–29 May, 1–28 Feb and 1–29 Jan. However, as an exception, if the specified end date is the last day of a calendar month, the end dates for all comparative reports will also be set to the last day of the calendar month. For example, if the dates are set to 1–30 Jun and ‘Compare 3 months’ is requested, the report will be generated for 1–30 Jun, 1–31 May and 1–30 Apr.
If the selected period is 1 calendar year and the compare unit is changed from ‘years’ to ‘months’, the selected period will automatically be changed to 1 calendar month ending on the original end date. Similarly, if the selected period is 1 calendar month and the compare unit is changed from ‘months’ to ‘years’, the selected period will automatically be changed to 1 calendar year ending on the original end date. The start date can be manually adjusted after changing the compare unit, if this is not the desired behaviour.
<table><tr>
<td></td>
<td>An account is not shown on the income statement, unless it is configured in the chart of accounts as income or an expense (see <a href="#chart-of-accounts">Chart of accounts</a>).</td>
</tr></table>

View File

@ -14,3 +14,5 @@ pub type QuantityInt = i64;
// TODO: Make this configurable
pub const CURRENT_YEAR_EARNINGS: &'static str = "Current Year Earnings";
pub const RETAINED_EARNINGS: &'static str = "Retained Earnings";
pub const UNCLASSIFIED_STATEMENT_LINE_CREDITS: &'static str = "Unclassified Statement Line Credits";
pub const UNCLASSIFIED_STATEMENT_LINE_DEBITS: &'static str = "Unclassified Statement Line Debits";

View File

@ -1,5 +1,5 @@
/*
DrCr: Web-based double-entry bookkeeping framework
DrCr: Double-entry bookkeeping framework
Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo)
This program is free software: you can redistribute it and/or modify
@ -31,7 +31,7 @@ use crate::model::transaction::{
};
use crate::reporting::types::{BalancesAt, DateStartDateEndArgs, ReportingProductId, Transactions};
use crate::util::{get_eofy, sofy_from_eofy};
use crate::QuantityInt;
use crate::{QuantityInt, UNCLASSIFIED_STATEMENT_LINE_CREDITS, UNCLASSIFIED_STATEMENT_LINE_DEBITS};
use super::calculator::ReportingGraphDependencies;
use super::dynamic_report::{entries_for_kind, DynamicReport, DynamicReportEntry, Row, Section};
@ -1238,9 +1238,9 @@ impl ReportingStep for PostUnreconciledStatementLines {
for line in unreconciled_statement_lines {
let unclassified_account = if line.quantity >= 0 {
"Unclassified Statement Line Debits"
UNCLASSIFIED_STATEMENT_LINE_DEBITS
} else {
"Unclassified Statement Line Credits"
UNCLASSIFIED_STATEMENT_LINE_CREDITS
};
transactions.transactions.push(TransactionWithPostings {
transaction: Transaction {
@ -1519,7 +1519,7 @@ impl ReportingStep for TrialBalance {
// Add entry for each account
let mut section = Section {
text: None,
id: None,
id: Some("accounts".to_string()),
visible: true,
entries: Vec::new(),
};

View File

@ -1,5 +1,5 @@
<!--
DrCr: Web-based double-entry bookkeeping framework
DrCr: Double-entry bookkeeping framework
Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo)
This program is free software: you can redistribute it and/or modify
@ -57,11 +57,13 @@
</template>
<script setup lang="ts">
import { invoke } from '@tauri-apps/api/core';
import { computed, ref } from 'vue';
import { drcrAccountKinds, getAccountKinds } from '../registry.ts';
import { db } from '../db.ts';
import DropdownBox from '../components/DropdownBox.vue';
import { DynamicReport, reportEntryById, Row, Section } from '../reports/base.ts';
const accountKinds = ref([...drcrAccountKinds]);
const accountKindsMap = computed(() => new Map(accountKinds.value));
@ -74,19 +76,26 @@
async function loadAccountConfigurations() {
const session = await db.load();
const accountKindsRaw: {account: string, kind: string | null}[] = await session.select(
`SELECT q1.account, q2.kind FROM
(SELECT account FROM account_configurations UNION SELECT account FROM postings ORDER BY account) q1
LEFT JOIN account_configurations q2 ON q1.account = q2.account`
);
// Get all accounts on the trial balance
const trialBalance = JSON.parse(await invoke('get_trial_balance', { date: '9999-12-31' })) as DynamicReport;
const trialBalanceAccounts = (reportEntryById(trialBalance, 'accounts') as { Section: Section }).Section.entries.map((e) => (e as { Row: Row }).Row.text);
for (const accountKindRaw of accountKindsRaw) {
const kinds = accounts.value.get(accountKindRaw.account) ?? [];
if (accountKindRaw.kind !== null) {
kinds.push(accountKindRaw.kind);
}
accounts.value.set(accountKindRaw.account, kinds);
// Get all configured account kinds
const accountKindsRaw: {account: string, kind: string}[] = await session.select(
`SELECT account, kind FROM account_configurations`
);
const accountKindsMap = Map.groupBy(accountKindsRaw, (a) => a.account);
// Include all accounts on the trial balance or which have configurations
const combinedAccountNames = [...new Set([...trialBalanceAccounts, ...accountKindsMap.keys()])];
combinedAccountNames.sort();
const accountKinds = new Map();
for (const accountName of combinedAccountNames) {
accountKinds.set(accountName, accountKindsMap.get(accountName)?.map((a) => a.kind) ?? []);
}
accounts.value = accountKinds;
}
async function loadAccountKinds() {

View File

@ -1,5 +1,5 @@
/*
DrCr: Web-based double-entry bookkeeping framework
DrCr: Double-entry bookkeeping framework
Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo)
This program is free software: you can redistribute it and/or modify
@ -51,6 +51,9 @@ export interface Spacer {
export function reportEntryById(report: DynamicReport | Section, id: string): DynamicReportEntry | null {
for (const entry of report.entries) {
if ((entry as { Section: Section }).Section) {
if ((entry as { Section: Section }).Section.id === id) {
return entry;
}
const result = reportEntryById((entry as { Section: Section }).Section, id);
if (result !== null) {
return result;