mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Make sure the convert controller works again.
This commit is contained in:
parent
3c5c14ff5a
commit
7fd3f77c3e
@ -111,7 +111,7 @@ class NetWorth implements NetWorthInterface
|
||||
|
||||
// if the account is a credit card, subtract the virtual balance from the balance,
|
||||
// to better reflect that this is not money that is actually "yours".
|
||||
$role = (string)$this->accountRepository->getMetaValue($account, 'accountRole');
|
||||
$role = (string)$this->accountRepository->getMetaValue($account, 'account_role');
|
||||
$virtualBalance = (string)$account->virtual_balance;
|
||||
if ('ccAsset' === $role && '' !== $virtualBalance && (float)$virtualBalance > 0) {
|
||||
$balance = bcsub($balance, $virtualBalance);
|
||||
|
@ -93,6 +93,37 @@ class AutoCompleteController extends Controller
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* An auto-complete specifically for revenue accounts, used when converting transactions mostly.
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function revenueAccounts(Request $request): JsonResponse
|
||||
{
|
||||
$search = $request->get('search');
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
// filter the account types:
|
||||
$allowedAccountTypes = [AccountType::REVENUE];
|
||||
Log::debug('Now in accounts(). Filtering results.', $allowedAccountTypes);
|
||||
|
||||
$return = [];
|
||||
$result = $repository->searchAccount((string)$search, $allowedAccountTypes);
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($result as $account) {
|
||||
$return[] = [
|
||||
'id' => $account->id,
|
||||
'name' => $account->name,
|
||||
'type' => $account->accountType->type,
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches in the titles of all transaction journals.
|
||||
* The result is limited to the top 15 unique results.
|
||||
|
@ -22,17 +22,26 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Transaction;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Update\JournalUpdateService;
|
||||
use FireflyIII\Support\Http\Controllers\ModelInformation;
|
||||
use FireflyIII\Transformers\TransactionGroupTransformer;
|
||||
use FireflyIII\Validation\AccountValidator;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
use View;
|
||||
|
||||
|
||||
/**
|
||||
* Class ConvertController.
|
||||
*/
|
||||
@ -45,6 +54,7 @@ class ConvertController extends Controller
|
||||
|
||||
/**
|
||||
* ConvertController constructor.
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@ -67,111 +77,272 @@ class ConvertController extends Controller
|
||||
/**
|
||||
* Show overview of a to be converted transaction.
|
||||
*
|
||||
* @param TransactionType $destinationType
|
||||
* @param TransactionJournal $journal
|
||||
* @param TransactionType $destinationType
|
||||
* @param TransactionGroup $group
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function index(TransactionType $destinationType, TransactionJournal $journal)
|
||||
public function index(TransactionType $destinationType, TransactionGroup $group)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->isOpeningBalance($journal)) {
|
||||
Log::debug('This is an opening balance.');
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
|
||||
return $this->redirectToAccount($journal);
|
||||
/** @var TransactionJournal $first */
|
||||
$first = $group->transactionJournals()->first();
|
||||
$sourceType = $first->transactionType;
|
||||
// return to account.
|
||||
if (!in_array($sourceType->type, [TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::DEPOSIT], true)) {
|
||||
return $this->redirectToAccount($first);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
$positiveAmount = $this->repository->getJournalTotal($journal);
|
||||
$sourceType = $journal->transactionType;
|
||||
$subTitle = (string)trans('firefly.convert_to_' . $destinationType->type, ['description' => $journal->description]);
|
||||
$subTitleIcon = 'fa-exchange';
|
||||
|
||||
$groupTitle = $group->title ?? $first->description;
|
||||
$groupArray = $transformer->transformObject($group);
|
||||
$subTitle = (string)trans('firefly.convert_to_' . $destinationType->type, ['description' => $groupTitle]);
|
||||
$subTitleIcon = 'fa-exchange';
|
||||
|
||||
// get a list of asset accounts and liabilities and stuff, in various combinations:
|
||||
$validDepositSources = $this->getValidDepositSources();
|
||||
$validWithdrawalDests = $this->getValidWithdrawalDests();
|
||||
$liabilities = $this->getLiabilities();
|
||||
$assets = $this->getAssetAccounts();
|
||||
|
||||
// old input variables:
|
||||
$preFilled = [
|
||||
'source_name' => old('source_name'),
|
||||
];
|
||||
|
||||
if ($sourceType->type === $destinationType->type) { // cannot convert to its own type.
|
||||
Log::debug('This is already a transaction of the expected type..');
|
||||
session()->flash('info', (string)trans('firefly.convert_is_already_type_' . $destinationType->type));
|
||||
|
||||
return redirect(route('transactions.show', [$journal->id]));
|
||||
return redirect(route('transactions.show', [$group->id]));
|
||||
}
|
||||
|
||||
if ($journal->transactions()->count() > 2) { // cannot convert split.
|
||||
Log::info('This journal has more than two transactions.');
|
||||
session()->flash('error', (string)trans('firefly.cannot_convert_split_journal'));
|
||||
|
||||
return redirect(route('transactions.show', [$journal->id]));
|
||||
}
|
||||
|
||||
// get source and destination account:
|
||||
$sourceAccount = $this->repository->getJournalSourceAccounts($journal)->first();
|
||||
$destinationAccount = $this->repository->getJournalDestinationAccounts($journal)->first();
|
||||
|
||||
return view(
|
||||
'transactions.convert', compact(
|
||||
'sourceType', 'destinationType', 'journal', 'positiveAmount', 'sourceAccount', 'destinationAccount', 'sourceType',
|
||||
'sourceType', 'destinationType',
|
||||
'group', 'groupTitle', 'groupArray', 'assets', 'validDepositSources', 'liabilities',
|
||||
'validWithdrawalDests', 'preFilled',
|
||||
'subTitle', 'subTitleIcon'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do the conversion.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param TransactionType $destinationType
|
||||
* @param TransactionJournal $journal
|
||||
* @param Request $request
|
||||
* @param TransactionType $destinationType
|
||||
* @param TransactionGroup $group
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*/
|
||||
public function postIndex(Request $request, TransactionType $destinationType, TransactionJournal $journal)
|
||||
public function postIndex(Request $request, TransactionType $destinationType, TransactionGroup $group)
|
||||
{
|
||||
throw new FireflyException('Needs refactor');
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->isOpeningBalance($journal)) {
|
||||
Log::debug('Journal is opening balance, return to account.');
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($group->transactionJournals as $journal) {
|
||||
// catch FF exception.
|
||||
try {
|
||||
$this->convertJournal($journal, $destinationType, $request->all());
|
||||
} catch (FireflyException $e) {
|
||||
session()->flash('error', $e->getMessage());
|
||||
|
||||
return $this->redirectToAccount($journal);
|
||||
return redirect()->route('transactions.convert.index', [strtolower($destinationType->type), $group->id])->withInput();
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$data = $request->all();
|
||||
|
||||
if ($journal->transactionType->type === $destinationType->type) {
|
||||
Log::info('Journal is already of the desired type.');
|
||||
session()->flash('error', (string)trans('firefly.convert_is_already_type_' . $destinationType->type));
|
||||
|
||||
return redirect(route('transactions.show', [$journal->id]));
|
||||
}
|
||||
|
||||
if ($journal->transactions()->count() > 2) {
|
||||
Log::info('Journal has more than two transactions.');
|
||||
session()->flash('error', (string)trans('firefly.cannot_convert_split_journal'));
|
||||
|
||||
return redirect(route('transactions.show', [$journal->id]));
|
||||
}
|
||||
|
||||
// get the new source and destination account:
|
||||
$source = $this->getSourceAccount($journal, $destinationType, $data);
|
||||
$destination = $this->getDestinationAccount($journal, $destinationType, $data);
|
||||
|
||||
// update the journal:
|
||||
$errors = $this->repository->convert($journal, $destinationType, $source, $destination);
|
||||
|
||||
if ($errors->count() > 0) {
|
||||
Log::error('Errors while converting: ', $errors->toArray());
|
||||
|
||||
return redirect(route('transactions.convert.index', [strtolower($destinationType->type), $journal->id]))->withErrors($errors)->withInput();
|
||||
}
|
||||
|
||||
// Success? Fire rules!
|
||||
session()->flash('success', (string)trans('firefly.converted_to_' . $destinationType->type));
|
||||
event(new UpdatedTransactionGroup($group));
|
||||
|
||||
return redirect(route('transactions.show', [$group->id]));
|
||||
}
|
||||
|
||||
session()->flash('success', (string)trans('firefly.converted_to_' . $destinationType->type));
|
||||
/**
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function getAssetAccounts(): array
|
||||
{
|
||||
// make repositories
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$accountList = $repository->getActiveAccountsByType([AccountType::ASSET]);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$grouped = [];
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($accountList as $account) {
|
||||
$balance = app('steam')->balance($account, new Carbon);
|
||||
$currency = $repository->getAccountCurrency($account) ?? $defaultCurrency;
|
||||
$role = (string)$repository->getMetaValue($account, 'account_role');
|
||||
if ('' === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return redirect(route('transactions.show', [$journal->id]));
|
||||
$key = (string)trans('firefly.opt_group_' . $role);
|
||||
$grouped[$key][$account->id] = $account->name . ' (' . app('amount')->formatAnything($currency, $balance, false) . ')';
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function getLiabilities(): array
|
||||
{
|
||||
// make repositories
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$accountList = $repository->getActiveAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$grouped = [];
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($accountList as $account) {
|
||||
$balance = app('steam')->balance($account, new Carbon);
|
||||
$currency = $repository->getAccountCurrency($account) ?? $defaultCurrency;
|
||||
$role = 'l_' . $account->accountType->type; // @codeCoverageIgnore
|
||||
$key = (string)trans('firefly.opt_group_' . $role);
|
||||
$grouped[$key][$account->id] = $account->name . ' (' . app('amount')->formatAnything($currency, $balance, false) . ')';
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getValidDepositSources(): array
|
||||
{
|
||||
// make repositories
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN];
|
||||
$accountList = $repository
|
||||
->getActiveAccountsByType([AccountType::REVENUE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
|
||||
$grouped = [];
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($accountList as $account) {
|
||||
$role = (string)$repository->getMetaValue($account, 'account_role');
|
||||
$name = $account->name;
|
||||
if ('' === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// maybe it's a liability thing:
|
||||
if (in_array($account->accountType->type, $liabilityTypes, true)) {
|
||||
$role = 'l_' . $account->accountType->type; // @codeCoverageIgnore
|
||||
}
|
||||
if (AccountType::CASH === $account->accountType->type) {
|
||||
$role = 'cash_account';
|
||||
$name = sprintf('(%s)', trans('firefly.cash'));
|
||||
}
|
||||
if (AccountType::REVENUE === $account->accountType->type) {
|
||||
$role = 'revenue_account';
|
||||
}
|
||||
|
||||
$key = (string)trans('firefly.opt_group_' . $role);
|
||||
$grouped[$key][$account->id] = $name;
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getValidWithdrawalDests(): array
|
||||
{
|
||||
// make repositories
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN];
|
||||
$accountList = $repository
|
||||
->getActiveAccountsByType([AccountType::EXPENSE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
|
||||
$grouped = [];
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($accountList as $account) {
|
||||
$role = (string)$repository->getMetaValue($account, 'account_role');
|
||||
$name = $account->name;
|
||||
if ('' === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// maybe it's a liability thing:
|
||||
if (in_array($account->accountType->type, $liabilityTypes, true)) {
|
||||
$role = 'l_' . $account->accountType->type; // @codeCoverageIgnore
|
||||
}
|
||||
if (AccountType::CASH === $account->accountType->type) {
|
||||
$role = 'cash_account';
|
||||
$name = sprintf('(%s)', trans('firefly.cash'));
|
||||
}
|
||||
if (AccountType::EXPENSE === $account->accountType->type) {
|
||||
$role = 'expense_account';
|
||||
}
|
||||
|
||||
$key = (string)trans('firefly.opt_group_' . $role);
|
||||
$grouped[$key][$account->id] = $name;
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param TransactionType $transactionType
|
||||
* @param array $data
|
||||
* @return TransactionJournal
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function convertJournal(TransactionJournal $journal, TransactionType $transactionType, array $data): TransactionJournal
|
||||
{
|
||||
$sourceType = $journal->transactionType->type;
|
||||
// make a switch based on original + dest type.
|
||||
/** @var AccountValidator $validator */
|
||||
$validator = app(AccountValidator::class);
|
||||
$validator->setUser(auth()->user());
|
||||
$validator->setTransactionType($transactionType->type);
|
||||
|
||||
$sourceId = $data['source_id'][$journal->id] ?? null;
|
||||
$sourceName = $data['source_name'][$journal->id] ?? null;
|
||||
$destinationId = $data['destination_id'][$journal->id] ?? null;
|
||||
$destinationName = $data['destination_name'][$journal->id] ?? null;
|
||||
|
||||
// double check its not an empty string.
|
||||
$sourceId = '' === $sourceId || null === $sourceId ? null : (int)$sourceId;
|
||||
$sourceName = '' === $sourceName ? null : $sourceName;
|
||||
$destinationId = '' === $destinationId || null === $destinationId ? null : (int)$destinationId;
|
||||
$destinationName = '' === $destinationName ? null : $destinationName;
|
||||
$validSource = $validator->validateSource($sourceId, $sourceName);
|
||||
$validDestination = $validator->validateDestination($destinationId, $destinationName);
|
||||
|
||||
if (false === $validSource) {
|
||||
throw new FireflyException(sprintf(trans('firefly.convert_invalid_source'), $journal->id));
|
||||
}
|
||||
if (false === $validDestination) {
|
||||
throw new FireflyException(sprintf(trans('firefly.convert_invalid_destination'), $journal->id));
|
||||
}
|
||||
|
||||
$update = [
|
||||
'source_id' => $sourceId,
|
||||
'source_name' => $sourceName,
|
||||
'destination_id' => $destinationId,
|
||||
'destination_name' => $destinationName,
|
||||
'type' => $transactionType->type,
|
||||
];
|
||||
/** @var JournalUpdateService $service */
|
||||
$service = app(JournalUpdateService::class);
|
||||
$service->setTransactionJournal($journal);
|
||||
$service->setData($update);
|
||||
$service->update();
|
||||
$journal->refresh();
|
||||
|
||||
return $journal;
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,6 @@ class IndexController extends Controller
|
||||
$types = config('firefly.transactionTypesByType.' . $objectType);
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$pageSize =3;
|
||||
if (null === $start) {
|
||||
$start = session('start');
|
||||
$end = session('end');
|
||||
|
@ -103,7 +103,7 @@ class AccountFormRequest extends Request
|
||||
'account_number' => 'between:1,255|uniqueAccountNumberForUser|nullable',
|
||||
'account_role' => 'in:' . $accountRoles,
|
||||
'active' => 'boolean',
|
||||
'ccType' => 'in:' . $ccPaymentTypes,
|
||||
'cc_type' => 'in:' . $ccPaymentTypes,
|
||||
'cc_monthly_payment_date' => 'date',
|
||||
'amount_currency_id_opening_balance' => 'exists:transaction_currencies,id',
|
||||
'amount_currency_id_virtual_balance' => 'exists:transaction_currencies,id',
|
||||
|
@ -268,7 +268,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
/** @var Collection $result */
|
||||
$query = $this->user->accounts()->with(
|
||||
['accountmeta' => function (HasMany $query) {
|
||||
$query->where('name', 'accountRole');
|
||||
$query->where('name', 'account_role');
|
||||
}]
|
||||
);
|
||||
if (count($types) > 0) {
|
||||
|
@ -75,7 +75,7 @@ class ExpandedForm
|
||||
$balance = app('steam')->balance($account, new Carbon);
|
||||
$currencyId = (int)$repository->getMetaValue($account, 'currency_id');
|
||||
$currency = $currencyRepos->findNull($currencyId);
|
||||
$role = $repository->getMetaValue($account, 'accountRole');
|
||||
$role = $repository->getMetaValue($account, 'account_role');
|
||||
if ('' === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
}
|
||||
@ -321,7 +321,7 @@ class ExpandedForm
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($assetAccounts as $account) {
|
||||
$role = $repository->getMetaValue($account, 'accountRole');
|
||||
$role = $repository->getMetaValue($account, 'account_role');
|
||||
if (null === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
}
|
||||
@ -364,7 +364,7 @@ class ExpandedForm
|
||||
$balance = app('steam')->balance($account, new Carbon);
|
||||
$currencyId = (int)$repository->getMetaValue($account, 'currency_id');
|
||||
$currency = $currencyRepos->findNull($currencyId);
|
||||
$role = (string)$repository->getMetaValue($account, 'accountRole');
|
||||
$role = (string)$repository->getMetaValue($account, 'account_role');
|
||||
if ('' === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
}
|
||||
@ -618,7 +618,7 @@ class ExpandedForm
|
||||
$balance = app('steam')->balance($account, new Carbon);
|
||||
$currencyId = (int)$repository->getMetaValue($account, 'currency_id');
|
||||
$currency = $currencyRepos->findNull($currencyId);
|
||||
$role = (string)$repository->getMetaValue($account, 'accountRole');
|
||||
$role = (string)$repository->getMetaValue($account, 'account_role'); // TODO bad form for currency
|
||||
if ('' === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ class AccountTransformer extends AbstractTransformer
|
||||
*/
|
||||
private function getAccountRole(Account $account, string $accountType): ?string
|
||||
{
|
||||
$accountRole = $this->repository->getMetaValue($account, 'accountRole');
|
||||
$accountRole = $this->repository->getMetaValue($account, 'account_role');
|
||||
if ('asset' !== $accountType || '' === (string)$accountRole) {
|
||||
$accountRole = null;
|
||||
}
|
||||
@ -157,8 +157,8 @@ class AccountTransformer extends AbstractTransformer
|
||||
$monthlyPaymentDate = null;
|
||||
$creditCardType = null;
|
||||
if ('ccAsset' === $accountRole && 'asset' === $accountType) {
|
||||
$creditCardType = $this->repository->getMetaValue($account, 'ccType');
|
||||
$monthlyPaymentDate = $this->repository->getMetaValue($account, 'ccMonthlyPaymentDate');
|
||||
$creditCardType = $this->repository->getMetaValue($account, 'cc_type');
|
||||
$monthlyPaymentDate = $this->repository->getMetaValue($account, 'cc_monthly_payment_date');
|
||||
}
|
||||
|
||||
return [$creditCardType, $monthlyPaymentDate];
|
||||
|
@ -127,9 +127,6 @@ class AccountValidator
|
||||
case TransactionType::RECONCILIATION:
|
||||
$result = $this->validateReconciliationDestination($destinationId);
|
||||
break;
|
||||
//case TransactionType::OPENING_BALANCE:
|
||||
//case TransactionType::RECONCILIATION:
|
||||
// die(sprintf('Cannot handle type "%s"', $this->transactionType));
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -479,8 +476,8 @@ class AccountValidator
|
||||
return false;
|
||||
}
|
||||
$this->destination = $search;
|
||||
|
||||
return true;
|
||||
// must not be the same as the source account
|
||||
return !(null !== $this->source && $this->source->id === $this->destination->id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Validation;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use DB;
|
||||
use FireflyIII\Models\Account;
|
||||
|
32
public/v1/js/ff/transactions/convert.js
vendored
32
public/v1/js/ff/transactions/convert.js
vendored
@ -28,7 +28,35 @@ $(document).ready(function () {
|
||||
* Set the auto-complete JSON things.
|
||||
*/
|
||||
function setAutocompletes() {
|
||||
initRevenueACField('source_account_revenue');
|
||||
initExpenseACField('destination_account_expense');
|
||||
//initRevenueACField('source_account_revenue');
|
||||
//initExpenseACField('destination_account_expense');
|
||||
|
||||
makeRevenueAC();
|
||||
}
|
||||
|
||||
function makeRevenueAC() {
|
||||
var sourceNames = new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
prefetch: {
|
||||
url: 'json/revenue-accounts?uid=' + uid,
|
||||
filter: function (list) {
|
||||
return $.map(list, function (object) {
|
||||
return {name: object.name};
|
||||
});
|
||||
}
|
||||
},
|
||||
remote: {
|
||||
url: 'json/revenue-accounts?search=%QUERY&uid=' + uid,
|
||||
wildcard: '%QUERY',
|
||||
filter: function (list) {
|
||||
return $.map(list, function (object) {
|
||||
return {name: object.name};
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
sourceNames.initialize();
|
||||
$('.input-revenue').typeahead({hint: true, highlight: true,}, {source: sourceNames, displayKey: 'name', autoSelect: false});
|
||||
}
|
||||
|
||||
|
@ -840,7 +840,7 @@ return [
|
||||
'mass_edit_journals' => 'Edit a number of transactions',
|
||||
'mass_bulk_journals' => 'Bulk edit a number of transactions',
|
||||
'mass_bulk_journals_explain' => 'This form allows you to change properties if the transactions listed below in one sweeping update. All the transactions in the table will be updated when you change the parameters you see here.',
|
||||
'part_of_split' => 'This transaction is part of a split transaction. If you have not selected all the splits, you may end up with changing only half the transaction.',
|
||||
'part_of_split' => 'This transaction is part of a split transaction. If you have not selected all the splits, you may end up with changing only half the transaction.',
|
||||
'bulk_set_new_values' => 'Use the inputs below to set new values. If you leave them empty, they will be made empty for all. Also, note that only withdrawals will be given a budget.',
|
||||
'no_bulk_category' => 'Don\'t update category',
|
||||
'no_bulk_budget' => 'Don\'t update budget',
|
||||
@ -864,6 +864,7 @@ return [
|
||||
'opt_group_expense_account' => 'Expense accounts',
|
||||
'opt_group_revenue_account' => 'Revenue accounts',
|
||||
'opt_group_l_Loan' => 'Liability: Loan',
|
||||
'opt_group_cash_account' => 'Cash account',
|
||||
'opt_group_l_Debt' => 'Liability: Debt',
|
||||
'opt_group_l_Mortgage' => 'Liability: Mortgage',
|
||||
'opt_group_l_Credit card' => 'Liability: Credit card',
|
||||
@ -1258,12 +1259,11 @@ return [
|
||||
'split_this_withdrawal' => 'Split this withdrawal',
|
||||
'split_this_deposit' => 'Split this deposit',
|
||||
'split_this_transfer' => 'Split this transfer',
|
||||
'cannot_edit_multiple_source' => 'You cannot edit splitted transaction #:id with description ":description" because it contains multiple source accounts.',
|
||||
'cannot_edit_multiple_dest' => 'You cannot edit splitted transaction #:id with description ":description" because it contains multiple destination accounts.',
|
||||
'cannot_edit_reconciled' => 'You cannot edit transaction #:id with description ":description" because it has been marked as reconciled.',
|
||||
'cannot_edit_opening_balance' => 'You cannot edit the opening balance of an account.',
|
||||
'no_edit_multiple_left' => 'You have selected no valid transactions to edit.',
|
||||
'cannot_convert_split_journal' => 'Cannot convert a split transaction',
|
||||
'breadcrumb_convert_group' => 'Convert transaction',
|
||||
'convert_invalid_source' => 'Source information is invalid for transaction #%d.',
|
||||
'convert_invalid_destination' => 'Destination information is invalid for transaction #%d.',
|
||||
|
||||
// Import page (general strings only)
|
||||
'import_index_title' => 'Import transactions into Firefly III',
|
||||
|
@ -1,29 +1,292 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, destinationType, journal) }}
|
||||
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, group, groupTitle) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="POST" action="{{ route('transactions.convert.index.post', [destinationType.type|lower, journal.id]) }}" accept-charset="UTF-8"
|
||||
class="form-horizontal" id="store"
|
||||
<form method="POST" action="{{ route('transactions.convert.index.post', [destinationType.type|lower, group.id]) }}" accept-charset="UTF-8"
|
||||
class="form-horizontal"
|
||||
enctype="multipart/form-data">
|
||||
<input name="_token" type="hidden" value="{{ csrf_token() }}">
|
||||
<div class="row">
|
||||
<div class="col-lg-10 col-md-12 col-sm-12">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ ('convert_options_'~sourceType.type~destinationType.type)|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{{ ExpandedForm.staticText('type', sourceType.type|_) }}
|
||||
{{ ExpandedForm.staticText('description', '<a href="'~route('transactions.show', journal.id)~'">'~journal.description~'</a>') }}
|
||||
{{ ExpandedForm.staticText('date', journal.date.formatLocalized(monthAndDayFormat)) }}
|
||||
|
||||
<p>
|
||||
{# ONE: WITHDRAWAL TO DEPOSIT #}
|
||||
{% if sourceType.type == 'Withdrawal' and destinationType.type == 'Deposit' %}
|
||||
When converting from a withdrawal to a deposit, the money will be deposited into the
|
||||
displayed destination account(s), instead of being withdrawn from them. To complete the conversion,
|
||||
please set the new source account(s) below.
|
||||
{% endif %}
|
||||
|
||||
{# TWO: WITHDRAWAL TO TRANSFER #}
|
||||
{% if sourceType.type == 'Withdrawal' and destinationType.type == 'Transfer' %}
|
||||
When converting a withdrawal into a transfer, the money will be transferred away from the source
|
||||
account(s) into other asset or liability account(s) instead of being spent on the original
|
||||
expense accounts. To complete the conversion, please select new destination account(s).
|
||||
{% endif %}
|
||||
|
||||
{# THREE: DEPOSIT TO WITHDRAWAL #}
|
||||
{% if sourceType.type == 'Deposit' and destinationType.type == 'Withdrawal' %}
|
||||
When converting a deposit into a withdrawal, the money will be withdrawn from the
|
||||
displayed source account(s), instead of being deposited into them. To complete the conversion,
|
||||
please select new destination accounts.
|
||||
{% endif %}
|
||||
|
||||
{# FOUR: DEPOSIT TO TRANSFER#}
|
||||
{% if sourceType.type == 'Deposit' and destinationType.type == 'Transfer' %}
|
||||
When you convert a deposit into a transfer, the money will be deposited into
|
||||
the listed destination account(s) from any of your asset or liability account(s).
|
||||
Please select the new source account(s) to complete the conversion.
|
||||
{% endif %}
|
||||
|
||||
{# FIVE: TRANSFER TO WITHDRAWAL #}
|
||||
{% if sourceType.type == 'Transfer' and destinationType.type == 'Withdrawal' %}
|
||||
When you convert a transfer into a withdrawal, the money will be spent
|
||||
on the destination account(s) you set here, instead of being transferred away.
|
||||
Please select the new destination account(s) to complete the conversion.
|
||||
{% endif %}
|
||||
|
||||
{# SIX: TRANSFER TO DEPOSIT #}
|
||||
{% if sourceType.type == 'Transfer' and destinationType.type == 'Deposit' %}
|
||||
When you convert a transfer into a deposit, the money will be deposited
|
||||
into the destination account(s) you see here, instead of being transferred into them.
|
||||
Please select the new source account(s) to complete the conversion.
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th style="width:10%;">ID</th>
|
||||
<th style="width:25%;">Description</th>
|
||||
<th style="width:25%;">Source account</th>
|
||||
<th style="width:25%;">Destination account</th>
|
||||
<th style="width:15%;">Amount</th>
|
||||
</tr>
|
||||
{% for transaction in groupArray.transactions %}
|
||||
<tr>
|
||||
<td>#{{ transaction.transaction_journal_id }}</td>
|
||||
<td>{{ transaction.description }}</td>
|
||||
<td>
|
||||
{# ONE: WITHDRAWAL TO DEPOSIT #}
|
||||
{% if sourceType.type == 'Withdrawal' and destinationType.type == 'Deposit' %}
|
||||
{# NEW DESTINATION = Asset, SOURCE MUST BE [Revenue, Cash, Loan, Debt, Mortgage] #}
|
||||
{% if
|
||||
transaction.source_type == 'Asset account' %}
|
||||
{{ Form.select('source_id['~transaction.transaction_journal_id~']', validDepositSources, null, {class: 'form-control'}) }}
|
||||
{% endif %}
|
||||
{# NEW DESTINATION = [Loan, Debt, Mortgage], SOURCE MUST BE [Revenue] #}
|
||||
{% if
|
||||
transaction.source_type == 'Loan' or
|
||||
transaction.source_type == 'Debt' or
|
||||
transaction.source_type == 'Mortgage' %}
|
||||
<input
|
||||
autocomplete="off"
|
||||
placeholder="Source account"
|
||||
name="source_name[{{ transaction.transaction_journal_id }}]"
|
||||
type="text"
|
||||
value="{% if transaction.destination_type != "Cash account" %}{{ preFilled.source_name[transaction.transaction_journal_id]|default(transaction.destination_name) }}{% endif %}"
|
||||
class="form-control tt-input input-revenue"
|
||||
spellcheck="false" dir="auto">
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# TWO: WITHDRAWAL TO TRANSFER #}
|
||||
{% if sourceType.type == 'Withdrawal' and destinationType.type == 'Transfer' %}
|
||||
<a href="{{ route('accounts.show', [transaction.source_id]) }}"
|
||||
title="{{ transaction.source_iban|default(transaction.source_name) }}">{{ transaction.source_name }}</a>
|
||||
{# hide source in hidden input #}
|
||||
<input type="hidden" name="source_id[{{ transaction.transaction_journal_id }}]" value="{{ transaction.source_id }}">
|
||||
{% endif %}
|
||||
|
||||
{# THREE: DEPOSIT TO WITHDRAWAL #}
|
||||
{% if sourceType.type == 'Deposit' and destinationType.type == 'Withdrawal' %}
|
||||
<a href="{{ route('accounts.show', [transaction.destination_id]) }}"
|
||||
title="{{ transaction.destination_iban|default(transaction.destination_name) }}">{{ transaction.destination_name }}</a>
|
||||
|
||||
{# hide new source in hidden input #}
|
||||
<input type="hidden" name="source_id[{{ transaction.transaction_journal_id }}]" value="{{ transaction.destination_id }}">
|
||||
{% endif %}
|
||||
|
||||
{# FOUR: DEPOSIT TO TRANSFER#}
|
||||
{% if sourceType.type == 'Deposit' and destinationType.type == 'Transfer' %}
|
||||
{# if new destination is asset, then asset#}
|
||||
{% if transaction.destination_type == 'Asset account' %}
|
||||
{{ Form.select('source_id['~transaction.transaction_journal_id~']', assets,null, {class: 'form-control'}) }}
|
||||
{% endif %}
|
||||
{% if transaction.destination_type == 'Loan' or
|
||||
transaction.destination_type == 'Debt' or
|
||||
transaction.destination_type == 'Mortgage' %}
|
||||
{{ Form.select('source_id['~transaction.transaction_journal_id~']', liabilities,null, {class: 'form-control'}) }}
|
||||
{% endif %}
|
||||
|
||||
{# if new destination liability, then liability.#}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{# FIVE: TRANSFER TO WITHDRAWAL #}
|
||||
{% if sourceType.type == 'Transfer' and destinationType.type == 'Withdrawal' %}
|
||||
<a href="{{ route('accounts.show', [transaction.source_id]) }}"
|
||||
title="{{ transaction.source_iban|default(transaction.source_name) }}">{{ transaction.source_name }}</a>
|
||||
|
||||
{# hide source in hidden input #}
|
||||
<input type="hidden" name="source_id[{{ transaction.transaction_journal_id }}]" value="{{ transaction.source_id }}">
|
||||
{% endif %}
|
||||
|
||||
{# SIX: TRANSFER TO DEPOSIT #}
|
||||
{% if sourceType.type == 'Transfer' and destinationType.type == 'Deposit' %}
|
||||
{# NEW DESTINATION = Asset, SOURCE MUST BE [Revenue, Cash, Loan, Debt, Mortgage] #}
|
||||
{% if
|
||||
transaction.source_type == 'Asset account' %}
|
||||
{{ Form.select('source_id['~transaction.transaction_journal_id~']', validDepositSources, null, {class: 'form-control'}) }}
|
||||
{% endif %}
|
||||
{# NEW DESTINATION = [Debt, Mortgage, Load], SOURCE MUST BE [Revenue] #}
|
||||
{% if
|
||||
transaction.source_type == 'Loan' or
|
||||
transaction.source_type == 'Debt' or
|
||||
transaction.source_type == 'Mortgage' %}
|
||||
<input
|
||||
autocomplete="off"
|
||||
placeholder="Source account"
|
||||
name="source_name[{{ transaction.transaction_journal_id }}]"
|
||||
type="text"
|
||||
value="{% if transaction.destination_type != "Cash account" %}{{ transaction.source_name }}{% endif %}"
|
||||
class="form-control tt-input"
|
||||
spellcheck="false" dir="auto">
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
</td>
|
||||
<td>
|
||||
{# ONE: WITHDRAWAL TO DEPOSIT #}
|
||||
{% if sourceType.type == 'Withdrawal' and destinationType.type == 'Deposit' %}
|
||||
<a href="{{ route('accounts.show', [transaction.source_id]) }}"
|
||||
title="{{ transaction.source_iban|default(transaction.source_name) }}">{{ transaction.source_name }}</a>
|
||||
|
||||
{# hide destination in hidden input #}
|
||||
<input type="hidden" name="destination_id[{{ transaction.transaction_journal_id }}]" value="{{ transaction.source_id }}">
|
||||
{% endif %}
|
||||
|
||||
{# TWO: WITHDRAWAL TO TRANSFER #}
|
||||
{% if sourceType.type == 'Withdrawal' and destinationType.type == 'Transfer' %}
|
||||
{#if the source is a liability, destination must also be a liability.#}
|
||||
{% if
|
||||
transaction.source_type == 'Loan' or
|
||||
transaction.source_type == 'Debt' or
|
||||
transaction.source_type == 'Mortgage' %}
|
||||
{{ Form.select('destination_id['~transaction.transaction_journal_id~']', liabilities, null, {class: 'form-control'}) }}
|
||||
{% endif %}
|
||||
|
||||
{# if the source is an asset, destination can only be an asset. #}
|
||||
{% if transaction.source_type == 'Asset account' %}
|
||||
{{ Form.select('destination_id['~transaction.transaction_journal_id~']', assets, null, {class: 'form-control'}) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# THREE: DEPOSIT TO WITHDRAWAL #}
|
||||
{% if sourceType.type == 'Deposit' and destinationType.type == 'Withdrawal' %}
|
||||
|
||||
{# if new source is Asset, destination must be [Expense, Loan, Debt or Mortgage] #}
|
||||
{% if transaction.destination_type == 'Asset account' %}
|
||||
{{ Form.select('destination_id['~transaction.transaction_journal_id~']', validWithdrawalDests, null, {class: 'form-control'}) }}
|
||||
{% endif %}
|
||||
{% if transaction.destination_type == 'Loan' or
|
||||
transaction.destination_type == 'Debt' or
|
||||
transaction.destination_type == 'Mortgage' %}
|
||||
{# if new source is Liability, destination must be expense account. #}
|
||||
{# hier ben je. #}
|
||||
|
||||
<input
|
||||
autocomplete="off"
|
||||
placeholder="Destination account"
|
||||
name="destination_name[{{ transaction.transaction_journal_id }}]"
|
||||
type="text"
|
||||
value="{% if transaction.source_type != "Cash account" %}{{ transaction.source_name }}{% endif %}"
|
||||
class="form-control tt-input"
|
||||
spellcheck="false" dir="auto">
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# FOUR: DEPOSIT TO TRANSFER#}
|
||||
{% if sourceType.type == 'Deposit' and destinationType.type == 'Transfer' %}
|
||||
<a href="{{ route('accounts.show', [transaction.destination_id]) }}"
|
||||
title="{{ transaction.destination_iban|default(transaction.destination_name) }}">{{ transaction.destination_name }}</a>
|
||||
|
||||
{# hide destination in hidden input #}
|
||||
<input type="hidden" name="destination_id[{{ transaction.transaction_journal_id }}]" value="{{ transaction.destination_id }}">
|
||||
{% endif %}
|
||||
|
||||
{# FIVE: TRANSFER TO WITHDRAWAL #}
|
||||
{% if sourceType.type == 'Transfer' and destinationType.type == 'Withdrawal' %}
|
||||
|
||||
{% if transaction.source_type == 'Asset account' %}
|
||||
{{ Form.select('destination_id['~transaction.transaction_journal_id~']', validWithdrawalDests, null, {class: 'form-control'}) }}
|
||||
{% endif %}
|
||||
{% if transaction.source_type == 'Loan' or
|
||||
transaction.source_type == 'Debt' or
|
||||
transaction.source_type == 'Mortgage' %}
|
||||
<input
|
||||
autocomplete="off"
|
||||
placeholder="Destination account"
|
||||
name="destination_name[{{ transaction.transaction_journal_id }}]"
|
||||
type="text"
|
||||
value="{% if transaction.source_type != "Cash account" %}{{ transaction.destination_name }}{% endif %}"
|
||||
class="form-control tt-input"
|
||||
spellcheck="false" dir="auto">
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# SIX: TRANSFER TO DEPOSIT #}
|
||||
{% if sourceType.type == 'Transfer' and destinationType.type == 'Deposit' %}
|
||||
<a href="{{ route('accounts.show', [transaction.destination_id]) }}"
|
||||
title="{{ transaction.destination_iban|default(transaction.destination_name) }}">{{ transaction.destination_name }}</a>
|
||||
|
||||
{# hide destination in hidden input #}
|
||||
<input type="hidden" name="destination_id[{{ transaction.transaction_journal_id }}]" value="{{ transaction.destination_id }}">
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if transaction.transaction_type_type == 'Deposit' %}
|
||||
{{ formatAmountBySymbol(transaction.amount*-1, transaction.currency_symbol, transaction.currency_symbol_decimal_places) }}
|
||||
{% if null != transaction.foreign_amount %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_amount*-1, transaction.foreign_currency_symbol, transaction.foreign_currency_symbol_decimal_places) }})
|
||||
{% endif %}
|
||||
{% elseif transaction.transaction_type_type == 'Transfer' %}
|
||||
<span class="text-info">{{ formatAmountBySymbol(transaction.amount*-1, transaction.currency_symbol, transaction.currency_symbol_decimal_places, false) }}
|
||||
{% if null != transaction.foreign_amount %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_amount*-1, transaction.foreign_currency_symbol, transaction.foreign_currency_symbol_decimal_places, false) }})
|
||||
{% endif %}</span>
|
||||
{% else %}
|
||||
{{ formatAmountBySymbol(transaction.amount, transaction.currency_symbol, transaction.currency_symbol_decimal_places) }}
|
||||
{% if null != transaction.foreign_amount %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_amount, transaction.foreign_currency_symbol, transaction.foreign_currency_symbol_decimal_places) }})
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
|
||||
{#
|
||||
|
||||
|
||||
{{ ExpandedForm.staticText('description', '<a href="'~route('transactions.show', group.id)~'">'~journal.description~'</a>') }}
|
||||
{{ ExpandedForm.staticText('type', sourceType.type|_) }}
|
||||
{{ ExpandedForm.staticText('date', journal.date.formatLocalized(monthAndDayFormat)) }}
|
||||
#}
|
||||
{# in case of withdrawal #}
|
||||
{% if sourceType.type == "Withdrawal" %}
|
||||
{#
|
||||
{% if journalType.type == "Withdrawal" %}
|
||||
{{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name~'</a>') }}
|
||||
{# if destination is cash, show (cash) #}
|
||||
<!-- if destination is cash, show (cash) -->
|
||||
{% if destinationAccount.accountType.type == "Cash account" %}
|
||||
{{ ExpandedForm.staticText('destination_account_expense', '<span class="text-success">(cash)</a>') }}
|
||||
{% else %}
|
||||
@ -31,10 +294,11 @@
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
#}
|
||||
{# in case of deposit #}
|
||||
{% if sourceType.type == "Deposit" %}
|
||||
{# if source is cash, show (cash) #}
|
||||
{#
|
||||
{% if journalType.type == "Deposit" %}
|
||||
<!-- if source is cash, show (cash) -->
|
||||
{% if sourceAccount.accountType.type == "Cash account" %}
|
||||
{{ ExpandedForm.staticText('source_account_revenue', '<span class="text-success">(cash)</a>') }}
|
||||
{% else %}
|
||||
@ -42,15 +306,22 @@
|
||||
{% endif %}
|
||||
{{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name~'</a>') }}
|
||||
{% endif %}
|
||||
#}
|
||||
|
||||
{# in case of transfer #}
|
||||
{% if sourceType.type == "Transfer" %}
|
||||
{#
|
||||
{% if journalType.type == "Transfer" %}
|
||||
{{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name~'</a>') }}
|
||||
{{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name~'</a>') }}
|
||||
{% endif %}
|
||||
#}
|
||||
|
||||
{# ONE #}
|
||||
{% if sourceType.type == 'Withdrawal' and destinationType.type == 'Deposit' %}
|
||||
{#
|
||||
{% if journalType.type == 'Withdrawal' and destinationType.type == 'Deposit' %}
|
||||
ONE
|
||||
{% endif %}
|
||||
{% if journalType.type == 'Withdrawal' and destinationType.type == 'Deposit' %}
|
||||
<p><em>
|
||||
{{ trans('firefly.convert_explanation_withdrawal_deposit',
|
||||
{
|
||||
@ -72,9 +343,10 @@
|
||||
{{ ExpandedForm.text('source_account_revenue', destinationAccount.name) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
#}
|
||||
{# TWO #}
|
||||
{% if sourceType.type == 'Withdrawal' and destinationType.type == 'Transfer' %}
|
||||
{#
|
||||
{% if journalType.type == 'Withdrawal' and destinationType.type == 'Transfer' %}
|
||||
<p><em>
|
||||
{{ trans('firefly.convert_explanation_withdrawal_transfer',
|
||||
{
|
||||
@ -95,9 +367,10 @@
|
||||
{{ ExpandedForm.activeLongAccountList('destination_account_asset', null) }}
|
||||
|
||||
{% endif %}
|
||||
|
||||
#}
|
||||
{# THREE #}
|
||||
{% if sourceType.type == 'Deposit' and destinationType.type == 'Withdrawal' %}
|
||||
{#
|
||||
{% if journalType.type == 'Deposit' and destinationType.type == 'Withdrawal' %}
|
||||
<p>
|
||||
<em>
|
||||
{{ trans('firefly.convert_explanation_deposit_withdrawal',
|
||||
@ -123,9 +396,10 @@
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
#}
|
||||
{# FOUR #}
|
||||
{% if sourceType.type == 'Deposit' and destinationType.type == 'Transfer' %}
|
||||
{#
|
||||
{% if journalType.type == 'Deposit' and destinationType.type == 'Transfer' %}
|
||||
|
||||
<p>
|
||||
<em>
|
||||
@ -147,9 +421,10 @@
|
||||
</p>
|
||||
{{ ExpandedForm.activeLongAccountList('source_account_asset', null) }}
|
||||
{% endif %}
|
||||
|
||||
#}
|
||||
{# FIVE #}
|
||||
{% if sourceType.type == 'Transfer' and destinationType.type == 'Withdrawal' %}
|
||||
{#
|
||||
{% if journalType.type == 'Transfer' and destinationType.type == 'Withdrawal' %}
|
||||
|
||||
<p>
|
||||
<em>
|
||||
@ -173,9 +448,10 @@
|
||||
{{ ExpandedForm.text('destination_account_expense', destinationAccount.name) }}
|
||||
|
||||
{% endif %}
|
||||
|
||||
#}
|
||||
{# SIX #}
|
||||
{% if sourceType.type == 'Transfer' and destinationType.type == 'Deposit' %}
|
||||
{#
|
||||
{% if journalType.type == 'Transfer' and destinationType.type == 'Deposit' %}
|
||||
|
||||
|
||||
<p>
|
||||
@ -200,10 +476,10 @@
|
||||
{{ ExpandedForm.text('source_account_revenue', sourceAccount.name) }}
|
||||
|
||||
{% endif %}
|
||||
|
||||
#}
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<a href="{{ route('transactions.show', journal.id) }}" class="btn btn-danger">{{ 'cancel'|_ }}</a>
|
||||
<a href="{{ route('transactions.show', group.id) }}" class="btn btn-danger">{{ 'cancel'|_ }}</a>
|
||||
<button type="submit" id="transaction-btn" class="btn btn-success pull-right">
|
||||
{{ trans('form.convert_'~sourceType.type) }}
|
||||
</button>
|
||||
@ -216,6 +492,5 @@
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript" src="v1/js/lib/typeahead/typeahead.bundle.min.js?v={{ FF_VERSION }}"></script>
|
||||
<script type="text/javascript" src="v1/js/ff/common/autocomplete.js?v={{ FF_VERSION }}"></script>
|
||||
<script type="text/javascript" src="v1/js/ff/transactions/convert.js?v={{ FF_VERSION }}"></script>
|
||||
{% endblock %}
|
||||
|
@ -70,20 +70,23 @@
|
||||
<div class="box-footer">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{ route('transactions.edit', [transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-pencil"></i> {{ 'edit'|_ }}</a>
|
||||
{% if type != 'Opening balance' and type != 'Reconciliation' %}
|
||||
{#<a href="{{ route('transactions.clone', [transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-copy"></i> {{ 'clone'|_ }}</a>#}
|
||||
|
||||
{#
|
||||
{% if type != 'Withdrawal' %}
|
||||
<a href="{{ route('transactions.convert', [transactionGroup.id, 'withdrawal']) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_withdrawal'|_ }}</a>
|
||||
{% if groupArray.transactions[0].type != 'withdrawal' %}
|
||||
<a href="{{ route('transactions.convert.index', ['withdrawal', transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_withdrawal'|_ }}</a>
|
||||
{% endif %}
|
||||
{% if type != 'Deposit' %}
|
||||
<a href="{{ route('transactions.convert', [transactionGroup.id, 'deposit']) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_deposit'|_ }}</a>
|
||||
|
||||
{% if groupArray.transactions[0].type != 'deposit' %}
|
||||
<a href="{{ route('transactions.convert.index', ['deposit', transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_deposit'|_ }}</a>
|
||||
{% endif %}
|
||||
{% if type != 'Transfer' %}
|
||||
<a href="{{ route('transactions.convert', [transactionGroup.id, 'transfer']) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_transfer'|_ }}</a>
|
||||
|
||||
{% if groupArray.transactions[0].type != 'transfer' %}
|
||||
<a href="{{ route('transactions.convert.index', ['transfer', transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_transfer'|_ }}</a>
|
||||
{% endif %}
|
||||
#}
|
||||
|
||||
|
||||
{% if groupArray.transactions[0].type != 'opening balance' and groupArray.transactions[0].type != 'reconciliation' %}
|
||||
CLONE
|
||||
{#<a href="{{ route('transactions.clone', [transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-copy"></i> {{ 'clone'|_ }}</a>#}
|
||||
{% endif %}
|
||||
{#
|
||||
<a href="{{ route('transactions.delete', [transactionGroup.id]) }}" class="btn btn-danger"><i class="fa fa-trash"></i> {{ 'delete'|_ }}</a>
|
||||
|
@ -1084,11 +1084,11 @@ try {
|
||||
|
||||
Breadcrumbs::register(
|
||||
'transactions.convert.index',
|
||||
function (BreadcrumbsGenerator $breadcrumbs, TransactionType $destinationType, TransactionJournal $journal) {
|
||||
$breadcrumbs->parent('transactions.show', $journal);
|
||||
function (BreadcrumbsGenerator $breadcrumbs, TransactionGroup $group, string $groupTitle) {
|
||||
$breadcrumbs->parent('transactions.show', $group);
|
||||
$breadcrumbs->push(
|
||||
trans('firefly.convert_to_' . $destinationType->type, ['description' => limitStringLength($journal->description)]),
|
||||
route('transactions.convert.index', [strtolower($destinationType->type), $journal->id])
|
||||
trans('firefly.breadcrumb_convert_group', ['description' => limitStringLength($groupTitle)]),
|
||||
route('transactions.convert.index', [$group->id, 'something'])
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -532,6 +532,8 @@ Route::group(
|
||||
|
||||
// for auto complete
|
||||
Route::get('accounts', ['uses' => 'Json\AutoCompleteController@accounts', 'as' => 'autocomplete.accounts']);
|
||||
Route::get('revenue-accounts', ['uses' => 'Json\AutoCompleteController@revenueAccounts', 'as' => 'autocomplete.revenue-accounts']);
|
||||
Route::get('expense-accounts', ['uses' => 'Json\AutoCompleteController@expenseAccounts', 'as' => 'autocomplete.expense-accounts']);
|
||||
Route::get('budgets', ['uses' => 'Json\AutoCompleteController@budgets', 'as' => 'autocomplete.budgets']);
|
||||
Route::get('categories', ['uses' => 'Json\AutoCompleteController@categories', 'as' => 'autocomplete.categories']);
|
||||
Route::get('currencies', ['uses' => 'Json\AutoCompleteController@currencies', 'as' => 'autocomplete.currencies']);
|
||||
@ -954,15 +956,13 @@ Route::group(
|
||||
/**
|
||||
* Transaction Convert Controller
|
||||
*/
|
||||
//Route::group(
|
||||
// ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/convert',
|
||||
// 'as' => 'transactions.convert.'], function () {
|
||||
// // TODO improve these routes
|
||||
// Route::get('{transactionType}/{tj}', ['uses' => 'ConvertController@index', 'as' => 'index']);
|
||||
// Route::post('{transactionType}/{tj}', ['uses' => 'ConvertController@postIndex', 'as' => 'index.post']);
|
||||
// // TODO end of todo
|
||||
//}
|
||||
//);
|
||||
Route::group(
|
||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/convert',
|
||||
'as' => 'transactions.convert.'], static function () {
|
||||
Route::get('{transactionType}/{transactionGroup}', ['uses' => 'ConvertController@index', 'as' => 'index']);
|
||||
Route::post('{transactionType}/{transactionGroup}', ['uses' => 'ConvertController@postIndex', 'as' => 'index.post']);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Transaction Link Controller
|
||||
|
@ -22,13 +22,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature\Controllers\Transaction;
|
||||
|
||||
use Amount;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Mockery;
|
||||
use Preferences;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
@ -54,101 +57,35 @@ class BulkControllerTest extends TestCase
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\BulkController
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\BulkController
|
||||
*/
|
||||
public function testEdit(): void
|
||||
public function testEditWithdrawal(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
// mock stuff:
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$budgetRepos = $this->mock(BudgetRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$journalRepos = $this->mockDefaultSession();
|
||||
$budgetRepos = $this->mock(BudgetRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$collector = $this->mock(GroupCollectorInterface::class);
|
||||
$withdrawal = $this->getRandomWithdrawal();
|
||||
$withdrawalArray = $this->getRandomWithdrawalAsArray();
|
||||
|
||||
Amount::shouldReceive('formatAnything')->atLeast()->once()->andReturn('-100');
|
||||
|
||||
$collector->shouldReceive('setTypes')
|
||||
->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER]])->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('withCategoryInformation')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('withBudgetInformation')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('withTagInformation')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('setJournalIds')->atLeast()->once()->withArgs([[$withdrawal->id]])->andReturnSelf();
|
||||
$collector->shouldReceive('getExtractedJournals')->atLeast()->once()->andReturn([$withdrawalArray]);
|
||||
|
||||
$userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->atLeast()->once()->andReturn(true);
|
||||
$budgetRepos->shouldReceive('getActiveBudgets')->andReturn(new Collection);
|
||||
$journalRepos->shouldReceive('getJournalSourceAccounts')->andReturn(new Collection);
|
||||
$journalRepos->shouldReceive('getJournalDestinationAccounts')->andReturn(new Collection);
|
||||
$journalRepos->shouldReceive('firstNull')->andReturn(new TransactionJournal);
|
||||
$journalRepos->shouldReceive('getTransactionType')->andReturn('Transfer');
|
||||
$journalRepos->shouldReceive('isJournalReconciled')->andReturn(false);
|
||||
|
||||
$transfers = TransactionJournal::where('transaction_type_id', 3)->where('user_id', $this->user()->id)->take(4)->get()->pluck('id')->toArray();
|
||||
|
||||
$this->be($this->user());
|
||||
$response = $this->get(route('transactions.bulk.edit', $transfers));
|
||||
$response->assertStatus(200);
|
||||
$response->assertSee('Bulk edit a number of transactions');
|
||||
// has bread crumb
|
||||
$response->assertSee('<ol class="breadcrumb">');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\BulkController
|
||||
*/
|
||||
public function testEditMultiple(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
// mock stuff:
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$budgetRepos = $this->mock(BudgetRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
|
||||
$userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->atLeast()->once()->andReturn(true);
|
||||
$budgetRepos->shouldReceive('getActiveBudgets')->andReturn(new Collection);
|
||||
$journalRepos->shouldReceive('firstNull')->andReturn(new TransactionJournal);
|
||||
$journalRepos->shouldReceive('getJournalSourceAccounts')
|
||||
->andReturn(new Collection([1, 2, 3]), new Collection, new Collection, new Collection, new Collection([1]));
|
||||
$journalRepos->shouldReceive('getJournalDestinationAccounts')
|
||||
->andReturn(new Collection, new Collection([1, 2, 3]), new Collection, new Collection, new Collection([1]));
|
||||
$journalRepos->shouldReceive('getTransactionType')
|
||||
->andReturn('Withdrawal', 'Opening balance', 'Withdrawal', 'Withdrawal', 'Withdrawal');
|
||||
$journalRepos->shouldReceive('isJournalReconciled')
|
||||
->andReturn(true, false, false, false, false);
|
||||
|
||||
// default transactions
|
||||
$collection = $this->user()->transactionJournals()->take(5)->get();
|
||||
$allIds = $collection->pluck('id')->toArray();
|
||||
$route = route('transactions.bulk.edit', implode(',', $allIds));
|
||||
$this->be($this->user());
|
||||
$response = $this->get($route);
|
||||
$response->assertStatus(200);
|
||||
$response->assertSee('Bulk edit a number of transactions');
|
||||
$response->assertSessionHas('info');
|
||||
// has bread crumb
|
||||
$response->assertSee('<ol class="breadcrumb">');
|
||||
$response->assertSee('marked as reconciled');
|
||||
$response->assertSee('multiple source accounts');
|
||||
$response->assertSee('multiple destination accounts');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\BulkController
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\BulkController
|
||||
*/
|
||||
public function testEditNull(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
// mock stuff:
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$budgetRepos = $this->mock(BudgetRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
|
||||
$userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->atLeast()->once()->andReturn(true);
|
||||
$budgetRepos->shouldReceive('getActiveBudgets')->andReturn(new Collection);
|
||||
$journalRepos->shouldReceive('getJournalSourceAccounts')->andReturn(new Collection);
|
||||
$journalRepos->shouldReceive('getJournalDestinationAccounts')->andReturn(new Collection);
|
||||
$journalRepos->shouldReceive('firstNull')->andReturn(new TransactionJournal, null);
|
||||
$journalRepos->shouldReceive('getTransactionType')->andReturn('Transfer');
|
||||
$journalRepos->shouldReceive('isJournalReconciled')->andReturn(false);
|
||||
|
||||
$transfers = TransactionJournal::where('transaction_type_id', 3)->where('user_id', $this->user()->id)->take(4)->get()->pluck('id')->toArray();
|
||||
|
||||
$this->be($this->user());
|
||||
$response = $this->get(route('transactions.bulk.edit', $transfers));
|
||||
$response = $this->get(route('transactions.bulk.edit', [$withdrawal->id]));
|
||||
$response->assertStatus(200);
|
||||
$response->assertSee('Bulk edit a number of transactions');
|
||||
// has bread crumb
|
||||
@ -161,34 +98,26 @@ class BulkControllerTest extends TestCase
|
||||
*/
|
||||
public function testUpdate(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
$tags = ['a', 'b', 'c'];
|
||||
$collection = TransactionJournal::where('transaction_type_id', 1)->where('user_id', $this->user()->id)->take(4)->get();
|
||||
$allIds = $collection->pluck('id')->toArray();
|
||||
|
||||
$data = [
|
||||
'category' => 'Some new category',
|
||||
'budget_id' => 1,
|
||||
$budget = $this->getRandomBudget();
|
||||
$category = $this->getRandomCategory();
|
||||
$withdrawal = $this->getRandomWithdrawalAsArray();
|
||||
$data = [
|
||||
'category' => $category->name,
|
||||
'budget_id' => $budget->id,
|
||||
'tags' => 'a,b,c',
|
||||
'journals' => $allIds,
|
||||
'journals' => [$withdrawal['transaction_journal_id']],
|
||||
];
|
||||
|
||||
$repository = $this->mock(JournalRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$repository = $this->mockDefaultSession();
|
||||
|
||||
$repository->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal);
|
||||
$repository->shouldReceive('findNull')->times(4)->andReturn(new TransactionJournal);
|
||||
Preferences::shouldReceive('mark')->atLeast()->once();
|
||||
|
||||
$repository->shouldReceive('updateCategory')->times(4)->andReturn(new TransactionJournal())
|
||||
->withArgs([Mockery::any(), $data['category']]);
|
||||
$repository->shouldReceive('updateBudget')->atLeast()->once()->andReturn(new TransactionJournal())->withArgs([Mockery::any(), $data['budget_id']]);
|
||||
$repository->shouldReceive('updateCategory')->atLeast()->once()->andReturn(new TransactionJournal())->withArgs([Mockery::any(), $data['category']]);
|
||||
$repository->shouldReceive('updateTags')->atLeast()->once()->andReturn(new TransactionJournal())->withArgs([Mockery::any(), $tags]);
|
||||
|
||||
$repository->shouldReceive('updateBudget')->times(4)->andReturn(new TransactionJournal())
|
||||
->withArgs([Mockery::any(), $data['budget_id']]);
|
||||
|
||||
$repository->shouldReceive('updateTags')->times(4)->andReturn(new TransactionJournal())
|
||||
->withArgs([Mockery::any(), ['tags' => $tags]]);
|
||||
$repository->shouldReceive('findNull')->atLeast()->once()->andReturn(new TransactionJournal);
|
||||
|
||||
|
||||
$route = route('transactions.bulk.update');
|
||||
@ -198,40 +127,34 @@ class BulkControllerTest extends TestCase
|
||||
$response->assertSessionHas('success');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\BulkController
|
||||
* @covers \FireflyIII\Http\Requests\BulkEditJournalRequest
|
||||
*/
|
||||
public function testUpdateNull(): void
|
||||
public function testUpdateIgnoreAll(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
$tags = ['a', 'b', 'c'];
|
||||
$collection = TransactionJournal::where('transaction_type_id', 1)->where('user_id', $this->user()->id)->take(4)->get();
|
||||
$allIds = $collection->pluck('id')->toArray();
|
||||
|
||||
$data = [
|
||||
'category' => 'Some new category',
|
||||
'budget_id' => 1,
|
||||
'tags' => 'a,b,c',
|
||||
'journals' => $allIds,
|
||||
$budget = $this->getRandomBudget();
|
||||
$category = $this->getRandomCategory();
|
||||
$withdrawal = $this->getRandomWithdrawalAsArray();
|
||||
$data = [
|
||||
'category' => $category->name,
|
||||
'budget_id' => $budget->id,
|
||||
'tags' => 'a,b,c',
|
||||
'journals' => [$withdrawal['transaction_journal_id']],
|
||||
'ignore_category' => '1',
|
||||
'ignore_budget' => '1',
|
||||
'ignore_tags' => '1',
|
||||
];
|
||||
|
||||
$repository = $this->mock(JournalRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$repository = $this->mockDefaultSession();
|
||||
|
||||
$repository->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal);
|
||||
$repository->shouldReceive('findNull')->times(4)->andReturn(new TransactionJournal, null);
|
||||
Preferences::shouldReceive('mark')->atLeast()->once();
|
||||
|
||||
$repository->shouldReceive('updateCategory')->times(1)->andReturn(new TransactionJournal())
|
||||
->withArgs([Mockery::any(), $data['category']]);
|
||||
|
||||
$repository->shouldReceive('updateBudget')->times(1)->andReturn(new TransactionJournal())
|
||||
->withArgs([Mockery::any(), $data['budget_id']]);
|
||||
|
||||
$repository->shouldReceive('updateTags')->times(1)->andReturn(new TransactionJournal())
|
||||
->withArgs([Mockery::any(), ['tags' => $tags]]);
|
||||
$repository->shouldNotReceive('updateBudget');
|
||||
$repository->shouldNotReceive('updateCategory');
|
||||
$repository->shouldNotReceive('updateTags');
|
||||
$repository->shouldReceive('findNull')->atLeast()->once()->andReturn(new TransactionJournal);
|
||||
|
||||
|
||||
$route = route('transactions.bulk.update');
|
||||
|
Loading…
Reference in New Issue
Block a user