mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Updates to transactions.
This commit is contained in:
parent
0ef3d0cf03
commit
4af8272faa
@ -36,6 +36,7 @@ SEND_REGISTRATION_MAIL=true
|
|||||||
MUST_CONFIRM_ACCOUNT=false
|
MUST_CONFIRM_ACCOUNT=false
|
||||||
|
|
||||||
SHOW_INCOMPLETE_TRANSLATIONS=false
|
SHOW_INCOMPLETE_TRANSLATIONS=false
|
||||||
|
SHOW_DEMO_WARNING=false
|
||||||
|
|
||||||
ANALYTICS_ID=
|
ANALYTICS_ID=
|
||||||
RUNCLEANUP=true
|
RUNCLEANUP=true
|
||||||
|
64
app/Http/Controllers/Transaction/SplitController.php
Normal file
64
app/Http/Controllers/Transaction/SplitController.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SplitController.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\Http\Controllers\Transaction;
|
||||||
|
|
||||||
|
|
||||||
|
use ExpandedForm;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SplitController
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Http\Controllers\Transaction
|
||||||
|
*/
|
||||||
|
class SplitController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function journalFromStore()
|
||||||
|
{
|
||||||
|
/** @var CurrencyRepositoryInterface $currencyRepository */
|
||||||
|
$currencyRepository = app(CurrencyRepositoryInterface::class);
|
||||||
|
/** @var AccountRepositoryInterface $accountRepository */
|
||||||
|
$accountRepository = app(AccountRepositoryInterface::class);
|
||||||
|
|
||||||
|
/** @var BudgetRepositoryInterface $budgetRepository */
|
||||||
|
$budgetRepository = app(BudgetRepositoryInterface::class);
|
||||||
|
|
||||||
|
// expect data to be in session or in post?
|
||||||
|
$journalData = session('temporary_split_data');
|
||||||
|
$currency = $currencyRepository->find(intval($journalData['amount_currency_id_amount']));
|
||||||
|
$assetAccounts = ExpandedForm::makeSelectList($accountRepository->getAccounts(['Default account', 'Asset account']));
|
||||||
|
$budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
|
||||||
|
if (!is_array($journalData)) {
|
||||||
|
throw new FireflyException('Could not find transaction data in your session. Please go back and try again.'); // translate me.
|
||||||
|
}
|
||||||
|
// echo '<pre>';
|
||||||
|
// var_dump($journalData);
|
||||||
|
// echo '</pre>';
|
||||||
|
// exit;
|
||||||
|
|
||||||
|
return view('split.journals.from-store', compact('currency', 'assetAccounts', 'budgets'))->with('data', $journalData);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postJournalFromStore()
|
||||||
|
{
|
||||||
|
// forget temp journal data
|
||||||
|
// Session::forget('temporary_split_data');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -54,28 +54,26 @@ class TransactionController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create(ARI $repository, string $what = TransactionType::DEPOSIT)
|
public function create(ARI $repository, string $what = TransactionType::DEPOSIT)
|
||||||
{
|
{
|
||||||
$what = strtolower($what);
|
/** @var BudgetRepositoryInterface $budgetRepository */
|
||||||
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
|
$budgetRepository = app(BudgetRepositoryInterface::class);
|
||||||
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
|
|
||||||
$uploadSize = min($maxFileSize, $maxPostSize);
|
/** @var PiggyBankRepositoryInterface $piggyRepository */
|
||||||
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
$piggyRepository = app(PiggyBankRepositoryInterface::class);
|
||||||
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
|
|
||||||
$budgets[0] = trans('firefly.no_budget');
|
$what = strtolower($what);
|
||||||
$piggyBanks = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get();
|
$uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size')));
|
||||||
|
$assetAccounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
||||||
|
$budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
|
||||||
|
$piggyBanks = $piggyRepository->getPiggyBanks();
|
||||||
/** @var PiggyBank $piggy */
|
/** @var PiggyBank $piggy */
|
||||||
foreach ($piggyBanks as $piggy) {
|
foreach ($piggyBanks as $piggy) {
|
||||||
$piggy->name = $piggy->name . ' (' . Amount::format($piggy->currentRelevantRep()->currentamount, false) . ')';
|
$piggy->name = $piggy->name . ' (' . Amount::format($piggy->currentRelevantRep()->currentamount, false) . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
$piggies = ExpandedForm::makeSelectList($piggyBanks);
|
$piggies = ExpandedForm::makeSelectListWithEmpty($piggyBanks);
|
||||||
$piggies[0] = trans('form.noPiggybank');
|
$preFilled = Session::has('preFilled') ? session('preFilled') : [];
|
||||||
$preFilled = Session::has('preFilled') ? session('preFilled') : [];
|
$subTitle = trans('form.add_new_' . $what);
|
||||||
$respondTo = ['account_id', 'account_from_id'];
|
|
||||||
$subTitle = trans('form.add_new_' . $what);
|
|
||||||
|
|
||||||
foreach ($respondTo as $r) {
|
|
||||||
$preFilled[$r] = Input::get($r);
|
|
||||||
}
|
|
||||||
Session::put('preFilled', $preFilled);
|
Session::put('preFilled', $preFilled);
|
||||||
|
|
||||||
// put previous url in session if not redirect from store (not "create another").
|
// put previous url in session if not redirect from store (not "create another").
|
||||||
@ -89,7 +87,7 @@ class TransactionController extends Controller
|
|||||||
asort($piggies);
|
asort($piggies);
|
||||||
|
|
||||||
|
|
||||||
return view('transactions.create', compact('accounts', 'uploadSize', 'budgets', 'what', 'piggies', 'subTitle'));
|
return view('transactions.create', compact('assetAccounts', 'uploadSize', 'budgets', 'what', 'piggies', 'subTitle'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -430,7 +428,14 @@ class TransactionController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att)
|
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att)
|
||||||
{
|
{
|
||||||
|
$doSplit = intval($request->get('split_journal')) === 1;
|
||||||
$journalData = $request->getJournalData();
|
$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'));
|
||||||
|
}
|
||||||
|
|
||||||
// if not withdrawal, unset budgetid.
|
// if not withdrawal, unset budgetid.
|
||||||
if ($journalData['what'] != strtolower(TransactionType::WITHDRAWAL)) {
|
if ($journalData['what'] != strtolower(TransactionType::WITHDRAWAL)) {
|
||||||
|
@ -37,11 +37,10 @@ class JournalFormRequest extends Request
|
|||||||
return [
|
return [
|
||||||
'what' => $this->get('what'),
|
'what' => $this->get('what'),
|
||||||
'description' => $this->get('description'),
|
'description' => $this->get('description'),
|
||||||
'account_id' => intval($this->get('account_id')),
|
'source_account_id' => intval($this->get('source_account_id')),
|
||||||
'account_from_id' => intval($this->get('account_from_id')),
|
'source_account_name' => $this->get('source_account_name') ?? '',
|
||||||
'account_to_id' => intval($this->get('account_to_id')),
|
'account_destination_id' => intval($this->get('account_destination_id')),
|
||||||
'expense_account' => $this->get('expense_account') ?? '',
|
'destination_account_name' => $this->get('destination_account_name') ?? '',
|
||||||
'revenue_account' => $this->get('revenue_account') ?? '',
|
|
||||||
'amount' => round($this->get('amount'), 2),
|
'amount' => round($this->get('amount'), 2),
|
||||||
'user' => Auth::user()->id,
|
'user' => Auth::user()->id,
|
||||||
'amount_currency_id_amount' => intval($this->get('amount_currency_id_amount')),
|
'amount_currency_id_amount' => intval($this->get('amount_currency_id_amount')),
|
||||||
@ -70,28 +69,27 @@ class JournalFormRequest extends Request
|
|||||||
'process_date' => 'date',
|
'process_date' => 'date',
|
||||||
'book_date' => 'date',
|
'book_date' => 'date',
|
||||||
'interest_date' => 'date',
|
'interest_date' => 'date',
|
||||||
|
'category' => 'between:1,255',
|
||||||
'amount_currency_id_amount' => 'required|exists:transaction_currencies,id',
|
'amount_currency_id_amount' => 'required|exists:transaction_currencies,id',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
switch ($what) {
|
switch ($what) {
|
||||||
case strtolower(TransactionType::WITHDRAWAL):
|
case strtolower(TransactionType::WITHDRAWAL):
|
||||||
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
$rules['source_account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
||||||
$rules['expense_account'] = 'between:1,255';
|
$rules['destination_account_name'] = 'between:1,255';
|
||||||
$rules['category'] = 'between:1,255';
|
|
||||||
if (intval(Input::get('budget_id')) != 0) {
|
if (intval(Input::get('budget_id')) != 0) {
|
||||||
$rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets';
|
$rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case strtolower(TransactionType::DEPOSIT):
|
case strtolower(TransactionType::DEPOSIT):
|
||||||
$rules['category'] = 'between:1,255';
|
$rules['source_account_name'] = 'between:1,255';
|
||||||
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
$rules['destination_account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
||||||
$rules['revenue_account'] = 'between:1,255';
|
|
||||||
break;
|
break;
|
||||||
case strtolower(TransactionType::TRANSFER):
|
case strtolower(TransactionType::TRANSFER):
|
||||||
$rules['account_from_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_to_id';
|
$rules['source_account_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:destination_account_id';
|
||||||
$rules['account_to_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_from_id';
|
$rules['destination_account_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:source_account_id';
|
||||||
$rules['category'] = 'between:1,255';
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new FireflyException('Cannot handle transaction type of type ' . e($what) . '.');
|
throw new FireflyException('Cannot handle transaction type of type ' . e($what) . '.');
|
||||||
|
@ -342,6 +342,11 @@ Route::group(
|
|||||||
*/
|
*/
|
||||||
Route::get('/search', ['uses' => 'SearchController@index', 'as' => 'search']);
|
Route::get('/search', ['uses' => 'SearchController@index', 'as' => 'search']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split controller
|
||||||
|
*/
|
||||||
|
Route::get('/transaction/split', ['uses' => 'Transaction\SplitController@journalFromStore', 'as' => 'split.journal.from-store']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag Controller
|
* Tag Controller
|
||||||
*/
|
*/
|
||||||
|
@ -248,19 +248,19 @@ class JournalRepository implements JournalRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// store accounts (depends on type)
|
// store accounts (depends on type)
|
||||||
list($fromAccount, $toAccount) = $this->storeAccounts($transactionType, $data);
|
list($sourceAccount, $destinationAccount) = $this->storeAccounts($transactionType, $data);
|
||||||
|
|
||||||
// store accompanying transactions.
|
// store accompanying transactions.
|
||||||
Transaction::create( // first transaction.
|
Transaction::create( // first transaction.
|
||||||
[
|
[
|
||||||
'account_id' => $fromAccount->id,
|
'account_id' => $sourceAccount->id,
|
||||||
'transaction_journal_id' => $journal->id,
|
'transaction_journal_id' => $journal->id,
|
||||||
'amount' => $data['amount'] * -1,
|
'amount' => $data['amount'] * -1,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
Transaction::create( // second transaction.
|
Transaction::create( // second transaction.
|
||||||
[
|
[
|
||||||
'account_id' => $toAccount->id,
|
'account_id' => $destinationAccount->id,
|
||||||
'transaction_journal_id' => $journal->id,
|
'transaction_journal_id' => $journal->id,
|
||||||
'amount' => $data['amount'],
|
'amount' => $data['amount'],
|
||||||
]
|
]
|
||||||
@ -391,38 +391,38 @@ class JournalRepository implements JournalRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
protected function storeAccounts(TransactionType $type, array $data): array
|
protected function storeAccounts(TransactionType $type, array $data): array
|
||||||
{
|
{
|
||||||
$fromAccount = null;
|
$sourceAccount = null;
|
||||||
$toAccount = null;
|
$destinationAccount = null;
|
||||||
switch ($type->type) {
|
switch ($type->type) {
|
||||||
case TransactionType::WITHDRAWAL:
|
case TransactionType::WITHDRAWAL:
|
||||||
list($fromAccount, $toAccount) = $this->storeWithdrawalAccounts($data);
|
list($sourceAccount, $destinationAccount) = $this->storeWithdrawalAccounts($data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TransactionType::DEPOSIT:
|
case TransactionType::DEPOSIT:
|
||||||
list($fromAccount, $toAccount) = $this->storeDepositAccounts($data);
|
list($sourceAccount, $destinationAccount) = $this->storeDepositAccounts($data);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case TransactionType::TRANSFER:
|
case TransactionType::TRANSFER:
|
||||||
$fromAccount = Account::find($data['account_from_id']);
|
$sourceAccount = Account::find($data['account_from_id']);
|
||||||
$toAccount = Account::find($data['account_to_id']);
|
$destinationAccount = Account::find($data['account_to_id']);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new FireflyException('Did not recognise transaction type.');
|
throw new FireflyException('Did not recognise transaction type.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($toAccount)) {
|
if (is_null($destinationAccount)) {
|
||||||
Log::error('"to"-account is null, so we cannot continue!', ['data' => $data]);
|
Log::error('"to"-account is null, so we cannot continue!', ['data' => $data]);
|
||||||
throw new FireflyException('"to"-account is null, so we cannot continue!');
|
throw new FireflyException('"to"-account is null, so we cannot continue!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($fromAccount)) {
|
if (is_null($sourceAccount)) {
|
||||||
Log::error('"from"-account is null, so we cannot continue!', ['data' => $data]);
|
Log::error('"from"-account is null, so we cannot continue!', ['data' => $data]);
|
||||||
throw new FireflyException('"from"-account is null, so we cannot continue!');
|
throw new FireflyException('"from"-account is null, so we cannot continue!');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return [$fromAccount, $toAccount];
|
return [$sourceAccount, $destinationAccount];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -432,21 +432,22 @@ class JournalRepository implements JournalRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
protected function storeDepositAccounts(array $data): array
|
protected function storeDepositAccounts(array $data): array
|
||||||
{
|
{
|
||||||
$toAccount = Account::find($data['account_id']);
|
$destinationAccount = Account::where('user_id', $this->user->id)->where('id', $data['account_destination_id'])->first(['accounts.*']);
|
||||||
|
|
||||||
if (strlen($data['revenue_account']) > 0) {
|
if (strlen($data['source_account_name']) > 0) {
|
||||||
$fromType = AccountType::where('type', 'Revenue account')->first();
|
$fromType = AccountType::where('type', 'Revenue account')->first();
|
||||||
$fromAccount = Account::firstOrCreateEncrypted(
|
$fromAccount = Account::firstOrCreateEncrypted(
|
||||||
['user_id' => $data['user'], 'account_type_id' => $fromType->id, 'name' => $data['revenue_account'], 'active' => 1]
|
['user_id' => $data['user'], 'account_type_id' => $fromType->id, 'name' => $data['source_account_name'], 'active' => 1]
|
||||||
);
|
);
|
||||||
|
return [$fromAccount, $destinationAccount];
|
||||||
} else {
|
} else {
|
||||||
$toType = AccountType::where('type', 'Cash account')->first();
|
$fromType = AccountType::where('type', 'Cash account')->first();
|
||||||
$fromAccount = Account::firstOrCreateEncrypted(
|
$fromAccount = Account::firstOrCreateEncrypted(
|
||||||
['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1]
|
['user_id' => $data['user'], 'account_type_id' => $fromType->id, 'name' => 'Cash account', 'active' => 1]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [$fromAccount, $toAccount];
|
return [$fromAccount, $destinationAccount];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -456,20 +457,28 @@ class JournalRepository implements JournalRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
protected function storeWithdrawalAccounts(array $data): array
|
protected function storeWithdrawalAccounts(array $data): array
|
||||||
{
|
{
|
||||||
$fromAccount = Account::find($data['account_id']);
|
$sourceAccount = Account::where('user_id', $this->user->id)->where('id', $data['source_account_id'])->first(['accounts.*']);
|
||||||
|
|
||||||
if (strlen($data['expense_account']) > 0) {
|
if (strlen($data['destination_account_name']) > 0) {
|
||||||
$toType = AccountType::where('type', 'Expense account')->first();
|
$destinationType = AccountType::where('type', 'Expense account')->first();
|
||||||
$toAccount = Account::firstOrCreateEncrypted(
|
$destinationAccount = Account::firstOrCreateEncrypted(
|
||||||
['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => $data['expense_account'], 'active' => 1]
|
[
|
||||||
);
|
'user_id' => $data['user'],
|
||||||
} else {
|
'account_type_id' => $destinationType->id,
|
||||||
$toType = AccountType::where('type', 'Cash account')->first();
|
'name' => $data['destination_account_name'],
|
||||||
$toAccount = Account::firstOrCreateEncrypted(
|
'active' => 1,
|
||||||
['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return [$sourceAccount, $destinationAccount];
|
||||||
}
|
}
|
||||||
|
$destinationType = AccountType::where('type', 'Cash account')->first();
|
||||||
|
$destinationAccount = Account::firstOrCreateEncrypted(
|
||||||
|
['user_id' => $data['user'], 'account_type_id' => $destinationType->id, 'name' => 'Cash account', 'active' => 1]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [$sourceAccount, $destinationAccount];
|
||||||
|
|
||||||
|
|
||||||
return [$fromAccount, $toAccount];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ declare(strict_types = 1);
|
|||||||
namespace FireflyIII\Support;
|
namespace FireflyIII\Support;
|
||||||
|
|
||||||
use Amount as Amt;
|
use Amount as Amt;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Eloquent;
|
use Eloquent;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\MessageBag;
|
use Illuminate\Support\MessageBag;
|
||||||
@ -220,7 +221,7 @@ class ExpandedForm
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $set
|
* @param \Illuminate\Support\Collection $set
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@ -443,6 +444,9 @@ class ExpandedForm
|
|||||||
} catch (RuntimeException $e) {
|
} catch (RuntimeException $e) {
|
||||||
// don't care about session errors.
|
// don't care about session errors.
|
||||||
}
|
}
|
||||||
|
if ($value instanceof Carbon) {
|
||||||
|
$value = $value->format('Y-m-d');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
|
@ -8,9 +8,18 @@
|
|||||||
/* globals what:true, $, doSwitch, txt, middleCrumbName, title,button, middleCrumbUrl, piggiesLength, breadcrumbs */
|
/* globals what:true, $, doSwitch, txt, middleCrumbName, title,button, middleCrumbUrl, piggiesLength, breadcrumbs */
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
if ($('input[name="expense_account"]').length > 0) {
|
|
||||||
|
// the destination account name is always an expense account name.
|
||||||
|
if ($('input[name="destination_account_name"]').length > 0) {
|
||||||
$.getJSON('json/expense-accounts').done(function (data) {
|
$.getJSON('json/expense-accounts').done(function (data) {
|
||||||
$('input[name="expense_account"]').typeahead({source: data});
|
$('input[name="destination_account_name"]').typeahead({source: data});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// also for multi input
|
||||||
|
if ($('input[name="destination_account_name[]"]').length > 0) {
|
||||||
|
$.getJSON('json/expense-accounts').done(function (data) {
|
||||||
|
$('input[name="destination_account_name[]"]').typeahead({source: data});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,9 +36,16 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($('input[name="revenue_account"]').length > 0) {
|
// the source account name is always a revenue account name.
|
||||||
|
if ($('input[name="source_account_name"]').length > 0) {
|
||||||
$.getJSON('json/revenue-accounts').done(function (data) {
|
$.getJSON('json/revenue-accounts').done(function (data) {
|
||||||
$('input[name="revenue_account"]').typeahead({source: data});
|
$('input[name="source_account_name"]').typeahead({source: data});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// also for multi-input:
|
||||||
|
if ($('input[name="source_account_name[]"]').length > 0) {
|
||||||
|
$.getJSON('json/revenue-accounts').done(function (data) {
|
||||||
|
$('input[name="source_account_name[]"]').typeahead({source: data});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,10 +54,29 @@ $(document).ready(function () {
|
|||||||
$('input[name="description"]').typeahead({source: data});
|
$('input[name="description"]').typeahead({source: data});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// also for multi input:
|
||||||
|
if ($('input[name="description[]"]').length > 0 && what !== undefined) {
|
||||||
|
$.getJSON('json/transaction-journals/' + what).done(function (data) {
|
||||||
|
$('input[name="description[]"]').typeahead({source: data});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// and for the (rare) journal_description:
|
||||||
|
if ($('input[name="journal_description"]').length > 0 && what !== undefined) {
|
||||||
|
$.getJSON('json/transaction-journals/' + what).done(function (data) {
|
||||||
|
$('input[name="journal_description"]').typeahead({source: data});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ($('input[name="category"]').length > 0) {
|
if ($('input[name="category"]').length > 0) {
|
||||||
$.getJSON('json/categories').done(function (data) {
|
$.getJSON('json/categories').done(function (data) {
|
||||||
$('input[name="category"]').typeahead({source: data});
|
$('input[name="category"]').typeahead({source: data});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// also for multi input:
|
||||||
|
if ($('input[name="category[]"]').length > 0) {
|
||||||
|
$.getJSON('json/categories').done(function (data) {
|
||||||
|
$('input[name="category[]"]').typeahead({source: data});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
@ -33,43 +33,60 @@ function updateForm() {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
$('input[name="what"]').val(what);
|
$('input[name="what"]').val(what);
|
||||||
|
|
||||||
switch (what) {
|
switch (what) {
|
||||||
case 'withdrawal':
|
case 'withdrawal':
|
||||||
$('#account_id_holder').show();
|
// show source_id and dest_name:
|
||||||
$('#expense_account_holder').show();
|
$('#source_account_id_holder').show();
|
||||||
$('#revenue_account_holder').hide();
|
$('#destination_account_name_holder').show();
|
||||||
$('#account_from_id_holder').hide();
|
|
||||||
$('#account_to_id_holder').hide();
|
// hide others:
|
||||||
|
$('#source_account_name_holder').hide();
|
||||||
|
$('#destination_account_id_holder').hide();
|
||||||
|
|
||||||
|
// show budget:
|
||||||
$('#budget_id_holder').show();
|
$('#budget_id_holder').show();
|
||||||
|
|
||||||
|
// hide piggy bank:
|
||||||
$('#piggy_bank_id_holder').hide();
|
$('#piggy_bank_id_holder').hide();
|
||||||
|
|
||||||
|
// copy destination account name to
|
||||||
if ($('#ffInput_revenue_account').val().length > 0) {
|
// source account name:
|
||||||
$('#ffInput_expense_account').val($('#ffInput_revenue_account').val());
|
if ($('#ffInput_destination_account_name').val().length > 0) {
|
||||||
|
$('#ffInput_source_account_name').val($('#ffInput_destination_account_name').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'deposit':
|
case 'deposit':
|
||||||
$('#account_id_holder').show();
|
// show source_name and dest_id:
|
||||||
$('#expense_account_holder').hide();
|
$('#source_account_name_holder').show();
|
||||||
$('#revenue_account_holder').show();
|
$('#destination_account_id_holder').show();
|
||||||
$('#account_from_id_holder').hide();
|
|
||||||
$('#account_to_id_holder').hide();
|
// hide others:
|
||||||
|
$('#source_account_id_holder').hide();
|
||||||
|
$('#destination_account_name_holder').hide();
|
||||||
|
|
||||||
|
// hide budget
|
||||||
$('#budget_id_holder').hide();
|
$('#budget_id_holder').hide();
|
||||||
|
|
||||||
|
// hide piggy bank
|
||||||
$('#piggy_bank_id_holder').hide();
|
$('#piggy_bank_id_holder').hide();
|
||||||
|
|
||||||
if ($('#ffInput_expense_account').val().length > 0) {
|
if ($('#ffInput_source_account_name').val().length > 0) {
|
||||||
$('#ffInput_revenue_account').val($('#ffInput_expense_account').val());
|
$('#ffInput_destination_account_name').val($('#ffInput_source_account_name').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'transfer':
|
case 'transfer':
|
||||||
$('#account_id_holder').hide();
|
// show source_id and dest_id:
|
||||||
$('#expense_account_holder').hide();
|
$('#source_account_id_holder').show();
|
||||||
$('#revenue_account_holder').hide();
|
$('#destination_account_id_holder').show();
|
||||||
$('#account_from_id_holder').show();
|
|
||||||
$('#account_to_id_holder').show();
|
// hide others:
|
||||||
|
$('#source_account_name_holder').hide();
|
||||||
|
$('#destination_account_name_holder').hide();
|
||||||
|
|
||||||
|
|
||||||
|
// hide budget
|
||||||
$('#budget_id_holder').hide();
|
$('#budget_id_holder').hide();
|
||||||
if (piggiesLength === 0) {
|
if (piggiesLength === 0) {
|
||||||
$('#piggy_bank_id_holder').hide();
|
$('#piggy_bank_id_holder').hide();
|
||||||
|
@ -24,6 +24,8 @@ return [
|
|||||||
'repeat_freq' => 'Repeats',
|
'repeat_freq' => 'Repeats',
|
||||||
'account_from_id' => 'From account',
|
'account_from_id' => 'From account',
|
||||||
'account_to_id' => 'To account',
|
'account_to_id' => 'To account',
|
||||||
|
'asset_destination_account' => 'Asset account (destination)',
|
||||||
|
'asset_source_account' => 'Asset account (source)',
|
||||||
'account_id' => 'Asset account',
|
'account_id' => 'Asset account',
|
||||||
'budget_id' => 'Budget',
|
'budget_id' => 'Budget',
|
||||||
'openingBalance' => 'Opening balance',
|
'openingBalance' => 'Opening balance',
|
||||||
|
@ -31,3 +31,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if type == 'create' and name == 'transaction' %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ name }}_split" class="col-sm-4 control-label">
|
||||||
|
{{ trans('form.split_journal') }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="radio"><label>
|
||||||
|
{{ Form.checkbox('split_journal', '1', Input.old('split_journal') == '1', {'id': name ~ 'split'}) }}
|
||||||
|
{{ trans('form.split_journal_explanation') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
@ -2,6 +2,6 @@
|
|||||||
<label for="{{ options.id }}" class="col-sm-4 control-label">{{ label }}</label>
|
<label for="{{ options.id }}" class="col-sm-4 control-label">{{ label }}</label>
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<p class="form-control-static">{{ value }}</p>
|
<p class="form-control-static">{{ value|raw }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
166
resources/views/split/journals/from-store.twig
Normal file
166
resources/views/split/journals/from-store.twig
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
{% extends "./layout/default.twig" %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
{{ Breadcrumbs.renderIfExists }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<form method="POST" action="bla" accept-charset="UTF-8" class="form-horizontal" id="store" enctype="multipart/form-data">
|
||||||
|
<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 your new [type]</h3>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
Firefly supports the "splitting" of an [expense / withdrawal / transfer].
|
||||||
|
|
||||||
|
It means that the amount of money you've spent/earned/transfered is divided between
|
||||||
|
several source accounts, destination accounts or budgets.
|
||||||
|
|
||||||
|
Example for withdrawals: split your 20,- groceries so you pay 15,- from your "daily groceries" budget
|
||||||
|
and 5,- from your "cigarettes" budget.
|
||||||
|
|
||||||
|
Example for deposits: split your 500,- salary so that 450,- is categorized "salary" and 50,- is categorized "reimbursed expenses".
|
||||||
|
|
||||||
|
Example for transfers: split your 100,- transfer so that 50,- is put in the piggy bank "new couch" and 50,- is not.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6 col-md-6 col-sm-6">
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">Transaction meta-data</h3>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
{{ ExpandedForm.text('journal_description', data.description) }}
|
||||||
|
{{ ExpandedForm.staticText('amount', data.amount|formatAmount) }}
|
||||||
|
<!-- show static source if withdrawal or transfer -->
|
||||||
|
{% if data.what == 'withdrawal' or data.what == 'transfer' %}
|
||||||
|
{{ ExpandedForm.staticText('asset_source_account', assetAccounts[data.source_account_id]) }}
|
||||||
|
{% endif %}
|
||||||
|
<!-- show static destination if deposit or transfer -->
|
||||||
|
{% if data.what == 'deposit' or data.what == 'transfer' %}
|
||||||
|
{{ ExpandedForm.staticText('asset_destination_account', assetAccounts[data.destination_account_id]) }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6 col-md-6 col-sm-6">
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">Transaction dates</h3>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
{{ ExpandedForm.date('date', data.date) }}
|
||||||
|
|
||||||
|
{{ ExpandedForm.date('interest_date', data.interest_date) }}
|
||||||
|
|
||||||
|
{{ ExpandedForm.date('book_date', data.book_date) }}
|
||||||
|
|
||||||
|
{{ ExpandedForm.date('process_date', data.process_date) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<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">Splits</h3>
|
||||||
|
|
||||||
|
<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 your [x] in as many things as you want. By default the transaction will not split, there is just one entry.
|
||||||
|
Add as many splits as you want to, below. Remember that you should not deviate from your total amount. If you
|
||||||
|
do, Firefly will warn you but not correct you.
|
||||||
|
</p>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Split #</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<!-- split the source of a deposit -->
|
||||||
|
{% if data.what == 'deposit' %}
|
||||||
|
<th>Source</th>
|
||||||
|
{% endif %}
|
||||||
|
<!-- split where a withdrawal is going -->
|
||||||
|
{% if data.what == 'withdrawal' %}
|
||||||
|
<th>Destination</th>
|
||||||
|
{% endif %}
|
||||||
|
<th>Amount</th>
|
||||||
|
{% if data.what == 'withdrawal' %}
|
||||||
|
<th>Budget</th>
|
||||||
|
{% endif %}
|
||||||
|
<th>Category</th>
|
||||||
|
{% if data.what == 'transfer' %}
|
||||||
|
<th>Piggy bank</th>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr class="initial-row">
|
||||||
|
<td>#1</td>
|
||||||
|
<td>{{ Form.input('text', 'description[]', data.description, {class: 'form-control'}) }}</td>
|
||||||
|
{% if data.what == 'deposit' %}
|
||||||
|
<td>
|
||||||
|
{{ Form.input('text', 'source_account_name[]', data.source_account_name, {class: 'form-control'}) }}
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
{% if data.what == 'withdrawal' %}
|
||||||
|
<td>
|
||||||
|
{{ Form.input('text', 'destination_account_name[]', data.destination_account_name, {class: 'form-control'}) }}
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
<td style="width:10%;">
|
||||||
|
{{ ExpandedForm.amountSmall('amount[]', data.amount) }}
|
||||||
|
</td>
|
||||||
|
{% if data.what == 'withdrawal' %}
|
||||||
|
<td>
|
||||||
|
{{ Form.select('budget[]', budgets, data.budget_id, {class: 'form-control'}) }}
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
<td>
|
||||||
|
{{ Form.input('text', 'category[]', data.category, {class: 'form-control'}) }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
<a href="#" class="btn btn-success btn-do-split"><i class="fa fa-plus-circle"></i> Add another split</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
{% block scripts %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
var what = "{{ data.what }}";
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="js/lib/bootstrap3-typeahead.min.js"></script>
|
||||||
|
<script type="text/javascript" src="js/ff/transactions/create-edit.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
{% block styles %}
|
||||||
|
{% endblock %}
|
@ -32,20 +32,17 @@
|
|||||||
<!-- DESCRIPTION ALWAYS AVAILABLE -->
|
<!-- DESCRIPTION ALWAYS AVAILABLE -->
|
||||||
{{ ExpandedForm.text('description') }}
|
{{ ExpandedForm.text('description') }}
|
||||||
|
|
||||||
<!-- ACCOUNT ONLY FOR DEPOSITS AND WITHDRAWALS -->
|
<!-- SELECTABLE SOURCE ACCOUNT ONLY FOR WITHDRAWALS AND TRANSFERS -->
|
||||||
{{ ExpandedForm.select('account_id',accounts) }}
|
{{ ExpandedForm.select('source_account_id',assetAccounts, null, {label: trans('form.asset_source_account')}) }}
|
||||||
|
|
||||||
|
<!-- FREE FORMAT SOURCE ACCOUNT ONLY FOR DEPOSITS -->
|
||||||
|
{{ ExpandedForm.text('source_account_name',null, {label: trans('form.revenue_account')}) }}
|
||||||
|
|
||||||
<!-- SHOW EXPENSE ACCOUNT ONLY FOR WITHDRAWALS -->
|
<!-- FREE FORMAT DESTINATION ACCOUNT ONLY FOR EXPENSES -->
|
||||||
{{ ExpandedForm.text('expense_account') }}
|
{{ ExpandedForm.text('destination_account_name',null, {label: trans('form.expense_account')}) }}
|
||||||
|
|
||||||
<!-- SHOW REVENUE ACCOUNT ONLY FOR DEPOSITS -->
|
<!-- SELECTABLE DESTINATION ACCOUNT ONLY FOR TRANSFERS -->
|
||||||
{{ ExpandedForm.text('revenue_account') }}
|
{{ ExpandedForm.select('destination_account_id',assetAccounts, null, {label: trans('form.asset_destination_account')} ) }}
|
||||||
|
|
||||||
|
|
||||||
<!-- ONLY SHOW FROM/TO ACCOUNT WHEN CREATING TRANSFER -->
|
|
||||||
{{ ExpandedForm.select('account_from_id',accounts) }}
|
|
||||||
{{ ExpandedForm.select('account_to_id',accounts) }}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ALWAYS SHOW AMOUNT -->
|
<!-- ALWAYS SHOW AMOUNT -->
|
||||||
|
Loading…
Reference in New Issue
Block a user