diff --git a/app/Crud/Split/Journal.php b/app/Crud/Split/Journal.php index 9315ba9193..bd0bfeb380 100644 --- a/app/Crud/Split/Journal.php +++ b/app/Crud/Split/Journal.php @@ -53,8 +53,8 @@ class Journal implements JournalInterface [ 'user_id' => $this->user->id, 'transaction_type_id' => $transactionType->id, - 'transaction_currency_id' => $data['currency_id'], - 'description' => $data['description'], + 'transaction_currency_id' => $data['journal_currency_id'], + 'description' => $data['journal_description'], 'completed' => 0, 'date' => $data['date'], 'interest_date' => $data['interest_date'], diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php index 913cd6cf97..62870495d3 100644 --- a/app/Http/Controllers/Transaction/SplitController.php +++ b/app/Http/Controllers/Transaction/SplitController.php @@ -19,8 +19,10 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; +use Illuminate\Http\Request; use Log; use Session; +use View; /** * Class SplitController @@ -32,8 +34,31 @@ class SplitController extends Controller /** * */ - public function journalFromStore() + public function __construct() { + parent::__construct(); + View::share('mainTitleIcon', 'fa-share-alt'); + View::share('title', trans('firefly.split-transactions')); + } + + + /** + * @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 */ @@ -45,20 +70,16 @@ class SplitController extends Controller /** @var PiggyBankRepositoryInterface $piggyBankRepository */ $piggyBankRepository = app(PiggyBankRepositoryInterface::class); - // expect data to be in session or in post? - $journalData = session('temporary_split_data'); + $currencies = ExpandedForm::makeSelectList($currencyRepository->get()); $assetAccounts = ExpandedForm::makeSelectList($accountRepository->getAccounts(['Default account', 'Asset account'])); $budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets()); $piggyBanks = ExpandedForm::makeSelectListWithEmpty($piggyBankRepository->getPiggyBanks()); - if (!is_array($journalData)) { - throw new FireflyException('Could not find transaction data in your session. Please go back and try again.'); // translate me. - } - Log::debug('Journal data', $journalData); + //Session::flash('warning', 'This feature is very experimental. Beware.'); - return view('split.journals.from-store', compact('currencies', 'piggyBanks', 'assetAccounts', 'budgets'))->with('data', $journalData); + return view('split.journals.from-store', compact('currencies', 'piggyBanks', 'assetAccounts', 'budgets'))->with('data', $preFilled); } @@ -77,6 +98,9 @@ class SplitController extends Controller $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) { $transactions = $repository->storeTransaction($journal, $transaction); } @@ -92,4 +116,74 @@ class SplitController extends Controller return redirect(session('transactions.create.url')); } + /** + * @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' => [], + 'piggy_bank_id' => [], + ]; + + // 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']; + $preFilled['piggy_bank_id'][] = $data['piggy_bank_id']; + + // echo '
'; + // var_dump($data); + // var_dump($preFilled); + // exit; + Log::debug('Prefilled', $preFilled); + + return $preFilled; + } + } \ No newline at end of file diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index 9aefd01b86..71871aabaa 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -30,6 +30,7 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use Illuminate\Support\Collection; use Input; +use Log; use Preferences; use Response; use Session; @@ -437,6 +438,7 @@ 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) { @@ -445,6 +447,7 @@ class TransactionController extends Controller return redirect(route('split.journal.from-store')); } + Log::debug('Not in split.'); // if not withdrawal, unset budgetid. if ($journalData['what'] != strtolower(TransactionType::WITHDRAWAL)) { @@ -493,6 +496,8 @@ class TransactionController extends Controller public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att, TransactionJournal $journal) { $journalData = $request->getJournalData(); + Log::debug('Will update journal ', $journal->toArray()); + Log::debug('Update related data ', $journalData); $repository->update($journal, $journalData); // save attachments: diff --git a/app/Http/Requests/SplitJournalFormRequest.php b/app/Http/Requests/SplitJournalFormRequest.php index aad2dd05ba..526fd30c45 100644 --- a/app/Http/Requests/SplitJournalFormRequest.php +++ b/app/Http/Requests/SplitJournalFormRequest.php @@ -35,26 +35,29 @@ class SplitJournalFormRequest extends Request public function getSplitData(): array { $data = [ - 'description' => $this->get('journal_description'), - 'currency_id' => intval($this->get('currency')), - 'source_account_id' => intval($this->get('source_account_id')), - 'source_account_name' => $this->get('source_account_name'), - 'date' => new Carbon($this->get('date')), - 'what' => $this->get('what'), - 'interest_date' => $this->get('interest_date') ? new Carbon($this->get('interest_date')) : null, - 'book_date' => $this->get('book_date') ? new Carbon($this->get('book_date')) : null, - 'process_date' => $this->get('process_date') ? new Carbon($this->get('process_date')) : null, - 'transactions' => [], + 'journal_description' => $this->get('journal_description'), + '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_name' => $this->get('journal_source_destination_name'), + 'date' => new Carbon($this->get('date')), + 'what' => $this->get('what'), + 'interest_date' => $this->get('interest_date') ? new Carbon($this->get('interest_date')) : null, + 'book_date' => $this->get('book_date') ? new Carbon($this->get('book_date')) : null, + 'process_date' => $this->get('process_date') ? new Carbon($this->get('process_date')) : null, + 'transactions' => [], ]; + // description is leading because it is one of the mandatory fields. foreach ($this->get('description') as $index => $description) { $transaction = [ 'description' => $description, 'amount' => round($this->get('amount')[$index], 2), - 'budget_id' => $this->get('budget')[$index] ? intval($this->get('budget')[$index]) : 0, + 'budget_id' => $this->get('budget_id')[$index] ? intval($this->get('budget_id')[$index]) : 0, 'category' => $this->get('category')[$index] ?? '', - 'source_account_id' => intval($this->get('source_account_id')), - 'source_account_name' => $this->get('source_account_name'), + 'source_account_id' => intval($this->get('journal_source_account_id')), + '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')), @@ -72,21 +75,23 @@ class SplitJournalFormRequest extends Request public function rules(): array { return [ - 'journal_description' => 'required|between:1,255', - 'currency' => 'required|exists:transaction_currencies,id', - 'source_account_id' => 'numeric|belongsToUser:accounts,id', - 'source_account_name.*' => 'between:1,255', - 'what' => 'required|in:withdrawal,deposit,transfer', - 'date' => 'required|date', - 'interest_date' => 'date', - 'book_date' => 'date', - 'process_date' => 'date', + 'what' => 'required|in:withdrawal,deposit,transfer', + 'journal_description' => 'required|between:1,255', + 'journal_source_account_id' => 'numeric|belongsToUser:accounts,id', + 'journal_source_account_name.*' => 'between:1,255', + 'journal_currency_id' => 'required|exists:transaction_currencies,id', + 'date' => 'required|date', + 'interest_date' => 'date', + 'book_date' => 'date', + 'process_date' => 'date', + 'description.*' => 'required|between:1,255', 'destination_account_id.*' => 'numeric|belongsToUser:accounts,id', 'destination_account_name.*' => 'between:1,255', 'amount.*' => 'required|numeric', - 'budget.*' => 'belongsToUser:budgets,id', + 'budget_id.*' => 'belongsToUser:budgets,id', 'category.*' => 'between:1,255', + 'piggy_bank_id.*' => 'between:1,255', ]; } } \ No newline at end of file diff --git a/app/Models/TransactionJournal.php b/app/Models/TransactionJournal.php index b6ed728650..6a16338f95 100644 --- a/app/Models/TransactionJournal.php +++ b/app/Models/TransactionJournal.php @@ -3,7 +3,6 @@ use Auth; use Carbon\Carbon; use Crypt; -use DB; use FireflyIII\Support\Models\TransactionJournalSupport; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -325,7 +324,6 @@ class TransactionJournal extends TransactionJournalSupport */ public function scopeExpanded(EloquentBuilder $query) { - $query->distinct(); // left join transaction type: if (!self::isJoined($query, 'transaction_types')) { $query->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'); @@ -336,39 +334,12 @@ class TransactionJournal extends TransactionJournalSupport // left join destination (for amount and account info). $query->leftJoin( - 'transactions as destination', function (JoinClause $join) { - $join->on('destination.transaction_journal_id', '=', 'transaction_journals.id') - ->where('destination.amount', '>', 0); + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '>', 0); } ); - // join destination account - $query->leftJoin('accounts as destination_account', 'destination_account.id', '=', 'destination.account_id'); - // join destination account type - $query->leftJoin('account_types as destination_acct_type', 'destination_account.account_type_id', '=', 'destination_acct_type.id'); - - // left join source (for amount and account info). - $query->leftJoin( - 'transactions as source', function (JoinClause $join) { - $join->on('source.transaction_journal_id', '=', 'transaction_journals.id') - ->where('source.amount', '<', 0); - } - ); - // join destination account - $query->leftJoin('accounts as source_account', 'source_account.id', '=', 'source.account_id'); - // join destination account type - $query->leftJoin('account_types as source_acct_type', 'source_account.account_type_id', '=', 'source_acct_type.id') - ->orderBy('transaction_journals.date', 'DESC')->orderBy('transaction_journals.order', 'ASC')->orderBy('transaction_journals.id', 'DESC'); - - // something else: - $query->where(DB::raw('`destination`.`amount` * -1'),'=',DB::raw('`source`.`amount`')); - - // group: $query->groupBy('transaction_journals.id'); - $query->groupBy('source.id'); - - $query->with(['categories', 'budgets', 'attachments', 'bill']); - - + $query->with(['categories', 'budgets', 'attachments', 'bill','transactions']); } /** diff --git a/app/Repositories/Account/AccountRepository.php b/app/Repositories/Account/AccountRepository.php index 44d9bee43f..198c9bd9b6 100644 --- a/app/Repositories/Account/AccountRepository.php +++ b/app/Repositories/Account/AccountRepository.php @@ -15,6 +15,7 @@ use FireflyIII\Models\TransactionType; use FireflyIII\User; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Query\JoinClause; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Log; @@ -232,23 +233,20 @@ class AccountRepository implements AccountRepositoryInterface */ public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end): Collection { - $set = $this->user + $query = $this->user ->transactionjournals() ->expanded() - ->where('source_account.id', $account->id) - // ->with(['transactions']) - // ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - // ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id) - // ->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transaction_journals.transaction_currency_id') - // ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') ->before($end) - ->after($start) - // ->orderBy('transaction_journals.date', 'DESC') - // ->orderBy('transaction_journals.order', 'ASC') - // ->orderBy('transaction_journals.id', 'DESC') - ->take(10) - // ->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']); - ->get(TransactionJournal::queryFields()); + ->after($start); + + // expand query: + $query->leftJoin( + 'transactions as source', function (JoinClause $join) { + $join->on('source.transaction_journal_id', '=', 'transaction_journals.id'); + } + )->where('source.account_id', $account->id); + + $set = $query->get(TransactionJournal::queryFields()); return $set; } @@ -290,13 +288,15 @@ class AccountRepository implements AccountRepositoryInterface $offset = ($page - 1) * $pageSize; $query = $this->user ->transactionJournals() - ->expanded() - ->where( - function (Builder $q) use ($account) { - $q->where('source_account.id', $account->id); - $q->orWhere('destination_account.id', $account->id); - } - ); + ->expanded(); + + // expand query: + $query->leftJoin( + 'transactions as source', function (JoinClause $join) { + $join->on('source.transaction_journal_id', '=', 'transaction_journals.id'); + } + )->where('source.account_id', $account->id); + $count = $query->count(); $set = $query->take($pageSize)->offset($offset)->get(TransactionJournal::queryFields()); diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 1e90caf829..c897a171f2 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -568,32 +568,9 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn public function getValidRepetitions(Budget $budget, Carbon $start, Carbon $end, LimitRepetition $ignore) : Collection { $query = $budget->limitrepetitions() - ->where( // valid when either of these are true: - function ($q) use ($start, $end) { - $q->where( - function ($query) use ($start, $end) { - // starts before start time, and the end also after start time. - $query->where('limit_repetitions.startdate', '<=', $start->format('Y-m-d 00:00:00')); - $query->where('limit_repetitions.enddate', '>=', $start->format('Y-m-d 00:00:00')); - } - ); - $q->orWhere( - function ($query) use ($start, $end) { - // end after end time, and start is before end time - $query->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00')); - $query->where('limit_repetitions.enddate', '>=', $end->format('Y-m-d 00:00:00')); - } - ); - // start is after start and end is before end - $q->orWhere( - function ($query) use ($start, $end) { - // end after end time, and start is before end time - $query->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00')); - $query->where('limit_repetitions.enddate', '<=', $end->format('Y-m-d 00:00:00')); - } - ); - } - ); + // starts before start time, and the end also after start time. + ->where('limit_repetitions.enddate', '>=', $start->format('Y-m-d 00:00:00')) + ->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00')); if (!is_null($ignore->id)) { $query->where('limit_repetitions.id', '!=', $ignore->id); } @@ -683,7 +660,7 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn } ) ->whereIn('transactions.account_id', $ids) - ->having('transaction_count', '=', 1) + //->having('transaction_count', '=', 1) TODO check if this still works ->transactionTypes([TransactionType::WITHDRAWAL]) ->first( [ diff --git a/app/Repositories/Category/SingleCategoryRepository.php b/app/Repositories/Category/SingleCategoryRepository.php index 3c6ba443ff..7918ceac72 100644 --- a/app/Repositories/Category/SingleCategoryRepository.php +++ b/app/Repositories/Category/SingleCategoryRepository.php @@ -10,6 +10,7 @@ use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Shared\ComponentRepository; use FireflyIII\User; +use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Collection; /** @@ -90,9 +91,16 @@ class SingleCategoryRepository extends ComponentRepository implements SingleCate ->after($start) ->groupBy('transaction_journals.date'); + $query->leftJoin( + 'transactions as destination', function (JoinClause $join) { + $join->on('destination.transaction_journal_id', '=', 'transaction_journals.id')->where('destination.amount', '>', 0); + } + ); + + if ($accounts->count() > 0) { $ids = $accounts->pluck('id')->toArray(); - $query->whereIn('destination_account.id', $ids); + $query->whereIn('destination.account.id', $ids); } $result = $query->get(['transaction_journals.date as dateFormatted', DB::raw('SUM(`destination`.`amount`) AS `sum`')]); @@ -258,13 +266,17 @@ class SingleCategoryRepository extends ComponentRepository implements SingleCate ->before($end) ->after($start) ->groupBy('transaction_journals.date'); + $query->leftJoin( + 'transactions as source', function (JoinClause $join) { + $join->on('source.transaction_journal_id', '=', 'transaction_journals.id')->where('source.amount', '<', 0); + } + ); if ($accounts->count() > 0) { $ids = $accounts->pluck('id')->toArray(); - $query->whereIn('source_account.id', $ids); + $query->whereIn('source.account_id', $ids); } - $result = $query->get(['transaction_journals.date as dateFormatted', DB::raw('SUM(`source`.`amount`) AS `sum`')]); $return = []; diff --git a/app/Repositories/Journal/JournalRepository.php b/app/Repositories/Journal/JournalRepository.php index b90617f5a5..617c87e9f8 100644 --- a/app/Repositories/Journal/JournalRepository.php +++ b/app/Repositories/Journal/JournalRepository.php @@ -336,31 +336,36 @@ class JournalRepository implements JournalRepositoryInterface { $sourceAccount = null; $destinationAccount = null; + Log::debug('Now in storeAccounts()'); switch ($type->type) { case TransactionType::WITHDRAWAL: + Log::debug('Now in storeAccounts()::withdrawal'); list($sourceAccount, $destinationAccount) = $this->storeWithdrawalAccounts($data); break; case TransactionType::DEPOSIT: + Log::debug('Now in storeAccounts()::deposit'); list($sourceAccount, $destinationAccount) = $this->storeDepositAccounts($data); break; case TransactionType::TRANSFER: + Log::debug('Now in storeAccounts()::transfer'); $sourceAccount = Account::where('user_id', $this->user->id)->where('id', $data['source_account_id'])->first(); $destinationAccount = Account::where('user_id', $this->user->id)->where('id', $data['destination_account_id'])->first(); break; default: throw new FireflyException('Did not recognise transaction type.'); } + Log::debug('Now in storeAccounts(), continued.'); if (is_null($destinationAccount)) { - Log::error('"to"-account is null, so we cannot continue!', ['data' => $data]); - throw new FireflyException('"to"-account is null, so we cannot continue!'); + Log::error('"destination"-account is null, so we cannot continue!', ['data' => $data]); + throw new FireflyException('"destination"-account is null, so we cannot continue!'); } if (is_null($sourceAccount)) { - Log::error('"from"-account is null, so we cannot continue!', ['data' => $data]); - throw new FireflyException('"from"-account is null, so we cannot continue!'); + Log::error('"source"-account is null, so we cannot continue!', ['data' => $data]); + throw new FireflyException('"source"-account is null, so we cannot continue!'); } @@ -402,8 +407,10 @@ class JournalRepository implements JournalRepositoryInterface private function storeWithdrawalAccounts(array $data): array { $sourceAccount = Account::where('user_id', $this->user->id)->where('id', $data['source_account_id'])->first(['accounts.*']); + Log::debug('Now in storeWithdrawalAccounts() with ', ['name' => $data['destination_account_name'], 'len' => strlen($data['destination_account_name'])]); if (strlen($data['destination_account_name']) > 0) { + Log::debug('Now in storeWithdrawalAccounts()'); $destinationType = AccountType::where('type', 'Expense account')->first(); $destinationAccount = Account::firstOrCreateEncrypted( [ @@ -413,6 +420,7 @@ class JournalRepository implements JournalRepositoryInterface 'active' => 1, ] ); + Log::debug('Errors: ', ['err' => $destinationAccount->getErrors()->toArray(), 'id' => $destinationAccount->id]); return [$sourceAccount, $destinationAccount]; } diff --git a/app/Support/Migration/TestData.php b/app/Support/Migration/TestData.php index c383da8e09..9a921e704d 100644 --- a/app/Support/Migration/TestData.php +++ b/app/Support/Migration/TestData.php @@ -367,7 +367,7 @@ class TestData public static function createExpenseAccounts(User $user): bool { $expenses = ['Adobe', 'Google', 'Vitens', 'Albert Heijn', 'PLUS', 'Apple', 'Bakker', 'Belastingdienst', 'bol.com', 'Cafe Central', 'conrad.nl', - 'Coolblue', 'Shell', + 'Coolblue', 'Shell', 'SixtyFive', 'EightyFour', 'Fiftyone', 'DUO', 'Etos', 'FEBO', 'Greenchoice', 'Halfords', 'XS4All', 'iCentre', 'Jumper', 'Land lord']; foreach ($expenses as $name) { // create account: diff --git a/app/Support/Models/TransactionJournalSupport.php b/app/Support/Models/TransactionJournalSupport.php index 71cea6ea8d..37e9a69603 100644 --- a/app/Support/Models/TransactionJournalSupport.php +++ b/app/Support/Models/TransactionJournalSupport.php @@ -56,8 +56,21 @@ class TransactionJournalSupport extends Model return $journal->destination_amount; } - $amount = $journal->transactions()->where('amount', '>', 0)->get()->sum('amount'); - if ($journal->isDeposit()) { + // saves on queries: + $amount = '0'; + if (count($journal->transactions) === 0) { + $amount = '0'; + foreach ($journal->transactions as $t) { + if ($t->amount > 0) { + $amount = bcadd($amount, $t->amount); + } + } + } + if ($amount === '0') { + $amount = $journal->transactions()->where('amount', '>', 0)->get()->sum('amount'); + } + + if ($journal->isWithdrawal()) { $amount = $amount * -1; } $amount = strval($amount); @@ -234,19 +247,8 @@ class TransactionJournalSupport extends Model 'transaction_journals.*', 'transaction_types.type AS transaction_type_type', // the other field is called "transaction_type_id" so this is pretty consistent. 'transaction_currencies.code AS transaction_currency_code', - // all for destination: - //'destination.amount AS destination_amount', // is always positive - DB::raw('SUM(`destination`.`amount`) as `destination_amount`'), - 'destination_account.id AS destination_account_id', - 'destination_account.name AS destination_account_name', - 'destination_acct_type.type AS destination_account_type', - // all for source: - //'source.amount AS source_amount', // is always negative - DB::raw('SUM(`source`.`amount`) as `source_amount`'), - 'source_account.id AS source_account_id', - 'source_account.name AS source_account_name', - 'source_acct_type.type AS source_account_type', - DB::raw('COUNT(`destination`.`id`) + COUNT(`source`.`id`) as `count_transactions`'), + DB::raw('SUM(`transactions`.`amount`) as `amount`'), + DB::raw('(COUNT(`transactions`.`id`) * 2) as `count_transactions`'), ]; } diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php index ba95ca1c4a..b7bb92b1bd 100644 --- a/app/Validation/FireflyValidator.php +++ b/app/Validation/FireflyValidator.php @@ -76,7 +76,9 @@ class FireflyValidator extends Validator { $field = $parameters[1] ?? 'id'; - + if (intval($value) === 0) { + return true; + } $count = DB::table($parameters[0])->where('user_id', Auth::user()->id)->where($field, $value)->count(); if ($count === 1) { return true; diff --git a/config/app.php b/config/app.php index 8ba2732c0d..0f9602b381 100644 --- a/config/app.php +++ b/config/app.php @@ -154,6 +154,7 @@ return [ /* * More service providers. */ + FireflyIII\Providers\CrudServiceProvider::class, FireflyIII\Providers\AccountServiceProvider::class, FireflyIII\Providers\AttachmentServiceProvider::class, FireflyIII\Providers\BillServiceProvider::class, diff --git a/database/seeds/SplitDataSeeder.php b/database/seeds/SplitDataSeeder.php index 96c350e993..1e4c864b8e 100644 --- a/database/seeds/SplitDataSeeder.php +++ b/database/seeds/SplitDataSeeder.php @@ -90,7 +90,7 @@ class SplitDataSeeder extends Seeder * Create splitted expense of 66,- */ $today = new Carbon; - $today->subDays(6); + $today->subDays(2); if (!$skipWithdrawal) { $journal = TransactionJournal::create( @@ -98,7 +98,7 @@ class SplitDataSeeder extends Seeder 'user_id' => $user->id, 'transaction_type_id' => 1, // withdrawal 'transaction_currency_id' => 1, - 'description' => 'Split Expense (journal)', + 'description' => 'Split Even Expense (journal (50/50))', 'completed' => 1, 'date' => $today->format('Y-m-d'), ] @@ -107,10 +107,11 @@ class SplitDataSeeder extends Seeder // split in 6 transactions (multiple destinations). 22,- each // source is TestData Checking Account. // also attach some budgets and stuff. - $destinations = ['Albert Heijn', 'PLUS', 'Apple']; - $budgets = ['Groceries', 'Groceries', 'Car']; - $categories = ['Bills', 'Bills', 'Car']; - $source = TestData::findAccount($user, 'Checking Account'); + $destinations = ['SixtyFive', 'EightyFour']; + $budgets = ['Groceries', 'Car']; + $categories = ['Bills', 'Bills']; + $amounts = [50, 50]; + $source = TestData::findAccount($user, 'Alternate Checking Account'); foreach ($destinations as $index => $dest) { $bud = $budgets[$index]; $cat = $categories[$index]; @@ -120,7 +121,7 @@ class SplitDataSeeder extends Seeder [ 'account_id' => $source->id, 'transaction_journal_id' => $journal->id, - 'amount' => '-22', + 'amount' => $amounts[$index] * -1, ] ); @@ -129,7 +130,7 @@ class SplitDataSeeder extends Seeder [ 'account_id' => $destination->id, 'transaction_journal_id' => $journal->id, - 'amount' => '22', + 'amount' => $amounts[$index], ] ); @@ -141,6 +142,57 @@ class SplitDataSeeder extends Seeder $two->categories()->save(TestData::findCategory($user, $cat)); } } + // AND ANOTHER ONE + $today->addDay(); + $journal = TransactionJournal::create( + [ + 'user_id' => $user->id, + 'transaction_type_id' => 1, // withdrawal + 'transaction_currency_id' => 1, + 'description' => 'Split Uneven Expense (journal (15/34/51=100))', + 'completed' => 1, + 'date' => $today->format('Y-m-d'), + ] + ); + + // split in 6 transactions (multiple destinations). 22,- each + // source is TestData Checking Account. + // also attach some budgets and stuff. + $destinations = ['SixtyFive', 'EightyFour', 'Fiftyone']; + $budgets = ['Groceries', 'Groceries', 'Car']; + $categories = ['Bills', 'Bills', 'Car']; + $amounts = [15, 34, 51]; + $source = TestData::findAccount($user, 'Checking Account'); + foreach ($destinations as $index => $dest) { + $bud = $budgets[$index]; + $cat = $categories[$index]; + $destination = TestData::findAccount($user, $dest); + + $one = Transaction::create( + [ + 'account_id' => $source->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amounts[$index] * -1, + + ] + ); + + $two = Transaction::create( + [ + 'account_id' => $destination->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amounts[$index], + + ] + ); + + $one->budgets()->save(TestData::findBudget($user, $bud)); + $two->budgets()->save(TestData::findBudget($user, $bud)); + + $one->categories()->save(TestData::findCategory($user, $cat)); + $two->categories()->save(TestData::findCategory($user, $cat)); + } + // create splitted income of 99,- $today->addDay(); diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000000..31ac89bcfe --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,31 @@ + ++ diff --git a/resources/views/split/journals/from-store.twig b/resources/views/split/journals/from-store.twig index 6f41cde1be..10e1f88d5c 100644 --- a/resources/views/split/journals/from-store.twig +++ b/resources/views/split/journals/from-store.twig @@ -73,18 +73,18 @@ {% if data.what == 'withdrawal' or data.what == 'transfer' %} - {{ ExpandedForm.staticText('asset_source_account', assetAccounts[data.journal_source_account_id]) }} - + {{ ExpandedForm.staticText('journal_asset_source_account', assetAccounts[data.journal_source_account_id]) }} + {% endif %} {% if data.what == 'deposit' %} {{ ExpandedForm.staticText('revenue_account', data.journal_source_account_name) }} - + {% endif %} {% if data.what == 'transfer' %} {{ ExpandedForm.staticText('asset_destination_account', assetAccounts[data.journal_destination_account_id]) }} - + {% endif %} diff --git a/tests/acceptance/Controllers/JsonControllerTest.php b/tests/acceptance/Controllers/JsonControllerTest.php index 140660f5f3..27e86491b0 100644 --- a/tests/acceptance/Controllers/JsonControllerTest.php +++ b/tests/acceptance/Controllers/JsonControllerTest.php @@ -155,11 +155,9 @@ class JsonControllerTest extends TestCase */ public function testTransactionJournals($range) { - $type = factory(FireflyIII\Models\TransactionType::class)->make(); $repository = $this->mock('FireflyIII\Repositories\Journal\JournalRepositoryInterface'); - - $repository->shouldReceive('getTransactionType')->with('deposit')->once()->andReturn($type); - $repository->shouldReceive('getJournalsOfType')->with($type)->once()->andReturn(new Collection); + $paginator = new \Illuminate\Pagination\LengthAwarePaginator(new Collection, 0, 40); + $repository->shouldReceive('getJournals')->withAnyArgs()->once()->andReturn($paginator); $this->be($this->user()); $this->changeDateRange($this->user(), $range); diff --git a/tests/acceptance/Controllers/TransactionControllerTest.php b/tests/acceptance/Controllers/TransactionControllerTest.php index 76223b68a5..a5ce3b5364 100644 --- a/tests/acceptance/Controllers/TransactionControllerTest.php +++ b/tests/acceptance/Controllers/TransactionControllerTest.php @@ -68,7 +68,7 @@ class TransactionControllerTest extends TestCase public function testIndex($range) { $journals = $this->mock('FireflyIII\Repositories\Journal\JournalRepositoryInterface'); - $journals->shouldReceive('getJournalsOfTypes')->once()->andReturn(new LengthAwarePaginator([], 0, 50)); + $journals->shouldReceive('getJournals')->once()->andReturn(new LengthAwarePaginator([], 0, 50)); $this->be($this->user()); $this->changeDateRange($this->user(), $range); @@ -117,8 +117,8 @@ class TransactionControllerTest extends TestCase $args = [ 'what' => 'withdrawal', 'description' => 'Something', - 'account_id' => '1', - 'expense_account' => 'Some expense', + 'source_account_id' => '1', + 'destination_account_name' => 'Some expense', 'amount' => 100, 'amount_currency_id_amount' => 1, 'date' => '2015-01-01', @@ -141,10 +141,10 @@ class TransactionControllerTest extends TestCase $args = [ 'what' => 'withdrawal', - 'id' => 2, + 'id' => 4, 'description' => 'Something new', - 'account_id' => '1', - 'expense_account' => 'Some expense', + 'source_account_id' => '1', + 'destination_account_name' => 'Some expense account', 'amount' => 100, 'amount_currency_id_amount' => 1, 'date' => '2015-01-01',+ ++ +./tests/ ++ ++ +app/ ++ + ++ + + + + ++