Currencies can now be enabled and disabled.

This commit is contained in:
James Cole
2018-11-10 10:04:46 +01:00
parent daa8aa5c9d
commit e491dda229
25 changed files with 457 additions and 51 deletions

View File

@@ -90,7 +90,7 @@ class CurrencyController extends Controller
// access denied: // access denied:
throw new FireflyException('No access to method, user is not owner.'); // @codeCoverageIgnore throw new FireflyException('No access to method, user is not owner.'); // @codeCoverageIgnore
} }
if (!$this->repository->canDeleteCurrency($currency)) { if ($this->repository->currencyInUse($currency)) {
throw new FireflyException('No access to method, currency is in use.'); // @codeCoverageIgnore throw new FireflyException('No access to method, currency is in use.'); // @codeCoverageIgnore
} }
$this->repository->destroy($currency); $this->repository->destroy($currency);
@@ -108,7 +108,7 @@ class CurrencyController extends Controller
public function index(Request $request): JsonResponse public function index(Request $request): JsonResponse
{ {
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$collection = $this->repository->get(); $collection = $this->repository->getAll();
$count = $collection->count(); $count = $collection->count();
// slice them: // slice them:
$currencies = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $currencies = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);

View File

@@ -53,6 +53,7 @@ class CurrencyRequest extends Request
'symbol' => $this->string('symbol'), 'symbol' => $this->string('symbol'),
'decimal_places' => $this->integer('decimal_places'), 'decimal_places' => $this->integer('decimal_places'),
'default' => $this->boolean('default'), 'default' => $this->boolean('default'),
'enabled' => $this->boolean('enabled'),
]; ];
} }
@@ -68,7 +69,9 @@ class CurrencyRequest extends Request
'code' => 'required|between:3,3|unique:transaction_currencies,code', 'code' => 'required|between:3,3|unique:transaction_currencies,code',
'symbol' => 'required|between:1,5|unique:transaction_currencies,symbol', 'symbol' => 'required|between:1,5|unique:transaction_currencies,symbol',
'decimal_places' => 'required|between:0,20|numeric|min:0|max:20', 'decimal_places' => 'required|between:0,20|numeric|min:0|max:20',
'enabled' => 'required|boolean',
'default' => 'boolean', 'default' => 'boolean',
]; ];
switch ($this->method()) { switch ($this->method()) {

View File

@@ -61,6 +61,7 @@ class TransactionCurrencyFactory
'code' => $data['code'], 'code' => $data['code'],
'symbol' => $data['symbol'], 'symbol' => $data['symbol'],
'decimal_places' => $data['decimal_places'], 'decimal_places' => $data['decimal_places'],
'enabled' => $data['enabled'],
] ]
); );
} catch (QueryException $e) { } catch (QueryException $e) {

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers; namespace FireflyIII\Http\Controllers;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Requests\CurrencyFormRequest; use FireflyIII\Http\Requests\CurrencyFormRequest;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
@@ -106,12 +107,12 @@ class CurrencyController extends Controller
app('preferences')->set('currencyPreference', $currency->code); app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark(); app('preferences')->mark();
$this->repository->enable($currency);
$request->session()->flash('success', (string)trans('firefly.new_default_currency', ['name' => $currency->name])); $request->session()->flash('success', (string)trans('firefly.new_default_currency', ['name' => $currency->name]));
return redirect(route('currencies.index')); return redirect(route('currencies.index'));
} }
/** /**
* Deletes a currency. * Deletes a currency.
* *
@@ -132,7 +133,7 @@ class CurrencyController extends Controller
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
} }
if (!$this->repository->canDeleteCurrency($currency)) { if ($this->repository->currencyInUse($currency)) {
$request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => $currency->name])); $request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
return redirect(route('currencies.index')); return redirect(route('currencies.index'));
@@ -145,7 +146,6 @@ class CurrencyController extends Controller
return view('currencies.delete', compact('currency', 'subTitle')); return view('currencies.delete', compact('currency', 'subTitle'));
} }
/** /**
* Destroys a currency. * Destroys a currency.
* *
@@ -166,7 +166,7 @@ class CurrencyController extends Controller
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
} }
if (!$this->repository->canDeleteCurrency($currency)) { if ($this->repository->currencyInUse($currency)) {
$request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => $currency->name])); $request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
return redirect(route('currencies.index')); return redirect(route('currencies.index'));
@@ -178,6 +178,49 @@ class CurrencyController extends Controller
return redirect($this->getPreviousUri('currencies.delete.uri')); return redirect($this->getPreviousUri('currencies.delete.uri'));
} }
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws FireflyException
*/
public function disableCurrency(Request $request, TransactionCurrency $currency)
{
app('preferences')->mark();
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
// @codeCoverageIgnoreStart
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => env('SITE_OWNER')]));
return redirect(route('currencies.index'));
// @codeCoverageIgnoreEnd
}
if ($this->repository->currencyInUse($currency)) {
$request->session()->flash('error', (string)trans('firefly.cannot_disable_currency', ['name' => $currency->name]));
return redirect(route('currencies.index'));
}
$this->repository->disable($currency);
// if no currencies are enabled, enable the first one in the DB (usually the EUR)
if (0 === $this->repository->get()->count()) {
$first = $this->repository->getAll()->first();
if (null === $first) {
throw new FireflyException('No currencies found.');
}
$this->repository->enable($first);
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark();
}
session()->flash('success', (string)trans('firefly.currency_is_now_disabled', ['name' => $currency->name]));
return redirect(route('currencies.index'));
}
/** /**
* Edit a currency. * Edit a currency.
@@ -203,6 +246,15 @@ class CurrencyController extends Controller
$subTitle = (string)trans('breadcrumbs.edit_currency', ['name' => $currency->name]); $subTitle = (string)trans('breadcrumbs.edit_currency', ['name' => $currency->name]);
$currency->symbol = htmlentities($currency->symbol); $currency->symbol = htmlentities($currency->symbol);
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
$preFilled = [
'enabled' => $hasOldInput ? (bool)$request->old('enabled') : $currency->enabled,
];
$request->session()->flash('preFilled', $preFilled);
// put previous url in session if not redirect from store (not "return_to_edit"). // put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('currencies.edit.fromUpdate')) { if (true !== session('currencies.edit.fromUpdate')) {
$this->rememberPreviousUri('currencies.edit.uri'); $this->rememberPreviousUri('currencies.edit.uri');
@@ -212,6 +264,21 @@ class CurrencyController extends Controller
return view('currencies.edit', compact('currency', 'subTitle', 'subTitleIcon')); return view('currencies.edit', compact('currency', 'subTitle', 'subTitleIcon'));
} }
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function enableCurrency(TransactionCurrency $currency)
{
app('preferences')->mark();
$this->repository->enable($currency);
session()->flash('success', (string)trans('firefly.currency_is_now_enabled', ['name' => $currency->name]));
return redirect(route('currencies.index'));
}
/** /**
* Show overview of currencies. * Show overview of currencies.
* *
@@ -225,11 +292,13 @@ class CurrencyController extends Controller
$user = auth()->user(); $user = auth()->user();
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page'); $page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data; $pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
$collection = $this->repository->get(); $collection = $this->repository->getAll();
$total = $collection->count(); $total = $collection->count();
$collection = $collection->sortBy( $collection = $collection->sortBy(
function (TransactionCurrency $currency) { function (TransactionCurrency $currency) {
return $currency->name; $intEnabled = $currency->enabled ? 0 : 1;
return $intEnabled . $currency->name;
} }
); );
$collection = $collection->slice(($page - 1) * $pageSize, $pageSize); $collection = $collection->slice(($page - 1) * $pageSize, $pageSize);
@@ -269,6 +338,7 @@ class CurrencyController extends Controller
} }
$data = $request->getCurrencyData(); $data = $request->getCurrencyData();
$data['enabled'] = true;
$currency = $this->repository->store($data); $currency = $this->repository->store($data);
$redirect = redirect($this->getPreviousUri('currencies.create.uri')); $redirect = redirect($this->getPreviousUri('currencies.create.uri'));
if (null !== $currency) { if (null !== $currency) {

View File

@@ -100,6 +100,7 @@ class NewUserController extends Controller
if (null === $currency) { if (null === $currency) {
$currency = $currencyRepository->findByCodeNull('EUR'); $currency = $currencyRepository->findByCodeNull('EUR');
} }
$currencyRepository->enable($currency);
$this->createAssetAccount($request, $currency); // create normal asset account $this->createAssetAccount($request, $currency); // create normal asset account
$this->createSavingsAccount($request, $currency, $language); // create savings account $this->createSavingsAccount($request, $currency, $language); // create savings account

View File

@@ -52,6 +52,7 @@ class CurrencyFormRequest extends Request
'code' => $this->string('code'), 'code' => $this->string('code'),
'symbol' => $this->string('symbol'), 'symbol' => $this->string('symbol'),
'decimal_places' => $this->integer('decimal_places'), 'decimal_places' => $this->integer('decimal_places'),
'enabled' => $this->boolean('enabled'),
]; ];
} }
@@ -68,6 +69,7 @@ class CurrencyFormRequest extends Request
'code' => 'required|min:3|max:3|unique:transaction_currencies,code', 'code' => 'required|min:3|max:3|unique:transaction_currencies,code',
'symbol' => 'required|min:1|max:8|unique:transaction_currencies,symbol', 'symbol' => 'required|min:1|max:8|unique:transaction_currencies,symbol',
'decimal_places' => 'required|min:0|max:12|numeric', 'decimal_places' => 'required|min:0|max:12|numeric',
'enabled' => 'in:0,1',
]; ];
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
@@ -79,6 +81,7 @@ class CurrencyFormRequest extends Request
'code' => 'required|min:3|max:3', 'code' => 'required|min:3|max:3',
'symbol' => 'required|min:1|max:8', 'symbol' => 'required|min:1|max:8',
'decimal_places' => 'required|min:0|max:12|numeric', 'decimal_places' => 'required|min:0|max:12|numeric',
'enabled' => 'in:0,1',
]; ];
} }

View File

@@ -35,6 +35,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property int $decimal_places * @property int $decimal_places
* @property int $id * @property int $id
* @property string name * @property string name
* @property bool $enabled
* *
*/ */
class TransactionCurrency extends Model class TransactionCurrency extends Model
@@ -52,9 +53,10 @@ class TransactionCurrency extends Model
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'decimal_places' => 'int', 'decimal_places' => 'int',
'enabled' => 'bool',
]; ];
/** @var array Fields that can be filled */ /** @var array Fields that can be filled */
protected $fillable = ['name', 'code', 'symbol', 'decimal_places']; protected $fillable = ['name', 'code', 'symbol', 'decimal_places', 'enabled'];
/** /**
* Route binder. Converts the key in the URL to the specified object (or throw 404). * Route binder. Converts the key in the URL to the specified object (or throw 404).
@@ -84,4 +86,13 @@ class TransactionCurrency extends Model
{ {
return $this->hasMany(TransactionJournal::class); return $this->hasMany(TransactionJournal::class);
} }
/**
* @codeCoverageIgnore
* @return HasMany
*/
public function transactions(): HasMany
{
return $this->hasMany(Transaction::class);
}
} }

View File

@@ -24,6 +24,7 @@ namespace FireflyIII\Repositories\Currency;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Factory\TransactionCurrencyFactory; use FireflyIII\Factory\TransactionCurrencyFactory;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\CurrencyExchangeRate; use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\Preference; use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
@@ -55,39 +56,62 @@ class CurrencyRepository implements CurrencyRepositoryInterface
/** /**
* @param TransactionCurrency $currency * @param TransactionCurrency $currency
* *
* @return bool * @return int
*/ */
public function canDeleteCurrency(TransactionCurrency $currency): bool public function countJournals(TransactionCurrency $currency): int
{ {
if ($this->countJournals($currency) > 0) { return $currency->transactions()->count();
return false;
}
// is the only currency left
if (1 === $this->get()->count()) {
return false;
}
// is the default currency for the user or the system
$defaultCode = app('preferences')->getForUser($this->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
if ($currency->code === $defaultCode) {
return false;
}
// is the default currency for the system
$defaultSystemCode = config('firefly.default_currency', 'EUR');
return !($currency->code === $defaultSystemCode);
} }
/** /**
* @param TransactionCurrency $currency * @param TransactionCurrency $currency
* *
* @return int * @return bool
*/ */
public function countJournals(TransactionCurrency $currency): int public function currencyInUse(TransactionCurrency $currency): bool
{ {
return $currency->transactionJournals()->count(); Log::debug(sprintf('Now in currencyInUse() for #%d ("%s")', $currency->id, $currency->code));
$countJournals = $this->countJournals($currency);
if ($countJournals > 0) {
Log::debug(sprintf('Count journals is %d, return true.', $countJournals));
return true;
}
// is the only currency left
if (1 === $this->getAll()->count()) {
Log::debug('Is the last currency in the system, return true. ', $countJournals);
return true;
}
// is being used in accounts:
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string)$currency->id))->count();
if ($meta > 0) {
Log::debug(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return true;
}
// is the default currency for the user or the system
$defaultCode = app('preferences')->getForUser($this->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
if ($currency->code === $defaultCode) {
Log::debug('Is the default currency of the user, return true.');
return true;
}
// is the default currency for the system
$defaultSystemCode = config('firefly.default_currency', 'EUR');
$result = $currency->code === $defaultSystemCode;
if (true === $result) {
Log::debug('Is the default currency of the SYSTEM, return true.');
return true;
}
Log::debug('Currency is not used, return false.');
return false;
} }
/** /**
@@ -110,12 +134,58 @@ class CurrencyRepository implements CurrencyRepositoryInterface
return true; return true;
} }
/**
* Disables a currency
*
* @param TransactionCurrency $currency
*/
public function disable(TransactionCurrency $currency): void
{
$currency->enabled = false;
$currency->save();
}
/**
* @param TransactionCurrency $currency
* Enables a currency
*/
public function enable(TransactionCurrency $currency): void
{
$currency->enabled = true;
$currency->save();
}
/**
* Find by ID, return NULL if not found.
*
* @param int $currencyId
*
* @return TransactionCurrency|null
*/
public function find(int $currencyId): ?TransactionCurrency
{
return TransactionCurrency::find($currencyId);
}
/**
* Find by currency code, return NULL if unfound.
*
* @param string $currencyCode
*
* @return TransactionCurrency|null
*/
public function findByCode(string $currencyCode): ?TransactionCurrency
{
return TransactionCurrency::where('code', $currencyCode)->first();
}
/** /**
* Find by currency code, return NULL if unfound. * Find by currency code, return NULL if unfound.
* Used in Import Currency! * Used in Import Currency!
* *
* @param string $currencyCode * @param string $currencyCode
* *
* @deprecated
* @return TransactionCurrency|null * @return TransactionCurrency|null
*/ */
public function findByCodeNull(string $currencyCode): ?TransactionCurrency public function findByCodeNull(string $currencyCode): ?TransactionCurrency
@@ -123,12 +193,25 @@ class CurrencyRepository implements CurrencyRepositoryInterface
return TransactionCurrency::where('code', $currencyCode)->first(); return TransactionCurrency::where('code', $currencyCode)->first();
} }
/**
* Find by currency name.
*
* @param string $currencyName
*
* @return TransactionCurrency
*/
public function findByName(string $currencyName): ?TransactionCurrency
{
return TransactionCurrency::whereName($currencyName)->first();
}
/** /**
* Find by currency name or return null. * Find by currency name or return null.
* Used in Import Currency! * Used in Import Currency!
* *
* @param string $currencyName * @param string $currencyName
* *
* @deprecated
* @return TransactionCurrency * @return TransactionCurrency
*/ */
public function findByNameNull(string $currencyName): ?TransactionCurrency public function findByNameNull(string $currencyName): ?TransactionCurrency
@@ -136,12 +219,25 @@ class CurrencyRepository implements CurrencyRepositoryInterface
return TransactionCurrency::whereName($currencyName)->first(); return TransactionCurrency::whereName($currencyName)->first();
} }
/**
* Find by currency symbol.
*
* @param string $currencySymbol
*
* @return TransactionCurrency
*/
public function findBySymbol(string $currencySymbol): ?TransactionCurrency
{
return TransactionCurrency::whereSymbol($currencySymbol)->first();
}
/** /**
* Find by currency symbol or return NULL * Find by currency symbol or return NULL
* Used in Import Currency! * Used in Import Currency!
* *
* @param string $currencySymbol * @param string $currencySymbol
* *
* @deprecated
* @return TransactionCurrency * @return TransactionCurrency
*/ */
public function findBySymbolNull(string $currencySymbol): ?TransactionCurrency public function findBySymbolNull(string $currencySymbol): ?TransactionCurrency
@@ -155,6 +251,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
* *
* @param int $currencyId * @param int $currencyId
* *
* @deprecated
* @return TransactionCurrency|null * @return TransactionCurrency|null
*/ */
public function findNull(int $currencyId): ?TransactionCurrency public function findNull(int $currencyId): ?TransactionCurrency
@@ -166,6 +263,14 @@ class CurrencyRepository implements CurrencyRepositoryInterface
* @return Collection * @return Collection
*/ */
public function get(): Collection public function get(): Collection
{
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
/**
* @return Collection
*/
public function getAll(): Collection
{ {
return TransactionCurrency::orderBy('code', 'ASC')->get(); return TransactionCurrency::orderBy('code', 'ASC')->get();
} }

View File

@@ -39,7 +39,7 @@ interface CurrencyRepositoryInterface
* *
* @return bool * @return bool
*/ */
public function canDeleteCurrency(TransactionCurrency $currency): bool; public function currencyInUse(TransactionCurrency $currency): bool;
/** /**
* @param TransactionCurrency $currency * @param TransactionCurrency $currency
@@ -55,6 +55,38 @@ interface CurrencyRepositoryInterface
*/ */
public function destroy(TransactionCurrency $currency): bool; public function destroy(TransactionCurrency $currency): bool;
/**
* Disables a currency
*
* @param TransactionCurrency $currency
*/
public function disable(TransactionCurrency $currency): void;
/**
* Enables a currency
*
* @param TransactionCurrency $currency
*/
public function enable(TransactionCurrency $currency): void;
/**
* Find by ID, return NULL if not found.
*
* @param int $currencyId
*
* @return TransactionCurrency|null
*/
public function find(int $currencyId): ?TransactionCurrency;
/**
* Find by currency code, return NULL if unfound.
*
* @param string $currencyCode
*
* @return TransactionCurrency|null
*/
public function findByCode(string $currencyCode): ?TransactionCurrency;
/** /**
* Find by currency code, return NULL if unfound. * Find by currency code, return NULL if unfound.
* *
@@ -64,6 +96,15 @@ interface CurrencyRepositoryInterface
*/ */
public function findByCodeNull(string $currencyCode): ?TransactionCurrency; public function findByCodeNull(string $currencyCode): ?TransactionCurrency;
/**
* Find by currency name.
*
* @param string $currencyName
*
* @return TransactionCurrency
*/
public function findByName(string $currencyName): ?TransactionCurrency;
/** /**
* Find by currency name. * Find by currency name.
* *
@@ -73,6 +114,15 @@ interface CurrencyRepositoryInterface
*/ */
public function findByNameNull(string $currencyName): ?TransactionCurrency; public function findByNameNull(string $currencyName): ?TransactionCurrency;
/**
* Find by currency symbol.
*
* @param string $currencySymbol
*
* @return TransactionCurrency
*/
public function findBySymbol(string $currencySymbol): ?TransactionCurrency;
/** /**
* Find by currency symbol. * Find by currency symbol.
* *
@@ -96,6 +146,11 @@ interface CurrencyRepositoryInterface
*/ */
public function get(): Collection; public function get(): Collection;
/**
* @return Collection
*/
public function getAll(): Collection;
/** /**
* @param array $ids * @param array $ids
* *

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Services\Internal\Update;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use Log; use Log;
/** /**
* Class CurrencyUpdateService * Class CurrencyUpdateService
*/ */
@@ -51,6 +52,7 @@ class CurrencyUpdateService
$currency->code = $data['code']; $currency->code = $data['code'];
$currency->symbol = $data['symbol']; $currency->symbol = $data['symbol'];
$currency->name = $data['name']; $currency->name = $data['name'];
$currency->enabled = $data['enabled'];
$currency->decimal_places = $data['decimal_places']; $currency->decimal_places = $data['decimal_places'];
$currency->save(); $currency->save();

View File

@@ -159,6 +159,14 @@ class Amount
return TransactionCurrency::orderBy('code', 'ASC')->get(); return TransactionCurrency::orderBy('code', 'ASC')->get();
} }
/**
* @return Collection
*/
public function getCurrencies(): Collection
{
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
/** /**
* @return string * @return string
*/ */

View File

@@ -278,6 +278,19 @@ class ExpandedForm
return $this->currencyField($name, 'balance', $value, $options); return $this->currencyField($name, 'balance', $value, $options);
} }
/**
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
* @throws FireflyException
*/
public function balanceAll(string $name, $value = null, array $options = null): string
{
return $this->allCurrencyField($name, 'balance', $value, $options);
}
/** /**
* @param string $name * @param string $name
* @param int $value * @param int $value
@@ -913,6 +926,60 @@ class ExpandedForm
* @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/ */
protected function currencyField(string $name, string $view, $value = null, array $options = null): string protected function currencyField(string $name, string $view, $value = null, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$defaultCurrency = $options['currency'] ?? Amt::getDefaultCurrency();
/** @var Collection $currencies */
$currencies = app('amount')->getCurrencies();
unset($options['currency'], $options['placeholder']);
// perhaps the currency has been sent to us in the field $amount_currency_id_$name (amount_currency_id_amount)
$preFilled = session('preFilled');
$key = 'amount_currency_id_' . $name;
$sentCurrencyId = isset($preFilled[$key]) ? (int)$preFilled[$key] : $defaultCurrency->id;
Log::debug(sprintf('Sent currency ID is %d', $sentCurrencyId));
// find this currency in set of currencies:
foreach ($currencies as $currency) {
if ($currency->id === $sentCurrencyId) {
$defaultCurrency = $currency;
Log::debug(sprintf('default currency is now %s', $defaultCurrency->code));
break;
}
}
// make sure value is formatted nicely:
if (null !== $value && '' !== $value) {
$value = round($value, $defaultCurrency->decimal_places);
}
try {
$html = view('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render currencyField(): %s', $e->getMessage()));
$html = 'Could not render currencyField.';
}
return $html;
}
/** @noinspection MoreThanThreeArgumentsInspection */
/**
* @param string $name
* @param string $view
* @param mixed $value
* @param array $options
*
* @return string
* @throws FireflyException
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function allCurrencyField(string $name, string $view, $value = null, array $options = null): string
{ {
$label = $this->label($name, $options); $label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options); $options = $this->expandOptionArray($name, $label, $options);

View File

@@ -33,6 +33,7 @@ use Illuminate\Support\Facades\Facade;
* *
* @method string formatAnything(TransactionCurrency $format, string $amount, bool $coloured = true) * @method string formatAnything(TransactionCurrency $format, string $amount, bool $coloured = true)
* @method Collection getAllCurrencies() * @method Collection getAllCurrencies()
* @method Collection getCurrencies()
* @method string getCurrencyCode() * @method string getCurrencyCode()
* @method string getCurrencySymbol() * @method string getCurrencySymbol()
* @method TransactionCurrency getDefaultCurrency() * @method TransactionCurrency getDefaultCurrency()

View File

@@ -83,6 +83,7 @@ class CurrencyTransformer extends TransformerAbstract
'symbol' => $currency->symbol, 'symbol' => $currency->symbol,
'decimal_places' => (int)$currency->decimal_places, 'decimal_places' => (int)$currency->decimal_places,
'default' => $isDefault, 'default' => $isDefault,
'enabled' => $currency->enabled,
'links' => [ 'links' => [
[ [
'rel' => 'self', 'rel' => 'self',

View File

@@ -165,7 +165,8 @@ return [
// currencies: index, create // currencies: index, create
'currencies_index' => [ 'currencies_index' => [
'intro' => [], 'intro' => [],
'default' => ['element' => '.defaultCurrency'], 'default' => ['element' => '#default-currency'],
'buttons' => ['element' => '.buttons',]
], ],
'currencies_create' => [ 'currencies_create' => [
'code' => ['element' => '#ffInput_code',], 'code' => ['element' => '#ffInput_code',],

View File

@@ -188,7 +188,7 @@ return [
'is_safe' => ['date', 'text', 'select', 'balance', 'optionsList', 'checkbox', 'amount', 'tags', 'integer', 'textarea', 'location', 'file', 'is_safe' => ['date', 'text', 'select', 'balance', 'optionsList', 'checkbox', 'amount', 'tags', 'integer', 'textarea', 'location', 'file',
'staticText', 'password', 'nonSelectableAmount', 'number', 'assetAccountList', 'amountNoCurrency', 'currencyList', 'staticText', 'password', 'nonSelectableAmount', 'number', 'assetAccountList', 'amountNoCurrency', 'currencyList',
'ruleGroupList', 'assetAccountCheckList', 'ruleGroupListWithEmpty', 'piggyBankList', 'currencyListEmpty', 'ruleGroupList', 'assetAccountCheckList', 'ruleGroupListWithEmpty', 'piggyBankList', 'currencyListEmpty',
'activeAssetAccountList', 'percentage', 'activeLongAccountList', 'longAccountList',],], 'activeAssetAccountList', 'percentage', 'activeLongAccountList', 'longAccountList','balanceAll'],],
'Form' => ['is_safe' => ['input', 'select', 'checkbox', 'model', 'open', 'radio', 'textarea', 'file',], 'Form' => ['is_safe' => ['input', 'select', 'checkbox', 'model', 'open', 'radio', 'textarea', 'file',],
], ],
], ],

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class ChangesForV479
*/
class ChangesForV479 extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table(
'transaction_currencies',
function (Blueprint $table) {
$table->boolean('enabled')->default(0)->after('deleted_at');
}
);
}
}

View File

@@ -32,7 +32,7 @@ class TransactionCurrencySeeder extends Seeder
{ {
$currencies = []; $currencies = [];
// european currencies // european currencies
$currencies[] = ['code' => 'EUR', 'name' => 'Euro', 'symbol' => '€', 'decimal_places' => 2]; $currencies[] = ['code' => 'EUR', 'name' => 'Euro', 'symbol' => '€', 'decimal_places' => 2,'enabled' => 1];
$currencies[] = ['code' => 'HUF', 'name' => 'Hungarian forint', 'symbol' => 'Ft', 'decimal_places' => 2]; $currencies[] = ['code' => 'HUF', 'name' => 'Hungarian forint', 'symbol' => 'Ft', 'decimal_places' => 2];
$currencies[] = ['code' => 'GBP', 'name' => 'British Pound', 'symbol' => '£', 'decimal_places' => 2]; $currencies[] = ['code' => 'GBP', 'name' => 'British Pound', 'symbol' => '£', 'decimal_places' => 2];
$currencies[] = ['code' => 'UAH', 'name' => 'Ukrainian hryvnia', 'symbol' => '₴', 'decimal_places' => 2]; $currencies[] = ['code' => 'UAH', 'name' => 'Ukrainian hryvnia', 'symbol' => '₴', 'decimal_places' => 2];

View File

@@ -624,14 +624,21 @@ return [
'update_currency' => 'Update currency', 'update_currency' => 'Update currency',
'new_default_currency' => ':name is now the default currency.', 'new_default_currency' => ':name is now the default currency.',
'cannot_delete_currency' => 'Cannot delete :name because it is still in use.', 'cannot_delete_currency' => 'Cannot delete :name because it is still in use.',
'cannot_disable_currency' => 'Cannot disable :name because it is still in use.',
'deleted_currency' => 'Currency :name deleted', 'deleted_currency' => 'Currency :name deleted',
'created_currency' => 'Currency :name created', 'created_currency' => 'Currency :name created',
'could_not_store_currency' => 'Could not store the new currency.', 'could_not_store_currency' => 'Could not store the new currency.',
'updated_currency' => 'Currency :name updated', 'updated_currency' => 'Currency :name updated',
'ask_site_owner' => 'Please ask :owner to add, remove or edit currencies.', 'ask_site_owner' => 'Please ask :owner to add, remove or edit currencies.',
'currencies_intro' => 'Firefly III supports various currencies which you can set and enable here.', 'currencies_intro' => 'Firefly III supports various currencies which you can set and enable here.',
'make_default_currency' => 'make default', 'make_default_currency' => 'Make default',
'default_currency' => 'default', 'default_currency' => 'default',
'currency_is_disabled' => 'Disabled',
'enable_currency' => 'Enable',
'disable_currency' => 'Disable',
'currencies_default_disabled' => 'Most of these currencies are disabled by default. To use them, you must enable them first.',
'currency_is_now_enabled' => 'Currency ":name" has been enabled',
'currency_is_now_disabled' => 'Currency ":name" has been disabled',
// forms: // forms:
'mandatoryFields' => 'Mandatory fields', 'mandatoryFields' => 'Mandatory fields',

View File

@@ -30,6 +30,7 @@ return [
'credit_card_limit' => 'Credit card limit', 'credit_card_limit' => 'Credit card limit',
'automatch' => 'Match automatically', 'automatch' => 'Match automatically',
'skip' => 'Skip', 'skip' => 'Skip',
'enabled' => 'Enabled',
'name' => 'Name', 'name' => 'Name',
'active' => 'Active', 'active' => 'Active',
'amount_min' => 'Minimum amount', 'amount_min' => 'Minimum amount',

View File

@@ -130,7 +130,8 @@ return [
// currencies // currencies
'currencies_index_intro' => 'Firefly III supports multiple currencies, which you can change on this page.', 'currencies_index_intro' => 'Firefly III supports multiple currencies, which you can change on this page.',
'currencies_index_default' => 'Firefly III has one default currency. You can always switch of course using these buttons.', 'currencies_index_default' => 'Firefly III has one default currency.',
'currencies_index_buttons' => 'Use these buttons to change the default currency or enable other currencies.',
// create currency // create currency
'currencies_create_code' => 'This code should be ISO compliant (Google it for your new currency).', 'currencies_create_code' => 'This code should be ISO compliant (Google it for your new currency).',

View File

@@ -19,6 +19,7 @@
{{ ExpandedForm.text('symbol',null,{'maxlength' : 8}) }} {{ ExpandedForm.text('symbol',null,{'maxlength' : 8}) }}
{{ ExpandedForm.text('code',null,{'maxlength' : 3}) }} {{ ExpandedForm.text('code',null,{'maxlength' : 3}) }}
{{ ExpandedForm.integer('decimal_places',null,{'maxlength' : 2,'min': 0,'max': 12}) }} {{ ExpandedForm.integer('decimal_places',null,{'maxlength' : 2,'min': 0,'max': 12}) }}
{{ ExpandedForm.checkbox('enabled',null) }}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -10,11 +10,15 @@
<div class="box"> <div class="box">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title">{{ 'currencies'|_ }}</h3> <h3 class="box-title">{{ 'currencies'|_ }}</h3>
<a class="btn btn-success pull-right" href="{{ route('currencies.create') }}">{{ 'create_currency'|_ }}</a>
</div> </div>
<div class="box-body"> <div class="box-body">
<p class="text-info"> <p class="text-info">
{{ 'currencies_intro'|_ }} {{ 'currencies_intro'|_ }}
</p> </p>
<p class="text-info">
{{ 'currencies_default_disabled'|_ }}
</p>
{% if currencies|length > 0 %} {% if currencies|length > 0 %}
<div style="padding-left:8px;"> <div style="padding-left:8px;">
{{ currencies.render|raw }} {{ currencies.render|raw }}
@@ -41,15 +45,42 @@
</div> </div>
</td> </td>
{% endif %} {% endif %}
<td>{{ currency.name }} ({{ currency.code }}) ({{ currency.symbol|raw }})</td> <td>
<td>{{ currency.decimal_places }}</td> {% if currency.enabled == false %}
<td class="defaultCurrency"> <span class="text-muted">
{% if currency.id == defaultCurrency.id %}
<span class="label label-success">{{ 'default_currency'|_ }}</span>
{% else %}
<a class="btn btn-info btn-xs"
href="{{ route('currencies.default',currency.id) }}">{{ 'make_default_currency'|_ }}</a>
{% endif %} {% endif %}
{{ currency.name }} ({{ currency.code }}) ({{ currency.symbol|raw }})
{% if currency.id == defaultCurrency.id %}
<span class="label label-success" id="default-currency">{{ 'default_currency'|_ }}</span>
{% endif %}
{% if currency.enabled == false %}
</span>
<br><small class="text-danger">{{ 'currency_is_disabled'|_ }}</small>
{% endif %}
</td>
<td>{{ currency.decimal_places }}</td>
<td class="buttons">
<div class="btn-group">
{% if currency.id != defaultCurrency.id %}
<a class="btn btn-default"
href="{{ route('currencies.default',currency.id) }}">
<i class="fa fa-fw fa-star"></i>
{{ 'make_default_currency'|_ }}</a>
{% endif %}
{% if currency.enabled %}
<a class="btn btn-default"
href="{{ route('currencies.disable',currency.id) }}">
<i class="fa fa-fw fa-square-o"></i>
{{ 'disable_currency'|_ }}</a>
{% endif %}
{% if not currency.enabled %}
<a class="btn btn-default"
href="{{ route('currencies.enable',currency.id) }}">
<i class="fa fa-fw fa-check-square-o"></i>
{{ 'enable_currency'|_ }}</a>
{% endif %}
</div>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@@ -24,7 +24,7 @@
{{ 'to_get_started'|_ }} {{ 'to_get_started'|_ }}
</p> </p>
{{ ExpandedForm.text('bank_name') }} {{ ExpandedForm.text('bank_name') }}
{{ ExpandedForm.balance('bank_balance') }} {{ ExpandedForm.balanceAll('bank_balance') }}
<p class="text-success"> <p class="text-success">
{{ 'currency_not_present'|_ }} {{ 'currency_not_present'|_ }}

View File

@@ -273,6 +273,8 @@ Route::group(
Route::get('edit/{currency}', ['uses' => 'CurrencyController@edit', 'as' => 'edit']); Route::get('edit/{currency}', ['uses' => 'CurrencyController@edit', 'as' => 'edit']);
Route::get('delete/{currency}', ['uses' => 'CurrencyController@delete', 'as' => 'delete']); Route::get('delete/{currency}', ['uses' => 'CurrencyController@delete', 'as' => 'delete']);
Route::get('default/{currency}', ['uses' => 'CurrencyController@defaultCurrency', 'as' => 'default']); Route::get('default/{currency}', ['uses' => 'CurrencyController@defaultCurrency', 'as' => 'default']);
Route::get('enable/{currency}', ['uses' => 'CurrencyController@enableCurrency', 'as' => 'enable']);
Route::get('disable/{currency}', ['uses' => 'CurrencyController@disableCurrency', 'as' => 'disable']);
Route::post('store', ['uses' => 'CurrencyController@store', 'as' => 'store']); Route::post('store', ['uses' => 'CurrencyController@store', 'as' => 'store']);
Route::post('update/{currency}', ['uses' => 'CurrencyController@update', 'as' => 'update']); Route::post('update/{currency}', ['uses' => 'CurrencyController@update', 'as' => 'update']);