Make sure that accounts and their opening balance values are the same currency.

This commit is contained in:
James Cole 2017-04-14 07:11:30 +02:00
parent 89ee9c058a
commit 953c38563b
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
10 changed files with 180 additions and 21 deletions

View File

@ -15,15 +15,20 @@ namespace FireflyIII\Console\Commands;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Console\Command;
use Illuminate\Database\QueryException;
use Log;
use Preferences;
use Schema;
/**
@ -63,8 +68,13 @@ class UpgradeDatabase extends Command
$this->setTransactionIdentifier();
$this->migrateRepetitions();
$this->repairPiggyBanks();
$this->updateAccountCurrencies();
$this->info('Firefly III database is up to date.');
}
/**
* Migrate budget repetitions to new format.
*/
private function migrateRepetitions()
{
if (!Schema::hasTable('budget_limits')) {
@ -153,6 +163,57 @@ class UpgradeDatabase extends Command
}
}
/**
*
*/
private function updateAccountCurrencies()
{
$accounts = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', [AccountType::DEFAULT, AccountType::ASSET])->get(['accounts.*']);
/** @var Account $account */
foreach ($accounts as $account) {
// get users preference, fall back to system pref.
$defaultCurrencyCode = Preferences::getForUser($account->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
$accountCurrency = intval($account->getMeta('currency_id'));
$openingBalance = $account->getOpeningBalance();
$openingBalanceCurrency = intval($openingBalance->transaction_currency_id);
// both 0? set to default currency:
if ($accountCurrency === 0 && $openingBalanceCurrency === 0) {
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $defaultCurrency->id]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $defaultCurrencyCode));
continue;
}
// opening balance 0, account not zero? just continue:
if ($accountCurrency > 0 && $openingBalanceCurrency === 0) {
continue;
}
// account is set to 0, opening balance is not?
if ($accountCurrency === 0 && $openingBalanceCurrency > 0) {
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $openingBalanceCurrency]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $defaultCurrencyCode));
continue;
}
// both are equal, just continue:
if ($accountCurrency === $openingBalanceCurrency) {
continue;
}
// do not match:
if ($accountCurrency !== $openingBalanceCurrency) {
// update opening balance:
$openingBalance->transaction_currency_id = $accountCurrency;
$openingBalance->save();
$this->line(sprintf('Account #%d ("%s") now has a correct currency for opening balance.', $account->id, $account->name));
continue;
}
}
}
/**
* grab all positive transactiosn from this journal that are not deleted. for each one, grab the negative opposing one
* which has 0 as an identifier and give it the same identifier.

View File

@ -147,14 +147,14 @@ class AccountController extends Controller
*/
public function edit(Request $request, Account $account)
{
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$currencies = ExpandedForm::makeSelectList($repository->get());
$roles = [];
$repository = app(CurrencyRepositoryInterface::class);
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
$allCurrencies = $repository->get();
$currencySelectList = ExpandedForm::makeSelectList($allCurrencies);
$roles = [];
foreach (config('firefly.accountRoles') as $role) {
$roles[$role] = strval(trans('firefly.account_role_' . $role));
}
@ -173,6 +173,7 @@ class AccountController extends Controller
$openingBalanceAmount = $account->getOpeningBalanceAmount() === '0' ? '' : $openingBalanceAmount;
$openingBalanceDate = $account->getOpeningBalanceDate();
$openingBalanceDate = $openingBalanceDate->year === 1900 ? null : $openingBalanceDate->format('Y-m-d');
$currency = $repository->find(intval($account->getMeta('currency_id')));
$preFilled = [
'accountNumber' => $account->getMeta('accountNumber'),
@ -183,13 +184,18 @@ class AccountController extends Controller
'openingBalanceDate' => $openingBalanceDate,
'openingBalance' => $openingBalanceAmount,
'virtualBalance' => $account->virtual_balance,
'currency_id' => $account->getMeta('currency_id'),
'currency_id' => $currency->id,
];
$request->session()->flash('preFilled', $preFilled);
$request->session()->flash('gaEventCategory', 'accounts');
$request->session()->flash('gaEventAction', 'edit-' . $what);
return view('accounts.edit', compact('currencies', 'account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what', 'roles'));
return view(
'accounts.edit', compact(
'allCurrencies', 'currencySelectList', 'account', 'currency', 'subTitle', 'subTitleIcon', 'openingBalance', 'what', 'roles'
)
);
}
/**

View File

@ -211,6 +211,26 @@ class Account extends Model
return $value;
}
/**
* Returns the opening balance
*
* @return TransactionJournal
* @throws FireflyException
*/
public function getOpeningBalance(): TransactionJournal
{
$journal = TransactionJournal::sortCorrectly()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $this->id)
->transactionTypes([TransactionType::OPENING_BALANCE])
->first(['transaction_journals.*']);
if (is_null($journal)) {
return new TransactionJournal;
}
return $journal;
}
/**
* Returns the amount of the opening balance for this account.
*

View File

@ -530,12 +530,10 @@ class AccountRepository implements AccountRepositoryInterface
}
// opening balance data? update it!
if (!is_null($openingBalance->id)) {
$date = $data['openingBalanceDate'];
$amount = $data['openingBalance'];
Log::debug('Opening balance journal found, update journal.');
$this->updateOpeningBalanceJournal($account, $openingBalance, $date, $amount);
$this->updateOpeningBalanceJournal($account, $openingBalance, $data);
return true;
}
@ -589,15 +587,19 @@ class AccountRepository implements AccountRepositoryInterface
/**
* @param Account $account
* @param TransactionJournal $journal
* @param Carbon $date
* @param float $amount
* @param array $data
*
* @return bool
*/
protected function updateOpeningBalanceJournal(Account $account, TransactionJournal $journal, Carbon $date, float $amount): bool
protected function updateOpeningBalanceJournal(Account $account, TransactionJournal $journal, array $data): bool
{
$date = $data['openingBalanceDate'];
$amount = $data['openingBalance'];
$currencyId = intval($data['currency_id']);
// update date:
$journal->date = $date;
$journal->date = $date;
$journal->transaction_currency_id = $currencyId;
$journal->save();
// update transactions:
/** @var Transaction $transaction */

View File

@ -137,4 +137,12 @@ interface AccountRepositoryInterface
*/
public function store(array $data): Account;
/**
* @param Account $account
* @param array $data
*
* @return Account
*/
public function update(Account $account, array $data): Account;
}

View File

@ -261,6 +261,36 @@ class ExpandedForm
return $html;
}
/**
* @param string $name
* @param null $value
* @param array $options
*
* @return string
*/
public function nonSelectableBalance(string $name, $value = null, array $options = []): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$selectedCurrency = isset($options['currency']) ? $options['currency'] : Amt::getDefaultCurrency();
unset($options['currency']);
unset($options['placeholder']);
// make sure value is formatted nicely:
if (!is_null($value) && $value !== '') {
$value = round($value, $selectedCurrency->decimal_places);
}
$html = view('form.non-selectable-balance', compact('selectedCurrency', 'classes', 'name', 'label', 'value', 'options'))->render();
return $html;
}
/**
* @param $type
* @param $name

View File

@ -159,7 +159,7 @@ return [
'ExpandedForm' => [
'is_safe' => [
'date', 'text', 'select', 'balance', 'optionsList', 'checkbox', 'amount', 'tags', 'integer', 'textarea', 'location',
'multiRadio', 'file', 'multiCheckbox', 'staticText', 'amountSmall', 'password',
'multiRadio', 'file', 'multiCheckbox', 'staticText', 'amountSmall', 'password','nonSelectableBalance'
],
],
'Form' => [

View File

@ -6,7 +6,7 @@
* See the LICENSE file for details.
*/
/** global: Modernizr */
/** global: Modernizr, currencies */
$(document).ready(function () {
"use strict";
@ -17,4 +17,14 @@ $(document).ready(function () {
}
);
}
// on change currency drop down list:
$('#ffInput_currency_id').change(updateCurrencyItems);
});
function updateCurrencyItems() {
var value = $('#ffInput_currency_id').val();
var symbol = currencies[value];
$('.non-selectable-currency-symbol').text(symbol);
}

View File

@ -19,7 +19,7 @@
{{ ExpandedForm.text('name') }}
{% if account.accounttype.type == 'Default account' or account.accounttype.type == 'Asset account' %}
{# Not really mandatory but OK #}
{{ ExpandedForm.select('currency_id', currencies) }}
{{ ExpandedForm.select('currency_id', currencySelectList) }}
{% endif %}
</div>
</div>
@ -36,10 +36,12 @@
{{ ExpandedForm.text('accountNumber') }}
{% if account.accounttype.type == 'Default account' or account.accounttype.type == 'Asset account' %}
{{ ExpandedForm.balance('openingBalance',null, {'currency' : openingBalance ? openingBalance.transactionCurrency : null}) }}
{# get opening balance entry for this thing! #}
{{ ExpandedForm.nonSelectableBalance('openingBalance',null, {'currency' : currency }) }}
{{ ExpandedForm.date('openingBalanceDate') }}
{{ ExpandedForm.select('accountRole', roles) }}
{{ ExpandedForm.balance('virtualBalance',null) }}
{{ ExpandedForm.nonSelectableBalance('virtualBalance',null, {'currency' : currency }) }}
{% endif %}
{{ ExpandedForm.checkbox('active','1') }}
@ -80,6 +82,15 @@
{% block scripts %}
<script type="text/javascript" src="js/lib/modernizr-custom.js"></script>
<script type="text/javascript" src="js/lib/jquery-ui.min.js"></script>
{# JS currency list for update thing #}
<script type="text/javascript">
var currencies = [];
{% for currency in allCurrencies %}
currencies[{{ currency.id }}] = "{{ currency.symbol }}";
{% endfor %}
</script>
<script type="text/javascript" src="js/ff/accounts/edit.js"></script>
{% endblock %}

View File

@ -0,0 +1,11 @@
<div class="{{ classes }}" id="{{ name }}_holder">
<label for="{{ options.id }}" class="col-sm-4 control-label">{{ label }}</label>
<div class="col-sm-8">
<div class="input-group">
<span class="input-group-addon non-selectable-currency-symbol">{{ selectedCurrency.symbol }}</span>
{{ Form.input('number', name, value, options) }}
</div>
{% include 'form/feedback' %}
</div>
</div>