Sebastian Walz 860d31cee1
Tohu vaBohu
2023-04-21 00:22:52 +02:00

226 lines
9.8 KiB
Nix
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ core, ... }:
{ balance, balance', balanceToTransaction, from, outcome, ... }:
let
inherit(core) list set string time;
inherit(time) formatDate;
concatLines'
= function: lines: string.concatLines (list.filter (value: value != null) (list.map function lines));
lineLength = 111;
padNameValue#: string -> string
= name:
value:
currency:
extra:
let
value' = string.from value;
nameLength = string.lengthUTF8 name;
valueLength = ( string.length value' ) - 4;
currencyLength = string.lengthUTF8 currency;
length = lineLength - nameLength - valueLength - currencyLength - extra - 2;
padding = string.repeat " " length;
theValue = string.slice 0 valueLength value';
theValue' = if theValue == "-0.00" then " 0.00" else theValue;
in
"${name}:${padding}${theValue'} ${currency}";
listSectionTotal'#: int -> T -> string
# where T: { title: string, accounts: [ T | { name: string, ... } ], ... }
= { ... } @ self:
negative:
depth:
{ title, accounts, ... } @ this:
let
entries = listSectionTotal self negative ( depth + 1 ) accounts;
in
if entries != ""
then
" ${string.repeat " " depth}${title}:\n${entries}"
else
null;
listSectionTotal#: int -> T -> string
# where T: { title: string, accounts: [ T | { name: string, ... } ], ... }
= { currency, events ? {}, ... } @ self:
negative:
depth:
concatLines'
(
{ ... } @ entry:
let
filterSection = events.filterSection or ({ ... }: true);
total
= if negative
then
-entry.total
else
entry.total;
in
if entry ? name
then
" ${padNameValue "${string.repeat " " depth}${entry.name}" total currency 2}"
else if filterSection entry
then
listSectionTotal' self negative depth entry
else
" ${padNameValue "${string.repeat " " depth}${entry.title}" total currency 2}"
);
formatBalance#: Self -> Date -> string
= dateTime:
self:
formatBalance' ( balance dateTime self );
formatBalance'#: Self -> string
= { name, currency, dateTime, assets, liabilities, outcome, journal, events ? {}, ... } @ self:
let
formatBalanceTitle
= events.formatBalanceTitle
or (
{ name, dateTime, ...}:
"Consolidated Statement Finance Positions of ${name} as of ${formatDate dateTime "eng"}"
);
title = formatBalanceTitle { inherit name dateTime; };
formatAccountNames
= events.formatAccountNames
or (
{ ... }:
{
balance = "Assets, Liabilities and Equity";
outcome = "Expenses and Revenues";
revenues = "Revenues";
expenses = "Expenses";
}
);
formatBalanceNames
= events.formatBalanceNames
or (
{ ... }:
{
credit = "Credit";
debit = "Debit";
total = "Total";
}
);
filterSection = events.filterSection or ( { ... }: true );
accountNames = formatAccountNames {};
balanceNames = formatBalanceNames {};
listSections'#: [ Transaction ] -> bool -> int -> T -> string
# where T: { title: string, accounts: [ T | { name: string, ... } ], ... }
= allTransactions:
depth:
{ title, accounts, ... }:
let
entries = listSections allTransactions depth accounts;
in
if entries != ""
then
"${string.repeat " " depth} ${title}:\n${entries}"
else
null;
listSections#: [ Transaction ] -> bool -> int -> T -> string
# where T: { title: string, accounts: [ T | { name: string, ... } ], ... }
= allTransactions:
depth:
let
padding = string.repeat " " depth;
formatAccount#: int -> { name, credit, debit, total, ... } -> string
= { name, credit, debit, total, ... }:
let
listTransactions#: [ Transaction ] -> [ { amount: Amount, reference: int, ... } ] -> string
= journal:
list.concatMap
(
{ amount, reference, ... }:
let
transaction
= list.get allTransactions reference;
in
"\n${padding} ${padNameValue transaction.description amount currency ( 8 + 2 * depth )}"
)
journal;
in
if debit.journal != []
|| credit.journal != []
then
''
${padding} ${name}
${padding} ${balanceNames.debit}:${listTransactions debit.journal}
${padding} ${string.repeat "" (lineLength - 8 - 2 * depth)}
${padding} ${padNameValue balanceNames.total debit.total currency ( 8 + 2 * depth)}
${padding} ${balanceNames.credit}:${listTransactions credit.journal}
${padding} ${string.repeat "" (lineLength - 8 - 2 * depth)}
${padding} ${padNameValue balanceNames.total credit.total currency ( 8 + 2 * depth)}
''
else
null;
in
concatLines'
(
{ ... } @ entry:
if entry ? name
then
formatAccount entry
else
listSections' allTransactions ( depth + 1 ) entry
);
expensesAndRevenues = list.partition ({ total, ... }: total >= 0) outcome.accounts;
expenses = { title = accountNames.expenses; accounts = expensesAndRevenues.wrong; };
revenues = { title = accountNames.revenues; accounts = expensesAndRevenues.right; };
in
''
== ${accountNames.balance} ==
=== ${assets.title} ===
${listSections journal 0 assets.accounts}
=== ${liabilities.title} ===
${listSections journal 0 liabilities.accounts}
== ${accountNames.outcome} ==
=== ${expenses.title} ===
${listSections journal 0 expenses.accounts}
=== ${revenues.title} ===
${listSections journal 0 revenues.accounts}
== ${title} ==
=== ${assets.title} ===
${listSectionTotal self false 0 assets.accounts}
${string.repeat "=" ( lineLength - 2)}
${padNameValue balanceNames.total assets.total currency 2}
=== ${liabilities.title} ===
${listSectionTotal self true 0 liabilities.accounts}
${string.repeat "=" ( lineLength - 2)}
${padNameValue balanceNames.total (- liabilities.total) currency 2}
'';
formatOutcome#: Self -> { from: D, till: D } -> string
# where D -> DateTime
= { from, till } @ period:
self:
formatOutcome' (outcome period self);
formatOutcome'#: Self -> { from: D, till: D } -> string
# where D -> DateTime
= { name, currency, from, till, events, outcome, ... } @ self:
let
formatOutcomeTitle
= events.formatOutcomeTitle
or (
{ name, from, till, ...}:
"Income statement of ${name} between ${time.formatDate from "eng"} and ${time.formatDate till "eng"}"
);
title = formatOutcomeTitle { inherit name from till; };
total = -1.0 * outcome.total;
in
''
${formatBalance' self}
== ${title} ==
${listSectionTotal self true 0 outcome.accounts}
${string.repeat "=" ( lineLength - 2)}
${padNameValue outcome.title total currency 2}
'';
in
{ inherit formatBalance formatOutcome; }