Make sure amounts are formatted, and fixed some issues.

This commit is contained in:
James Cole 2017-06-04 23:39:26 +02:00
parent 82e74a2afd
commit a487c7b4b2
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
15 changed files with 301 additions and 71 deletions

View File

@ -65,12 +65,22 @@ class JournalCollector implements JournalCollectorInterface
'bills.name as bill_name',
'bills.name_encrypted as bill_name_encrypted',
'transactions.id as id',
'transactions.amount as transaction_amount',
'transactions.description as transaction_description',
'transactions.account_id',
'transactions.identifier',
'transactions.transaction_journal_id',
'transactions.amount as transaction_amount',
'transaction_currencies.code as transaction_currency_code',
'transaction_currencies.symbol as transaction_currency_symbol',
'transaction_currencies.decimal_places as transaction_currency_dp',
'transactions.foreign_amount as transaction_foreign_amount',
'foreign_currencies.code as foreign_currency_code',
'foreign_currencies.symbol as foreign_currency_symbol',
'foreign_currencies.decimal_places as foreign_currency_dp',
'accounts.name as account_name',
'accounts.encrypted as account_encrypted',
'account_types.type as account_type',
@ -489,6 +499,7 @@ class JournalCollector implements JournalCollectorInterface
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transactions.transaction_currency_id')
->leftJoin('transaction_currencies as foreign_currencies', 'foreign_currencies.id', 'transactions.foreign_currency_id')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.user_id', $this->user->id)

View File

@ -187,7 +187,7 @@ class PopupReport implements PopupReportInterface
$journals = $journals->filter(
function (Transaction $transaction) use ($report) {
// get the destinations:
$destinations = $transaction->destinationAccountList($transaction->transactionJournal)->pluck('id')->toArray();
$destinations = $transaction->transactionJournal->destinationAccountList()->pluck('id')->toArray();
// do these intersect with the current list?
return !empty(array_intersect($report, $destinations));

View File

@ -116,10 +116,11 @@ class JsonController extends Controller
* Since both this method and the chart use the exact same data, we can suffice
* with calling the one method in the bill repository that will get this amount.
*/
$amount = $repository->getBillsPaidInRange($start, $end); // will be a negative amount.
$amount = bcmul($amount, '-1');
$amount = $repository->getBillsPaidInRange($start, $end); // will be a negative amount.
$amount = bcmul($amount, '-1');
$currency = Amount::getDefaultCurrency();
$data = ['box' => 'bills-paid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$data = ['box' => 'bills-paid', 'amount' => Amount::formatAnything($currency, $amount, false), 'amount_raw' => $amount];
return Response::json($data);
}
@ -131,10 +132,11 @@ class JsonController extends Controller
*/
public function boxBillsUnpaid(BillRepositoryInterface $repository)
{
$start = session('start', Carbon::now()->startOfMonth());
$end = session('end', Carbon::now()->endOfMonth());
$amount = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount.
$data = ['box' => 'bills-unpaid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$start = session('start', Carbon::now()->startOfMonth());
$end = session('end', Carbon::now()->endOfMonth());
$amount = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount.
$currency = Amount::getDefaultCurrency();
$data = ['box' => 'bills-unpaid', 'amount' => Amount::formatAnything($currency, $amount, false), 'amount_raw' => $amount];
return Response::json($data);
}
@ -167,8 +169,9 @@ class JsonController extends Controller
->setTypes([TransactionType::DEPOSIT])
->withOpposingAccount();
$amount = strval($collector->getJournals()->sum('transaction_amount'));
$data = ['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$amount = strval($collector->getJournals()->sum('transaction_amount'));
$currency = Amount::getDefaultCurrency();
$data = ['box' => 'in', 'amount' => Amount::formatAnything($currency, $amount, false), 'amount_raw' => $amount];
$cache->store($data);
return Response::json($data);
@ -200,9 +203,9 @@ class JsonController extends Controller
$collector->setAllAssetAccounts()->setRange($start, $end)
->setTypes([TransactionType::WITHDRAWAL])
->withOpposingAccount();
$amount = strval($collector->getJournals()->sum('transaction_amount'));
$data = ['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$amount = strval($collector->getJournals()->sum('transaction_amount'));
$currency = Amount::getDefaultCurrency();
$data = ['box' => 'out', 'amount' => Amount::formatAnything($currency, $amount, false), 'amount_raw' => $amount];
$cache->store($data);
return Response::json($data);

View File

@ -276,18 +276,29 @@ class PiggyBankController extends Controller
*/
public function postAdd(Request $request, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
{
$amount = $request->get('amount');
$amount = $request->get('amount');
$currency = Amount::getDefaultCurrency();
if ($repository->canAddAmount($piggyBank, $amount)) {
$repository->addAmount($piggyBank, $amount);
Session::flash('success', strval(trans('firefly.added_amount_to_piggy', ['amount' => Amount::format($amount, false), 'name' => $piggyBank->name])));
Session::flash(
'success', strval(
trans(
'firefly.added_amount_to_piggy',
['amount' => Amount::formatAnything($currency, $amount, false), 'name' => $piggyBank->name]
)
)
);
Preferences::mark();
return redirect(route('piggy-banks.index'));
}
Log::error('Cannot add ' . $amount . ' because canAddAmount returned false.');
Session::flash('error', strval(trans('firefly.cannot_add_amount_piggy', ['amount' => Amount::format($amount, false), 'name' => e($piggyBank->name)])));
Session::flash(
'error', strval(
trans('firefly.cannot_add_amount_piggy', ['amount' => Amount::formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)])
)
);
return redirect(route('piggy-banks.index'));
}
@ -302,10 +313,11 @@ class PiggyBankController extends Controller
public function postRemove(Request $request, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
{
$amount = $request->get('amount');
$currency = Amount::getDefaultCurrency();
if ($repository->canRemoveAmount($piggyBank, $amount)) {
$repository->removeAmount($piggyBank, $amount);
Session::flash(
'success', strval(trans('firefly.removed_amount_from_piggy', ['amount' => Amount::format($amount, false), 'name' => $piggyBank->name]))
'success', strval(trans('firefly.removed_amount_from_piggy', ['amount' => Amount::formatAnything($currency, $amount, false), 'name' => $piggyBank->name]))
);
Preferences::mark();
@ -314,7 +326,7 @@ class PiggyBankController extends Controller
$amount = strval(round($request->get('amount'), 12));
Session::flash('error', strval(trans('firefly.cannot_remove_from_piggy', ['amount' => Amount::format($amount, false), 'name' => e($piggyBank->name)])));
Session::flash('error', strval(trans('firefly.cannot_remove_from_piggy', ['amount' => Amount::formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)])));
return redirect(route('piggy-banks.index'));
}

View File

@ -481,7 +481,6 @@ class AccountRepository implements AccountRepositoryInterface
[
'user_id' => $this->user->id,
'transaction_type_id' => $transactionType->id,
// TODO update this transaction currency reference.
'transaction_currency_id' => $currencyId,
'description' => 'Initial balance for "' . $account->name . '"',
'completed' => true,
@ -502,9 +501,23 @@ class AccountRepository implements AccountRepositoryInterface
$secondAmount = $amount;
}
$one = new Transaction(['account_id' => $firstAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $firstAmount]);
$one = new Transaction(
[
'account_id' => $firstAccount->id,
'transaction_journal_id' => $journal->id,
'amount' => $firstAmount,
'transaction_currency_id' => $currencyId,
]
);
$one->save();// first transaction: from
$two = new Transaction(['account_id' => $secondAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $secondAmount]);
$two = new Transaction(
[
'account_id' => $secondAccount->id,
'transaction_journal_id' => $journal->id,
'amount' => $secondAmount,
'transaction_currency_id' => $currencyId,]
);
$two->save(); // second transaction: to
Log::debug(sprintf('Stored two transactions, #%d and #%d', $one->id, $two->id));
@ -623,18 +636,19 @@ class AccountRepository implements AccountRepositoryInterface
// update date:
$journal->date = $date;
// TODO update this transaction currency reference.
$journal->transaction_currency_id = $currencyId;
$journal->save();
// update transactions:
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($account->id == $transaction->account_id) {
$transaction->amount = $amount;
$transaction->amount = $amount;
$transaction->transaction_currency_id = $currencyId;
$transaction->save();
}
if ($account->id != $transaction->account_id) {
$transaction->amount = bcmul($amount, '-1');
$transaction->amount = bcmul($amount, '-1');
$transaction->transaction_currency_id = $currencyId;
$transaction->save();
}
}

View File

@ -101,10 +101,12 @@ class JournalTasker implements JournalTaskerInterface
'destination_accounts.encrypted as destination_account_encrypted',
'destination_account_types.type as destination_account_type',
'native_currencies.id as transaction_currency_id',
'native_currencies.decimal_places as transaction_currency_dp',
'native_currencies.code as transaction_currency_code',
'native_currencies.symbol as transaction_currency_symbol',
'foreign_currencies.id as foreign_currency_id',
'foreign_currencies.decimal_places as foreign_currency_dp',
'foreign_currencies.code as foreign_currency_code',
'foreign_currencies.symbol as foreign_currency_symbol',
@ -142,9 +144,11 @@ class JournalTasker implements JournalTaskerInterface
'transaction_currency_id' => $entry->transaction_currency_id,
'transaction_currency_code' => $entry->transaction_currency_code,
'transaction_currency_symbol' => $entry->transaction_currency_symbol,
'transaction_currency_dp' => $entry->transaction_currency_dp,
'foreign_currency_id' => $entry->foreign_currency_id,
'foreign_currency_code' => $entry->foreign_currency_code,
'foreign_currency_symbol' => $entry->foreign_currency_symbol,
'foreign_currency_dp' => $entry->foreign_currency_dp,
];
if ($entry->destination_account_type === AccountType::CASH) {
$transaction['destination_account_name'] = '';

View File

@ -240,10 +240,12 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
*/
public function getPiggyBanksWithAmount(): Collection
{
$currency = Amount::getDefaultCurrency();
$set = $this->getPiggyBanks();
foreach ($set as $piggy) {
$currentAmount = $piggy->currentRelevantRep()->currentamount ?? '0';
$piggy->name = $piggy->name . ' (' . Amount::format($currentAmount, false) . ')';
$piggy->name = $piggy->name . ' (' . Amount::formatAnything($currency, $currentAmount, false) . ')';
}
return $set;

View File

@ -14,7 +14,7 @@ declare(strict_types=1);
namespace FireflyIII\Support;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\Transaction as TransactionModel;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
@ -28,6 +28,7 @@ use Preferences as Prefs;
*/
class Amount
{
/**
* bool $sepBySpace is $localeconv['n_sep_by_space']
* int $signPosn = $localeconv['n_sign_posn']
@ -242,4 +243,81 @@ class Amount
'zero' => $positive,
];
}
/**
* @param TransactionJournal $journal
* @param bool $coloured
*
* @return string
*/
public function journalAmount(TransactionJournal $journal, bool $coloured = true): string
{
$amounts = [];
$transactions = $journal->transactions()->where('amount', '>', 0)->get();
/** @var TransactionModel $transaction */
foreach ($transactions as $transaction) {
// model some fields to fit "transactionAmount()":
$transaction->transaction_amount = $transaction->amount;
$transaction->transaction_foreign_amount = $transaction->foreign_amount;
$transaction->transaction_type_type = $journal->transactionType->type;
$transaction->transaction_currency_symbol = $transaction->transactionCurrency->symbol;
$transaction->transaction_currency_dp = $transaction->transactionCurrency->decimal_places;
if (!is_null($transaction->foreign_currency_id)) {
$transaction->foreign_currency_symbol = $transaction->foreignCurrency->symbol;
$transaction->foreign_currency_dp = $transaction->foreignCurrency->decimal_places;
}
$amounts[] = $this->transactionAmount($transaction, $coloured);
}
return join(' / ', $amounts);
}
/**
* This formats a transaction, IF that transaction has been "collected" using the JournalCollector.
*
* @param TransactionModel $transaction
* @param bool $coloured
*
* @return string
*/
public function transactionAmount(TransactionModel $transaction, bool $coloured = true): string
{
$amount = bcmul(app('steam')->positive(strval($transaction->transaction_amount)), '-1');
$format = '%s';
if ($transaction->transaction_type_type === TransactionType::DEPOSIT) {
$amount = bcmul($amount, '-1');
}
if ($transaction->transaction_type_type === TransactionType::TRANSFER) {
$amount = app('steam')->positive($amount);
$coloured = false;
$format = '<span class="text-info">%s</span>';
}
$currency = new TransactionCurrency;
$currency->symbol = $transaction->transaction_currency_symbol;
$currency->decimal_places = $transaction->transaction_currency_dp;
$str = sprintf($format, $this->formatAnything($currency, $amount, $coloured));
if (!is_null($transaction->transaction_foreign_amount)) {
$amount = strval($transaction->transaction_foreign_amount);
if ($transaction->transaction_type_type === TransactionType::TRANSFER) {
$amount = app('steam')->positive($amount);
$coloured = false;
$format = '<span class="text-info">%s</span>';
}
$currency = new TransactionCurrency;
$currency->symbol = $transaction->foreign_currency_symbol;
$currency->decimal_places = $transaction->foreign_currency_dp;
$str .= ' (' . sprintf($format, $this->formatAnything($currency, $amount, $coloured)) . ')';
}
return $str;
}
}

View File

@ -13,6 +13,7 @@ namespace FireflyIII\Support\Twig;
use FireflyIII\Models\Account as AccountModel;
use FireflyIII\Models\Transaction as TransactionModel;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use Twig_Extension;
@ -45,6 +46,12 @@ class AmountFormat extends Twig_Extension
{
return [
$this->formatAmountByAccount(),
$this->transactionAmount(),
$this->journalAmount(),
$this->formatDestinationAfter(),
$this->formatDestinationBefore(),
$this->formatSourceAfter(),
$this->formatSourceBefore(),
];
}
@ -68,7 +75,9 @@ class AmountFormat extends Twig_Extension
return new Twig_SimpleFilter(
'formatAmount', function (string $string): string {
return app('amount')->format($string);
$currency = app('amount')->getDefaultCurrency();
return app('amount')->formatAnything($currency, $string, true);
}, ['is_safe' => ['html']]
);
}
@ -102,8 +111,136 @@ class AmountFormat extends Twig_Extension
return new Twig_SimpleFilter(
'formatAmountPlain', function (string $string): string {
return app('amount')->format($string, false);
$currency = app('amount')->getDefaultCurrency();
return app('amount')->formatAnything($currency, $string, false);
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
protected function formatDestinationAfter(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'formatDestinationAfter', function (array $transaction): string {
// build fake currency for main amount.
$format = new TransactionCurrency;
$format->decimal_places = $transaction['transaction_currency_dp'];
$format->symbol = $transaction['transaction_currency_symbol'];
$string = app('amount')->formatAnything($format, $transaction['destination_account_after'], true);
// also append foreign amount for clarity:
if (!is_null($transaction['foreign_destination_amount'])) {
// build fake currency for foreign amount
$format = new TransactionCurrency;
$format->decimal_places = $transaction['foreign_currency_dp'];
$format->symbol = $transaction['foreign_currency_symbol'];
$string .= ' (' . app('amount')->formatAnything($format, $transaction['foreign_destination_amount'], true) . ')';
}
return $string;
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
protected function formatDestinationBefore(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'formatDestinationBefore', function (array $transaction): string {
// build fake currency for main amount.
$format = new TransactionCurrency;
$format->decimal_places = $transaction['transaction_currency_dp'];
$format->symbol = $transaction['transaction_currency_symbol'];
return app('amount')->formatAnything($format, $transaction['destination_account_before'], true);
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
protected function formatSourceAfter(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'formatSourceAfter', function (array $transaction): string {
// build fake currency for main amount.
$format = new TransactionCurrency;
$format->decimal_places = $transaction['transaction_currency_dp'];
$format->symbol = $transaction['transaction_currency_symbol'];
$string = app('amount')->formatAnything($format, $transaction['source_account_after'], true);
// also append foreign amount for clarity:
if (!is_null($transaction['foreign_source_amount'])) {
// build fake currency for foreign amount
$format = new TransactionCurrency;
$format->decimal_places = $transaction['foreign_currency_dp'];
$format->symbol = $transaction['foreign_currency_symbol'];
$string .= ' (' . app('amount')->formatAnything($format, $transaction['foreign_source_amount'], true) . ')';
}
return $string;
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
protected function formatSourceBefore(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'formatSourceBefore', function (array $transaction): string {
// build fake currency for main amount.
$format = new TransactionCurrency;
$format->decimal_places = $transaction['transaction_currency_dp'];
$format->symbol = $transaction['transaction_currency_symbol'];
return app('amount')->formatAnything($format, $transaction['source_account_before'], true);
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
protected function journalAmount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'journalAmount', function (TransactionJournal $journal): string {
return app('amount')->journalAmount($journal, true);
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
protected function transactionAmount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionAmount', function (TransactionModel $transaction): string {
return app('amount')->transactionAmount($transaction, true);
}, ['is_safe' => ['html']]
);
}
}

View File

@ -14,8 +14,7 @@
{{ transaction.description }}
{% endif %}
<span class="pull-right small">
{# TODO replace with new format code #}
XX.XX
{{ transactionAmount(transaction) }}
</span>
</a>
{% endfor %}

View File

@ -62,14 +62,7 @@
</td>
<td style="text-align: right;">
<span style="margin-right:5px;">
{% if transaction.transaction_type_type == 'Transfer' %}
<!-- format amount of transaction -->
{# TODO format amount of transaction. #}
{# TODO format: Amount of transaction (amount in foreign) / total (total foreign) #}
XX.XX
{% else %}
XX.XX
{% endif %}
{{ transactionAmount(transaction) }}
</span>
</td>

View File

@ -46,7 +46,7 @@
</td>
<td>
{# TODO replace with new format code #}
XX.XX
{{ transactionAmount(transaction) }}
</td>
<td class="hidden-sm hidden-xs">
{{ transaction.date.formatLocalized(monthAndDayFormat) }}

View File

@ -59,8 +59,7 @@
</td>
<td class="hide-balance_before" style="text-align: right;">{{ transaction.before|formatAmount }}</td>
<td class="hide-amount" style="text-align: right;">
{# TODO replace with new format code #}
XX.XX
{{ transactionAmount(transaction) }}
</td>
<td class="hide-balance_after" style="text-align: right;">{{ transaction.after|formatAmount }}</td>

View File

@ -29,7 +29,7 @@
<tr>
<th>&nbsp;</th>
<th>{{ trans('list.description') }}</th>
<th>{{ trans('list.amount') }}</th>
<th>{{ trans('list.total_amount') }}</th>
<th class="hidden-sm hidden-xs">{{ trans('list.date') }}</th>
<th class="hidden-xs">{{ trans('list.from') }}</th>
<th class="hidden-xs">{{ trans('list.to') }}</th>
@ -43,8 +43,7 @@
<a href="{{ route('transactions.show',journal.id) }}" title="{{ journal.description }}">{{ journal.description }}</a>
</td>
<td>
{# TODO fix amount display #}
XX.XX
{{ journalAmount(journal) }}
</td>
<td>
{{ journal.date.formatLocalized(monthAndDayFormat) }}

View File

@ -37,8 +37,7 @@
<tr>
<td>{{ 'total_amount'|_ }}</td>
<td>
{# TODO fix amount display #}
XX.XX
{{ journalAmount(journal) }}
</td>
</tr>
<tr>
@ -299,8 +298,7 @@
</td>
<td>
{# TODO replace with new display: #}
XX.XX
{{ formatSourceBefore(transaction) }} &rarr; {{ formatSourceAfter(transaction) }}
</td>
<td>
{% if transaction.destination_account_type == 'Cash account' %}
@ -311,29 +309,10 @@
</td>
<td>
{# TODO replace with new format code #}
XX.XX
{{ formatDestinationBefore(transaction) }} &rarr; {{ formatDestinationAfter(transaction) }}
</td>
<td>
{% if journal.transactiontype.type == 'Deposit' %}
<!-- deposit, positive amount with correct currency -->
{# TODO replace with new format code #}
XX.XX
{% endif %}
{% if journal.transactiontype.type == 'Withdrawal' %}
<!-- withdrawal, negative amount with correct currency -->
{# TODO replace with new format code #}
XX.XX
{% endif %}
{% if journal.transactiontype.type == 'Transfer' %}
<!-- transfer, positive amount in blue -->
<span class="text-info">
{# TODO replace with new format code #}
XX.XX
</span>
{% endif %}
{{ journalAmount(journal) }}
</td>
<td>
{{ transactionIdBudgets(transaction.source_id) }}