Basic list, no functionalities.

This commit is contained in:
James Cole
2019-04-18 20:05:40 +02:00
parent 66c55b7bbe
commit 4d3af1dcde
15 changed files with 469 additions and 318 deletions

View File

@@ -115,10 +115,11 @@ class ApplyRules extends Command
return 1;
}
return 1;
// get transactions from asset accounts.
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
/** @var TODO REPLACE $collector */
//$collector = app();
$collector->setUser($this->getUser());
$collector->setAccounts($this->accounts);
$collector->setRange($this->startDate, $this->endDate);

View File

@@ -108,9 +108,10 @@ class ExpandedProcessor implements ProcessorInterface
*/
public function collectJournals(): bool
{
return true;
// use journal collector thing.
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
/** @var TODO replace me. $collector */
//$collector = app();
$collector->setUser($this->job->user);
$collector->setAccounts($this->accounts)->setRange($this->settings['startDate'], $this->settings['endDate'])
->withOpposingAccount()->withBudgetInformation()->withCategoryInformation()

View File

@@ -110,6 +110,7 @@ class GroupCollector implements GroupCollectorInterface
'source.amount as amount',
'source.transaction_currency_id as currency_id',
'currency.code as currency_code',
'currency.name as currency_name',
'currency.symbol as currency_symbol',
'currency.decimal_places as currency_decimal_places',
@@ -134,7 +135,7 @@ class GroupCollector implements GroupCollectorInterface
public function getExtractedJournals(): array
{
$selection = $this->getGroups();
$return = new Collection;
$return = [];
/** @var array $group */
foreach ($selection as $group) {
foreach ($group['transactions'] as $journalId => $journal) {
@@ -161,9 +162,8 @@ class GroupCollector implements GroupCollectorInterface
// now filter the array according to the page and the
$offset = $this->page * $this->limit;
$limited = $collection->slice($offset, $this->limit);
return $collection->slice($offset, $this->limit);
return $limited;
}
/**
@@ -552,10 +552,9 @@ class GroupCollector implements GroupCollectorInterface
$groupArray = [
'id' => $augmentedGroup->transaction_group_id,
'user_id' => $augmentedGroup->user_id,
'title' => $augmentedGroup->title,
'title' => $augmentedGroup->transaction_group_title,
'count' => 1,
'sum' => $augmentedGroup->amount,
'foreign_sum' => $augmentedGroup->foreign_amount ?? '0',
'sums' => [],
'transactions' => [],
];
$journalId = (int)$augmentedGroup->transaction_journal_id;
@@ -563,12 +562,12 @@ class GroupCollector implements GroupCollectorInterface
$groups[$groupId] = $groupArray;
continue;
}
// or parse the rest.
$journalId = (int)$augmentedGroup->transaction_journal_id;
$groups[$groupId]['count']++;
$groups[$groupId]['sum'] = bcadd($augmentedGroup->amount, $groups[$groupId]['sum']);
$groups[$groupId]['foreign_sum'] = bcadd($augmentedGroup->foreign_amount ?? '0', $groups[$groupId]['foreign_sum']);
$journalId = (int)$augmentedGroup->transaction_journal_id;
$groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedGroup($augmentedGroup);
}
$groups = $this->parseSums($groups);
return new Collection($groups);
}
@@ -590,6 +589,51 @@ class GroupCollector implements GroupCollectorInterface
return $result;
}
/**
* @param array $groups
*
* @return array
*/
private function parseSums(array $groups): array
{
/**
* @var int $groudId
* @var array $group
*/
foreach ($groups as $groudId => $group) {
/** @var array $transaction */
foreach ($group['transactions'] as $transaction) {
$currencyId = (int)$transaction['currency_id'];
// set default:
if (!isset($groups[$groudId]['sums'][$currencyId])) {
$groups[$groudId]['sums'][$currencyId]['currency_id'] = $currencyId;
$groups[$groudId]['sums'][$currencyId]['currency_code'] = $transaction['currency_code'];
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['currency_symbol'];
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['currency_decimal_places'];
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']);
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
$currencyId = (int)$transaction['foreign_currency_id'];
// set default:
if (!isset($groups[$groudId]['sums'][$currencyId])) {
$groups[$groudId]['sums'][$currencyId]['currency_id'] = $currencyId;
$groups[$groudId]['sums'][$currencyId]['currency_code'] = $transaction['foreign_currency_code'];
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['foreign_currency_symbol'];
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['foreign_currency_decimal_places'];
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['foreign_amount']);
}
}
}
return $groups;
}
/**
* Build the query.
*/

View File

@@ -89,7 +89,6 @@ class ShowController extends Controller
'decimal_places' => $transaction['currency_decimal_places'],
];
}
$amounts[$symbol]['amount'] = bcadd($amounts[$symbol]['amount'], $transaction['amount']);
if (null !== $transaction['foreign_amount']) {
// same for foreign currency:
@@ -101,8 +100,7 @@ class ShowController extends Controller
'decimal_places' => $transaction['foreign_currency_decimal_places'],
];
}
$amounts[$symbol]['amount'] = bcadd($amounts[$symbol]['amount'], $transaction['foreign_amount']);
$amounts[$foreignSymbol]['amount'] = bcadd($amounts[$foreignSymbol]['amount'], $transaction['foreign_amount']);
}
}
@@ -110,10 +108,6 @@ class ShowController extends Controller
$attachments = $this->repository->getAttachments($transactionGroup);
$links = $this->repository->getLinks($transactionGroup);
// TODO links to other journals, use the API
// TODO links to attachments, use the API.
// TODO links to piggy bank events.
return view(
'transactions.show', compact(
'transactionGroup', 'amounts', 'first', 'type', 'subTitle', 'splits', 'groupArray',

View File

@@ -25,27 +25,19 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\CountAttachmentsFilter;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Helpers\Filter\SplitIndicatorFilter;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Support\Http\Controllers\ModelInformation;
use FireflyIII\Support\Http\Controllers\PeriodOverview;
use FireflyIII\Transformers\TransactionTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Log;
use Symfony\Component\HttpFoundation\ParameterBag;
use View;
/**
* Class TransactionController.
@@ -114,18 +106,20 @@ class TransactionController extends Controller
$subTitle = (string)trans('firefly.title_' . $what . '_between', ['start' => $startStr, 'end' => $endStr]);
$periods = $this->getTransactionPeriodOverview($what, $end);
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)
->setTypes($types)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
->withBudgetInformation()->withCategoryInformation();
$collector->removeFilter(InternalTransferFilter::class);
$collector->addFilter(SplitIndicatorFilter::class);
$collector->addFilter(CountAttachmentsFilter::class);
$transactions = $collector->getPaginatedTransactions();
$transactions->setPath($path);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'transactions', 'periods', 'start', 'end'));
$collector->setRange($start, $end)
->setTypes($types)
->setLimit($pageSize)
->setPage($page)
->withBudgetInformation()
->withCategoryInformation()
->withAccountInformation();
$groups = $collector->getPaginatedGroups();
$groups->setPath($path);
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'groups', 'periods', 'start', 'end'));
}
/**
@@ -213,5 +207,4 @@ class TransactionController extends Controller
}
}

View File

@@ -60,6 +60,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property string foreign_amount
* @property int transaction_group_id
* @property int transaction_journal_id
* @property string transaction_group_title
*/
class TransactionGroup extends Model
{

View File

@@ -29,11 +29,16 @@ use DB;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\TransactionGroupFactory;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Note;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalLink;
use FireflyIII\Models\TransactionType;
use FireflyIII\Services\Internal\Update\GroupUpdateService;
use FireflyIII\Support\NullArrayObject;
use Illuminate\Database\Eloquent\Builder;
@@ -72,16 +77,15 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
$result = [];
/** @var Attachment $attachment */
foreach ($set as $attachment) {
$journalId = (int)$attachment->attachable_id;
$result[$journalId] = $result[$journalId] ?? [];
$current = $attachment->toArray();
$current['file_exists'] = true;
$current['journal_title'] = $attachment->attachable->description;
$result[] = $current;
$result[$journalId][] = $current;
}
//$result = $set->toArray();
return $result;
}
@@ -103,25 +107,34 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
$q->orWhereIn('destination_id', $journals);
}
)
->with(['source', 'destination'])
->with(['source', 'destination', 'source.transactions'])
->leftJoin('link_types', 'link_types.id', '=', 'journal_links.link_type_id')
->get(['journal_links.*', 'link_types.inward', 'link_types.outward']);
/** @var TransactionJournalLink $entry */
foreach ($set as $entry) {
$journalId = in_array($entry->source_id, $journals, true) ? $entry->source_id : $entry->destination_id;
$return[$journalId] = $return[$journalId] ?? [];
if ($journalId === $entry->source_id) {
$amount = $this->getFormattedAmount($entry->destination);
$foreignAmount = $this->getFormattedForeignAmount($entry->destination);
$return[$journalId][] = [
'link' => $entry->outward,
'group' => $entry->destination->transaction_group_id,
'description' => $entry->destination->description,
'link' => $entry->outward,
'group' => $entry->destination->transaction_group_id,
'description' => $entry->destination->description,
'amount' => $amount,
'foreign_amount' => $foreignAmount,
];
}
if ($journalId === $entry->destination_id) {
$amount = $this->getFormattedAmount($entry->source);
$foreignAmount = $this->getFormattedForeignAmount($entry->source);
$return[$journalId][] = [
'link' => $entry->inward,
'group' => $entry->source->transaction_group_id,
'description' => $entry->source->description,
'link' => $entry->inward,
'group' => $entry->source->transaction_group_id,
'description' => $entry->source->description,
'amount' => $amount,
'foreign_amount' => $foreignAmount,
];
}
}
@@ -210,7 +223,37 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
*/
public function getPiggyEvents(TransactionGroup $group): array
{
return [];
$return = [];
$journals = $group->transactionJournals->pluck('id')->toArray();
$data = PiggyBankEvent
::whereIn('transaction_journal_id', $journals)
->with('piggyBank', 'piggyBank.account')
->get(['piggy_bank_events.*']);
/** @var PiggyBankEvent $row */
foreach ($data as $row) {
// get currency preference.
$currencyPreference = AccountMeta
::where('account_id', $row->piggyBank->account_id)
->where('name', 'currency_id')
->first();
if (null !== $currencyPreference) {
$currency = TransactionCurrency::where('id', $currencyPreference->data)->first();
}
if (null === $currencyPreference) {
$currencyCode = app('preferences')->getForUser($this->user, 'currencyPreference', 'EUR')->data;
$currency = TransactionCurrency::where('code', $currencyCode)->first();
}
$journalId = (int)$row->transaction_journal_id;
$return[$journalId] = $return[$journalId] ?? [];
$return[$journalId][] = [
'piggy' => $row->piggyBank->name,
'piggy_id' => $row->piggy_bank_id,
'amount' => app('amount')->formatAnything($currency, $row->amount),
];
}
return $return;
}
/**
@@ -271,4 +314,54 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
return $updatedGroup;
}
/**
* @param TransactionJournal $journal
*
* @return string
*/
private function getFormattedAmount(TransactionJournal $journal): string
{
/** @var Transaction $transaction */
$transaction = $journal->transactions->first();
$currency = $transaction->transactionCurrency;
$type = $journal->transactionType->type;
$amount = app('steam')->positive($transaction->amount);
$return = '';
if (TransactionType::WITHDRAWAL === $type) {
$return = app('amount')->formatAnything($currency, app('steam')->negative($amount));
}
if (TransactionType::WITHDRAWAL !== $type) {
$return = app('amount')->formatAnything($currency, $amount);
}
return $return;
}
/**
* @param TransactionJournal $journal
*
* @return string
*/
private function getFormattedForeignAmount(TransactionJournal $journal): string
{
/** @var Transaction $transaction */
$transaction = $journal->transactions->first();
if (null === $transaction->foreign_amount) {
return '';
}
$currency = $transaction->foreignCurrency;
$type = $journal->transactionType->type;
$amount = app('steam')->positive($transaction->foreign_amount);
$return = '';
if (TransactionType::WITHDRAWAL === $type) {
$return = app('amount')->formatAnything($currency, app('steam')->negative($amount));
}
if (TransactionType::WITHDRAWAL !== $type) {
$return = app('amount')->formatAnything($currency, $amount);
}
return $return;
}
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Support\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\Account;
@@ -451,13 +452,12 @@ trait PeriodOverview
foreach ($dates as $currentDate) {
// get all expenses, income or transfers:
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($currentDate['start'], $currentDate['end'])->withOpposingAccount()->setTypes($types);
$collector->removeFilter(InternalTransferFilter::class);
$transactions = $collector->getTransactions();
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setRange($currentDate['start'], $currentDate['end'])->withAccountInformation()->setTypes($types);
$journals = $collector->getExtractedJournals();
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$grouped = $this->groupByCurrency($transactions);
$grouped = $this->groupByCurrency($journals);
$spent = [];
$earned = [];
$transferred = [];
@@ -472,7 +472,7 @@ trait PeriodOverview
}
$entries->push(
[
'transactions' => $transactions->count(),
'transactions' => count($journals),
'title' => $title,
'spent' => $spent,
'earned' => $earned,
@@ -525,27 +525,27 @@ trait PeriodOverview
}
/**
* @param Collection $transactions
* @param array $journals
*
* @return array
*/
private function groupByCurrency(Collection $transactions): array
private function groupByCurrency(array $journals): array
{
$return = [];
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$currencyId = (int)$transaction->transaction_currency_id;
/** @var array $journal */
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
if (!isset($return[$currencyId])) {
$currency = new TransactionCurrency;
$currency->symbol = $transaction->transaction_currency_symbol;
$currency->decimal_places = $transaction->transaction_currency_dp;
$currency->name = $transaction->transaction_currency_name;
$currency->symbol = $journal['currency_symbol'];
$currency->decimal_places = $journal['currency_decimal_places'];
$currency->name = $journal['currency_name'];
$return[$currencyId] = [
'amount' => '0',
'currency' => $currency,
];
}
$return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $transaction->transaction_amount);
$return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $journal['amount']);
}
return $return;

View File

@@ -34,8 +34,10 @@ use Twig_SimpleFunction;
*/
class TransactionGroupTwig extends Twig_Extension
{
/** @noinspection PhpMissingParentCallCommonInspection */
/**
* @return array
*
*/
public function getFunctions(): array
{
@@ -44,7 +46,7 @@ class TransactionGroupTwig extends Twig_Extension
$this->groupAmount(),
$this->journalHasMeta(),
$this->journalGetMetaDate(),
$this->journalGetMetaField()
$this->journalGetMetaField(),
];
}
@@ -55,15 +57,30 @@ class TransactionGroupTwig extends Twig_Extension
{
return new Twig_SimpleFunction(
'groupAmount',
function (array $array): string {
$result = $this->normalGroupAmount($array);
// now append foreign amount, if any.
if (0 !== bccomp('0', $array['foreign_sum'])) {
$foreign = $this->foreignGroupAmount($array);
$result = sprintf('%s (%s)', $result, $foreign);
static function (array $array): string {
$sums = $array['sums'];
$return = [];
$first = reset($array['transactions']);
$type = $first['transaction_type_type'] ?? TransactionType::WITHDRAWAL;
$colored = true;
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
return $result;
/** @var array $sum */
foreach ($sums as $sum) {
$amount = $sum['amount'];
// do multiplication thing.
if ($type !== TransactionType::WITHDRAWAL) {
$amount = bcmul($amount, '-1');
}
$return[] = app('amount')->formatFlat($sum['currency_symbol'], (int)$sum['currency_decimal_places'], $amount, $colored);
}
return implode(', ', $return);
},
['is_safe' => ['html']]
);
@@ -182,32 +199,6 @@ class TransactionGroupTwig extends Twig_Extension
return $result;
}
/**
* @param array $array
*
* @return string
*/
private function foreignGroupAmount(array $array): string
{
// take cue from the first entry in the array:
$first = $array['transactions'][0];
$type = $first['transaction_type_type'] ?? TransactionType::WITHDRAWAL;
$amount = $array['foreign_sum'] ?? '0';
$colored = true;
if ($type !== TransactionType::WITHDRAWAL) {
$amount = bcmul($amount, '-1');
}
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($first['foreign_currency_symbol'], (int)$first['foreign_currency_decimal_places'], $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
/**
* Generate normal amount for transaction from a transaction group.
*
@@ -233,30 +224,4 @@ class TransactionGroupTwig extends Twig_Extension
return $result;
}
/**
* @param array $array
*
* @return string
*/
private function normalGroupAmount(array $array): string
{
// take cue from the first entry in the array:
$first = reset($array['transactions']);
$type = $first['transaction_type_type'] ?? TransactionType::WITHDRAWAL;
$amount = $array['sum'] ?? '0';
$colored = true;
if ($type !== TransactionType::WITHDRAWAL) {
$amount = bcmul($amount, '-1');
}
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($first['currency_symbol'], (int)$first['currency_decimal_places'], $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
}

View File

@@ -176,8 +176,8 @@ class TransactionGroupTransformer extends AbstractTransformer
$foreignAmount = null;
if (null !== $source->foreign_amount) {
$foreignAmount = TransactionType::WITHDRAWAL !== $type
? app('steam')->positive($source->foreign_amount)
: app('steam')->negative($source->foreign_amount);
? app('steam')->negative($source->foreign_amount)
: app('steam')->positive($source->foreign_amount);
}
$metaFieldData = $this->groupRepos->getMetaFields($journal->id, $this->metaFields);

View File

@@ -33,7 +33,7 @@ return [
'last_seven_days' => 'Last seven days',
'last_thirty_days' => 'Last thirty days',
'welcomeBack' => 'What\'s playing?',
'welcome_back' => 'What\'s playing?',
'welcome_back' => 'What\'s playing?',
'everything' => 'Everything',
'today' => 'today',
'customRange' => 'Custom range',
@@ -634,9 +634,9 @@ return [
'converted_to_Transfer' => 'The transaction has been converted to a transfer',
'invalid_convert_selection' => 'The account you have selected is already used in this transaction or does not exist.',
'source_or_dest_invalid' => 'Cannot find the correct transaction details. Conversion is not possible.',
'convert_to_withdrawal' => 'Convert to a withdrawal',
'convert_to_deposit' => 'Convert to a deposit',
'convert_to_transfer' => 'Convert to a transfer',
'convert_to_withdrawal' => 'Convert to a withdrawal',
'convert_to_deposit' => 'Convert to a deposit',
'convert_to_transfer' => 'Convert to a transfer',
// create new stuff:
'create_new_withdrawal' => 'Create new withdrawal',
@@ -1148,6 +1148,7 @@ return [
'deleted_piggy_bank' => 'Deleted piggy bank ":name"',
'added_amount_to_piggy' => 'Added :amount to ":name"',
'removed_amount_from_piggy' => 'Removed :amount from ":name"',
'piggy_events' => 'Related piggy banks',
// tags
'delete_tag' => 'Delete tag ":tag"',
@@ -1160,7 +1161,7 @@ return [
'transaction_journal_information' => 'Transaction information',
'transaction_journal_meta' => 'Meta information',
'transaction_journal_more' => 'More information',
'att_part_of_journal' => 'Stored under ":journal"',
'att_part_of_journal' => 'Stored under ":journal"',
'total_amount' => 'Total amount',
'number_of_decimals' => 'Number of decimals',

View File

@@ -0,0 +1,98 @@
<table class="table">
<thead>
<tr>
<th>X</th>
</tr>
</thead>
<tbody>
{% for group in groups %}
{% if group.count > 1 %}
<tr>
<td colspan="2" style="border-top:1px #aaa solid;">
<small><strong>
<a href="{{ route('transactions.edit', [group.id]) }}" title="{{ group.title }}">{{ group.title }}</a>
</strong></small>
</td>
<td colspan="2" style="border-top:1px #aaa solid;">
{% for sum in group.sums %}
{{ formatAmountBySymbol(sum.amount, sum.currency_symbol, sum.currency_symbol_decimal_places) }}{% if loop.index != group.sums|length %},{% endif %}
{% endfor %}
</td>
<td colspan="2" style="border-top:1px #aaa solid;">&nbsp;</td>
<td style="border-top:1px #aaa solid;">
<div class="btn-group btn-group-xs">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ 'actions'|_ }} <span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
<li><a href="{{ route('transactions.edit', [group.id]) }}"><i class="fa fa-fw fa-pencil"></i> {{ 'edit'|_ }}</a></li>
<li><a href="{{ route('transactions.delete', [group.id]) }}"><i class="fa fa-fw fa-trash"></i> {{ 'delete'|_ }}</a></li>
<li><a href="{{ route('transactions.clone', [group.id]) }}"><i class="fa fa-copy fa-fw"></i> {{ 'clone'|_ }}</a></li>
</ul>
</div>
</td>
</tr>
{% endif %}
{% for index, transaction in group.transactions %}
{% set style="" %}
{% if group.transactions|length == loop.index and group.count > 1 %}
{% set style="style='border-bottom:1px #aaa solid;'" %}
{% endif %}
<tr>
<td {{ style|raw }}>
{% if transaction.transaction_type_type == 'Withdrawal' %}
<i class="fa fa-long-arrow-left fa-fw" title="{{ trans('firefly.Withdrawal') }}"></i>
{% endif %}
{% if transaction.transaction_type_type == 'Deposit' %}
<i class="fa fa-long-arrow-right fa-fw" title="{{ trans('firefly.Deposit') }}"></i>
{% endif %}
{% if transaction.transaction_type_type == 'Transfer' %}
<i class="fa fa-exchange fa-fw" title="{{ trans('firefly.Deposit') }}"></i>
{% endif %}
{% if transaction.transaction_type_type == 'Reconciliation' %}
XX
{% endif %}
{% if transaction.transaction_type_type == 'Opening balance' %}
XX
{% endif %}
</td>
<td {{ style|raw }}>
<a href="{{ route('transactions.edit', [group.id]) }}" title="{{ transaction.description }}">{{ transaction.description }}</a>
</td>
<td {{ style|raw }}>
{{ formatAmountBySymbol(transaction.amount, transaction.currency_symbol, transaction.currency_symbol_decimal_places) }}
{% if null != transaction.foreign_amount %}
({{ formatAmountBySymbol(transaction.foreign_amount, transaction.foreign_currency_symbol, transaction.foreign_currency_symbol_decimal_places) }})
{% endif %}
</td>
<td {{ style|raw }}>{{ transaction.date.formatLocalized(monthAndDayFormat) }}</td>
<td {{ style|raw }}>
<a href="{{ route('accounts.show', [transaction.source_account_id]) }}" title="{{ transaction.source_account_iban|default(transaction.source_account_name) }}">{{ transaction.source_account_name }}</a>
</td>
<td {{ style|raw }}>
<a href="{{ route('accounts.show', [transaction.destination_account_id]) }}" title="{{ transaction.destination_account_iban|default(transaction.destination_account_name) }}">{{ transaction.destination_account_name }}</a>
</td>
<td {{ style|raw }}>
{% if group.count == 1 %}
<div class="btn-group btn-group-xs">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ 'actions'|_ }} <span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
<li><a href="{{ route('transactions.edit', [group.id]) }}"><i class="fa fa-fw fa-pencil"></i> {{ 'edit'|_ }}</a></li>
<li><a href="{{ route('transactions.delete', [group.id]) }}"><i class="fa fa-fw fa-trash"></i> {{ 'delete'|_ }}</a></li>
<li><a href="{{ route('transactions.clone', [group.id]) }}"><i class="fa fa-copy fa-fw"></i> {{ 'clone'|_ }}</a></li>
</ul>
</div>
{% endif %}
</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>

View File

@@ -31,12 +31,7 @@
{% endif %}
</div>
{# actual list #}
{% if periods.count > 0 %}
{# page is not "all"-overview#}
{% include 'list.transactions' %}
{% else %}
{% include 'list.transactions' with {showCategories: true, showBudgets: true, showBill:true} %}
{% endif %}
{% include 'list.transactions' %}
</div>
<div class="box-footer">
{# links for other views #}

View File

@@ -39,20 +39,20 @@
</div>
<div class="box-footer">
<div class="btn-group btn-group-xs">
<a href="#" class="btn btn-default"><i class="fa fa-pencil"></i> {{ 'edit'|_ }}</a>
<a href="{{ route('transactions.edit', [transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-pencil"></i> {{ 'edit'|_ }}</a>
{% if type != 'Opening balance' and type != 'Reconciliation' %}
<a href="#" class="btn btn-default"><i class="fa fa-copy"></i> {{ 'clone'|_ }}</a>
<a href="{{ route('transactions.clone', [transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-copy"></i> {{ 'clone'|_ }}</a>
{% if type != 'Withdrawal' %}
<a href="#" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_withdrawal'|_ }}</a>
<a href="{{ route('transactions.convert', [transactionGroup.id, 'withdrawal']) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_withdrawal'|_ }}</a>
{% endif %}
{% if type != 'Deposit' %}
<a href="#" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_deposit'|_ }}</a>
<a href="{{ route('transactions.convert', [transactionGroup.id, 'deposit']) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_deposit'|_ }}</a>
{% endif %}
{% if type != 'Transfer' %}
<a href="#" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_transfer'|_ }}</a>
<a href="{{ route('transactions.convert', [transactionGroup.id, 'transfer']) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_transfer'|_ }}</a>
{% endif %}
{% endif %}
<a href="#" class="btn btn-danger"><i class="fa fa-trash"></i> {{ 'delete'|_ }}</a>
<a href="{{ route('transactions.delete', [transactionGroup.id]) }}" class="btn btn-danger"><i class="fa fa-trash"></i> {{ 'delete'|_ }}</a>
</div>
</div>
</div>
@@ -103,14 +103,12 @@
<td style="width:30%;">{{ 'total_amount'|_ }}</td>
<td>
{% for amount in amounts %}
{% if type == 'Withdrawal' %}
{{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }}
{% if type == 'Withdrawal' or type == 'Deposit' %}
{{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }},
{% elseif type == 'Transfer' %}
<span class="text-info">
{{ formatAmountBySymbol(amount.amount,amount.symbol, amount.decimal_places, false) }}
{{ formatAmountBySymbol(amount.amount, amount.symbol, amount.decimal_places, false) }},
</span>
{% else %}
{{ formatAmountBySymbol(amount.amount,amount.symbol, amount.decimal_places) }}
{% endif %}
{% endfor %}
</td>
@@ -125,11 +123,11 @@
</div>
{% if splits > 1 %}
<div class="row">
<div class="col-lg-12">
<h3>{{ 'splits'|_ }}</h3>
<div class="row">
<div class="col-lg-12">
<h3>{{ 'splits'|_ }}</h3>
</div>
</div>
</div>
{% endif %}
{% set boxSize=12 %}
{% if(splits == 2) %}
@@ -149,9 +147,9 @@
<i class="fa fa-check"></i>
{% endif %}
{% if splits > 1 %}
<small>
{{ index+1 }} / {{ splits }}
</small>
<small>
{{ index+1 }} / {{ splits }}
</small>
{% endif %}
</h3>
</div>
@@ -161,15 +159,26 @@
<td colspan="2">
<a href="{{ route('accounts.show', journal.source_id) }}"
title="{{ journal.source_iban|default(journal.source_name) }}">{{ journal.source_name }}</a> &rarr;
{% if type == 'Withdrawal' %}
{% if type == 'Withdrawal' or type == 'Deposit' %}
{{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places) }}
{% elseif type == 'Transfer' %}
<span class="text-info">
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places, false) }}
</span>
{% else %}
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places) }}
{% endif %}
<!-- do foreign amount -->
{% if null != journal.foreign_amount %}
{% if type == 'Withdrawal' or type == 'Deposit' %}
({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }})
{% elseif type == 'Transfer' %}
<span class="text-info">
({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places, false) }})
</span>
{% endif %}
{% endif %}
&rarr;
<a href="{{ route('accounts.show', journal.destination_id) }}"
title="{{ journal.destination_iban|default(journal.destination_name) }}">{{ journal.destination_name }}</a>
@@ -229,98 +238,125 @@
</td>
</tr>
{% endif %}
{% if links[journal.transaction_journal_id]|length > 0 %}
{% for link in links[journal.transaction_journal_id] %}
<tr>
<td colspan="2">{{ link.link }} "<a href="{{ route('transactions.show', link.group) }}" title="{{ link.description }}">{{ link.description }}</a></td>
</tr>
{% endfor %}
{% endif %}
</table>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="row">
<div class="col-lg-12">
<h3>But wait, there's more!</h3>
Transaction links, piggy bank events and attachments.
</div>
</div>
<!-- Transaction links -->
{% if links[journal.transaction_journal_id]|length > 0 %}
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">
{{ 'journal_links'|_ }}
</h3>
</div>
<div class="box-body no-padding">
<table class="table">
{% for link in links[journal.transaction_journal_id] %}
<tr>
<td style="width:30%;">
<div class="btn-group btn-group-xs">
<a href="#" class="btn btn-default"><i class="fa fa-pencil"></i></a>
<a href="#" class="btn btn-danger"><i class="fa fa-trash"></i></a>
</div>
</td>
<td>{{ link.link }} "<a href="{{ route('transactions.show', link.group) }}"
title="{{ link.description }}">{{ link.description }}</a>"
<div class="row">
<!-- attachments -->
{% if attachments|length > 0 %}
<div class="col-lg-6">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'attachments'|_ }}</h3>
({{ link.amount|raw }})
{% if '' != link.foreign_amount %}
({{ link.foreign_amount|raw }})
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
{% for attachment in attachments %}
<tr>
<td>
<div class="btn-group btn-group-xs">
<a href="{{ route('attachments.edit', attachment.id) }}" class="btn btn-default"><i class="fa fa-pencil"></i></a>
<a href="{{ route('attachments.delete', attachment.id) }}" class="btn btn-danger"><i class="fa fa-trash"></i></a>
{% endif %}
<!-- Attachments -->
{% if attachments[journal.transaction_journal_id]|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 attachment in attachments[journal.transaction_journal_id] %}
<tr>
<td style="width:30%;">
<div class="btn-group btn-group-xs">
<a href="{{ route('attachments.edit', attachment.id) }}" class="btn btn-default"><i
class="fa fa-pencil"></i></a>
<a href="{{ route('attachments.delete', attachment.id) }}" class="btn btn-danger"><i
class="fa fa-trash"></i></a>
{% if attachment.file_exists %}
<a href="{{ route('attachments.download', attachment.id) }}" class="btn btn-default"><i
class="fa fa-download"></i></a>
{% endif %}
{% if not attachment.file_exists %}
<a href="#" class="btn btn-danger"><i class="fa fa-exclamation-triangle"></i></a>
{% endif %}
</div>
</td>
<td>
{% if attachment.file_exists %}
<a href="{{ route('attachments.download', attachment.id) }}" class="btn btn-default"><i
class="fa fa-download"></i></a>
<i class="fa {{ attachment.mime|mimeIcon }}"></i>
<a href="{{ route('attachments.view', attachment.id) }}" title="{{ attachment.filename }}">
{% if attachment.title %}
{{ attachment.title }}
{% else %}
{{ attachment.filename }}
{% endif %}
</a>
({{ attachment.size|filesize }})
{% if null != attachment.notes and '' != attachment.notes %}
{{ attachment.notes|markdown }}
{% endif %}
{% endif %}
{% if not attachment.file_exists %}
<a href="#" class="btn btn-danger"><i class="fa fa-exclamation-triangle"></i></a>
{% endif %}
</div>
</td>
<td>
{% if attachment.file_exists %}
<i class="fa {{ attachment.mime|mimeIcon }}"></i>
<a href="{{ route('attachments.view', attachment.id) }}" title="{{ attachment.filename }}">
<i class="fa fa-fw fa-exclamation-triangle"></i>
{% if attachment.title %}
{{ attachment.title }}
{% else %}
{{ attachment.filename }}
{% endif %}
</a>
({{ attachment.size|filesize }})
{% if null != attachment.notes and '' != attachment.notes %}
{{ attachment.notes|markdown }}
<br>
<span class="text-danger">{{ 'attachment_not_found'|_ }}</span>
{% endif %}
{% endif %}
{% if not attachment.file_exists %}
<i class="fa fa-fw fa-exclamation-triangle"></i>
{% if attachment.title %}
{{ attachment.title }}
{% else %}
{{ attachment.filename }}
{% endif %}
<br>
<span class="text-danger">{{ 'attachment_not_found'|_ }}</span>
{% endif %}
{% if splits > 1 %}
<small><em><br/>{{ trans('firefly.att_part_of_journal',{journal: attachment.journal_title}) }}
</em></small>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
{% endif %}
<!-- Piggy bank events -->
{% if events[journal.transaction_journal_id]|length > 0 %}
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'piggy_events'|_ }}</h3>
</div>
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
{% for event in events[journal.transaction_journal_id] %}
<tr>
<td style="width:30%;">{{ event.amount|raw }}</td>
<td>
<a href="{{ route('piggy-banks.show', [event.piggy_id]) }}">{{ event.piggy }}</a></td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endif %}
</div>
{% endif %}
<!-- link -->
<div class="col-lg-4">
{% endfor %}
</div>
<!-- events -->
<div class="col-lg-4">
</div>
</div>
{% endblock %}
{% block scripts %}
@@ -328,78 +364,6 @@
{#
{% 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 table-responsive no-padding">
{% 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">
</tbody>
</table>
</div>
</div>
{% if 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>
{% if att.file_exists %}
<a href="{{ route('attachments.download', att.id) }}" class="btn btn-default"><i class="fa fa-download"></i></a>
{% endif %}
{% if not att.file_exists %}
<a href="#" class="btn btn-danger"><i class="fa fa-exclamation-triangle"></i></a>
{% endif %}
</div>
</td>
<td>
{% if att.file_exists %}
<i class="fa {{ att.mime|mimeIcon }}"></i>
<a href="{{ route('attachments.view', att.id) }}" title="{{ att.filename }}">
{% if att.title %}
{{ att.title }}
{% else %}
{{ att.filename }}
{% endif %}
</a>
({{ att.size|filesize }})
{% if att.notes.first %}
{{ att.notes.first.text|markdown }}
{% endif %}
{% endif %}
{% if not att.file_exists %}
<i class="fa fa-fw fa-exclamation-triangle"></i>
{% if att.title %}
{{ att.title }}
{% else %}
{{ att.filename }}
{% endif %}
<br>
<span class="text-danger">{{ 'attachment_not_found'|_ }}</span>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endif %}
{% if links.count > 0 %}
<div class="box">
<div class="box-header with-border">

View File

@@ -905,6 +905,7 @@ Route::group(
Route::post('update/{tj}', ['uses' => 'SingleController@update', 'as' => 'update']);
Route::post('destroy/{tj}', ['uses' => 'SingleController@destroy', 'as' => 'destroy']);
Route::get('clone/{tj}', ['uses' => 'SingleController@cloneTransaction', 'as' => 'clone']);
Route::get('{tj}/{type}', ['uses' => 'ConvertController@index', 'as' => 'convert']);
// TODO end of improvement.
}
);
@@ -950,15 +951,15 @@ Route::group(
/**
* Transaction Convert Controller
*/
Route::group(
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/convert',
'as' => 'transactions.convert.'], function () {
// TODO improve these routes
Route::get('{transactionType}/{tj}', ['uses' => 'ConvertController@index', 'as' => 'index']);
Route::post('{transactionType}/{tj}', ['uses' => 'ConvertController@postIndex', 'as' => 'index.post']);
// TODO end of todo
}
);
//Route::group(
// ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/convert',
// 'as' => 'transactions.convert.'], function () {
// // TODO improve these routes
// Route::get('{transactionType}/{tj}', ['uses' => 'ConvertController@index', 'as' => 'index']);
// Route::post('{transactionType}/{tj}', ['uses' => 'ConvertController@postIndex', 'as' => 'index.post']);
// // TODO end of todo
//}
//);
/**
* Transaction Link Controller