Daily cash register
The end-of-day report of a cash register becomes one cash transaction: the sales per VAT rate, the expenses paid from the till, and the difference between the cash count and the calculated balance.
Twinfield documentation: Cash transactions.
The report has amounts including VAT; the example splits them into amount and VAT with bcmath and books them with receive() and pay(). The closing balance must be what was counted, so a difference goes to a cash differences account.
Change the accounts and VAT codes at the top to those of your administration. By default it is a dry run; add --save to create the transaction as provisional. Pass the counted amount as first argument, e.g. 940.00.
$twinfield = Example::twinfield();
// The end-of-day report of the cash register: sales per VAT rate, including VAT.$sales = [ ['account' => '8000', 'vatCode' => 'VH', 'rate' => '21', 'gross' => '605.00', 'text' => 'Sales 21% VAT'], ['account' => '8010', 'vatCode' => 'VL', 'rate' => '9', 'gross' => '109.00', 'text' => 'Sales 9% VAT'],];$expenses = [ ['account' => '4300', 'vatCode' => 'IH', 'rate' => '21', 'gross' => '24.20', 'text' => 'Coffee and milk'],];$opening = Amount::of('250.00');$counted = Amount::fromString($argv[1] ?? '939.50');
// Amount without VAT: gross × 100 / (100 + rate), rounded half up to cents; and the VAT.$split = static function (Amount $gross, Amount $rate): array { $net = Amount::of(bcadd(bcdiv(bcmul($gross->value, '100', 6), bcadd('100', $rate->value, 6), 6), '0.005', 2));
return [$net, $gross->minus($net)];};
$input = CashTransactionInput::create('KAS', '1000', new DateTimeImmutable('2026-11-03')) ->statement(311, startValue: $opening) ->description('Cash register 3 November');
foreach ($sales as $line) { [$net, $vat] = $split(Amount::of($line['gross']), Amount::of($line['rate'])); $input = $input->receive( $line['account'], $net, vatCode: $line['vatCode'], vatValue: $vat, description: $line['text'], );
echo sprintf('+ %8s = %8s + VAT %6s %s', $line['gross'], $net, $vat, $line['text']), PHP_EOL;}
foreach ($expenses as $line) { [$net, $vat] = $split(Amount::of($line['gross']), Amount::of($line['rate'])); $input = $input->pay($line['account'], $net, vatCode: $line['vatCode'], vatValue: $vat, description: $line['text']);
echo sprintf('- %8s = %8s + VAT %6s %s', $line['gross'], $net, $vat, $line['text']), PHP_EOL;}
// The cash count decides the closing balance; book the difference.$difference = $counted->minus($input->closeValue() ?? $opening);
if (!$difference->isZero()) { $input = $difference->isNegative() ? $input->pay('8990', $difference->absolute(), description: 'Cash difference') : $input->receive('8990', $difference, description: 'Cash difference');
echo 'Cash difference: ', $difference, PHP_EOL;}
echo 'Cash: ', $opening, ' → ', $input->closeValue(), ' (counted ', $counted, ')', PHP_EOL;
if (!in_array('--save', $argv ?? [], true)) { echo PHP_EOL, 'Dry run; add --save to create it as provisional transaction:', PHP_EOL, PHP_EOL; echo Example::xml($input->toXml($twinfield->companyCode() ?? '')), PHP_EOL;
exit(0);}
$transaction = $twinfield->cashTransactions()->create($input);
echo 'Created provisional transaction ', $transaction->dayBook(), ' ', $transaction->number(), PHP_EOL;php examples/cash-transactions/daily-cash-register/example.php+ 605.00 = 500.00 + VAT 105.00 Sales 21% VAT+ 109.00 = 100.00 + VAT 9.00 Sales 9% VAT- 24.20 = 20.00 + VAT 4.20 Coffee and milkCash difference: -0.30Cash: 250.00 → 939.50 (counted 939.50)
Dry run; add --save to create it as provisional transaction:
<transaction destiny="temporary"> <header> <office>1002</office> <code>KAS</code> <date>20261103</date> <statementnumber>311</statementnumber> <startvalue>250.00</startvalue> <closevalue>939.50</closevalue> </header> <lines> <line type="total" id="1"> <dim1>1000</dim1> <debitcredit>debit</debitcredit> <value>689.50</value> <description>Cash register 3 November</description> </line> <line type="detail" id="2"> <dim1>8000</dim1> <debitcredit>credit</debitcredit> <value>500.00</value> <description>Sales 21% VAT</description> <vatcode>VH</vatcode> <vatvalue>105.00</vatvalue> </line> <line type="detail" id="3"> <dim1>8010</dim1> <debitcredit>credit</debitcredit> <value>100.00</value> <description>Sales 9% VAT</description> <vatcode>VL</vatcode> <vatvalue>9.00</vatvalue> </line>…What the SDK sends to Twinfield and what Twinfield sends back, for a call like the one in this example. The responses come from the tests, with example data.
Create
Section titled “Create”Twinfield documentation: Cash transactions: Create.
$twinfield->cashTransactions()->create( CashTransactionInput::create('KAS', '1000', new DateTimeImmutable('2026-11-03')) ->statement(311, startValue: '250.00') ->description('Cash register 3 November') ->receive('8000', '500.00', vatCode: 'VH', vatValue: '105.00', description: 'Sales 21% VAT') ->receive('8010', '100.00', vatCode: 'VL', vatValue: '9.00', description: 'Sales 9% VAT') ->pay('4300', '20.00', vatCode: 'IH', vatValue: '4.20', description: 'Coffee and milk'),);The SDK sends this XML as xmlRequest of ProcessXmlString to processxml.asmx:
<transaction destiny="temporary"> <header> <office>1000</office> <code>KAS</code> <date>20261103</date> <statementnumber>311</statementnumber> <startvalue>250.00</startvalue> <closevalue>939.80</closevalue> </header> <lines> <line type="total" id="1"> <dim1>1000</dim1> <debitcredit>debit</debitcredit> <value>689.80</value> <description>Cash register 3 November</description> </line> <line type="detail" id="2"> <dim1>8000</dim1> <debitcredit>credit</debitcredit> <value>500.00</value> <description>Sales 21% VAT</description> <vatcode>VH</vatcode> <vatvalue>105.00</vatvalue> </line> <line type="detail" id="3"> <dim1>8010</dim1> <debitcredit>credit</debitcredit> <value>100.00</value> <description>Sales 9% VAT</description> <vatcode>VL</vatcode> <vatvalue>9.00</vatvalue> </line> <line type="detail" id="4"> <dim1>4300</dim1> <debitcredit>debit</debitcredit> <value>20.00</value> <description>Coffee and milk</description> <vatcode>IH</vatcode> <vatvalue>4.20</vatvalue> </line> </lines></transaction>Twinfield answers with the saved transaction, with its number and the names of the codes, in the same format as Read cash transaction.
Source
Section titled “Source”View examples/cash-transactions/daily-cash-register/example.php on GitHub.
Twinfield and Wolters Kluwer are trademarks of Wolters Kluwer. Their names and logos are used only to refer to their products.