Code cleanup

This commit is contained in:
James Cole 2021-03-21 09:15:40 +01:00
parent da1751940e
commit 206845575c
No known key found for this signature in database
GPG Key ID: B5669F9493CDE38D
317 changed files with 7418 additions and 7362 deletions

View File

@ -57,31 +57,6 @@ class CurrencyController extends Controller
);
}
/**
* @param AutocompleteRequest $request
*
* @return JsonResponse
*/
public function currenciesWithCode(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$collection = $this->repository->searchCurrency($data['query'], $data['limit']);
$result = [];
/** @var TransactionCurrency $currency */
foreach ($collection as $currency) {
$result[] = [
'id' => (string) $currency->id,
'name' => sprintf('%s (%s)', $currency->name, $currency->code),
'code' => $currency->code,
'symbol' => $currency->symbol,
'decimal_places' => $currency->decimal_places,
];
}
return response()->json($result);
}
/**
* @param AutocompleteRequest $request
*
@ -106,4 +81,29 @@ class CurrencyController extends Controller
return response()->json($result);
}
/**
* @param AutocompleteRequest $request
*
* @return JsonResponse
*/
public function currenciesWithCode(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$collection = $this->repository->searchCurrency($data['query'], $data['limit']);
$result = [];
/** @var TransactionCurrency $currency */
foreach ($collection as $currency) {
$result[] = [
'id' => (string)$currency->id,
'name' => sprintf('%s (%s)', $currency->name, $currency->code),
'code' => $currency->code,
'symbol' => $currency->symbol,
'decimal_places' => $currency->decimal_places,
];
}
return response()->json($result);
}
}

View File

@ -37,10 +37,8 @@ use Illuminate\Http\JsonResponse;
*/
class PiggyBankController extends Controller
{
private PiggyBankRepositoryInterface $piggyRepository;
private AccountRepositoryInterface $accountRepository;
private PiggyBankRepositoryInterface $piggyRepository;
/**
* PiggyBankController constructor.

View File

@ -38,10 +38,8 @@ use Illuminate\Support\Collection;
*/
class TransactionController extends Controller
{
private JournalRepositoryInterface $repository;
private TransactionGroupRepositoryInterface $groupRepository;
private JournalRepositoryInterface $repository;
/**
* TransactionController constructor.

View File

@ -27,6 +27,7 @@ use FireflyIII\Api\V1\Requests\Data\Export\ExportRequest;
use FireflyIII\Support\Export\ExportDataGenerator;
use FireflyIII\User;
use Illuminate\Http\Response as LaravelResponse;
use League\Csv\CannotInsertRecord;
/**
* Class ExportController
@ -59,7 +60,7 @@ class ExportController extends Controller
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
* @throws CannotInsertRecord
*/
public function accounts(ExportRequest $request): LaravelResponse
{
@ -69,120 +70,11 @@ class ExportController extends Controller
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
*/
public function bills(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportBills(true);
return $this->returnExport('bills');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
*/
public function budgets(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportBudgets(true);
return $this->returnExport('budgets');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
*/
public function categories(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportCategories(true);
return $this->returnExport('categories');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
*/
public function piggyBanks(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportPiggies(true);
return $this->returnExport('piggies');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
*/
public function recurring(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportRecurring(true);
return $this->returnExport('recurrences');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
*/
public function rules(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportRules(true);
return $this->returnExport('rules');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
*/
public function tags(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportTags(true);
return $this->returnExport('tags');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
*/
public function transactions(ExportRequest $request): LaravelResponse
{
$params = $request->getAll();
$this->exporter->setStart($params['start']);
$this->exporter->setEnd($params['end']);
$this->exporter->setAccounts($params['accounts']);
$this->exporter->setExportTransactions(true);
return $this->returnExport('transactions');
}
/**
* @param string $key
*
* @return LaravelResponse
* @throws \League\Csv\CannotInsertRecord
* @throws CannotInsertRecord
*/
private function returnExport(string $key): LaravelResponse
{
@ -206,4 +98,112 @@ class ExportController extends Controller
return $response;
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws CannotInsertRecord
*/
public function bills(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportBills(true);
return $this->returnExport('bills');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws CannotInsertRecord
*/
public function budgets(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportBudgets(true);
return $this->returnExport('budgets');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws CannotInsertRecord
*/
public function categories(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportCategories(true);
return $this->returnExport('categories');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws CannotInsertRecord
*/
public function piggyBanks(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportPiggies(true);
return $this->returnExport('piggies');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws CannotInsertRecord
*/
public function recurring(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportRecurring(true);
return $this->returnExport('recurrences');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws CannotInsertRecord
*/
public function rules(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportRules(true);
return $this->returnExport('rules');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws CannotInsertRecord
*/
public function tags(ExportRequest $request): LaravelResponse
{
$this->exporter->setExportTags(true);
return $this->returnExport('tags');
}
/**
* @param ExportRequest $request
*
* @return LaravelResponse
* @throws CannotInsertRecord
*/
public function transactions(ExportRequest $request): LaravelResponse
{
$params = $request->getAll();
$this->exporter->setStart($params['start']);
$this->exporter->setEnd($params['end']);
$this->exporter->setAccounts($params['accounts']);
$this->exporter->setExportTransactions(true);
return $this->returnExport('transactions');
}
}

View File

@ -44,8 +44,8 @@ class AccountController extends Controller
use ApiSupport;
private CurrencyRepositoryInterface $currencyRepository;
private AccountRepositoryInterface $repository;
private OperationsRepositoryInterface $opsRepository;
private AccountRepositoryInterface $repository;
/**
* AccountController constructor.
@ -72,6 +72,32 @@ class AccountController extends Controller
);
}
/**
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function asset(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
$end = $request->getEnd();
$assetAccounts = $request->getAssetAccounts();
$expenses = $this->opsRepository->sumExpenses($start, $end, $assetAccounts);
$result = [];
/** @var array $expense */
foreach ($expenses as $expense) {
$result[] = [
'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'],
'currency_id' => (string)$expense['currency_id'],
'currency_code' => $expense['currency_code'],
];
}
return response()->json($result);
}
/**
* @param GenericRequest $request
*
@ -99,30 +125,4 @@ class AccountController extends Controller
return response()->json($result);
}
/**
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function asset(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
$end = $request->getEnd();
$assetAccounts = $request->getAssetAccounts();
$expenses = $this->opsRepository->sumExpenses($start, $end, $assetAccounts);
$result = [];
/** @var array $expense */
foreach ($expenses as $expense) {
$result[] = [
'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'],
'currency_id' => (string)$expense['currency_id'],
'currency_code' => $expense['currency_code'],
];
}
return response()->json($result);
}
}

View File

@ -36,9 +36,9 @@ use Illuminate\Support\Collection;
*/
class BudgetController extends Controller
{
private NoBudgetRepositoryInterface $noRepository;
private OperationsRepositoryInterface $opsRepository;
private BudgetRepositoryInterface $repository;
private NoBudgetRepositoryInterface $noRepository;
/**
* AccountController constructor.

View File

@ -18,9 +18,9 @@ use Illuminate\Support\Collection;
*/
class CategoryController extends Controller
{
private NoCategoryRepositoryInterface $noRepository;
private OperationsRepositoryInterface $opsRepository;
private CategoryRepositoryInterface $repository;
private NoCategoryRepositoryInterface $noRepository;
/**
* AccountController constructor.

View File

@ -53,6 +53,56 @@ class TagController extends Controller
);
}
/**
* Expenses for no tag filtered by account.
*
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::WITHDRAWAL])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->withoutTags();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id'];
if (0 !== $currencyId) {
$response[$currencyId] = $response[$currencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $journal['amount']);
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference'];
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] = $response[$foreignCurrencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
}
return response()->json(array_values($response));
}
/**
* Expenses per tag, possibly filtered by tag and account.
*
@ -120,54 +170,4 @@ class TagController extends Controller
return response()->json(array_values($response));
}
/**
* Expenses for no tag filtered by account.
*
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::WITHDRAWAL])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->withoutTags();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id'];
if (0 !== $currencyId) {
$response[$currencyId] = $response[$currencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $journal['amount']);
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference'];
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] = $response[$foreignCurrencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
}
return response()->json(array_values($response));
}
}

View File

@ -45,8 +45,8 @@ class AccountController extends Controller
use ApiSupport;
private CurrencyRepositoryInterface $currencyRepository;
private AccountRepositoryInterface $repository;
private OperationsRepositoryInterface $opsRepository;
private AccountRepositoryInterface $repository;
/**
* AccountController constructor.
@ -73,34 +73,6 @@ class AccountController extends Controller
);
}
/**
* // TOOD same as
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function revenue(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
$end = $request->getEnd();
$assetAccounts = $request->getAssetAccounts();
$revenueAccounts = $request->getRevenueAccounts();
$income = $this->opsRepository->sumIncome($start, $end, $assetAccounts, $revenueAccounts);
$result = [];
/** @var array $entry */
foreach ($income as $entry) {
$result[] = [
'difference' => $entry['sum'],
'difference_float' => (float)$entry['sum'],
'currency_id' => (string)$entry['currency_id'],
'currency_code' => $entry['currency_code'],
];
}
return response()->json($result);
}
/**
* TODO same code as Expense/AccountController.
*
@ -128,4 +100,33 @@ class AccountController extends Controller
return response()->json($result);
}
/**
* // TOOD same as
*
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function revenue(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
$end = $request->getEnd();
$assetAccounts = $request->getAssetAccounts();
$revenueAccounts = $request->getRevenueAccounts();
$income = $this->opsRepository->sumIncome($start, $end, $assetAccounts, $revenueAccounts);
$result = [];
/** @var array $entry */
foreach ($income as $entry) {
$result[] = [
'difference' => $entry['sum'],
'difference_float' => (float)$entry['sum'],
'currency_id' => (string)$entry['currency_id'],
'currency_code' => $entry['currency_code'],
];
}
return response()->json($result);
}
}

View File

@ -19,9 +19,9 @@ use Illuminate\Support\Collection;
*/
class CategoryController extends Controller
{
private NoCategoryRepositoryInterface $noRepository;
private OperationsRepositoryInterface $opsRepository;
private CategoryRepositoryInterface $repository;
private NoCategoryRepositoryInterface $noRepository;
/**
* AccountController constructor.

View File

@ -71,7 +71,9 @@ class PeriodController extends Controller
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], app('steam')->positive($journal['foreign_amount']));
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'], app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
}

View File

@ -53,6 +53,58 @@ class TagController extends Controller
);
}
/**
* Expenses for no tag filtered by account.
*
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::DEPOSIT])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->withoutTags();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id'];
if (0 !== $currencyId) {
$response[$currencyId] = $response[$currencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference'];
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] = $response[$foreignCurrencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'], app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
}
return response()->json(array_values($response));
}
/**
* Expenses per tag, possibly filtered by tag and account.
*
@ -111,7 +163,9 @@ class TagController extends Controller
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignKey]['difference'] = bcadd($response[$foreignKey]['difference'], app('steam')->positive($journal['foreign_amount']));
$response[$foreignKey]['difference'] = bcadd(
$response[$foreignKey]['difference'], app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignKey]['difference_float'] = (float)$response[$foreignKey]['difference'];
}
}
@ -120,54 +174,4 @@ class TagController extends Controller
return response()->json(array_values($response));
}
/**
* Expenses for no tag filtered by account.
*
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::DEPOSIT])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->withoutTags();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id'];
if (0 !== $currencyId) {
$response[$currencyId] = $response[$currencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference'];
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] = $response[$foreignCurrencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], app('steam')->positive($journal['foreign_amount']));
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
}
return response()->json(array_values($response));
}
}

View File

@ -36,9 +36,9 @@ use Illuminate\Support\Collection;
*/
class CategoryController extends Controller
{
private NoCategoryRepositoryInterface $noRepository;
private OperationsRepositoryInterface $opsRepository;
private CategoryRepositoryInterface $repository;
private NoCategoryRepositoryInterface $noRepository;
/**
* AccountController constructor.

View File

@ -71,7 +71,9 @@ class PeriodController extends Controller
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], app('steam')->positive($journal['foreign_amount']));
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'], app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
}

View File

@ -54,6 +54,58 @@ class TagController extends Controller
);
}
/**
* Expenses for no tag filtered by account.
*
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->withoutTags();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id'];
if (0 !== $currencyId) {
$response[$currencyId] = $response[$currencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference'];
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] = $response[$foreignCurrencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'], app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
}
return response()->json(array_values($response));
}
/**
* Transfers per tag, possibly filtered by tag and account.
*
@ -112,7 +164,9 @@ class TagController extends Controller
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignKey]['difference'] = bcadd($response[$foreignKey]['difference'], app('steam')->positive($journal['foreign_amount']));
$response[$foreignKey]['difference'] = bcadd(
$response[$foreignKey]['difference'], app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignKey]['difference_float'] = (float)$response[$foreignKey]['difference'];
}
}
@ -120,54 +174,4 @@ class TagController extends Controller
return response()->json(array_values($response));
}
/**
* Expenses for no tag filtered by account.
*
* @param GenericRequest $request
*
* @return JsonResponse
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->withoutTags();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id'];
if (0 !== $currencyId) {
$response[$currencyId] = $response[$currencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference'];
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] = $response[$foreignCurrencyId] ?? [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], app('steam')->positive($journal['foreign_amount']));
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
}
return response()->json(array_values($response));
}
}

View File

@ -141,7 +141,6 @@ class ShowController extends Controller
}
/**
* Display the specified resource.
*

View File

@ -67,7 +67,6 @@ class StoreController extends Controller
}
/**
* Store a newly created resource in storage.
*

View File

@ -63,7 +63,6 @@ class UpdateController extends Controller
}
/**
* Update the specified resource in storage.
*

View File

@ -54,6 +54,7 @@ class DestroyController extends Controller
}
);
}
/**
* Remove the specified resource from storage.
*

View File

@ -26,7 +26,6 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\AvailableBudget\Request;
use FireflyIII\Factory\TransactionCurrencyFactory;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Transformers\AvailableBudgetTransformer;
use FireflyIII\User;

View File

@ -101,7 +101,6 @@ class ListController extends Controller
}
/**
* List all of them.
*
@ -139,7 +138,6 @@ class ListController extends Controller
}
/**
* Show all transactions.
*

View File

@ -25,7 +25,6 @@ namespace FireflyIII\Api\V1\Controllers\Models\Bill;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\BillTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;

View File

@ -96,31 +96,6 @@ class ShowController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* @param Request $request
* @param Budget $budget
* @param BudgetLimit $budgetLimit
*
* @return JsonResponse
*/
public function show(Request $request, Budget $budget, BudgetLimit $budgetLimit): JsonResponse
{
if ((int)$budget->id !== (int)$budgetLimit->budget_id) {
throw new FireflyException('20028: The budget limit does not belong to the budget.');
}
// continue!
$manager = $this->getManager();
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budgetLimit, $transformer, 'budget_limits');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* Display a listing of the budget limits for this budget..
*
@ -150,4 +125,28 @@ class ShowController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* @param Request $request
* @param Budget $budget
* @param BudgetLimit $budgetLimit
*
* @return JsonResponse
*/
public function show(Request $request, Budget $budget, BudgetLimit $budgetLimit): JsonResponse
{
if ((int)$budget->id !== (int)$budgetLimit->budget_id) {
throw new FireflyException('20028: The budget limit does not belong to the budget.');
}
// continue!
$manager = $this->getManager();
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budgetLimit, $transformer, 'budget_limits');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@ -28,7 +28,6 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Transformers\BudgetLimitTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;

View File

@ -74,5 +74,4 @@ class DestroyController extends Controller
}
}

View File

@ -61,6 +61,37 @@ class ListController extends Controller
);
}
/**
* List all bills
*
* @param ObjectGroup $objectGroup
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function bills(ObjectGroup $objectGroup): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of piggy banks. Count it and split it.
$collection = $this->repository->getBills($objectGroup);
$count = $collection->count();
$bills = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.bills', [$objectGroup->id]) . $this->buildParams());
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($bills, $transformer, 'bills');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* List all piggies under the object group.
@ -97,36 +128,4 @@ class ListController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* List all bills
*
* @param ObjectGroup $objectGroup
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function bills(ObjectGroup $objectGroup): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of piggy banks. Count it and split it.
$collection = $this->repository->getBills($objectGroup);
$count = $collection->count();
$bills = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.bills', [$objectGroup->id]) . $this->buildParams());
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($bills, $transformer, 'bills');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@ -61,7 +61,6 @@ class UpdateController extends Controller
}
/**
* Update single recurrence.
*

View File

@ -24,7 +24,6 @@ namespace FireflyIII\Api\V1\Controllers\Models\Rule;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;

View File

@ -24,7 +24,6 @@ namespace FireflyIII\Api\V1\Controllers\Models\Rule;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Transformers\RuleTransformer;
use FireflyIII\User;
@ -97,7 +96,6 @@ class ShowController extends Controller
}
/**
* List single resource.
*

View File

@ -25,7 +25,6 @@ namespace FireflyIII\Api\V1\Controllers\Models\Tag;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@ -59,7 +58,6 @@ class DestroyController extends Controller
}
/**
* Delete the resource.
*

View File

@ -42,6 +42,7 @@ use League\Fractal\Resource\Collection as FractalCollection;
class ListController extends Controller
{
use TransactionFilter;
private TagRepositoryInterface $repository;
@ -67,7 +68,6 @@ class ListController extends Controller
}
/**
* @param Tag $tag
*
@ -98,7 +98,6 @@ class ListController extends Controller
}
/**
* Show all transactions.
*

View File

@ -25,7 +25,6 @@ namespace FireflyIII\Api\V1\Controllers\Models\Tag;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\TagTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@ -95,7 +94,6 @@ class ShowController extends Controller
}
/**
* List single resource.
*

View File

@ -25,7 +25,6 @@ namespace FireflyIII\Api\V1\Controllers\Models\Tag;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Tag\StoreRequest;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\TagTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@ -61,7 +60,6 @@ class StoreController extends Controller
}
/**
* Store new object.
*

View File

@ -26,7 +26,6 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Tag\UpdateRequest;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\TagTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@ -62,7 +61,6 @@ class UpdateController extends Controller
}
/**
* Update a rule.
*

View File

@ -27,7 +27,6 @@ use FireflyIII\Events\DestroyedTransactionGroup;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;

View File

@ -26,8 +26,6 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalAPIRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\PiggyBankEventTransformer;
use FireflyIII\Transformers\TransactionLinkTransformer;
@ -130,7 +128,6 @@ class ListController extends Controller
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
// /** @var PiggyBankEventTransformer $transformer */
// $transformer = app(PiggyBankEventTransformer::class);
// $transformer->setParameters($this->parameters);

View File

@ -94,6 +94,18 @@ class ShowController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* Show a single transaction, by transaction journal.
*
* @param TransactionJournal $transactionJournal
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function showJournal(TransactionJournal $transactionJournal): JsonResponse
{
return $this->show($transactionJournal->transactionGroup);
}
/**
* Show a single transaction.
@ -130,17 +142,4 @@ class ShowController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* Show a single transaction, by transaction journal.
*
* @param TransactionJournal $transactionJournal
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function showJournal(TransactionJournal $transactionJournal): JsonResponse
{
return $this->show($transactionJournal->transactionGroup);
}
}

View File

@ -32,8 +32,8 @@ use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Log;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class UpdateController

View File

@ -50,8 +50,6 @@ class StoreController extends Controller
}
/**
* Store new currency.
*

View File

@ -18,6 +18,7 @@ use League\Fractal\Resource\Item;
class StoreController extends Controller
{
use TransactionFilter;
private JournalRepositoryInterface $journalRepository;
private LinkTypeRepositoryInterface $repository;

View File

@ -49,7 +49,6 @@ class ListController extends Controller
}
/**
* Delete the resource.
*

View File

@ -81,7 +81,6 @@ class ShowController extends Controller
}
/**
* List single resource.
*

View File

@ -47,7 +47,6 @@ class StoreController extends Controller
}
/**
* Store new object.
*

View File

@ -48,7 +48,6 @@ class UpdateController extends Controller
}
/**
* Update object.
*

View File

@ -85,6 +85,41 @@ class ConfigurationController extends Controller
return response()->json($return);
}
/**
* Get all config values.
*
* @return array
* @throws FireflyException
*/
private function getDynamicConfiguration(): array
{
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
$updateCheck = app('fireflyconfig')->get('permission_update_check');
$lastCheck = app('fireflyconfig')->get('last_update_check');
$singleUser = app('fireflyconfig')->get('single_user_mode');
return [
'is_demo_site' => null === $isDemoSite ? null : $isDemoSite->data,
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data,
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data,
'single_user_mode' => null === $singleUser ? null : $singleUser->data,
];
}
/**
* @return array
*/
private function getStaticConfiguration(): array
{
$list = EitherConfigKey::$static;
$return = [];
foreach ($list as $key) {
$return[$key] = config($key);
}
return $return;
}
/**
* @param string $configKey
*
@ -144,41 +179,4 @@ class ConfigurationController extends Controller
return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
}
/**
* @return array
*/
private function getStaticConfiguration(): array
{
$list = EitherConfigKey::$static;
$return = [];
foreach ($list as $key) {
$return[$key] = config($key);
}
return $return;
}
/**
* Get all config values.
*
* @return array
* @throws FireflyException
*/
private function getDynamicConfiguration(): array
{
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
$updateCheck = app('fireflyconfig')->get('permission_update_check');
$lastCheck = app('fireflyconfig')->get('last_update_check');
$singleUser = app('fireflyconfig')->get('single_user_mode');
return [
'is_demo_site' => null === $isDemoSite ? null : $isDemoSite->data,
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data,
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data,
'single_user_mode' => null === $singleUser ? null : $singleUser->data,
];
}
}

View File

@ -73,6 +73,26 @@ class PreferencesController extends Controller
}
/**
* Return a single preference by name.
*
* @param Preference $preference
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function show(Preference $preference): JsonResponse
{
$manager = $this->getManager();
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($preference, $transformer, 'preferences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* @param PreferenceStoreRequest $request
*
@ -113,24 +133,4 @@ class PreferencesController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* Return a single preference by name.
*
* @param Preference $preference
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function show(Preference $preference): JsonResponse
{
$manager = $this->getManager();
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($preference, $transformer, 'preferences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@ -29,7 +29,6 @@ use FireflyIII\Models\WebhookAttempt;
use FireflyIII\Models\WebhookMessage;
use FireflyIII\Repositories\Webhook\WebhookRepositoryInterface;
use FireflyIII\Transformers\WebhookAttemptTransformer;
use FireflyIII\Transformers\WebhookMessageTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
@ -42,8 +41,8 @@ use League\Fractal\Resource\Item;
*/
class AttemptController extends Controller
{
private WebhookRepositoryInterface $repository;
public const RESOURCE_KEY = 'webhook_attempts';
private WebhookRepositoryInterface $repository;
/**
* @codeCoverageIgnore

View File

@ -95,24 +95,6 @@ class DestroyController extends Controller
return response()->json([], 204);
}
/**
* Remove the specified resource from storage.
*
* @param Webhook $webhook
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function destroyMessage(Webhook $webhook, WebhookMessage $message): JsonResponse
{
if ($message->webhook_id !== $webhook->id) {
throw new FireflyException('Webhook and webhook message are no match');
}
$this->repository->destroyMessage($message);
return response()->json([], 204);
}
/**
* Remove the specified resource from storage.
*
@ -136,6 +118,23 @@ class DestroyController extends Controller
return response()->json([], 204);
}
/**
* Remove the specified resource from storage.
*
* @param Webhook $webhook
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function destroyMessage(Webhook $webhook, WebhookMessage $message): JsonResponse
{
if ($message->webhook_id !== $webhook->id) {
throw new FireflyException('Webhook and webhook message are no match');
}
$this->repository->destroyMessage($message);
return response()->json([], 204);
}
}

View File

@ -37,21 +37,6 @@ class ExportRequest extends FormRequest
{
use ChecksLogin, ConvertsDataTypes;
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
return [
'type' => 'in:csv',
'accounts' => 'min:1',
'start' => 'date|before:end',
'end' => 'date|after:start',
];
}
public function getAll(): array
{
$result = [
@ -77,4 +62,19 @@ class ExportRequest extends FormRequest
return $result;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
return [
'type' => 'in:csv',
'accounts' => 'min:1',
'start' => 'date|before:end',
'end' => 'date|after:start',
];
}
}

View File

@ -25,31 +25,110 @@ class GenericRequest extends FormRequest
use ConvertsDataTypes, ChecksLogin;
private Collection $accounts;
private Collection $bills;
private Collection $budgets;
private Collection $categories;
private Collection $bills;
private Collection $tags;
/**
* @return Carbon
* Get all data from the request.
*
* @return array
*/
public function getStart(): Carbon
public function getAll(): array
{
$date = $this->date('start');
$date->startOfDay();
return $date;
return [
'start' => $this->date('start'),
'end' => $this->date('end'),
];
}
/**
* @return Carbon
* @return Collection
*/
public function getEnd(): Carbon
public function getAssetAccounts(): Collection
{
$date = $this->date('end');
$date->endOfDay();
$this->parseAccounts();
$return = new Collection;
/** @var Account $account */
foreach ($this->accounts as $account) {
$type = $account->accountType->type;
if (in_array($type, [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE])) {
$return->push($account);
}
}
return $date;
return $return;
}
/**
*
*/
private function parseAccounts(): void
{
if (null === $this->accounts) {
$this->accounts = new Collection;
}
if (0 !== $this->accounts->count()) {
return;
}
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('accounts');
if (is_array($array)) {
foreach ($array as $accountId) {
$accountId = (int)$accountId;
$account = $repository->findNull($accountId);
if (null !== $account) {
$this->accounts->push($account);
}
}
}
}
/**
* @return Collection
*/
public function getBills(): Collection
{
$this->parseBills();
return $this->bills;
}
/**
*
*/
private function parseBills(): void
{
if (null === $this->bills) {
$this->bills = new Collection;
}
if (0 !== $this->bills->count()) {
return;
}
$repository = app(BillRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('bills');
if (is_array($array)) {
foreach ($array as $billId) {
$billId = (int)$billId;
$bill = $repository->find($billId);
if (null !== $billId) {
$this->bills->push($bill);
}
}
}
}
/**
* @return Collection
*/
public function getBudgets(): Collection
{
$this->parseBudgets();
return $this->budgets;
}
/**
@ -77,16 +156,6 @@ class GenericRequest extends FormRequest
}
}
/**
* @return Collection
*/
public function getBudgets(): Collection
{
$this->parseBudgets();
return $this->budgets;
}
/**
* @return Collection
*/
@ -98,42 +167,39 @@ class GenericRequest extends FormRequest
}
/**
* @return Collection
*
*/
public function getBills(): Collection
private function parseCategories(): void
{
$this->parseBills();
return $this->bills;
if (null === $this->categories) {
$this->categories = new Collection;
}
if (0 !== $this->categories->count()) {
return;
}
$repository = app(CategoryRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('categories');
if (is_array($array)) {
foreach ($array as $categoryId) {
$categoryId = (int)$categoryId;
$category = $repository->findNull($categoryId);
if (null !== $categoryId) {
$this->categories->push($category);
}
}
}
}
/**
* @return Collection
* @return Carbon
*/
public function getTags(): Collection
public function getEnd(): Carbon
{
$this->parseTags();
$date = $this->date('end');
$date->endOfDay();
return $this->tags;
}
/**
* @return Collection
*/
public function getAssetAccounts(): Collection
{
$this->parseAccounts();
$return = new Collection;
/** @var Account $account */
foreach ($this->accounts as $account) {
$type = $account->accountType->type;
if (in_array($type, [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE])) {
$return->push($account);
}
}
return $return;
return $date;
}
/**
@ -173,111 +239,24 @@ class GenericRequest extends FormRequest
}
/**
* Get all data from the request.
*
* @return array
* @return Carbon
*/
public function getAll(): array
public function getStart(): Carbon
{
return [
'start' => $this->date('start'),
'end' => $this->date('end'),
];
$date = $this->date('start');
$date->startOfDay();
return $date;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
* @return Collection
*/
public function rules(): array
public function getTags(): Collection
{
// this is cheating but it works:
$this->accounts = new Collection;
$this->budgets = new Collection;
$this->categories = new Collection;
$this->bills = new Collection;
$this->tags = new Collection;
$this->parseTags();
return [
'start' => 'required|date',
'end' => 'required|date|after:start',
];
}
/**
*
*/
private function parseAccounts(): void
{
if (null === $this->accounts) {
$this->accounts = new Collection;
}
if (0 !== $this->accounts->count()) {
return;
}
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('accounts');
if (is_array($array)) {
foreach ($array as $accountId) {
$accountId = (int)$accountId;
$account = $repository->findNull($accountId);
if (null !== $account) {
$this->accounts->push($account);
}
}
}
}
/**
*
*/
private function parseBills(): void
{
if (null === $this->bills) {
$this->bills = new Collection;
}
if (0 !== $this->bills->count()) {
return;
}
$repository = app(BillRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('bills');
if (is_array($array)) {
foreach ($array as $billId) {
$billId = (int)$billId;
$bill = $repository->find($billId);
if (null !== $billId) {
$this->bills->push($bill);
}
}
}
}
/**
*
*/
private function parseCategories(): void
{
if (null === $this->categories) {
$this->categories = new Collection;
}
if (0 !== $this->categories->count()) {
return;
}
$repository = app(CategoryRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('categories');
if (is_array($array)) {
foreach ($array as $categoryId) {
$categoryId = (int)$categoryId;
$category = $repository->findNull($categoryId);
if (null !== $categoryId) {
$this->categories->push($category);
}
}
}
return $this->tags;
}
/**
@ -304,4 +283,24 @@ class GenericRequest extends FormRequest
}
}
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
// this is cheating but it works:
$this->accounts = new Collection;
$this->budgets = new Collection;
$this->categories = new Collection;
$this->bills = new Collection;
$this->tags = new Collection;
return [
'start' => 'required|date',
'end' => 'required|date|after:start',
];
}
}

View File

@ -45,8 +45,9 @@ class UpdateRequest extends FormRequest
{
$fields = [
'name' => ['name', 'string'],
'notes' => ['notes', 'nlString']
'notes' => ['notes', 'nlString'],
];
return $this->getAllData($fields);
}

View File

@ -44,8 +44,9 @@ class UpdateRequest extends FormRequest
{
$fields = [
'title' => ['title', 'string'],
'order' =>['order', 'integer']
'order' => ['order', 'integer'],
];
return $this->getAllData($fields);
}

View File

@ -76,29 +76,6 @@ class UpdateRequest extends FormRequest
return $return;
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array|null
*/
private function getTransactionData(): ?array
{
$return = [];
// transaction data:
/** @var array $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return null;
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
/**
* Returns the repetition data as it is found in the submitted data.
*
@ -140,6 +117,29 @@ class UpdateRequest extends FormRequest
return $return;
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array|null
*/
private function getTransactionData(): ?array
{
$return = [];
// transaction data:
/** @var array $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return null;
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*

View File

@ -38,7 +38,6 @@ class TriggerRequest extends FormRequest
use ConvertsDataTypes, ChecksLogin;
/**
* @return array
*/

View File

@ -29,7 +29,6 @@ use Carbon\Carbon;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Collection;
/**
* Class TestRequest
@ -39,7 +38,6 @@ class TestRequest extends FormRequest
use ConvertsDataTypes, ChecksLogin;
/**
* @return array
*/

View File

@ -38,7 +38,6 @@ class TriggerRequest extends FormRequest
use ConvertsDataTypes, ChecksLogin;
/**
* @return array
*/

View File

@ -59,6 +59,7 @@ class StoreRequest extends FormRequest
'apply_rules' => $this->boolean('apply_rules', true),
'transactions' => $this->getTransactionData(),
];
// TODO location
return $data;
}

View File

@ -23,11 +23,9 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\TransactionLinkType;
use FireflyIII\Models\LinkType;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
/**
* Class StoreRequest

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\TransactionLinkType;
use FireflyIII\Models\LinkType;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
@ -62,6 +61,7 @@ class UpdateRequest extends FormRequest
public function rules(): array
{
$linkType = $this->route()->parameter('linkType');
return [
'name' => [Rule::unique('link_types', 'name')->ignore($linkType->id), 'min:1'],
'outward' => ['different:inward', Rule::unique('link_types', 'outward')->ignore($linkType->id), 'min:1'],

View File

@ -39,7 +39,6 @@ class UpdateRequest extends FormRequest
use ConvertsDataTypes, ChecksLogin;
/**
* Get all data from the request.
*

View File

@ -31,24 +31,23 @@ use Str;
/**
* Class CreateFirstUser
*
* @package FireflyIII\Console\Commands
*/
class CreateFirstUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:create-first-user {email}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Creates a new user and gives admin rights. Outputs the password on the command line. Strictly for testing.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:create-first-user {email}';
private UserRepositoryInterface $repository;
/**
@ -60,12 +59,14 @@ class CreateFirstUser extends Command
{
if ('testing' !== env('APP_ENV', 'local')) {
$this->error('This command only works in the testing environment.');
return 1;
}
$this->stupidLaravel();
$count = $this->repository->count();
if ($count > 0) {
$this->error('Already have more than zero users in DB.');
return 1;
}
$data = [
@ -82,6 +83,7 @@ class CreateFirstUser extends Command
$this->info(sprintf('Created new admin user (ID #%d) with email address "%s" and password "%s".', $user->id, $user->email, $password));
$this->error('Change this password.');
return 0;
}

View File

@ -85,6 +85,26 @@ class DecryptDatabase extends Command
return 0;
}
/**
* @param string $table
* @param array $fields
*/
private function decryptTable(string $table, array $fields): void
{
if ($this->isDecrypted($table)) {
$this->info(sprintf('No decryption required for table "%s".', $table));
return;
}
foreach ($fields as $field) {
$this->decryptField($table, $field);
}
$this->line(sprintf('Decrypted the data in table "%s".', $table));
// mark as decrypted:
$configName = sprintf('is_decrypted_%s', $table);
app('fireflyconfig')->set($configName, true);
}
/**
* @param string $table
*
@ -106,47 +126,6 @@ class DecryptDatabase extends Command
return false;
}
/**
* Tries to decrypt data. Will only throw an exception when the MAC is invalid.
*
* @param $value
*
* @return string
* @throws FireflyException
*/
private function tryDecrypt($value)
{
try {
$value = Crypt::decrypt($value);
} catch (DecryptException $e) {
if ('The MAC is invalid.' === $e->getMessage()) {
throw new FireflyException($e->getMessage()); // @codeCoverageIgnore
}
}
return $value;
}
/**
* @param string $table
* @param array $fields
*/
private function decryptTable(string $table, array $fields): void
{
if ($this->isDecrypted($table)) {
$this->info(sprintf('No decryption required for table "%s".', $table));
return;
}
foreach ($fields as $field) {
$this->decryptField($table, $field);
}
$this->line(sprintf('Decrypted the data in table "%s".', $table));
// mark as decrypted:
$configName = sprintf('is_decrypted_%s', $table);
app('fireflyconfig')->set($configName, true);
}
/**
* @param string $table
* @param string $field
@ -186,6 +165,7 @@ class DecryptDatabase extends Command
// A separate routine for preferences table:
if ('preferences' === $table) {
$this->decryptPreferencesRow($id, $value);
return;
}
@ -194,6 +174,27 @@ class DecryptDatabase extends Command
}
}
/**
* Tries to decrypt data. Will only throw an exception when the MAC is invalid.
*
* @param $value
*
* @return string
* @throws FireflyException
*/
private function tryDecrypt($value)
{
try {
$value = Crypt::decrypt($value);
} catch (DecryptException $e) {
if ('The MAC is invalid.' === $e->getMessage()) {
throw new FireflyException($e->getMessage()); // @codeCoverageIgnore
}
}
return $value;
}
/**
* @param int $id
* @param string $value
@ -209,6 +210,7 @@ class DecryptDatabase extends Command
Log::warning($message);
Log::warning($value);
Log::warning($e->getTraceAsString());
return;
}

View File

@ -88,6 +88,7 @@ class ScanAttachments extends Command
}
app('telemetry')->feature('system.command.executed', $this->signature);
return 0;
}
}

View File

@ -63,14 +63,6 @@ class MigrateRecurrenceType extends Command
return false; // @codeCoverageIgnore
}
/**
*
*/
private function getInvalidType(): TransactionType
{
return TransactionType::whereType(TransactionType::INVALID)->firstOrCreate(['type' => TransactionType::INVALID]);
}
/**
*
*/
@ -85,14 +77,6 @@ class MigrateRecurrenceType extends Command
}
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
private function migrateRecurrence(Recurrence $recurrence): void
{
$originalType = (int)$recurrence->transaction_type_id;
@ -106,4 +90,20 @@ class MigrateRecurrenceType extends Command
}
$this->line(sprintf('Updated recurrence #%d to new transaction type model.', $recurrence->id));
}
/**
*
*/
private function getInvalidType(): TransactionType
{
return TransactionType::whereType(TransactionType::INVALID)->firstOrCreate(['type' => TransactionType::INVALID]);
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}

View File

@ -80,6 +80,53 @@ class UpgradeFireflyInstructions extends Command
return 0;
}
/**
* Render upgrade instructions.
*/
private function updateInstructions(): void
{
/** @var string $version */
$version = config('firefly.version');
$config = config('upgrade.text.upgrade');
$text = '';
foreach (array_keys($config) as $compare) {
// if string starts with:
if (0 === strpos($version, $compare)) {
$text = $config[$compare];
}
}
$this->showLine();
$this->boxed('');
if (null === $text) {
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s', $version));
$this->boxedInfo('There are no extra upgrade instructions.');
$this->boxed('Firefly III should be ready for use.');
$this->boxed('');
$this->showLine();
return;
}
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s!', $version));
$this->boxedInfo($text);
$this->boxed('');
$this->showLine();
}
/**
* Show a line.
*/
private function showLine(): void
{
$line = '+';
for ($i = 0; $i < 78; ++$i) {
$line .= '-';
}
$line .= '+';
$this->line($line);
}
/**
* Show a nice box.
*
@ -140,51 +187,4 @@ class UpgradeFireflyInstructions extends Command
$this->boxed('');
$this->showLine();
}
/**
* Show a line.
*/
private function showLine(): void
{
$line = '+';
for ($i = 0; $i < 78; ++$i) {
$line .= '-';
}
$line .= '+';
$this->line($line);
}
/**
* Render upgrade instructions.
*/
private function updateInstructions(): void
{
/** @var string $version */
$version = config('firefly.version');
$config = config('upgrade.text.upgrade');
$text = '';
foreach (array_keys($config) as $compare) {
// if string starts with:
if (0 === strpos($version, $compare)) {
$text = $config[$compare];
}
}
$this->showLine();
$this->boxed('');
if (null === $text) {
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s', $version));
$this->boxedInfo('There are no extra upgrade instructions.');
$this->boxed('Firefly III should be ready for use.');
$this->boxed('');
$this->showLine();
return;
}
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s!', $version));
$this->boxedInfo($text);
$this->boxed('');
$this->showLine();
}
}

View File

@ -38,8 +38,8 @@ use Log;
trait VerifiesAccessToken
{
/**
* @throws FireflyException
* @return User
* @throws FireflyException
*/
public function getUser(): User
{

View File

@ -35,6 +35,7 @@ use Illuminate\Queue\SerializesModels;
class DestroyedTransactionGroup extends Event
{
use SerializesModels;
public TransactionGroup $transactionGroup;

View File

@ -20,6 +20,7 @@
*/
declare(strict_types=1);
namespace FireflyIII\Events;

View File

@ -20,6 +20,7 @@
*/
declare(strict_types=1);
namespace FireflyIII\Events;

View File

@ -128,8 +128,10 @@ class GracefulNotFoundHandler extends ExceptionHandler
case 'transactions.bulk.edit':
if ('POST' === $request->method()) {
$request->session()->reflash();
return redirect(route('index'));
}
return parent::render($request, $exception);
}
@ -163,6 +165,46 @@ class GracefulNotFoundHandler extends ExceptionHandler
return redirect(route('accounts.index', [$shortType]));
}
/**
* @param Throwable $request
* @param Exception $exception
*
* @return RedirectResponse|\Illuminate\Http\Response|Redirector|Response
* @throws Exception
*/
private function handleGroup(Request $request, Throwable $exception)
{
Log::debug('404 page is probably a deleted group. Redirect to overview of group types.');
/** @var User $user */
$user = auth()->user();
$route = $request->route();
$groupId = (int)$route->parameter('transactionGroup');
/** @var TransactionGroup $group */
$group = $user->transactionGroups()->withTrashed()->find($groupId);
if (null === $group) {
Log::error(sprintf('Could not find group %d, so give big fat error.', $groupId));
return parent::render($request, $exception);
}
/** @var TransactionJournal $journal */
$journal = $group->transactionJournals()->withTrashed()->first();
if (null === $journal) {
Log::error(sprintf('Could not find journal for group %d, so give big fat error.', $groupId));
return parent::render($request, $exception);
}
$type = $journal->transactionType->type;
$request->session()->reflash();
if (TransactionType::RECONCILIATION === $type) {
return redirect(route('accounts.index', ['asset']));
}
return redirect(route('transactions.index', [strtolower($type)]));
}
/**
* @param Request $request
* @param Throwable $exception
@ -208,44 +250,4 @@ class GracefulNotFoundHandler extends ExceptionHandler
return parent::render($request, $exception);
}
/**
* @param Throwable $request
* @param Exception $exception
*
* @return RedirectResponse|\Illuminate\Http\Response|Redirector|Response
* @throws Exception
*/
private function handleGroup(Request $request, Throwable $exception)
{
Log::debug('404 page is probably a deleted group. Redirect to overview of group types.');
/** @var User $user */
$user = auth()->user();
$route = $request->route();
$groupId = (int) $route->parameter('transactionGroup');
/** @var TransactionGroup $group */
$group = $user->transactionGroups()->withTrashed()->find($groupId);
if (null === $group) {
Log::error(sprintf('Could not find group %d, so give big fat error.', $groupId));
return parent::render($request, $exception);
}
/** @var TransactionJournal $journal */
$journal = $group->transactionJournals()->withTrashed()->first();
if (null === $journal) {
Log::error(sprintf('Could not find journal for group %d, so give big fat error.', $groupId));
return parent::render($request, $exception);
}
$type = $journal->transactionType->type;
$request->session()->reflash();
if (TransactionType::RECONCILIATION === $type) {
return redirect(route('accounts.index', ['asset']));
}
return redirect(route('transactions.index', [strtolower($type)]));
}
}

View File

@ -36,6 +36,7 @@ use Illuminate\Validation\ValidationException as LaravelValidationException;
use League\OAuth2\Server\Exception\OAuthServerException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;
/**
* Class Handler
*
@ -87,7 +88,9 @@ class Handler extends ExceptionHandler
);
}
return response()->json(['message' => sprintf('Internal Firefly III Exception: %s', $exception->getMessage()), 'exception' => get_class($exception)], 500);
return response()->json(
['message' => sprintf('Internal Firefly III Exception: %s', $exception->getMessage()), 'exception' => get_class($exception)], 500
);
}
if ($exception instanceof NotFoundHttpException) {
@ -115,9 +118,9 @@ class Handler extends ExceptionHandler
*
* @param Exception $exception
*
* @return void
* @throws Exception
*
* @return void
*/
public function report(Throwable $exception)
{

View File

@ -65,6 +65,31 @@ class AccountFactory
}
/**
* @param string $accountName
* @param string $accountType
*
* @return Account
* @throws FireflyException
*/
public function findOrCreate(string $accountName, string $accountType): Account
{
Log::debug(sprintf('Searching for "%s" of type "%s"', $accountName, $accountType));
/** @var AccountType $type */
$type = AccountType::whereType($accountType)->first();
$return = $this->user->accounts->where('account_type_id', $type->id)->where('name', $accountName)->first();
if (null === $return) {
Log::debug('Found nothing. Will create a new one.');
$return = $this->create(
['user_id' => $this->user->id, 'name' => $accountName, 'account_type_id' => $type->id, 'account_type' => null, 'virtual_balance' => '0',
'iban' => null, 'active' => true,]
);
}
return $return;
}
/**
* @param array $data
*
@ -150,52 +175,6 @@ class AccountFactory
return $return;
}
/**
* @param string $accountName
* @param string $accountType
*
* @return Account|null
*/
public function find(string $accountName, string $accountType): ?Account
{
$type = AccountType::whereType($accountType)->first();
return $this->user->accounts()->where('account_type_id', $type->id)->where('name', $accountName)->first();
}
/**
* @param string $accountName
* @param string $accountType
*
* @return Account
* @throws FireflyException
*/
public function findOrCreate(string $accountName, string $accountType): Account
{
Log::debug(sprintf('Searching for "%s" of type "%s"', $accountName, $accountType));
/** @var AccountType $type */
$type = AccountType::whereType($accountType)->first();
$return = $this->user->accounts->where('account_type_id', $type->id)->where('name', $accountName)->first();
if (null === $return) {
Log::debug('Found nothing. Will create a new one.');
$return = $this->create(
['user_id' => $this->user->id, 'name' => $accountName, 'account_type_id' => $type->id, 'account_type' => null, 'virtual_balance' => '0',
'iban' => null, 'active' => true,]
);
}
return $return;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* @param int|null $accountTypeId
* @param null|string $accountType
@ -234,5 +213,26 @@ class AccountFactory
}
/**
* @param string $accountName
* @param string $accountType
*
* @return Account|null
*/
public function find(string $accountName, string $accountType): ?Account
{
$type = AccountType::whereType($accountType)->first();
return $this->user->accounts()->where('account_type_id', $type->id)->where('name', $accountName)->first();
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
}

View File

@ -34,16 +34,6 @@ use Log;
*/
class AccountMetaFactory
{
/**
* @param array $data
*
* @return AccountMeta|null
*/
public function create(array $data): ?AccountMeta
{
return AccountMeta::create($data);
}
/**
* Create update or delete meta data.
*
@ -87,4 +77,14 @@ class AccountMetaFactory
return $entry;
}
/**
* @param array $data
*
* @return AccountMeta|null
*/
public function create(array $data): ?AccountMeta
{
return AccountMeta::create($data);
}
}

View File

@ -40,13 +40,14 @@ class AttachmentFactory
/**
* @param array $data
*
* @throws FireflyException
* @return Attachment|null
* @throws FireflyException
*/
public function create(array $data): ?Attachment
{
// append if necessary.
$model = false === strpos($data['attachable_type'], 'FireflyIII') ? sprintf('FireflyIII\\Models\\%s', $data['attachable_type']) : $data['attachable_type'];
$model = false === strpos($data['attachable_type'], 'FireflyIII') ? sprintf('FireflyIII\\Models\\%s', $data['attachable_type'])
: $data['attachable_type'];
// get journal instead of transaction.
if (Transaction::class === $model) {

View File

@ -37,16 +37,6 @@ class CategoryFactory
{
private User $user;
/**
* @param string $name
*
* @return Category|null
*/
public function findByName(string $name): ?Category
{
return $this->user->categories()->where('name', $name)->first();
}
/**
* @param int|null $categoryId
* @param null|string $categoryName
@ -94,6 +84,16 @@ class CategoryFactory
return null;
}
/**
* @param string $name
*
* @return Category|null
*/
public function findByName(string $name): ?Category
{
return $this->user->categories()->where('name', $name)->first();
}
/**
* @param User $user
*/

View File

@ -36,6 +36,43 @@ class TagFactory
{
private User $user;
/**
* @param string $tag
*
* @return Tag|null
*/
public function findOrCreate(string $tag): ?Tag
{
$tag = trim($tag);
Log::debug(sprintf('Now in TagFactory::findOrCreate("%s")', $tag));
/** @var Tag $dbTag */
$dbTag = $this->user->tags()->where('tag', $tag)->first();
if (null !== $dbTag) {
Log::debug(sprintf('Tag exists (#%d), return it.', $dbTag->id));
return $dbTag;
}
$newTag = $this->create(
[
'tag' => $tag,
'date' => null,
'description' => null,
'latitude' => null,
'longitude' => null,
'zoom_level' => null,
]
);
if (null === $newTag) {
Log::error(sprintf('TagFactory::findOrCreate("%s") but tag is unexpectedly NULL!', $tag));
return null;
}
Log::debug(sprintf('Created new tag #%d ("%s")', $newTag->id, $newTag->tag));
return $newTag;
}
/**
* @param array $data
*
@ -70,41 +107,6 @@ class TagFactory
return $tag;
}
/**
* @param string $tag
*
* @return Tag|null
*/
public function findOrCreate(string $tag): ?Tag
{
$tag = trim($tag);
Log::debug(sprintf('Now in TagFactory::findOrCreate("%s")', $tag));
/** @var Tag $dbTag */
$dbTag = $this->user->tags()->where('tag', $tag)->first();
if (null !== $dbTag) {
Log::debug(sprintf('Tag exists (#%d), return it.', $dbTag->id));
return $dbTag;
}
$newTag = $this->create(
[
'tag' => $tag,
'date' => null,
'description' => null,
'latitude' => null,
'longitude' => null,
'zoom_level' => null,
]
);
if (null === $newTag) {
Log::error(sprintf('TagFactory::findOrCreate("%s") but tag is unexpectedly NULL!', $tag));
return null;
}
Log::debug(sprintf('Created new tag #%d ("%s")', $newTag->id, $newTag->tag));
return $newTag;
}
/**
* @param User $user
*/

View File

@ -40,8 +40,8 @@ class TransactionCurrencyFactory
/**
* @param array $data
*
* @throws FireflyException
* @return TransactionCurrency
* @throws FireflyException
*/
public function create(array $data): TransactionCurrency
{

View File

@ -62,8 +62,8 @@ class TransactionFactory
* @param string $amount
* @param string|null $foreignAmount
*
* @throws FireflyException
* @return Transaction
* @throws FireflyException
*/
public function createNegative(string $amount, ?string $foreignAmount): Transaction
{
@ -77,14 +77,74 @@ class TransactionFactory
return $this->create(app('steam')->negative($amount), $foreignAmount);
}
/**
* @param string $amount
* @param string|null $foreignAmount
*
* @return Transaction
* @throws FireflyException
*/
private function create(string $amount, ?string $foreignAmount): Transaction
{
$result = null;
if ('' === $foreignAmount) {
$foreignAmount = null;
}
$data = [
'reconciled' => $this->reconciled,
'account_id' => $this->account->id,
'transaction_journal_id' => $this->journal->id,
'description' => null,
'transaction_currency_id' => $this->currency->id,
'amount' => $amount,
'foreign_amount' => null,
'foreign_currency_id' => null,
'identifier' => 0,
];
try {
$result = Transaction::create($data);
// @codeCoverageIgnoreStart
} catch (QueryException $e) {
Log::error(sprintf('Could not create transaction: %s', $e->getMessage()), $data);
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException('Query exception when creating transaction.');
}
if (null === $result) {
throw new FireflyException('Transaction is NULL.');
}
// @codeCoverageIgnoreEnd
if (null !== $result) {
Log::debug(
sprintf(
'Created transaction #%d (%s %s, account %s), part of journal #%d',
$result->id,
$this->currency->code,
$amount,
$this->account->name,
$this->journal->id
)
);
// do foreign currency thing: add foreign currency info to $one and $two if necessary.
if (null !== $this->foreignCurrency && null !== $foreignAmount && $this->foreignCurrency->id !== $this->currency->id && '' !== $foreignAmount) {
$result->foreign_currency_id = $this->foreignCurrency->id;
$result->foreign_amount = $foreignAmount;
}
$result->save();
}
return $result;
}
/**
* Create transaction with positive amount (for destination accounts).
*
* @param string $amount
* @param string|null $foreignAmount
*
* @throws FireflyException
* @return Transaction
* @throws FireflyException
*/
public function createPositive(string $amount, ?string $foreignAmount): Transaction
{
@ -157,64 +217,4 @@ class TransactionFactory
{
$this->user = $user;
}
/**
* @param string $amount
* @param string|null $foreignAmount
*
* @throws FireflyException
* @return Transaction
*/
private function create(string $amount, ?string $foreignAmount): Transaction
{
$result = null;
if ('' === $foreignAmount) {
$foreignAmount = null;
}
$data = [
'reconciled' => $this->reconciled,
'account_id' => $this->account->id,
'transaction_journal_id' => $this->journal->id,
'description' => null,
'transaction_currency_id' => $this->currency->id,
'amount' => $amount,
'foreign_amount' => null,
'foreign_currency_id' => null,
'identifier' => 0,
];
try {
$result = Transaction::create($data);
// @codeCoverageIgnoreStart
} catch (QueryException $e) {
Log::error(sprintf('Could not create transaction: %s', $e->getMessage()), $data);
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException('Query exception when creating transaction.');
}
if (null === $result) {
throw new FireflyException('Transaction is NULL.');
}
// @codeCoverageIgnoreEnd
if (null !== $result) {
Log::debug(
sprintf(
'Created transaction #%d (%s %s, account %s), part of journal #%d',
$result->id,
$this->currency->code,
$amount,
$this->account->name,
$this->journal->id
)
);
// do foreign currency thing: add foreign currency info to $one and $two if necessary.
if (null !== $this->foreignCurrency && null !== $foreignAmount && $this->foreignCurrency->id !== $this->currency->id && '' !== $foreignAmount) {
$result->foreign_currency_id = $this->foreignCurrency->id;
$result->foreign_amount = $foreignAmount;
}
$result->save();
}
return $result;
}
}

View File

@ -54,8 +54,8 @@ class TransactionGroupFactory
*
* @param array $data
*
* @throws DuplicateTransactionException
* @return TransactionGroup
* @throws DuplicateTransactionException
*/
public function create(array $data): TransactionGroup
{

View File

@ -140,74 +140,6 @@ class TransactionJournalFactory
return $collection;
}
/**
* @param bool $errorOnHash
*/
public function setErrorOnHash(bool $errorOnHash): void
{
$this->errorOnHash = $errorOnHash;
if (true === $errorOnHash) {
Log::info('Will trigger duplication alert for this journal.');
}
}
/**
* Set the user.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->currencyRepository->setUser($this->user);
$this->tagFactory->setUser($user);
$this->billRepository->setUser($this->user);
$this->budgetRepository->setUser($this->user);
$this->categoryRepository->setUser($this->user);
$this->piggyRepository->setUser($this->user);
$this->accountRepository->setUser($this->user);
}
/**
* @param TransactionJournal $journal
* @param NullArrayObject $data
* @param string $field
*/
protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void
{
$set = [
'journal' => $journal,
'name' => $field,
'data' => (string)($data[$field] ?? ''),
];
Log::debug(sprintf('Going to store meta-field "%s", with value "%s".', $set['name'], $set['data']));
/** @var TransactionJournalMetaFactory $factory */
$factory = app(TransactionJournalMetaFactory::class);
$factory->updateOrCreate($set);
}
/**
* Set foreign currency to NULL if it's the same as the normal currency:
*
* @param TransactionCurrency $currency
* @param TransactionCurrency|null $foreignCurrency
*
* @return TransactionCurrency|null
*/
private function compareCurrencies(?TransactionCurrency $currency, ?TransactionCurrency $foreignCurrency): ?TransactionCurrency
{
if (null === $currency) {
return null;
}
if (null !== $foreignCurrency && $foreignCurrency->id === $currency->id) {
return null;
}
return $foreignCurrency;
}
/**
* @param NullArrayObject $row
*
@ -360,6 +292,29 @@ class TransactionJournalFactory
return $journal;
}
/**
* @param NullArrayObject $row
*
* @return string
*/
private function hashArray(NullArrayObject $row): string
{
$dataRow = $row->getArrayCopy();
unset($dataRow['import_hash_v2'], $dataRow['original_source']);
$json = json_encode($dataRow, JSON_THROW_ON_ERROR, 512);
if (false === $json) {
// @codeCoverageIgnoreStart
$json = json_encode((string)microtime(), JSON_THROW_ON_ERROR, 512);
Log::error(sprintf('Could not hash the original row! %s', json_last_error_msg()), $dataRow);
// @codeCoverageIgnoreEnd
}
$hash = hash('sha256', $json);
Log::debug(sprintf('The hash is: %s', $hash), $dataRow);
return $hash;
}
/**
* If this transaction already exists, throw an error.
*
@ -387,6 +342,127 @@ class TransactionJournalFactory
}
}
/**
* @param NullArrayObject $data
*
* @throws FireflyException
*/
private function validateAccounts(NullArrayObject $data): void
{
$transactionType = $data['type'] ?? 'invalid';
$this->accountValidator->setUser($this->user);
$this->accountValidator->setTransactionType($transactionType);
// validate source account.
$sourceId = $data['source_id'] ? (int)$data['source_id'] : null;
$sourceName = $data['source_name'] ? (string)$data['source_name'] : null;
$validSource = $this->accountValidator->validateSource($sourceId, $sourceName, null);
// do something with result:
if (false === $validSource) {
throw new FireflyException(sprintf('Source: %s', $this->accountValidator->sourceError)); // @codeCoverageIgnore
}
Log::debug('Source seems valid.');
// validate destination account
$destinationId = $data['destination_id'] ? (int)$data['destination_id'] : null;
$destinationName = $data['destination_name'] ? (string)$data['destination_name'] : null;
$validDestination = $this->accountValidator->validateDestination($destinationId, $destinationName, null);
// do something with result:
if (false === $validDestination) {
throw new FireflyException(sprintf('Destination: %s', $this->accountValidator->destError)); // @codeCoverageIgnore
}
}
/**
* @param string $type
* @param TransactionCurrency|null $currency
* @param Account $source
* @param Account $destination
*
* @return TransactionCurrency
*/
private function getCurrencyByAccount(string $type, ?TransactionCurrency $currency, Account $source, Account $destination): TransactionCurrency
{
Log::debug('Now ingetCurrencyByAccount()');
switch ($type) {
default:
case TransactionType::WITHDRAWAL:
case TransactionType::TRANSFER:
return $this->getCurrency($currency, $source);
case TransactionType::DEPOSIT:
return $this->getCurrency($currency, $destination);
}
}
/**
* @param TransactionCurrency|null $currency
* @param Account $account
*
* @return TransactionCurrency
*/
private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency
{
Log::debug('Now in getCurrency()');
$preference = $this->accountRepository->getAccountCurrency($account);
if (null === $preference && null === $currency) {
// return user's default:
return app('amount')->getDefaultCurrencyByUser($this->user);
}
$result = ($preference ?? $currency) ?? app('amount')->getSystemCurrency();
Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));
return $result;
}
/**
* Set foreign currency to NULL if it's the same as the normal currency:
*
* @param TransactionCurrency $currency
* @param TransactionCurrency|null $foreignCurrency
*
* @return TransactionCurrency|null
*/
private function compareCurrencies(?TransactionCurrency $currency, ?TransactionCurrency $foreignCurrency): ?TransactionCurrency
{
if (null === $currency) {
return null;
}
if (null !== $foreignCurrency && $foreignCurrency->id === $currency->id) {
return null;
}
return $foreignCurrency;
}
/**
* @param string $type
* @param TransactionCurrency|null $foreignCurrency
* @param Account $destination
*
* @return TransactionCurrency|null
*/
private function getForeignByAccount(string $type, ?TransactionCurrency $foreignCurrency, Account $destination): ?TransactionCurrency
{
if (TransactionType::TRANSFER === $type) {
return $this->getCurrency($foreignCurrency, $destination);
}
return $foreignCurrency;
}
/**
* @param string $description
*
* @return string
*/
private function getDescription(string $description): string
{
$description = '' === $description ? '(empty description)' : $description;
return substr($description, 0, 255);
}
/**
* Force the deletion of an entire set of transaction journals and their meta object in case of
* an error creating a group.
@ -418,110 +494,6 @@ class TransactionJournalFactory
}
}
/**
* @param TransactionCurrency|null $currency
* @param Account $account
*
* @return TransactionCurrency
*/
private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency
{
Log::debug('Now in getCurrency()');
$preference = $this->accountRepository->getAccountCurrency($account);
if (null === $preference && null === $currency) {
// return user's default:
return app('amount')->getDefaultCurrencyByUser($this->user);
}
$result = ($preference ?? $currency) ?? app('amount')->getSystemCurrency();
Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));
return $result;
}
/**
* @param string $type
* @param TransactionCurrency|null $currency
* @param Account $source
* @param Account $destination
*
* @return TransactionCurrency
*/
private function getCurrencyByAccount(string $type, ?TransactionCurrency $currency, Account $source, Account $destination): TransactionCurrency
{
Log::debug('Now ingetCurrencyByAccount()');
switch ($type) {
default:
case TransactionType::WITHDRAWAL:
case TransactionType::TRANSFER:
return $this->getCurrency($currency, $source);
case TransactionType::DEPOSIT:
return $this->getCurrency($currency, $destination);
}
}
/**
* @param string $description
*
* @return string
*/
private function getDescription(string $description): string
{
$description = '' === $description ? '(empty description)' : $description;
return substr($description, 0, 255);
}
/**
* @param string $type
* @param TransactionCurrency|null $foreignCurrency
* @param Account $destination
*
* @return TransactionCurrency|null
*/
private function getForeignByAccount(string $type, ?TransactionCurrency $foreignCurrency, Account $destination): ?TransactionCurrency
{
if (TransactionType::TRANSFER === $type) {
return $this->getCurrency($foreignCurrency, $destination);
}
return $foreignCurrency;
}
/**
* @param NullArrayObject $row
*
* @return string
*/
private function hashArray(NullArrayObject $row): string
{
$dataRow = $row->getArrayCopy();
unset($dataRow['import_hash_v2'], $dataRow['original_source']);
$json = json_encode($dataRow, JSON_THROW_ON_ERROR, 512);
if (false === $json) {
// @codeCoverageIgnoreStart
$json = json_encode((string)microtime(), JSON_THROW_ON_ERROR, 512);
Log::error(sprintf('Could not hash the original row! %s', json_last_error_msg()), $dataRow);
// @codeCoverageIgnoreEnd
}
$hash = hash('sha256', $json);
Log::debug(sprintf('The hash is: %s', $hash), $dataRow);
return $hash;
}
/**
* @param TransactionJournal $journal
* @param NullArrayObject $transaction
*/
private function storeMetaFields(TransactionJournal $journal, NullArrayObject $transaction): void
{
foreach ($this->fields as $field) {
$this->storeMeta($journal, $transaction, $field);
}
}
/**
* Link a piggy bank to this journal.
*
@ -549,34 +521,62 @@ class TransactionJournalFactory
}
/**
* @param NullArrayObject $data
*
* @throws FireflyException
* @param TransactionJournal $journal
* @param NullArrayObject $transaction
*/
private function validateAccounts(NullArrayObject $data): void
private function storeMetaFields(TransactionJournal $journal, NullArrayObject $transaction): void
{
$transactionType = $data['type'] ?? 'invalid';
$this->accountValidator->setUser($this->user);
$this->accountValidator->setTransactionType($transactionType);
// validate source account.
$sourceId = $data['source_id'] ? (int)$data['source_id'] : null;
$sourceName = $data['source_name'] ? (string)$data['source_name'] : null;
$validSource = $this->accountValidator->validateSource($sourceId, $sourceName, null);
// do something with result:
if (false === $validSource) {
throw new FireflyException(sprintf('Source: %s', $this->accountValidator->sourceError)); // @codeCoverageIgnore
foreach ($this->fields as $field) {
$this->storeMeta($journal, $transaction, $field);
}
Log::debug('Source seems valid.');
// validate destination account
$destinationId = $data['destination_id'] ? (int)$data['destination_id'] : null;
$destinationName = $data['destination_name'] ? (string)$data['destination_name'] : null;
$validDestination = $this->accountValidator->validateDestination($destinationId, $destinationName, null);
// do something with result:
if (false === $validDestination) {
throw new FireflyException(sprintf('Destination: %s', $this->accountValidator->destError)); // @codeCoverageIgnore
}
/**
* @param TransactionJournal $journal
* @param NullArrayObject $data
* @param string $field
*/
protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void
{
$set = [
'journal' => $journal,
'name' => $field,
'data' => (string)($data[$field] ?? ''),
];
Log::debug(sprintf('Going to store meta-field "%s", with value "%s".', $set['name'], $set['data']));
/** @var TransactionJournalMetaFactory $factory */
$factory = app(TransactionJournalMetaFactory::class);
$factory->updateOrCreate($set);
}
/**
* @param bool $errorOnHash
*/
public function setErrorOnHash(bool $errorOnHash): void
{
$this->errorOnHash = $errorOnHash;
if (true === $errorOnHash) {
Log::info('Will trigger duplication alert for this journal.');
}
}
/**
* Set the user.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->currencyRepository->setUser($this->user);
$this->tagFactory->setUser($user);
$this->billRepository->setUser($this->user);
$this->budgetRepository->setUser($this->user);
$this->categoryRepository->setUser($this->user);
$this->piggyRepository->setUser($this->user);
$this->accountRepository->setUser($this->user);
}

View File

@ -26,7 +26,6 @@ declare(strict_types=1);
namespace FireflyIII\Factory;
use FireflyIII\Models\TransactionType;
use Log;
/**
* Class TransactionTypeFactory

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Generator\Chart\Basic;
use FireflyIII\Support\ChartColour;
use Log;
/**
* Class ChartJsGenerator.

View File

@ -48,9 +48,9 @@ class MonthReportGenerator implements ReportGeneratorInterface
/**
* Generates the report.
*
* @return string
* @throws FireflyException
* @codeCoverageIgnore
* @return string
*/
public function generate(): string
{
@ -91,78 +91,6 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $result;
}
/**
* Get the audit report.
*
* @param Account $account
* @param Carbon $date
*
* @throws FireflyException
* @return array
*
*/
public function getAuditReport(Account $account, Carbon $date): array
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$accountRepository->setUser($account->user);
/** @var JournalRepositoryInterface $journalRepository */
$journalRepository = app(JournalRepositoryInterface::class);
$journalRepository->setUser($account->user);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($this->start, $this->end)->withAccountInformation()
->withBudgetInformation()->withCategoryInformation()->withBillInformation();
$journals = $collector->getExtractedJournals();
$journals = array_reverse($journals, true);
$dayBeforeBalance = app('steam')->balance($account, $date);
$startBalance = $dayBeforeBalance;
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($account->user);
$currency = $accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
foreach ($journals as $index => $journal) {
$journals[$index]['balance_before'] = $startBalance;
$transactionAmount = $journal['amount'];
// make sure amount is in the right "direction".
if ($account->id === $journal['destination_account_id']) {
$transactionAmount = app('steam')->positive($journal['amount']);
}
if ($currency->id === $journal['foreign_currency_id']) {
$transactionAmount = $journal['foreign_amount'];
if ($account->id === $journal['destination_account_id']) {
$transactionAmount = app('steam')->positive($journal['foreign_amount']);
}
}
$newBalance = bcadd($startBalance, $transactionAmount);
$journals[$index]['balance_after'] = $newBalance;
$startBalance = $newBalance;
// add meta dates for each journal.
$journals[$index]['interest_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'interest_date');
$journals[$index]['book_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'book_date');
$journals[$index]['process_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'process_date');
$journals[$index]['due_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'due_date');
$journals[$index]['payment_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'payment_date');
$journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date');
}
$locale = app('steam')->getLocale();
return [
'journals' => $journals,
'currency' => $currency,
'exists' => !empty($journals),
'end' => $this->end->formatLocalized((string) trans('config.month_and_day', [], $locale)),
'endBalance' => app('steam')->balance($account, $this->end),
'dayBefore' => $date->formatLocalized((string) trans('config.month_and_day', [], $locale)),
'dayBeforeBalance' => $dayBeforeBalance,
];
}
/**
* Account collection setter.
*
@ -260,4 +188,77 @@ class MonthReportGenerator implements ReportGeneratorInterface
{
return $this;
}
/**
* Get the audit report.
*
* @param Account $account
* @param Carbon $date
*
* @return array
*
* @throws FireflyException
*/
public function getAuditReport(Account $account, Carbon $date): array
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$accountRepository->setUser($account->user);
/** @var JournalRepositoryInterface $journalRepository */
$journalRepository = app(JournalRepositoryInterface::class);
$journalRepository->setUser($account->user);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($this->start, $this->end)->withAccountInformation()
->withBudgetInformation()->withCategoryInformation()->withBillInformation();
$journals = $collector->getExtractedJournals();
$journals = array_reverse($journals, true);
$dayBeforeBalance = app('steam')->balance($account, $date);
$startBalance = $dayBeforeBalance;
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($account->user);
$currency = $accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
foreach ($journals as $index => $journal) {
$journals[$index]['balance_before'] = $startBalance;
$transactionAmount = $journal['amount'];
// make sure amount is in the right "direction".
if ($account->id === $journal['destination_account_id']) {
$transactionAmount = app('steam')->positive($journal['amount']);
}
if ($currency->id === $journal['foreign_currency_id']) {
$transactionAmount = $journal['foreign_amount'];
if ($account->id === $journal['destination_account_id']) {
$transactionAmount = app('steam')->positive($journal['foreign_amount']);
}
}
$newBalance = bcadd($startBalance, $transactionAmount);
$journals[$index]['balance_after'] = $newBalance;
$startBalance = $newBalance;
// add meta dates for each journal.
$journals[$index]['interest_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'interest_date');
$journals[$index]['book_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'book_date');
$journals[$index]['process_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'process_date');
$journals[$index]['due_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'due_date');
$journals[$index]['payment_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'payment_date');
$journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date');
}
$locale = app('steam')->getLocale();
return [
'journals' => $journals,
'currency' => $currency,
'exists' => !empty($journals),
'end' => $this->end->formatLocalized((string)trans('config.month_and_day', [], $locale)),
'endBalance' => app('steam')->balance($account, $this->end),
'dayBefore' => $date->formatLocalized((string)trans('config.month_and_day', [], $locale)),
'dayBeforeBalance' => $dayBeforeBalance,
];
}
}

View File

@ -39,9 +39,9 @@ class ReportGeneratorFactory
* @param Carbon $start
* @param Carbon $end
*
* @throws FireflyException
* @return ReportGeneratorInterface
*
* @throws FireflyException
*/
public static function reportGenerator(string $type, Carbon $start, Carbon $end): ReportGeneratorInterface
{

View File

@ -52,20 +52,15 @@ use Illuminate\Support\Collection;
interface MessageGeneratorInterface
{
/**
* @return int
*/
public function getVersion(): int;
/**
*
*/
public function generateMessages(): void;
/**
* @param User $user
* @return int
*/
public function setUser(User $user): void;
public function getVersion(): int;
/**
* @param Collection $objects
@ -76,4 +71,9 @@ interface MessageGeneratorInterface
* @param int $trigger
*/
public function setTrigger(int $trigger): void;
/**
* @param User $user
*/
public function setUser(User $user): void;
}

View File

@ -63,10 +63,10 @@ use Symfony\Component\HttpFoundation\ParameterBag;
*/
class StandardMessageGenerator implements MessageGeneratorInterface
{
private int $version = 0;
private User $user;
private Collection $objects;
private int $trigger;
private User $user;
private int $version = 0;
private Collection $webhooks;
/**
@ -86,11 +86,11 @@ class StandardMessageGenerator implements MessageGeneratorInterface
}
/**
* @param User $user
* @inheritDoc
*/
public function setUser(User $user): void
public function getVersion(): int
{
$this->user = $user;
return $this->version;
}
/**
@ -109,6 +109,14 @@ class StandardMessageGenerator implements MessageGeneratorInterface
$this->trigger = $trigger;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* @return Collection
*/
@ -246,13 +254,4 @@ class StandardMessageGenerator implements MessageGeneratorInterface
return $webhookMessage;
}
/**
* @inheritDoc
*/
public function getVersion(): int
{
return $this->version;
}
}

View File

@ -27,7 +27,6 @@ use FireflyIII\Events\StoredTransactionGroup;
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Webhook;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
use Illuminate\Support\Collection;

View File

@ -30,7 +30,6 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Models\Webhook;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
use Illuminate\Support\Collection;
@ -41,46 +40,6 @@ use Log;
*/
class UpdatedGroupEventHandler
{
/**
* This method will make sure all source / destination accounts are the same.
*
* @param UpdatedTransactionGroup $updatedGroupEvent
*/
public function unifyAccounts(UpdatedTransactionGroup $updatedGroupEvent): void
{
$group = $updatedGroupEvent->transactionGroup;
if (1 === $group->transactionJournals->count()) {
return;
}
Log::debug(sprintf('Correct inconsistent accounts in group #%d', $group->id));
// first journal:
/** @var TransactionJournal $first */
$first = $group->transactionJournals()
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC')
->first();
$all = $group->transactionJournals()->get()->pluck('id')->toArray();
/** @var Account $sourceAccount */
$sourceAccount = $first->transactions()->where('amount', '<', '0')->first()->account;
/** @var Account $destAccount */
$destAccount = $first->transactions()->where('amount', '>', '0')->first()->account;
$type = $first->transactionType->type;
if (TransactionType::TRANSFER === $type || TransactionType::WITHDRAWAL === $type) {
// set all source transactions to source account:
Transaction::whereIn('transaction_journal_id', $all)
->where('amount', '<', 0)->update(['account_id' => $sourceAccount->id]);
}
if (TransactionType::TRANSFER === $type || TransactionType::DEPOSIT === $type) {
// set all destination transactions to destination account:
Transaction::whereIn('transaction_journal_id', $all)
->where('amount', '>', 0)->update(['account_id' => $destAccount->id]);
}
}
/**
* This method will check all the rules when a journal is updated.
*
@ -134,4 +93,44 @@ class UpdatedGroupEventHandler
event(new RequestedSendWebhookMessages);
}
/**
* This method will make sure all source / destination accounts are the same.
*
* @param UpdatedTransactionGroup $updatedGroupEvent
*/
public function unifyAccounts(UpdatedTransactionGroup $updatedGroupEvent): void
{
$group = $updatedGroupEvent->transactionGroup;
if (1 === $group->transactionJournals->count()) {
return;
}
Log::debug(sprintf('Correct inconsistent accounts in group #%d', $group->id));
// first journal:
/** @var TransactionJournal $first */
$first = $group->transactionJournals()
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC')
->first();
$all = $group->transactionJournals()->get()->pluck('id')->toArray();
/** @var Account $sourceAccount */
$sourceAccount = $first->transactions()->where('amount', '<', '0')->first()->account;
/** @var Account $destAccount */
$destAccount = $first->transactions()->where('amount', '>', '0')->first()->account;
$type = $first->transactionType->type;
if (TransactionType::TRANSFER === $type || TransactionType::WITHDRAWAL === $type) {
// set all source transactions to source account:
Transaction::whereIn('transaction_journal_id', $all)
->where('amount', '<', 0)->update(['account_id' => $sourceAccount->id]);
}
if (TransactionType::TRANSFER === $type || TransactionType::DEPOSIT === $type) {
// set all destination transactions to destination account:
Transaction::whereIn('transaction_journal_id', $all)
->where('amount', '>', 0)->update(['account_id' => $destAccount->id]);
}
}
}

View File

@ -128,52 +128,6 @@ class UserEventHandler
return true;
}
/**
* @param Login $event
*/
public function storeUserIPAddress(Login $event): void
{
/** @var User $user */
$user = $event->user;
/** @var array $preference */
$preference = app('preferences')->getForUser($user, 'login_ip_history', [])->data;
$inArray = false;
$ip = request()->ip();
Log::debug(sprintf('User logging in from IP address %s', $ip));
// update array if in array
foreach ($preference as $index => $row) {
if ($row['ip'] === $ip) {
Log::debug('Found IP in array, refresh time.');
$preference[$index]['time'] = now(config('app.timezone'))->format('Y-m-d H:i:s');
$inArray = true;
}
// clean up old entries (6 months)
$carbon = Carbon::createFromFormat('Y-m-d H:i:s', $preference[$index]['time']);
if ($carbon->diffInMonths(today()) > 6) {
Log::debug(sprintf('Entry for %s is very old, remove it.', $row['ip']));
unset($preference[$index]);
}
}
// add to array if not the case:
if (false === $inArray) {
$preference[] = [
'ip' => $ip,
'time' => now(config('app.timezone'))->format('Y-m-d H:i:s'),
'notified' => false,
];
}
$preference = array_values($preference);
app('preferences')->setForUser($user, 'login_ip_history', $preference);
if (false === $inArray && true === config('firefly.warn_new_ip')) {
event(new DetectedNewIPAddress($user, $ip));
}
}
/**
* @param DetectedNewIPAddress $event
*/
@ -329,4 +283,50 @@ class UserEventHandler
return true;
}
/**
* @param Login $event
*/
public function storeUserIPAddress(Login $event): void
{
/** @var User $user */
$user = $event->user;
/** @var array $preference */
$preference = app('preferences')->getForUser($user, 'login_ip_history', [])->data;
$inArray = false;
$ip = request()->ip();
Log::debug(sprintf('User logging in from IP address %s', $ip));
// update array if in array
foreach ($preference as $index => $row) {
if ($row['ip'] === $ip) {
Log::debug('Found IP in array, refresh time.');
$preference[$index]['time'] = now(config('app.timezone'))->format('Y-m-d H:i:s');
$inArray = true;
}
// clean up old entries (6 months)
$carbon = Carbon::createFromFormat('Y-m-d H:i:s', $preference[$index]['time']);
if ($carbon->diffInMonths(today()) > 6) {
Log::debug(sprintf('Entry for %s is very old, remove it.', $row['ip']));
unset($preference[$index]);
}
}
// add to array if not the case:
if (false === $inArray) {
$preference[] = [
'ip' => $ip,
'time' => now(config('app.timezone'))->format('Y-m-d H:i:s'),
'notified' => false,
];
}
$preference = array_values($preference);
app('preferences')->setForUser($user, 'login_ip_history', $preference);
if (false === $inArray && true === config('firefly.warn_new_ip')) {
event(new DetectedNewIPAddress($user, $ip));
}
}
}

View File

@ -200,8 +200,8 @@ class AttachmentHelper implements AttachmentHelperInterface
* @param object $model
* @param array|null $files
*
* @throws FireflyException
* @return bool
* @throws FireflyException
*/
public function saveAttachmentsForModel(object $model, ?array $files): bool
{
@ -227,46 +227,15 @@ class AttachmentHelper implements AttachmentHelperInterface
return true;
}
/**
* Check if a model already has this file attached.
*
* @param UploadedFile $file
* @param Model $model
*
* @return bool
*/
protected function hasFile(UploadedFile $file, Model $model): bool
{
$md5 = md5_file($file->getRealPath());
$name = $file->getClientOriginalName();
$class = get_class($model);
$count = 0;
if (PiggyBank::class === $class) {
$count = $model->account->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
}
if (PiggyBank::class !== $class) {
$count = $model->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
}
$result = false;
if ($count > 0) {
$msg = (string) trans('validation.file_already_attached', ['name' => $name]);
$this->errors->add('attachments', $msg);
Log::error($msg);
$result = true;
}
return $result;
}
/**
* Process the upload of a file.
*
* @param UploadedFile $file
* @param Model $model
*
* @throws EncryptException
* @throws FireflyException
* @return Attachment|null
* @throws FireflyException
* @throws EncryptException
*/
protected function processFile(UploadedFile $file, Model $model): ?Attachment
{
@ -316,6 +285,39 @@ class AttachmentHelper implements AttachmentHelperInterface
return $attachment;
}
/**
* Verify if the file was uploaded correctly.
*
* @param UploadedFile $file
* @param Model $model
*
* @return bool
*/
protected function validateUpload(UploadedFile $file, Model $model): bool
{
Log::debug('Now in validateUpload()');
$result = true;
if (!$this->validMime($file)) {
$result = false;
}
if (0 === $file->getSize()) {
Log::error('Cannot upload empty file.');
$result = false;
}
// @codeCoverageIgnoreStart
// can't seem to reach this point.
if (true === $result && !$this->validSize($file)) {
$result = false;
}
// @codeCoverageIgnoreEnd
if (true === $result && $this->hasFile($file, $model)) {
$result = false;
}
return $result;
}
/**
* Verify if the mime of a file is valid.
*
@ -369,33 +371,31 @@ class AttachmentHelper implements AttachmentHelperInterface
}
/**
* Verify if the file was uploaded correctly.
* Check if a model already has this file attached.
*
* @param UploadedFile $file
* @param Model $model
*
* @return bool
*/
protected function validateUpload(UploadedFile $file, Model $model): bool
protected function hasFile(UploadedFile $file, Model $model): bool
{
Log::debug('Now in validateUpload()');
$md5 = md5_file($file->getRealPath());
$name = $file->getClientOriginalName();
$class = get_class($model);
$count = 0;
if (PiggyBank::class === $class) {
$count = $model->account->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
}
if (PiggyBank::class !== $class) {
$count = $model->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
}
$result = false;
if ($count > 0) {
$msg = (string)trans('validation.file_already_attached', ['name' => $name]);
$this->errors->add('attachments', $msg);
Log::error($msg);
$result = true;
if (!$this->validMime($file)) {
$result = false;
}
if (0 === $file->getSize()) {
Log::error('Cannot upload empty file.');
$result = false;
}
// @codeCoverageIgnoreStart
// can't seem to reach this point.
if (true === $result && !$this->validSize($file)) {
$result = false;
}
// @codeCoverageIgnoreEnd
if (true === $result && $this->hasFile($file, $model)) {
$result = false;
}
return $result;

View File

@ -38,16 +38,17 @@ trait CollectorProperties
private $hasAccountInfo;
/** @var bool Will be true if query result includes bill information. */
private $hasBillInformation;
/** @var bool */
private $hasNotesInformation;
/** @var bool Will be true if query result contains budget info. */
private $hasBudgetInformation;
/** @var bool Will be true if query result contains category info. */
private $hasCatInformation;
/** @var bool Will be true for attachments */
private $hasJoinedAttTables;
private bool $hasJoinedMetaTables;
/** @var bool Will be true of the query has the tag info tables joined. */
private $hasJoinedTagTables;
/** @var bool */
private $hasNotesInformation;
/** @var array */
private $integerFields;
/** @var int The maximum number of results. */
@ -60,6 +61,4 @@ trait CollectorProperties
private $total;
/** @var User The user object. */
private $user;
private bool $hasJoinedMetaTables;
}

View File

@ -39,84 +39,60 @@ trait MetaCollection
{
/**
* @inheritDoc
* Where has no tags.
*
* @return GroupCollectorInterface
*/
public function withNotes(): GroupCollectorInterface
public function hasAnyTag(): GroupCollectorInterface
{
if (false === $this->hasNotesInformation) {
// join bill table
$this->query->leftJoin(
'notes',
static function (JoinClause $join) {
$join->on('notes.noteable_id', '=', 'transaction_journals.id');
$join->where('notes.noteable_type', '=', 'FireflyIII\Models\TransactionJournal');
}
);
// add fields
$this->fields[] = 'notes.text as notes';
$this->hasNotesInformation = true;
}
$this->withTagInformation();
$this->query->whereNotNull('tag_transaction_journal.tag_id');
return $this;
}
/**
* @param string $value
*
* @return GroupCollectorInterface
*/
public function notesContain(string $value): GroupCollectorInterface
{
$this->withNotes();
$this->query->where('notes.text', 'LIKE', sprintf('%%%s%%', $value));
return $this;
}
/**
* @param string $value
*
* @return GroupCollectorInterface
*/
public function notesEndWith(string $value): GroupCollectorInterface
{
$this->withNotes();
$this->query->where('notes.text', 'LIKE', sprintf('%%%s', $value));
return $this;
}
/**
* @return GroupCollectorInterface
*/
public function withoutNotes(): GroupCollectorInterface
{
$this->withNotes();
$this->query->whereNull('notes.text');
return $this;
}
/**
* @return GroupCollectorInterface
*/
public function withAnyNotes(): GroupCollectorInterface
{
$this->withNotes();
$this->query->whereNotNull('notes.text');
return $this;
}
/**
* @param string $value
*
* @return GroupCollectorInterface
*/
public function notesExactly(string $value): GroupCollectorInterface
{
$this->withNotes();
$this->query->where('notes.text', '=', sprintf('%s', $value));
return $this;
}
/**
* @param string $value
*
* @return GroupCollectorInterface
*/
public function notesStartWith(string $value): GroupCollectorInterface
@ -221,219 +197,6 @@ trait MetaCollection
return $this;
}
/**
* Limit results to a specific tag.
*
* @param Tag $tag
*
* @return GroupCollectorInterface
*/
public function setTag(Tag $tag): GroupCollectorInterface
{
$this->withTagInformation();
$this->query->where('tag_transaction_journal.tag_id', $tag->id);
return $this;
}
/**
* Limit results to a specific set of tags.
*
* @param Collection $tags
*
* @return GroupCollectorInterface
*/
public function setTags(Collection $tags): GroupCollectorInterface
{
$this->withTagInformation();
$this->query->whereIn('tag_transaction_journal.tag_id', $tags->pluck('id')->toArray());
return $this;
}
/**
* Where has no tags.
*
* @return GroupCollectorInterface
*/
public function withoutTags(): GroupCollectorInterface
{
$this->withTagInformation();
$this->query->whereNull('tag_transaction_journal.tag_id');
return $this;
}
/**
* Where has no tags.
*
* @return GroupCollectorInterface
*/
public function hasAnyTag(): GroupCollectorInterface
{
$this->withTagInformation();
$this->query->whereNotNull('tag_transaction_journal.tag_id');
return $this;
}
/**
* Will include bill name + ID, if any.
*
* @return GroupCollectorInterface
*/
public function withBillInformation(): GroupCollectorInterface
{
if (false === $this->hasBillInformation) {
// join bill table
$this->query->leftJoin('bills', 'bills.id', '=', 'transaction_journals.bill_id');
// add fields
$this->fields[] = 'bills.id as bill_id';
$this->fields[] = 'bills.name as bill_name';
$this->hasBillInformation = true;
}
return $this;
}
/**
* Will include budget ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withBudgetInformation(): GroupCollectorInterface
{
if (false === $this->hasBudgetInformation) {
// join link table
$this->query->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id');
// add fields
$this->fields[] = 'budgets.id as budget_id';
$this->fields[] = 'budgets.name as budget_name';
$this->hasBudgetInformation = true;
}
return $this;
}
/**
* Will include category ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withCategoryInformation(): GroupCollectorInterface
{
if (false === $this->hasCatInformation) {
// join link table
$this->query->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id');
// add fields
$this->fields[] = 'categories.id as category_id';
$this->fields[] = 'categories.name as category_name';
$this->hasCatInformation = true;
}
return $this;
}
/**
* @return GroupCollectorInterface
*/
public function withTagInformation(): GroupCollectorInterface
{
$this->fields[] = 'tags.id as tag_id';
$this->fields[] = 'tags.tag as tag_name';
$this->fields[] = 'tags.date as tag_date';
$this->fields[] = 'tags.description as tag_description';
$this->fields[] = 'tags.latitude as tag_latitude';
$this->fields[] = 'tags.longitude as tag_longitude';
$this->fields[] = 'tags.zoomLevel as tag_zoom_level';
$this->joinTagTables();
return $this;
}
/**
* Limit results to a transactions without a budget..
*
* @return GroupCollectorInterface
*/
public function withoutBudget(): GroupCollectorInterface
{
$this->withBudgetInformation();
$this->query->whereNull('budget_transaction_journal.budget_id');
return $this;
}
/**
* Limit results to a transactions without a bill.
*
* @return GroupCollectorInterface
*/
public function withoutBill(): GroupCollectorInterface
{
$this->query->whereNull('transaction_journals.bill_id');
return $this;
}
/**
* Limit results to a transactions without a budget..
*
* @return GroupCollectorInterface
*/
public function withBudget(): GroupCollectorInterface
{
$this->withBudgetInformation();
$this->query->whereNotNull('budget_transaction_journal.budget_id');
return $this;
}
/**
* Limit results to a transactions without a category.
*
* @return GroupCollectorInterface
*/
public function withoutCategory(): GroupCollectorInterface
{
$this->withCategoryInformation();
$this->query->whereNull('category_transaction_journal.category_id');
return $this;
}
/**
* Limit results to a transactions without a category.
*
* @return GroupCollectorInterface
*/
public function withCategory(): GroupCollectorInterface
{
$this->withCategoryInformation();
$this->query->whereNotNull('category_transaction_journal.category_id');
return $this;
}
/**
* Join table to get tag information.
*/
protected function joinTagTables(): void
{
if (false === $this->hasJoinedTagTables) {
// join some extra tables:
$this->hasJoinedTagTables = true;
$this->query->leftJoin('tag_transaction_journal', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
$this->query->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id');
}
}
/**
* @inheritDoc
*/
@ -465,5 +228,248 @@ trait MetaCollection
return $this;
}
/**
* Limit results to a specific tag.
*
* @param Tag $tag
*
* @return GroupCollectorInterface
*/
public function setTag(Tag $tag): GroupCollectorInterface
{
$this->withTagInformation();
$this->query->where('tag_transaction_journal.tag_id', $tag->id);
return $this;
}
/**
* Limit results to a specific set of tags.
*
* @param Collection $tags
*
* @return GroupCollectorInterface
*/
public function setTags(Collection $tags): GroupCollectorInterface
{
$this->withTagInformation();
$this->query->whereIn('tag_transaction_journal.tag_id', $tags->pluck('id')->toArray());
return $this;
}
/**
* @return GroupCollectorInterface
*/
public function withAnyNotes(): GroupCollectorInterface
{
$this->withNotes();
$this->query->whereNotNull('notes.text');
return $this;
}
/**
* Will include bill name + ID, if any.
*
* @return GroupCollectorInterface
*/
public function withBillInformation(): GroupCollectorInterface
{
if (false === $this->hasBillInformation) {
// join bill table
$this->query->leftJoin('bills', 'bills.id', '=', 'transaction_journals.bill_id');
// add fields
$this->fields[] = 'bills.id as bill_id';
$this->fields[] = 'bills.name as bill_name';
$this->hasBillInformation = true;
}
return $this;
}
/**
* Limit results to a transactions without a budget..
*
* @return GroupCollectorInterface
*/
public function withBudget(): GroupCollectorInterface
{
$this->withBudgetInformation();
$this->query->whereNotNull('budget_transaction_journal.budget_id');
return $this;
}
/**
* Will include budget ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withBudgetInformation(): GroupCollectorInterface
{
if (false === $this->hasBudgetInformation) {
// join link table
$this->query->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id');
// add fields
$this->fields[] = 'budgets.id as budget_id';
$this->fields[] = 'budgets.name as budget_name';
$this->hasBudgetInformation = true;
}
return $this;
}
/**
* Limit results to a transactions without a category.
*
* @return GroupCollectorInterface
*/
public function withCategory(): GroupCollectorInterface
{
$this->withCategoryInformation();
$this->query->whereNotNull('category_transaction_journal.category_id');
return $this;
}
/**
* Will include category ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withCategoryInformation(): GroupCollectorInterface
{
if (false === $this->hasCatInformation) {
// join link table
$this->query->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id');
// add fields
$this->fields[] = 'categories.id as category_id';
$this->fields[] = 'categories.name as category_name';
$this->hasCatInformation = true;
}
return $this;
}
/**
* @inheritDoc
*/
public function withNotes(): GroupCollectorInterface
{
if (false === $this->hasNotesInformation) {
// join bill table
$this->query->leftJoin(
'notes',
static function (JoinClause $join) {
$join->on('notes.noteable_id', '=', 'transaction_journals.id');
$join->where('notes.noteable_type', '=', 'FireflyIII\Models\TransactionJournal');
}
);
// add fields
$this->fields[] = 'notes.text as notes';
$this->hasNotesInformation = true;
}
return $this;
}
/**
* @return GroupCollectorInterface
*/
public function withTagInformation(): GroupCollectorInterface
{
$this->fields[] = 'tags.id as tag_id';
$this->fields[] = 'tags.tag as tag_name';
$this->fields[] = 'tags.date as tag_date';
$this->fields[] = 'tags.description as tag_description';
$this->fields[] = 'tags.latitude as tag_latitude';
$this->fields[] = 'tags.longitude as tag_longitude';
$this->fields[] = 'tags.zoomLevel as tag_zoom_level';
$this->joinTagTables();
return $this;
}
/**
* Limit results to a transactions without a bill.
*
* @return GroupCollectorInterface
*/
public function withoutBill(): GroupCollectorInterface
{
$this->query->whereNull('transaction_journals.bill_id');
return $this;
}
/**
* Limit results to a transactions without a budget..
*
* @return GroupCollectorInterface
*/
public function withoutBudget(): GroupCollectorInterface
{
$this->withBudgetInformation();
$this->query->whereNull('budget_transaction_journal.budget_id');
return $this;
}
/**
* Limit results to a transactions without a category.
*
* @return GroupCollectorInterface
*/
public function withoutCategory(): GroupCollectorInterface
{
$this->withCategoryInformation();
$this->query->whereNull('category_transaction_journal.category_id');
return $this;
}
/**
* @return GroupCollectorInterface
*/
public function withoutNotes(): GroupCollectorInterface
{
$this->withNotes();
$this->query->whereNull('notes.text');
return $this;
}
/**
* Where has no tags.
*
* @return GroupCollectorInterface
*/
public function withoutTags(): GroupCollectorInterface
{
$this->withTagInformation();
$this->query->whereNull('tag_transaction_journal.tag_id');
return $this;
}
/**
* Join table to get tag information.
*/
protected function joinTagTables(): void
{
if (false === $this->hasJoinedTagTables) {
// join some extra tables:
$this->hasJoinedTagTables = true;
$this->query->leftJoin('tag_transaction_journal', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
$this->query->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id');
}
}
}

View File

@ -126,14 +126,76 @@ class GroupCollector implements GroupCollectorInterface
}
/**
*
* @inheritDoc
*/
public function dumpQuery(): void
public function descriptionEnds(array $array): GroupCollectorInterface
{
echo $this->query->select($this->fields)->toSql();
echo '<pre>';
print_r($this->query->getBindings());
echo '</pre>';
$this->query->where(
static function (EloquentBuilder $q) use ($array) {
$q->where(
static function (EloquentBuilder $q1) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%%%s', $word);
$q1->where('transaction_journals.description', 'LIKE', $keyword);
}
}
);
$q->orWhere(
static function (EloquentBuilder $q2) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%%%s', $word);
$q2->where('transaction_groups.title', 'LIKE', $keyword);
}
}
);
}
);
return $this;
}
/**
* @inheritDoc
*/
public function descriptionIs(string $value): GroupCollectorInterface
{
$this->query->where(
static function (EloquentBuilder $q) use ($value) {
$q->where('transaction_journals.description', '=', $value);
$q->orWhere('transaction_groups.title', '=', $value);
}
);
return $this;
}
/**
* @inheritDoc
*/
public function descriptionStarts(array $array): GroupCollectorInterface
{
$this->query->where(
static function (EloquentBuilder $q) use ($array) {
$q->where(
static function (EloquentBuilder $q1) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%s%%', $word);
$q1->where('transaction_journals.description', 'LIKE', $keyword);
}
}
);
$q->orWhere(
static function (EloquentBuilder $q2) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%s%%', $word);
$q2->where('transaction_groups.title', 'LIKE', $keyword);
}
}
);
}
);
return $this;
}
/**
@ -209,6 +271,19 @@ class GroupCollector implements GroupCollectorInterface
return new LengthAwarePaginator($set, $this->total, $this->limit, $this->page);
}
/**
* Has attachments
*
* @return GroupCollectorInterface
*/
public function hasAttachments(): GroupCollectorInterface
{
Log::debug('Add filter on attachment ID.');
$this->joinAttachmentTables();
$this->query->whereNotNull('attachments.attachable_id');
return $this;
}
/**
* Limit results to a specific currency, either foreign or normal one.
@ -239,6 +314,21 @@ class GroupCollector implements GroupCollectorInterface
return $this;
}
/**
* Limit the result to a set of specific transaction groups.
*
* @param array $groupIds
*
* @return GroupCollectorInterface
*/
public function setIds(array $groupIds): GroupCollectorInterface
{
$this->query->whereIn('transaction_groups.id', $groupIds);
return $this;
}
/**
* Limit the result to a set of specific journals.
*
@ -255,20 +345,6 @@ class GroupCollector implements GroupCollectorInterface
return $this;
}
/**
* Limit the result to a set of specific transaction groups.
*
* @param array $groupIds
*
* @return GroupCollectorInterface
*/
public function setIds(array $groupIds): GroupCollectorInterface {
$this->query->whereIn('transaction_groups.id', $groupIds);
return $this;
}
/**
* Limit the number of returned entries.
*
@ -333,80 +409,6 @@ class GroupCollector implements GroupCollectorInterface
return $this;
}
/**
* @inheritDoc
*/
public function descriptionStarts(array $array): GroupCollectorInterface
{
$this->query->where(
static function (EloquentBuilder $q) use ($array) {
$q->where(
static function (EloquentBuilder $q1) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%s%%', $word);
$q1->where('transaction_journals.description', 'LIKE', $keyword);
}
}
);
$q->orWhere(
static function (EloquentBuilder $q2) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%s%%', $word);
$q2->where('transaction_groups.title', 'LIKE', $keyword);
}
}
);
}
);
return $this;
}
/**
* @inheritDoc
*/
public function descriptionEnds(array $array): GroupCollectorInterface
{
$this->query->where(
static function (EloquentBuilder $q) use ($array) {
$q->where(
static function (EloquentBuilder $q1) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%%%s', $word);
$q1->where('transaction_journals.description', 'LIKE', $keyword);
}
}
);
$q->orWhere(
static function (EloquentBuilder $q2) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%%%s', $word);
$q2->where('transaction_groups.title', 'LIKE', $keyword);
}
}
);
}
);
return $this;
}
/**
* @inheritDoc
*/
public function descriptionIs(string $value): GroupCollectorInterface
{
$this->query->where(
static function (EloquentBuilder $q) use ($value) {
$q->where('transaction_journals.description', '=', $value);
$q->orWhere('transaction_groups.title', '=', $value);
}
);
return $this;
}
/**
* Limit the search to one specific transaction group.
*
@ -483,35 +485,47 @@ class GroupCollector implements GroupCollectorInterface
return $this;
}
/**
* Convert a selected set of fields to arrays.
*
* @param array $array
*
* @return array
* Build the query.
*/
private function convertToInteger(array $array): array
private function startQuery(): void
{
foreach ($this->integerFields as $field) {
$array[$field] = array_key_exists($field, $array) ? (int)$array[$field] : null;
//app('log')->debug('GroupCollector::startQuery');
$this->query = $this->user
//->transactionGroups()
//->leftJoin('transaction_journals', 'transaction_journals.transaction_group_id', 'transaction_groups.id')
->transactionJournals()
->leftJoin('transaction_groups', 'transaction_journals.transaction_group_id', 'transaction_groups.id')
// join source transaction.
->leftJoin(
'transactions as source',
function (JoinClause $join) {
$join->on('source.transaction_journal_id', '=', 'transaction_journals.id')
->where('source.amount', '<', 0);
}
return $array;
)
// join destination transaction
->leftJoin(
'transactions as destination',
function (JoinClause $join) {
$join->on('destination.transaction_journal_id', '=', 'transaction_journals.id')
->where('destination.amount', '>', 0);
}
/**
* Has attachments
*
* @return GroupCollectorInterface
*/
public function hasAttachments(): GroupCollectorInterface
{
Log::debug('Add filter on attachment ID.');
$this->joinAttachmentTables();
$this->query->whereNotNull('attachments.attachable_id');
return $this;
)
// left join transaction type.
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin('transaction_currencies as currency', 'currency.id', '=', 'source.transaction_currency_id')
->leftJoin('transaction_currencies as foreign_currency', 'foreign_currency.id', '=', 'source.foreign_currency_id')
->whereNull('transaction_groups.deleted_at')
->whereNull('transaction_journals.deleted_at')
->whereNull('source.deleted_at')
->whereNull('destination.deleted_at')
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC')
->orderBy('source.amount', 'DESC');
}
/**
@ -533,6 +547,33 @@ class GroupCollector implements GroupCollectorInterface
}
}
/**
*
*/
public function dumpQuery(): void
{
echo $this->query->select($this->fields)->toSql();
echo '<pre>';
print_r($this->query->getBindings());
echo '</pre>';
}
/**
* Convert a selected set of fields to arrays.
*
* @param array $array
*
* @return array
*/
private function convertToInteger(array $array): array
{
foreach ($this->integerFields as $field) {
$array[$field] = array_key_exists($field, $array) ? (int)$array[$field] : null;
}
return $array;
}
/**
* @param array $existingJournal
* @param TransactionJournal $newJournal
@ -735,47 +776,4 @@ class GroupCollector implements GroupCollectorInterface
return $groups;
}
/**
* Build the query.
*/
private function startQuery(): void
{
//app('log')->debug('GroupCollector::startQuery');
$this->query = $this->user
//->transactionGroups()
//->leftJoin('transaction_journals', 'transaction_journals.transaction_group_id', 'transaction_groups.id')
->transactionJournals()
->leftJoin('transaction_groups', 'transaction_journals.transaction_group_id', 'transaction_groups.id')
// join source transaction.
->leftJoin(
'transactions as source',
function (JoinClause $join) {
$join->on('source.transaction_journal_id', '=', 'transaction_journals.id')
->where('source.amount', '<', 0);
}
)
// join destination transaction
->leftJoin(
'transactions as destination',
function (JoinClause $join) {
$join->on('destination.transaction_journal_id', '=', 'transaction_journals.id')
->where('destination.amount', '>', 0);
}
)
// left join transaction type.
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin('transaction_currencies as currency', 'currency.id', '=', 'source.transaction_currency_id')
->leftJoin('transaction_currencies as foreign_currency', 'foreign_currency.id', '=', 'source.foreign_currency_id')
->whereNull('transaction_groups.deleted_at')
->whereNull('transaction_journals.deleted_at')
->whereNull('source.deleted_at')
->whereNull('destination.deleted_at')
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC')
->orderBy('source.amount', 'DESC');
}
}

View File

@ -66,6 +66,33 @@ interface GroupCollectorInterface
*/
public function amountMore(string $amount): GroupCollectorInterface;
/**
* End of the description must match:
*
* @param array $array
*
* @return GroupCollectorInterface
*/
public function descriptionEnds(array $array): GroupCollectorInterface;
/**
* Description must be:
*
* @param string $value
*
* @return GroupCollectorInterface
*/
public function descriptionIs(string $value): GroupCollectorInterface;
/**
* Beginning of the description must match:
*
* @param array $array
*
* @return GroupCollectorInterface
*/
public function descriptionStarts(array $array): GroupCollectorInterface;
/**
* Exclude destination accounts.
*
@ -105,6 +132,46 @@ interface GroupCollectorInterface
*/
public function getPaginatedGroups(): LengthAwarePaginator;
/**
* @return GroupCollectorInterface
*/
public function hasAnyTag(): GroupCollectorInterface;
/**
* Has attachments
*
* @return GroupCollectorInterface
*/
public function hasAttachments(): GroupCollectorInterface;
/**
* @param string $value
*
* @return GroupCollectorInterface
*/
public function notesContain(string $value): GroupCollectorInterface;
/**
* @param string $value
*
* @return GroupCollectorInterface
*/
public function notesEndWith(string $value): GroupCollectorInterface;
/**
* @param string $value
*
* @return GroupCollectorInterface
*/
public function notesExactly(string $value): GroupCollectorInterface;
/**
* @param string $value
*
* @return GroupCollectorInterface
*/
public function notesStartWith(string $value): GroupCollectorInterface;
/**
* Define which accounts can be part of the source and destination transactions.
*
@ -213,15 +280,6 @@ interface GroupCollectorInterface
*/
public function setCurrency(TransactionCurrency $currency): GroupCollectorInterface;
/**
* Limit results to a specific foreign currency.
*
* @param TransactionCurrency $currency
*
* @return GroupCollectorInterface
*/
public function setForeignCurrency(TransactionCurrency $currency): GroupCollectorInterface;
/**
* Set destination accounts.
*
@ -232,13 +290,22 @@ interface GroupCollectorInterface
public function setDestinationAccounts(Collection $accounts): GroupCollectorInterface;
/**
* Limit the result to a set of specific transaction journals.
* Look for specific external ID's.
*
* @param array $journalIds
* @param string $externalId
*
* @return GroupCollectorInterface
*/
public function setJournalIds(array $journalIds): GroupCollectorInterface;
public function setExternalId(string $externalId): GroupCollectorInterface;
/**
* Limit results to a specific foreign currency.
*
* @param TransactionCurrency $currency
*
* @return GroupCollectorInterface
*/
public function setForeignCurrency(TransactionCurrency $currency): GroupCollectorInterface;
/**
* Limit the result to a set of specific transaction groups.
@ -249,6 +316,24 @@ interface GroupCollectorInterface
*/
public function setIds(array $groupIds): GroupCollectorInterface;
/**
* Look for specific external ID's.
*
* @param string $externalId
*
* @return GroupCollectorInterface
*/
public function setInternalReference(string $externalId): GroupCollectorInterface;
/**
* Limit the result to a set of specific transaction journals.
*
* @param array $journalIds
*
* @return GroupCollectorInterface
*/
public function setJournalIds(array $journalIds): GroupCollectorInterface;
/**
* Limit the number of returned entries.
*
@ -286,33 +371,6 @@ interface GroupCollectorInterface
*/
public function setSearchWords(array $array): GroupCollectorInterface;
/**
* Beginning of the description must match:
*
* @param array $array
*
* @return GroupCollectorInterface
*/
public function descriptionStarts(array $array): GroupCollectorInterface;
/**
* End of the description must match:
*
* @param array $array
*
* @return GroupCollectorInterface
*/
public function descriptionEnds(array $array): GroupCollectorInterface;
/**
* Description must be:
*
* @param string $value
*
* @return GroupCollectorInterface
*/
public function descriptionIs(string $value): GroupCollectorInterface;
/**
* Set source accounts.
*
@ -340,16 +398,6 @@ interface GroupCollectorInterface
*/
public function setTags(Collection $tags): GroupCollectorInterface;
/**
* @return GroupCollectorInterface
*/
public function withoutTags(): GroupCollectorInterface;
/**
* @return GroupCollectorInterface
*/
public function hasAnyTag(): GroupCollectorInterface;
/**
* Limit the search to one specific transaction group.
*
@ -409,6 +457,13 @@ interface GroupCollectorInterface
*/
public function withAccountInformation(): GroupCollectorInterface;
/**
* Any notes, no matter what.
*
* @return GroupCollectorInterface
*/
public function withAnyNotes(): GroupCollectorInterface;
/**
* Add basic info on attachments of transactions.
*
@ -416,13 +471,6 @@ interface GroupCollectorInterface
*/
public function withAttachmentInformation(): GroupCollectorInterface;
/**
* Has attachments
*
* @return GroupCollectorInterface
*/
public function hasAttachments(): GroupCollectorInterface;
/**
* Include bill name + ID.
*
@ -430,6 +478,13 @@ interface GroupCollectorInterface
*/
public function withBillInformation(): GroupCollectorInterface;
/**
* Limit results to a transactions with a budget.
*
* @return GroupCollectorInterface
*/
public function withBudget(): GroupCollectorInterface;
/**
* Will include budget ID + name, if any.
*
@ -437,6 +492,13 @@ interface GroupCollectorInterface
*/
public function withBudgetInformation(): GroupCollectorInterface;
/**
* Limit results to a transactions with a category.
*
* @return GroupCollectorInterface
*/
public function withCategory(): GroupCollectorInterface;
/**
* Will include category ID + name, if any.
*
@ -451,42 +513,6 @@ interface GroupCollectorInterface
*/
public function withNotes(): GroupCollectorInterface;
/**
* Any notes, no matter what.
*
* @return GroupCollectorInterface
*/
public function withAnyNotes(): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function notesContain(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function withoutNotes(): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function notesStartWith(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function notesEndWith(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function notesExactly(string $value): GroupCollectorInterface;
/**
* Add tag info.
*
@ -494,13 +520,6 @@ interface GroupCollectorInterface
*/
public function withTagInformation(): GroupCollectorInterface;
/**
* Limit results to a transactions without a budget.
*
* @return GroupCollectorInterface
*/
public function withoutBudget(): GroupCollectorInterface;
/**
* Limit results to a transactions without a bill.
*
@ -508,6 +527,13 @@ interface GroupCollectorInterface
*/
public function withoutBill(): GroupCollectorInterface;
/**
* Limit results to a transactions without a budget.
*
* @return GroupCollectorInterface
*/
public function withoutBudget(): GroupCollectorInterface;
/**
* Limit results to a transactions without a category.
*
@ -516,35 +542,15 @@ interface GroupCollectorInterface
public function withoutCategory(): GroupCollectorInterface;
/**
* Limit results to a transactions with a category.
* @param string $value
*
* @return GroupCollectorInterface
*/
public function withCategory(): GroupCollectorInterface;
public function withoutNotes(): GroupCollectorInterface;
/**
* Limit results to a transactions with a budget.
*
* @return GroupCollectorInterface
*/
public function withBudget(): GroupCollectorInterface;
/**
* Look for specific external ID's.
*
* @param string $externalId
*
* @return GroupCollectorInterface
*/
public function setExternalId(string $externalId): GroupCollectorInterface;
/**
* Look for specific external ID's.
*
* @param string $externalId
*
* @return GroupCollectorInterface
*/
public function setInternalReference(string $externalId): GroupCollectorInterface;
public function withoutTags(): GroupCollectorInterface;
}

View File

@ -31,7 +31,6 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
/**
* Class PopupReport.

View File

@ -29,7 +29,6 @@ use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
/**
* Class ReportHelper.

View File

@ -53,14 +53,6 @@ class Sha3SignatureGenerator implements SignatureGeneratorInterface
{
private int $version = 1;
/**
* @inheritDoc
*/
public function getVersion(): int
{
return $this->version;
}
/**
* @inheritDoc
*/
@ -89,4 +81,12 @@ class Sha3SignatureGenerator implements SignatureGeneratorInterface
// Schemes start with v, followed by an integer. Currently, the only valid live signature scheme is v1.
return sprintf('t=%s,v%d=%s', $timestamp, $this->getVersion(), $signature);
}
/**
* @inheritDoc
*/
public function getVersion(): int
{
return $this->version;
}
}

View File

@ -50,17 +50,17 @@ use FireflyIII\Models\WebhookMessage;
*/
interface SignatureGeneratorInterface
{
/**
* Return the version of this signature generator.
*
* @return int
*/
public function getVersion(): int;
/**
* @param WebhookMessage $message
*
* @return string
*/
public function generate(WebhookMessage $message): string;
/**
* Return the version of this signature generator.
*
* @return int
*/
public function getVersion(): int;
}

View File

@ -31,6 +31,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use Log;
/**
@ -66,7 +67,7 @@ class LinkController extends Controller
/**
* Make a new link form.
*
* @return Factory|\Illuminate\View\View
* @return Factory|View
*/
public function create()
{
@ -89,7 +90,7 @@ class LinkController extends Controller
* @param Request $request
* @param LinkType $linkType
*
* @return Factory|RedirectResponse|Redirector|\Illuminate\View\View
* @return Factory|RedirectResponse|Redirector|View
*/
public function delete(Request $request, LinkType $linkType)
{
@ -146,7 +147,7 @@ class LinkController extends Controller
* @param Request $request
* @param LinkType $linkType
*
* @return Factory|RedirectResponse|Redirector|\Illuminate\View\View
* @return Factory|RedirectResponse|Redirector|View
*/
public function edit(Request $request, LinkType $linkType)
{
@ -172,7 +173,7 @@ class LinkController extends Controller
/**
* Show index of all links.
*
* @return Factory|\Illuminate\View\View
* @return Factory|View
*/
public function index()
{
@ -195,7 +196,7 @@ class LinkController extends Controller
*
* @param LinkType $linkType
*
* @return Factory|\Illuminate\View\View
* @return Factory|View
*/
public function show(LinkType $linkType)
{

View File

@ -63,6 +63,7 @@ class UserController extends Controller
/**
* @param User $user
*
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|RedirectResponse|Redirector|\Illuminate\View\View
*/
public function delete(User $user)

Some files were not shown because too many files have changed in this diff Show More