mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Improve mass controller and test controllers.
This commit is contained in:
parent
6d34cfb940
commit
889b7e9a18
@ -124,6 +124,37 @@ class AutoCompleteController extends Controller
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* An auto-complete specifically for expense accounts, used when mass updating mostly.
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function expenseAccounts(Request $request): JsonResponse
|
||||
{
|
||||
$search = $request->get('search');
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
// filter the account types:
|
||||
$allowedAccountTypes = [AccountType::EXPENSE];
|
||||
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.
|
||||
|
@ -63,6 +63,8 @@ class BulkController extends Controller
|
||||
/**
|
||||
* Edit a set of journals in bulk.
|
||||
*
|
||||
* TODO user wont be able to tell if journal is part of split.
|
||||
*
|
||||
* @param Collection $journals
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
@ -71,6 +73,8 @@ class BulkController extends Controller
|
||||
{
|
||||
$subTitle = (string)trans('firefly.mass_bulk_journals');
|
||||
|
||||
// make amounts positive.
|
||||
|
||||
// get list of budgets:
|
||||
/** @var BudgetRepositoryInterface $repository */
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
|
@ -25,23 +25,19 @@ namespace FireflyIII\Http\Controllers\Transaction;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\TransactionViewFilter;
|
||||
use FireflyIII\Helpers\Filter\TransferFilter;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\MassDeleteJournalRequest;
|
||||
use FireflyIII\Http\Requests\MassEditJournalRequest;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Transformers\TransactionTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use FireflyIII\Services\Internal\Update\JournalUpdateService;
|
||||
use Illuminate\View\View as IlluminateView;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use InvalidArgumentException;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class MassController.
|
||||
@ -55,6 +51,7 @@ class MassController extends Controller
|
||||
|
||||
/**
|
||||
* MassController constructor.
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@ -65,7 +62,6 @@ class MassController extends Controller
|
||||
app('view')->share('title', (string)trans('firefly.transactions'));
|
||||
app('view')->share('mainTitleIcon', 'fa-repeat');
|
||||
$this->repository = app(JournalRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
@ -74,11 +70,11 @@ class MassController extends Controller
|
||||
/**
|
||||
* Mass delete transactions.
|
||||
*
|
||||
* @param Collection $journals
|
||||
* @param array $journals
|
||||
*
|
||||
* @return IlluminateView
|
||||
*/
|
||||
public function delete(Collection $journals): IlluminateView
|
||||
public function delete(array $journals): IlluminateView
|
||||
{
|
||||
$subTitle = (string)trans('firefly.mass_delete_journals');
|
||||
|
||||
@ -103,10 +99,11 @@ class MassController extends Controller
|
||||
if (is_array($ids)) {
|
||||
/** @var string $journalId */
|
||||
foreach ($ids as $journalId) {
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $this->repository->findNull((int)$journalId);
|
||||
if (null !== $journal && (int)$journalId === $journal->id) {
|
||||
$this->repository->destroy($journal);
|
||||
$this->repository->destroyJournal($journal);
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
@ -123,137 +120,69 @@ class MassController extends Controller
|
||||
/**
|
||||
* Mass edit of journals.
|
||||
*
|
||||
* @param Collection $journals
|
||||
* @param array $journals
|
||||
*
|
||||
* @return IlluminateView
|
||||
*
|
||||
* TODO rebuild this feature.
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function edit(Collection $journals): IlluminateView
|
||||
public function edit(array $journals): IlluminateView
|
||||
{
|
||||
throw new FireflyException(sprintf('The mass-editor is not available in v%s of Firefly III. Sorry about that. It will be back soon.', config('firefly.version')));
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$subTitle = (string)trans('firefly.mass_edit_journals');
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||
|
||||
// valid withdrawal sources:
|
||||
$array = array_keys(config(sprintf('firefly.source_dests.%s', TransactionType::WITHDRAWAL)));
|
||||
$withdrawalSources = $repository->getAccountsByType($array);
|
||||
|
||||
// valid deposit destinations:
|
||||
$array = config(sprintf('firefly.source_dests.%s.%s', TransactionType::DEPOSIT, AccountType::REVENUE));
|
||||
$depositDestinations = $repository->getAccountsByType($array);
|
||||
|
||||
/** @var BudgetRepositoryInterface $budgetRepository */
|
||||
$budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$budgets = $budgetRepository->getBudgets();
|
||||
|
||||
// reverse amounts
|
||||
foreach ($journals as $index => $journal) {
|
||||
$journals[$index]['amount'] = app('steam')->positive($journal['amount']);
|
||||
$journals[$index]['foreign_amount'] = null === $journal['foreign_amount'] ?
|
||||
null : app('steam')->positive($journal['foreign_amount']);
|
||||
}
|
||||
|
||||
$this->rememberPreviousUri('transactions.mass-edit.uri');
|
||||
|
||||
/** @var TransactionTransformer $transformer */
|
||||
$transformer = app(TransactionTransformer::class);
|
||||
$transformer->setParameters(new ParameterBag);
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($user);
|
||||
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
|
||||
$collector->setJournals($journals);
|
||||
$collector->addFilter(TransactionViewFilter::class);
|
||||
$collector->addFilter(TransferFilter::class);
|
||||
|
||||
|
||||
$collection = $collector->getTransactions();
|
||||
$transactions = $collection->map(
|
||||
function (Transaction $transaction) use ($transformer) {
|
||||
$transformed = $transformer->transform($transaction);
|
||||
// make sure amount is positive:
|
||||
$transformed['amount'] = app('steam')->positive((string)$transformed['amount']);
|
||||
$transformed['foreign_amount'] = app('steam')->positive((string)$transformed['foreign_amount']);
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
);
|
||||
|
||||
return view('transactions.mass.edit', compact('transactions', 'subTitle', 'accounts', 'budgets'));
|
||||
return view('transactions.mass.edit', compact('journals', 'subTitle', 'withdrawalSources', 'depositDestinations', 'budgets'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass update of journals.
|
||||
*
|
||||
* @param MassEditJournalRequest $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
*
|
||||
* @return mixed
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function update(MassEditJournalRequest $request, JournalRepositoryInterface $repository)
|
||||
public function update(MassEditJournalRequest $request)
|
||||
{
|
||||
throw new FireflyException('Needs refactor');
|
||||
$journalIds = $request->get('journals');
|
||||
$count = 0;
|
||||
if (is_array($journalIds)) {
|
||||
foreach ($journalIds as $journalId) {
|
||||
$journal = $repository->findNull((int)$journalId);
|
||||
if (null !== $journal) {
|
||||
// get optional fields:
|
||||
$what = strtolower($this->repository->getTransactionType($journal));
|
||||
$sourceAccountId = $request->get('source_id')[$journal->id] ?? null;
|
||||
$currencyId = $request->get('transaction_currency_id')[$journal->id] ?? 1;
|
||||
$sourceAccountName = $request->get('source_name')[$journal->id] ?? null;
|
||||
$destAccountId = $request->get('destination_id')[$journal->id] ?? null;
|
||||
$destAccountName = $request->get('destination_name')[$journal->id] ?? null;
|
||||
$budgetId = (int)($request->get('budget_id')[$journal->id] ?? 0.0);
|
||||
$category = $request->get('category')[$journal->id];
|
||||
$tags = $journal->tags->pluck('tag')->toArray();
|
||||
$amount = round($request->get('amount')[$journal->id], 12);
|
||||
$foreignAmount = isset($request->get('foreign_amount')[$journal->id]) ? round($request->get('foreign_amount')[$journal->id], 12) : null;
|
||||
$foreignCurrencyId = isset($request->get('foreign_currency_id')[$journal->id]) ?
|
||||
(int)$request->get('foreign_currency_id')[$journal->id] : null;
|
||||
// build data array
|
||||
$data = [
|
||||
'id' => $journal->id,
|
||||
'what' => $what,
|
||||
'description' => $request->get('description')[$journal->id],
|
||||
'date' => new Carbon($request->get('date')[$journal->id]),
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
'notes' => $repository->getNoteText($journal),
|
||||
'transactions' => [[
|
||||
|
||||
'category_id' => null,
|
||||
'category_name' => $category,
|
||||
'budget_id' => $budgetId,
|
||||
'budget_name' => null,
|
||||
'source_id' => (int)$sourceAccountId,
|
||||
'source_name' => $sourceAccountName,
|
||||
'destination_id' => (int)$destAccountId,
|
||||
'destination_name' => $destAccountName,
|
||||
'amount' => $amount,
|
||||
'identifier' => 0,
|
||||
'reconciled' => false,
|
||||
'currency_id' => (int)$currencyId,
|
||||
'currency_code' => null,
|
||||
'description' => null,
|
||||
'foreign_amount' => $foreignAmount,
|
||||
'foreign_currency_id' => $foreignCurrencyId,
|
||||
'foreign_currency_code' => null,
|
||||
]],
|
||||
'currency_id' => $foreignCurrencyId,
|
||||
'tags' => $tags,
|
||||
'interest_date' => $journal->interest_date,
|
||||
'book_date' => $journal->book_date,
|
||||
'process_date' => $journal->process_date,
|
||||
|
||||
];
|
||||
// call repository update function.
|
||||
$repository->update($journal, $data);
|
||||
|
||||
// trigger rules
|
||||
event(new UpdatedTransactionGroup($group));
|
||||
|
||||
++$count;
|
||||
}
|
||||
if (!is_array($journalIds)) {
|
||||
// TODO something error.
|
||||
throw new FireflyException('This is not an array.'); // @codeCoverageIgnore
|
||||
}
|
||||
$count = 0;
|
||||
/** @var string $journalId */
|
||||
foreach ($journalIds as $journalId) {
|
||||
$integer = (int)$journalId;
|
||||
try {
|
||||
$this->updateJournal($integer, $request);
|
||||
$count++;
|
||||
} catch (FireflyException $e) { // @codeCoverageIgnore
|
||||
// do something with error.
|
||||
//echo $e->getMessage();
|
||||
//exit;
|
||||
}
|
||||
}
|
||||
|
||||
app('preferences')->mark();
|
||||
session()->flash('success', (string)trans('firefly.mass_edited_transactions_success', ['amount' => $count]));
|
||||
|
||||
@ -261,4 +190,106 @@ class MassController extends Controller
|
||||
return redirect($this->getPreviousUri('transactions.mass-edit.uri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $journalId
|
||||
* @param MassEditJournalRequest $request
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function updateJournal(int $journalId, MassEditJournalRequest $request): void
|
||||
{
|
||||
$journal = $this->repository->findNull($journalId);
|
||||
if (null === $journal) {
|
||||
throw new FireflyException(sprintf('Trying to edit non-existent or deleted journal #%d', $journalId)); // @codeCoverageIgnore
|
||||
}
|
||||
$service = app(JournalUpdateService::class);
|
||||
// for each field, call the update service.
|
||||
$service->setTransactionJournal($journal);
|
||||
|
||||
$data = [
|
||||
'date' => $this->getDateFromRequest($request, $journal->id, 'date'),
|
||||
'description' => $this->getStringFromRequest($request, $journal->id, 'description'),
|
||||
'source_id' => $this->getIntFromRequest($request, $journal->id, 'source_id'),
|
||||
'source_name' => $this->getStringFromRequest($request, $journal->id, 'source_name'),
|
||||
'destination_id' => $this->getIntFromRequest($request, $journal->id, 'destination_id'),
|
||||
'destination_name' => $this->getStringFromRequest($request, $journal->id, 'destination_name'),
|
||||
'budget_id' => $this->getIntFromRequest($request, $journal->id, 'budget_id'),
|
||||
'category_name' => $this->getStringFromRequest($request, $journal->id, 'category'),
|
||||
'amount' => $this->getStringFromRequest($request, $journal->id, 'amount'),
|
||||
'foreign_amount' => $this->getStringFromRequest($request, $journal->id, 'foreign_amount'),
|
||||
];
|
||||
Log::debug(sprintf('Will update journal #%d with data.', $journal->id), $data);
|
||||
|
||||
// call service to update.
|
||||
$service->setData($data);
|
||||
$service->update();
|
||||
// trigger rules
|
||||
event(new UpdatedTransactionGroup($journal->transactionGroup));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MassEditJournalRequest $request
|
||||
* @param int $journalId
|
||||
* @param string $string
|
||||
* @return int|null
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function getIntFromRequest(MassEditJournalRequest $request, int $journalId, string $string): ?int
|
||||
{
|
||||
$value = $request->get($string);
|
||||
if (!is_array($value)) {
|
||||
return null;
|
||||
}
|
||||
if (!isset($value[$journalId])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int)$value[$journalId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MassEditJournalRequest $request
|
||||
* @param int $journalId
|
||||
* @param string $string
|
||||
* @return string|null
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function getStringFromRequest(MassEditJournalRequest $request, int $journalId, string $string): ?string
|
||||
{
|
||||
$value = $request->get($string);
|
||||
if (!is_array($value)) {
|
||||
return null;
|
||||
}
|
||||
if (!isset($value[$journalId])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string)$value[$journalId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MassEditJournalRequest $request
|
||||
* @param int $journalId
|
||||
* @param string $string
|
||||
* @return Carbon|null
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function getDateFromRequest(MassEditJournalRequest $request, int $journalId, string $string): ?Carbon
|
||||
{
|
||||
$value = $request->get($string);
|
||||
if (!is_array($value)) {
|
||||
return null;
|
||||
}
|
||||
if (!isset($value[$journalId])) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$carbon = Carbon::parse($value[$journalId]);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$e->getMessage();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $carbon;
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class ShowController extends Controller
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* ConvertController constructor.
|
||||
* ShowController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@ -81,8 +81,29 @@ class ShowController extends Controller
|
||||
$groupArray = $transformer->transformObject($transactionGroup);
|
||||
|
||||
// do some amount calculations:
|
||||
$amounts = $this->getAmounts($groupArray);
|
||||
|
||||
|
||||
$events = $this->repository->getPiggyEvents($transactionGroup);
|
||||
$attachments = $this->repository->getAttachments($transactionGroup);
|
||||
$links = $this->repository->getLinks($transactionGroup);
|
||||
|
||||
return view(
|
||||
'transactions.show', compact(
|
||||
'transactionGroup', 'amounts', 'first', 'type', 'subTitle', 'splits', 'groupArray',
|
||||
'events', 'attachments', 'links', 'message'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $group
|
||||
* @return array
|
||||
*/
|
||||
private function getAmounts(array $group): array
|
||||
{
|
||||
$amounts = [];
|
||||
foreach ($groupArray['transactions'] as $transaction) {
|
||||
foreach ($group['transactions'] as $transaction) {
|
||||
$symbol = $transaction['currency_symbol'];
|
||||
if (!isset($amounts[$symbol])) {
|
||||
$amounts[$symbol] = [
|
||||
@ -106,15 +127,6 @@ class ShowController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$events = $this->repository->getPiggyEvents($transactionGroup);
|
||||
$attachments = $this->repository->getAttachments($transactionGroup);
|
||||
$links = $this->repository->getLinks($transactionGroup);
|
||||
|
||||
return view(
|
||||
'transactions.show', compact(
|
||||
'transactionGroup', 'amounts', 'first', 'type', 'subTitle', 'splits', 'groupArray',
|
||||
'events', 'attachments', 'links', 'message'
|
||||
)
|
||||
);
|
||||
return $amounts;
|
||||
}
|
||||
}
|
@ -53,6 +53,7 @@ class MassEditJournalRequest extends Request
|
||||
'description.*' => 'required|min:1,max:255',
|
||||
'source_id.*' => 'numeric|belongsToUser:accounts,id',
|
||||
'destination_id.*' => 'numeric|belongsToUser:accounts,id',
|
||||
'journals.*' => 'numeric|belongsToUser:transaction_journals,id',
|
||||
'revenue_account' => 'max:255',
|
||||
'expense_account' => 'max:255',
|
||||
];
|
||||
|
@ -131,7 +131,6 @@ class JournalUpdateService
|
||||
public function update(): void
|
||||
{
|
||||
Log::debug(sprintf('Now in JournalUpdateService for journal #%d.', $this->transactionJournal->id));
|
||||
|
||||
// can we update account data using the new type?
|
||||
if ($this->hasValidAccounts()) {
|
||||
Log::info('-- account info is valid, now update.');
|
||||
@ -142,7 +141,6 @@ class JournalUpdateService
|
||||
$this->updateType();
|
||||
$this->transactionJournal->refresh();
|
||||
}
|
||||
|
||||
// find and update bill, if possible.
|
||||
$this->updateBill();
|
||||
|
||||
@ -276,6 +274,7 @@ class JournalUpdateService
|
||||
if (null === $this->sourceTransaction) {
|
||||
$this->sourceTransaction = $this->transactionJournal->transactions()->with(['account'])->where('amount', '<', 0)->first();
|
||||
}
|
||||
Log::debug(sprintf('getSourceTransaction: %s', $this->sourceTransaction->amount));
|
||||
|
||||
return $this->sourceTransaction;
|
||||
}
|
||||
@ -447,9 +446,14 @@ class JournalUpdateService
|
||||
$sourceTransaction->account()->associate($source);
|
||||
$sourceTransaction->save();
|
||||
|
||||
$destinationTransaction = $this->getDestinationTransaction();
|
||||
$destinationTransaction->account()->associate($destination);
|
||||
$destinationTransaction->save();
|
||||
$destTransaction = $this->getDestinationTransaction();
|
||||
$destTransaction->account()->associate($destination);
|
||||
$destTransaction->save();
|
||||
|
||||
// refresh transactions.
|
||||
$this->sourceTransaction->refresh();
|
||||
$this->destinationTransaction->refresh();
|
||||
|
||||
|
||||
Log::debug(sprintf('Will set source to #%d ("%s")', $source->id, $source->name));
|
||||
Log::debug(sprintf('Will set dest to #%d ("%s")', $destination->id, $destination->name));
|
||||
@ -468,14 +472,20 @@ class JournalUpdateService
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug(sprintf('Updated amount to %s', $amount));
|
||||
$sourceTransaction = $this->getSourceTransaction();
|
||||
$sourceTransaction->amount = app('steam')->negative($value);
|
||||
$sourceTransaction->amount = app('steam')->negative($amount);
|
||||
$sourceTransaction->save();
|
||||
|
||||
$destinationTransaction = $this->getDestinationTransaction();
|
||||
$destinationTransaction->amount = app('steam')->positive($value);
|
||||
$destinationTransaction->save();
|
||||
|
||||
$destTransaction = $this->getDestinationTransaction();
|
||||
$destTransaction->amount = app('steam')->positive($amount);
|
||||
$destTransaction->save();
|
||||
|
||||
|
||||
// refresh transactions.
|
||||
$this->sourceTransaction->refresh();
|
||||
$this->destinationTransaction->refresh();
|
||||
Log::debug(sprintf('Updated amount to "%s"', $amount));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -518,6 +528,10 @@ class JournalUpdateService
|
||||
$dest = $this->getDestinationTransaction();
|
||||
$dest->transaction_currency_id = $currency->id;
|
||||
$dest->save();
|
||||
|
||||
// refresh transactions.
|
||||
$this->sourceTransaction->refresh();
|
||||
$this->destinationTransaction->refresh();
|
||||
Log::debug(sprintf('Updated currency to #%d (%s)', $currency->id, $currency->code));
|
||||
}
|
||||
}
|
||||
@ -572,6 +586,10 @@ class JournalUpdateService
|
||||
|
||||
Log::debug(sprintf('Update foreign info to %s (#%d) %s', $foreignCurrency->code, $foreignCurrency->id, $foreignAmount));
|
||||
|
||||
// refresh transactions.
|
||||
$this->sourceTransaction->refresh();
|
||||
$this->destinationTransaction->refresh();
|
||||
|
||||
return;
|
||||
}
|
||||
if ('0' === $amount) {
|
||||
@ -585,6 +603,10 @@ class JournalUpdateService
|
||||
Log::debug(sprintf('Foreign amount is "%s" so remove foreign amount info.', $amount));
|
||||
}
|
||||
Log::info('Not enough info to update foreign currency info.');
|
||||
|
||||
// refresh transactions.
|
||||
$this->sourceTransaction->refresh();
|
||||
$this->destinationTransaction->refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,8 +22,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Binder;
|
||||
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Routing\Route;
|
||||
use Illuminate\Support\Collection;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
@ -38,24 +39,38 @@ class JournalList implements BinderInterface
|
||||
* @return mixed
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value, Route $route): Collection
|
||||
public static function routeBinder(string $value, Route $route): array
|
||||
{
|
||||
if (auth()->check()) {
|
||||
$list = array_unique(array_map('\intval', explode(',', $value)));
|
||||
if (0 === count($list)) {
|
||||
throw new NotFoundHttpException; // @codeCoverageIgnore
|
||||
$list = self::parseList($value);
|
||||
|
||||
// get the journals by using the collector.
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$collector->withCategoryInformation()->withBudgetInformation()->withTagInformation()->withAccountInformation();
|
||||
$collector->setJournalIds($list);
|
||||
$result = $collector->getExtractedJournals();
|
||||
if (0 === count($result)) {
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Support\Collection $collection */
|
||||
$collection = auth()->user()->transactionJournals()
|
||||
->whereIn('transaction_journals.id', $list)
|
||||
->where('transaction_journals.completed', 1)
|
||||
->get(['transaction_journals.*']);
|
||||
|
||||
if ($collection->count() > 0) {
|
||||
return $collection;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
protected static function parseList(string $value): array
|
||||
{
|
||||
$list = array_unique(array_map('\intval', explode(',', $value)));
|
||||
if (0 === count($list)) {
|
||||
throw new NotFoundHttpException; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
|
@ -1,78 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* SimpleJournalList.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Binder;
|
||||
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Routing\Route;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Class SimpleJournalList
|
||||
*/
|
||||
class SimpleJournalList implements BinderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @param Route $route
|
||||
*
|
||||
* @return mixed
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value, Route $route): array
|
||||
{
|
||||
if (auth()->check()) {
|
||||
$list = self::parseList($value);
|
||||
|
||||
// get the journals by using the collector.
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$collector->withCategoryInformation()->withBudgetInformation()->withTagInformation();
|
||||
$collector->setJournalIds($list);
|
||||
$result = $collector->getExtractedJournals();
|
||||
if (0 === count($result)) {
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
protected static function parseList(string $value): array
|
||||
{
|
||||
$list = array_unique(array_map('\intval', explode(',', $value)));
|
||||
if (0 === count($list)) {
|
||||
throw new NotFoundHttpException; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
@ -58,7 +58,6 @@ use FireflyIII\Support\Binder\CurrencyCode;
|
||||
use FireflyIII\Support\Binder\Date;
|
||||
use FireflyIII\Support\Binder\ImportProvider;
|
||||
use FireflyIII\Support\Binder\JournalList;
|
||||
use FireflyIII\Support\Binder\SimpleJournalList;
|
||||
use FireflyIII\Support\Binder\TagList;
|
||||
use FireflyIII\Support\Binder\TagOrId;
|
||||
use FireflyIII\Support\Binder\UnfinishedJournal;
|
||||
@ -398,7 +397,6 @@ return [
|
||||
'journalList' => JournalList::class,
|
||||
'categoryList' => CategoryList::class,
|
||||
'tagList' => TagList::class,
|
||||
'simpleJournalList' => SimpleJournalList::class,
|
||||
|
||||
// others
|
||||
'fromCurrencyCode' => CurrencyCode::class,
|
||||
|
40
public/v1/js/ff/transactions/mass/edit.js
vendored
40
public/v1/js/ff/transactions/mass/edit.js
vendored
@ -18,22 +18,20 @@
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** global: what */
|
||||
|
||||
$(document).ready(function () {
|
||||
"use strict";
|
||||
|
||||
// description
|
||||
if ($('input[name^="description["]').length > 0) {
|
||||
console.log('descr');
|
||||
console.log('Description.');
|
||||
var journalNames = new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
prefetch: {
|
||||
url: 'json/transaction-journals/all?uid=' + uid,
|
||||
filter: function (list) {
|
||||
return $.map(list, function (name) {
|
||||
return {name: name};
|
||||
return $.map(list, function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -41,8 +39,8 @@ $(document).ready(function () {
|
||||
url: 'json/transaction-journals/all?search=%QUERY&uid=' + uid,
|
||||
wildcard: '%QUERY',
|
||||
filter: function (list) {
|
||||
return $.map(list, function (name) {
|
||||
return {name: name};
|
||||
return $.map(list, function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -52,15 +50,15 @@ $(document).ready(function () {
|
||||
}
|
||||
// destination account names:
|
||||
if ($('input[name^="destination_name["]').length > 0) {
|
||||
|
||||
console.log('Destination.');
|
||||
var destNames = new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
prefetch: {
|
||||
url: 'json/expense-accounts?uid=' + uid,
|
||||
filter: function (list) {
|
||||
return $.map(list, function (name) {
|
||||
return {name: name};
|
||||
return $.map(list, function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -68,8 +66,8 @@ $(document).ready(function () {
|
||||
url: 'json/expense-accounts?search=%QUERY&uid=' + uid,
|
||||
wildcard: '%QUERY',
|
||||
filter: function (list) {
|
||||
return $.map(list, function (name) {
|
||||
return {name: name};
|
||||
return $.map(list, function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -80,15 +78,15 @@ $(document).ready(function () {
|
||||
|
||||
// source account name
|
||||
if ($('input[name^="source_name["]').length > 0) {
|
||||
|
||||
console.log('Source.');
|
||||
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 (name) {
|
||||
return {name: name};
|
||||
return $.map(list, function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -96,8 +94,8 @@ $(document).ready(function () {
|
||||
url: 'json/revenue-accounts?search=%QUERY&uid=' + uid,
|
||||
wildcard: '%QUERY',
|
||||
filter: function (list) {
|
||||
return $.map(list, function (name) {
|
||||
return {name: name};
|
||||
return $.map(list, function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -113,8 +111,8 @@ $(document).ready(function () {
|
||||
prefetch: {
|
||||
url: 'json/categories?uid=' + uid,
|
||||
filter: function (list) {
|
||||
return $.map(list, function (name) {
|
||||
return {name: name};
|
||||
return $.map(list, function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -122,8 +120,8 @@ $(document).ready(function () {
|
||||
url: 'json/categories?search=%QUERY&uid=' + uid,
|
||||
wildcard: '%QUERY',
|
||||
filter: function (list) {
|
||||
return $.map(list, function (name) {
|
||||
return {name: name};
|
||||
return $.map(list, function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -851,7 +851,7 @@ return [
|
||||
'cannot_edit_other_fields' => 'You cannot mass-edit other fields than the ones here, because there is no room to show them. Please follow the link and edit them by one-by-one, if you need to edit these fields.',
|
||||
'no_budget' => '(no budget)',
|
||||
'no_budget_squared' => '(no budget)',
|
||||
'perm-delete-many' => 'Deleting many items in one go can be very disruptive. Please be cautious.',
|
||||
'perm-delete-many' => 'Deleting many items in one go can be very disruptive. Please be cautious. You can delete part of a split transaction from this page, so take care.',
|
||||
'mass_deleted_transactions_success' => 'Deleted :amount transaction(s).',
|
||||
'mass_edited_transactions_success' => 'Updated :amount transaction(s)',
|
||||
'opt_group_' => '(no account type)',
|
||||
|
@ -23,64 +23,65 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'buttons' => 'Buttons',
|
||||
'icon' => 'Icon',
|
||||
'id' => 'ID',
|
||||
'create_date' => 'Created at',
|
||||
'update_date' => 'Updated at',
|
||||
'updated_at' => 'Updated at',
|
||||
'balance_before' => 'Balance before',
|
||||
'balance_after' => 'Balance after',
|
||||
'name' => 'Name',
|
||||
'role' => 'Role',
|
||||
'currentBalance' => 'Current balance',
|
||||
'linked_to_rules' => 'Relevant rules',
|
||||
'active' => 'Is active?',
|
||||
'lastActivity' => 'Last activity',
|
||||
'balanceDiff' => 'Balance difference',
|
||||
'matchesOn' => 'Matched on',
|
||||
'account_type' => 'Account type',
|
||||
'created_at' => 'Created at',
|
||||
'account' => 'Account',
|
||||
'matchingAmount' => 'Amount',
|
||||
'split_number' => 'Split #',
|
||||
'destination' => 'Destination',
|
||||
'source' => 'Source',
|
||||
'next_expected_match' => 'Next expected match',
|
||||
'automatch' => 'Auto match?',
|
||||
'repeat_freq' => 'Repeats',
|
||||
'description' => 'Description',
|
||||
'amount' => 'Amount',
|
||||
'internal_reference' => 'Internal reference',
|
||||
'date' => 'Date',
|
||||
'interest_date' => 'Interest date',
|
||||
'book_date' => 'Book date',
|
||||
'process_date' => 'Processing date',
|
||||
'due_date' => 'Due date',
|
||||
'payment_date' => 'Payment date',
|
||||
'invoice_date' => 'Invoice date',
|
||||
'interal_reference' => 'Internal reference',
|
||||
'notes' => 'Notes',
|
||||
'from' => 'From',
|
||||
'piggy_bank' => 'Piggy bank',
|
||||
'to' => 'To',
|
||||
'budget' => 'Budget',
|
||||
'category' => 'Category',
|
||||
'bill' => 'Bill',
|
||||
'withdrawal' => 'Withdrawal',
|
||||
'deposit' => 'Deposit',
|
||||
'transfer' => 'Transfer',
|
||||
'type' => 'Type',
|
||||
'completed' => 'Completed',
|
||||
'iban' => 'IBAN',
|
||||
'paid_current_period' => 'Paid this period',
|
||||
'email' => 'Email',
|
||||
'registered_at' => 'Registered at',
|
||||
'is_blocked' => 'Is blocked',
|
||||
'is_admin' => 'Is admin',
|
||||
'has_two_factor' => 'Has 2FA',
|
||||
'blocked_code' => 'Block code',
|
||||
'source_account' => 'Source account',
|
||||
'buttons' => 'Buttons',
|
||||
'icon' => 'Icon',
|
||||
'id' => 'ID',
|
||||
'create_date' => 'Created at',
|
||||
'update_date' => 'Updated at',
|
||||
'updated_at' => 'Updated at',
|
||||
'balance_before' => 'Balance before',
|
||||
'balance_after' => 'Balance after',
|
||||
'name' => 'Name',
|
||||
'role' => 'Role',
|
||||
'currentBalance' => 'Current balance',
|
||||
'linked_to_rules' => 'Relevant rules',
|
||||
'active' => 'Is active?',
|
||||
'transaction_type' => 'Type',
|
||||
'lastActivity' => 'Last activity',
|
||||
'balanceDiff' => 'Balance difference',
|
||||
'matchesOn' => 'Matched on',
|
||||
'account_type' => 'Account type',
|
||||
'created_at' => 'Created at',
|
||||
'account' => 'Account',
|
||||
'matchingAmount' => 'Amount',
|
||||
'split_number' => 'Split #',
|
||||
'destination' => 'Destination',
|
||||
'source' => 'Source',
|
||||
'next_expected_match' => 'Next expected match',
|
||||
'automatch' => 'Auto match?',
|
||||
'repeat_freq' => 'Repeats',
|
||||
'description' => 'Description',
|
||||
'amount' => 'Amount',
|
||||
'internal_reference' => 'Internal reference',
|
||||
'date' => 'Date',
|
||||
'interest_date' => 'Interest date',
|
||||
'book_date' => 'Book date',
|
||||
'process_date' => 'Processing date',
|
||||
'due_date' => 'Due date',
|
||||
'payment_date' => 'Payment date',
|
||||
'invoice_date' => 'Invoice date',
|
||||
'interal_reference' => 'Internal reference',
|
||||
'notes' => 'Notes',
|
||||
'from' => 'From',
|
||||
'piggy_bank' => 'Piggy bank',
|
||||
'to' => 'To',
|
||||
'budget' => 'Budget',
|
||||
'category' => 'Category',
|
||||
'bill' => 'Bill',
|
||||
'withdrawal' => 'Withdrawal',
|
||||
'deposit' => 'Deposit',
|
||||
'transfer' => 'Transfer',
|
||||
'type' => 'Type',
|
||||
'completed' => 'Completed',
|
||||
'iban' => 'IBAN',
|
||||
'paid_current_period' => 'Paid this period',
|
||||
'email' => 'Email',
|
||||
'registered_at' => 'Registered at',
|
||||
'is_blocked' => 'Is blocked',
|
||||
'is_admin' => 'Is admin',
|
||||
'has_two_factor' => 'Has 2FA',
|
||||
'blocked_code' => 'Block code',
|
||||
'source_account' => 'Source account',
|
||||
'destination_account' => 'Destination account',
|
||||
'accounts_count' => 'Number of accounts',
|
||||
'journals_count' => 'Number of transactions',
|
||||
|
@ -19,7 +19,6 @@
|
||||
{{ trans('form.permDeleteWarning') }}
|
||||
{{ 'perm-delete-many'|_ }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ trans('form.mass_journal_are_you_sure') }}
|
||||
{{ trans('form.mass_make_selection') }}
|
||||
@ -28,8 +27,9 @@
|
||||
<table class="table table-striped table-condensed">
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>{{ trans('list.transaction_type') }}</th>
|
||||
<th>{{ trans('list.description') }}</th>
|
||||
<th>{{ trans('list.total_amount') }}</th>
|
||||
<th>{{ trans('list.amount') }}</th>
|
||||
<th class="hidden-sm hidden-xs">{{ trans('list.date') }}</th>
|
||||
<th class="hidden-xs">{{ trans('list.from') }}</th>
|
||||
<th class="hidden-xs">{{ trans('list.to') }}</th>
|
||||
@ -37,22 +37,61 @@
|
||||
{% for journal in journals %}
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" name="confirm_mass_delete[]" value="{{ journal.id }}" checked/>
|
||||
<input type="checkbox" name="confirm_mass_delete[]" value="{{ journal.transaction_journal_id }}" checked/>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('transactions.show',journal.id) }}" title="{{ journal.description }}">{{ journal.description }}</a>
|
||||
{% if journal.transaction_type_type == 'Withdrawal' %}
|
||||
<i class="fa fa-long-arrow-left fa-fw" title="{{ trans('firefly.Withdrawal') }}"></i>
|
||||
{% endif %}
|
||||
|
||||
{% if journal.transaction_type_type == 'Deposit' %}
|
||||
<i class="fa fa-long-arrow-right fa-fw" title="{{ trans('firefly.Deposit') }}"></i>
|
||||
{% endif %}
|
||||
|
||||
{% if journal.transaction_type_type == 'Transfer' %}
|
||||
<i class="fa fa-exchange fa-fw" title="{{ trans('firefly.Deposit') }}"></i>
|
||||
{% endif %}
|
||||
|
||||
{% if journal.transaction_type_type == 'Reconciliation' %}
|
||||
<i class="fa-fw fa fa-calculator" title="{{ trans('firefly.reconciliation_transaction') }}"></i>
|
||||
{% endif %}
|
||||
{% if journal.transaction_type_type == 'Opening balance' %}
|
||||
<i class="fa-fw fa fa-star-o" title="{{ trans('firefly.Opening balance') }}"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ journal|journalTotalAmount }}
|
||||
<a href="{{ route('transactions.show',journal.transaction_journal_id) }}"
|
||||
title="{{ journal.description }}">{{ journal.description }}</a>
|
||||
</td>
|
||||
<td>
|
||||
{% if journal.transaction_type_type == 'Deposit' %}
|
||||
{{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_symbol_decimal_places) }}
|
||||
{% if null != journal.foreign_amount %}
|
||||
({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_symbol_decimal_places) }})
|
||||
{% endif %}
|
||||
{% elseif journal.transaction_type_type == 'Transfer' %}
|
||||
<span class="text-info">{{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_symbol_decimal_places, false) }}
|
||||
{% if null != journal.foreign_amount %}
|
||||
({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_symbol_decimal_places, false) }})
|
||||
{% endif %}
|
||||
</span>
|
||||
{% else %}
|
||||
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_symbol_decimal_places) }}
|
||||
{% if null != journal.foreign_amount %}
|
||||
({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_symbol_decimal_places) }})
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ journal.date.formatLocalized(monthAndDayFormat) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ sourceAccount(journal)|raw }}
|
||||
<a href="{{ route('accounts.show', [journal.source_account_id]) }}"
|
||||
title="{{ journal.source_account_iban|default(journal.source_account_name) }}">{{ journal.source_account_name }}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ destinationXAccount(journal)|raw }}
|
||||
<a href="{{ route('accounts.show', [journal.destination_account_id]) }}"
|
||||
title="{{ journal.destination_account_iban|default(journal.destination_account_name) }}">{{ journal.destination_account_name }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, transactions) }}
|
||||
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, journals) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@ -29,91 +29,107 @@
|
||||
<th class="col-lg-2 col-md-2 col-sm-2">{{ trans('list.category') }}</th>
|
||||
<th class="col-lg-2 col-md-2 col-sm-2">{{ trans('list.budget') }}</th>
|
||||
</tr>
|
||||
{% for transaction in transactions %}
|
||||
{% for journal in journals %}
|
||||
<tr>
|
||||
<td>
|
||||
{# LINK TO EDIT FORM #}
|
||||
<a href="{{ route('transactions.edit', transaction.journal_id) }}" class="btn btn-xs btn-default"><i
|
||||
<a href="{{ route('transactions.edit', journal.transaction_group_id) }}" class="btn btn-xs btn-default"><i
|
||||
class="fa fa-fw fa-pencil"></i></a>
|
||||
<input type="hidden" name="journals[]" value="{{ transaction.journal_id }}"/>
|
||||
<input type="hidden" name="journals[]" value="{{ journal.transaction_journal_id }}"/>
|
||||
</td>
|
||||
<td>
|
||||
{# DESCRIPTION #}
|
||||
<input class="form-control input-sm" autocomplete="off"
|
||||
placeholder="{{ transaction.description }}" name="description[{{ transaction.journal_id }}]"
|
||||
type="text" value="{{ transaction.description }}">
|
||||
placeholder="{{ journal.description }}" name="description[{{ journal.transaction_journal_id }}]"
|
||||
type="text" value="{{ journal.description }}">
|
||||
</td>
|
||||
{# AMOUNT #}
|
||||
<td>
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon">{{ transaction.currency_symbol }}</span>
|
||||
<input name="amount[{{ transaction.journal_id }}]" class="form-control" autocomplete="off"
|
||||
step="any" type="number" value="{{ transaction.amount }}">
|
||||
<input type="hidden" name="transaction_currency_id[{{ transaction.journal_id }}]"
|
||||
value="{{ transaction.currency_id }}">
|
||||
|
||||
|
||||
<span class="input-group-addon">{{ journal.currency_symbol }}</span>
|
||||
<input name="amount[{{ journal.transaction_journal_id }}]" class="form-control" autocomplete="off"
|
||||
step="any" type="number" value="{{ journal.amount }}">
|
||||
<input type="hidden" name="transaction_currency_id[{{ journal.transaction_journal_id }}]"
|
||||
value="{{ journal.currency_id }}">
|
||||
</div>
|
||||
{% if transaction.foreign_amount %}
|
||||
{% if journal.foreign_amount %}
|
||||
{# insert foreign data #}
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon">{{ transaction.foreign_currency_symbol }}</span>
|
||||
<input name="foreign_amount[{{ transaction.journal_id }}]" class="form-control" autocomplete="off"
|
||||
step="any" type="number" value="{{ transaction.foreign_amount }}">
|
||||
<input type="hidden" name="foreign_currency_id[{{ transaction.journal_id }}]" value="{{ transaction.foreign_currency_id }}">
|
||||
<span class="input-group-addon">{{ journal.foreign_currency_symbol }}</span>
|
||||
<input name="foreign_amount[{{ journal.transaction_journal_id }}]" class="form-control" autocomplete="off"
|
||||
step="any" type="number" value="{{ journal.foreign_amount }}">
|
||||
<input type="hidden" name="foreign_currency_id[{{ journal.transaction_journal_id }}]"
|
||||
value="{{ journal.foreign_currency_id }}">
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{# DATE #}
|
||||
<input class="form-control input-sm" autocomplete="off"
|
||||
name="date[{{ transaction.journal_id }}]" type="date" value="{{ transaction.date|slice(0,10) }}">
|
||||
name="date[{{ journal.transaction_journal_id }}]" type="date" value="{{ journal.date|slice(0,10) }}">
|
||||
</td>
|
||||
<!-- {{ journal.transaction_type_type }} -->
|
||||
<!-- Source: {{ journal.source_account_name }} ({{ journal.source_account_id }}) -->
|
||||
<!-- Destination: {{ journal.destination_account_name }} ({{ journal.destination_account_id }}) -->
|
||||
<td style="position: relative;">
|
||||
|
||||
{# SOURCE ACCOUNT ID FOR TRANSFER OR WITHDRAWAL #}
|
||||
{% if transaction.type == 'Transfer' or transaction.type == 'Withdrawal' %}
|
||||
<select class="form-control input-sm" name="source_id[{{ transaction.journal_id }}]">
|
||||
{% for account in accounts %}
|
||||
<!-- {{ transaction.type }}: {{ transaction.source_name }} -->
|
||||
<option value="{{ account.id }}"{% if account.id == transaction.source_id %} selected{% endif %} label="{{ account.name }}">{{ account.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
{# SOURCE ACCOUNT NAME FOR DEPOSIT #}
|
||||
<input class="form-control input-sm" placeholder="{% if transaction.source_type != 'Cash account' %}{{ transaction.source_name }}{% endif %}" autocomplete="off"
|
||||
name="source_name[{{ transaction.journal_id }}]" type="text" value="{% if transaction.source_type != 'Cash account' %}{{ transaction.source_name }}{% endif %}">
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="position: relative;">
|
||||
{% if transaction.type == 'Transfer' or transaction.type == 'Deposit' %}
|
||||
{# DESTINATION ACCOUNT NAME FOR TRANSFER AND DEPOSIT #}
|
||||
<select class="form-control input-sm" name="destination_id[{{ transaction.journal_id }}]">
|
||||
{% for account in accounts %}
|
||||
<option value="{{ account.id }}"{% if account.id == transaction.destination_id %} selected="selected"{% endif %}
|
||||
{% if journal.transaction_type_type == 'Transfer' or journal.transaction_type_type == 'Withdrawal' %}
|
||||
<select class="form-control input-sm" name="source_id[{{ journal.transaction_journal_id }}]">
|
||||
{% for account in withdrawalSources %}
|
||||
<option value="{{ account.id }}"{% if account.id == journal.source_account_id %} selected{% endif %}
|
||||
label="{{ account.name }}">{{ account.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
{% endif %}
|
||||
|
||||
{# DESTINATION ACCOUNT NAME FOR EXPENSE #}
|
||||
<input class="form-control input-sm" placeholder="{% if transaction.destination_type != 'Cash account' %}{{ transaction.destination_name }}{% endif %}"
|
||||
name="destination_name[{{ transaction.journal_id }}]" type="text" autocomplete="off"
|
||||
value="{% if transaction.destination_type != 'Cash account' %}{{ transaction.destination_name }}{% endif %}">
|
||||
{# SOURCE ACCOUNT NAME FOR DEPOSIT #}
|
||||
{% if journal.transaction_type_type == 'Deposit' %}
|
||||
<input class="form-control input-sm"
|
||||
placeholder="{% if journal.source_type != 'Cash account' %}{{ journal.source_account_name }}{% endif %}"
|
||||
autocomplete="off"
|
||||
name="source_name[{{ journal.transaction_journal_id }}]" type="text"
|
||||
value="{% if journal.source_type != 'Cash account' %}{{ journal.source_account_name }}{% endif %}">
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="position: relative;">
|
||||
|
||||
{# DESTINATION ACCOUNT NAME FOR TRANSFER AND DEPOSIT #}
|
||||
{% if journal.transaction_type_type == 'Transfer' or journal.transaction_type_type == 'Deposit' %}
|
||||
|
||||
<select class="form-control input-sm" name="destination_id[{{ journal.transaction_journal_id }}]">
|
||||
{% for account in depositDestinations %}
|
||||
<option value="{{ account.id }}"{% if account.id == journal.destination_account_id %} selected="selected"{% endif %}
|
||||
label="{{ account.name }}">{{ account.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% endif %}
|
||||
|
||||
{# DESTINATION ACCOUNT NAME FOR WITHDRAWAL #}
|
||||
{% if journal.transaction_type_type == 'Withdrawal' %}
|
||||
<input class="form-control input-sm"
|
||||
placeholder="{% if journal.destination_type != 'Cash account' %}{{ journal.destination_account_name }}{% endif %}"
|
||||
name="destination_name[{{ journal.transaction_journal_id }}]" type="text" autocomplete="off"
|
||||
value="{% if journal.destination_type != 'Cash account' %}{{ journal.destination_account_name }}{% endif %}">
|
||||
{% endif %}
|
||||
</td>
|
||||
{# category #}
|
||||
<td style="position: relative;">
|
||||
<input class="form-control input-sm" placeholder="{{ transaction.category_name }}" autocomplete="off"
|
||||
name="category[{{ transaction.journal_id }}]" type="text" value="{{ transaction.category_name }}">
|
||||
<input class="form-control input-sm" placeholder="{{ journal.category_name }}" autocomplete="off"
|
||||
name="category[{{ journal.transaction_journal_id }}]" type="text" value="{{ journal.category_name }}">
|
||||
</td>
|
||||
{# budget #}
|
||||
<td>
|
||||
{% if transaction.type == 'Withdrawal' %}
|
||||
<select class="form-control input-sm" name="budget_id[{{ transaction.journal_id }}]">
|
||||
{% if journal.transaction_type_type == 'Withdrawal' %}
|
||||
<select class="form-control input-sm" name="budget_id[{{ journal.transaction_journal_id }}]">
|
||||
<option value="0" label="({{ 'no_budget'|_ }})"
|
||||
{% if transaction.budget_id == 0 %}selected="selected"{% endif %}
|
||||
{% if journal.budget_id == 0 %}selected="selected"{% endif %}
|
||||
>({{ 'no_budget'|_ }})
|
||||
</option>
|
||||
{% for budget in budgets %}
|
||||
<option value="{{ budget.id }}"{% if budget.id == transaction.budget_id %} selected="selected"{% endif %}
|
||||
<option value="{{ budget.id }}"{% if budget.id == journal.budget_id %} selected="selected"{% endif %}
|
||||
label="{{ budget.name }}">{{ budget.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
@ -41,7 +41,6 @@ use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionJournalLink;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -1096,12 +1095,11 @@ try {
|
||||
// MASS TRANSACTION EDIT / DELETE
|
||||
Breadcrumbs::register(
|
||||
'transactions.mass.edit',
|
||||
function (BreadcrumbsGenerator $breadcrumbs, Collection $journals): void {
|
||||
if (\count($journals) > 0) {
|
||||
$journalIds = $journals->pluck('id')->toArray();
|
||||
$what = strtolower($journals->first()['type']);
|
||||
$breadcrumbs->parent('transactions.index', $what);
|
||||
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.edit', $journalIds));
|
||||
static function (BreadcrumbsGenerator $breadcrumbs, array $journals): void {
|
||||
if (count($journals) > 0) {
|
||||
$objectType = strtolower(reset($journals)['transaction_type_type']);
|
||||
$breadcrumbs->parent('transactions.index', $objectType);
|
||||
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.edit', ['']));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1111,11 +1109,10 @@ try {
|
||||
|
||||
Breadcrumbs::register(
|
||||
'transactions.mass.delete',
|
||||
function (BreadcrumbsGenerator $breadcrumbs, Collection $journals) {
|
||||
$journalIds = $journals->pluck('id')->toArray();
|
||||
$what = strtolower($journals->first()->transactionType->type);
|
||||
$breadcrumbs->parent('transactions.index', $what);
|
||||
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.delete', $journalIds));
|
||||
static function (BreadcrumbsGenerator $breadcrumbs, array $journals) {
|
||||
$objectType= strtolower(reset($journals)['transaction_type_type']);
|
||||
$breadcrumbs->parent('transactions.index', $objectType);
|
||||
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.delete', ['']));
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -922,7 +922,7 @@ Route::group(
|
||||
Route::group(
|
||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/mass', 'as' => 'transactions.mass.'],
|
||||
function () {
|
||||
Route::get('edit/{simpleJournalList}', ['uses' => 'MassController@edit', 'as' => 'edit']);
|
||||
Route::get('edit/{journalList}', ['uses' => 'MassController@edit', 'as' => 'edit']);
|
||||
Route::get('delete/{journalList}', ['uses' => 'MassController@delete', 'as' => 'delete']);
|
||||
Route::post('update', ['uses' => 'MassController@update', 'as' => 'update']);
|
||||
Route::post('destroy', ['uses' => 'MassController@destroy', 'as' => 'destroy']);
|
||||
@ -935,7 +935,7 @@ Route::group(
|
||||
Route::group(
|
||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/bulk', 'as' => 'transactions.bulk.'],
|
||||
function () {
|
||||
Route::get('edit/{simpleJournalList}', ['uses' => 'BulkController@edit', 'as' => 'edit']);
|
||||
Route::get('edit/{journalList}', ['uses' => 'BulkController@edit', 'as' => 'edit']);
|
||||
Route::post('update', ['uses' => 'BulkController@update', 'as' => 'update']);
|
||||
}
|
||||
);
|
||||
|
@ -23,17 +23,18 @@ declare(strict_types=1);
|
||||
namespace Tests\Feature\Controllers\Transaction;
|
||||
|
||||
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Amount;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Transformers\TransactionTransformer;
|
||||
use FireflyIII\Services\Internal\Update\JournalUpdateService;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Mockery;
|
||||
use Preferences;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
@ -56,26 +57,32 @@ class MassControllerTest extends TestCase
|
||||
|
||||
|
||||
/**
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\MassController
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\MassController
|
||||
*/
|
||||
public function testDelete(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$this->mockDefaultSession();
|
||||
$withdrawal = $this->getRandomWithdrawal();
|
||||
$withdrawalArray = $this->getRandomWithdrawalAsArray();
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->atLeast()->once()->andReturn(true);
|
||||
|
||||
$journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal);
|
||||
$journalRepos->shouldReceive('getJournalSourceAccounts')->andReturn(new Collection)->once();
|
||||
$journalRepos->shouldReceive('getJournalDestinationAccounts')->andReturn(new Collection)->once();
|
||||
$collector = $this->mock(GroupCollectorInterface::class);
|
||||
$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('withAccountInformation')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('setJournalIds')->withArgs([[$withdrawal->id]])->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('getExtractedJournals')->atLeast()->once()->andReturn([$withdrawalArray]);
|
||||
|
||||
Amount::shouldReceive('formatAnything')->atLeast()->once()->andReturn('x');
|
||||
|
||||
$withdrawals = TransactionJournal::where('transaction_type_id', 1)->where('user_id', $this->user()->id)->take(2)->get()->pluck('id')->toArray();
|
||||
$this->be($this->user());
|
||||
$response = $this->get(route('transactions.mass.delete', $withdrawals));
|
||||
$response = $this->get(route('transactions.mass.delete', [$withdrawal->id]));
|
||||
$response->assertStatus(200);
|
||||
$response->assertSee('Delete a number of transactions');
|
||||
// has bread crumb
|
||||
@ -87,26 +94,16 @@ class MassControllerTest extends TestCase
|
||||
*/
|
||||
public function testDestroy(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
$repository = $this->mockDefaultSession();
|
||||
$deposit = $this->getRandomDeposit();
|
||||
|
||||
return;
|
||||
|
||||
$deposits = TransactionJournal::where('transaction_type_id', 2)->where('user_id', $this->user()->id)->take(2)->get();
|
||||
$depositIds = $deposits->pluck('id')->toArray();
|
||||
|
||||
// mock deletion:
|
||||
$repository = $this->mock(JournalRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
|
||||
$repository->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal);
|
||||
$repository->shouldReceive('findNull')->andReturnValues([$deposits[0], $deposits[1]])->times(2);
|
||||
$repository->shouldReceive('destroy')->times(2);
|
||||
$repository->shouldReceive('findNull')->atLeast()->once()->andReturn($deposit);
|
||||
$repository->shouldReceive('destroyJournal')->atLeast()->once();
|
||||
Preferences::shouldReceive('mark')->atLeast()->once();
|
||||
|
||||
$this->session(['transactions.mass-delete.uri' => 'http://localhost']);
|
||||
|
||||
$data = [
|
||||
'confirm_mass_delete' => $depositIds,
|
||||
];
|
||||
$data = ['confirm_mass_delete' => [$deposit->id],];
|
||||
$this->be($this->user());
|
||||
$response = $this->post(route('transactions.mass.destroy'), $data);
|
||||
$response->assertSessionHas('success');
|
||||
@ -118,161 +115,59 @@ class MassControllerTest extends TestCase
|
||||
*/
|
||||
public function testEdit(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
$withdrawal = $this->getRandomWithdrawal();
|
||||
$withdrawalArray = $this->getRandomWithdrawalAsArray();
|
||||
$asset = $this->getRandomAsset();
|
||||
$budget = $this->getRandomBudget();
|
||||
|
||||
return;
|
||||
// mock things
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$journalRepos = $this->mockDefaultSession();
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$transformer = $this->mock(TransactionTransformer::class);
|
||||
$collector = $this->mock(TransactionCollectorInterface::class);
|
||||
|
||||
// data:
|
||||
$transfers = TransactionJournal::where('transaction_type_id', 3)->where('user_id', $this->user()->id)->take(2)->get();
|
||||
$transfersArray = $transfers->pluck('id')->toArray();
|
||||
$source = $this->user()->accounts()->first();
|
||||
|
||||
$transaction = new Transaction;
|
||||
|
||||
// mock calls:
|
||||
$transformer->shouldReceive('setParameters')->atLeast()->once();
|
||||
$transformer->shouldReceive('transform')->atLeast()->once()->andReturn(
|
||||
[
|
||||
'amount' => '10',
|
||||
'foreign_amount' => '',
|
||||
'type' => 'transfer',
|
||||
'id' => 3,
|
||||
'journal_id' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$collector->shouldReceive('setUser')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('withOpposingAccount')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('withCategoryInformation')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('withBudgetInformation')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('setJournals')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('addFilter')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('getTransactions')->atLeast()->once()->andReturn(new Collection([new Transaction]));
|
||||
|
||||
|
||||
$userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->atLeast()->once()->andReturn(true);
|
||||
|
||||
|
||||
$journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal);
|
||||
// mock data for edit page:
|
||||
$journalRepos->shouldReceive('getJournalSourceAccounts')->andReturn(new Collection([$source]))->atLeast()->once();
|
||||
$journalRepos->shouldReceive('getJournalDestinationAccounts')->andReturn(new Collection([$source]))->atLeast()->once();
|
||||
$journalRepos->shouldReceive('getTransactionType')->andReturn('Transfer')->atLeast()->once();
|
||||
|
||||
$journalRepos->shouldReceive('isJournalReconciled')->andReturn(false)->atLeast()->once();
|
||||
|
||||
// mock stuff:
|
||||
$repository = $this->mock(AccountRepositoryInterface::class);
|
||||
$repository->shouldReceive('getAccountsByType')->once()->withArgs([[AccountType::DEFAULT, AccountType::ASSET]])->andReturn(new Collection);
|
||||
|
||||
// mock more stuff:
|
||||
$budgetRepos = $this->mock(BudgetRepositoryInterface::class);
|
||||
$budgetRepos->shouldReceive('getBudgets')->andReturn(new Collection)->atLeast()->once();
|
||||
|
||||
|
||||
$this->be($this->user());
|
||||
$response = $this->get(route('transactions.mass.edit', $transfersArray));
|
||||
$response->assertStatus(200);
|
||||
$response->assertSee('Edit a number of transactions');
|
||||
// has bread crumb
|
||||
$response->assertSee('<ol class="breadcrumb">');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\MassController
|
||||
*/
|
||||
public function testEditMultiple(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
$repository = $this->mock(AccountRepositoryInterface::class);
|
||||
$budgetRepos = $this->mock(BudgetRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$transformer = $this->mock(TransactionTransformer::class);
|
||||
$collector = $this->mock(TransactionCollectorInterface::class);
|
||||
|
||||
// mock calls:
|
||||
$transformer->shouldReceive('setParameters')->atLeast()->once();
|
||||
$transformer->shouldReceive('transform')->atLeast()->once()->andReturn(
|
||||
[
|
||||
'amount' => '10',
|
||||
'foreign_amount' => '',
|
||||
'type' => 'transfer',
|
||||
'id' => 3,
|
||||
'journal_id' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$collector->shouldReceive('setUser')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('withOpposingAccount')->atLeast()->once()->andReturnSelf();
|
||||
$collector = $this->mock(GroupCollectorInterface::class);
|
||||
$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('setJournals')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('addFilter')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('getTransactions')->atLeast()->once()->andReturn(new Collection([new Transaction]));
|
||||
$collector->shouldReceive('withTagInformation')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('withAccountInformation')->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('setJournalIds')->withArgs([[$withdrawal->id]])->atLeast()->once()->andReturnSelf();
|
||||
$collector->shouldReceive('getExtractedJournals')->atLeast()->once()->andReturn([$withdrawalArray]);
|
||||
|
||||
$repository->shouldReceive('getAccountsByType')->atLeast()->once()->andReturn(new Collection([$asset]));
|
||||
$budgetRepos->shouldReceive('getBudgets')->atLeast()->once()->andReturn(new Collection([$budget]));
|
||||
|
||||
$userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->atLeast()->once()->andReturn(true);
|
||||
$budgetRepos->shouldReceive('getBudgets')->andReturn(new Collection)->atLeast()->once();
|
||||
|
||||
|
||||
// mock stuff:
|
||||
$repository = $this->mock(AccountRepositoryInterface::class);
|
||||
$repository->shouldReceive('getAccountsByType')->once()->withArgs([[AccountType::DEFAULT, AccountType::ASSET]])->andReturn(new Collection);
|
||||
|
||||
$journalRepos->shouldReceive('firstNull')->andReturn(new TransactionJournal)->atLeast()->once();
|
||||
$journalRepos->shouldReceive('getJournalSourceAccounts')
|
||||
->andReturn(new Collection([1, 2, 3]), new Collection, new Collection, new Collection, new Collection([1]))->atLeast()->once();
|
||||
$journalRepos->shouldReceive('getJournalDestinationAccounts')
|
||||
->andReturn(new Collection, new Collection([1, 2, 3]), new Collection, new Collection, new Collection([1]))->atLeast()->once();
|
||||
$journalRepos->shouldReceive('getTransactionType')
|
||||
->andReturn('Withdrawal', 'Opening balance', 'Withdrawal', 'Withdrawal', 'Withdrawal')->atLeast()->once();
|
||||
$journalRepos->shouldReceive('isJournalReconciled')
|
||||
->andReturn(true, false, false, false, false)->atLeast()->once();
|
||||
|
||||
// default transactions
|
||||
$collection = $this->user()->transactionJournals()->take(5)->get();
|
||||
$allIds = $collection->pluck('id')->toArray();
|
||||
$route = route('transactions.mass.edit', implode(',', $allIds));
|
||||
$this->be($this->user());
|
||||
$response = $this->get($route);
|
||||
$response = $this->get(route('transactions.mass.edit', [$withdrawal->id]));
|
||||
$response->assertStatus(200);
|
||||
$response->assertSee('Edit a number of transactions');
|
||||
// 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\MassController
|
||||
*/
|
||||
public function testUpdate(): void
|
||||
{
|
||||
$this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
$deposit = $this->getRandomDeposit();
|
||||
$repository = $this->mockDefaultSession();
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$updateService = $this->mock(JournalUpdateService::class);
|
||||
|
||||
return;
|
||||
$deposit = TransactionJournal::where('transaction_type_id', 2)->where('user_id', $this->user()->id)
|
||||
->whereNull('deleted_at')
|
||||
->first();
|
||||
$this->expectsEvents(UpdatedTransactionGroup::class);
|
||||
|
||||
// mock stuff
|
||||
$repository = $this->mock(JournalRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$updateService->shouldReceive('setTransactionJournal')->atLeast()->once();
|
||||
$updateService->shouldReceive('setData')->atLeast()->once();
|
||||
$updateService->shouldReceive('update')->atLeast()->once();
|
||||
Preferences::shouldReceive('mark')->atLeast()->once();
|
||||
|
||||
$repository->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal);
|
||||
$repository->shouldReceive('update')->once();
|
||||
$repository->shouldReceive('findNull')->once()->andReturn($deposit);
|
||||
$repository->shouldReceive('getTransactionType')->andReturn('Deposit');
|
||||
$repository->shouldReceive('getNoteText')->andReturn('Some note');
|
||||
$repository->shouldReceive('findNull')->atLeast()->once()->andReturn($deposit);
|
||||
|
||||
$this->session(['transactions.mass-edit.uri' => 'http://localhost']);
|
||||
|
||||
@ -280,7 +175,6 @@ class MassControllerTest extends TestCase
|
||||
'journals' => [$deposit->id],
|
||||
'description' => [$deposit->id => 'Updated salary thing'],
|
||||
'amount' => [$deposit->id => 1600],
|
||||
'amount_currency_id_amount_' . $deposit->id => 1,
|
||||
'date' => [$deposit->id => '2014-07-24'],
|
||||
'source_name' => [$deposit->id => 'Job'],
|
||||
'destination_id' => [$deposit->id => 1],
|
||||
|
@ -159,6 +159,7 @@ abstract class TestCase extends BaseTestCase
|
||||
}
|
||||
|
||||
return [
|
||||
'transaction_group_id' => $withdrawal->transaction_group_id,
|
||||
'transaction_journal_id' => $withdrawal->id,
|
||||
'transaction_type_type' => 'Withdrawal',
|
||||
'currency_id' => $euro->id,
|
||||
@ -166,6 +167,7 @@ abstract class TestCase extends BaseTestCase
|
||||
'date' => $date,
|
||||
'description' => sprintf('I am descr #%d', $this->randomInt()),
|
||||
'source_account_id' => 1,
|
||||
'foreign_amount' => null,
|
||||
'destination_account_id' => $expense->id,
|
||||
'destination_account_name' => $expense->name,
|
||||
'currency_name' => $euro->name,
|
||||
|
Loading…
Reference in New Issue
Block a user