2024-12-29 18:32:02 +01:00
< ? php
2024-12-30 04:12:18 +01:00
2024-12-29 18:32:02 +01:00
/*
* TransactionSummarizer . php
* Copyright ( c ) 2024 james @ firefly - iii . org .
*
* This file is part of Firefly III ( https :// github . com / firefly - iii ) .
*
* 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 the Free Software Foundation , either version 3 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see https :// www . gnu . org / licenses /.
*/
declare ( strict_types = 1 );
namespace FireflyIII\Support\Report\Summarizer ;
use FireflyIII\Models\TransactionCurrency ;
use FireflyIII\Support\Facades\Amount ;
use FireflyIII\User ;
use Illuminate\Support\Facades\Log ;
class TransactionSummarizer
{
2025-08-01 12:31:01 +02:00
private bool $convertToPrimary = false ;
2025-05-04 17:41:26 +02:00
private TransactionCurrency $default ;
private User $user ;
2024-12-29 18:32:02 +01:00
public function __construct ( ? User $user = null )
{
2025-05-27 17:06:15 +02:00
if ( $user instanceof User ) {
2024-12-29 18:32:02 +01:00
$this -> setUser ( $user );
}
}
public function setUser ( User $user ) : void
{
2025-08-01 13:10:11 +02:00
$this -> user = $user ;
$this -> default = Amount :: getPrimaryCurrencyByUserGroup ( $user -> userGroup );
2025-08-01 12:31:01 +02:00
$this -> convertToPrimary = Amount :: convertToPrimary ( $user );
2024-12-29 18:32:02 +01:00
}
2025-03-23 15:04:29 +01:00
public function groupByCurrencyId ( array $journals , string $method = 'negative' , bool $includeForeign = true ) : array
2024-12-29 18:32:02 +01:00
{
2025-06-20 05:59:44 +02:00
Log :: debug ( sprintf ( 'Now in groupByCurrencyId([%d journals], "%s", %s)' , count ( $journals ), $method , var_export ( $includeForeign , true )));
2024-12-29 18:32:02 +01:00
$array = [];
foreach ( $journals as $journal ) {
2025-02-17 04:11:50 +01:00
$field = 'amount' ;
2024-12-29 18:32:02 +01:00
// grab default currency information.
2025-02-17 04:11:50 +01:00
$currencyId = ( int ) $journal [ 'currency_id' ];
$currencyName = $journal [ 'currency_name' ];
$currencySymbol = $journal [ 'currency_symbol' ];
$currencyCode = $journal [ 'currency_code' ];
$currencyDecimalPlaces = $journal [ 'currency_decimal_places' ];
2025-02-11 16:27:18 +01:00
// prepare foreign currency info:
2025-02-17 04:11:50 +01:00
$foreignCurrencyId = 0 ;
2025-02-15 14:10:54 +01:00
$foreignCurrencyName = null ;
$foreignCurrencySymbol = null ;
$foreignCurrencyCode = null ;
$foreignCurrencyDecimalPlaces = null ;
2025-02-11 16:27:18 +01:00
2025-08-01 12:31:01 +02:00
if ( $this -> convertToPrimary ) {
// Log::debug('convertToPrimary is true.');
// if convert to primary currency, use the primary currency amount yes or no?
2025-08-01 13:10:11 +02:00
$usePrimary = $this -> default -> id !== ( int ) $journal [ 'currency_id' ];
2024-12-29 18:32:02 +01:00
$useForeign = $this -> default -> id === ( int ) $journal [ 'foreign_currency_id' ];
2025-08-01 12:31:01 +02:00
if ( $usePrimary ) {
// Log::debug(sprintf('Journal #%d switches to primary currency amount (original is %s)', $journal['transaction_journal_id'], $journal['currency_code']));
$field = 'pc_amount' ;
2024-12-29 18:32:02 +01:00
$currencyId = $this -> default -> id ;
$currencyName = $this -> default -> name ;
$currencySymbol = $this -> default -> symbol ;
$currencyCode = $this -> default -> code ;
$currencyDecimalPlaces = $this -> default -> decimal_places ;
}
if ( $useForeign ) {
2025-06-26 11:57:15 +02:00
// Log::debug(sprintf('Journal #%d switches to foreign amount (foreign is %s)', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
2024-12-29 18:32:02 +01:00
$field = 'foreign_amount' ;
$currencyId = ( int ) $journal [ 'foreign_currency_id' ];
$currencyName = $journal [ 'foreign_currency_name' ];
$currencySymbol = $journal [ 'foreign_currency_symbol' ];
$currencyCode = $journal [ 'foreign_currency_code' ];
$currencyDecimalPlaces = $journal [ 'foreign_currency_decimal_places' ];
}
}
2025-08-01 12:31:01 +02:00
if ( ! $this -> convertToPrimary ) {
// Log::debug('convertToPrimary is false.');
2025-02-11 16:27:18 +01:00
// use foreign amount?
2025-02-12 10:50:48 +01:00
$foreignCurrencyId = ( int ) $journal [ 'foreign_currency_id' ];
if ( 0 !== $foreignCurrencyId ) {
2025-03-23 15:04:29 +01:00
Log :: debug ( sprintf ( 'Journal #%d also includes foreign amount (foreign is "%s")' , $journal [ 'transaction_journal_id' ], $journal [ 'foreign_currency_code' ]));
2025-02-11 16:27:18 +01:00
$foreignCurrencyName = $journal [ 'foreign_currency_name' ];
$foreignCurrencySymbol = $journal [ 'foreign_currency_symbol' ];
$foreignCurrencyCode = $journal [ 'foreign_currency_code' ];
$foreignCurrencyDecimalPlaces = $journal [ 'foreign_currency_decimal_places' ];
}
2024-12-29 18:32:02 +01:00
}
2025-02-11 16:27:18 +01:00
// first process normal amount
2025-02-17 04:11:50 +01:00
$amount = ( string ) ( $journal [ $field ] ? ? '0' );
2024-12-30 04:12:18 +01:00
$array [ $currencyId ] ? ? = [
2024-12-29 18:32:02 +01:00
'sum' => '0' ,
'currency_id' => $currencyId ,
'currency_name' => $currencyName ,
'currency_symbol' => $currencySymbol ,
'currency_code' => $currencyCode ,
'currency_decimal_places' => $currencyDecimalPlaces ,
];
2025-02-11 16:27:18 +01:00
2025-01-04 07:39:16 +01:00
if ( 'positive' === $method ) {
2025-05-04 13:47:00 +02:00
$array [ $currencyId ][ 'sum' ] = bcadd ( $array [ $currencyId ][ 'sum' ], ( string ) app ( 'steam' ) -> positive ( $amount ));
2025-01-03 14:56:06 +01:00
}
2025-01-04 07:39:16 +01:00
if ( 'negative' === $method ) {
2025-05-04 13:47:00 +02:00
$array [ $currencyId ][ 'sum' ] = bcadd ( $array [ $currencyId ][ 'sum' ], ( string ) app ( 'steam' ) -> negative ( $amount ));
2025-01-03 14:56:06 +01:00
}
2025-02-11 16:27:18 +01:00
// then process foreign amount, if it exists.
2025-03-23 15:04:29 +01:00
if ( 0 !== $foreignCurrencyId && true === $includeForeign ) {
2025-02-12 10:50:48 +01:00
$amount = ( string ) ( $journal [ 'foreign_amount' ] ? ? '0' );
2025-02-11 16:27:18 +01:00
$array [ $foreignCurrencyId ] ? ? = [
'sum' => '0' ,
'currency_id' => $foreignCurrencyId ,
'currency_name' => $foreignCurrencyName ,
'currency_symbol' => $foreignCurrencySymbol ,
'currency_code' => $foreignCurrencyCode ,
'currency_decimal_places' => $foreignCurrencyDecimalPlaces ,
];
if ( 'positive' === $method ) {
2025-05-04 13:47:00 +02:00
$array [ $foreignCurrencyId ][ 'sum' ] = bcadd ( $array [ $foreignCurrencyId ][ 'sum' ], ( string ) app ( 'steam' ) -> positive ( $amount ));
2025-02-11 16:27:18 +01:00
}
if ( 'negative' === $method ) {
2025-05-04 13:47:00 +02:00
$array [ $foreignCurrencyId ][ 'sum' ] = bcadd ( $array [ $foreignCurrencyId ][ 'sum' ], ( string ) app ( 'steam' ) -> negative ( $amount ));
2025-02-11 16:27:18 +01:00
}
}
2025-02-12 10:50:48 +01:00
2025-01-03 14:56:06 +01:00
// $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->{$method}($amount));
2024-12-30 15:35:26 +01:00
// Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
2024-12-29 18:32:02 +01:00
}
Log :: debug ( 'End of sumExpenses.' , $array );
2024-12-30 04:12:18 +01:00
2024-12-29 18:32:02 +01:00
return $array ;
}
2024-12-30 04:12:18 +01:00
public function groupByDirection ( array $journals , string $method , string $direction ) : array
{
2024-12-29 18:32:02 +01:00
2025-08-01 13:10:11 +02:00
$array = [];
$idKey = sprintf ( '%s_account_id' , $direction );
$nameKey = sprintf ( '%s_account_name' , $direction );
2025-08-01 12:31:01 +02:00
$convertToPrimary = Amount :: convertToPrimary ( $this -> user );
2025-08-01 13:10:11 +02:00
$primary = Amount :: getPrimaryCurrencyByUserGroup ( $this -> user -> userGroup );
2024-12-29 18:32:02 +01:00
Log :: debug ( sprintf ( 'groupByDirection(array, %s, %s).' , $direction , $method ));
foreach ( $journals as $journal ) {
// currency
$currencyId = $journal [ 'currency_id' ];
$currencyName = $journal [ 'currency_name' ];
$currencySymbol = $journal [ 'currency_symbol' ];
$currencyCode = $journal [ 'currency_code' ];
$currencyDecimalPlaces = $journal [ 'currency_decimal_places' ];
2025-08-01 12:31:01 +02:00
$field = $convertToPrimary && $currencyId !== $primary -> id ? 'pc_amount' : 'amount' ;
2024-12-29 18:32:02 +01:00
// perhaps use default currency instead?
2025-08-01 12:31:01 +02:00
if ( $convertToPrimary && $journal [ 'currency_id' ] !== $primary -> id ) {
$currencyId = $primary -> id ;
$currencyName = $primary -> name ;
$currencySymbol = $primary -> symbol ;
$currencyCode = $primary -> code ;
$currencyDecimalPlaces = $primary -> decimal_places ;
2024-12-29 18:32:02 +01:00
}
// use foreign amount when the foreign currency IS the default currency.
2025-08-01 12:31:01 +02:00
if ( $convertToPrimary && $journal [ 'currency_id' ] !== $primary -> id && $primary -> id === $journal [ 'foreign_currency_id' ]) {
2024-12-29 18:32:02 +01:00
$field = 'foreign_amount' ;
}
2024-12-30 04:12:18 +01:00
$key = sprintf ( '%s-%s' , $journal [ $idKey ], $currencyId );
2024-12-29 18:32:02 +01:00
// sum it all up or create a new array.
$array [ $key ] ? ? = [
'id' => $journal [ $idKey ],
'name' => $journal [ $nameKey ],
'sum' => '0' ,
'currency_id' => $currencyId ,
'currency_name' => $currencyName ,
'currency_symbol' => $currencySymbol ,
'currency_code' => $currencyCode ,
'currency_decimal_places' => $currencyDecimalPlaces ,
];
// add the data from the $field to the array.
2025-05-04 13:47:00 +02:00
$array [ $key ][ 'sum' ] = bcadd ( $array [ $key ][ 'sum' ], ( string ) app ( 'steam' ) -> { $method }(( string ) ( $journal [ $field ] ? ? '0' ))); // @phpstan-ignore-line
2024-12-29 18:32:02 +01:00
Log :: debug ( sprintf ( 'Field for transaction #%d is "%s" (%s). Sum: %s' , $journal [ 'transaction_group_id' ], $currencyCode , $field , $array [ $key ][ 'sum' ]));
2025-08-01 12:31:01 +02:00
// also do foreign amount, but only when convertToPrimary is false (otherwise we have it already)
// or when convertToPrimary is true and the foreign currency is ALSO not the default currency.
if (( ! $convertToPrimary || $journal [ 'foreign_currency_id' ] !== $primary -> id ) && 0 !== ( int ) $journal [ 'foreign_currency_id' ]) {
2024-12-29 18:32:02 +01:00
Log :: debug ( sprintf ( 'Use foreign amount from transaction #%d: %s %s. Sum: %s' , $journal [ 'transaction_group_id' ], $currencyCode , $journal [ 'foreign_amount' ], $array [ $key ][ 'sum' ]));
$key = sprintf ( '%s-%s' , $journal [ $idKey ], $journal [ 'foreign_currency_id' ]);
2024-12-30 04:12:18 +01:00
$array [ $key ] ? ? = [
2024-12-29 18:32:02 +01:00
'id' => $journal [ $idKey ],
'name' => $journal [ $nameKey ],
'sum' => '0' ,
'currency_id' => $journal [ 'foreign_currency_id' ],
'currency_name' => $journal [ 'foreign_currency_name' ],
'currency_symbol' => $journal [ 'foreign_currency_symbol' ],
'currency_code' => $journal [ 'foreign_currency_code' ],
'currency_decimal_places' => $journal [ 'foreign_currency_decimal_places' ],
];
2025-05-04 13:47:00 +02:00
$array [ $key ][ 'sum' ] = bcadd ( $array [ $key ][ 'sum' ], ( string ) app ( 'steam' ) -> { $method }(( string ) $journal [ 'foreign_amount' ])); // @phpstan-ignore-line
2024-12-29 18:32:02 +01:00
}
}
return $array ;
}
2025-04-21 08:03:32 +02:00
2025-08-01 12:31:01 +02:00
public function setConvertToPrimary ( bool $convertToPrimary ) : void
2025-04-21 08:03:32 +02:00
{
2025-08-01 12:31:01 +02:00
Log :: debug ( sprintf ( 'Overrule convertToPrimary to become %s' , var_export ( $convertToPrimary , true )));
$this -> convertToPrimary = $convertToPrimary ;
2025-04-21 08:03:32 +02:00
}
2024-12-29 18:32:02 +01:00
}