Accounting
Analysis and generation of bookkeeping data according to Swedish standards.
Install / Use
/learn @byrokrat/AccountingREADME
Accounting
Analysis and generation of bookkeeping data according to Swedish standards.
Installation
composer require byrokrat/accounting
Why?
Although it would be possible to build a general bookkeeping application on top of Accounting this was never the primary concern. The motivation for creating Accounting was to provide solutions for two scenarios:
- The need to generate bookkeeping data using templates (and possibly import to general bookkeeping).
- The need to analyze accounting data (possibly exported from general bookkeeping).
To enable import and export of bookkeeping data Accounting supports parsing and generating files in the SIE4 file format.
Usage
- Generating accounting data using templates
- Handling monetary amounts
- Writing SIE4 files
- Parsing SIE4 files
- Querying accounting data
- Writing macros
Handling monetary amounts
Accounting uses Moneyphp to hande monetary amounts. More
information on the money api can be found on their website. In these examples
we need to format amounts, wich we do using the simple DecimalMoneyFormatter.
use Money\Formatter\DecimalMoneyFormatter;
use Money\Currencies\ISOCurrencies;
$moneyFormatter = new DecimalMoneyFormatter(new ISOCurrencies());
Generating accounting data using templates
First we create an accounting template. Values enclosed in curly braces {}
are placeholders for values supplied at render time.
use byrokrat\accounting\Template\TransactionTemplate;
use byrokrat\accounting\Template\VerificationTemplate;
$template = new VerificationTemplate(
description: '{description}',
transactionDate: '{date}',
transactions: [
new TransactionTemplate(
account: '1920',
amount: '{bank_amount}'
),
new TransactionTemplate(
account: '{income_account}',
amount: '{income_amount}'
)
]
);
Create an account plan, a set of accounts.
<!-- @example accounts @include template -->use byrokrat\accounting\Container;
use byrokrat\accounting\Dimension\Account;
$accounts = new Container(
new Account(id: '1920', description: 'Bank'),
new Account(id: '3000', description: 'Incomes'),
new Account(id: '3010', description: 'Sales'),
);
And to render verifications we supply a list of translation values and the account plan.
<!-- @example verifications @include accounts -->use byrokrat\accounting\Template\TemplateRendererFactory;
use byrokrat\accounting\Template\Translator;
$renderer = (new TemplateRendererFactory)->createRenderer($accounts);
$verifications = new Container(
$renderer->render(
$template,
new Translator([
'description' => 'Some donation...',
'date' => '2021-01-12',
'bank_amount' => '999',
'income_amount' => '-999',
'income_account' => '3000'
])
),
$renderer->render(
$template,
new Translator([
'description' => 'Daily cash register',
'date' => '2021-01-12',
'bank_amount' => '333',
'income_amount' => '-333',
'income_account' => '3010'
])
)
);
Writing SIE4 files
<!-- @example sie-generated @include verifications -->use byrokrat\accounting\Sie4\Writer\Sie4iWriter;
$sie = (new Sie4iWriter)->generateSie($verifications);
Parsing SIE4 files
<!-- @example sie-parsed @include sie-generated @expectOutput "/Some donation.../" -->use byrokrat\accounting\Sie4\Parser\Sie4Parser;
$parser = new Sie4Parser();
$container = $parser->parse($sie);
echo $container->select()->verifications()->first()->getDescription();
Querying accounting data
Listing accounts
<!-- @example list-accounts @include verifications -->$orderedAccounts = $verifications->select()->accounts()->orderById()->asArray();
Calculate book magnitude
<!-- @example calculate-magnitude @include verifications @include moneyFormatter @expectOutput "1332.00" -->echo $moneyFormatter->format(
$verifications->select()->verifications()->asSummary()->getMagnitude()
);
Sorting transactions into a ledger (huvudbok)
An example of how Accounting may be used to sort transactions inte a ledger (or huvudbok as it is known in swedish).
<!-- @example ledger @include verifications @include moneyFormatter @expectOutput "/Outgoing balance 1332.00/" -->$verifications->select()->accounts()->orderById()->each(function ($account) use ($moneyFormatter) {
printf(
"%s %s\nIncoming balance %s\n",
$account->getId(),
$account->getDescription(),
$moneyFormatter->format($account->getSummary()->getIncomingBalance())
);
foreach ($account->getTransactions() as $trans) {
printf(
"%s\t%s\t%s\n",
$trans->getVerificationId(),
$account->getDescription(),
$moneyFormatter->format($trans->getAmount()),
);
}
printf(
"Outgoing balance %s\n\n",
$moneyFormatter->format($account->getSummary()->getOutgoingBalance())
);
});
Writing macros
Macros expose the posibility to extend the query api on the fly, without having to subclass the Query class itself. It is suitable for adding project specific order and filter methods. If we for example whant to filter on description we can define a macro for this:
<!-- @example register-macro -->use byrokrat\accounting\Query;
Query::macro('filterOnDescription', function (string $desc) {
return $this->filter(
fn($item) => str_contains($item->getDescription(), $desc)
);
});
And then use it to query accounting data:
<!-- @example filterOnDescription @include verifications @include register-macro @expectOutput "/Some donation.../" -->echo $verifications->select()->filterOnDescription('donation')->first()->getDescription();
Hacking
With composer installed as composer and
phive installed as phive
make
Or use something like
make COMPOSER_CMD=./composer.phar PHIVE_CMD=./phive.phar
