mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Expand API administration validation
This commit is contained in:
parent
2c4f2082fe
commit
74291b3870
@ -27,6 +27,7 @@ namespace FireflyIII\Api\V2\Controllers\Chart;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Api\V2\Controllers\Controller;
|
use FireflyIII\Api\V2\Controllers\Controller;
|
||||||
use FireflyIII\Api\V2\Request\Chart\DashboardChartRequest;
|
use FireflyIII\Api\V2\Request\Chart\DashboardChartRequest;
|
||||||
|
use FireflyIII\Enums\UserRoleEnum;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
@ -46,6 +47,7 @@ class AccountController extends Controller
|
|||||||
use ValidatesUserGroupTrait;
|
use ValidatesUserGroupTrait;
|
||||||
|
|
||||||
private AccountRepositoryInterface $repository;
|
private AccountRepositoryInterface $repository;
|
||||||
|
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@ -54,9 +56,7 @@ class AccountController extends Controller
|
|||||||
function ($request, $next) {
|
function ($request, $next) {
|
||||||
$this->repository = app(AccountRepositoryInterface::class);
|
$this->repository = app(AccountRepositoryInterface::class);
|
||||||
$userGroup = $this->validateUserGroup($request);
|
$userGroup = $this->validateUserGroup($request);
|
||||||
if (null !== $userGroup) {
|
$this->repository->setUserGroup($userGroup);
|
||||||
$this->repository->setUserGroup($userGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
@ -81,15 +81,15 @@ class AccountController extends Controller
|
|||||||
public function dashboard(DashboardChartRequest $request): JsonResponse
|
public function dashboard(DashboardChartRequest $request): JsonResponse
|
||||||
{
|
{
|
||||||
/** @var Carbon $start */
|
/** @var Carbon $start */
|
||||||
$start = $this->parameters->get('start');
|
$start = $this->parameters->get('start');
|
||||||
|
|
||||||
/** @var Carbon $end */
|
/** @var Carbon $end */
|
||||||
$end = $this->parameters->get('end');
|
$end = $this->parameters->get('end');
|
||||||
$end->endOfDay();
|
$end->endOfDay();
|
||||||
|
|
||||||
/** @var TransactionCurrency $default */
|
/** @var TransactionCurrency $default */
|
||||||
$default = app('amount')->getDefaultCurrency();
|
$default = app('amount')->getDefaultCurrency();
|
||||||
$params = $request->getAll();
|
$params = $request->getAll();
|
||||||
|
|
||||||
/** @var Collection $accounts */
|
/** @var Collection $accounts */
|
||||||
$accounts = $params['accounts'];
|
$accounts = $params['accounts'];
|
||||||
@ -105,7 +105,7 @@ class AccountController extends Controller
|
|||||||
$frontpage->save();
|
$frontpage->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
$accounts = $this->repository->getAccountsById($frontpage->data);
|
$accounts = $this->repository->getAccountsById($frontpage->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// both options are overruled by "preselected"
|
// both options are overruled by "preselected"
|
||||||
@ -121,11 +121,11 @@ class AccountController extends Controller
|
|||||||
|
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$currency = $this->repository->getAccountCurrency($account);
|
$currency = $this->repository->getAccountCurrency($account);
|
||||||
if (null === $currency) {
|
if (null === $currency) {
|
||||||
$currency = $default;
|
$currency = $default;
|
||||||
}
|
}
|
||||||
$currentSet = [
|
$currentSet = [
|
||||||
'label' => $account->name,
|
'label' => $account->name,
|
||||||
// the currency that belongs to the account.
|
// the currency that belongs to the account.
|
||||||
'currency_id' => (string)$currency->id,
|
'currency_id' => (string)$currency->id,
|
||||||
@ -144,25 +144,25 @@ class AccountController extends Controller
|
|||||||
'entries' => [],
|
'entries' => [],
|
||||||
'native_entries' => [],
|
'native_entries' => [],
|
||||||
];
|
];
|
||||||
$currentStart = clone $start;
|
$currentStart = clone $start;
|
||||||
$range = app('steam')->balanceInRange($account, $start, clone $end, $currency);
|
$range = app('steam')->balanceInRange($account, $start, clone $end, $currency);
|
||||||
$rangeConverted = app('steam')->balanceInRangeConverted($account, $start, clone $end, $default);
|
$rangeConverted = app('steam')->balanceInRangeConverted($account, $start, clone $end, $default);
|
||||||
|
|
||||||
$previous = array_values($range)[0];
|
$previous = array_values($range)[0];
|
||||||
$previousConverted = array_values($rangeConverted)[0];
|
$previousConverted = array_values($rangeConverted)[0];
|
||||||
while ($currentStart <= $end) {
|
while ($currentStart <= $end) {
|
||||||
$format = $currentStart->format('Y-m-d');
|
$format = $currentStart->format('Y-m-d');
|
||||||
$label = $currentStart->toAtomString();
|
$label = $currentStart->toAtomString();
|
||||||
$balance = array_key_exists($format, $range) ? $range[$format] : $previous;
|
$balance = array_key_exists($format, $range) ? $range[$format] : $previous;
|
||||||
$balanceConverted = array_key_exists($format, $rangeConverted) ? $rangeConverted[$format] : $previousConverted;
|
$balanceConverted = array_key_exists($format, $rangeConverted) ? $rangeConverted[$format] : $previousConverted;
|
||||||
$previous = $balance;
|
$previous = $balance;
|
||||||
$previousConverted = $balanceConverted;
|
$previousConverted = $balanceConverted;
|
||||||
|
|
||||||
$currentStart->addDay();
|
$currentStart->addDay();
|
||||||
$currentSet['entries'][$label] = $balance;
|
$currentSet['entries'][$label] = $balance;
|
||||||
$currentSet['native_entries'][$label] = $balanceConverted;
|
$currentSet['native_entries'][$label] = $balanceConverted;
|
||||||
}
|
}
|
||||||
$chartData[] = $currentSet;
|
$chartData[] = $currentSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json($this->clean($chartData));
|
return response()->json($this->clean($chartData));
|
||||||
|
@ -27,6 +27,7 @@ namespace FireflyIII\Api\V2\Controllers;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Carbon\Exceptions\InvalidDateException;
|
use Carbon\Exceptions\InvalidDateException;
|
||||||
use Carbon\Exceptions\InvalidFormatException;
|
use Carbon\Exceptions\InvalidFormatException;
|
||||||
|
use FireflyIII\Enums\UserRoleEnum;
|
||||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||||
use FireflyIII\Transformers\V2\AbstractTransformer;
|
use FireflyIII\Transformers\V2\AbstractTransformer;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
@ -55,6 +56,7 @@ class Controller extends BaseController
|
|||||||
|
|
||||||
protected const string CONTENT_TYPE = 'application/vnd.api+json';
|
protected const string CONTENT_TYPE = 'application/vnd.api+json';
|
||||||
protected ParameterBag $parameters;
|
protected ParameterBag $parameters;
|
||||||
|
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -26,6 +26,7 @@ namespace FireflyIII\Api\V2\Controllers\Model\Account;
|
|||||||
use FireflyIII\Api\V2\Controllers\Controller;
|
use FireflyIII\Api\V2\Controllers\Controller;
|
||||||
use FireflyIII\Api\V2\Request\Model\Account\IndexRequest;
|
use FireflyIII\Api\V2\Request\Model\Account\IndexRequest;
|
||||||
use FireflyIII\Api\V2\Request\Model\Transaction\InfiniteListRequest;
|
use FireflyIII\Api\V2\Request\Model\Transaction\InfiniteListRequest;
|
||||||
|
use FireflyIII\Enums\UserRoleEnum;
|
||||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Transformers\V2\AccountTransformer;
|
use FireflyIII\Transformers\V2\AccountTransformer;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
@ -36,6 +37,7 @@ class IndexController extends Controller
|
|||||||
public const string RESOURCE_KEY = 'accounts';
|
public const string RESOURCE_KEY = 'accounts';
|
||||||
|
|
||||||
private AccountRepositoryInterface $repository;
|
private AccountRepositoryInterface $repository;
|
||||||
|
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY, UserRoleEnum::MANAGE_TRANSACTIONS];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AccountController constructor.
|
* AccountController constructor.
|
||||||
@ -47,10 +49,8 @@ class IndexController extends Controller
|
|||||||
function ($request, $next) {
|
function ($request, $next) {
|
||||||
$this->repository = app(AccountRepositoryInterface::class);
|
$this->repository = app(AccountRepositoryInterface::class);
|
||||||
// new way of user group validation
|
// new way of user group validation
|
||||||
$userGroup = $this->validateUserGroup($request);
|
$userGroup = $this->validateUserGroup($request);
|
||||||
if (null !== $userGroup) {
|
$this->repository->setUserGroup($userGroup);
|
||||||
$this->repository->setUserGroup($userGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
@ -77,8 +77,7 @@ class IndexController extends Controller
|
|||||||
|
|
||||||
return response()
|
return response()
|
||||||
->json($this->jsonApiList('accounts', $paginator, $transformer))
|
->json($this->jsonApiList('accounts', $paginator, $transformer))
|
||||||
->header('Content-Type', self::CONTENT_TYPE)
|
->header('Content-Type', self::CONTENT_TYPE);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function infiniteList(InfiniteListRequest $request): JsonResponse
|
public function infiniteList(InfiniteListRequest $request): JsonResponse
|
||||||
@ -86,7 +85,7 @@ class IndexController extends Controller
|
|||||||
$this->repository->resetAccountOrder();
|
$this->repository->resetAccountOrder();
|
||||||
|
|
||||||
// get accounts of the specified type, and return.
|
// get accounts of the specified type, and return.
|
||||||
$types = $request->getAccountTypes();
|
$types = $request->getAccountTypes();
|
||||||
|
|
||||||
// get from repository
|
// get from repository
|
||||||
$accounts = $this->repository->getAccountsInOrder($types, $request->getSortInstructions('accounts'), $request->getStartRow(), $request->getEndRow());
|
$accounts = $this->repository->getAccountsInOrder($types, $request->getSortInstructions('accounts'), $request->getStartRow(), $request->getEndRow());
|
||||||
@ -98,7 +97,6 @@ class IndexController extends Controller
|
|||||||
|
|
||||||
return response()
|
return response()
|
||||||
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
|
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
|
||||||
->header('Content-Type', self::CONTENT_TYPE)
|
->header('Content-Type', self::CONTENT_TYPE);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,9 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Api\V2\Controllers\Model\Account;
|
namespace FireflyIII\Api\V2\Controllers\Model\Account;
|
||||||
|
|
||||||
use FireflyIII\Api\V2\Controllers\Controller;
|
use FireflyIII\Api\V2\Controllers\Controller;
|
||||||
|
use FireflyIII\Enums\UserRoleEnum;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Transformers\V2\AccountTransformer;
|
use FireflyIII\Transformers\V2\AccountTransformer;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
@ -36,6 +38,28 @@ use Illuminate\Http\JsonResponse;
|
|||||||
*/
|
*/
|
||||||
class ShowController extends Controller
|
class ShowController extends Controller
|
||||||
{
|
{
|
||||||
|
public const string RESOURCE_KEY = 'accounts';
|
||||||
|
|
||||||
|
private AccountRepositoryInterface $repository;
|
||||||
|
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY, UserRoleEnum::MANAGE_TRANSACTIONS];
|
||||||
|
/**
|
||||||
|
* AccountController constructor.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->middleware(
|
||||||
|
function ($request, $next) {
|
||||||
|
$this->repository = app(AccountRepositoryInterface::class);
|
||||||
|
// new way of user group validation
|
||||||
|
$userGroup = $this->validateUserGroup($request);
|
||||||
|
$this->repository->setUserGroup($userGroup);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO this endpoint is not yet reachable.
|
* TODO this endpoint is not yet reachable.
|
||||||
*/
|
*/
|
||||||
|
@ -76,14 +76,12 @@ class BasicController extends Controller
|
|||||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||||
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
||||||
|
|
||||||
$userGroup = $this->validateUserGroup($request);
|
$userGroup = $this->validateUserGroup($request);
|
||||||
if (null !== $userGroup) {
|
$this->abRepository->setUserGroup($userGroup);
|
||||||
$this->abRepository->setUserGroup($userGroup);
|
$this->accountRepository->setUserGroup($userGroup);
|
||||||
$this->accountRepository->setUserGroup($userGroup);
|
$this->billRepository->setUserGroup($userGroup);
|
||||||
$this->billRepository->setUserGroup($userGroup);
|
$this->budgetRepository->setUserGroup($userGroup);
|
||||||
$this->budgetRepository->setUserGroup($userGroup);
|
$this->opsRepository->setUserGroup($userGroup);
|
||||||
$this->opsRepository->setUserGroup($userGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
@ -101,8 +99,8 @@ class BasicController extends Controller
|
|||||||
public function basic(DateRequest $request): JsonResponse
|
public function basic(DateRequest $request): JsonResponse
|
||||||
{
|
{
|
||||||
// parameters for boxes:
|
// parameters for boxes:
|
||||||
$start = $this->parameters->get('start');
|
$start = $this->parameters->get('start');
|
||||||
$end = $this->parameters->get('end');
|
$end = $this->parameters->get('end');
|
||||||
|
|
||||||
// balance information:
|
// balance information:
|
||||||
$balanceData = $this->getBalanceInformation($start, $end);
|
$balanceData = $this->getBalanceInformation($start, $end);
|
||||||
@ -119,13 +117,13 @@ class BasicController extends Controller
|
|||||||
*/
|
*/
|
||||||
private function getBalanceInformation(Carbon $start, Carbon $end): array
|
private function getBalanceInformation(Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
$object = new SummaryBalanceGrouped();
|
$object = new SummaryBalanceGrouped();
|
||||||
$default = app('amount')->getDefaultCurrency();
|
$default = app('amount')->getDefaultCurrency();
|
||||||
|
|
||||||
$object->setDefault($default);
|
$object->setDefault($default);
|
||||||
|
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
// collect income of user using the new group collector.
|
// collect income of user using the new group collector.
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
@ -137,10 +135,9 @@ class BasicController extends Controller
|
|||||||
->setPage($this->parameters->get('page'))
|
->setPage($this->parameters->get('page'))
|
||||||
// set types of transactions to return.
|
// set types of transactions to return.
|
||||||
->setTypes([TransactionType::DEPOSIT])
|
->setTypes([TransactionType::DEPOSIT])
|
||||||
->setRange($start, $end)
|
->setRange($start, $end);
|
||||||
;
|
|
||||||
|
|
||||||
$set = $collector->getExtractedJournals();
|
$set = $collector->getExtractedJournals();
|
||||||
$object->groupTransactions('income', $set);
|
$object->groupTransactions('income', $set);
|
||||||
|
|
||||||
// collect expenses of user using the new group collector.
|
// collect expenses of user using the new group collector.
|
||||||
@ -153,9 +150,8 @@ class BasicController extends Controller
|
|||||||
->setPage($this->parameters->get('page'))
|
->setPage($this->parameters->get('page'))
|
||||||
// set types of transactions to return.
|
// set types of transactions to return.
|
||||||
->setTypes([TransactionType::WITHDRAWAL])
|
->setTypes([TransactionType::WITHDRAWAL])
|
||||||
->setRange($start, $end)
|
->setRange($start, $end);
|
||||||
;
|
$set = $collector->getExtractedJournals();
|
||||||
$set = $collector->getExtractedJournals();
|
|
||||||
$object->groupTransactions('expense', $set);
|
$object->groupTransactions('expense', $set);
|
||||||
|
|
||||||
return $object->groupData();
|
return $object->groupData();
|
||||||
@ -170,7 +166,7 @@ class BasicController extends Controller
|
|||||||
$paidAmount = $this->billRepository->sumPaidInRange($start, $end);
|
$paidAmount = $this->billRepository->sumPaidInRange($start, $end);
|
||||||
$unpaidAmount = $this->billRepository->sumUnpaidInRange($start, $end);
|
$unpaidAmount = $this->billRepository->sumUnpaidInRange($start, $end);
|
||||||
|
|
||||||
$return = [];
|
$return = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array $info
|
* @var array $info
|
||||||
@ -230,14 +226,14 @@ class BasicController extends Controller
|
|||||||
{
|
{
|
||||||
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
|
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
|
||||||
app('log')->debug('Now in getLeftToSpendInfo');
|
app('log')->debug('Now in getLeftToSpendInfo');
|
||||||
$return = [];
|
$return = [];
|
||||||
$today = today(config('app.timezone'));
|
$today = today(config('app.timezone'));
|
||||||
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
|
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
|
||||||
$budgets = $this->budgetRepository->getActiveBudgets();
|
$budgets = $this->budgetRepository->getActiveBudgets();
|
||||||
$spent = $this->opsRepository->listExpenses($start, $end, null, $budgets);
|
$spent = $this->opsRepository->listExpenses($start, $end, null, $budgets);
|
||||||
$default = app('amount')->getDefaultCurrency();
|
$default = app('amount')->getDefaultCurrency();
|
||||||
$currencies = [];
|
$currencies = [];
|
||||||
$converter = new ExchangeRateConverter();
|
$converter = new ExchangeRateConverter();
|
||||||
|
|
||||||
// native info:
|
// native info:
|
||||||
$nativeLeft = [
|
$nativeLeft = [
|
||||||
@ -263,8 +259,8 @@ class BasicController extends Controller
|
|||||||
*/
|
*/
|
||||||
foreach ($spent as $currencyId => $row) {
|
foreach ($spent as $currencyId => $row) {
|
||||||
app('log')->debug(sprintf('Processing spent array in currency #%d', $currencyId));
|
app('log')->debug(sprintf('Processing spent array in currency #%d', $currencyId));
|
||||||
$spent = '0';
|
$spent = '0';
|
||||||
$spentNative = '0';
|
$spentNative = '0';
|
||||||
|
|
||||||
// get the sum from the array of transactions (double loop but who cares)
|
// get the sum from the array of transactions (double loop but who cares)
|
||||||
/** @var array $budget */
|
/** @var array $budget */
|
||||||
@ -281,8 +277,8 @@ class BasicController extends Controller
|
|||||||
if ((int)$journal['foreign_currency_id'] === $default->id) {
|
if ((int)$journal['foreign_currency_id'] === $default->id) {
|
||||||
$amountNative = $journal['foreign_amount'];
|
$amountNative = $journal['foreign_amount'];
|
||||||
}
|
}
|
||||||
$spent = bcadd($spent, $amount);
|
$spent = bcadd($spent, $amount);
|
||||||
$spentNative = bcadd($spentNative, $amountNative);
|
$spentNative = bcadd($spentNative, $amountNative);
|
||||||
}
|
}
|
||||||
app('log')->debug(sprintf('Total spent in budget "%s" is %s', $budget['name'], $spent));
|
app('log')->debug(sprintf('Total spent in budget "%s" is %s', $budget['name'], $spent));
|
||||||
}
|
}
|
||||||
@ -298,9 +294,9 @@ class BasicController extends Controller
|
|||||||
app('log')->debug(sprintf('Amount left is %s', $left));
|
app('log')->debug(sprintf('Amount left is %s', $left));
|
||||||
|
|
||||||
// how much left per day?
|
// how much left per day?
|
||||||
$days = (int)$today->diffInDays($end, true) + 1;
|
$days = (int)$today->diffInDays($end, true) + 1;
|
||||||
$perDay = '0';
|
$perDay = '0';
|
||||||
$perDayNative = '0';
|
$perDayNative = '0';
|
||||||
if (0 !== $days && bccomp($left, '0') > -1) {
|
if (0 !== $days && bccomp($left, '0') > -1) {
|
||||||
$perDay = bcdiv($left, (string)$days);
|
$perDay = bcdiv($left, (string)$days);
|
||||||
}
|
}
|
||||||
@ -309,7 +305,7 @@ class BasicController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// left
|
// left
|
||||||
$return[] = [
|
$return[] = [
|
||||||
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
|
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
|
||||||
'value' => $left,
|
'value' => $left,
|
||||||
'currency_id' => (string)$row['currency_id'],
|
'currency_id' => (string)$row['currency_id'],
|
||||||
@ -318,10 +314,10 @@ class BasicController extends Controller
|
|||||||
'currency_decimal_places' => (int)$row['currency_decimal_places'],
|
'currency_decimal_places' => (int)$row['currency_decimal_places'],
|
||||||
];
|
];
|
||||||
// left (native)
|
// left (native)
|
||||||
$nativeLeft['value'] = $leftNative;
|
$nativeLeft['value'] = $leftNative;
|
||||||
|
|
||||||
// left per day:
|
// left per day:
|
||||||
$return[] = [
|
$return[] = [
|
||||||
'key' => sprintf('left-per-day-to-spend-in-%s', $row['currency_code']),
|
'key' => sprintf('left-per-day-to-spend-in-%s', $row['currency_code']),
|
||||||
'value' => $perDay,
|
'value' => $perDay,
|
||||||
'currency_id' => (string)$row['currency_id'],
|
'currency_id' => (string)$row['currency_id'],
|
||||||
@ -331,10 +327,10 @@ class BasicController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
// left per day (native)
|
// left per day (native)
|
||||||
$nativePerDay['value'] = $perDayNative;
|
$nativePerDay['value'] = $perDayNative;
|
||||||
}
|
}
|
||||||
$return[] = $nativeLeft;
|
$return[] = $nativeLeft;
|
||||||
$return[] = $nativePerDay;
|
$return[] = $nativePerDay;
|
||||||
$converter->summarize();
|
$converter->summarize();
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
@ -343,8 +339,8 @@ class BasicController extends Controller
|
|||||||
private function getNetWorthInfo(Carbon $start, Carbon $end): array
|
private function getNetWorthInfo(Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
/** @var UserGroup $userGroup */
|
/** @var UserGroup $userGroup */
|
||||||
$userGroup = auth()->user()->userGroup;
|
$userGroup = auth()->user()->userGroup;
|
||||||
$date = today(config('app.timezone'))->startOfDay();
|
$date = today(config('app.timezone'))->startOfDay();
|
||||||
// start and end in the future? use $end
|
// start and end in the future? use $end
|
||||||
if ($this->notInDateRange($date, $start, $end)) {
|
if ($this->notInDateRange($date, $start, $end)) {
|
||||||
/** @var Carbon $date */
|
/** @var Carbon $date */
|
||||||
@ -354,12 +350,12 @@ class BasicController extends Controller
|
|||||||
/** @var NetWorthInterface $netWorthHelper */
|
/** @var NetWorthInterface $netWorthHelper */
|
||||||
$netWorthHelper = app(NetWorthInterface::class);
|
$netWorthHelper = app(NetWorthInterface::class);
|
||||||
$netWorthHelper->setUserGroup($userGroup);
|
$netWorthHelper->setUserGroup($userGroup);
|
||||||
$allAccounts = $this->accountRepository->getActiveAccountsByType(
|
$allAccounts = $this->accountRepository->getActiveAccountsByType(
|
||||||
[AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT]
|
[AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT]
|
||||||
);
|
);
|
||||||
|
|
||||||
// filter list on preference of being included.
|
// filter list on preference of being included.
|
||||||
$filtered = $allAccounts->filter(
|
$filtered = $allAccounts->filter(
|
||||||
function (Account $account) {
|
function (Account $account) {
|
||||||
$includeNetWorth = $this->accountRepository->getMetaValue($account, 'include_net_worth');
|
$includeNetWorth = $this->accountRepository->getMetaValue($account, 'include_net_worth');
|
||||||
|
|
||||||
@ -367,10 +363,10 @@ class BasicController extends Controller
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
$netWorthSet = $netWorthHelper->byAccounts($filtered, $date);
|
$netWorthSet = $netWorthHelper->byAccounts($filtered, $date);
|
||||||
$return = [];
|
$return = [];
|
||||||
// in native amount
|
// in native amount
|
||||||
$return[] = [
|
$return[] = [
|
||||||
'key' => 'net-worth-in-native',
|
'key' => 'net-worth-in-native',
|
||||||
'value' => $netWorthSet['native']['balance'],
|
'value' => $netWorthSet['native']['balance'],
|
||||||
'currency_id' => (string)$netWorthSet['native']['currency_id'],
|
'currency_id' => (string)$netWorthSet['native']['currency_id'],
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Api\V2\Request\Chart;
|
namespace FireflyIII\Api\V2\Request\Chart;
|
||||||
|
|
||||||
|
use FireflyIII\Enums\UserRoleEnum;
|
||||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||||
use FireflyIII\Support\Request\ChecksLogin;
|
use FireflyIII\Support\Request\ChecksLogin;
|
||||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||||
@ -39,6 +40,8 @@ class DashboardChartRequest extends FormRequest
|
|||||||
use ConvertsDataTypes;
|
use ConvertsDataTypes;
|
||||||
use ValidatesUserGroupTrait;
|
use ValidatesUserGroupTrait;
|
||||||
|
|
||||||
|
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all data from the request.
|
* Get all data from the request.
|
||||||
*/
|
*/
|
||||||
|
@ -25,6 +25,7 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Exceptions;
|
namespace FireflyIII\Exceptions;
|
||||||
|
|
||||||
use FireflyIII\Jobs\MailError;
|
use FireflyIII\Jobs\MailError;
|
||||||
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
use Illuminate\Database\QueryException;
|
use Illuminate\Database\QueryException;
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
@ -98,6 +99,13 @@ class Handler extends ExceptionHandler
|
|||||||
return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404);
|
return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($e instanceof AuthorizationException && $expectsJson) {
|
||||||
|
// somehow Laravel handler does not catch this:
|
||||||
|
app('log')->debug('Return JSON unauthorized error.');
|
||||||
|
|
||||||
|
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthorizationException'], 401);
|
||||||
|
}
|
||||||
|
|
||||||
if ($e instanceof AuthenticationException && $expectsJson) {
|
if ($e instanceof AuthenticationException && $expectsJson) {
|
||||||
// somehow Laravel handler does not catch this:
|
// somehow Laravel handler does not catch this:
|
||||||
app('log')->debug('Return JSON unauthenticated error.');
|
app('log')->debug('Return JSON unauthenticated error.');
|
||||||
|
@ -32,6 +32,7 @@ use FireflyIII\Http\Middleware\Installer;
|
|||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as UserGroupAccountRepositoryInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -61,8 +62,8 @@ class HomeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function dateRange(Request $request): JsonResponse
|
public function dateRange(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$stringStart = '';
|
$stringStart = '';
|
||||||
$stringEnd = '';
|
$stringEnd = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stringStart = e((string)$request->get('start'));
|
$stringStart = e((string)$request->get('start'));
|
||||||
@ -97,7 +98,7 @@ class HomeController extends Controller
|
|||||||
app('log')->debug('Range is now marked as "custom".');
|
app('log')->debug('Range is now marked as "custom".');
|
||||||
}
|
}
|
||||||
|
|
||||||
$diff = $start->diffInDays($end, true) + 1;
|
$diff = $start->diffInDays($end, true) + 1;
|
||||||
|
|
||||||
if ($diff > 366) {
|
if ($diff > 366) {
|
||||||
$request->session()->flash('warning', (string)trans('firefly.warning_much_data', ['days' => (int)$diff]));
|
$request->session()->flash('warning', (string)trans('firefly.warning_much_data', ['days' => (int)$diff]));
|
||||||
@ -120,13 +121,27 @@ class HomeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index(AccountRepositoryInterface $repository): mixed
|
public function index(AccountRepositoryInterface $repository): mixed
|
||||||
{
|
{
|
||||||
$types = config('firefly.accountTypesByIdentifier.asset');
|
$types = config('firefly.accountTypesByIdentifier.asset');
|
||||||
$count = $repository->count($types);
|
$count = $repository->count($types);
|
||||||
Log::channel('audit')->info('User visits homepage.');
|
Log::channel('audit')->info('User visits homepage.');
|
||||||
|
|
||||||
if (0 === $count) {
|
if (0 === $count) {
|
||||||
return redirect(route('new-user.index'));
|
return redirect(route('new-user.index'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('v1' === (string)config('view.layout')) {
|
||||||
|
return $this->indexV1($repository);
|
||||||
|
}
|
||||||
|
if ('v2' === (string)config('view.layout')) {
|
||||||
|
return $this->indexV2();
|
||||||
|
}
|
||||||
|
throw new FireflyException('Invalid layout configuration');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function indexV1(AccountRepositoryInterface $repository): mixed
|
||||||
|
{
|
||||||
|
$types = config('firefly.accountTypesByIdentifier.asset');
|
||||||
|
$count = $repository->count($types);
|
||||||
$subTitle = (string)trans('firefly.welcome_back');
|
$subTitle = (string)trans('firefly.welcome_back');
|
||||||
$transactions = [];
|
$transactions = [];
|
||||||
$frontpage = app('preferences')->getFresh('frontpageAccounts', $repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray());
|
$frontpage = app('preferences')->getFresh('frontpageAccounts', $repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray());
|
||||||
@ -136,15 +151,12 @@ class HomeController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @var Carbon $start */
|
/** @var Carbon $start */
|
||||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
|
||||||
|
|
||||||
/** @var Carbon $end */
|
/** @var Carbon $end */
|
||||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||||
$accounts = $repository->getAccountsById($frontpageArray);
|
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||||
$today = today(config('app.timezone'));
|
$accounts = $repository->getAccountsById($frontpageArray);
|
||||||
|
$today = today(config('app.timezone'));
|
||||||
// sort frontpage accounts by order
|
$accounts = $accounts->sortBy('order'); // sort frontpage accounts by order
|
||||||
$accounts = $accounts->sortBy('order');
|
|
||||||
|
|
||||||
app('log')->debug('Frontpage accounts are ', $frontpageArray);
|
app('log')->debug('Frontpage accounts are ', $frontpageArray);
|
||||||
|
|
||||||
@ -154,16 +166,30 @@ class HomeController extends Controller
|
|||||||
// collect groups for each transaction.
|
// collect groups for each transaction.
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setAccounts(new Collection([$account]))->withAccountInformation()->setRange($start, $end)->setLimit(10)->setPage(1);
|
$collector->setAccounts(new Collection([$account]))->withAccountInformation()->setRange($start, $end)->setLimit(10)->setPage(1);
|
||||||
$set = $collector->getExtractedJournals();
|
$set = $collector->getExtractedJournals();
|
||||||
$transactions[] = ['transactions' => $set, 'account' => $account];
|
$transactions[] = ['transactions' => $set, 'account' => $account];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
event(new RequestedVersionCheckStatus($user));
|
event(new RequestedVersionCheckStatus($user));
|
||||||
|
|
||||||
return view('index', compact('count', 'subTitle', 'transactions', 'billCount', 'start', 'end', 'today'));
|
return view('index', compact('count', 'subTitle', 'transactions', 'billCount', 'start', 'end', 'today'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function indexV2(): mixed
|
||||||
|
{
|
||||||
|
$subTitle = (string)trans('firefly.welcome_back');
|
||||||
|
|
||||||
|
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||||
|
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||||
|
|
||||||
|
/** @var User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
event(new RequestedVersionCheckStatus($user));
|
||||||
|
|
||||||
|
return view('index', compact( 'subTitle','start','end'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Support\Http\Api;
|
namespace FireflyIII\Support\Http\Api;
|
||||||
|
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Enums\UserRoleEnum;
|
||||||
use FireflyIII\Models\GroupMembership;
|
use FireflyIII\Models\GroupMembership;
|
||||||
use FireflyIII\Models\UserGroup;
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
|
use Illuminate\Auth\AuthenticationException;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trait ValidatesUserGroupTrait
|
* Trait ValidatesUserGroupTrait
|
||||||
@ -35,37 +38,63 @@ use Illuminate\Http\Request;
|
|||||||
trait ValidatesUserGroupTrait
|
trait ValidatesUserGroupTrait
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* This check does not validate which rights the user has, that comes later.
|
* @throws AuthorizationException
|
||||||
*
|
* @throws AuthenticationException
|
||||||
* @throws FireflyException
|
|
||||||
*/
|
*/
|
||||||
protected function validateUserGroup(Request $request): ?UserGroup
|
protected function validateUserGroup(Request $request): UserGroup
|
||||||
{
|
{
|
||||||
|
app('log')->debug(sprintf('validateUserGroup: %s', get_class($this)));
|
||||||
if (!auth()->check()) {
|
if (!auth()->check()) {
|
||||||
app('log')->debug('validateUserGroup: user is not logged in, return NULL.');
|
app('log')->debug('validateUserGroup: user is not logged in, return NULL.');
|
||||||
|
|
||||||
return null;
|
throw new AuthenticationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
$groupId = 0;
|
||||||
if (!$request->has('user_group_id')) {
|
if (!$request->has('user_group_id')) {
|
||||||
$group = $user->userGroup;
|
$groupId = $user->user_group_id;
|
||||||
app('log')->debug(sprintf('validateUserGroup: no user group submitted, return default group #%d.', $group?->id));
|
app('log')->debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId));
|
||||||
|
|
||||||
return $group;
|
|
||||||
}
|
}
|
||||||
$groupId = (int)$request->get('user_group_id');
|
if ($request->has('user_group_id')) {
|
||||||
|
$groupId = (int)$request->get('user_group_id');
|
||||||
/** @var null|GroupMembership $membership */
|
app('log')->debug(sprintf('validateUserGroup: user group submitted, search for memberships in group #%d.', $groupId));
|
||||||
|
}
|
||||||
|
/** @var GroupMembership|null $membership */
|
||||||
$membership = $user->groupMemberships()->where('user_group_id', $groupId)->first();
|
$membership = $user->groupMemberships()->where('user_group_id', $groupId)->first();
|
||||||
|
|
||||||
if (null === $membership) {
|
if (null === $membership) {
|
||||||
app('log')->debug('validateUserGroup: user has no access to this group.');
|
app('log')->debug(sprintf('validateUserGroup: user has no access to group #%d.', $groupId));
|
||||||
|
throw new AuthorizationException((string)trans('validation.no_access_group'));
|
||||||
throw new FireflyException((string)trans('validation.belongs_user_or_user_group'));
|
|
||||||
}
|
}
|
||||||
app('log')->debug(sprintf('validateUserGroup: user has role "%s" in group #%d.', $membership->userRole->title, $membership->userGroup->id));
|
|
||||||
|
|
||||||
return $membership->userGroup;
|
// need to get the group from the membership:
|
||||||
|
/** @var UserGroup|null $group */
|
||||||
|
$group = $membership->userGroup;
|
||||||
|
if (null === $group) {
|
||||||
|
app('log')->debug(sprintf('validateUserGroup: group #%d does not exist.', $groupId));
|
||||||
|
throw new AuthorizationException((string)trans('validation.belongs_user_or_user_group'));
|
||||||
|
}
|
||||||
|
app('log')->debug(sprintf('validateUserGroup: validate access of user to group #%d ("%s").', $groupId, $group->title));
|
||||||
|
$roles = property_exists($this, 'acceptedRoles') ? $this->acceptedRoles : [];
|
||||||
|
if(0 === count($roles)) {
|
||||||
|
app('log')->debug('validateUserGroup: no roles defined, so no access.');
|
||||||
|
|
||||||
|
throw new AuthorizationException((string)trans('validation.no_accepted_roles_defined'));
|
||||||
|
}
|
||||||
|
app('log')->debug(sprintf('validateUserGroup: have %d roles to check.', count($roles)), $roles);
|
||||||
|
/** @var UserRoleEnum $role */
|
||||||
|
foreach($roles as $role) {
|
||||||
|
if($user->hasRoleInGroupOrOwner($group, $role)) {
|
||||||
|
app('log')->debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId));
|
||||||
|
return $group;
|
||||||
|
}
|
||||||
|
app('log')->debug(sprintf('validateUserGroup: User does NOT have role "%s" in group #%d, continue searching.', $role->value, $groupId));
|
||||||
|
}
|
||||||
|
|
||||||
|
app('log')->debug('validateUserGroup: User does NOT have enough rights to access endpoint.');
|
||||||
|
|
||||||
|
throw new AuthorizationException((string)trans('validation.belongs_user_or_user_group'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ return [
|
|||||||
| the usual Laravel view path has already been registered for you.
|
| the usual Laravel view path has already been registered for you.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
'layout' => env('FIREFLY_III_LAYOUT', 'v1'),
|
||||||
'paths' => $paths,
|
'paths' => $paths,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -25,156 +25,158 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'bad_type_source' => 'Firefly III can\'t determine the transaction type based on this source account.',
|
'bad_type_source' => 'Firefly III can\'t determine the transaction type based on this source account.',
|
||||||
'bad_type_destination' => 'Firefly III can\'t determine the transaction type based on this destination account.',
|
'bad_type_destination' => 'Firefly III can\'t determine the transaction type based on this destination account.',
|
||||||
'missing_where' => 'Array is missing "where"-clause',
|
'missing_where' => 'Array is missing "where"-clause',
|
||||||
'missing_update' => 'Array is missing "update"-clause',
|
'missing_update' => 'Array is missing "update"-clause',
|
||||||
'invalid_where_key' => 'JSON contains an invalid key for the "where"-clause',
|
'invalid_where_key' => 'JSON contains an invalid key for the "where"-clause',
|
||||||
'invalid_update_key' => 'JSON contains an invalid key for the "update"-clause',
|
'invalid_update_key' => 'JSON contains an invalid key for the "update"-clause',
|
||||||
'invalid_query_data' => 'There is invalid data in the %s:%s field of your query.',
|
'invalid_query_data' => 'There is invalid data in the %s:%s field of your query.',
|
||||||
'invalid_query_account_type' => 'Your query contains accounts of different types, which is not allowed.',
|
'invalid_query_account_type' => 'Your query contains accounts of different types, which is not allowed.',
|
||||||
'invalid_query_currency' => 'Your query contains accounts that have different currency settings, which is not allowed.',
|
'invalid_query_currency' => 'Your query contains accounts that have different currency settings, which is not allowed.',
|
||||||
'iban' => 'This is not a valid IBAN.',
|
'iban' => 'This is not a valid IBAN.',
|
||||||
'zero_or_more' => 'The value cannot be negative.',
|
'zero_or_more' => 'The value cannot be negative.',
|
||||||
'more_than_zero' => 'The value must be more than zero.',
|
'more_than_zero' => 'The value must be more than zero.',
|
||||||
'more_than_zero_correct' => 'The value must be zero or more.',
|
'more_than_zero_correct' => 'The value must be zero or more.',
|
||||||
'no_asset_account' => 'This is not an asset account.',
|
'no_asset_account' => 'This is not an asset account.',
|
||||||
'date_or_time' => 'The value must be a valid date or time value (ISO 8601).',
|
'date_or_time' => 'The value must be a valid date or time value (ISO 8601).',
|
||||||
'source_equals_destination' => 'The source account equals the destination account.',
|
'source_equals_destination' => 'The source account equals the destination account.',
|
||||||
'unique_account_number_for_user' => 'It looks like this account number is already in use.',
|
'unique_account_number_for_user' => 'It looks like this account number is already in use.',
|
||||||
'unique_iban_for_user' => 'It looks like this IBAN is already in use.',
|
'unique_iban_for_user' => 'It looks like this IBAN is already in use.',
|
||||||
'reconciled_forbidden_field' => 'This transaction is already reconciled, you cannot change the ":field"',
|
'reconciled_forbidden_field' => 'This transaction is already reconciled, you cannot change the ":field"',
|
||||||
'deleted_user' => 'Due to security constraints, you cannot register using this email address.',
|
'deleted_user' => 'Due to security constraints, you cannot register using this email address.',
|
||||||
'rule_trigger_value' => 'This value is invalid for the selected trigger.',
|
'rule_trigger_value' => 'This value is invalid for the selected trigger.',
|
||||||
'rule_action_expression' => 'Invalid expression. :error',
|
'rule_action_expression' => 'Invalid expression. :error',
|
||||||
'rule_action_value' => 'This value is invalid for the selected action.',
|
'rule_action_value' => 'This value is invalid for the selected action.',
|
||||||
'file_already_attached' => 'Uploaded file ":name" is already attached to this object.',
|
'file_already_attached' => 'Uploaded file ":name" is already attached to this object.',
|
||||||
'file_attached' => 'Successfully uploaded file ":name".',
|
'file_attached' => 'Successfully uploaded file ":name".',
|
||||||
'file_zero' => 'The file is zero bytes in size.',
|
'file_zero' => 'The file is zero bytes in size.',
|
||||||
'must_exist' => 'The ID in field :attribute does not exist in the database.',
|
'must_exist' => 'The ID in field :attribute does not exist in the database.',
|
||||||
'all_accounts_equal' => 'All accounts in this field must be equal.',
|
'all_accounts_equal' => 'All accounts in this field must be equal.',
|
||||||
'group_title_mandatory' => 'A group title is mandatory when there is more than one transaction.',
|
'group_title_mandatory' => 'A group title is mandatory when there is more than one transaction.',
|
||||||
'transaction_types_equal' => 'All splits must be of the same type.',
|
'transaction_types_equal' => 'All splits must be of the same type.',
|
||||||
'invalid_transaction_type' => 'Invalid transaction type.',
|
'invalid_transaction_type' => 'Invalid transaction type.',
|
||||||
'invalid_selection' => 'Your selection is invalid.',
|
'invalid_selection' => 'Your selection is invalid.',
|
||||||
'belongs_user' => 'This value is linked to an object that does not seem to exist.',
|
'belongs_user' => 'This value is linked to an object that does not seem to exist.',
|
||||||
'belongs_user_or_user_group' => 'This value is linked to an object that does not seem to exist in your current financial administration.',
|
'belongs_user_or_user_group' => 'This value is linked to an object that does not seem to exist in your current financial administration.',
|
||||||
'at_least_one_transaction' => 'Need at least one transaction.',
|
'no_access_group' => 'The user has no access to this user group.',
|
||||||
'recurring_transaction_id' => 'Need at least one transaction.',
|
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.',
|
||||||
'need_id_to_match' => 'You need to submit this entry with an ID for the API to be able to match it.',
|
'at_least_one_transaction' => 'Need at least one transaction.',
|
||||||
'too_many_unmatched' => 'Too many submitted transactions cannot be matched to their respective database entries. Make sure existing entries have a valid ID.',
|
'recurring_transaction_id' => 'Need at least one transaction.',
|
||||||
'id_does_not_match' => 'Submitted ID #:id does not match expected ID. Make sure it matches or omit the field.',
|
'need_id_to_match' => 'You need to submit this entry with an ID for the API to be able to match it.',
|
||||||
'at_least_one_repetition' => 'Need at least one repetition.',
|
'too_many_unmatched' => 'Too many submitted transactions cannot be matched to their respective database entries. Make sure existing entries have a valid ID.',
|
||||||
'require_repeat_until' => 'Require either a number of repetitions, or an end date (repeat_until). Not both.',
|
'id_does_not_match' => 'Submitted ID #:id does not match expected ID. Make sure it matches or omit the field.',
|
||||||
'require_currency_info' => 'The content of this field is invalid without currency information.',
|
'at_least_one_repetition' => 'Need at least one repetition.',
|
||||||
'not_transfer_account' => 'This account is not an account that can be used for transfers.',
|
'require_repeat_until' => 'Require either a number of repetitions, or an end date (repeat_until). Not both.',
|
||||||
'require_currency_amount' => 'The content of this field is invalid without foreign amount information.',
|
'require_currency_info' => 'The content of this field is invalid without currency information.',
|
||||||
'require_foreign_currency' => 'This field requires a number',
|
'not_transfer_account' => 'This account is not an account that can be used for transfers.',
|
||||||
'require_foreign_dest' => 'This field value must match the currency of the destination account.',
|
'require_currency_amount' => 'The content of this field is invalid without foreign amount information.',
|
||||||
'require_foreign_src' => 'This field value must match the currency of the source account.',
|
'require_foreign_currency' => 'This field requires a number',
|
||||||
'equal_description' => 'Transaction description should not equal global description.',
|
'require_foreign_dest' => 'This field value must match the currency of the destination account.',
|
||||||
'file_invalid_mime' => 'File ":name" is of type ":mime" which is not accepted as a new upload.',
|
'require_foreign_src' => 'This field value must match the currency of the source account.',
|
||||||
'file_too_large' => 'File ":name" is too large.',
|
'equal_description' => 'Transaction description should not equal global description.',
|
||||||
'belongs_to_user' => 'The value of :attribute is unknown.',
|
'file_invalid_mime' => 'File ":name" is of type ":mime" which is not accepted as a new upload.',
|
||||||
'accepted' => 'The :attribute must be accepted.',
|
'file_too_large' => 'File ":name" is too large.',
|
||||||
'bic' => 'This is not a valid BIC.',
|
'belongs_to_user' => 'The value of :attribute is unknown.',
|
||||||
'at_least_one_trigger' => 'Rule must have at least one trigger.',
|
'accepted' => 'The :attribute must be accepted.',
|
||||||
'at_least_one_active_trigger' => 'Rule must have at least one active trigger.',
|
'bic' => 'This is not a valid BIC.',
|
||||||
'at_least_one_action' => 'Rule must have at least one action.',
|
'at_least_one_trigger' => 'Rule must have at least one trigger.',
|
||||||
'at_least_one_active_action' => 'Rule must have at least one active action.',
|
'at_least_one_active_trigger' => 'Rule must have at least one active trigger.',
|
||||||
'base64' => 'This is not valid base64 encoded data.',
|
'at_least_one_action' => 'Rule must have at least one action.',
|
||||||
'model_id_invalid' => 'The given ID seems invalid for this model.',
|
'at_least_one_active_action' => 'Rule must have at least one active action.',
|
||||||
'less' => ':attribute must be less than 10,000,000',
|
'base64' => 'This is not valid base64 encoded data.',
|
||||||
'active_url' => 'The :attribute is not a valid URL.',
|
'model_id_invalid' => 'The given ID seems invalid for this model.',
|
||||||
'after' => 'The :attribute must be a date after :date.',
|
'less' => ':attribute must be less than 10,000,000',
|
||||||
'date_after' => 'The start date must be before the end date.',
|
'active_url' => 'The :attribute is not a valid URL.',
|
||||||
'alpha' => 'The :attribute may only contain letters.',
|
'after' => 'The :attribute must be a date after :date.',
|
||||||
'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
|
'date_after' => 'The start date must be before the end date.',
|
||||||
'alpha_num' => 'The :attribute may only contain letters and numbers.',
|
'alpha' => 'The :attribute may only contain letters.',
|
||||||
'array' => 'The :attribute must be an array.',
|
'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
|
||||||
'unique_for_user' => 'There already is an entry with this :attribute.',
|
'alpha_num' => 'The :attribute may only contain letters and numbers.',
|
||||||
'before' => 'The :attribute must be a date before :date.',
|
'array' => 'The :attribute must be an array.',
|
||||||
'unique_object_for_user' => 'This name is already in use.',
|
'unique_for_user' => 'There already is an entry with this :attribute.',
|
||||||
'unique_account_for_user' => 'This account name is already in use.',
|
'before' => 'The :attribute must be a date before :date.',
|
||||||
|
'unique_object_for_user' => 'This name is already in use.',
|
||||||
|
'unique_account_for_user' => 'This account name is already in use.',
|
||||||
|
|
||||||
// Ignore this comment
|
// Ignore this comment
|
||||||
|
|
||||||
'between.numeric' => 'The :attribute must be between :min and :max.',
|
'between.numeric' => 'The :attribute must be between :min and :max.',
|
||||||
'between.file' => 'The :attribute must be between :min and :max kilobytes.',
|
'between.file' => 'The :attribute must be between :min and :max kilobytes.',
|
||||||
'between.string' => 'The :attribute must be between :min and :max characters.',
|
'between.string' => 'The :attribute must be between :min and :max characters.',
|
||||||
'between.array' => 'The :attribute must have between :min and :max items.',
|
'between.array' => 'The :attribute must have between :min and :max items.',
|
||||||
'boolean' => 'The :attribute field must be true or false.',
|
'boolean' => 'The :attribute field must be true or false.',
|
||||||
'confirmed' => 'The :attribute confirmation does not match.',
|
'confirmed' => 'The :attribute confirmation does not match.',
|
||||||
'date' => 'The :attribute is not a valid date.',
|
'date' => 'The :attribute is not a valid date.',
|
||||||
'date_format' => 'The :attribute does not match the format :format.',
|
'date_format' => 'The :attribute does not match the format :format.',
|
||||||
'different' => 'The :attribute and :other must be different.',
|
'different' => 'The :attribute and :other must be different.',
|
||||||
'digits' => 'The :attribute must be :digits digits.',
|
'digits' => 'The :attribute must be :digits digits.',
|
||||||
'digits_between' => 'The :attribute must be between :min and :max digits.',
|
'digits_between' => 'The :attribute must be between :min and :max digits.',
|
||||||
'email' => 'The :attribute must be a valid email address.',
|
'email' => 'The :attribute must be a valid email address.',
|
||||||
'filled' => 'The :attribute field is required.',
|
'filled' => 'The :attribute field is required.',
|
||||||
'exists' => 'The selected :attribute is invalid.',
|
'exists' => 'The selected :attribute is invalid.',
|
||||||
'image' => 'The :attribute must be an image.',
|
'image' => 'The :attribute must be an image.',
|
||||||
'in' => 'The selected :attribute is invalid.',
|
'in' => 'The selected :attribute is invalid.',
|
||||||
'integer' => 'The :attribute must be an integer.',
|
'integer' => 'The :attribute must be an integer.',
|
||||||
'ip' => 'The :attribute must be a valid IP address.',
|
'ip' => 'The :attribute must be a valid IP address.',
|
||||||
'json' => 'The :attribute must be a valid JSON string.',
|
'json' => 'The :attribute must be a valid JSON string.',
|
||||||
'max.numeric' => 'The :attribute may not be greater than :max.',
|
'max.numeric' => 'The :attribute may not be greater than :max.',
|
||||||
'max.file' => 'The :attribute may not be greater than :max kilobytes.',
|
'max.file' => 'The :attribute may not be greater than :max kilobytes.',
|
||||||
'max.string' => 'The :attribute may not be greater than :max characters.',
|
'max.string' => 'The :attribute may not be greater than :max characters.',
|
||||||
'max.array' => 'The :attribute may not have more than :max items.',
|
'max.array' => 'The :attribute may not have more than :max items.',
|
||||||
'mimes' => 'The :attribute must be a file of type: :values.',
|
'mimes' => 'The :attribute must be a file of type: :values.',
|
||||||
'min.numeric' => 'The :attribute must be at least :min.',
|
'min.numeric' => 'The :attribute must be at least :min.',
|
||||||
'lte.numeric' => 'The :attribute must be less than or equal :value.',
|
'lte.numeric' => 'The :attribute must be less than or equal :value.',
|
||||||
'min.file' => 'The :attribute must be at least :min kilobytes.',
|
'min.file' => 'The :attribute must be at least :min kilobytes.',
|
||||||
'min.string' => 'The :attribute must be at least :min characters.',
|
'min.string' => 'The :attribute must be at least :min characters.',
|
||||||
'min.array' => 'The :attribute must have at least :min items.',
|
'min.array' => 'The :attribute must have at least :min items.',
|
||||||
'not_in' => 'The selected :attribute is invalid.',
|
'not_in' => 'The selected :attribute is invalid.',
|
||||||
'numeric' => 'The :attribute must be a number.',
|
'numeric' => 'The :attribute must be a number.',
|
||||||
'scientific_notation' => 'The :attribute cannot use the scientific notation.',
|
'scientific_notation' => 'The :attribute cannot use the scientific notation.',
|
||||||
'numeric_native' => 'The native amount must be a number.',
|
'numeric_native' => 'The native amount must be a number.',
|
||||||
'numeric_destination' => 'The destination amount must be a number.',
|
'numeric_destination' => 'The destination amount must be a number.',
|
||||||
'numeric_source' => 'The source amount must be a number.',
|
'numeric_source' => 'The source amount must be a number.',
|
||||||
'regex' => 'The :attribute format is invalid.',
|
'regex' => 'The :attribute format is invalid.',
|
||||||
'required' => 'The :attribute field is required.',
|
'required' => 'The :attribute field is required.',
|
||||||
'required_if' => 'The :attribute field is required when :other is :value.',
|
'required_if' => 'The :attribute field is required when :other is :value.',
|
||||||
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
||||||
'required_with' => 'The :attribute field is required when :values is present.',
|
'required_with' => 'The :attribute field is required when :values is present.',
|
||||||
'required_with_all' => 'The :attribute field is required when :values is present.',
|
'required_with_all' => 'The :attribute field is required when :values is present.',
|
||||||
'required_without' => 'The :attribute field is required when :values is not present.',
|
'required_without' => 'The :attribute field is required when :values is not present.',
|
||||||
'required_without_all' => 'The :attribute field is required when none of :values are present.',
|
'required_without_all' => 'The :attribute field is required when none of :values are present.',
|
||||||
'same' => 'The :attribute and :other must match.',
|
'same' => 'The :attribute and :other must match.',
|
||||||
'size.numeric' => 'The :attribute must be :size.',
|
'size.numeric' => 'The :attribute must be :size.',
|
||||||
'amount_min_over_max' => 'The minimum amount cannot be larger than the maximum amount.',
|
'amount_min_over_max' => 'The minimum amount cannot be larger than the maximum amount.',
|
||||||
'size.file' => 'The :attribute must be :size kilobytes.',
|
'size.file' => 'The :attribute must be :size kilobytes.',
|
||||||
'size.string' => 'The :attribute must be :size characters.',
|
'size.string' => 'The :attribute must be :size characters.',
|
||||||
'size.array' => 'The :attribute must contain :size items.',
|
'size.array' => 'The :attribute must contain :size items.',
|
||||||
'unique' => 'The :attribute has already been taken.',
|
'unique' => 'The :attribute has already been taken.',
|
||||||
'string' => 'The :attribute must be a string.',
|
'string' => 'The :attribute must be a string.',
|
||||||
'url' => 'The :attribute format is invalid.',
|
'url' => 'The :attribute format is invalid.',
|
||||||
'timezone' => 'The :attribute must be a valid zone.',
|
'timezone' => 'The :attribute must be a valid zone.',
|
||||||
'2fa_code' => 'The :attribute field is invalid.',
|
'2fa_code' => 'The :attribute field is invalid.',
|
||||||
'dimensions' => 'The :attribute has invalid image dimensions.',
|
'dimensions' => 'The :attribute has invalid image dimensions.',
|
||||||
'distinct' => 'The :attribute field has a duplicate value.',
|
'distinct' => 'The :attribute field has a duplicate value.',
|
||||||
'file' => 'The :attribute must be a file.',
|
'file' => 'The :attribute must be a file.',
|
||||||
'in_array' => 'The :attribute field does not exist in :other.',
|
'in_array' => 'The :attribute field does not exist in :other.',
|
||||||
'present' => 'The :attribute field must be present.',
|
'present' => 'The :attribute field must be present.',
|
||||||
'amount_zero' => 'The total amount cannot be zero.',
|
'amount_zero' => 'The total amount cannot be zero.',
|
||||||
'current_target_amount' => 'The current amount must be less than the target amount.',
|
'current_target_amount' => 'The current amount must be less than the target amount.',
|
||||||
'unique_piggy_bank_for_user' => 'The name of the piggy bank must be unique.',
|
'unique_piggy_bank_for_user' => 'The name of the piggy bank must be unique.',
|
||||||
'unique_object_group' => 'The group name must be unique',
|
'unique_object_group' => 'The group name must be unique',
|
||||||
'starts_with' => 'The value must start with :values.',
|
'starts_with' => 'The value must start with :values.',
|
||||||
'unique_webhook' => 'You already have a webhook with this combination of URL, trigger, response and delivery.',
|
'unique_webhook' => 'You already have a webhook with this combination of URL, trigger, response and delivery.',
|
||||||
'unique_existing_webhook' => 'You already have another webhook with this combination of URL, trigger, response and delivery.',
|
'unique_existing_webhook' => 'You already have another webhook with this combination of URL, trigger, response and delivery.',
|
||||||
'same_account_type' => 'Both accounts must be of the same account type',
|
'same_account_type' => 'Both accounts must be of the same account type',
|
||||||
'same_account_currency' => 'Both accounts must have the same currency setting',
|
'same_account_currency' => 'Both accounts must have the same currency setting',
|
||||||
|
|
||||||
// Ignore this comment
|
// Ignore this comment
|
||||||
|
|
||||||
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password',
|
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password',
|
||||||
'valid_recurrence_rep_type' => 'Invalid repetition type for recurring transactions.',
|
'valid_recurrence_rep_type' => 'Invalid repetition type for recurring transactions.',
|
||||||
'valid_recurrence_rep_moment' => 'Invalid repetition moment for this type of repetition.',
|
'valid_recurrence_rep_moment' => 'Invalid repetition moment for this type of repetition.',
|
||||||
'invalid_account_info' => 'Invalid account information.',
|
'invalid_account_info' => 'Invalid account information.',
|
||||||
'attributes' => [
|
'attributes' => [
|
||||||
'email' => 'email address',
|
'email' => 'email address',
|
||||||
'description' => 'description',
|
'description' => 'description',
|
||||||
'amount' => 'amount',
|
'amount' => 'amount',
|
||||||
@ -213,58 +215,58 @@ return [
|
|||||||
],
|
],
|
||||||
|
|
||||||
// validation of accounts:
|
// validation of accounts:
|
||||||
'withdrawal_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
|
'withdrawal_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
|
||||||
'withdrawal_source_bad_data' => '[a] Could not find a valid source account when searching for ID ":id" or name ":name".',
|
'withdrawal_source_bad_data' => '[a] Could not find a valid source account when searching for ID ":id" or name ":name".',
|
||||||
'withdrawal_dest_need_data' => '[a] Need to get a valid destination account ID and/or valid destination account name to continue.',
|
'withdrawal_dest_need_data' => '[a] Need to get a valid destination account ID and/or valid destination account name to continue.',
|
||||||
'withdrawal_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
|
'withdrawal_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
|
||||||
|
|
||||||
'withdrawal_dest_iban_exists' => 'This destination account IBAN is already in use by an asset account or a liability and cannot be used as a withdrawal destination.',
|
'withdrawal_dest_iban_exists' => 'This destination account IBAN is already in use by an asset account or a liability and cannot be used as a withdrawal destination.',
|
||||||
'deposit_src_iban_exists' => 'This source account IBAN is already in use by an asset account or a liability and cannot be used as a deposit source.',
|
'deposit_src_iban_exists' => 'This source account IBAN is already in use by an asset account or a liability and cannot be used as a deposit source.',
|
||||||
|
|
||||||
'reconciliation_source_bad_data' => 'Could not find a valid reconciliation account when searching for ID ":id" or name ":name".',
|
'reconciliation_source_bad_data' => 'Could not find a valid reconciliation account when searching for ID ":id" or name ":name".',
|
||||||
|
|
||||||
'generic_source_bad_data' => '[e] Could not find a valid source account when searching for ID ":id" or name ":name".',
|
'generic_source_bad_data' => '[e] Could not find a valid source account when searching for ID ":id" or name ":name".',
|
||||||
|
|
||||||
'deposit_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
|
'deposit_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
|
||||||
'deposit_source_bad_data' => '[b] Could not find a valid source account when searching for ID ":id" or name ":name".',
|
'deposit_source_bad_data' => '[b] Could not find a valid source account when searching for ID ":id" or name ":name".',
|
||||||
'deposit_dest_need_data' => '[b] Need to get a valid destination account ID and/or valid destination account name to continue.',
|
'deposit_dest_need_data' => '[b] Need to get a valid destination account ID and/or valid destination account name to continue.',
|
||||||
'deposit_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
|
'deposit_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
|
||||||
'deposit_dest_wrong_type' => 'The submitted destination account is not of the right type.',
|
'deposit_dest_wrong_type' => 'The submitted destination account is not of the right type.',
|
||||||
|
|
||||||
// Ignore this comment
|
// Ignore this comment
|
||||||
|
|
||||||
'transfer_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
|
'transfer_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
|
||||||
'transfer_source_bad_data' => '[c] Could not find a valid source account when searching for ID ":id" or name ":name".',
|
'transfer_source_bad_data' => '[c] Could not find a valid source account when searching for ID ":id" or name ":name".',
|
||||||
'transfer_dest_need_data' => '[c] Need to get a valid destination account ID and/or valid destination account name to continue.',
|
'transfer_dest_need_data' => '[c] Need to get a valid destination account ID and/or valid destination account name to continue.',
|
||||||
'transfer_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
|
'transfer_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
|
||||||
'need_id_in_edit' => 'Each split must have transaction_journal_id (either valid ID or 0).',
|
'need_id_in_edit' => 'Each split must have transaction_journal_id (either valid ID or 0).',
|
||||||
|
|
||||||
'ob_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
|
'ob_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
|
||||||
'lc_source_need_data' => 'Need to get a valid source account ID to continue.',
|
'lc_source_need_data' => 'Need to get a valid source account ID to continue.',
|
||||||
'ob_dest_need_data' => '[d] Need to get a valid destination account ID and/or valid destination account name to continue.',
|
'ob_dest_need_data' => '[d] Need to get a valid destination account ID and/or valid destination account name to continue.',
|
||||||
'ob_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
|
'ob_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
|
||||||
'reconciliation_either_account' => 'To submit a reconciliation, you must submit either a source or a destination account. Not both, not neither.',
|
'reconciliation_either_account' => 'To submit a reconciliation, you must submit either a source or a destination account. Not both, not neither.',
|
||||||
|
|
||||||
'generic_invalid_source' => 'You can\'t use this account as the source account.',
|
'generic_invalid_source' => 'You can\'t use this account as the source account.',
|
||||||
'generic_invalid_destination' => 'You can\'t use this account as the destination account.',
|
'generic_invalid_destination' => 'You can\'t use this account as the destination account.',
|
||||||
|
|
||||||
'generic_no_source' => 'You must submit source account information or submit a transaction journal ID.',
|
'generic_no_source' => 'You must submit source account information or submit a transaction journal ID.',
|
||||||
'generic_no_destination' => 'You must submit destination account information or submit a transaction journal ID.',
|
'generic_no_destination' => 'You must submit destination account information or submit a transaction journal ID.',
|
||||||
|
|
||||||
'gte.numeric' => 'The :attribute must be greater than or equal to :value.',
|
'gte.numeric' => 'The :attribute must be greater than or equal to :value.',
|
||||||
'gt.numeric' => 'The :attribute must be greater than :value.',
|
'gt.numeric' => 'The :attribute must be greater than :value.',
|
||||||
'gte.file' => 'The :attribute must be greater than or equal to :value kilobytes.',
|
'gte.file' => 'The :attribute must be greater than or equal to :value kilobytes.',
|
||||||
'gte.string' => 'The :attribute must be greater than or equal to :value characters.',
|
'gte.string' => 'The :attribute must be greater than or equal to :value characters.',
|
||||||
'gte.array' => 'The :attribute must have :value items or more.',
|
'gte.array' => 'The :attribute must have :value items or more.',
|
||||||
|
|
||||||
'amount_required_for_auto_budget' => 'The amount is required.',
|
'amount_required_for_auto_budget' => 'The amount is required.',
|
||||||
'auto_budget_amount_positive' => 'The amount must be more than zero.',
|
'auto_budget_amount_positive' => 'The amount must be more than zero.',
|
||||||
|
|
||||||
'auto_budget_period_mandatory' => 'The auto budget period is a mandatory field.',
|
'auto_budget_period_mandatory' => 'The auto budget period is a mandatory field.',
|
||||||
|
|
||||||
// no access to administration:
|
// no access to administration:
|
||||||
'no_access_user_group' => 'You do not have the correct access rights for this administration.',
|
'no_access_user_group' => 'You do not have the correct access rights for this administration.',
|
||||||
'administration_owner_rename' => 'You can\'t rename your standard administration.',
|
'administration_owner_rename' => 'You can\'t rename your standard administration.',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Ignore this comment
|
// Ignore this comment
|
||||||
|
1
resources/views/administrations/index.twig
Normal file
1
resources/views/administrations/index.twig
Normal file
@ -0,0 +1 @@
|
|||||||
|
This feature is only available in the v2 layout.
|
Loading…
Reference in New Issue
Block a user