Migrated all code to group collector.

This commit is contained in:
James Cole
2019-05-31 13:35:33 +02:00
parent eb6329e556
commit e15c35de64
31 changed files with 1540 additions and 1671 deletions

View File

@@ -25,12 +25,10 @@ namespace FireflyIII\Support\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
@@ -86,22 +84,19 @@ trait AugumentData
*/
protected function earnedByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
{
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($assets);
$collector->setOpposingAccounts($opposing)->withCategoryInformation();
$set = $collector->getTransactions();
$sum = [];
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$total = $assets->merge($opposing);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($total);
$collector->withCategoryInformation();
$journals = $collector->getExtractedJournals();
$sum = [];
// loop to support multi currency
foreach ($set as $transaction) {
$currencyId = $transaction->transaction_currency_id;
$categoryName = $transaction->transaction_category_name;
$categoryId = (int)$transaction->transaction_category_id;
// if null, grab from journal:
if (0 === $categoryId) {
$categoryName = $transaction->transaction_journal_category_name;
$categoryId = (int)$transaction->transaction_journal_category_id;
}
foreach ($journals as $journal) {
$currencyId = $journal['currency_id'];
$categoryName = $journal['category_name'];
$categoryId = (int)$journal['category_id'];
// if not set, set to zero:
if (!isset($sum[$categoryId][$currencyId])) {
@@ -116,8 +111,8 @@ trait AugumentData
'name' => $categoryName,
],
'currency' => [
'symbol' => $transaction->transaction_currency_symbol,
'dp' => $transaction->transaction_currency_dp,
'symbol' => $journal['currency_symbol'],
'dp' => $journal['currency_decimal_places'],
],
],
],
@@ -126,9 +121,9 @@ trait AugumentData
// add amount
$sum[$categoryId]['per_currency'][$currencyId]['sum'] = bcadd(
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $transaction->transaction_amount
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $journal['amount']
);
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $transaction->transaction_amount);
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $journal['amount']);
}
return $sum;
@@ -146,33 +141,34 @@ trait AugumentData
*/
protected function earnedInPeriod(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
{
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($assets);
$collector->setOpposingAccounts($opposing);
$set = $collector->getTransactions();
$sum = [
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$total = $assets->merge($opposing);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($total);
$journals = $collector->getExtractedJournals();
$sum = [
'grand_sum' => '0',
'per_currency' => [],
];
// loop to support multi currency
foreach ($set as $transaction) {
$currencyId = $transaction->transaction_currency_id;
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
// if not set, set to zero:
if (!isset($sum['per_currency'][$currencyId])) {
$sum['per_currency'][$currencyId] = [
'sum' => '0',
'currency' => [
'symbol' => $transaction->transaction_currency_symbol,
'dp' => $transaction->transaction_currency_dp,
'symbol' => $journal['currency_symbol'],
'decimal_places' => $journal['currency_decimal_places'],
],
];
}
// add amount
$sum['per_currency'][$currencyId]['sum'] = bcadd($sum['per_currency'][$currencyId]['sum'], $transaction->transaction_amount);
$sum['grand_sum'] = bcadd($sum['grand_sum'], $transaction->transaction_amount);
$sum['per_currency'][$currencyId]['sum'] = bcadd($sum['per_currency'][$currencyId]['sum'], $journal['amount']);
$sum['grand_sum'] = bcadd($sum['grand_sum'], $journal['amount']);
}
return $sum;
@@ -525,19 +521,27 @@ trait AugumentData
/**
* Group set of transactions by name of opposing account.
*
* @param Collection $set
* @param array $array
*
* @return array
*/
protected function groupByName(Collection $set): array // filter + group data
protected function groupByName(array $array): array // filter + group data
{
// group by opposing account name.
$grouped = [];
/** @var Transaction $transaction */
foreach ($set as $transaction) {
$name = $transaction->opposing_account_name;
/** @var array $journal */
foreach ($array as $journal) {
$name = '(no name)';
if (TransactionType::WITHDRAWAL === $journal['transaction_type_type']) {
$name = $journal['destination_account_name'];
}
if (TransactionType::WITHDRAWAL !== $journal['transaction_type_type']) {
$name = $journal['source_account_name'];
}
$grouped[$name] = $grouped[$name] ?? '0';
$grouped[$name] = bcadd($transaction->transaction_amount, $grouped[$name]);
$grouped[$name] = bcadd($journal['amount'], $grouped[$name]);
}
return $grouped;
@@ -587,22 +591,18 @@ trait AugumentData
*/
protected function spentByBudget(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
{
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
$collector->setOpposingAccounts($opposing)->withBudgetInformation();
$set = $collector->getTransactions();
$sum = [];
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$total = $assets->merge($opposing);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($total);
$collector->withBudgetInformation();
$journals = $collector->getExtractedJournals();
$sum = [];
// loop to support multi currency
foreach ($set as $transaction) {
$currencyId = $transaction->transaction_currency_id;
$budgetName = $transaction->transaction_budget_name;
$budgetId = (int)$transaction->transaction_budget_id;
// if null, grab from journal:
if (0 === $budgetId) {
$budgetName = $transaction->transaction_journal_budget_name;
$budgetId = (int)$transaction->transaction_journal_budget_id;
}
foreach ($journals as $journal) {
$currencyId = $journal['currency_id'];
$budgetName = $journal['budget_name'];
$budgetId = (int)$journal['budget_id'];
// if not set, set to zero:
if (!isset($sum[$budgetId][$currencyId])) {
@@ -617,8 +617,8 @@ trait AugumentData
'name' => $budgetName,
],
'currency' => [
'symbol' => $transaction->transaction_currency_symbol,
'dp' => $transaction->transaction_currency_dp,
'symbol' => $journal['currency_symbol'],
'dp' => $journal['currency_decimal_places'],
],
],
],
@@ -627,9 +627,9 @@ trait AugumentData
// add amount
$sum[$budgetId]['per_currency'][$currencyId]['sum'] = bcadd(
$sum[$budgetId]['per_currency'][$currencyId]['sum'], $transaction->transaction_amount
$sum[$budgetId]['per_currency'][$currencyId]['sum'], $journal['amount']
);
$sum[$budgetId]['grand_total'] = bcadd($sum[$budgetId]['grand_total'], $transaction->transaction_amount);
$sum[$budgetId]['grand_total'] = bcadd($sum[$budgetId]['grand_total'], $journal['amount']);
}
return $sum;
@@ -652,22 +652,18 @@ trait AugumentData
*/
protected function spentByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
{
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
$collector->setOpposingAccounts($opposing)->withCategoryInformation();
$set = $collector->getTransactions();
$sum = [];
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$total = $assets->merge($opposing);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($total);
$collector->withCategoryInformation();
$journals = $collector->getExtractedJournals();
$sum = [];
// loop to support multi currency
foreach ($set as $transaction) {
$currencyId = $transaction->transaction_currency_id;
$categoryName = $transaction->transaction_category_name;
$categoryId = (int)$transaction->transaction_category_id;
// if null, grab from journal:
if (0 === $categoryId) {
$categoryName = $transaction->transaction_journal_category_name;
$categoryId = (int)$transaction->transaction_journal_category_id;
}
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
$categoryName = $journal['category_name'];
$categoryId = (int)$journal['category_id'];
// if not set, set to zero:
if (!isset($sum[$categoryId][$currencyId])) {
@@ -682,8 +678,8 @@ trait AugumentData
'name' => $categoryName,
],
'currency' => [
'symbol' => $transaction->transaction_currency_symbol,
'dp' => $transaction->transaction_currency_dp,
'symbol' => $journal['currency_symbol'],
'dp' => $journal['currency_decimal_places'],
],
],
],
@@ -692,9 +688,9 @@ trait AugumentData
// add amount
$sum[$categoryId]['per_currency'][$currencyId]['sum'] = bcadd(
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $transaction->transaction_amount
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $journal['amount']
);
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $transaction->transaction_amount);
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $journal['amount']);
}
return $sum;
@@ -714,33 +710,35 @@ trait AugumentData
*/
protected function spentInPeriod(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
{
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
$collector->setOpposingAccounts($opposing);
$set = $collector->getTransactions();
$sum = [
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$total = $assets->merge($opposing);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($total);
$journals = $collector->getExtractedJournals();
$sum = [
'grand_sum' => '0',
'per_currency' => [],
];
// loop to support multi currency
foreach ($set as $transaction) {
$currencyId = (int)$transaction->transaction_currency_id;
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
// if not set, set to zero:
if (!isset($sum['per_currency'][$currencyId])) {
$sum['per_currency'][$currencyId] = [
'sum' => '0',
'currency' => [
'symbol' => $transaction->transaction_currency_symbol,
'dp' => $transaction->transaction_currency_dp,
'name' => $journal['currency_name'],
'symbol' => $journal['currency_symbol'],
'decimal_places' => $journal['currency_decimal_places'],
],
];
}
// add amount
$sum['per_currency'][$currencyId]['sum'] = bcadd($sum['per_currency'][$currencyId]['sum'], $transaction->transaction_amount);
$sum['grand_sum'] = bcadd($sum['grand_sum'], $transaction->transaction_amount);
$sum['per_currency'][$currencyId]['sum'] = bcadd($sum['per_currency'][$currencyId]['sum'], $journal['amount']);
$sum['grand_sum'] = bcadd($sum['grand_sum'], $journal['amount']);
}
return $sum;
@@ -767,6 +765,7 @@ trait AugumentData
$collector = app(GroupCollectorInterface::class);
$types = [TransactionType::WITHDRAWAL];
$collector->setTypes($types)->setRange($start, $end)->withoutBudget();
return $collector->getSum();
}
}

View File

@@ -24,11 +24,8 @@ declare(strict_types=1);
namespace FireflyIII\Support\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Helpers\Collector\GroupSumCollectorInterface;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\Account;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;

View File

@@ -24,29 +24,18 @@ declare(strict_types=1);
namespace FireflyIII\Support\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Exceptions\ValidationException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Help\HelpInterface;
use FireflyIII\Http\Requests\SplitJournalFormRequest;
use FireflyIII\Http\Requests\TestRuleFormRequest;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Binder\AccountList;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Hash;
use Illuminate\Contracts\Validation\Validator as ValidatorContract;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Validator;
use InvalidArgumentException;
use Log;
use Route as RouteFacade;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
* Trait RequestInformation
@@ -54,138 +43,7 @@ use Symfony\Component\HttpFoundation\ParameterBag;
*/
trait RequestInformation
{
/**
* Create data-array from a journal.
*
* @param SplitJournalFormRequest|Request $request
* @param TransactionJournal $journal
*
* @return array
* @throws FireflyException
*/
protected function arrayFromJournal(Request $request, TransactionJournal $journal): array // convert user input.
{
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$sourceAccounts = $repository->getJournalSourceAccounts($journal);
$destinationAccounts = $repository->getJournalDestinationAccounts($journal);
$array = [
'journal_description' => $request->old('journal_description', $journal->description),
'journal_amount' => '0',
'journal_foreign_amount' => '0',
'sourceAccounts' => $sourceAccounts,
'journal_source_id' => $request->old('journal_source_id', $sourceAccounts->first()->id),
'journal_source_name' => $request->old('journal_source_name', $sourceAccounts->first()->name),
'journal_destination_id' => $request->old('journal_destination_id', $destinationAccounts->first()->id),
'destinationAccounts' => $destinationAccounts,
'what' => strtolower($this->repository->getTransactionType($journal)),
'date' => $request->old('date', $this->repository->getJournalDate($journal, null)),
'tags' => implode(',', $journal->tags->pluck('tag')->toArray()),
// all custom fields:
'interest_date' => $request->old('interest_date', $repository->getMetaField($journal, 'interest_date')),
'book_date' => $request->old('book_date', $repository->getMetaField($journal, 'book_date')),
'process_date' => $request->old('process_date', $repository->getMetaField($journal, 'process_date')),
'due_date' => $request->old('due_date', $repository->getMetaField($journal, 'due_date')),
'payment_date' => $request->old('payment_date', $repository->getMetaField($journal, 'payment_date')),
'invoice_date' => $request->old('invoice_date', $repository->getMetaField($journal, 'invoice_date')),
'internal_reference' => $request->old('internal_reference', $repository->getMetaField($journal, 'internal_reference')),
'notes' => $request->old('notes', $repository->getNoteText($journal)),
// transactions.
'transactions' => $this->getTransactionDataFromJournal($journal),
];
// update transactions array with old request data.
$array['transactions'] = $this->updateWithPrevious($array['transactions'], $request->old());
// update journal amount and foreign amount:
$array['journal_amount'] = array_sum(array_column($array['transactions'], 'amount'));
$array['journal_foreign_amount'] = array_sum(array_column($array['transactions'], 'foreign_amount'));
return $array;
}
/**
* Get transaction overview from journal.
*
* @param TransactionJournal $journal
*
* @return array
* @throws FireflyException
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function getTransactionDataFromJournal(TransactionJournal $journal): array // convert object
{
// use collector to collect transactions.
$collector = app(TransactionCollectorInterface::class);
$collector->setUser(auth()->user());
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
// filter on specific journals.
$collector->setJournals(new Collection([$journal]));
$set = $collector->getTransactions();
$transactions = [];
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters(new ParameterBag());
/** @var Transaction $transaction */
foreach ($set as $transaction) {
$res = [];
if ((float)$transaction->transaction_amount > 0 && $journal->transactionType->type === TransactionType::DEPOSIT) {
$res = $transformer->transform($transaction);
}
if ((float)$transaction->transaction_amount < 0 && $journal->transactionType->type !== TransactionType::DEPOSIT) {
$res = $transformer->transform($transaction);
}
if (count($res) > 0) {
$res['amount'] = app('steam')->positive((string)$res['amount']);
$res['foreign_amount'] = app('steam')->positive((string)$res['foreign_amount']);
$transactions[] = $res;
}
}
return $transactions;
}
/**
* Get info from old input.
*
* @param $array
* @param $old
*
* @return array
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function updateWithPrevious($array, $old): array // update object with new info
{
if (0 === count($old) || !isset($old['transactions'])) {
return $array;
}
$old = $old['transactions'];
foreach ($old as $index => $row) {
if (isset($array[$index])) {
/** @noinspection SlowArrayOperationsInLoopInspection */
$array[$index] = array_merge($array[$index], $row);
continue;
}
// take some info from first transaction, that should at least exist.
$array[$index] = $row;
$array[$index]['currency_id'] = $array[0]['currency_id'];
$array[$index]['currency_code'] = $array[0]['currency_code'] ?? '';
$array[$index]['currency_symbol'] = $array[0]['currency_symbol'] ?? '';
$array[$index]['foreign_amount'] = round($array[0]['foreign_destination_amount'] ?? '0', 12);
$array[$index]['foreign_currency_id'] = $array[0]['foreign_currency_id'];
$array[$index]['foreign_currency_code'] = $array[0]['foreign_currency_code'];
$array[$index]['foreign_currency_symbol'] = $array[0]['foreign_currency_symbol'];
}
return $array;
}
/**
* Get the domain of FF system.

View File

@@ -46,14 +46,18 @@ trait TransactionCalculation
*/
protected function getExpensesForOpposing(Collection $accounts, Collection $opposing, Carbon $start, Carbon $end): array
{
$total = $accounts->merge($opposing);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)
$collector->setAccounts($total)
->setRange($start, $end)
->setTypes([TransactionType::WITHDRAWAL])
->setAccounts($opposing);
->withAccountInformation()
->setTypes([TransactionType::WITHDRAWAL]);
return $collector->getExtractedJournals();
$result = $collector->getExtractedJournals();
return $result;
}
/**
@@ -156,10 +160,10 @@ trait TransactionCalculation
*/
protected function getIncomeForOpposing(Collection $accounts, Collection $opposing, Carbon $start, Carbon $end): array
{
$total =$accounts->merge($opposing);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])
->setAccounts($opposing);
$collector->setAccounts($total)->setRange($start, $end)->withAccountInformation()->setTypes([TransactionType::DEPOSIT]);
return $collector->getExtractedJournals();
}

View File

@@ -160,6 +160,12 @@ class ImportTransaction
'opposing-bic' => 'opposingBic',
'opposing-number' => 'opposingNumber',
];
// overrule some old role values.
if ('original-source' === $role) {
$role = 'original_source';
}
if (isset($basics[$role])) {
$field = $basics[$role];
$this->$field = $columnValue->getValue();
@@ -229,6 +235,18 @@ class ImportTransaction
}
}
/**
* Returns the mapped value if it exists in the ColumnValue object.
*
* @param ColumnValue $columnValue
*
* @return int
*/
private function getMappedValue(ColumnValue $columnValue): int
{
return $columnValue->getMappedValue() > 0 ? $columnValue->getMappedValue() : (int)$columnValue->getValue();
}
/**
* Calculate the amount of this transaction.
*
@@ -276,6 +294,40 @@ class ImportTransaction
return $result;
}
/**
* This methods decides which input value to use for the amount calculation.
*
* @return array
*/
private function selectAmountInput(): array
{
$info = [];
$converterClass = '';
if (null !== $this->amount) {
Log::debug('Amount value is not NULL, assume this is the correct value.');
$converterClass = Amount::class;
$info['amount'] = $this->amount;
}
if (null !== $this->amountDebit) {
Log::debug('Amount DEBIT value is not NULL, assume this is the correct value (overrules Amount).');
$converterClass = AmountDebit::class;
$info['amount'] = $this->amountDebit;
}
if (null !== $this->amountCredit) {
Log::debug('Amount CREDIT value is not NULL, assume this is the correct value (overrules Amount and AmountDebit).');
$converterClass = AmountCredit::class;
$info['amount'] = $this->amountCredit;
}
if (null !== $this->amountNegated) {
Log::debug('Amount NEGATED value is not NULL, assume this is the correct value (overrules Amount and AmountDebit and AmountCredit).');
$converterClass = AmountNegated::class;
$info['amount'] = $this->amountNegated;
}
$info['class'] = $converterClass;
return $info;
}
/**
* The method that calculates the foreign amount isn't nearly as complex,\
* because Firefly III only supports one foreign amount field. So the foreign amount is there
@@ -372,50 +424,4 @@ class ImportTransaction
];
}
/**
* Returns the mapped value if it exists in the ColumnValue object.
*
* @param ColumnValue $columnValue
*
* @return int
*/
private function getMappedValue(ColumnValue $columnValue): int
{
return $columnValue->getMappedValue() > 0 ? $columnValue->getMappedValue() : (int)$columnValue->getValue();
}
/**
* This methods decides which input value to use for the amount calculation.
*
* @return array
*/
private function selectAmountInput(): array
{
$info = [];
$converterClass = '';
if (null !== $this->amount) {
Log::debug('Amount value is not NULL, assume this is the correct value.');
$converterClass = Amount::class;
$info['amount'] = $this->amount;
}
if (null !== $this->amountDebit) {
Log::debug('Amount DEBIT value is not NULL, assume this is the correct value (overrules Amount).');
$converterClass = AmountDebit::class;
$info['amount'] = $this->amountDebit;
}
if (null !== $this->amountCredit) {
Log::debug('Amount CREDIT value is not NULL, assume this is the correct value (overrules Amount and AmountDebit).');
$converterClass = AmountCredit::class;
$info['amount'] = $this->amountCredit;
}
if (null !== $this->amountNegated) {
Log::debug('Amount NEGATED value is not NULL, assume this is the correct value (overrules Amount and AmountDebit and AmountCredit).');
$converterClass = AmountNegated::class;
$info['amount'] = $this->amountNegated;
}
$info['class'] = $converterClass;
return $info;
}
}

View File

@@ -89,79 +89,11 @@ class ImportableConverter
return $result;
}
/**
* @param ImportJob $importJob
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->config = $importJob->configuration;
// repository is used for error messages
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
// asset account mapper can map asset accounts (makes sense right?)
$this->assetMapper = app(AssetAccountMapper::class);
$this->assetMapper->setUser($importJob->user);
$this->assetMapper->setDefaultAccount($this->config['import-account'] ?? 0);
// asset account repository is used for currency information
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->accountRepository->setUser($importJob->user);
// opposing account mapper:
$this->opposingMapper = app(OpposingAccountMapper::class);
$this->opposingMapper->setUser($importJob->user);
// currency mapper:
$this->currencyMapper = app(CurrencyMapper::class);
$this->currencyMapper->setUser($importJob->user);
$this->defaultCurrency = app('amount')->getDefaultCurrencyByUser($importJob->user);
}
/**
* @codeCoverageIgnore
*
* @param array $mappedValues
*/
public function setMappedValues(array $mappedValues): void
{
$this->mappedValues = $mappedValues;
}
/**
* @param string|null $date
*
* @return string|null
*/
private function convertDateValue(string $date = null): ?string
{
$result = null;
if (null !== $date) {
try {
// add exclamation mark for better parsing. http://php.net/manual/en/datetime.createfromformat.php
$dateFormat = $this->config['date-format'] ?? 'Ymd';
if ('!' !== $dateFormat{0}) {
$dateFormat = '!' . $dateFormat;
}
$object = Carbon::createFromFormat($dateFormat, $date);
$result = $object->format('Y-m-d H:i:s');
Log::debug(sprintf('createFromFormat: Turning "%s" into "%s" using "%s"', $date, $result, $this->config['date-format'] ?? 'Ymd'));
} catch (InvalidDateException|InvalidArgumentException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
}
}
return $result;
}
/**
* @param ImportTransaction $importable
*
* @throws FireflyException
* @return array
* @throws FireflyException
*/
private function convertSingle(ImportTransaction $importable): array
{
@@ -218,60 +150,98 @@ class ImportableConverter
}
return [
'type' => $transactionType,
'date' => $this->convertDateValue($importable->date) ?? Carbon::now()->format('Y-m-d H:i:s'),
'tags' => $importable->tags,
'user' => $this->importJob->user_id,
'notes' => $importable->note,
// all custom fields:
'internal_reference' => $importable->meta['internal-reference'] ?? null,
'sepa_cc' => $importable->meta['sepa_cc'] ?? null,
'sepa_ct_op' => $importable->meta['sepa_ct_op'] ?? null,
'sepa_ct_id' => $importable->meta['sepa_ct_id'] ?? null,
'sepa_db' => $importable->meta['sepa_db'] ?? null,
'sepa_country' => $importable->meta['sepa_country'] ?? null,
'sepa_ep' => $importable->meta['sepa_ep'] ?? null,
'sepa_ci' => $importable->meta['sepa_ci'] ?? null,
'sepa_batch_id' => $importable->meta['sepa_batch_id'] ?? null,
'interest_date' => $this->convertDateValue($importable->meta['date-interest'] ?? null),
'book_date' => $this->convertDateValue($importable->meta['date-book'] ?? null),
'process_date' => $this->convertDateValue($importable->meta['date-process'] ?? null),
'due_date' => $this->convertDateValue($importable->meta['date-due'] ?? null),
'payment_date' => $this->convertDateValue($importable->meta['date-payment'] ?? null),
'invoice_date' => $this->convertDateValue($importable->meta['date-invoice'] ?? null),
'external_id' => $importable->externalId,
'original-source' => $importable->meta['original-source'] ?? null,
// journal data:
'description' => $importable->description,
'piggy_bank_id' => null,
'piggy_bank_name' => null,
'bill_id' => $importable->billId,
'bill_name' => $importable->billName,
// transaction data:
'transactions' => [
'user' => $this->importJob->user_id,
'group_title' => null,
'transactions' => [
[
'currency_id' => $currency->id,
'currency_code' => null,
'description' => null,
'amount' => $amount,
'budget_id' => $importable->budgetId,
'budget_name' => $importable->budgetName,
'category_id' => $importable->categoryId,
'category_name' => $importable->categoryName,
'source_id' => $source->id,
'source_name' => null,
'destination_id' => $destination->id,
'destination_name' => null,
'user' => $this->importJob->user_id,
'type' => $transactionType,
'date' => $this->convertDateValue($importable->date) ?? Carbon::now()->format('Y-m-d H:i:s'),
'order' => 0,
'currency_id' => $currency->id,
'currency_code' => null,
'foreign_currency_id' => $importable->foreignCurrencyId,
'foreign_currency_code' => null === $foreignCurrency ? null : $foreignCurrency->code,
'foreign_amount' => $foreignAmount,
'reconciled' => false,
'identifier' => 0,
'amount' => $amount,
'foreign_amount' => $foreignAmount,
'description' => $importable->description,
'source_id' => $source->id,
'source_name' => null,
'destination_id' => $destination->id,
'destination_name' => null,
'budget_id' => $importable->budgetId,
'budget_name' => $importable->budgetName,
'category_id' => $importable->categoryId,
'category_name' => $importable->categoryName,
'bill_id' => $importable->billId,
'bill_name' => $importable->billName,
'piggy_bank_id' => null,
'piggy_bank_name' => null,
'reconciled' => false,
'notes' => $importable->note,
'tags' => $importable->tags,
'internal_reference' => $importable->meta['internal-reference'] ?? null,
'external_id' => $importable->externalId,
'original_source' => $importable->meta['original-source'] ?? null,
'sepa_cc' => $importable->meta['sepa_cc'] ?? null,
'sepa_ct_op' => $importable->meta['sepa_ct_op'] ?? null,
'sepa_ct_id' => $importable->meta['sepa_ct_id'] ?? null,
'sepa_db' => $importable->meta['sepa_db'] ?? null,
'sepa_country' => $importable->meta['sepa_country'] ?? null,
'sepa_ep' => $importable->meta['sepa_ep'] ?? null,
'sepa_ci' => $importable->meta['sepa_ci'] ?? null,
'sepa_batch_id' => $importable->meta['sepa_batch_id'] ?? null,
'interest_date' => $this->convertDateValue($importable->meta['date-interest'] ?? null),
'book_date' => $this->convertDateValue($importable->meta['date-book'] ?? null),
'process_date' => $this->convertDateValue($importable->meta['date-process'] ?? null),
'due_date' => $this->convertDateValue($importable->meta['date-due'] ?? null),
'payment_date' => $this->convertDateValue($importable->meta['date-payment'] ?? null),
'invoice_date' => $this->convertDateValue($importable->meta['date-invoice'] ?? null),
],
],
];
}
/**
* @param string $source
* @param string $destination
*
* @return string
*/
private function getTransactionType(string $source, string $destination): string
{
$type = 'unknown';
if ($source === AccountType::ASSET && $destination === AccountType::ASSET) {
Log::debug('Source and destination are asset accounts. This is a transfer.');
$type = 'transfer';
}
if ($source === AccountType::REVENUE) {
Log::debug('Source is a revenue account. This is a deposit.');
$type = 'deposit';
}
if ($destination === AccountType::EXPENSE) {
Log::debug('Destination is an expense account. This is a withdrawal.');
$type = 'withdrawal';
}
return $type;
}
/**
@@ -305,28 +275,70 @@ class ImportableConverter
}
/**
* @param string $source
* @param string $destination
* @param string|null $date
*
* @return string
* @return string|null
*/
private function getTransactionType(string $source, string $destination): string
private function convertDateValue(string $date = null): ?string
{
$type = 'unknown';
if ($source === AccountType::ASSET && $destination === AccountType::ASSET) {
Log::debug('Source and destination are asset accounts. This is a transfer.');
$type = 'transfer';
}
if ($source === AccountType::REVENUE) {
Log::debug('Source is a revenue account. This is a deposit.');
$type = 'deposit';
}
if ($destination === AccountType::EXPENSE) {
Log::debug('Destination is an expense account. This is a withdrawal.');
$type = 'withdrawal';
$result = null;
if (null !== $date) {
try {
// add exclamation mark for better parsing. http://php.net/manual/en/datetime.createfromformat.php
$dateFormat = $this->config['date-format'] ?? 'Ymd';
if ('!' !== $dateFormat{0}) {
$dateFormat = '!' . $dateFormat;
}
$object = Carbon::createFromFormat($dateFormat, $date);
$result = $object->format('Y-m-d H:i:s');
Log::debug(sprintf('createFromFormat: Turning "%s" into "%s" using "%s"', $date, $result, $this->config['date-format'] ?? 'Ymd'));
} catch (InvalidDateException|InvalidArgumentException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
}
}
return $type;
return $result;
}
/**
* @param ImportJob $importJob
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->config = $importJob->configuration;
// repository is used for error messages
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
// asset account mapper can map asset accounts (makes sense right?)
$this->assetMapper = app(AssetAccountMapper::class);
$this->assetMapper->setUser($importJob->user);
$this->assetMapper->setDefaultAccount($this->config['import-account'] ?? 0);
// asset account repository is used for currency information
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->accountRepository->setUser($importJob->user);
// opposing account mapper:
$this->opposingMapper = app(OpposingAccountMapper::class);
$this->opposingMapper->setUser($importJob->user);
// currency mapper:
$this->currencyMapper = app(CurrencyMapper::class);
$this->currencyMapper->setUser($importJob->user);
$this->defaultCurrency = app('amount')->getDefaultCurrencyByUser($importJob->user);
}
/**
* @codeCoverageIgnore
*
* @param array $mappedValues
*/
public function setMappedValues(array $mappedValues): void
{
$this->mappedValues = $mappedValues;
}
}

View File

@@ -23,9 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Support\Search;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\DoubleTransactionFilter;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
@@ -132,6 +130,22 @@ class Search implements SearchInterface
}
}
/**
* @param string $string
*/
private function extractModifier(string $string): void
{
$parts = explode(':', $string);
if (2 === count($parts) && '' !== trim((string)$parts[1]) && '' !== trim((string)$parts[0])) {
$type = trim((string)$parts[0]);
$value = trim((string)$parts[1]);
if (\in_array($type, $this->validModifiers, true)) {
// filter for valid type
$this->modifiers->push(['type' => $type, 'value' => $value]);
}
}
}
/**
* @return float
*/
@@ -149,16 +163,13 @@ class Search implements SearchInterface
$pageSize = 50;
$page = 1;
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setAllAssetAccounts()->setLimit($pageSize)->setPage($page)->withOpposingAccount();
if ($this->hasModifiers()) {
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
}
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setLimit($pageSize)->setPage($page)->withAccountInformation();
$collector->withCategoryInformation()->withBudgetInformation();
$collector->setSearchWords($this->words);
$collector->removeFilter(InternalTransferFilter::class);
$collector->addFilter(DoubleTransactionFilter::class);
// Most modifiers can be applied to the collector directly.
$collector = $this->applyModifiers($collector);
@@ -168,37 +179,18 @@ class Search implements SearchInterface
}
/**
* @param int $limit
*/
public function setLimit(int $limit): void
{
$this->limit = $limit;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->accountRepository->setUser($user);
$this->billRepository->setUser($user);
$this->categoryRepository->setUser($user);
$this->budgetRepository->setUser($user);
}
/**
* @param TransactionCollectorInterface $collector
* @param GroupCollectorInterface $collector
*
* @return TransactionCollectorInterface
* @return GroupCollectorInterface
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
private function applyModifiers(TransactionCollectorInterface $collector): TransactionCollectorInterface
private function applyModifiers(GroupCollectorInterface $collector): GroupCollectorInterface
{
/*
* TODO:
* 'bill',
*/
$totalAccounts = new Collection;
foreach ($this->modifiers as $modifier) {
switch ($modifier['type']) {
@@ -209,7 +201,7 @@ class Search implements SearchInterface
$searchTypes = [AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT, AccountType::REVENUE];
$accounts = $this->accountRepository->searchAccount($modifier['value'], $searchTypes);
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
$totalAccounts = $accounts->merge($totalAccounts);
}
break;
case 'destination':
@@ -217,7 +209,7 @@ class Search implements SearchInterface
$searchTypes = [AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT, AccountType::EXPENSE];
$accounts = $this->accountRepository->searchAccount($modifier['value'], $searchTypes);
if ($accounts->count() > 0) {
$collector->setOpposingAccounts($accounts);
$totalAccounts = $accounts->merge($totalAccounts);
}
break;
case 'category':
@@ -280,23 +272,28 @@ class Search implements SearchInterface
break;
}
}
$collector->setAccounts($totalAccounts);
return $collector;
}
/**
* @param string $string
* @param int $limit
*/
private function extractModifier(string $string): void
public function setLimit(int $limit): void
{
$parts = explode(':', $string);
if (2 === count($parts) && '' !== trim((string)$parts[1]) && '' !== trim((string)$parts[0])) {
$type = trim((string)$parts[0]);
$value = trim((string)$parts[1]);
if (\in_array($type, $this->validModifiers, true)) {
// filter for valid type
$this->modifiers->push(['type' => $type, 'value' => $value]);
}
}
$this->limit = $limit;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->accountRepository->setUser($user);
$this->billRepository->setUser($user);
$this->categoryRepository->setUser($user);
$this->budgetRepository->setUser($user);
}
}