More test data and better views.

This commit is contained in:
James Cole 2016-05-15 12:08:41 +02:00
parent 626404407e
commit 1c93d8bf79
17 changed files with 926 additions and 626 deletions

View File

@ -13,17 +13,12 @@ namespace FireflyIII\Http\Controllers\Transaction;
use ExpandedForm;
use FireflyIII\Crud\Split\JournalInterface;
use FireflyIII\Events\TransactionJournalUpdated;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\SplitJournalFormRequest;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use Illuminate\Http\Request;
use Input;
use Log;
use Preferences;
use Session;
@ -48,6 +43,37 @@ class SplitController extends Controller
View::share('title', trans('firefly.split-transactions'));
}
/**
* @param TransactionJournal $journal
*
* @return View
*/
public function create(TransactionJournal $journal)
{
$accountRepository = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
$currencyRepository = app('FireflyIII\Repositories\Currency\CurrencyRepositoryInterface');
$budgetRepository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$assetAccounts = ExpandedForm::makeSelectList($accountRepository->getAccountsByType(['Default account', 'Asset account']));
$sessionData = session('journal-data', []);
$uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size')));
$currencies = ExpandedForm::makeSelectList($currencyRepository->get());
$budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
$preFilled = [
'what' => $sessionData['what'] ?? 'withdrawal',
'journal_amount' => $sessionData['amount'] ?? 0,
'journal_source_account_id' => $sessionData['source_account_id'] ?? 0,
'journal_source_account_name' => $sessionData['source_account_name'] ?? '',
'description' => [$journal->description],
'destination_account_name' => [$sessionData['destination_account_name']],
'destination_account_id' => [$sessionData['destination_account_id']],
'amount' => [$sessionData['amount']],
'budget_id' => [$sessionData['budget_id']],
'category' => [$sessionData['category']],
];
return view('split.journals.create', compact('journal', 'preFilled', 'assetAccounts', 'currencies', 'budgets', 'uploadSize'));
}
/**
* @param Request $request
* @param TransactionJournal $journal
@ -56,24 +82,14 @@ class SplitController extends Controller
*/
public function edit(Request $request, TransactionJournal $journal)
{
$count = $journal->transactions()->count();
if ($count === 2) {
return redirect(route('transactions.edit', [$journal->id]));
}
/** @var CurrencyRepositoryInterface $currencyRepository */
$currencyRepository = app(CurrencyRepositoryInterface::class);
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size')));
$currencies = ExpandedForm::makeSelectList($currencyRepository->get());
$assetAccounts = ExpandedForm::makeSelectList($accountRepository->getAccountsByType(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
$preFilled = $this->arrayFromJournal($request, $journal);
$currencyRepository = app('FireflyIII\Repositories\Currency\CurrencyRepositoryInterface');
$accountRepository = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
$budgetRepository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size')));
$currencies = ExpandedForm::makeSelectList($currencyRepository->get());
$assetAccounts = ExpandedForm::makeSelectList($accountRepository->getAccountsByType(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
$preFilled = $this->arrayFromJournal($request, $journal);
Session::flash('gaEventCategory', 'transactions');
Session::flash('gaEventAction', 'edit-split-' . $preFilled['what']);
@ -91,62 +107,35 @@ class SplitController extends Controller
}
/**
* @param Request $request
*
* @return mixed
* @throws FireflyException
*/
public function journalFromStore(Request $request)
{
if ($request->old('journal_currency_id')) {
$preFilled = $this->arrayFromOldData($request->old());
} else {
$preFilled = $this->arrayFromSession();
}
Session::flash('preFilled', $preFilled);
View::share('subTitle', trans('firefly.split-new-transaction'));
/** @var CurrencyRepositoryInterface $currencyRepository */
$currencyRepository = app(CurrencyRepositoryInterface::class);
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$currencies = ExpandedForm::makeSelectList($currencyRepository->get());
$assetAccounts = ExpandedForm::makeSelectList($accountRepository->getAccountsByType(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
return view('split.journals.from-store', compact('currencies', 'assetAccounts', 'budgets', 'preFilled'));
}
/**
* @param SplitJournalFormRequest $request
* @param JournalInterface $repository
* @param SplitJournalFormRequest $request
* @param TransactionJournal $journal
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws FireflyException
*/
public function postJournalFromStore(SplitJournalFormRequest $request, JournalInterface $repository)
public function store(JournalInterface $repository, SplitJournalFormRequest $request, TransactionJournal $journal)
{
$data = $request->getSplitData();
// store an empty journal first. This will be the place holder.
$journal = $repository->storeJournal($data);
// Then, store each transaction individually.
if (is_null($journal->id)) {
throw new FireflyException('Could not store transaction.');
foreach ($data['transactions'] as $transaction) {
$repository->storeTransaction($journal, $transaction);
}
// forget temp journal data
Session::forget('temporary_split_data');
// TODO move to repository
$journal->completed = 1;
$journal->save();
// this is where we originally came from.
Session::flash('success', strval(trans('firefly.stored_journal', ['description' => e($journal->description)])));
Preferences::mark();
if (intval($request->get('create_another')) === 1) {
// set value so create routine will not overwrite URL:
Session::put('transactions.create.fromStore', true);
return redirect(route('transactions.create', [$request->input('what')]))->withInput();
}
// redirect to previous URL.
return redirect(session('transactions.create.url'));
}
@ -180,7 +169,7 @@ class SplitController extends Controller
Session::flash('success', strval(trans('firefly.updated_' . $type, ['description' => e($data['journal_description'])])));
Preferences::mark();
if (intval(Input::get('return_to_edit')) === 1) {
if (intval($request->get('return_to_edit')) === 1) {
// set value so edit routine will not overwrite URL:
Session::put('transactions.edit-split.fromUpdate', true);
@ -190,9 +179,6 @@ class SplitController extends Controller
// redirect to previous URL.
return redirect(session('transactions.edit-split.url'));
// update all:
}
/**
@ -206,27 +192,32 @@ class SplitController extends Controller
if (Session::has('_old_input')) {
Log::debug('Old input: ', session('_old_input'));
}
$sourceAccounts = TransactionJournal::sourceAccountList($journal);
$firstSourceId = $sourceAccounts->first()->id;
$array = [
'journal_description' => $request->old('journal_description', $journal->description),
'journal_amount' => TransactionJournal::amountPositive($journal),
'sourceAccounts' => $sourceAccounts,
'transaction_currency_id' => $request->old('transaction_currency_id', $journal->transaction_currency_id),
'destinationAccounts' => TransactionJournal::destinationAccountList($journal),
'what' => strtolower(TransactionJournal::transactionTypeStr($journal)),
'date' => $request->old('date', $journal->date),
'interest_date' => $request->old('interest_date', $journal->interest_date),
'book_date' => $request->old('book_date', $journal->book_date),
'process_date' => $request->old('process_date', $journal->process_date),
'description' => [],
'destination_account_id' => [],
'destination_account_name' => [],
'amount' => [],
'budget_id' => [],
'category' => [],
$sourceAccounts = TransactionJournal::sourceAccountList($journal);
$destinationAccounts = TransactionJournal::destinationAccountList($journal);
$array = [
'journal_description' => $request->old('journal_description', $journal->description),
'journal_amount' => TransactionJournal::amountPositive($journal),
'sourceAccounts' => $sourceAccounts,
'journal_source_account_id' => $sourceAccounts->first()->id,
'journal_source_account_name' => $sourceAccounts->first()->name,
'journal_destination_account_id' => $destinationAccounts->first()->id,
'transaction_currency_id' => $request->old('transaction_currency_id', $journal->transaction_currency_id),
'destinationAccounts' => $destinationAccounts,
'what' => strtolower(TransactionJournal::transactionTypeStr($journal)),
'date' => $request->old('date', $journal->date),
'interest_date' => $request->old('interest_date', $journal->interest_date),
'book_date' => $request->old('book_date', $journal->book_date),
'process_date' => $request->old('process_date', $journal->process_date),
'description' => [],
'source_account_id' => [],
'source_account_name' => [],
'destination_account_id' => [],
'destination_account_name' => [],
'amount' => [],
'budget_id' => [],
'category' => [],
];
$index = 0;
$index = 0;
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
$budget = $transaction->budgets()->first();
@ -245,10 +236,10 @@ class SplitController extends Controller
$categoryName = $request->old('category')[$index] ?? $categoryName;
$amount = $request->old('amount')[$index] ?? $transaction->amount;
$description = $request->old('description')[$index] ?? $transaction->description;
$destinationName = $request->old('destination_account_name')[$index] ??$transaction->account->name;
$destinationName = $request->old('destination_account_name')[$index] ?? $transaction->account->name;
if ($journal->isWithdrawal() && $transaction->account_id !== $firstSourceId) {
// any transfer not from the source:
if (($journal->isWithdrawal() || $journal->isDeposit()) && $transaction->account_id !== $sourceAccounts->first()->id) {
$array['description'][] = $description;
$array['destination_account_id'][] = $transaction->account_id;
$array['destination_account_name'][] = $destinationName;
@ -258,79 +249,10 @@ class SplitController extends Controller
// only add one when "valid" transaction
$index++;
}
}
return $array;
}
/**
* @param array $old
*
* @return array
*/
private function arrayFromOldData(array $old): array
{
// this array is pretty much equal to what we expect it to be.
Log::debug('Prefilled', $old);
return $old;
}
/**
* @return array
* @throws FireflyException
*/
private function arrayFromSession(): array
{
// expect data to be in session or in post?
$data = session('temporary_split_data');
if (!is_array($data)) {
Log::error('Could not find transaction data in your session. Please go back and try again.', ['data' => $data]); // translate me.
throw new FireflyException('Could not find transaction data in your session. Please go back and try again.'); // translate me.
}
Log::debug('Journal data', $data);
$preFilled = [
'what' => $data['what'],
'journal_description' => $data['description'],
'journal_source_account_id' => $data['source_account_id'],
'journal_source_account_name' => $data['source_account_name'],
'journal_destination_account_id' => $data['destination_account_id'],
'journal_destination_account_name' => $data['destination_account_name'],
'journal_amount' => $data['amount'],
'journal_currency_id' => $data['amount_currency_id_amount'],
'date' => $data['date'],
'interest_date' => $data['interest_date'],
'book_date' => $data['book_date'],
'process_date' => $data['process_date'],
'description' => [],
'destination_account_id' => [],
'destination_account_name' => [],
'amount' => [],
'budget_id' => [],
'category' => [],
];
// create the first transaction:
$preFilled['description'][] = $data['description'];
$preFilled['destination_account_id'][] = $data['destination_account_id'];
$preFilled['destination_account_name'][] = $data['destination_account_name'];
$preFilled['amount'][] = $data['amount'];
$preFilled['budget_id'][] = $data['budget_id'];
$preFilled['category'][] = $data['category'];
// echo '<pre>';
// var_dump($data);
// var_dump($preFilled);
// exit;
Log::debug('Prefilled', $preFilled);
return $preFilled;
}
}

View File

@ -9,10 +9,8 @@
namespace FireflyIII\Http\Controllers;
use Amount;
use Auth;
use Carbon\Carbon;
use DB;
use ExpandedForm;
use FireflyIII\Events\TransactionJournalStored;
use FireflyIII\Events\TransactionJournalUpdated;
@ -21,17 +19,12 @@ use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Requests\JournalFormRequest;
use FireflyIII\Http\Requests\MassDeleteJournalRequest;
use FireflyIII\Http\Requests\MassEditJournalRequest;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Input;
use Log;
use Preferences;
use Response;
@ -65,31 +58,24 @@ class TransactionController extends Controller
*/
public function create(ARI $repository, string $what = TransactionType::DEPOSIT)
{
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
/** @var PiggyBankRepositoryInterface $piggyRepository */
$piggyRepository = app(PiggyBankRepositoryInterface::class);
$what = strtolower($what);
$uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size')));
$assetAccounts = ExpandedForm::makeSelectList($repository->getAccountsByType(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
$piggyBanks = $piggyRepository->getPiggyBanks();
/** @var PiggyBank $piggy */
foreach ($piggyBanks as $piggy) {
$piggy->name = $piggy->name . ' (' . Amount::format($piggy->currentRelevantRep()->currentamount, false) . ')';
}
$piggies = ExpandedForm::makeSelectListWithEmpty($piggyBanks);
$preFilled = Session::has('preFilled') ? session('preFilled') : [];
$subTitle = trans('form.add_new_' . $what);
$budgetRepository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$piggyRepository = app('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface');
$what = strtolower($what);
$uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size')));
$assetAccounts = ExpandedForm::makeSelectList($repository->getAccountsByType(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
$piggyBanks = $piggyRepository->getPiggyBanksWithAmount();
$piggies = ExpandedForm::makeSelectListWithEmpty($piggyBanks);
$preFilled = Session::has('preFilled') ? session('preFilled') : [];
$subTitle = trans('form.add_new_' . $what);
Session::put('preFilled', $preFilled);
// put previous url in session if not redirect from store (not "create another").
if (session('transactions.create.fromStore') !== true) {
Session::put('transactions.create.url', URL::previous());
$url = URL::previous();
Log::debug('TransactionController::create. Previous URL is ' . $url);
Session::put('transactions.create.url', $url);
}
Session::forget('transactions.create.fromStore');
Session::flash('gaEventCategory', 'transactions');
@ -131,7 +117,7 @@ class TransactionController extends Controller
*/
public function destroy(JournalRepositoryInterface $repository, TransactionJournal $transactionJournal)
{
$type = strtolower($transactionJournal->transaction_type_type ?? TransactionJournal::transactionTypeStr($transactionJournal));
$type = TransactionJournal::transactionTypeStr($transactionJournal);
Session::flash('success', strval(trans('firefly.deleted_' . $type, ['description' => e($transactionJournal->description)])));
$repository->delete($transactionJournal);
@ -153,24 +139,18 @@ class TransactionController extends Controller
if ($count > 2) {
return redirect(route('split.journal.edit', [$journal->id]));
}
/** @var ARI $accountRepository */
$accountRepository = app(ARI::class);
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
/** @var PiggyBankRepositoryInterface $piggyRepository */
$piggyRepository = app(PiggyBankRepositoryInterface::class);
$assetAccounts = ExpandedForm::makeSelectList($accountRepository->getAccountsByType(['Default account', 'Asset account']));
$budgetList = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
$piggyBankList = ExpandedForm::makeSelectListWithEmpty($piggyRepository->getPiggyBanks());
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
$uploadSize = min($maxFileSize, $maxPostSize);
$what = strtolower(TransactionJournal::transactionTypeStr($journal));
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
$preFilled = [
$accountRepository = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
$budgetRepository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$piggyRepository = app('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface');
$assetAccounts = ExpandedForm::makeSelectList($accountRepository->getAccountsByType(['Default account', 'Asset account']));
$budgetList = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
$piggyBankList = ExpandedForm::makeSelectListWithEmpty($piggyRepository->getPiggyBanks());
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
$uploadSize = min($maxFileSize, $maxPostSize);
$what = strtolower(TransactionJournal::transactionTypeStr($journal));
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
$preFilled = [
'date' => TransactionJournal::dateAsString($journal),
'interest_date' => TransactionJournal::dateAsString($journal, 'interest_date'),
'book_date' => TransactionJournal::dateAsString($journal, 'book_date'),
@ -204,25 +184,25 @@ class TransactionController extends Controller
}
Session::forget('transactions.edit.fromUpdate');
return view('transactions.edit', compact('journal', 'uploadSize', 'assetAccounts', 'what', 'budgetList', 'piggyBankList', 'subTitle'))->with(
'data', $preFilled
);
}
/**
* @param Request $request
* @param JournalRepositoryInterface $repository
* @param $what
* @param string $what
*
* @return \Illuminate\View\View
* @return View
*/
public function index(JournalRepositoryInterface $repository, string $what)
public function index(Request $request, JournalRepositoryInterface $repository, string $what)
{
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
$types = config('firefly.transactionTypesByWhat.' . $what);
$subTitle = trans('firefly.title_' . $what);
$page = intval(Input::get('page'));
$page = intval($request->get('page'));
$journals = $repository->getJournals($types, $page, $pageSize);
$journals->setPath('transactions/' . $what);
@ -294,9 +274,8 @@ class TransactionController extends Controller
*/
public function massEdit(Collection $journals)
{
$subTitle = trans('firefly.mass_edit_journals');
/** @var ARI $accountRepository */
$accountRepository = app(ARI::class);
$subTitle = trans('firefly.mass_edit_journals');
$accountRepository = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
$accountList = ExpandedForm::makeSelectList($accountRepository->getAccountsByType(['Default account', 'Asset account']));
// put previous url in session
@ -315,14 +294,12 @@ class TransactionController extends Controller
*/
public function massUpdate(MassEditJournalRequest $request, JournalRepositoryInterface $repository)
{
$journalIds = Input::get('journals');
$journalIds = $request->get('journals');
$count = 0;
if (is_array($journalIds)) {
foreach ($journalIds as $journalId) {
$journal = $repository->find(intval($journalId));
if ($journal) {
// do update.
// get optional fields:
$what = strtolower(TransactionJournal::transactionTypeStr($journal));
$sourceAccountId = $request->get('source_account_id')[$journal->id] ?? 0;
@ -379,18 +356,18 @@ class TransactionController extends Controller
}
/**
* @param Request $request
* @param JournalRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
* @return \Illuminate\Http\JsonResponse
*/
public function reorder(JournalRepositoryInterface $repository)
public function reorder(Request $request, JournalRepositoryInterface $repository)
{
$ids = Input::get('items');
$date = new Carbon(Input::get('date'));
$ids = $request->get('items');
$date = new Carbon($request->get('date'));
if (count($ids) > 0) {
$order = 0;
foreach ($ids as $id) {
$journal = $repository->find($id);
if ($journal && $journal->date->format('Y-m-d') == $date->format('Y-m-d')) {
$journal->order = $order;
@ -406,72 +383,26 @@ class TransactionController extends Controller
}
/**
* @param TransactionJournal $journal
* @param TransactionJournal $journal
* @param JournalRepositoryInterface $repository
*
* @return \Illuminate\View\View
* @return View
* @throws FireflyException
*/
public function show(TransactionJournal $journal, JournalRepositoryInterface $repository)
{
$events = $repository->getPiggyBankEvents($journal);
$transactions = $repository->getTransactions($journal);
$what = strtolower($journal->transaction_type_type ?? $journal->transactionType->type);
$subTitle = trans('firefly.' . $what) . ' "' . e($journal->description) . '"';
/** @var Collection $set */
$events = $journal->piggyBankEvents()->get();
$events->each(
function (PiggyBankEvent $event) {
$event->piggyBank = $event->piggyBank()->withTrashed()->first();
}
);
switch ($journal->transactionType->type) {
case TransactionType::DEPOSIT:
/** @var Collection $transactions */
$transactions = $journal->transactions()
->groupBy('transactions.account_id')
->where('amount', '<', 0)
->orderBy('amount', 'ASC')->get(
['transactions.*', DB::raw('SUM(`transactions`.`amount`) as `sum`')]
);
$final = $journal->transactions()
->groupBy('transactions.account_id')
->where('amount', '>', 0)
->orderBy('amount', 'ASC')->first(
['transactions.*', DB::raw('SUM(`transactions`.`amount`) as `sum`')]
);
$transactions->push($final);
break;
case TransactionType::WITHDRAWAL:
/** @var Collection $transactions */
$transactions = $journal->transactions()
->groupBy('transactions.account_id')
->where('amount', '>', 0)
->orderBy('amount', 'ASC')->get(
['transactions.*', DB::raw('SUM(`transactions`.`amount`) as `sum`')]
);
$final = $journal->transactions()
->groupBy('transactions.account_id')
->where('amount', '<', 0)
->orderBy('amount', 'ASC')->first(
['transactions.*', DB::raw('SUM(`transactions`.`amount`) as `sum`')]
);
$transactions->push($final);
break;
default:
throw new FireflyException('Cannot handle ' . $journal->transactionType->type);
break;
if ($transactions->count() > 2) {
return view('split.journals.show', compact('journal', 'events', 'subTitle', 'what', 'transactions'));
}
// foreach do balance thing
$transactions->each(
function (Transaction $t) use ($repository) {
$t->before = $repository->balanceBeforeTransaction($t);
}
);
$what = strtolower($journal->transaction_type_type ?? $journal->transactionType->type);
$subTitle = trans('firefly.' . $what) . ' "' . e($journal->description) . '"';
return view('transactions.show', compact('journal', 'events', 'subTitle', 'what', 'transactions'));
}
/**
@ -484,16 +415,30 @@ class TransactionController extends Controller
*/
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att)
{
Log::debug('Start of store.');
$doSplit = intval($request->get('split_journal')) === 1;
$journalData = $request->getJournalData();
if ($doSplit) {
// put all journal data in the session and redirect to split routine.
Session::put('temporary_split_data', $journalData);
return redirect(route('split.journal.from-store'));
// store the journal only, flash the rest.
if ($doSplit) {
$journal = $repository->storeJournal($journalData);
// store attachments:
$att->saveAttachmentsForModel($journal);
// flash errors
if (count($att->getErrors()->get('attachments')) > 0) {
Session::flash('error', $att->getErrors()->get('attachments'));
}
// flash messages
if (count($att->getMessages()->get('attachments')) > 0) {
Session::flash('info', $att->getMessages()->get('attachments'));
}
Session::put('journal-data', $journalData);
return redirect(route('split.journal.create', [$journal->id]));
}
Log::debug('Not in split.');
// if not withdrawal, unset budgetid.
if ($journalData['what'] != strtolower(TransactionType::WITHDRAWAL)) {
@ -501,7 +446,6 @@ class TransactionController extends Controller
}
$journal = $repository->store($journalData);
$att->saveAttachmentsForModel($journal);
// flash errors
@ -518,7 +462,7 @@ class TransactionController extends Controller
Session::flash('success', strval(trans('firefly.stored_journal', ['description' => e($journal->description)])));
Preferences::mark();
if (intval(Input::get('create_another')) === 1) {
if (intval($request->get('create_another')) === 1) {
// set value so create routine will not overwrite URL:
Session::put('transactions.create.fromStore', true);
@ -565,7 +509,7 @@ class TransactionController extends Controller
Session::flash('success', strval(trans('firefly.updated_' . $type, ['description' => e($journalData['description'])])));
Preferences::mark();
if (intval(Input::get('return_to_edit')) === 1) {
if (intval($request->get('return_to_edit')) === 1) {
// set value so edit routine will not overwrite URL:
Session::put('transactions.edit.fromUpdate', true);

View File

@ -40,7 +40,7 @@ class SplitJournalFormRequest extends Request
'journal_currency_id' => intval($this->get('journal_currency_id')),
'journal_source_account_id' => intval($this->get('journal_source_account_id')),
'journal_source_account_name' => $this->get('journal_source_account_name'),
'journal_destination_account_id' => intval($this->get('journal_source_destination_id')),
'journal_destination_account_id' => intval($this->get('journal_destination_account_id')),
'journal_destination_account_name' => $this->get('journal_source_destination_name'),
'date' => new Carbon($this->get('date')),
'what' => $this->get('what'),
@ -61,7 +61,7 @@ class SplitJournalFormRequest extends Request
'source_account_name' => $this->get('journal_source_account_name'),
'destination_account_id' => isset($this->get('destination_account_id')[$index])
? intval($this->get('destination_account_id')[$index])
: intval($this->get('destination_account_id')),
: intval($this->get('journal_destination_account_id')),
'destination_account_name' => $this->get('destination_account_name')[$index] ?? '',
];
$data['transactions'][] = $transaction;

View File

@ -343,10 +343,11 @@ Route::group(
/**
* Split controller
*/
Route::get('/transaction/split', ['uses' => 'Transaction\SplitController@journalFromStore', 'as' => 'split.journal.from-store']);
Route::post('/transaction/split', ['uses' => 'Transaction\SplitController@postJournalFromStore', 'as' => 'split.journal.from-store.post']);
Route::get('/transaction/edit-split/{journal}',['uses' => 'Transaction\SplitController@edit', 'as' => 'split.journal.edit']);
Route::post('/transaction/edit-split/{journal}',['uses' => 'Transaction\SplitController@update', 'as' => 'split.journal.update']);
Route::get('/transaction/create-split/{unfinishedJournal}', ['uses' => 'Transaction\SplitController@create', 'as' => 'split.journal.create']);
Route::post('/transaction/store-split/{unfinishedJournal}', ['uses' => 'Transaction\SplitController@store', 'as' => 'split.journal.store']);
Route::get('/transaction/edit-split/{journal}', ['uses' => 'Transaction\SplitController@edit', 'as' => 'split.journal.edit']);
Route::post('/transaction/edit-split/{journal}', ['uses' => 'Transaction\SplitController@update', 'as' => 'split.journal.update']);
/**
* Tag Controller
*/

View File

@ -10,6 +10,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
@ -208,6 +209,91 @@ class JournalRepository implements JournalRepositoryInterface
return $set;
}
/**
* @param TransactionJournal $journal
*
* @return Collection
*/
public function getPiggyBankEvents(TransactionJournal $journal): Collection
{
/** @var Collection $set */
$events = $journal->piggyBankEvents()->get();
$events->each(
function (PiggyBankEvent $event) {
$event->piggyBank = $event->piggyBank()->withTrashed()->first();
}
);
return $events;
}
/**
* @param TransactionJournal $journal
*
* @return Collection
* @throws FireflyException
*/
public function getTransactions(TransactionJournal $journal): Collection
{
switch ($journal->transactionType->type) {
case TransactionType::DEPOSIT:
/** @var Collection $transactions */
$transactions = $journal->transactions()
->groupBy('transactions.account_id')
->where('amount', '<', 0)
->groupBy('transactions.id')
->orderBy('amount', 'ASC')->get(
['transactions.*', DB::raw('SUM(`transactions`.`amount`) as `sum`')]
);
$final = $journal->transactions()
->groupBy('transactions.account_id')
->where('amount', '>', 0)
->orderBy('amount', 'ASC')->first(
['transactions.*', DB::raw('SUM(`transactions`.`amount`) as `sum`')]
);
$transactions->push($final);
break;
case TransactionType::TRANSFER:
/** @var Collection $transactions */
$transactions = $journal->transactions()
->groupBy('transactions.id')
->orderBy('transactions.id')->get(
['transactions.*', DB::raw('SUM(`transactions`.`amount`) as `sum`')]
);
break;
case TransactionType::WITHDRAWAL:
/** @var Collection $transactions */
$transactions = $journal->transactions()
->where('amount', '>', 0)
->groupBy('transactions.id')
->orderBy('amount', 'ASC')->get(
['transactions.*', DB::raw('SUM(`transactions`.`amount`) as `sum`')]
);
$final = $journal->transactions()
->where('amount', '<', 0)
->groupBy('transactions.account_id')
->orderBy('amount', 'ASC')->first(
['transactions.*', DB::raw('SUM(`transactions`.`amount`) as `sum`')]
);
$transactions->push($final);
break;
default:
throw new FireflyException('Cannot handle ' . $journal->transactionType->type);
break;
}
// foreach do balance thing
$transactions->each(
function (Transaction $t) {
$t->before = $this->balanceBeforeTransaction($t);
}
);
return $transactions;
}
/**
* @param array $data
*
@ -278,6 +364,37 @@ class JournalRepository implements JournalRepositoryInterface
}
/**
* Store journal only, uncompleted, with attachments if necessary.
*
* @param array $data
*
* @return TransactionJournal
*/
public function storeJournal(array $data): TransactionJournal
{
// find transaction type.
$transactionType = TransactionType::where('type', ucfirst($data['what']))->first();
// store actual journal.
$journal = new TransactionJournal(
[
'user_id' => $data['user'],
'transaction_type_id' => $transactionType->id,
'transaction_currency_id' => $data['amount_currency_id_amount'],
'description' => $data['description'],
'completed' => 0,
'date' => $data['date'],
'interest_date' => $data['interest_date'],
'book_date' => $data['book_date'],
'process_date' => $data['process_date'],
]
);
$journal->save();
return $journal;
}
/**
* @param TransactionJournal $journal
* @param array $data

View File

@ -16,6 +16,15 @@ use Illuminate\Support\Collection;
*/
interface JournalRepositoryInterface
{
/**
* Returns the amount in the account before the specified transaction took place.
*
* @param Transaction $transaction
*
* @return string
*/
public function balanceBeforeTransaction(Transaction $transaction): string;
/**
* Deletes a journal.
*
@ -41,16 +50,6 @@ interface JournalRepositoryInterface
*/
public function first(): TransactionJournal;
/**
* Returns the amount in the account before the specified transaction took place.
*
* @param Transaction $transaction
*
* @return string
*/
public function balanceBeforeTransaction(Transaction $transaction): string;
/**
* Returns the amount in the account before the specified transaction took place.
*
@ -85,6 +84,20 @@ interface JournalRepositoryInterface
*/
public function getJournalsInRange(Collection $accounts, Carbon $start, Carbon $end): Collection;
/**
* @param TransactionJournal $journal
*
* @return Collection
*/
public function getPiggyBankEvents(TransactionJournal $journal): Collection;
/**
* @param TransactionJournal $journal
*
* @return Collection
*/
public function getTransactions(TransactionJournal $journal): Collection;
/**
* @param array $data
*
@ -92,6 +105,15 @@ interface JournalRepositoryInterface
*/
public function store(array $data): TransactionJournal;
/**
* Store journal only, uncompleted, with attachments if necessary.
*
* @param array $data
*
* @return TransactionJournal
*/
public function storeJournal(array $data): TransactionJournal;
/**
* @param TransactionJournal $journal
* @param array $data

View File

@ -3,8 +3,8 @@ declare(strict_types = 1);
namespace FireflyIII\Repositories\PiggyBank;
use Amount;
use Carbon\Carbon;
use DB;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\User;
@ -86,6 +86,21 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return $set;
}
/**
* Also add amount in name.
*
* @return Collection
*/
public function getPiggyBanksWithAmount() : Collection
{
$set = $this->getPiggyBanks();
foreach ($set as $piggy) {
$piggy->name = $piggy->name . ' (' . Amount::format($piggy->currentRelevantRep()->currentamount, false) . ')';
}
return $set;
}
/**
* Set all piggy banks to order 0.
*

View File

@ -57,6 +57,13 @@ interface PiggyBankRepositoryInterface
*/
public function getPiggyBanks() : Collection;
/**
* Also add amount in name.
*
* @return Collection
*/
public function getPiggyBanksWithAmount() : Collection;
/**
* Set all piggy banks to order 0.
*
@ -86,7 +93,7 @@ interface PiggyBankRepositoryInterface
/**
* Update existing piggy bank.
*
*
* @param PiggyBank $piggyBank
* @param array $data
*

View File

@ -0,0 +1,55 @@
<?php
/**
* UnfinishedJournal.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
/**
* Date.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace FireflyIII\Support\Binder;
use Auth;
use FireflyIII\Models\TransactionJournal;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class Date
*
* @package FireflyIII\Support\Binder
*/
class UnfinishedJournal implements BinderInterface
{
/**
* @param $value
* @param $route
*
* @return mixed
*/
public static function routeBinder($value, $route): TransactionJournal
{
if (Auth::check()) {
$object = TransactionJournal::where('transaction_journals.id', $value)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where('completed', 0)
->where('user_id', Auth::user()->id)->first(['transaction_journals.*']);
if ($object) {
return $object;
}
}
throw new NotFoundHttpException;
}
}

View File

@ -415,6 +415,73 @@ class TestData
DB::table('transactions')->insert($transactions);
}
/**
*
*/
private function createMultiDeposits()
{
foreach ($this->data['multi-deposits'] as $deposit) {
$journalId = DB::table('transaction_journals')->insertGetId(
[
'created_at' => DB::raw('NOW()'),
'updated_at' => DB::raw('NOW()'),
'user_id' => $deposit['user_id'],
'transaction_type_id' => 2,
'transaction_currency_id' => 1,
'description' => Crypt::encrypt($deposit['description']),
'completed' => 1,
'date' => $deposit['date'],
'interest_date' => $deposit['interest_date'] ?? null,
'book_date' => $deposit['book_date'] ?? null,
'process_date' => $deposit['process_date'] ?? null,
'encrypted' => 1,
'order' => 0,
'tag_count' => 0,
]
);
foreach ($deposit['source_ids'] as $index => $source) {
$description = $deposit['description'] . ' (#' . ($index + 1) . ')';
$amount = $deposit['amounts'][$index];
$first = DB::table('transactions')->insertGetId(
[
'created_at' => DB::raw('NOW()'),
'updated_at' => DB::raw('NOW()'),
'account_id' => $deposit['destination_id'],
'transaction_journal_id' => $journalId,
'description' => $description,
'amount' => $amount,
]
);
$second = DB::table('transactions')->insertGetId(
[
'created_at' => DB::raw('NOW()'),
'updated_at' => DB::raw('NOW()'),
'account_id' => $source,
'transaction_journal_id' => $journalId,
'description' => $description,
'amount' => $amount * -1,
]
);
// link first and second to budget and category, if present.
if (isset($deposit['category_ids'][$index])) {
DB::table('category_transaction')->insert(
[
'category_id' => $deposit['category_ids'][$index],
'transaction_id' => $first,
]
);
DB::table('category_transaction')->insert(
[
'category_id' => $deposit['category_ids'][$index],
'transaction_id' => $second,
]
);
}
}
}
}
/**
*
*/
@ -660,6 +727,7 @@ class TestData
$this->createJournals();
$this->createAttachments();
$this->createMultiWithdrawals();
$this->createMultiDeposits();
}
}

View File

@ -158,28 +158,29 @@ return [
],
'bindables' => [
// models
'account' => 'FireflyIII\Models\Account',
'attachment' => 'FireflyIII\Models\Attachment',
'bill' => 'FireflyIII\Models\Bill',
'budget' => 'FireflyIII\Models\Budget',
'category' => 'FireflyIII\Models\Category',
'currency' => 'FireflyIII\Models\TransactionCurrency',
'limitrepetition' => 'FireflyIII\Models\LimitRepetition',
'piggyBank' => 'FireflyIII\Models\PiggyBank',
'tj' => 'FireflyIII\Models\TransactionJournal',
'tag' => 'FireflyIII\Models\Tag',
'rule' => 'FireflyIII\Models\Rule',
'ruleGroup' => 'FireflyIII\Models\RuleGroup',
'jobKey' => 'FireflyIII\Models\ExportJob',
'account' => 'FireflyIII\Models\Account',
'attachment' => 'FireflyIII\Models\Attachment',
'bill' => 'FireflyIII\Models\Bill',
'budget' => 'FireflyIII\Models\Budget',
'category' => 'FireflyIII\Models\Category',
'currency' => 'FireflyIII\Models\TransactionCurrency',
'limitrepetition' => 'FireflyIII\Models\LimitRepetition',
'piggyBank' => 'FireflyIII\Models\PiggyBank',
'tj' => 'FireflyIII\Models\TransactionJournal',
'unfinishedJournal' => 'FireflyIII\Support\Binder\UnfinishedJournal',
'tag' => 'FireflyIII\Models\Tag',
'rule' => 'FireflyIII\Models\Rule',
'ruleGroup' => 'FireflyIII\Models\RuleGroup',
'jobKey' => 'FireflyIII\Models\ExportJob',
// lists
'accountList' => 'FireflyIII\Support\Binder\AccountList',
'budgetList' => 'FireflyIII\Support\Binder\BudgetList',
'journalList' => 'FireflyIII\Support\Binder\JournalList',
'categoryList' => 'FireflyIII\Support\Binder\CategoryList',
'accountList' => 'FireflyIII\Support\Binder\AccountList',
'budgetList' => 'FireflyIII\Support\Binder\BudgetList',
'journalList' => 'FireflyIII\Support\Binder\JournalList',
'categoryList' => 'FireflyIII\Support\Binder\CategoryList',
// others
'start_date' => 'FireflyIII\Support\Binder\Date',
'end_date' => 'FireflyIII\Support\Binder\Date',
'start_date' => 'FireflyIII\Support\Binder\Date',
'end_date' => 'FireflyIII\Support\Binder\Date',
],
'rule-triggers' => [

View File

@ -10,129 +10,131 @@
return [
// new user:
'bank_name' => 'Bank name',
'bank_balance' => 'Balance',
'savings_balance' => 'Savings balance',
'credit_card_limit' => 'Credit card limit',
'automatch' => 'Match automatically',
'skip' => 'Skip',
'name' => 'Name',
'active' => 'Active',
'amount_min' => 'Minimum amount',
'amount_max' => 'Maximum amount',
'match' => 'Matches on',
'repeat_freq' => 'Repeats',
'journal_currency_id' => 'Currency',
'journal_amount' => 'Amount',
'journal_asset_source_account' => 'Asset account (source)',
'journal_source_account_id' => 'Asset account (source)',
'account_from_id' => 'From account',
'account_to_id' => 'To account',
'asset_destination_account' => 'Asset account (destination)',
'asset_source_account' => 'Asset account (source)',
'journal_description' => 'Description',
'split_journal' => 'Split this transaction',
'split_journal_explanation' => 'Split this transaction in multiple parts',
'currency' => 'Currency',
'account_id' => 'Asset account',
'budget_id' => 'Budget',
'openingBalance' => 'Opening balance',
'tagMode' => 'Tag mode',
'tagPosition' => 'Tag location',
'virtualBalance' => 'Virtual balance',
'longitude_latitude' => 'Location',
'targetamount' => 'Target amount',
'accountRole' => 'Account role',
'openingBalanceDate' => 'Opening balance date',
'ccType' => 'Credit card payment plan',
'ccMonthlyPaymentDate' => 'Credit card monthly payment date',
'piggy_bank_id' => 'Piggy bank',
'returnHere' => 'Return here',
'returnHereExplanation' => 'After storing, return here to create another one.',
'returnHereUpdateExplanation' => 'After updating, return here.',
'description' => 'Description',
'expense_account' => 'Expense account',
'revenue_account' => 'Revenue account',
'amount' => 'Amount',
'date' => 'Date',
'interest_date' => 'Interest date',
'book_date' => 'Book date',
'process_date' => 'Processing date',
'category' => 'Category',
'tags' => 'Tags',
'deletePermanently' => 'Delete permanently',
'cancel' => 'Cancel',
'targetdate' => 'Target date',
'tag' => 'Tag',
'under' => 'Under',
'symbol' => 'Symbol',
'code' => 'Code',
'iban' => 'IBAN',
'accountNumber' => 'Account number',
'csv' => 'CSV file',
'has_headers' => 'Headers',
'date_format' => 'Date format',
'csv_config' => 'CSV import configuration',
'specifix' => 'Bank- or file specific fixes',
'csv_import_account' => 'Default import account',
'csv_delimiter' => 'CSV field delimiter',
'attachments[]' => 'Attachments',
'store_new_withdrawal' => 'Store new withdrawal',
'store_new_deposit' => 'Store new deposit',
'store_new_transfer' => 'Store new transfer',
'add_new_withdrawal' => 'Add a new withdrawal',
'add_new_deposit' => 'Add a new deposit',
'add_new_transfer' => 'Add a new transfer',
'noPiggybank' => '(no piggy bank)',
'title' => 'Title',
'notes' => 'Notes',
'filename' => 'File name',
'mime' => 'Mime type',
'size' => 'Size',
'trigger' => 'Trigger',
'stop_processing' => 'Stop processing',
'start_date' => 'Start of range',
'end_date' => 'End of range',
'export_start_range' => 'Start of export range',
'export_end_range' => 'End of export range',
'export_format' => 'File format',
'include_attachments' => 'Include uploaded attachments',
'include_config' => 'Include configuration file',
'include_old_uploads' => 'Include imported data',
'accounts' => 'Export transactions from these accounts',
'csv_comma' => 'A comma (,)',
'csv_semicolon' => 'A semicolon (;)',
'csv_tab' => 'A tab (invisible)',
'delete_account' => 'Delete account ":name"',
'delete_bill' => 'Delete bill ":name"',
'delete_budget' => 'Delete budget ":name"',
'delete_category' => 'Delete category ":name"',
'delete_currency' => 'Delete currency ":name"',
'delete_journal' => 'Delete transaction with description ":description"',
'delete_attachment' => 'Delete attachment ":name"',
'delete_rule' => 'Delete rule ":title"',
'delete_rule_group' => 'Delete rule group ":title"',
'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?',
'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?',
'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?',
'rule_areYouSure' => 'Are you sure you want to delete the rule titled ":title"?',
'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titled ":title"?',
'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?',
'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?',
'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?',
'piggyBank_areYouSure' => 'Are you sure you want to delete the piggy bank named ":name"?',
'journal_areYouSure' => 'Are you sure you want to delete the transaction described ":description"?',
'mass_journal_are_you_sure' => 'Are you sure you want to delete these transactions?',
'tag_areYouSure' => 'Are you sure you want to delete the tag ":tag"?',
'permDeleteWarning' => 'Deleting stuff from Firely is permanent and cannot be undone.',
'mass_make_selection' => 'You can still prevent items from being deleted by removing the checkbox.',
'delete_all_permanently' => 'Delete selected permanently',
'update_all_journals' => 'Update these transactions',
'also_delete_transactions' => 'The only transaction connected to this account will be deleted as well.|All :count transactions connected to this account will be deleted as well.',
'also_delete_rules' => 'The only rule connected to this rule group will be deleted as well.|All :count rules connected to this rule group will be deleted as well.',
'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.|All :count piggy bank connected to this account will be deleted as well.',
'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill will spared deletion.',
'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.|All :count transactions connected to this budget will spared deletion.',
'category_keep_transactions' => 'The only transaction connected to this category will not be deleted.|All :count transactions connected to this category will spared deletion.',
'tag_keep_transactions' => 'The only transaction connected to this tag will not be deleted.|All :count transactions connected to this tag will spared deletion.',
'bank_name' => 'Bank name',
'bank_balance' => 'Balance',
'savings_balance' => 'Savings balance',
'credit_card_limit' => 'Credit card limit',
'automatch' => 'Match automatically',
'skip' => 'Skip',
'name' => 'Name',
'active' => 'Active',
'amount_min' => 'Minimum amount',
'amount_max' => 'Maximum amount',
'match' => 'Matches on',
'repeat_freq' => 'Repeats',
'journal_currency_id' => 'Currency',
'journal_amount' => 'Amount',
'journal_asset_source_account' => 'Asset account (source)',
'journal_source_account_name' => 'Revenue account (source)',
'journal_source_account_id' => 'Asset account (source)',
'account_from_id' => 'From account',
'account_to_id' => 'To account',
'journal_destination_account_id' => 'Asset account (destination)',
'asset_destination_account' => 'Asset account (destination)',
'asset_source_account' => 'Asset account (source)',
'journal_description' => 'Description',
'split_journal' => 'Split this transaction',
'split_journal_explanation' => 'Split this transaction in multiple parts',
'currency' => 'Currency',
'account_id' => 'Asset account',
'budget_id' => 'Budget',
'openingBalance' => 'Opening balance',
'tagMode' => 'Tag mode',
'tagPosition' => 'Tag location',
'virtualBalance' => 'Virtual balance',
'longitude_latitude' => 'Location',
'targetamount' => 'Target amount',
'accountRole' => 'Account role',
'openingBalanceDate' => 'Opening balance date',
'ccType' => 'Credit card payment plan',
'ccMonthlyPaymentDate' => 'Credit card monthly payment date',
'piggy_bank_id' => 'Piggy bank',
'returnHere' => 'Return here',
'returnHereExplanation' => 'After storing, return here to create another one.',
'returnHereUpdateExplanation' => 'After updating, return here.',
'description' => 'Description',
'expense_account' => 'Expense account',
'revenue_account' => 'Revenue account',
'amount' => 'Amount',
'date' => 'Date',
'interest_date' => 'Interest date',
'book_date' => 'Book date',
'process_date' => 'Processing date',
'category' => 'Category',
'tags' => 'Tags',
'deletePermanently' => 'Delete permanently',
'cancel' => 'Cancel',
'targetdate' => 'Target date',
'tag' => 'Tag',
'under' => 'Under',
'symbol' => 'Symbol',
'code' => 'Code',
'iban' => 'IBAN',
'accountNumber' => 'Account number',
'csv' => 'CSV file',
'has_headers' => 'Headers',
'date_format' => 'Date format',
'csv_config' => 'CSV import configuration',
'specifix' => 'Bank- or file specific fixes',
'csv_import_account' => 'Default import account',
'csv_delimiter' => 'CSV field delimiter',
'attachments[]' => 'Attachments',
'store_new_withdrawal' => 'Store new withdrawal',
'store_new_deposit' => 'Store new deposit',
'store_new_transfer' => 'Store new transfer',
'add_new_withdrawal' => 'Add a new withdrawal',
'add_new_deposit' => 'Add a new deposit',
'add_new_transfer' => 'Add a new transfer',
'noPiggybank' => '(no piggy bank)',
'title' => 'Title',
'notes' => 'Notes',
'filename' => 'File name',
'mime' => 'Mime type',
'size' => 'Size',
'trigger' => 'Trigger',
'stop_processing' => 'Stop processing',
'start_date' => 'Start of range',
'end_date' => 'End of range',
'export_start_range' => 'Start of export range',
'export_end_range' => 'End of export range',
'export_format' => 'File format',
'include_attachments' => 'Include uploaded attachments',
'include_config' => 'Include configuration file',
'include_old_uploads' => 'Include imported data',
'accounts' => 'Export transactions from these accounts',
'csv_comma' => 'A comma (,)',
'csv_semicolon' => 'A semicolon (;)',
'csv_tab' => 'A tab (invisible)',
'delete_account' => 'Delete account ":name"',
'delete_bill' => 'Delete bill ":name"',
'delete_budget' => 'Delete budget ":name"',
'delete_category' => 'Delete category ":name"',
'delete_currency' => 'Delete currency ":name"',
'delete_journal' => 'Delete transaction with description ":description"',
'delete_attachment' => 'Delete attachment ":name"',
'delete_rule' => 'Delete rule ":title"',
'delete_rule_group' => 'Delete rule group ":title"',
'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?',
'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?',
'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?',
'rule_areYouSure' => 'Are you sure you want to delete the rule titled ":title"?',
'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titled ":title"?',
'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?',
'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?',
'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?',
'piggyBank_areYouSure' => 'Are you sure you want to delete the piggy bank named ":name"?',
'journal_areYouSure' => 'Are you sure you want to delete the transaction described ":description"?',
'mass_journal_are_you_sure' => 'Are you sure you want to delete these transactions?',
'tag_areYouSure' => 'Are you sure you want to delete the tag ":tag"?',
'permDeleteWarning' => 'Deleting stuff from Firely is permanent and cannot be undone.',
'mass_make_selection' => 'You can still prevent items from being deleted by removing the checkbox.',
'delete_all_permanently' => 'Delete selected permanently',
'update_all_journals' => 'Update these transactions',
'also_delete_transactions' => 'The only transaction connected to this account will be deleted as well.|All :count transactions connected to this account will be deleted as well.',
'also_delete_rules' => 'The only rule connected to this rule group will be deleted as well.|All :count rules connected to this rule group will be deleted as well.',
'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.|All :count piggy bank connected to this account will be deleted as well.',
'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill will spared deletion.',
'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.|All :count transactions connected to this budget will spared deletion.',
'category_keep_transactions' => 'The only transaction connected to this category will not be deleted.|All :count transactions connected to this category will spared deletion.',
'tag_keep_transactions' => 'The only transaction connected to this tag will not be deleted.|All :count transactions connected to this tag will spared deletion.',
];

View File

@ -4,37 +4,13 @@
{{ Breadcrumbs.renderIfExists }}
{% endblock %}
{% block content %}
{{ Form.open({'class' : 'form-horizontal','id' : 'store','url' : route('split.journal.from-store.post')}) }}
<input type="hidden" name="what" value="{{ preFilled.what }}"/>
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ ('split_title_'~preFilled.what)|_ }}</h3>
<form method="POST" action="{{ route('split.journal.store',journal.id) }}" accept-charset="UTF-8" class="form-horizontal" id="update"
enctype="multipart/form-data">
<input name="_token" type="hidden" value="{{ csrf_token() }}">
<input type="hidden" name="id" value="{{ journal.id }}"/>
<input type="hidden" name="what" value="{{ preFilled.what }}"/>
<div class="box-tools pull-right">
<button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
</div>
</div>
<div class="box-body">
<p>
{{ ('split_intro_one_'~preFilled.what)|_ }}
</p>
<p>
{{ ('split_intro_two_'~preFilled.what)|_ }}
</p>
<p>
{% if preFilled.what =='deposit' %}
{{ trans(('firefly.split_intro_three_'~preFilled.what), {total: 500|formatAmount, split_one: 425|formatAmount, split_two: 75|formatAmount})|raw }}
{% else %}
{{ trans(('firefly.split_intro_three_'~preFilled.what), {total: 20|formatAmount, split_one: 15|formatAmount, split_two: 5|formatAmount})|raw }}
{% endif %}
</p>
<p class="text-danger">This feature is experimental.</p>
</div>
</div>
</div>
</div>
{% if errors.all()|length > 0 %}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
@ -67,20 +43,19 @@
</div>
</div>
<div class="box-body">
{{ ExpandedForm.text('journal_description') }}
{{ ExpandedForm.select('journal_currency_id', currencies, preFilled.journal_currency_id) }}
{{ ExpandedForm.staticText('journal_amount', preFilled.journal_amount|formatAmount) }}
{{ ExpandedForm.text('journal_description', journal.description) }}
{{ ExpandedForm.select('journal_currency_id', currencies, journal.transaction_currency_id) }}
{{ ExpandedForm.staticText('journal_amount', preFilled.journal_amount|formatAmount ) }}
<input type="hidden" name="journal_amount" value="{{ preFilled.journal_amount }}"/>
<!-- show source drop down box if withdrawal or transfer -->
<!-- show source if withdrawal or transfer -->
{% if preFilled.what == 'withdrawal' or preFilled.what == 'transfer' %}
{{ ExpandedForm.select('journal_source_account_id', assetAccounts, preFilled.journal_source_account_id) }}
{% endif %}
<!-- show source text input if deposit: -->
<!-- show static source if deposit: -->
{% if preFilled.what == 'deposit' %}
{{ ExpandedForm.text('journal_source_account_name', preFilled.journal_source_account_name) }}
{% endif %}
<!-- show destination drop down if transfer -->
<!-- show static destination if transfer -->
{% if preFilled.what == 'transfer' %}
{{ ExpandedForm.select('journal_destination_account_id', assetAccounts, preFilled.journal_destination_account_id) }}
{% endif %}
@ -97,15 +72,16 @@
</div>
</div>
<div class="box-body">
{{ ExpandedForm.date('date', preFilled.date) }}
{{ ExpandedForm.date('date', journal.date) }}
{{ ExpandedForm.date('interest_date', preFilled.interest_date) }}
{{ ExpandedForm.date('interest_date', journal.interest_date) }}
{{ ExpandedForm.date('book_date', preFilled.book_date) }}
{{ ExpandedForm.date('book_date', journal.book_date) }}
{{ ExpandedForm.date('process_date', preFilled.process_date) }}
{{ ExpandedForm.date('process_date', journal.process_date) }}
</div>
</div>
</div>
</div>
<div class="row">
@ -119,22 +95,11 @@
</div>
</div>
<div class="box-body">
<p>
{{ ('split_table_intro_'~preFilled.what)|_ }}
</p>
<table class="table table-bordered table-condensed table-striped split-table">
<thead>
<tr>
<th>{{ trans('list.split_number') }}</th>
<th>{{ trans('list.description') }}</th>
<!-- split the source of a deposit -->
<!--
{% if preFilled.what == 'deposit' %}
<th>{{ trans('list.source') }}</th>
{% endif %}
-->
<!-- split where a withdrawal is going -->
<!-- split where a deposit is going -->
{% if preFilled.what == 'withdrawal' or preFilled.what == 'deposit' %}
<th>{{ trans('list.destination') }}</th>
{% endif %}
@ -175,7 +140,15 @@
</td>
{% if preFilled.what == 'withdrawal' %}
<td>
{{ Form.select('budget_id[]', budgets, preFilled.budget_id[index], {class: 'form-control'}) }}
<select class="form-control" name="budget_id[]">
{% for key, budget in budgets %}
<option label="{{ budget }}" value="{{ key }}"
{% if preFilled.budget_id[index] == key %}
selected="selected"
{% endif %}
>{{ budget }}</option>
{% endfor %}
</select>
</td>
{% endif %}
<td>
@ -189,11 +162,40 @@
<br/>
<a href="#" class="btn btn-default btn-do-split"><i class="fa fa-plus-circle"></i> {{ 'add_another_split'|_ }}</a>
</p>
<p class="pull-right">
<!--<p class="pull-right">
<button type="submit" id="transaction-btn" class="btn btn-success pull-right">
{{ ('store_splitted_'~preFilled.what)|_ }}
{{ ('update_splitted_'~preFilled.what)|_ }}
</button>
</p>
-->
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'optionalFields'|_ }}</h3>
</div>
<div class="box-body">
<!-- ATTACHMENTS -->
{{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }}
</div>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<!-- panel for options -->
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'options'|_ }}</h3>
</div>
<div class="box-body">
{{ ExpandedForm.optionsList('create','split-transaction') }}
</div>
<div class="box-footer">
<button type="submit" class="pull-right btn btn-success">{{ ('store_' ~ preFilled.what)|_ }}</button>
</div>
</div>
</div>

View File

@ -47,14 +47,17 @@
{{ ExpandedForm.select('journal_currency_id', currencies, preFilled.transaction_currency_id) }}
{{ ExpandedForm.staticText('journal_amount', preFilled.journal_amount|formatAmount ) }}
<input type="hidden" name="journal_amount" value="{{ preFilled.journal_amount }}"/>
<!-- show source if withdrawal or transfer -->
{% if preFilled.what == 'withdrawal' or preFilled.what == 'transfer' %}
{{ ExpandedForm.select('journal_source_account_id', assetAccounts, preFilled.journal_source_account_id) }}
{% endif %}
<!-- show static source if deposit: -->
{% if preFilled.what == 'deposit' %}
{{ ExpandedForm.text('journal_source_account_name', preFilled.journal_source_account_name) }}
{% endif %}
<!-- show static destination if transfer -->
{% if preFilled.what == 'transfer' %}
{{ ExpandedForm.select('journal_destination_account_id', assetAccounts, preFilled.journal_destination_account_id) }}
@ -100,25 +103,19 @@
<tr>
<th>{{ trans('list.split_number') }}</th>
<th>{{ trans('list.description') }}</th>
<!-- split the source of a deposit -->
<!--
{% if preFilled.what == 'deposit' %}
<th>{{ trans('list.source') }}</th>
{% endif %}
-->
<!-- split where a withdrawal is going -->
<!-- split where a deposit is going -->
<!-- withdrawal and deposit have a destination. -->
{% if preFilled.what == 'withdrawal' or preFilled.what == 'deposit' %}
<th>{{ trans('list.destination') }}</th>
{% endif %}
<th>{{ trans('list.amount') }}</th>
<!-- only withdrawal has budget -->
{% if preFilled.what == 'withdrawal' %}
<th>{{ trans('list.budget') }}</th>
{% endif %}
<th>{{ trans('list.category') }}</th>
{% if preFilled.what == 'transfer' %}
<th>{{ trans('list.piggy_bank') }}</th>
{% endif %}
</tr>
</thead>
<tbody>
@ -165,11 +162,6 @@
<td>
<input type="text" name="category[]" value="{{ preFilled.category[index] }}" class="form-control"/>
</td>
{% if preFilled.what == 'transfer' %}
<td>
{{ Form.select('piggy_bank_id[]', piggyBanks, preFilled.piggy_bank_id[index], {class: 'form-control'}) }}
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>

View File

@ -0,0 +1,206 @@
{% extends "./layout/default.twig" %}
{% block breadcrumbs %}
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, journal) }}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">Metadata</h3>
</div>
<div class="box-body table-responsive no-padding">
<table class="table table-hover sortable">
<tr>
<td>{{ trans('list.date') }}</td>
<td>{{ journal.date.formatLocalized(monthAndDayFormat) }}</td>
</tr>
{% if journal.interest_date %}
<tr>
<td>{{ trans('list.interest_date') }}</td>
<td>{{ journal.interest_date.formatLocalized(monthAndDayFormat) }}</td>
</tr>
{% endif %}
{% if journal.book_date %}
<tr>
<td>{{ trans('list.book_date') }}</td>
<td>{{ journal.book_date.formatLocalized(monthAndDayFormat) }}</td>
</tr>
{% endif %}
{% if journal.process_date %}
<tr>
<td>{{ trans('list.process_date') }}</td>
<td>{{ journal.process_date.formatLocalized(monthAndDayFormat) }}</td>
</tr>
{% endif %}
<tr>
<td>{{ trans('list.type') }}</td>
<td>{{ journal.transactiontype.type|_ }}</td>
</tr>
<tr>
<td>{{ trans('list.completed') }}</td>
<td>
{% if journal.completed %}
<span class="text-success">{{ 'yes'|_ }}</span>
{% else %}
<span class="text-danger">{{ 'no'|_ }}</span>
{% endif %}
</td>
</tr>
{% for budget in journal.budgets %}
<tr>
<td>{{ 'budget'|_ }}</td>
<td><a href="{{ route('budgets.show',budget.id) }}">{{ budget.name }}</a></td>
</tr>
{% endfor %}
{% for category in journal.categories %}
<tr>
<td>{{ 'category'|_ }}</td>
<td><a href="{{ route('categories.show',category.id) }}">{{ category.name }}</a></td>
</tr>
{% endfor %}
{% if journal.bill %}
<tr>
<td>{{ 'bill'|_ }}</td>
<td><a href="{{ route('bills.show', journal.bill_id) }}">{{ journal.bill.name }}</a></td>
</tr>
{% endif %}
{% if journal.tags|length > 0 %}
<tr>
<td>{{ 'tags'|_ }}</td>
<td>
{% for tag in journal.tags %}
<h4 style="display: inline;"><a class="label label-success" href="{{ route('tags.show',tag) }}">
{% if tag.tagMode == 'nothing' %}
<i class="fa fa-fw fa-tag"></i>
{% endif %}
{% if tag.tagMode == 'balancingAct' %}
<i class="fa fa-fw fa-refresh"></i>
{% endif %}
{% if tag.tagMode == 'advancePayment' %}
<i class="fa fa-fw fa-sort-numeric-desc"></i>
{% endif %}
{{ tag.tag }}</a>
</h4>
{% endfor %}
</td>
</tr>
{% endif %}
</table>
</div>
<div class="box-footer">
<div class="pull-right">
<a class="btn btn-default" href="{{ route('transactions.edit',journal.id) }}">{{ 'edit'|_ }}</a>
<a href="{{ route('transactions.delete',journal.id) }}" class="btn btn-danger">{{ 'delete'|_ }}</a>
</div>
</div>
</div>
<!-- events, if present -->
{% if journal.piggyBankEvents|length > 0 %}
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'piggyBanks'|_ }}</h3>
</div>
<div class="box-body">
{% include 'list/piggy-bank-events' with {'events': events, 'showPiggyBank':true} %}
</div>
</div>
{% endif %}
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
{% if journal.attachments|length > 0 %}
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'attachments'|_ }}</h3>
</div>
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
{% for att in journal.attachments %}
<tr>
<td>
<div class="btn-group btn-group-xs">
<a href="{{ route('attachments.edit', att.id) }}" class="btn btn-default"><i class="fa fa-pencil"></i></a>
<a href="{{ route('attachments.delete', att.id) }}" class="btn btn-danger"><i class="fa fa-trash"></i></a>
</div>
</td>
<td>
<i class="fa {{ att.mime|mimeIcon }}"></i>
<a href="{{ route('attachments.download', att.id) }}" title="{{ att.filename }}">
{% if att.title %}
{{ att.title }}
{% else %}
{{ att.filename }}
{% endif %}
</a>
({{ att.size|filesize }})
{% if att.description %}
<br/>
<em>{{ att.description }}</em>
{% endif %}
</td>
<td style="width:100px;">
<img src="{{ route('attachments.preview', att.id) }}"/>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endif %}
</div>
</div>
<!-- more than two transactions-->
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">Transactions</h3>
</div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>{{ trans('list.description') }}</th>
<th>{{ trans('list.account') }}</th>
<th>{{ trans('list.amount') }}</th>
<th>{{ trans('list.new_balance') }}</th>
<th>{{ trans('list.budget') }}</th>
<th>{{ trans('list.category') }}</th>
</tr>
</thead>
<tbody>
{% for index, t in transactions %}
<tr>
<td>
{% if (index+1) != transactions|length or what == 'transfer' %}
{{ t.description }}
{% endif %}
</td>
<td><a href="{{ route('accounts.show',t.account.id) }}">{{ t.account.name }}</a> ({{ t.account.accounttype.type|_ }})</td>
<td>{{ t.sum|formatAmount }}</td>
<td>{{ t.before|formatAmount }} &rarr; {{ (t.sum+t.before)|formatAmount }}</td>
<td>
{% if (index+1) != transactions|length or what == 'transfer' %}
{{ transactionBudgets(t)|raw }}
{% endif %}
</td>
<td>
{% if (index+1) != transactions|length or what == 'transfer' %}
{{ transactionCategories(t)|raw }}
{% endif %}
</td>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- end -->
{% endblock %}

View File

@ -101,7 +101,7 @@
</div>
<!-- attachments for unsplitted journals -->
{% if journal.attachments|length > 0 and transactions.count == 2 %}
{% if journal.attachments|length > 0 %}
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'attachments'|_ }}</h3>
@ -154,7 +154,6 @@
{% endif %}
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
{% if transactions.count == 2 %}
{% for t in transactions %}
<div class="box">
<div class="box-header with-border">
@ -199,100 +198,6 @@
</table>
</div>
{% endfor %}
{% endif %}
<!-- attachments for splitted journals -->
{% if journal.attachments|length > 0 and transactions.count > 2 %}
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'attachments'|_ }}</h3>
</div>
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
{% for att in journal.attachments %}
<tr>
<td>
<div class="btn-group btn-group-xs">
<a href="{{ route('attachments.edit', att.id) }}" class="btn btn-default"><i class="fa fa-pencil"></i></a>
<a href="{{ route('attachments.delete', att.id) }}" class="btn btn-danger"><i class="fa fa-trash"></i></a>
</div>
</td>
<td>
<i class="fa {{ att.mime|mimeIcon }}"></i>
<a href="{{ route('attachments.download', att.id) }}" title="{{ att.filename }}">
{% if att.title %}
{{ att.title }}
{% else %}
{{ att.filename }}
{% endif %}
</a>
({{ att.size|filesize }})
{% if att.description %}
<br/>
<em>{{ att.description }}</em>
{% endif %}
</td>
<td style="width:100px;">
<img src="{{ route('attachments.preview', att.id) }}"/>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endif %}
</div>
</div>
<!-- more than two transactions-->
{% if transactions.count > 2 %}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">Transactions</h3>
</div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>{{ trans('list.description') }}</th>
<th>{{ trans('list.account') }}</th>
<th>{{ trans('list.amount') }}</th>
<th>{{ trans('list.new_balance') }}</th>
<th>{{ trans('list.budget') }}</th>
<th>{{ trans('list.category') }}</th>
</tr>
</thead>
<tbody>
{% for index, t in transactions %}
<tr>
<td>
{% if (index+1) != transactions|length %}
{{ t.description }}
{% endif %}
</td>
<td><a href="{{ route('accounts.show',t.account.id) }}">{{ t.account.name }}</a> ({{ t.account.accounttype.type|_ }})</td>
<td>{{ t.sum|formatAmount }}</td>
<td>{{ t.before|formatAmount }} &rarr; {{ (t.sum+t.before)|formatAmount }}</td>
<td>
{% if (index+1) != transactions|length %}
{{ transactionBudgets(t)|raw }}
{% endif %}
</td>
<td>
{% if (index+1) != transactions|length %}
{{ transactionCategories(t)|raw }}
{% endif %}
</td>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
<!-- end -->
{% endblock %}

View File

@ -917,6 +917,47 @@
]
}
],
"multi-deposits": [],
"multi-deposits": [
{
"user_id": 1,
"date": "2016-03-02",
"description": "Even multi-deposit (50, 50)",
"source_ids": [
35,
36
],
"destination_id": 1,
"amounts": [
50,
50
],
"category_ids": [
7,
8,
9
]
},
{
"user_id": 1,
"date": "2016-05-02",
"description": "Uneven multi-deposit (15,34,51)",
"source_ids": [
35,
36,
37
],
"destination_id": 1,
"amounts": [
14,
35,
51
],
"category_ids": [
7,
8,
9
]
}
],
"multi-transfers": []
}