diff --git a/app/Api/V1/Controllers/Autocomplete/CurrencyController.php b/app/Api/V1/Controllers/Autocomplete/CurrencyController.php index fe6cc5648f..8aa7d6cf52 100644 --- a/app/Api/V1/Controllers/Autocomplete/CurrencyController.php +++ b/app/Api/V1/Controllers/Autocomplete/CurrencyController.php @@ -62,7 +62,7 @@ class CurrencyController extends Controller * * @return JsonResponse */ - public function currenciesWithCode(AutocompleteRequest $request): JsonResponse + public function currencies(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); $collection = $this->repository->searchCurrency($data['query'], $data['limit']); @@ -71,8 +71,8 @@ class CurrencyController extends Controller /** @var TransactionCurrency $currency */ foreach ($collection as $currency) { $result[] = [ - 'id' => (string) $currency->id, - 'name' => sprintf('%s (%s)', $currency->name, $currency->code), + 'id' => (string)$currency->id, + 'name' => $currency->name, 'code' => $currency->code, 'symbol' => $currency->symbol, 'decimal_places' => $currency->decimal_places, @@ -87,7 +87,7 @@ class CurrencyController extends Controller * * @return JsonResponse */ - public function currencies(AutocompleteRequest $request): JsonResponse + public function currenciesWithCode(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); $collection = $this->repository->searchCurrency($data['query'], $data['limit']); @@ -96,8 +96,8 @@ class CurrencyController extends Controller /** @var TransactionCurrency $currency */ foreach ($collection as $currency) { $result[] = [ - 'id' => (string) $currency->id, - 'name' => $currency->name, + 'id' => (string)$currency->id, + 'name' => sprintf('%s (%s)', $currency->name, $currency->code), 'code' => $currency->code, 'symbol' => $currency->symbol, 'decimal_places' => $currency->decimal_places, diff --git a/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php b/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php index c1499c9f25..4887963ea1 100644 --- a/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php +++ b/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php @@ -37,11 +37,9 @@ use Illuminate\Http\JsonResponse; */ class PiggyBankController extends Controller { + private AccountRepositoryInterface $accountRepository; private PiggyBankRepositoryInterface $piggyRepository; - private AccountRepositoryInterface $accountRepository; - - /** * PiggyBankController constructor. */ diff --git a/app/Api/V1/Controllers/Autocomplete/RuleController.php b/app/Api/V1/Controllers/Autocomplete/RuleController.php index cbd9022ed2..05510fceea 100644 --- a/app/Api/V1/Controllers/Autocomplete/RuleController.php +++ b/app/Api/V1/Controllers/Autocomplete/RuleController.php @@ -62,7 +62,7 @@ class RuleController extends Controller public function rules(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $rules = $this->repository->searchRule($data['query'], $data['limit']); + $rules = $this->repository->searchRule($data['query'], $data['limit']); $response = []; /** @var Rule $rule */ diff --git a/app/Api/V1/Controllers/Autocomplete/TransactionController.php b/app/Api/V1/Controllers/Autocomplete/TransactionController.php index 680e72bba4..579eb422b1 100644 --- a/app/Api/V1/Controllers/Autocomplete/TransactionController.php +++ b/app/Api/V1/Controllers/Autocomplete/TransactionController.php @@ -38,10 +38,8 @@ use Illuminate\Support\Collection; */ class TransactionController extends Controller { - private JournalRepositoryInterface $repository; - private TransactionGroupRepositoryInterface $groupRepository; - + private JournalRepositoryInterface $repository; /** * TransactionController constructor. @@ -102,7 +100,7 @@ class TransactionController extends Controller $result = new Collection; if (is_numeric($data['query'])) { // search for group, not journal. - $firstResult = $this->groupRepository->find((int) $data['query']); + $firstResult = $this->groupRepository->find((int)$data['query']); if (null !== $firstResult) { // group may contain multiple journals, each a result: foreach ($firstResult->transactionJournals as $journal) { diff --git a/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php b/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php index 38faca2036..2984aab1e9 100644 --- a/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php +++ b/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php @@ -69,7 +69,7 @@ class TransactionTypeController extends Controller foreach ($types as $type) { // different key for consistency. $array[] = [ - 'id' =>(string) $type->id, + 'id' => (string)$type->id, 'name' => $type->type, 'type' => $type->type, ]; diff --git a/app/Api/V1/Controllers/Data/Export/ExportController.php b/app/Api/V1/Controllers/Data/Export/ExportController.php index 7f4aa32dbf..5851a4e34b 100644 --- a/app/Api/V1/Controllers/Data/Export/ExportController.php +++ b/app/Api/V1/Controllers/Data/Export/ExportController.php @@ -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'); + } + } \ No newline at end of file diff --git a/app/Api/V1/Controllers/Insight/Expense/AccountController.php b/app/Api/V1/Controllers/Insight/Expense/AccountController.php index b41f203da6..66fd5c8ce8 100644 --- a/app/Api/V1/Controllers/Insight/Expense/AccountController.php +++ b/app/Api/V1/Controllers/Insight/Expense/AccountController.php @@ -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); - } - } diff --git a/app/Api/V1/Controllers/Insight/Expense/BillController.php b/app/Api/V1/Controllers/Insight/Expense/BillController.php index 8cc53cc329..2a6f398810 100644 --- a/app/Api/V1/Controllers/Insight/Expense/BillController.php +++ b/app/Api/V1/Controllers/Insight/Expense/BillController.php @@ -87,7 +87,7 @@ class BillController extends Controller $foreignKey = sprintf('%d-%d', $billId, $foreignCurrencyId); if (0 !== $currencyId) { - $response[$key] = $response[$key] ?? [ + $response[$key] = $response[$key] ?? [ 'id' => (string)$billId, 'name' => $journal['bill_name'], 'difference' => '0', @@ -139,7 +139,7 @@ class BillController extends Controller $foreignCurrencyId = (int)$journal['foreign_currency_id']; if (0 !== $currencyId) { - $response[$currencyId] = $response[$currencyId] ?? [ + $response[$currencyId] = $response[$currencyId] ?? [ 'difference' => '0', 'difference_float' => 0, 'currency_id' => (string)$currencyId, diff --git a/app/Api/V1/Controllers/Insight/Expense/BudgetController.php b/app/Api/V1/Controllers/Insight/Expense/BudgetController.php index 69deaa6e84..0d8431a60b 100644 --- a/app/Api/V1/Controllers/Insight/Expense/BudgetController.php +++ b/app/Api/V1/Controllers/Insight/Expense/BudgetController.php @@ -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. diff --git a/app/Api/V1/Controllers/Insight/Expense/CategoryController.php b/app/Api/V1/Controllers/Insight/Expense/CategoryController.php index 7d2b5de843..bea6b88901 100644 --- a/app/Api/V1/Controllers/Insight/Expense/CategoryController.php +++ b/app/Api/V1/Controllers/Insight/Expense/CategoryController.php @@ -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. diff --git a/app/Api/V1/Controllers/Insight/Expense/TagController.php b/app/Api/V1/Controllers/Insight/Expense/TagController.php index 98a84457e4..0894fd16c3 100644 --- a/app/Api/V1/Controllers/Insight/Expense/TagController.php +++ b/app/Api/V1/Controllers/Insight/Expense/TagController.php @@ -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)); - } - } \ No newline at end of file diff --git a/app/Api/V1/Controllers/Insight/Income/AccountController.php b/app/Api/V1/Controllers/Insight/Income/AccountController.php index 8fc49cee7c..9de160f284 100644 --- a/app/Api/V1/Controllers/Insight/Income/AccountController.php +++ b/app/Api/V1/Controllers/Insight/Income/AccountController.php @@ -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); + } + } diff --git a/app/Api/V1/Controllers/Insight/Income/CategoryController.php b/app/Api/V1/Controllers/Insight/Income/CategoryController.php index c368bd5b9a..431233d0b7 100644 --- a/app/Api/V1/Controllers/Insight/Income/CategoryController.php +++ b/app/Api/V1/Controllers/Insight/Income/CategoryController.php @@ -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. diff --git a/app/Api/V1/Controllers/Insight/Income/PeriodController.php b/app/Api/V1/Controllers/Insight/Income/PeriodController.php index bf43a4fba5..f32bcc4fc8 100644 --- a/app/Api/V1/Controllers/Insight/Income/PeriodController.php +++ b/app/Api/V1/Controllers/Insight/Income/PeriodController.php @@ -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']; } } diff --git a/app/Api/V1/Controllers/Insight/Income/TagController.php b/app/Api/V1/Controllers/Insight/Income/TagController.php index eca5d01b4f..af88ccfe3c 100644 --- a/app/Api/V1/Controllers/Insight/Income/TagController.php +++ b/app/Api/V1/Controllers/Insight/Income/TagController.php @@ -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)); - } - } \ No newline at end of file diff --git a/app/Api/V1/Controllers/Insight/Transfer/CategoryController.php b/app/Api/V1/Controllers/Insight/Transfer/CategoryController.php index 1f13918a0f..3fea7cf04a 100644 --- a/app/Api/V1/Controllers/Insight/Transfer/CategoryController.php +++ b/app/Api/V1/Controllers/Insight/Transfer/CategoryController.php @@ -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. diff --git a/app/Api/V1/Controllers/Insight/Transfer/PeriodController.php b/app/Api/V1/Controllers/Insight/Transfer/PeriodController.php index b03788c0d3..8be400b2d4 100644 --- a/app/Api/V1/Controllers/Insight/Transfer/PeriodController.php +++ b/app/Api/V1/Controllers/Insight/Transfer/PeriodController.php @@ -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']; } } diff --git a/app/Api/V1/Controllers/Insight/Transfer/TagController.php b/app/Api/V1/Controllers/Insight/Transfer/TagController.php index 5001cf21bb..51b949d651 100644 --- a/app/Api/V1/Controllers/Insight/Transfer/TagController.php +++ b/app/Api/V1/Controllers/Insight/Transfer/TagController.php @@ -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)); - } } \ No newline at end of file diff --git a/app/Api/V1/Controllers/Models/Account/StoreController.php b/app/Api/V1/Controllers/Models/Account/StoreController.php index a0d8d464ef..89254c6c1f 100644 --- a/app/Api/V1/Controllers/Models/Account/StoreController.php +++ b/app/Api/V1/Controllers/Models/Account/StoreController.php @@ -67,7 +67,7 @@ class StoreController extends Controller */ public function store(StoreRequest $request): JsonResponse { - $data = $request->getAllAccountData(); + $data = $request->getAllAccountData(); $this->repository->resetAccountOrder(); $account = $this->repository->store($data); $manager = $this->getManager(); diff --git a/app/Api/V1/Controllers/Models/Attachment/ShowController.php b/app/Api/V1/Controllers/Models/Attachment/ShowController.php index cc49aa53ba..8047339f7c 100644 --- a/app/Api/V1/Controllers/Models/Attachment/ShowController.php +++ b/app/Api/V1/Controllers/Models/Attachment/ShowController.php @@ -119,7 +119,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of attachments. Count it and split it. $collection = $this->repository->get(); @@ -141,7 +141,6 @@ class ShowController extends Controller } - /** * Display the specified resource. * diff --git a/app/Api/V1/Controllers/Models/Attachment/StoreController.php b/app/Api/V1/Controllers/Models/Attachment/StoreController.php index 63218934cb..a6bc307bd1 100644 --- a/app/Api/V1/Controllers/Models/Attachment/StoreController.php +++ b/app/Api/V1/Controllers/Models/Attachment/StoreController.php @@ -67,7 +67,6 @@ class StoreController extends Controller } - /** * Store a newly created resource in storage. * diff --git a/app/Api/V1/Controllers/Models/Attachment/UpdateController.php b/app/Api/V1/Controllers/Models/Attachment/UpdateController.php index 209a2c6b65..fd2a8271b3 100644 --- a/app/Api/V1/Controllers/Models/Attachment/UpdateController.php +++ b/app/Api/V1/Controllers/Models/Attachment/UpdateController.php @@ -63,12 +63,11 @@ class UpdateController extends Controller } - /** * Update the specified resource in storage. * * @param UpdateRequest $request - * @param Attachment $attachment + * @param Attachment $attachment * * @return JsonResponse */ diff --git a/app/Api/V1/Controllers/Models/AvailableBudget/DestroyController.php b/app/Api/V1/Controllers/Models/AvailableBudget/DestroyController.php index 79f264d4cf..482ec355c1 100644 --- a/app/Api/V1/Controllers/Models/AvailableBudget/DestroyController.php +++ b/app/Api/V1/Controllers/Models/AvailableBudget/DestroyController.php @@ -54,6 +54,7 @@ class DestroyController extends Controller } ); } + /** * Remove the specified resource from storage. * diff --git a/app/Api/V1/Controllers/Models/AvailableBudget/ShowController.php b/app/Api/V1/Controllers/Models/AvailableBudget/ShowController.php index 459e6816ca..a767b144ac 100644 --- a/app/Api/V1/Controllers/Models/AvailableBudget/ShowController.php +++ b/app/Api/V1/Controllers/Models/AvailableBudget/ShowController.php @@ -71,7 +71,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $start = $this->parameters->get('start'); $end = $this->parameters->get('end'); diff --git a/app/Api/V1/Controllers/Models/AvailableBudget/UpdateController.php b/app/Api/V1/Controllers/Models/AvailableBudget/UpdateController.php index e9c8bb53ad..50c1d77e61 100644 --- a/app/Api/V1/Controllers/Models/AvailableBudget/UpdateController.php +++ b/app/Api/V1/Controllers/Models/AvailableBudget/UpdateController.php @@ -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; @@ -73,9 +72,9 @@ class UpdateController extends Controller $data = $request->getAll(); // find and validate currency ID - if(array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) { - $factory = app(TransactionCurrencyFactory::class); - $currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null) ?? app('amount')->getDefaultCurrency(); + if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) { + $factory = app(TransactionCurrencyFactory::class); + $currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null) ?? app('amount')->getDefaultCurrency(); $currency->enabled = true; $currency->save(); unset($data['currency_code']); diff --git a/app/Api/V1/Controllers/Models/Bill/ListController.php b/app/Api/V1/Controllers/Models/Bill/ListController.php index d5d91b45d4..fef22d7896 100644 --- a/app/Api/V1/Controllers/Models/Bill/ListController.php +++ b/app/Api/V1/Controllers/Models/Bill/ListController.php @@ -80,7 +80,7 @@ class ListController extends Controller public function attachments(Bill $bill): JsonResponse { $manager = $this->getManager(); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $collection = $this->repository->getAttachments($bill); $count = $collection->count(); @@ -101,7 +101,6 @@ class ListController extends Controller } - /** * List all of them. * @@ -115,7 +114,7 @@ class ListController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of budgets. Count it and split it. $collection = $this->repository->getRulesForBill($bill); @@ -139,7 +138,6 @@ class ListController extends Controller } - /** * Show all transactions. * @@ -152,7 +150,7 @@ class ListController extends Controller */ public function transactions(Request $request, Bill $bill): JsonResponse { - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); diff --git a/app/Api/V1/Controllers/Models/Bill/ShowController.php b/app/Api/V1/Controllers/Models/Bill/ShowController.php index 385066d96b..b80093d496 100644 --- a/app/Api/V1/Controllers/Models/Bill/ShowController.php +++ b/app/Api/V1/Controllers/Models/Bill/ShowController.php @@ -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; @@ -74,7 +73,7 @@ class ShowController extends Controller $this->repository->correctOrder(); $bills = $this->repository->getBills(); $manager = $this->getManager(); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $count = $bills->count(); $bills = $bills->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page')); diff --git a/app/Api/V1/Controllers/Models/Budget/StoreController.php b/app/Api/V1/Controllers/Models/Budget/StoreController.php index 9fd4299a77..8ce134b648 100644 --- a/app/Api/V1/Controllers/Models/Budget/StoreController.php +++ b/app/Api/V1/Controllers/Models/Budget/StoreController.php @@ -67,7 +67,7 @@ class StoreController extends Controller */ public function store(StoreRequest $request): JsonResponse { - $budget = $this->repository->store($request->getAll()); + $budget = $this->repository->store($request->getAll()); $budget->refresh(); $manager = $this->getManager(); diff --git a/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php b/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php index 4f7120b52d..52b05b11af 100644 --- a/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php +++ b/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php @@ -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); + } + } \ No newline at end of file diff --git a/app/Api/V1/Controllers/Models/BudgetLimit/UpdateController.php b/app/Api/V1/Controllers/Models/BudgetLimit/UpdateController.php index bad2d4418b..1930a955a7 100644 --- a/app/Api/V1/Controllers/Models/BudgetLimit/UpdateController.php +++ b/app/Api/V1/Controllers/Models/BudgetLimit/UpdateController.php @@ -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; diff --git a/app/Api/V1/Controllers/Models/Category/DestroyController.php b/app/Api/V1/Controllers/Models/Category/DestroyController.php index b0ad5d5e0a..0a3dd9854e 100644 --- a/app/Api/V1/Controllers/Models/Category/DestroyController.php +++ b/app/Api/V1/Controllers/Models/Category/DestroyController.php @@ -74,5 +74,4 @@ class DestroyController extends Controller } - } \ No newline at end of file diff --git a/app/Api/V1/Controllers/Models/Category/ShowController.php b/app/Api/V1/Controllers/Models/Category/ShowController.php index e7b5e267b6..f33dc446dd 100644 --- a/app/Api/V1/Controllers/Models/Category/ShowController.php +++ b/app/Api/V1/Controllers/Models/Category/ShowController.php @@ -74,7 +74,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of budgets. Count it and split it. $collection = $this->repository->getCategories(); diff --git a/app/Api/V1/Controllers/Models/Category/UpdateController.php b/app/Api/V1/Controllers/Models/Category/UpdateController.php index 565def622b..05cd41adf1 100644 --- a/app/Api/V1/Controllers/Models/Category/UpdateController.php +++ b/app/Api/V1/Controllers/Models/Category/UpdateController.php @@ -64,7 +64,7 @@ class UpdateController extends Controller * Update the category. * * @param UpdateRequest $request - * @param Category $category + * @param Category $category * * @return JsonResponse */ diff --git a/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php b/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php index 258e641ce7..9a2375ffde 100644 --- a/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php +++ b/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php @@ -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); - } } \ No newline at end of file diff --git a/app/Api/V1/Controllers/Models/PiggyBank/ListController.php b/app/Api/V1/Controllers/Models/PiggyBank/ListController.php index d4b65206f0..33ae7728f3 100644 --- a/app/Api/V1/Controllers/Models/PiggyBank/ListController.php +++ b/app/Api/V1/Controllers/Models/PiggyBank/ListController.php @@ -67,7 +67,7 @@ class ListController extends Controller public function attachments(PiggyBank $piggyBank): JsonResponse { $manager = $this->getManager(); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $collection = $this->repository->getAttachments($piggyBank); $count = $collection->count(); @@ -98,7 +98,7 @@ class ListController extends Controller public function piggyBankEvents(PiggyBank $piggyBank): JsonResponse { // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $manager = $this->getManager(); $collection = $this->repository->getEvents($piggyBank); diff --git a/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php b/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php index f9d5ddd584..fa9dce1248 100644 --- a/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php +++ b/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php @@ -68,7 +68,7 @@ class ShowController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of budgets. Count it and split it. $collection = $this->repository->getPiggyBanks(); diff --git a/app/Api/V1/Controllers/Models/PiggyBank/UpdateController.php b/app/Api/V1/Controllers/Models/PiggyBank/UpdateController.php index 718fdaa206..6a756c6b30 100644 --- a/app/Api/V1/Controllers/Models/PiggyBank/UpdateController.php +++ b/app/Api/V1/Controllers/Models/PiggyBank/UpdateController.php @@ -60,7 +60,7 @@ class UpdateController extends Controller * Update piggy bank. * * @param UpdateRequest $request - * @param PiggyBank $piggyBank + * @param PiggyBank $piggyBank * * @return JsonResponse */ diff --git a/app/Api/V1/Controllers/Models/Recurrence/UpdateController.php b/app/Api/V1/Controllers/Models/Recurrence/UpdateController.php index 5c988790f4..8065bdf2c1 100644 --- a/app/Api/V1/Controllers/Models/Recurrence/UpdateController.php +++ b/app/Api/V1/Controllers/Models/Recurrence/UpdateController.php @@ -61,20 +61,19 @@ class UpdateController extends Controller } - /** * Update single recurrence. * * @param UpdateRequest $request - * @param Recurrence $recurrence + * @param Recurrence $recurrence * * @return JsonResponse */ public function update(UpdateRequest $request, Recurrence $recurrence): JsonResponse { - $data = $request->getAll(); + $data = $request->getAll(); $recurrence = $this->repository->update($recurrence, $data); - $manager = $this->getManager(); + $manager = $this->getManager(); /** @var RecurrenceTransformer $transformer */ $transformer = app(RecurrenceTransformer::class); diff --git a/app/Api/V1/Controllers/Models/Rule/DestroyController.php b/app/Api/V1/Controllers/Models/Rule/DestroyController.php index 237f44621a..5238a31249 100644 --- a/app/Api/V1/Controllers/Models/Rule/DestroyController.php +++ b/app/Api/V1/Controllers/Models/Rule/DestroyController.php @@ -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; diff --git a/app/Api/V1/Controllers/Models/Rule/ListController.php b/app/Api/V1/Controllers/Models/Rule/ListController.php index 86a9a99a44..3f52273e79 100644 --- a/app/Api/V1/Controllers/Models/Rule/ListController.php +++ b/app/Api/V1/Controllers/Models/Rule/ListController.php @@ -33,7 +33,7 @@ use FireflyIII\User; class ListController extends Controller { private AccountRepositoryInterface $accountRepository; - private RuleRepositoryInterface $ruleRepository; + private RuleRepositoryInterface $ruleRepository; /** diff --git a/app/Api/V1/Controllers/Models/Rule/ShowController.php b/app/Api/V1/Controllers/Models/Rule/ShowController.php index 6a46329d62..8ab227136c 100644 --- a/app/Api/V1/Controllers/Models/Rule/ShowController.php +++ b/app/Api/V1/Controllers/Models/Rule/ShowController.php @@ -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; @@ -74,7 +73,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of budgets. Count it and split it. $collection = $this->ruleRepository->getAll(); @@ -97,7 +96,6 @@ class ShowController extends Controller } - /** * List single resource. * diff --git a/app/Api/V1/Controllers/Models/Rule/UpdateController.php b/app/Api/V1/Controllers/Models/Rule/UpdateController.php index 84d91db599..6488aee87c 100644 --- a/app/Api/V1/Controllers/Models/Rule/UpdateController.php +++ b/app/Api/V1/Controllers/Models/Rule/UpdateController.php @@ -65,7 +65,7 @@ class UpdateController extends Controller * Update a rule. * * @param UpdateRequest $request - * @param Rule $rule + * @param Rule $rule * * @return JsonResponse */ diff --git a/app/Api/V1/Controllers/Models/RuleGroup/TriggerController.php b/app/Api/V1/Controllers/Models/RuleGroup/TriggerController.php index 7813528869..7a7e4fec6b 100644 --- a/app/Api/V1/Controllers/Models/RuleGroup/TriggerController.php +++ b/app/Api/V1/Controllers/Models/RuleGroup/TriggerController.php @@ -69,7 +69,7 @@ class TriggerController extends Controller /** * @param TestRequest $request - * @param RuleGroup $group + * @param RuleGroup $group * * @return JsonResponse * @throws FireflyException @@ -126,7 +126,7 @@ class TriggerController extends Controller * Execute the given rule group on a set of existing transactions. * * @param TriggerRequest $request - * @param RuleGroup $group + * @param RuleGroup $group * * @return JsonResponse * @throws Exception diff --git a/app/Api/V1/Controllers/Models/RuleGroup/UpdateController.php b/app/Api/V1/Controllers/Models/RuleGroup/UpdateController.php index d99a8ed8b4..98ee2ef161 100644 --- a/app/Api/V1/Controllers/Models/RuleGroup/UpdateController.php +++ b/app/Api/V1/Controllers/Models/RuleGroup/UpdateController.php @@ -66,7 +66,7 @@ class UpdateController extends Controller * Update a rule group. * * @param UpdateRequest $request - * @param RuleGroup $ruleGroup + * @param RuleGroup $ruleGroup * * @return JsonResponse */ diff --git a/app/Api/V1/Controllers/Models/Tag/DestroyController.php b/app/Api/V1/Controllers/Models/Tag/DestroyController.php index 93d273be1b..d8b9a7d4f8 100644 --- a/app/Api/V1/Controllers/Models/Tag/DestroyController.php +++ b/app/Api/V1/Controllers/Models/Tag/DestroyController.php @@ -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. * diff --git a/app/Api/V1/Controllers/Models/Tag/ListController.php b/app/Api/V1/Controllers/Models/Tag/ListController.php index 57f3ada42d..82d41d8f64 100644 --- a/app/Api/V1/Controllers/Models/Tag/ListController.php +++ b/app/Api/V1/Controllers/Models/Tag/ListController.php @@ -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 * @@ -77,7 +77,7 @@ class ListController extends Controller public function attachments(Tag $tag): JsonResponse { $manager = $this->getManager(); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $collection = $this->repository->getAttachments($tag); $count = $collection->count(); @@ -98,7 +98,6 @@ class ListController extends Controller } - /** * Show all transactions. * @@ -110,7 +109,7 @@ class ListController extends Controller */ public function transactions(Request $request, Tag $tag): JsonResponse { - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); diff --git a/app/Api/V1/Controllers/Models/Tag/ShowController.php b/app/Api/V1/Controllers/Models/Tag/ShowController.php index edf104fb85..c834493adf 100644 --- a/app/Api/V1/Controllers/Models/Tag/ShowController.php +++ b/app/Api/V1/Controllers/Models/Tag/ShowController.php @@ -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; @@ -73,7 +72,7 @@ class ShowController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of budgets. Count it and split it. $collection = $this->repository->get(); @@ -95,7 +94,6 @@ class ShowController extends Controller } - /** * List single resource. * diff --git a/app/Api/V1/Controllers/Models/Tag/StoreController.php b/app/Api/V1/Controllers/Models/Tag/StoreController.php index 11b264a5a2..e958ed2ea3 100644 --- a/app/Api/V1/Controllers/Models/Tag/StoreController.php +++ b/app/Api/V1/Controllers/Models/Tag/StoreController.php @@ -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. * diff --git a/app/Api/V1/Controllers/Models/Tag/UpdateController.php b/app/Api/V1/Controllers/Models/Tag/UpdateController.php index 87811a2ad1..b229ca3785 100644 --- a/app/Api/V1/Controllers/Models/Tag/UpdateController.php +++ b/app/Api/V1/Controllers/Models/Tag/UpdateController.php @@ -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,12 +61,11 @@ class UpdateController extends Controller } - /** * Update a rule. * * @param UpdateRequest $request - * @param Tag $tag + * @param Tag $tag * * @return JsonResponse */ diff --git a/app/Api/V1/Controllers/Models/Transaction/DestroyController.php b/app/Api/V1/Controllers/Models/Transaction/DestroyController.php index f4eacf40f7..f997a28536 100644 --- a/app/Api/V1/Controllers/Models/Transaction/DestroyController.php +++ b/app/Api/V1/Controllers/Models/Transaction/DestroyController.php @@ -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; diff --git a/app/Api/V1/Controllers/Models/Transaction/ListController.php b/app/Api/V1/Controllers/Models/Transaction/ListController.php index ce9393db4a..9acf1f58d2 100644 --- a/app/Api/V1/Controllers/Models/Transaction/ListController.php +++ b/app/Api/V1/Controllers/Models/Transaction/ListController.php @@ -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; @@ -75,8 +73,8 @@ class ListController extends Controller */ public function attachments(TransactionGroup $transactionGroup): JsonResponse { - $manager = $this->getManager(); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $manager = $this->getManager(); + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $collection = new Collection; foreach ($transactionGroup->transactionJournals as $transactionJournal) { $collection = $this->journalAPIRepository->getAttachments($transactionJournal)->merge($collection); @@ -108,13 +106,13 @@ class ListController extends Controller */ public function piggyBankEvents(TransactionGroup $transactionGroup): JsonResponse { - $manager = $this->getManager(); - $collection = new Collection; - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $manager = $this->getManager(); + $collection = new Collection; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; foreach ($transactionGroup->transactionJournals as $transactionJournal) { $collection = $this->journalAPIRepository->getPiggyBankEvents($transactionJournal)->merge($collection); } - $count = $collection->count(); + $count = $collection->count(); $events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); @@ -130,12 +128,11 @@ class ListController extends Controller $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); - -// /** @var PiggyBankEventTransformer $transformer */ -// $transformer = app(PiggyBankEventTransformer::class); -// $transformer->setParameters($this->parameters); -// -// $resource = new FractalCollection($events, $transformer, 'piggy_bank_events'); + // /** @var PiggyBankEventTransformer $transformer */ + // $transformer = app(PiggyBankEventTransformer::class); + // $transformer->setParameters($this->parameters); + // + // $resource = new FractalCollection($events, $transformer, 'piggy_bank_events'); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); } @@ -150,9 +147,9 @@ class ListController extends Controller public function transactionLinks(TransactionJournal $transactionJournal): JsonResponse { $manager = $this->getManager(); - $collection = $this->journalAPIRepository->getJournalLinks($transactionJournal); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; - $count = $collection->count(); + $collection = $this->journalAPIRepository->getJournalLinks($transactionJournal); + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $count = $collection->count(); $journalLinks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); // make paginator: diff --git a/app/Api/V1/Controllers/Models/Transaction/ShowController.php b/app/Api/V1/Controllers/Models/Transaction/ShowController.php index b1fa5a81ac..0b0bd67c57 100644 --- a/app/Api/V1/Controllers/Models/Transaction/ShowController.php +++ b/app/Api/V1/Controllers/Models/Transaction/ShowController.php @@ -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); - } - } \ No newline at end of file diff --git a/app/Api/V1/Controllers/Models/Transaction/UpdateController.php b/app/Api/V1/Controllers/Models/Transaction/UpdateController.php index 515ef16a72..e1365cb6bc 100644 --- a/app/Api/V1/Controllers/Models/Transaction/UpdateController.php +++ b/app/Api/V1/Controllers/Models/Transaction/UpdateController.php @@ -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 @@ -67,8 +67,8 @@ class UpdateController extends Controller /** * Update a transaction. * - * @param UpdateRequest $request - * @param TransactionGroup $transactionGroup + * @param UpdateRequest $request + * @param TransactionGroup $transactionGroup * * @return JsonResponse */ diff --git a/app/Api/V1/Controllers/Models/TransactionCurrency/ListController.php b/app/Api/V1/Controllers/Models/TransactionCurrency/ListController.php index 4e99811b26..3d6f185db0 100644 --- a/app/Api/V1/Controllers/Models/TransactionCurrency/ListController.php +++ b/app/Api/V1/Controllers/Models/TransactionCurrency/ListController.php @@ -89,7 +89,7 @@ class ListController extends Controller // types to get, page size: $types = $this->mapAccountTypes($this->parameters->get('type')); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of accounts. Count it and split it. /** @var AccountRepositoryInterface $accountRepository */ @@ -99,7 +99,7 @@ class ListController extends Controller // filter list on currency preference: $collection = $unfiltered->filter( static function (Account $account) use ($currency, $accountRepository) { - $currencyId = (int) $accountRepository->getMetaValue($account, 'currency_id'); + $currencyId = (int)$accountRepository->getMetaValue($account, 'currency_id'); return $currencyId === $currency->id; } @@ -135,7 +135,7 @@ class ListController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of available budgets. Count it and split it. /** @var AvailableBudgetRepositoryInterface $abRepository */ @@ -174,7 +174,7 @@ class ListController extends Controller /** @var BillRepositoryInterface $billRepos */ $billRepos = app(BillRepositoryInterface::class); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $unfiltered = $billRepos->getBills(); // filter and paginate list: @@ -214,7 +214,7 @@ class ListController extends Controller $blRepository = app(BudgetLimitRepositoryInterface::class); $manager = $this->getManager(); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $collection = $blRepository->getAllBudgetLimitsByCurrency($currency, $this->parameters->get('start'), $this->parameters->get('end')); $count = $collection->count(); $budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); @@ -243,7 +243,7 @@ class ListController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of budgets. Count it and split it. /** @var RecurringRepositoryInterface $recurringRepos */ @@ -294,7 +294,7 @@ class ListController extends Controller public function rules(TransactionCurrency $currency): JsonResponse { $manager = $this->getManager(); - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; // get list of budgets. Count it and split it. /** @var RuleRepositoryInterface $ruleRepos */ @@ -344,7 +344,7 @@ class ListController extends Controller */ public function transactions(Request $request, TransactionCurrency $currency): JsonResponse { - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); diff --git a/app/Api/V1/Controllers/Models/TransactionCurrency/StoreController.php b/app/Api/V1/Controllers/Models/TransactionCurrency/StoreController.php index 6af9f38832..840aaa0e18 100644 --- a/app/Api/V1/Controllers/Models/TransactionCurrency/StoreController.php +++ b/app/Api/V1/Controllers/Models/TransactionCurrency/StoreController.php @@ -50,8 +50,6 @@ class StoreController extends Controller } - - /** * Store new currency. * diff --git a/app/Api/V1/Controllers/Models/TransactionCurrency/UpdateController.php b/app/Api/V1/Controllers/Models/TransactionCurrency/UpdateController.php index c844b88c58..2495bd783a 100644 --- a/app/Api/V1/Controllers/Models/TransactionCurrency/UpdateController.php +++ b/app/Api/V1/Controllers/Models/TransactionCurrency/UpdateController.php @@ -137,7 +137,7 @@ class UpdateController extends Controller /** * Update a currency. * - * @param UpdateRequest $request + * @param UpdateRequest $request * @param TransactionCurrency $currency * * @return JsonResponse diff --git a/app/Api/V1/Controllers/Models/TransactionLink/StoreController.php b/app/Api/V1/Controllers/Models/TransactionLink/StoreController.php index 856dd39e34..f2f1ca1903 100644 --- a/app/Api/V1/Controllers/Models/TransactionLink/StoreController.php +++ b/app/Api/V1/Controllers/Models/TransactionLink/StoreController.php @@ -18,7 +18,8 @@ use League\Fractal\Resource\Item; class StoreController extends Controller { use TransactionFilter; - private JournalRepositoryInterface $journalRepository; + + private JournalRepositoryInterface $journalRepository; private LinkTypeRepositoryInterface $repository; diff --git a/app/Api/V1/Controllers/Models/TransactionLinkType/ListController.php b/app/Api/V1/Controllers/Models/TransactionLinkType/ListController.php index 0a4c077bb3..b2dc4aa630 100644 --- a/app/Api/V1/Controllers/Models/TransactionLinkType/ListController.php +++ b/app/Api/V1/Controllers/Models/TransactionLinkType/ListController.php @@ -49,7 +49,6 @@ class ListController extends Controller } - /** * Delete the resource. * diff --git a/app/Api/V1/Controllers/Models/TransactionLinkType/ShowController.php b/app/Api/V1/Controllers/Models/TransactionLinkType/ShowController.php index 9d5b6fb45f..5f9560cf67 100644 --- a/app/Api/V1/Controllers/Models/TransactionLinkType/ShowController.php +++ b/app/Api/V1/Controllers/Models/TransactionLinkType/ShowController.php @@ -81,7 +81,6 @@ class ShowController extends Controller } - /** * List single resource. * diff --git a/app/Api/V1/Controllers/Models/TransactionLinkType/StoreController.php b/app/Api/V1/Controllers/Models/TransactionLinkType/StoreController.php index 1154d9c451..7a66d5cd88 100644 --- a/app/Api/V1/Controllers/Models/TransactionLinkType/StoreController.php +++ b/app/Api/V1/Controllers/Models/TransactionLinkType/StoreController.php @@ -47,7 +47,6 @@ class StoreController extends Controller } - /** * Store new object. * diff --git a/app/Api/V1/Controllers/Models/TransactionLinkType/UpdateController.php b/app/Api/V1/Controllers/Models/TransactionLinkType/UpdateController.php index 9c06b2a672..c9c6a63aa7 100644 --- a/app/Api/V1/Controllers/Models/TransactionLinkType/UpdateController.php +++ b/app/Api/V1/Controllers/Models/TransactionLinkType/UpdateController.php @@ -48,12 +48,11 @@ class UpdateController extends Controller } - /** * Update object. * * @param UpdateRequest $request - * @param LinkType $linkType + * @param LinkType $linkType * * @return JsonResponse * @throws FireflyException diff --git a/app/Api/V1/Controllers/Summary/BasicController.php b/app/Api/V1/Controllers/Summary/BasicController.php index d18af60f8c..5d8d830f03 100644 --- a/app/Api/V1/Controllers/Summary/BasicController.php +++ b/app/Api/V1/Controllers/Summary/BasicController.php @@ -49,11 +49,11 @@ use Illuminate\Http\JsonResponse; class BasicController extends Controller { private AvailableBudgetRepositoryInterface $abRepository; - private AccountRepositoryInterface $accountRepository; - private BillRepositoryInterface $billRepository; - private BudgetRepositoryInterface $budgetRepository; - private CurrencyRepositoryInterface $currencyRepos; - private OperationsRepositoryInterface $opsRepository; + private AccountRepositoryInterface $accountRepository; + private BillRepositoryInterface $billRepository; + private BudgetRepositoryInterface $budgetRepository; + private CurrencyRepositoryInterface $currencyRepos; + private OperationsRepositoryInterface $opsRepository; /** * BasicController constructor. @@ -146,7 +146,7 @@ class BasicController extends Controller $set = $collector->getExtractedJournals(); /** @var array $transactionJournal */ foreach ($set as $transactionJournal) { - $currencyId = (int) $transactionJournal['currency_id']; + $currencyId = (int)$transactionJournal['currency_id']; $incomes[$currencyId] = $incomes[$currencyId] ?? '0'; $incomes[$currencyId] = bcadd($incomes[$currencyId], bcmul($transactionJournal['amount'], '-1')); $sums[$currencyId] = $sums[$currencyId] ?? '0'; @@ -168,7 +168,7 @@ class BasicController extends Controller /** @var array $transactionJournal */ foreach ($set as $transactionJournal) { - $currencyId = (int) $transactionJournal['currency_id']; + $currencyId = (int)$transactionJournal['currency_id']; $expenses[$currencyId] = $expenses[$currencyId] ?? '0'; $expenses[$currencyId] = bcadd($expenses[$currencyId], $transactionJournal['amount']); $sums[$currencyId] = $sums[$currencyId] ?? '0'; @@ -186,7 +186,7 @@ class BasicController extends Controller $return[] = [ 'key' => sprintf('balance-in-%s', $currency->code), 'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]), - 'monetary_value' => round((float) $sums[$currencyId] ?? 0, $currency->decimal_places), + 'monetary_value' => round((float)$sums[$currencyId] ?? 0, $currency->decimal_places), 'currency_id' => $currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, @@ -199,7 +199,7 @@ class BasicController extends Controller $return[] = [ 'key' => sprintf('spent-in-%s', $currency->code), 'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]), - 'monetary_value' => round((float) ($expenses[$currencyId] ?? 0), $currency->decimal_places), + 'monetary_value' => round((float)($expenses[$currencyId] ?? 0), $currency->decimal_places), 'currency_id' => $currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, @@ -211,7 +211,7 @@ class BasicController extends Controller $return[] = [ 'key' => sprintf('earned-in-%s', $currency->code), 'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]), - 'monetary_value' => round((float) ($incomes[$currencyId] ?? 0), $currency->decimal_places), + 'monetary_value' => round((float)($incomes[$currencyId] ?? 0), $currency->decimal_places), 'currency_id' => $currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, @@ -242,14 +242,14 @@ class BasicController extends Controller $return = []; foreach ($paidAmount as $currencyId => $amount) { $amount = bcmul($amount, '-1'); - $currency = $this->currencyRepos->findNull((int) $currencyId); + $currency = $this->currencyRepos->findNull((int)$currencyId); if (null === $currency) { continue; } $return[] = [ 'key' => sprintf('bills-paid-in-%s', $currency->code), 'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $currency->symbol]), - 'monetary_value' => round((float) $amount, $currency->decimal_places), + 'monetary_value' => round((float)$amount, $currency->decimal_places), 'currency_id' => $currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, @@ -262,14 +262,14 @@ class BasicController extends Controller foreach ($unpaidAmount as $currencyId => $amount) { $amount = bcmul($amount, '-1'); - $currency = $this->currencyRepos->findNull((int) $currencyId); + $currency = $this->currencyRepos->findNull((int)$currencyId); if (null === $currency) { continue; } $return[] = [ 'key' => sprintf('bills-unpaid-in-%s', $currency->code), 'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $currency->symbol]), - 'monetary_value' => round((float) $amount, $currency->decimal_places), + 'monetary_value' => round((float)$amount, $currency->decimal_places), 'currency_id' => $currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, @@ -307,20 +307,20 @@ class BasicController extends Controller $days = $today->diffInDays($end) + 1; $perDay = '0'; if (0 !== $days && bccomp($leftToSpend, '0') > -1) { - $perDay = bcdiv($leftToSpend, (string) $days); + $perDay = bcdiv($leftToSpend, (string)$days); } $return[] = [ 'key' => sprintf('left-to-spend-in-%s', $row['currency_code']), 'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]), - 'monetary_value' => round((float) $leftToSpend, $row['currency_decimal_places']), + 'monetary_value' => round((float)$leftToSpend, $row['currency_decimal_places']), 'currency_id' => $row['currency_id'], 'currency_code' => $row['currency_code'], 'currency_symbol' => $row['currency_symbol'], 'currency_decimal_places' => $row['currency_decimal_places'], 'value_parsed' => app('amount')->formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $leftToSpend, false), 'local_icon' => 'money', - 'sub_title' => (string) trans( + 'sub_title' => (string)trans( 'firefly.box_spend_per_day', ['amount' => app('amount')->formatFlat( $row['currency_symbol'], @@ -373,7 +373,7 @@ class BasicController extends Controller foreach ($netWorthSet as $data) { /** @var TransactionCurrency $currency */ $currency = $data['currency']; - $amount = round((float) $data['balance'], $currency->decimal_places); + $amount = round((float)$data['balance'], $currency->decimal_places); if (0.0 === $amount) { continue; } diff --git a/app/Api/V1/Controllers/System/ConfigurationController.php b/app/Api/V1/Controllers/System/ConfigurationController.php index f91cad2b8d..d52ccf332f 100644 --- a/app/Api/V1/Controllers/System/ConfigurationController.php +++ b/app/Api/V1/Controllers/System/ConfigurationController.php @@ -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 * @@ -118,7 +153,7 @@ class ConfigurationController extends Controller * Update the configuration. * * @param UpdateRequest $request - * @param string $name + * @param string $name * * @return JsonResponse */ @@ -127,8 +162,8 @@ class ConfigurationController extends Controller if (!$this->repository->hasRole(auth()->user(), 'owner')) { throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore } - $data = $request->getAll(); - $shortName = str_replace('configuration.','', $name); + $data = $request->getAll(); + $shortName = str_replace('configuration.', '', $name); app('fireflyconfig')->set($shortName, $data['value']); @@ -136,49 +171,12 @@ class ConfigurationController extends Controller $newConfig = $this->getDynamicConfiguration(); - $data = [ - 'title' => $name, - 'value' => $newConfig[$shortName], - 'editable' => true, - ]; + $data = [ + 'title' => $name, + 'value' => $newConfig[$shortName], + 'editable' => true, + ]; 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, - ]; - } } \ No newline at end of file diff --git a/app/Api/V1/Controllers/System/UserController.php b/app/Api/V1/Controllers/System/UserController.php index 75fca8d115..0165d2afcb 100644 --- a/app/Api/V1/Controllers/System/UserController.php +++ b/app/Api/V1/Controllers/System/UserController.php @@ -77,7 +77,7 @@ class UserController extends Controller { /** @var User $admin */ $admin = auth()->user(); - if($admin->id === $user->id) { + if ($admin->id === $user->id) { return response()->json([], 500); } @@ -98,7 +98,7 @@ class UserController extends Controller public function index(): JsonResponse { // user preferences - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $manager = $this->getManager(); // build collection diff --git a/app/Api/V1/Controllers/User/PreferencesController.php b/app/Api/V1/Controllers/User/PreferencesController.php index 255e993979..39e26e0994 100644 --- a/app/Api/V1/Controllers/User/PreferencesController.php +++ b/app/Api/V1/Controllers/User/PreferencesController.php @@ -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); - } - } diff --git a/app/Api/V1/Controllers/Webhook/AttemptController.php b/app/Api/V1/Controllers/Webhook/AttemptController.php index 25b1e76fc1..dd130f1a2d 100644 --- a/app/Api/V1/Controllers/Webhook/AttemptController.php +++ b/app/Api/V1/Controllers/Webhook/AttemptController.php @@ -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 @@ -108,10 +107,10 @@ class AttemptController extends Controller */ public function show(Webhook $webhook, WebhookMessage $message, WebhookAttempt $attempt): JsonResponse { - if($message->webhook_id !== $webhook->id) { + if ($message->webhook_id !== $webhook->id) { throw new FireflyException('Webhook and webhook message are no match'); } - if($attempt->webhook_message_id !== $message->id) { + if ($attempt->webhook_message_id !== $message->id) { throw new FireflyException('Webhook message and webhook attempt are no match'); } diff --git a/app/Api/V1/Controllers/Webhook/DestroyController.php b/app/Api/V1/Controllers/Webhook/DestroyController.php index 61fe2acec5..268613e60c 100644 --- a/app/Api/V1/Controllers/Webhook/DestroyController.php +++ b/app/Api/V1/Controllers/Webhook/DestroyController.php @@ -103,12 +103,17 @@ class DestroyController extends Controller * @return JsonResponse * @codeCoverageIgnore */ - public function destroyMessage(Webhook $webhook, WebhookMessage $message): JsonResponse + public function destroyAttempt(Webhook $webhook, WebhookMessage $message, WebhookAttempt $attempt): JsonResponse { if ($message->webhook_id !== $webhook->id) { throw new FireflyException('Webhook and webhook message are no match'); } - $this->repository->destroyMessage($message); + if ($attempt->webhook_message_id !== $message->id) { + throw new FireflyException('Webhook message and webhook attempt are no match'); + + } + + $this->repository->destroyAttempt($attempt); return response()->json([], 204); } @@ -121,21 +126,15 @@ class DestroyController extends Controller * @return JsonResponse * @codeCoverageIgnore */ - public function destroyAttempt(Webhook $webhook, WebhookMessage $message, WebhookAttempt $attempt): JsonResponse + public function destroyMessage(Webhook $webhook, WebhookMessage $message): JsonResponse { if ($message->webhook_id !== $webhook->id) { throw new FireflyException('Webhook and webhook message are no match'); } - if($attempt->webhook_message_id !== $message->id) { - throw new FireflyException('Webhook message and webhook attempt are no match'); - - } - - $this->repository->destroyAttempt($attempt); + $this->repository->destroyMessage($message); return response()->json([], 204); } - } diff --git a/app/Api/V1/Controllers/Webhook/MessageController.php b/app/Api/V1/Controllers/Webhook/MessageController.php index 25bab9f655..33f5124282 100644 --- a/app/Api/V1/Controllers/Webhook/MessageController.php +++ b/app/Api/V1/Controllers/Webhook/MessageController.php @@ -71,7 +71,7 @@ class MessageController extends Controller $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $collection = $this->repository->getMessages($webhook); - $count = $collection->count(); + $count = $collection->count(); $messages = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); // make paginator: @@ -99,7 +99,7 @@ class MessageController extends Controller */ public function show(Webhook $webhook, WebhookMessage $message): JsonResponse { - if($message->webhook_id !== $webhook->id) { + if ($message->webhook_id !== $webhook->id) { throw new FireflyException('Webhook and webhook message are no match'); } diff --git a/app/Api/V1/Requests/Data/Export/ExportRequest.php b/app/Api/V1/Requests/Data/Export/ExportRequest.php index 41ed66d0b8..6eefffa754 100644 --- a/app/Api/V1/Requests/Data/Export/ExportRequest.php +++ b/app/Api/V1/Requests/Data/Export/ExportRequest.php @@ -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', + ]; + } } \ No newline at end of file diff --git a/app/Api/V1/Requests/Insight/GenericRequest.php b/app/Api/V1/Requests/Insight/GenericRequest.php index 0ebac45ef1..504178c906 100644 --- a/app/Api/V1/Requests/Insight/GenericRequest.php +++ b/app/Api/V1/Requests/Insight/GenericRequest.php @@ -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; - } - - /** - * @return Collection - */ - public function getTags(): Collection - { - $this->parseTags(); - - 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); + 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 $return; + /** + * @return Carbon + */ + public function getEnd(): Carbon + { + $date = $this->date('end'); + $date->endOfDay(); + + 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', + ]; + } } \ No newline at end of file diff --git a/app/Api/V1/Requests/Models/Account/UpdateRequest.php b/app/Api/V1/Requests/Models/Account/UpdateRequest.php index 193d0cb236..c1c484f5f8 100644 --- a/app/Api/V1/Requests/Models/Account/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Account/UpdateRequest.php @@ -70,7 +70,7 @@ class UpdateRequest extends FormRequest 'currency_code' => ['currency_code', 'string'], ]; $data = $this->getAllData($fields); - $data = $this->appendLocationData($data, null); + $data = $this->appendLocationData($data, null); if (array_key_exists('account_type', $data) && 'liability' === $data['account_type']) { $data['opening_balance'] = bcmul($this->nullableString('liability_amount'), '-1'); diff --git a/app/Api/V1/Requests/Models/Category/UpdateRequest.php b/app/Api/V1/Requests/Models/Category/UpdateRequest.php index befa561963..ee0b56880c 100644 --- a/app/Api/V1/Requests/Models/Category/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Category/UpdateRequest.php @@ -44,9 +44,10 @@ class UpdateRequest extends FormRequest public function getAll(): array { $fields = [ - 'name' => ['name', 'string'], - 'notes' => ['notes', 'nlString'] + 'name' => ['name', 'string'], + 'notes' => ['notes', 'nlString'], ]; + return $this->getAllData($fields); } diff --git a/app/Api/V1/Requests/Models/ObjectGroup/UpdateRequest.php b/app/Api/V1/Requests/Models/ObjectGroup/UpdateRequest.php index e0e8c282df..6d3c5c9740 100644 --- a/app/Api/V1/Requests/Models/ObjectGroup/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/ObjectGroup/UpdateRequest.php @@ -44,8 +44,9 @@ class UpdateRequest extends FormRequest { $fields = [ 'title' => ['title', 'string'], - 'order' =>['order', 'integer'] + 'order' => ['order', 'integer'], ]; + return $this->getAllData($fields); } diff --git a/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php b/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php index 9077bb38d9..02634ba488 100644 --- a/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php @@ -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. * diff --git a/app/Api/V1/Requests/Models/Rule/TriggerRequest.php b/app/Api/V1/Requests/Models/Rule/TriggerRequest.php index 8fe6b92fcf..479647ce73 100644 --- a/app/Api/V1/Requests/Models/Rule/TriggerRequest.php +++ b/app/Api/V1/Requests/Models/Rule/TriggerRequest.php @@ -38,7 +38,6 @@ class TriggerRequest extends FormRequest use ConvertsDataTypes, ChecksLogin; - /** * @return array */ diff --git a/app/Api/V1/Requests/Models/Rule/UpdateRequest.php b/app/Api/V1/Requests/Models/Rule/UpdateRequest.php index f1d3ef43be..d73f5c7806 100644 --- a/app/Api/V1/Requests/Models/Rule/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Rule/UpdateRequest.php @@ -59,10 +59,10 @@ class UpdateRequest extends FormRequest $return = $this->getAllData($fields); $triggers = $this->getRuleTriggers(); $actions = $this->getRuleActions(); - if(null !== $triggers) { + if (null !== $triggers) { $return['triggers'] = $triggers; } - if(null !== $actions) { + if (null !== $actions) { $return['actions'] = $actions; } @@ -81,9 +81,9 @@ class UpdateRequest extends FormRequest $return = []; if (is_array($triggers)) { foreach ($triggers as $trigger) { - $active = array_key_exists('active', $trigger) ? $trigger['active'] : true; - $stopProcessing= array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false; - $return[] = [ + $active = array_key_exists('active', $trigger) ? $trigger['active'] : true; + $stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false; + $return[] = [ 'type' => $trigger['type'], 'value' => $trigger['value'], 'active' => $active, diff --git a/app/Api/V1/Requests/Models/RuleGroup/TestRequest.php b/app/Api/V1/Requests/Models/RuleGroup/TestRequest.php index ef7d1bedb8..51a9bc9e0b 100644 --- a/app/Api/V1/Requests/Models/RuleGroup/TestRequest.php +++ b/app/Api/V1/Requests/Models/RuleGroup/TestRequest.php @@ -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 */ diff --git a/app/Api/V1/Requests/Models/RuleGroup/TriggerRequest.php b/app/Api/V1/Requests/Models/RuleGroup/TriggerRequest.php index 033f5feae9..c8d1f87ded 100644 --- a/app/Api/V1/Requests/Models/RuleGroup/TriggerRequest.php +++ b/app/Api/V1/Requests/Models/RuleGroup/TriggerRequest.php @@ -38,7 +38,6 @@ class TriggerRequest extends FormRequest use ConvertsDataTypes, ChecksLogin; - /** * @return array */ diff --git a/app/Api/V1/Requests/Models/Transaction/StoreRequest.php b/app/Api/V1/Requests/Models/Transaction/StoreRequest.php index c6ab9280e2..19854987d5 100644 --- a/app/Api/V1/Requests/Models/Transaction/StoreRequest.php +++ b/app/Api/V1/Requests/Models/Transaction/StoreRequest.php @@ -59,6 +59,7 @@ class StoreRequest extends FormRequest 'apply_rules' => $this->boolean('apply_rules', true), 'transactions' => $this->getTransactionData(), ]; + // TODO location return $data; } @@ -79,64 +80,64 @@ class StoreRequest extends FormRequest $return[] = [ 'type' => $this->stringFromValue($object['type']), 'date' => $this->dateFromValue($object['date']), - 'order' => $this->integerFromValue((string) $object['order']), + 'order' => $this->integerFromValue((string)$object['order']), - 'currency_id' => $this->integerFromValue((string) $object['currency_id']), + 'currency_id' => $this->integerFromValue((string)$object['currency_id']), 'currency_code' => $this->stringFromValue($object['currency_code']), // foreign currency info: - 'foreign_currency_id' => $this->integerFromValue((string) $object['foreign_currency_id']), - 'foreign_currency_code' => $this->stringFromValue((string) $object['foreign_currency_code']), + 'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']), + 'foreign_currency_code' => $this->stringFromValue((string)$object['foreign_currency_code']), // amount and foreign amount. Cannot be 0. - 'amount' => $this->stringFromValue((string) $object['amount']), - 'foreign_amount' => $this->stringFromValue((string) $object['foreign_amount']), + 'amount' => $this->stringFromValue((string)$object['amount']), + 'foreign_amount' => $this->stringFromValue((string)$object['foreign_amount']), // description. 'description' => $this->stringFromValue($object['description']), // source of transaction. If everything is null, assume cash account. - 'source_id' => $this->integerFromValue((string) $object['source_id']), - 'source_name' => $this->stringFromValue((string) $object['source_name']), - 'source_iban' => $this->stringFromValue((string) $object['source_iban']), - 'source_number' => $this->stringFromValue((string) $object['source_number']), - 'source_bic' => $this->stringFromValue((string) $object['source_bic']), + 'source_id' => $this->integerFromValue((string)$object['source_id']), + 'source_name' => $this->stringFromValue((string)$object['source_name']), + 'source_iban' => $this->stringFromValue((string)$object['source_iban']), + 'source_number' => $this->stringFromValue((string)$object['source_number']), + 'source_bic' => $this->stringFromValue((string)$object['source_bic']), // destination of transaction. If everything is null, assume cash account. - 'destination_id' => $this->integerFromValue((string) $object['destination_id']), - 'destination_name' => $this->stringFromValue((string) $object['destination_name']), - 'destination_iban' => $this->stringFromValue((string) $object['destination_iban']), - 'destination_number' => $this->stringFromValue((string) $object['destination_number']), - 'destination_bic' => $this->stringFromValue((string) $object['destination_bic']), + 'destination_id' => $this->integerFromValue((string)$object['destination_id']), + 'destination_name' => $this->stringFromValue((string)$object['destination_name']), + 'destination_iban' => $this->stringFromValue((string)$object['destination_iban']), + 'destination_number' => $this->stringFromValue((string)$object['destination_number']), + 'destination_bic' => $this->stringFromValue((string)$object['destination_bic']), // budget info - 'budget_id' => $this->integerFromValue((string) $object['budget_id']), - 'budget_name' => $this->stringFromValue((string) $object['budget_name']), + 'budget_id' => $this->integerFromValue((string)$object['budget_id']), + 'budget_name' => $this->stringFromValue((string)$object['budget_name']), // category info - 'category_id' => $this->integerFromValue((string) $object['category_id']), - 'category_name' => $this->stringFromValue((string) $object['category_name']), + 'category_id' => $this->integerFromValue((string)$object['category_id']), + 'category_name' => $this->stringFromValue((string)$object['category_name']), // journal bill reference. Optional. Will only work for withdrawals - 'bill_id' => $this->integerFromValue((string) $object['bill_id']), - 'bill_name' => $this->stringFromValue((string) $object['bill_name']), + 'bill_id' => $this->integerFromValue((string)$object['bill_id']), + 'bill_name' => $this->stringFromValue((string)$object['bill_name']), // piggy bank reference. Optional. Will only work for transfers - 'piggy_bank_id' => $this->integerFromValue((string) $object['piggy_bank_id']), - 'piggy_bank_name' => $this->stringFromValue((string) $object['piggy_bank_name']), + 'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']), + 'piggy_bank_name' => $this->stringFromValue((string)$object['piggy_bank_name']), // some other interesting properties - 'reconciled' => $this->convertBoolean((string) $object['reconciled']), - 'notes' => $this->nlStringFromValue((string) $object['notes']), + 'reconciled' => $this->convertBoolean((string)$object['reconciled']), + 'notes' => $this->nlStringFromValue((string)$object['notes']), 'tags' => $this->arrayFromValue($object['tags']), // all custom fields: - 'internal_reference' => $this->stringFromValue((string) $object['internal_reference']), - 'external_id' => $this->stringFromValue((string) $object['external_id']), + 'internal_reference' => $this->stringFromValue((string)$object['internal_reference']), + 'external_id' => $this->stringFromValue((string)$object['external_id']), 'original_source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')), 'recurrence_id' => $this->integerFromValue($object['recurrence_id']), - 'bunq_payment_id' => $this->stringFromValue((string) $object['bunq_payment_id']), - 'external_uri' => $this->stringFromValue((string) $object['external_uri']), + 'bunq_payment_id' => $this->stringFromValue((string)$object['bunq_payment_id']), + 'external_uri' => $this->stringFromValue((string)$object['external_uri']), 'sepa_cc' => $this->stringFromValue($object['sepa_cc']), 'sepa_ct_op' => $this->stringFromValue($object['sepa_ct_op']), diff --git a/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php b/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php index ac82f4a817..21ae0d8f92 100644 --- a/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php @@ -156,13 +156,13 @@ class UpdateRequest extends FormRequest */ foreach ($this->get('transactions') as $transaction) { // default response is to update nothing in the transaction: - $current = []; - $current = $this->getIntegerData($current, $transaction); - $current = $this->getStringData($current, $transaction); - $current = $this->getNlStringData($current, $transaction); - $current = $this->getDateData($current, $transaction); - $current = $this->getBooleanData($current, $transaction); - $current = $this->getArrayData($current, $transaction); + $current = []; + $current = $this->getIntegerData($current, $transaction); + $current = $this->getStringData($current, $transaction); + $current = $this->getNlStringData($current, $transaction); + $current = $this->getDateData($current, $transaction); + $current = $this->getBooleanData($current, $transaction); + $current = $this->getArrayData($current, $transaction); $return[] = $current; } diff --git a/app/Api/V1/Requests/Models/TransactionLink/StoreRequest.php b/app/Api/V1/Requests/Models/TransactionLink/StoreRequest.php index 1b8540728f..fb7c1741b1 100644 --- a/app/Api/V1/Requests/Models/TransactionLink/StoreRequest.php +++ b/app/Api/V1/Requests/Models/TransactionLink/StoreRequest.php @@ -102,8 +102,8 @@ class StoreRequest extends FormRequest $journalRepos->setUser($user); $data = $validator->getData(); - $inwardId = (int) ($data['inward_id'] ?? 0); - $outwardId = (int) ($data['outward_id'] ?? 0); + $inwardId = (int)($data['inward_id'] ?? 0); + $outwardId = (int)($data['outward_id'] ?? 0); $inward = $journalRepos->findNull($inwardId); $outward = $journalRepos->findNull($outwardId); diff --git a/app/Api/V1/Requests/Models/TransactionLinkType/StoreRequest.php b/app/Api/V1/Requests/Models/TransactionLinkType/StoreRequest.php index 3794b87a83..00a6376489 100644 --- a/app/Api/V1/Requests/Models/TransactionLinkType/StoreRequest.php +++ b/app/Api/V1/Requests/Models/TransactionLinkType/StoreRequest.php @@ -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 diff --git a/app/Api/V1/Requests/Models/TransactionLinkType/UpdateRequest.php b/app/Api/V1/Requests/Models/TransactionLinkType/UpdateRequest.php index fb50a34a7d..3d738cfef7 100644 --- a/app/Api/V1/Requests/Models/TransactionLinkType/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/TransactionLinkType/UpdateRequest.php @@ -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; @@ -61,7 +60,8 @@ class UpdateRequest extends FormRequest */ public function rules(): array { - $linkType = $this->route()->parameter('linkType'); + $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'], diff --git a/app/Api/V1/Requests/System/UpdateRequest.php b/app/Api/V1/Requests/System/UpdateRequest.php index cf6ddf5c6d..67b40c52a0 100644 --- a/app/Api/V1/Requests/System/UpdateRequest.php +++ b/app/Api/V1/Requests/System/UpdateRequest.php @@ -39,7 +39,6 @@ class UpdateRequest extends FormRequest use ConvertsDataTypes, ChecksLogin; - /** * Get all data from the request. * diff --git a/app/Api/V1/Requests/User/PreferenceStoreRequest.php b/app/Api/V1/Requests/User/PreferenceStoreRequest.php index 38f4eca932..fe589f2801 100644 --- a/app/Api/V1/Requests/User/PreferenceStoreRequest.php +++ b/app/Api/V1/Requests/User/PreferenceStoreRequest.php @@ -45,7 +45,7 @@ class PreferenceStoreRequest extends FormRequest if ('false' === $array['data']) { $array['data'] = false; } - if(is_numeric($array['data'])) { + if (is_numeric($array['data'])) { $array['data'] = (float)$array['data']; } diff --git a/app/Api/V1/Requests/User/PreferenceUpdateRequest.php b/app/Api/V1/Requests/User/PreferenceUpdateRequest.php index 2dcf0f1f86..60d91d4d5e 100644 --- a/app/Api/V1/Requests/User/PreferenceUpdateRequest.php +++ b/app/Api/V1/Requests/User/PreferenceUpdateRequest.php @@ -45,7 +45,7 @@ class PreferenceUpdateRequest extends FormRequest if ('false' === $array['data']) { $array['data'] = false; } - if(is_numeric($array['data'])) { + if (is_numeric($array['data'])) { $array['data'] = (float)$array['data']; } diff --git a/app/Console/Commands/Correction/CorrectOpeningBalanceCurrencies.php b/app/Console/Commands/Correction/CorrectOpeningBalanceCurrencies.php index 4e44b49307..fb5d5e97a9 100644 --- a/app/Console/Commands/Correction/CorrectOpeningBalanceCurrencies.php +++ b/app/Console/Commands/Correction/CorrectOpeningBalanceCurrencies.php @@ -159,7 +159,7 @@ class CorrectOpeningBalanceCurrencies extends Command } /** - * @param TransactionJournal $journal + * @param TransactionJournal $journal * @param TransactionCurrency $currency * * @return int diff --git a/app/Console/Commands/CreateFirstUser.php b/app/Console/Commands/CreateFirstUser.php index be7bcb1155..3ddec90a24 100644 --- a/app/Console/Commands/CreateFirstUser.php +++ b/app/Console/Commands/CreateFirstUser.php @@ -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; } diff --git a/app/Console/Commands/DecryptDatabase.php b/app/Console/Commands/DecryptDatabase.php index a8f1bbed63..41e8004fa8 100644 --- a/app/Console/Commands/DecryptDatabase.php +++ b/app/Console/Commands/DecryptDatabase.php @@ -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 * @@ -100,53 +120,12 @@ class DecryptDatabase extends Command Log::error($e->getMessage()); } if (null !== $configVar) { - return (bool) $configVar->data; + return (bool)$configVar->data; } 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 @@ -171,7 +150,7 @@ class DecryptDatabase extends Command if (null === $original) { return; } - $id = (int) $row->id; + $id = (int)$row->id; $value = ''; try { @@ -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,11 +210,12 @@ class DecryptDatabase extends Command Log::warning($message); Log::warning($value); Log::warning($e->getTraceAsString()); + return; } /** @var Preference $object */ - $object = Preference::find((int) $id); + $object = Preference::find((int)$id); if (null !== $object) { $object->data = $newValue; $object->save(); diff --git a/app/Console/Commands/ScanAttachments.php b/app/Console/Commands/ScanAttachments.php index abe7b209f2..51e2a42abe 100644 --- a/app/Console/Commands/ScanAttachments.php +++ b/app/Console/Commands/ScanAttachments.php @@ -88,6 +88,7 @@ class ScanAttachments extends Command } app('telemetry')->feature('system.command.executed', $this->signature); + return 0; } } diff --git a/app/Console/Commands/Upgrade/MigrateRecurrenceType.php b/app/Console/Commands/Upgrade/MigrateRecurrenceType.php index bb86826544..af5e5a7a7a 100644 --- a/app/Console/Commands/Upgrade/MigrateRecurrenceType.php +++ b/app/Console/Commands/Upgrade/MigrateRecurrenceType.php @@ -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); + } } diff --git a/app/Console/Commands/UpgradeFireflyInstructions.php b/app/Console/Commands/UpgradeFireflyInstructions.php index e2fb1027a4..f905385b12 100644 --- a/app/Console/Commands/UpgradeFireflyInstructions.php +++ b/app/Console/Commands/UpgradeFireflyInstructions.php @@ -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. * @@ -113,8 +160,8 @@ class UpgradeFireflyInstructions extends Command { /** @var string $version */ $version = config('firefly.version'); - $config = config('upgrade.text.install'); - $text = ''; + $config = config('upgrade.text.install'); + $text = ''; foreach (array_keys($config) as $compare) { // if string starts with: if (0 === strpos($version, $compare)) { @@ -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(); - } } diff --git a/app/Console/Commands/VerifiesAccessToken.php b/app/Console/Commands/VerifiesAccessToken.php index 89fa96fc76..7f243ca710 100644 --- a/app/Console/Commands/VerifiesAccessToken.php +++ b/app/Console/Commands/VerifiesAccessToken.php @@ -38,12 +38,12 @@ use Log; trait VerifiesAccessToken { /** - * @throws FireflyException * @return User + * @throws FireflyException */ public function getUser(): User { - $userId = (int) $this->option('user'); + $userId = (int)$this->option('user'); /** @var UserRepositoryInterface $repository */ $repository = app(UserRepositoryInterface::class); $user = $repository->findNull($userId); @@ -70,8 +70,8 @@ trait VerifiesAccessToken */ protected function verifyAccessToken(): bool { - $userId = (int) $this->option('user'); - $token = (string) $this->option('token'); + $userId = (int)$this->option('user'); + $token = (string)$this->option('token'); /** @var UserRepositoryInterface $repository */ $repository = app(UserRepositoryInterface::class); $user = $repository->findNull($userId); diff --git a/app/Events/DestroyedTransactionGroup.php b/app/Events/DestroyedTransactionGroup.php index 68d3f6a941..483dbc1abc 100644 --- a/app/Events/DestroyedTransactionGroup.php +++ b/app/Events/DestroyedTransactionGroup.php @@ -35,6 +35,7 @@ use Illuminate\Queue\SerializesModels; class DestroyedTransactionGroup extends Event { use SerializesModels; + public TransactionGroup $transactionGroup; diff --git a/app/Events/StoredTransactionGroup.php b/app/Events/StoredTransactionGroup.php index 95fe3c92da..56b80fd217 100644 --- a/app/Events/StoredTransactionGroup.php +++ b/app/Events/StoredTransactionGroup.php @@ -36,7 +36,7 @@ class StoredTransactionGroup extends Event { use SerializesModels; - public bool $applyRules; + public bool $applyRules; public TransactionGroup $transactionGroup; diff --git a/app/Events/StoredTransactionLink.php b/app/Events/StoredTransactionLink.php index f97f22799b..401a506b0b 100644 --- a/app/Events/StoredTransactionLink.php +++ b/app/Events/StoredTransactionLink.php @@ -20,6 +20,7 @@ */ declare(strict_types=1); + namespace FireflyIII\Events; diff --git a/app/Events/UpdatedTransactionLink.php b/app/Events/UpdatedTransactionLink.php index 386ea2041c..6e18ee2463 100644 --- a/app/Events/UpdatedTransactionLink.php +++ b/app/Events/UpdatedTransactionLink.php @@ -20,6 +20,7 @@ */ declare(strict_types=1); + namespace FireflyIII\Events; diff --git a/app/Exceptions/GracefulNotFoundHandler.php b/app/Exceptions/GracefulNotFoundHandler.php index 91df0dfd59..9af5faa991 100644 --- a/app/Exceptions/GracefulNotFoundHandler.php +++ b/app/Exceptions/GracefulNotFoundHandler.php @@ -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); } @@ -148,7 +150,7 @@ class GracefulNotFoundHandler extends ExceptionHandler /** @var User $user */ $user = auth()->user(); $route = $request->route(); - $accountId = (int) $route->parameter('account'); + $accountId = (int)$route->parameter('account'); /** @var Account $account */ $account = $user->accounts()->with(['accountType'])->withTrashed()->find($accountId); if (null === $account) { @@ -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 @@ -176,7 +218,7 @@ class GracefulNotFoundHandler extends ExceptionHandler /** @var User $user */ $user = auth()->user(); $route = $request->route(); - $attachmentId = (int) $route->parameter('attachment'); + $attachmentId = (int)$route->parameter('attachment'); /** @var Attachment $attachment */ $attachment = $user->attachments()->withTrashed()->find($attachmentId); if (null === $attachment) { @@ -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)])); - - } - } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index d780e47191..2e94350ecc 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -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) { @@ -150,7 +153,7 @@ class Handler extends ExceptionHandler // create job that will mail. $ipAddress = request()->ip() ?? '0.0.0.0'; - $job = new MailError($userData, (string) config('firefly.site_owner'), $ipAddress, $data); + $job = new MailError($userData, (string)config('firefly.site_owner'), $ipAddress, $data); dispatch($job); } diff --git a/app/Factory/AccountFactory.php b/app/Factory/AccountFactory.php index 833cfe9658..74c349d22d 100644 --- a/app/Factory/AccountFactory.php +++ b/app/Factory/AccountFactory.php @@ -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; + } + } diff --git a/app/Factory/AccountMetaFactory.php b/app/Factory/AccountMetaFactory.php index ff139598c7..ae74aeefb7 100644 --- a/app/Factory/AccountMetaFactory.php +++ b/app/Factory/AccountMetaFactory.php @@ -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); + } + } diff --git a/app/Factory/AttachmentFactory.php b/app/Factory/AttachmentFactory.php index 98d87967de..53a08866a3 100644 --- a/app/Factory/AttachmentFactory.php +++ b/app/Factory/AttachmentFactory.php @@ -40,23 +40,24 @@ 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) { /** @var Transaction $transaction */ - $transaction = $this->user->transactions()->find((int) $data['attachable_id']); + $transaction = $this->user->transactions()->find((int)$data['attachable_id']); if (null === $transaction) { throw new FireflyException('Unexpectedly could not find transaction'); // @codeCoverageIgnore } $data['attachable_id'] = $transaction->transaction_journal_id; - $model = TransactionJournal::class; + $model = TransactionJournal::class; } // create attachment: @@ -74,7 +75,7 @@ class AttachmentFactory 'uploaded' => 0, ] ); - $notes = (string) ($data['notes'] ?? ''); + $notes = (string)($data['notes'] ?? ''); if ('' !== $notes) { $note = new Note; $note->noteable()->associate($attachment); diff --git a/app/Factory/BudgetFactory.php b/app/Factory/BudgetFactory.php index 69a25e6b92..f3ea839f9e 100644 --- a/app/Factory/BudgetFactory.php +++ b/app/Factory/BudgetFactory.php @@ -41,8 +41,8 @@ class BudgetFactory */ public function find(?int $budgetId, ?string $budgetName): ?Budget { - $budgetId = (int) $budgetId; - $budgetName = (string) $budgetName; + $budgetId = (int)$budgetId; + $budgetName = (string)$budgetName; if (0 === $budgetId && '' === $budgetName) { return null; diff --git a/app/Factory/CategoryFactory.php b/app/Factory/CategoryFactory.php index 1be0a4c0c6..9a84dda2a6 100644 --- a/app/Factory/CategoryFactory.php +++ b/app/Factory/CategoryFactory.php @@ -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 */ diff --git a/app/Factory/PiggyBankFactory.php b/app/Factory/PiggyBankFactory.php index e512e9f1e8..4d337dcf1e 100644 --- a/app/Factory/PiggyBankFactory.php +++ b/app/Factory/PiggyBankFactory.php @@ -42,8 +42,8 @@ class PiggyBankFactory */ public function find(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank { - $piggyBankId = (int) $piggyBankId; - $piggyBankName = (string) $piggyBankName; + $piggyBankId = (int)$piggyBankId; + $piggyBankName = (string)$piggyBankName; if ('' === $piggyBankName && 0 === $piggyBankId) { return null; } diff --git a/app/Factory/RecurrenceFactory.php b/app/Factory/RecurrenceFactory.php index 4de18bfd91..7a9298e88a 100644 --- a/app/Factory/RecurrenceFactory.php +++ b/app/Factory/RecurrenceFactory.php @@ -73,13 +73,13 @@ class RecurrenceFactory throw new FireflyException($message); } - $firstDate = null; - $repeatUntil = null; - $repetitions = 0; - $title = null; - $description = ''; - $applyRules = true; - $active = true; + $firstDate = null; + $repeatUntil = null; + $repetitions = 0; + $title = null; + $description = ''; + $applyRules = true; + $active = true; $repeatUntilString = null; if (array_key_exists('first_date', $data['recurrence'])) { /** @var Carbon $firstDate */ diff --git a/app/Factory/TagFactory.php b/app/Factory/TagFactory.php index 8db6c25fb9..406fb4e1ad 100644 --- a/app/Factory/TagFactory.php +++ b/app/Factory/TagFactory.php @@ -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 * @@ -43,9 +80,9 @@ class TagFactory */ public function create(array $data): ?Tag { - $zoomLevel = 0 === (int) $data['zoom_level'] ? null : (int) $data['zoom_level']; - $latitude = 0.0 === (float) $data['latitude'] ? null : (float) $data['latitude']; - $longitude = 0.0 === (float) $data['longitude'] ? null : (float) $data['longitude']; + $zoomLevel = 0 === (int)$data['zoom_level'] ? null : (int)$data['zoom_level']; + $latitude = 0.0 === (float)$data['latitude'] ? null : (float)$data['latitude']; + $longitude = 0.0 === (float)$data['longitude'] ? null : (float)$data['longitude']; $array = [ 'user_id' => $this->user->id, 'tag' => trim($data['tag']), @@ -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 */ diff --git a/app/Factory/TransactionCurrencyFactory.php b/app/Factory/TransactionCurrencyFactory.php index 1c739c8506..4e355b3c09 100644 --- a/app/Factory/TransactionCurrencyFactory.php +++ b/app/Factory/TransactionCurrencyFactory.php @@ -40,8 +40,8 @@ class TransactionCurrencyFactory /** * @param array $data * - * @throws FireflyException * @return TransactionCurrency + * @throws FireflyException */ public function create(array $data): TransactionCurrency { @@ -73,8 +73,8 @@ class TransactionCurrencyFactory */ public function find(?int $currencyId, ?string $currencyCode): ?TransactionCurrency { - $currencyCode = (string) $currencyCode; - $currencyId = (int) $currencyId; + $currencyCode = (string)$currencyCode; + $currencyId = (int)$currencyId; if ('' === $currencyCode && 0 === $currencyId) { Log::debug('Cannot find anything on empty currency code and empty currency ID!'); diff --git a/app/Factory/TransactionFactory.php b/app/Factory/TransactionFactory.php index 49a1b59ffd..66739d3209 100644 --- a/app/Factory/TransactionFactory.php +++ b/app/Factory/TransactionFactory.php @@ -38,12 +38,12 @@ use Log; */ class TransactionFactory { - private Account $account; - private TransactionCurrency $currency; + private Account $account; + private TransactionCurrency $currency; private ?TransactionCurrency $foreignCurrency; - private TransactionJournal $journal; - private bool $reconciled; - private User $user; + private TransactionJournal $journal; + private bool $reconciled; + private User $user; /** @@ -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; - } } diff --git a/app/Factory/TransactionGroupFactory.php b/app/Factory/TransactionGroupFactory.php index 146c7ac139..ceba156fe6 100644 --- a/app/Factory/TransactionGroupFactory.php +++ b/app/Factory/TransactionGroupFactory.php @@ -54,8 +54,8 @@ class TransactionGroupFactory * * @param array $data * - * @throws DuplicateTransactionException * @return TransactionGroup + * @throws DuplicateTransactionException */ public function create(array $data): TransactionGroup { diff --git a/app/Factory/TransactionJournalFactory.php b/app/Factory/TransactionJournalFactory.php index 1dc51b5db6..3350b2720e 100644 --- a/app/Factory/TransactionJournalFactory.php +++ b/app/Factory/TransactionJournalFactory.php @@ -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,35 +521,63 @@ 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); + } + } diff --git a/app/Factory/TransactionJournalMetaFactory.php b/app/Factory/TransactionJournalMetaFactory.php index 872e0ca601..d3adb5777b 100644 --- a/app/Factory/TransactionJournalMetaFactory.php +++ b/app/Factory/TransactionJournalMetaFactory.php @@ -60,7 +60,7 @@ class TransactionJournalMetaFactory Log::debug('Is a carbon object.'); $value = $data['data']->toW3cString(); } - if ('' === (string) $value) { + if ('' === (string)$value) { Log::debug('Is an empty string.'); // don't store blank strings. if (null !== $entry) { diff --git a/app/Factory/TransactionTypeFactory.php b/app/Factory/TransactionTypeFactory.php index 2ec9b54a29..437055f184 100644 --- a/app/Factory/TransactionTypeFactory.php +++ b/app/Factory/TransactionTypeFactory.php @@ -26,7 +26,6 @@ declare(strict_types=1); namespace FireflyIII\Factory; use FireflyIII\Models\TransactionType; -use Log; /** * Class TransactionTypeFactory diff --git a/app/Generator/Chart/Basic/ChartJsGenerator.php b/app/Generator/Chart/Basic/ChartJsGenerator.php index a9158ca78b..a2d9d2aea7 100644 --- a/app/Generator/Chart/Basic/ChartJsGenerator.php +++ b/app/Generator/Chart/Basic/ChartJsGenerator.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace FireflyIII\Generator\Chart\Basic; use FireflyIII\Support\ChartColour; -use Log; /** * Class ChartJsGenerator. @@ -51,7 +50,7 @@ class ChartJsGenerator implements GeneratorInterface $amounts = array_column($data, 'amount'); $next = next($amounts); $sortFlag = SORT_ASC; - if (!is_bool($next) && 1 === bccomp((string) $next, '0')) { + if (!is_bool($next) && 1 === bccomp((string)$next, '0')) { $sortFlag = SORT_DESC; } array_multisort($amounts, $sortFlag, $data); @@ -60,7 +59,7 @@ class ChartJsGenerator implements GeneratorInterface $index = 0; foreach ($data as $key => $valueArray) { // make larger than 0 - $chartData['datasets'][0]['data'][] = (float) app('steam')->positive((string) $valueArray['amount']); + $chartData['datasets'][0]['data'][] = (float)app('steam')->positive((string)$valueArray['amount']); $chartData['datasets'][0]['backgroundColor'][] = ChartColour::getColour($index); $chartData['datasets'][0]['currency_symbol'][] = $valueArray['currency_symbol']; $chartData['labels'][] = $key; @@ -166,7 +165,7 @@ class ChartJsGenerator implements GeneratorInterface // different sort when values are positive and when they're negative. asort($data); $next = next($data); - if (!is_bool($next) && 1 === bccomp((string) $next, '0')) { + if (!is_bool($next) && 1 === bccomp((string)$next, '0')) { // next is positive, sort other way around. arsort($data); } @@ -175,7 +174,7 @@ class ChartJsGenerator implements GeneratorInterface $index = 0; foreach ($data as $key => $value) { // make larger than 0 - $chartData['datasets'][0]['data'][] = (float) app('steam')->positive((string) $value); + $chartData['datasets'][0]['data'][] = (float)app('steam')->positive((string)$value); $chartData['datasets'][0]['backgroundColor'][] = ChartColour::getColour($index); $chartData['labels'][] = $key; diff --git a/app/Generator/Report/Audit/MonthReportGenerator.php b/app/Generator/Report/Audit/MonthReportGenerator.php index d67e8af911..754485d02f 100644 --- a/app/Generator/Report/Audit/MonthReportGenerator.php +++ b/app/Generator/Report/Audit/MonthReportGenerator.php @@ -42,15 +42,15 @@ use Throwable; class MonthReportGenerator implements ReportGeneratorInterface { private Collection $accounts; - private Carbon $end; - private Carbon $start; + private Carbon $end; + private Carbon $start; /** * 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, + ]; + } } diff --git a/app/Generator/Report/Category/MonthReportGenerator.php b/app/Generator/Report/Category/MonthReportGenerator.php index 1bc8be9b89..4836354b38 100644 --- a/app/Generator/Report/Category/MonthReportGenerator.php +++ b/app/Generator/Report/Category/MonthReportGenerator.php @@ -76,7 +76,7 @@ class MonthReportGenerator implements ReportGeneratorInterface // render! try { - return view('reports.category.month', compact('accountIds', 'categoryIds', 'reportType', )) + return view('reports.category.month', compact('accountIds', 'categoryIds', 'reportType',)) ->with('start', $this->start)->with('end', $this->end) ->with('categories', $this->categories) ->with('accounts', $this->accounts) diff --git a/app/Generator/Report/ReportGeneratorFactory.php b/app/Generator/Report/ReportGeneratorFactory.php index 011cf97fc1..ceeb641a0f 100644 --- a/app/Generator/Report/ReportGeneratorFactory.php +++ b/app/Generator/Report/ReportGeneratorFactory.php @@ -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 { diff --git a/app/Generator/Webhook/MessageGeneratorInterface.php b/app/Generator/Webhook/MessageGeneratorInterface.php index d86490563d..8d02908203 100644 --- a/app/Generator/Webhook/MessageGeneratorInterface.php +++ b/app/Generator/Webhook/MessageGeneratorInterface.php @@ -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; } diff --git a/app/Generator/Webhook/StandardMessageGenerator.php b/app/Generator/Webhook/StandardMessageGenerator.php index 90174354bc..751dd6260d 100644 --- a/app/Generator/Webhook/StandardMessageGenerator.php +++ b/app/Generator/Webhook/StandardMessageGenerator.php @@ -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; - } } diff --git a/app/Handlers/Events/APIEventHandler.php b/app/Handlers/Events/APIEventHandler.php index ad14ef4a31..b04c80ed5d 100644 --- a/app/Handlers/Events/APIEventHandler.php +++ b/app/Handlers/Events/APIEventHandler.php @@ -49,12 +49,12 @@ class APIEventHandler { /** @var UserRepositoryInterface $repository */ $repository = app(UserRepositoryInterface::class); - $user = $repository->findNull((int) $event->userId); + $user = $repository->findNull((int)$event->userId); if (null !== $user) { - $email = $user->email; + $email = $user->email; // if user is demo user, send to owner: - if($user->hasRole('demo')) { + if ($user->hasRole('demo')) { $email = config('firefly.site_owner'); } diff --git a/app/Handlers/Events/AdminEventHandler.php b/app/Handlers/Events/AdminEventHandler.php index 7ce138cb3a..1b16371383 100644 --- a/app/Handlers/Events/AdminEventHandler.php +++ b/app/Handlers/Events/AdminEventHandler.php @@ -53,7 +53,7 @@ class AdminEventHandler $ipAddress = $event->ipAddress; // if user is demo user, send to owner: - if($event->user->hasRole('demo')) { + if ($event->user->hasRole('demo')) { $email = config('firefly.site_owner'); } diff --git a/app/Handlers/Events/AutomationHandler.php b/app/Handlers/Events/AutomationHandler.php index 9c513a8794..e65abbb55d 100644 --- a/app/Handlers/Events/AutomationHandler.php +++ b/app/Handlers/Events/AutomationHandler.php @@ -57,7 +57,7 @@ class AutomationHandler $user = $repository->findNull($event->userId); if (null !== $user && 0 !== $event->groups->count()) { - $email = $user->email; + $email = $user->email; // see if user has alternative email address: $pref = app('preferences')->getForUser($user, 'remote_guard_alt_email', null); @@ -66,7 +66,7 @@ class AutomationHandler } // if user is demo user, send to owner: - if($user->hasRole('demo')) { + if ($user->hasRole('demo')) { $email = config('firefly.site_owner'); } diff --git a/app/Handlers/Events/StoredGroupEventHandler.php b/app/Handlers/Events/StoredGroupEventHandler.php index 751a0422bb..3824d6f499 100644 --- a/app/Handlers/Events/StoredGroupEventHandler.php +++ b/app/Handlers/Events/StoredGroupEventHandler.php @@ -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; @@ -85,8 +84,8 @@ class StoredGroupEventHandler public function triggerWebhooks(StoredTransactionGroup $storedGroupEvent): void { Log::debug(__METHOD__); - $group = $storedGroupEvent->transactionGroup; - $user = $group->user; + $group = $storedGroupEvent->transactionGroup; + $user = $group->user; /** @var MessageGeneratorInterface $engine */ $engine = app(MessageGeneratorInterface::class); $engine->setUser($user); diff --git a/app/Handlers/Events/UpdatedGroupEventHandler.php b/app/Handlers/Events/UpdatedGroupEventHandler.php index fc281330d9..5cd7cf4619 100644 --- a/app/Handlers/Events/UpdatedGroupEventHandler.php +++ b/app/Handlers/Events/UpdatedGroupEventHandler.php @@ -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. * @@ -123,8 +82,8 @@ class UpdatedGroupEventHandler public function triggerWebhooks(UpdatedTransactionGroup $updatedGroupEvent): void { Log::debug('UpdatedGroupEventHandler:triggerWebhooks'); - $group = $updatedGroupEvent->transactionGroup; - $user = $group->user; + $group = $updatedGroupEvent->transactionGroup; + $user = $group->user; /** @var MessageGeneratorInterface $engine */ $engine = app(MessageGeneratorInterface::class); $engine->setUser($user); @@ -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]); + } + + } } diff --git a/app/Handlers/Events/UserEventHandler.php b/app/Handlers/Events/UserEventHandler.php index 4931da418c..f2606086a4 100644 --- a/app/Handlers/Events/UserEventHandler.php +++ b/app/Handlers/Events/UserEventHandler.php @@ -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 */ @@ -183,11 +137,11 @@ class UserEventHandler $email = $user->email; $ipAddress = $event->ipAddress; - if($user->hasRole('demo')) { + if ($user->hasRole('demo')) { return; // do not email demo user. } - $list = app('preferences')->getForUser($user, 'login_ip_history', [])->data; + $list = app('preferences')->getForUser($user, 'login_ip_history', [])->data; // see if user has alternative email address: $pref = app('preferences')->getForUser($user, 'remote_guard_alt_email', null); @@ -252,7 +206,7 @@ class UserEventHandler $user = $event->user; $ipAddress = $event->ipAddress; $token = app('preferences')->getForUser($user, 'email_change_undo_token', 'invalid'); - $hashed = hash('sha256', sprintf('%s%s', (string) config('app.key'), $oldEmail)); + $hashed = hash('sha256', sprintf('%s%s', (string)config('app.key'), $oldEmail)); $uri = route('profile.undo-email-change', [$token->data, $hashed]); try { Mail::to($oldEmail)->send(new UndoEmailChangeMail($newEmail, $oldEmail, $uri, $ipAddress)); @@ -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)); + } + + } } diff --git a/app/Handlers/Events/VersionCheckEventHandler.php b/app/Handlers/Events/VersionCheckEventHandler.php index 3c068ffade..7399974dc4 100644 --- a/app/Handlers/Events/VersionCheckEventHandler.php +++ b/app/Handlers/Events/VersionCheckEventHandler.php @@ -51,7 +51,7 @@ class VersionCheckEventHandler // should not check for updates: $permission = app('fireflyconfig')->get('permission_update_check', -1); - $value = (int) $permission->data; + $value = (int)$permission->data; if (1 !== $value) { Log::info('Update check is not enabled.'); $this->warnToCheckForUpdates($event); @@ -115,7 +115,7 @@ class VersionCheckEventHandler // last check time was more than a week ago. Log::debug('Have warned about a new version in four weeks!'); - session()->flash('info', (string) trans('firefly.disabled_but_check')); + session()->flash('info', (string)trans('firefly.disabled_but_check')); app('fireflyconfig')->set('last_update_warning', time()); } } diff --git a/app/Helpers/Attachments/AttachmentHelper.php b/app/Helpers/Attachments/AttachmentHelper.php index c20a6413e6..ef89e71efe 100644 --- a/app/Helpers/Attachments/AttachmentHelper.php +++ b/app/Helpers/Attachments/AttachmentHelper.php @@ -64,8 +64,8 @@ class AttachmentHelper implements AttachmentHelperInterface */ public function __construct() { - $this->maxUploadSize = (int) config('firefly.maxUploadSize'); - $this->allowedMimes = (array) config('firefly.allowedMimes'); + $this->maxUploadSize = (int)config('firefly.maxUploadSize'); + $this->allowedMimes = (array)config('firefly.allowedMimes'); $this->errors = new MessageBag; $this->messages = new MessageBag; $this->attachments = new Collection; @@ -92,7 +92,7 @@ class AttachmentHelper implements AttachmentHelperInterface } try { $unencryptedData = Crypt::decrypt($encryptedData); // verified - } catch (DecryptException|FileNotFoundException $e) { + } catch (DecryptException | FileNotFoundException $e) { Log::error(sprintf('Could not decrypt data of attachment #%d: %s', $attachment->id, $e->getMessage())); $unencryptedData = $encryptedData; } @@ -110,7 +110,7 @@ class AttachmentHelper implements AttachmentHelperInterface */ public function getAttachmentLocation(Attachment $attachment): string { - return sprintf('%sat-%d.data', DIRECTORY_SEPARATOR, (int) $attachment->id); + return sprintf('%sat-%d.data', DIRECTORY_SEPARATOR, (int)$attachment->id); } /** @@ -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 { @@ -275,7 +244,7 @@ class AttachmentHelper implements AttachmentHelperInterface $attachment = null; if (false !== $validation) { $class = get_class($model); - $user = $model->user; + $user = $model->user; if (PiggyBank::class === $class) { $user = $model->account->user; } @@ -309,65 +278,13 @@ class AttachmentHelper implements AttachmentHelperInterface $this->attachments->push($attachment); $name = e($file->getClientOriginalName()); // add message: - $msg = (string) trans('validation.file_attached', ['name' => $name]); + $msg = (string)trans('validation.file_attached', ['name' => $name]); $this->messages->add('attachments', $msg); } return $attachment; } - /** - * Verify if the mime of a file is valid. - * - * @param UploadedFile $file - * - * @return bool - */ - protected function validMime(UploadedFile $file): bool - { - Log::debug('Now in validMime()'); - $mime = e($file->getMimeType()); - $name = e($file->getClientOriginalName()); - Log::debug(sprintf('Name is %s, and mime is %s', $name, $mime)); - Log::debug('Valid mimes are', $this->allowedMimes); - $result = true; - - if (!in_array($mime, $this->allowedMimes, true)) { - $msg = (string) trans('validation.file_invalid_mime', ['name' => $name, 'mime' => $mime]); - $this->errors->add('attachments', $msg); - Log::error($msg); - - $result = false; - } - - return $result; - } - - /** - * Verify if the size of a file is valid. - * - * @codeCoverageIgnore - * - * @param UploadedFile $file - * - * @return bool - */ - protected function validSize(UploadedFile $file): bool - { - $size = $file->getSize(); - $name = e($file->getClientOriginalName()); - $result = true; - if ($size > $this->maxUploadSize) { - $msg = (string) trans('validation.file_too_large', ['name' => $name]); - $this->errors->add('attachments', $msg); - Log::error($msg); - - $result = false; - } - - return $result; - } - /** * Verify if the file was uploaded correctly. * @@ -400,4 +317,87 @@ class AttachmentHelper implements AttachmentHelperInterface return $result; } + + /** + * Verify if the mime of a file is valid. + * + * @param UploadedFile $file + * + * @return bool + */ + protected function validMime(UploadedFile $file): bool + { + Log::debug('Now in validMime()'); + $mime = e($file->getMimeType()); + $name = e($file->getClientOriginalName()); + Log::debug(sprintf('Name is %s, and mime is %s', $name, $mime)); + Log::debug('Valid mimes are', $this->allowedMimes); + $result = true; + + if (!in_array($mime, $this->allowedMimes, true)) { + $msg = (string)trans('validation.file_invalid_mime', ['name' => $name, 'mime' => $mime]); + $this->errors->add('attachments', $msg); + Log::error($msg); + + $result = false; + } + + return $result; + } + + /** + * Verify if the size of a file is valid. + * + * @codeCoverageIgnore + * + * @param UploadedFile $file + * + * @return bool + */ + protected function validSize(UploadedFile $file): bool + { + $size = $file->getSize(); + $name = e($file->getClientOriginalName()); + $result = true; + if ($size > $this->maxUploadSize) { + $msg = (string)trans('validation.file_too_large', ['name' => $name]); + $this->errors->add('attachments', $msg); + Log::error($msg); + + $result = false; + } + + return $result; + } + + /** + * 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; + } } diff --git a/app/Helpers/Collector/Extensions/CollectorProperties.php b/app/Helpers/Collector/Extensions/CollectorProperties.php index e8cdc2712f..ea497d7391 100644 --- a/app/Helpers/Collector/Extensions/CollectorProperties.php +++ b/app/Helpers/Collector/Extensions/CollectorProperties.php @@ -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; } diff --git a/app/Helpers/Collector/Extensions/MetaCollection.php b/app/Helpers/Collector/Extensions/MetaCollection.php index c176fc2687..538050e508 100644 --- a/app/Helpers/Collector/Extensions/MetaCollection.php +++ b/app/Helpers/Collector/Extensions/MetaCollection.php @@ -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 @@ -124,7 +100,7 @@ trait MetaCollection $this->withNotes(); $this->query->where('notes.text', 'LIKE', sprintf('%s%%', $value)); - return $this; + return $this; } /** @@ -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'); + } + } + } diff --git a/app/Helpers/Collector/GroupCollector.php b/app/Helpers/Collector/GroupCollector.php index f2339850da..c12f3da83b 100644 --- a/app/Helpers/Collector/GroupCollector.php +++ b/app/Helpers/Collector/GroupCollector.php @@ -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 '
';
-        print_r($this->query->getBindings());
-        echo '
'; + $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') - return $array; - } - - /** - * 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; + // 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'); } /** @@ -533,6 +547,33 @@ class GroupCollector implements GroupCollectorInterface } } + /** + * + */ + public function dumpQuery(): void + { + echo $this->query->select($this->fields)->toSql(); + echo '
';
+        print_r($this->query->getBindings());
+        echo '
'; + } + + /** + * 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'); - } } diff --git a/app/Helpers/Collector/GroupCollectorInterface.php b/app/Helpers/Collector/GroupCollectorInterface.php index 43493c59ed..964ad19aa0 100644 --- a/app/Helpers/Collector/GroupCollectorInterface.php +++ b/app/Helpers/Collector/GroupCollectorInterface.php @@ -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; } diff --git a/app/Helpers/Fiscal/FiscalHelper.php b/app/Helpers/Fiscal/FiscalHelper.php index b9dbd6be39..15a92d3c83 100644 --- a/app/Helpers/Fiscal/FiscalHelper.php +++ b/app/Helpers/Fiscal/FiscalHelper.php @@ -75,7 +75,7 @@ class FiscalHelper implements FiscalHelperInterface if (true === $this->useCustomFiscalYear) { $prefStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data; [$mth, $day] = explode('-', $prefStartStr); - $startDate->day((int) $day)->month((int) $mth); + $startDate->day((int)$day)->month((int)$mth); // if start date is after passed date, sub 1 year. if ($startDate > $date) { diff --git a/app/Helpers/Report/NetWorth.php b/app/Helpers/Report/NetWorth.php index 63aa980dae..01303273f9 100644 --- a/app/Helpers/Report/NetWorth.php +++ b/app/Helpers/Report/NetWorth.php @@ -89,7 +89,7 @@ class NetWorth implements NetWorthInterface /** @var Account $account */ foreach ($accounts as $account) { Log::debug(sprintf('Now at account #%d: "%s"', $account->id, $account->name)); - $currencyId = (int) $this->accountRepository->getMetaValue($account, 'currency_id'); + $currencyId = (int)$this->accountRepository->getMetaValue($account, 'currency_id'); $currencyId = 0 === $currencyId ? $default->id : $currencyId; Log::debug(sprintf('Currency ID is #%d', $currencyId)); @@ -100,7 +100,7 @@ class NetWorth implements NetWorthInterface Log::debug(sprintf('Balance is %s', $balance)); // always subtract virtual balance. - $virtualBalance = (string) $account->virtual_balance; + $virtualBalance = (string)$account->virtual_balance; if ('' !== $virtualBalance) { $balance = bcsub($balance, $virtualBalance); } diff --git a/app/Helpers/Report/PopupReport.php b/app/Helpers/Report/PopupReport.php index 36d7ec389b..8230672a3c 100644 --- a/app/Helpers/Report/PopupReport.php +++ b/app/Helpers/Report/PopupReport.php @@ -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. @@ -78,7 +77,7 @@ class PopupReport implements PopupReportInterface if (null !== $currencyId) { /** @var CurrencyRepositoryInterface $repos */ $repos = app(CurrencyRepositoryInterface::class); - $currency = $repos->find((int) $currencyId); + $currency = $repos->find((int)$currencyId); } @@ -115,7 +114,7 @@ class PopupReport implements PopupReportInterface if (null !== $currencyId) { /** @var CurrencyRepositoryInterface $repos */ $repos = app(CurrencyRepositoryInterface::class); - $currency = $repos->find((int) $currencyId); + $currency = $repos->find((int)$currencyId); } @@ -157,7 +156,7 @@ class PopupReport implements PopupReportInterface if (null !== $currencyId) { /** @var CurrencyRepositoryInterface $repos */ $repos = app(CurrencyRepositoryInterface::class); - $currency = $repos->find((int) $currencyId); + $currency = $repos->find((int)$currencyId); } /** @var GroupCollectorInterface $collector */ @@ -200,7 +199,7 @@ class PopupReport implements PopupReportInterface if (null !== $currencyId) { /** @var CurrencyRepositoryInterface $repos */ $repos = app(CurrencyRepositoryInterface::class); - $currency = $repos->find((int) $currencyId); + $currency = $repos->find((int)$currencyId); } /** @var JournalRepositoryInterface $repository */ diff --git a/app/Helpers/Report/ReportHelper.php b/app/Helpers/Report/ReportHelper.php index 70745d1a6b..9221359b0a 100644 --- a/app/Helpers/Report/ReportHelper.php +++ b/app/Helpers/Report/ReportHelper.php @@ -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. diff --git a/app/Helpers/Webhook/Sha3SignatureGenerator.php b/app/Helpers/Webhook/Sha3SignatureGenerator.php index 8674a2b3bb..8077432f9d 100644 --- a/app/Helpers/Webhook/Sha3SignatureGenerator.php +++ b/app/Helpers/Webhook/Sha3SignatureGenerator.php @@ -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; + } } diff --git a/app/Helpers/Webhook/SignatureGeneratorInterface.php b/app/Helpers/Webhook/SignatureGeneratorInterface.php index 1c4506c377..cf27c888b1 100644 --- a/app/Helpers/Webhook/SignatureGeneratorInterface.php +++ b/app/Helpers/Webhook/SignatureGeneratorInterface.php @@ -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; } diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php index c29703af67..fc921db193 100644 --- a/app/Http/Controllers/Admin/HomeController.php +++ b/app/Http/Controllers/Admin/HomeController.php @@ -57,16 +57,16 @@ class HomeController extends Controller public function index() { Log::channel('audit')->info('User visits admin index.'); - $title = (string) trans('firefly.administration'); + $title = (string)trans('firefly.administration'); $mainTitleIcon = 'fa-hand-spock-o'; - $email = auth()->user()->email; - $pref = app('preferences')->get('remote_guard_alt_email', null); - if(null !== $pref && is_string($pref->data)) { + $email = auth()->user()->email; + $pref = app('preferences')->get('remote_guard_alt_email', null); + if (null !== $pref && is_string($pref->data)) { $email = $pref->data; } Log::debug('Email is ', [$email]); - return prefixView('admin.index', compact('title', 'mainTitleIcon','email')); + return prefixView('admin.index', compact('title', 'mainTitleIcon', 'email')); } /** @@ -84,7 +84,7 @@ class HomeController extends Controller $ipAddress = $request->ip(); Log::debug(sprintf('Now in testMessage() controller. IP is %s', $ipAddress)); event(new AdminRequestedTestMessage($user, $ipAddress)); - session()->flash('info', (string) trans('firefly.send_test_triggered')); + session()->flash('info', (string)trans('firefly.send_test_triggered')); return redirect(route('admin.index')); } diff --git a/app/Http/Controllers/Admin/LinkController.php b/app/Http/Controllers/Admin/LinkController.php index e59d2a3b2c..68256d93d6 100644 --- a/app/Http/Controllers/Admin/LinkController.php +++ b/app/Http/Controllers/Admin/LinkController.php @@ -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; /** @@ -53,7 +54,7 @@ class LinkController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.administration')); + app('view')->share('title', (string)trans('firefly.administration')); app('view')->share('mainTitleIcon', 'fa-hand-spock-o'); $this->repository = app(LinkTypeRepositoryInterface::class); @@ -66,13 +67,13 @@ class LinkController extends Controller /** * Make a new link form. * - * @return Factory|\Illuminate\View\View + * @return Factory|View */ public function create() { Log::channel('audit')->info('User visits link index.'); - $subTitle = (string) trans('firefly.create_new_link_type'); + $subTitle = (string)trans('firefly.create_new_link_type'); $subTitleIcon = 'fa-link'; // put previous url in session if not redirect from store (not "create another"). @@ -89,22 +90,22 @@ 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) { if (!$linkType->editable) { - $request->session()->flash('error', (string) trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)])); + $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)])); return redirect(route('admin.links.index')); } Log::channel('audit')->info(sprintf('User wants to delete link type #%d', $linkType->id)); - $subTitle = (string) trans('firefly.delete_link_type', ['name' => $linkType->name]); + $subTitle = (string)trans('firefly.delete_link_type', ['name' => $linkType->name]); $otherTypes = $this->repository->get(); $count = $this->repository->countJournals($linkType); $moveTo = []; - $moveTo[0] = (string) trans('firefly.do_not_save_connection'); + $moveTo[0] = (string)trans('firefly.do_not_save_connection'); /** @var LinkType $otherType */ foreach ($otherTypes as $otherType) { @@ -131,10 +132,10 @@ class LinkController extends Controller { Log::channel('audit')->info(sprintf('User destroyed link type #%d', $linkType->id)); $name = $linkType->name; - $moveTo = $this->repository->findNull((int) $request->get('move_link_type_before_delete')); + $moveTo = $this->repository->findNull((int)$request->get('move_link_type_before_delete')); $this->repository->destroy($linkType, $moveTo); - $request->session()->flash('success', (string) trans('firefly.deleted_link_type', ['name' => $name])); + $request->session()->flash('success', (string)trans('firefly.deleted_link_type', ['name' => $name])); app('preferences')->mark(); return redirect($this->getPreviousUri('link-types.delete.uri')); @@ -146,16 +147,16 @@ 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) { if (!$linkType->editable) { - $request->session()->flash('error', (string) trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)])); + $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)])); return redirect(route('admin.links.index')); } - $subTitle = (string) trans('firefly.edit_link_type', ['name' => $linkType->name]); + $subTitle = (string)trans('firefly.edit_link_type', ['name' => $linkType->name]); $subTitleIcon = 'fa-link'; Log::channel('audit')->info(sprintf('User wants to edit link type #%d', $linkType->id)); @@ -172,11 +173,11 @@ class LinkController extends Controller /** * Show index of all links. * - * @return Factory|\Illuminate\View\View + * @return Factory|View */ public function index() { - $subTitle = (string) trans('firefly.journal_link_configuration'); + $subTitle = (string)trans('firefly.journal_link_configuration'); $subTitleIcon = 'fa-link'; $linkTypes = $this->repository->get(); @@ -195,11 +196,11 @@ class LinkController extends Controller * * @param LinkType $linkType * - * @return Factory|\Illuminate\View\View + * @return Factory|View */ public function show(LinkType $linkType) { - $subTitle = (string) trans('firefly.overview_for_link', ['name' => $linkType->name]); + $subTitle = (string)trans('firefly.overview_for_link', ['name' => $linkType->name]); $subTitleIcon = 'fa-link'; $links = $this->repository->getJournalLinks($linkType); @@ -226,9 +227,9 @@ class LinkController extends Controller Log::channel('audit')->info('User stored new link type.', $linkType->toArray()); - $request->session()->flash('success', (string) trans('firefly.stored_new_link_type', ['name' => $linkType->name])); + $request->session()->flash('success', (string)trans('firefly.stored_new_link_type', ['name' => $linkType->name])); $redirect = redirect($this->getPreviousUri('link-types.create.uri')); - if (1 === (int) $request->get('create_another')) { + if (1 === (int)$request->get('create_another')) { // set value so create routine will not overwrite URL: $request->session()->put('link-types.create.fromStore', true); @@ -250,7 +251,7 @@ class LinkController extends Controller public function update(LinkTypeFormRequest $request, LinkType $linkType) { if (!$linkType->editable) { - $request->session()->flash('error', (string) trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)])); + $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)])); return redirect(route('admin.links.index')); } @@ -264,10 +265,10 @@ class LinkController extends Controller Log::channel('audit')->info(sprintf('User update link type #%d.', $linkType->id), $data); - $request->session()->flash('success', (string) trans('firefly.updated_link_type', ['name' => $linkType->name])); + $request->session()->flash('success', (string)trans('firefly.updated_link_type', ['name' => $linkType->name])); app('preferences')->mark(); $redirect = redirect($this->getPreviousUri('link-types.edit.uri')); - if (1 === (int) $request->get('return_to_edit')) { + if (1 === (int)$request->get('return_to_edit')) { // set value so edit routine will not overwrite URL: $request->session()->put('link-types.edit.fromUpdate', true); diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index cdefb8f96a..bae9542d46 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -48,7 +48,7 @@ class UserController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.administration')); + app('view')->share('title', (string)trans('firefly.administration')); app('view')->share('mainTitleIcon', 'fa-hand-spock-o'); $this->repository = app(UserRepositoryInterface::class); @@ -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) @@ -73,7 +74,7 @@ class UserController extends Controller return redirect(route('admin.users')); } - $subTitle = (string) trans('firefly.delete_user', ['email' => $user->email]); + $subTitle = (string)trans('firefly.delete_user', ['email' => $user->email]); return prefixView('admin.users.delete', compact('user', 'subTitle')); } @@ -93,7 +94,7 @@ class UserController extends Controller return redirect(route('admin.users')); } $this->repository->destroy($user); - session()->flash('success', (string) trans('firefly.user_deleted')); + session()->flash('success', (string)trans('firefly.user_deleted')); return redirect(route('admin.users')); } @@ -117,15 +118,15 @@ class UserController extends Controller } session()->forget('users.edit.fromUpdate'); - $subTitle = (string) trans('firefly.edit_user', ['email' => $user->email]); + $subTitle = (string)trans('firefly.edit_user', ['email' => $user->email]); $subTitleIcon = 'fa-user-o'; $currentUser = auth()->user(); $isAdmin = $this->repository->hasRole($user, 'owner'); $codes = [ - '' => (string) trans('firefly.no_block_code'), - 'bounced' => (string) trans('firefly.block_code_bounced'), - 'expired' => (string) trans('firefly.block_code_expired'), - 'email_changed' => (string) trans('firefly.block_code_email_changed'), + '' => (string)trans('firefly.no_block_code'), + 'bounced' => (string)trans('firefly.block_code_bounced'), + 'expired' => (string)trans('firefly.block_code_expired'), + 'email_changed' => (string)trans('firefly.block_code_email_changed'), ]; return prefixView('admin.users.edit', compact('user', 'canEditDetails', 'subTitle', 'subTitleIcon', 'codes', 'currentUser', 'isAdmin')); @@ -138,7 +139,7 @@ class UserController extends Controller */ public function index() { - $subTitle = (string) trans('firefly.user_administration'); + $subTitle = (string)trans('firefly.user_administration'); $subTitleIcon = 'fa-users'; $users = $this->repository->all(); @@ -162,9 +163,9 @@ class UserController extends Controller */ public function show(User $user) { - $title = (string) trans('firefly.administration'); + $title = (string)trans('firefly.administration'); $mainTitleIcon = 'fa-hand-spock-o'; - $subTitle = (string) trans('firefly.single_user_administration', ['email' => $user->email]); + $subTitle = (string)trans('firefly.single_user_administration', ['email' => $user->email]); $subTitleIcon = 'fa-user'; $information = $this->repository->getUserData($user); @@ -211,10 +212,10 @@ class UserController extends Controller $this->repository->changeStatus($user, $data['blocked'], $data['blocked_code']); $this->repository->updateEmail($user, $data['email']); - session()->flash('success', (string) trans('firefly.updated_user', ['email' => $user->email])); + session()->flash('success', (string)trans('firefly.updated_user', ['email' => $user->email])); app('preferences')->mark(); $redirect = redirect($this->getPreviousUri('users.edit.uri')); - if (1 === (int) $request->get('return_to_edit')) { + if (1 === (int)$request->get('return_to_edit')) { // @codeCoverageIgnoreStart session()->put('users.edit.fromUpdate', true); diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 9842a3eaa1..b17e8652a7 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -88,7 +88,7 @@ class ForgotPasswordController extends Controller $user = User::where('email', $request->get('email'))->first(); if (null !== $user && $repository->hasRole($user, 'demo')) { - return back()->withErrors(['email' => (string) trans('firefly.cannot_reset_demo_user')]); + return back()->withErrors(['email' => (string)trans('firefly.cannot_reset_demo_user')]); } // We will send the password reset link to this user. Once we have attempted @@ -125,7 +125,7 @@ class ForgotPasswordController extends Controller $singleUserMode = app('fireflyconfig')->get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; $userCount = User::count(); $allowRegistration = true; - $pageTitle = (string) trans('firefly.forgot_pw_page_title'); + $pageTitle = (string)trans('firefly.forgot_pw_page_title'); if (true === $singleUserMode && $userCount > 0) { $allowRegistration = false; } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index a77d6a3a88..f5f2c776fd 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -120,6 +120,64 @@ class LoginController extends Controller $this->sendFailedLoginResponse($request); } + /** + * Log the user out of the application. + * + * @param Request $request + * + * @return \Illuminate\Http\Response + */ + public function logout(Request $request) + { + $authGuard = config('firefly.authentication_guard'); + $logoutUri = config('firefly.custom_logout_uri'); + if ('remote_user_guard' === $authGuard && '' !== $logoutUri) { + return redirect($logoutUri); + } + if ('remote_user_guard' === $authGuard && '' === $logoutUri) { + session()->flash('error', trans('firefly.cant_logout_guard')); + } + + // also logout current 2FA tokens. + $cookieName = config('google2fa.cookie_name', 'google2fa_token'); + Cookie::forget($cookieName); + + $this->guard()->logout(); + + $request->session()->invalidate(); + + $request->session()->regenerateToken(); + + if ($response = $this->loggedOut($request)) { + return $response; + } + + return $request->wantsJson() + ? new \Illuminate\Http\Response('', 204) + : redirect('/'); + } + + /** + * Get the failed login response instance. + * + * @param Request $request + * + * @return Response + * + * @throws ValidationException + */ + protected function sendFailedLoginResponse(Request $request) + { + $exception = ValidationException::withMessages( + [ + $this->username() => [trans('auth.failed')], + ] + ); + $exception->redirectTo = route('login'); + + throw $exception; + } + /** * Show the application's login form. * @@ -163,63 +221,4 @@ class LoginController extends Controller return prefixView('auth.login', compact('allowRegistration', 'email', 'remember', 'allowReset', 'title')); } - /** - * Get the failed login response instance. - * - * @param Request $request - * - * @return Response - * - * @throws ValidationException - */ - protected function sendFailedLoginResponse(Request $request) - { - $exception = ValidationException::withMessages( - [ - $this->username() => [trans('auth.failed')], - ] - ); - $exception->redirectTo = route('login'); - - throw $exception; - } - - - /** - * Log the user out of the application. - * - * @param \Illuminate\Http\Request $request - * - * @return \Illuminate\Http\Response - */ - public function logout(Request $request) - { - $authGuard = config('firefly.authentication_guard'); - $logoutUri = config('firefly.custom_logout_uri'); - if ('remote_user_guard' === $authGuard && '' !== $logoutUri) { - return redirect($logoutUri); - } - if ('remote_user_guard' === $authGuard && '' === $logoutUri) { - session()->flash('error', trans('firefly.cant_logout_guard')); - } - - // also logout current 2FA tokens. - $cookieName = config('google2fa.cookie_name', 'google2fa_token'); - Cookie::forget($cookieName); - - $this->guard()->logout(); - - $request->session()->invalidate(); - - $request->session()->regenerateToken(); - - if ($response = $this->loggedOut($request)) { - return $response; - } - - return $request->wantsJson() - ? new \Illuminate\Http\Response('', 204) - : redirect('/'); - } - } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index a7152d0b80..4f669d4c7b 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -108,7 +108,7 @@ class RegisterController extends Controller $this->guard()->login($user); - session()->flash('success', (string) trans('firefly.registered')); + session()->flash('success', (string)trans('firefly.registered')); $this->registered($request, $user); @@ -132,7 +132,7 @@ class RegisterController extends Controller $isDemoSite = app('fireflyconfig')->get('is_demo_site', config('firefly.configuration.is_demo_site'))->data; $singleUserMode = app('fireflyconfig')->get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; $userCount = User::count(); - $pageTitle = (string) trans('firefly.register_page_title'); + $pageTitle = (string)trans('firefly.register_page_title'); if (true === $isDemoSite) { $allowRegistration = false; diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index fd0b9c0f07..99a4a456b1 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -32,6 +32,7 @@ use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Password; +use Illuminate\Validation\ValidationException; use Illuminate\View\View; /** @@ -76,7 +77,7 @@ class ResetPasswordController extends Controller * @param Request $request * * @return Factory|JsonResponse|RedirectResponse|View - * @throws \Illuminate\Validation\ValidationException + * @throws ValidationException * */ public function reset(Request $request) @@ -137,7 +138,7 @@ class ResetPasswordController extends Controller $singleUserMode = app('fireflyconfig')->get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; $userCount = User::count(); $allowRegistration = true; - $pageTitle = (string) trans('firefly.reset_pw_page_title'); + $pageTitle = (string)trans('firefly.reset_pw_page_title'); if (true === $singleUserMode && $userCount > 0) { $allowRegistration = false; } diff --git a/app/Http/Controllers/Auth/TwoFactorController.php b/app/Http/Controllers/Auth/TwoFactorController.php index 2bf8164b84..753e4aeb3a 100644 --- a/app/Http/Controllers/Auth/TwoFactorController.php +++ b/app/Http/Controllers/Auth/TwoFactorController.php @@ -45,7 +45,7 @@ class TwoFactorController extends Controller /** @var User $user */ $user = auth()->user(); $siteOwner = config('firefly.site_owner'); - $title = (string) trans('firefly.two_factor_forgot_title'); + $title = (string)trans('firefly.two_factor_forgot_title'); return prefixView('auth.lost-two-factor', compact('user', 'siteOwner', 'title')); } @@ -96,20 +96,26 @@ class TwoFactorController extends Controller } /** + * Each MFA history has a timestamp and a code, saving the MFA entries for 5 minutes. So if the + * submitted MFA code has been submitted in the last 5 minutes, it won't work despite being valid. + * * @param string $mfaCode + * @param array $mfaHistory + * + * @return bool */ - private function addToMFAHistory(string $mfaCode): void + private function inMFAHistory(string $mfaCode, array $mfaHistory): bool { - /** @var array $mfaHistory */ - $mfaHistory = Preferences::get('mfa_history', [])->data; - $entry = [ - 'time' => time(), - 'code' => $mfaCode, - ]; - $mfaHistory[] = $entry; + $now = time(); + foreach ($mfaHistory as $entry) { + $time = $entry['time']; + $code = $entry['code']; + if ($code === $mfaCode && $now - $time <= 300) { + return true; + } + } - Preferences::set('mfa_history', $mfaHistory); - $this->filterMFAHistory(); + return false; } /** @@ -135,26 +141,20 @@ class TwoFactorController extends Controller } /** - * Each MFA history has a timestamp and a code, saving the MFA entries for 5 minutes. So if the - * submitted MFA code has been submitted in the last 5 minutes, it won't work despite being valid. - * * @param string $mfaCode - * @param array $mfaHistory - * - * @return bool */ - private function inMFAHistory(string $mfaCode, array $mfaHistory): bool + private function addToMFAHistory(string $mfaCode): void { - $now = time(); - foreach ($mfaHistory as $entry) { - $time = $entry['time']; - $code = $entry['code']; - if ($code === $mfaCode && $now - $time <= 300) { - return true; - } - } + /** @var array $mfaHistory */ + $mfaHistory = Preferences::get('mfa_history', [])->data; + $entry = [ + 'time' => time(), + 'code' => $mfaCode, + ]; + $mfaHistory[] = $entry; - return false; + Preferences::set('mfa_history', $mfaHistory); + $this->filterMFAHistory(); } /** diff --git a/app/Http/Controllers/Bill/CreateController.php b/app/Http/Controllers/Bill/CreateController.php index f39a91c7e7..3b05ee956a 100644 --- a/app/Http/Controllers/Bill/CreateController.php +++ b/app/Http/Controllers/Bill/CreateController.php @@ -30,8 +30,11 @@ use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\BillStoreRequest; use FireflyIII\Repositories\Bill\BillRepositoryInterface; +use Illuminate\Contracts\Foundation\Application; +use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; +use Illuminate\View\View; /** * Class CreateController @@ -52,7 +55,7 @@ class CreateController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.bills')); + app('view')->share('title', (string)trans('firefly.bills')); app('view')->share('mainTitleIcon', 'fa-calendar-o'); $this->attachments = app(AttachmentHelperInterface::class); $this->repository = app(BillRepositoryInterface::class); @@ -67,7 +70,7 @@ class CreateController extends Controller * * @param Request $request * - * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @return Application|Factory|View */ public function create(Request $request) { @@ -75,9 +78,9 @@ class CreateController extends Controller /** @var array $billPeriods */ $billPeriods = config('firefly.bill_periods'); foreach ($billPeriods as $current) { - $periods[$current] = (string) trans('firefly.repeat_freq_' . $current); + $periods[$current] = (string)trans('firefly.repeat_freq_' . $current); } - $subTitle = (string) trans('firefly.create_new_bill'); + $subTitle = (string)trans('firefly.create_new_bill'); $defaultCurrency = app('amount')->getDefaultCurrency(); // put previous url in session if not redirect from store (not "create another"). @@ -105,11 +108,11 @@ class CreateController extends Controller $bill = $this->repository->store($billData); } catch (FireflyException $e) { Log::error($e->getMessage()); - $request->session()->flash('error', (string) trans('firefly.bill_store_error')); + $request->session()->flash('error', (string)trans('firefly.bill_store_error')); return redirect(route('bills.create'))->withInput(); } - $request->session()->flash('success', (string) trans('firefly.stored_new_bill', ['name' => $bill->name])); + $request->session()->flash('success', (string)trans('firefly.stored_new_bill', ['name' => $bill->name])); app('preferences')->mark(); /** @var array $files */ @@ -118,7 +121,7 @@ class CreateController extends Controller $this->attachments->saveAttachmentsForModel($bill, $files); } if (null !== $files && auth()->user()->hasRole('demo')) { - session()->flash('info', (string) trans('firefly.no_att_demo_user')); + session()->flash('info', (string)trans('firefly.no_att_demo_user')); } if (count($this->attachments->getMessages()->get('attachments')) > 0) { diff --git a/app/Http/Controllers/Bill/DeleteController.php b/app/Http/Controllers/Bill/DeleteController.php index ee1ef297fb..634a40cc56 100644 --- a/app/Http/Controllers/Bill/DeleteController.php +++ b/app/Http/Controllers/Bill/DeleteController.php @@ -54,7 +54,7 @@ class DeleteController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.bills')); + app('view')->share('title', (string)trans('firefly.bills')); app('view')->share('mainTitleIcon', 'fa-calendar-o'); $this->repository = app(BillRepositoryInterface::class); @@ -62,6 +62,7 @@ class DeleteController extends Controller } ); } + /** * Delete a bill. * @@ -73,7 +74,7 @@ class DeleteController extends Controller { // put previous url in session $this->rememberPreviousUri('bills.delete.uri'); - $subTitle = (string) trans('firefly.delete_bill', ['name' => $bill->name]); + $subTitle = (string)trans('firefly.delete_bill', ['name' => $bill->name]); return prefixView('bills.delete', compact('bill', 'subTitle')); } @@ -91,7 +92,7 @@ class DeleteController extends Controller $name = $bill->name; $this->repository->destroy($bill); - $request->session()->flash('success', (string) trans('firefly.deleted_bill', ['name' => $name])); + $request->session()->flash('success', (string)trans('firefly.deleted_bill', ['name' => $name])); app('preferences')->mark(); return redirect($this->getPreviousUri('bills.delete.uri')); diff --git a/app/Http/Controllers/Bill/EditController.php b/app/Http/Controllers/Bill/EditController.php index 691d9a7038..37ec000360 100644 --- a/app/Http/Controllers/Bill/EditController.php +++ b/app/Http/Controllers/Bill/EditController.php @@ -30,8 +30,11 @@ use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\BillUpdateRequest; use FireflyIII\Models\Bill; use FireflyIII\Repositories\Bill\BillRepositoryInterface; +use Illuminate\Contracts\Foundation\Application; +use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; +use Illuminate\View\View; /** * Class EditController @@ -52,7 +55,7 @@ class EditController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.bills')); + app('view')->share('title', (string)trans('firefly.bills')); app('view')->share('mainTitleIcon', 'fa-calendar-o'); $this->attachments = app(AttachmentHelperInterface::class); $this->repository = app(BillRepositoryInterface::class); @@ -69,7 +72,7 @@ class EditController extends Controller * @param Request $request * @param Bill $bill * - * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @return Application|Factory|View */ public function edit(Request $request, Bill $bill) { @@ -78,10 +81,10 @@ class EditController extends Controller $billPeriods = config('firefly.bill_periods'); foreach ($billPeriods as $current) { - $periods[$current] = (string) trans('firefly.' . $current); + $periods[$current] = (string)trans('firefly.' . $current); } - $subTitle = (string) trans('firefly.edit_bill', ['name' => $bill->name]); + $subTitle = (string)trans('firefly.edit_bill', ['name' => $bill->name]); // put previous url in session if not redirect from store (not "return_to_edit"). if (true !== session('bills.edit.fromUpdate')) { @@ -89,8 +92,8 @@ class EditController extends Controller } $currency = app('amount')->getDefaultCurrency(); - $bill->amount_min = round((float) $bill->amount_min, $currency->decimal_places); - $bill->amount_max = round((float) $bill->amount_max, $currency->decimal_places); + $bill->amount_min = round((float)$bill->amount_min, $currency->decimal_places); + $bill->amount_max = round((float)$bill->amount_max, $currency->decimal_places); $rules = $this->repository->getRulesForBill($bill); $defaultCurrency = app('amount')->getDefaultCurrency(); @@ -100,7 +103,7 @@ class EditController extends Controller $preFilled = [ 'notes' => $this->repository->getNoteText($bill), 'transaction_currency_id' => $bill->transaction_currency_id, - 'active' => $hasOldInput ? (bool) $request->old('active') : $bill->active, + 'active' => $hasOldInput ? (bool)$request->old('active') : $bill->active, 'object_group' => $bill->objectGroups->first() ? $bill->objectGroups->first()->title : '', ]; @@ -115,7 +118,7 @@ class EditController extends Controller * Update a bill. * * @param BillUpdateRequest $request - * @param Bill $bill + * @param Bill $bill * * @return RedirectResponse */ @@ -124,7 +127,7 @@ class EditController extends Controller $billData = $request->getBillData(); $bill = $this->repository->update($bill, $billData); - $request->session()->flash('success', (string) trans('firefly.updated_bill', ['name' => $bill->name])); + $request->session()->flash('success', (string)trans('firefly.updated_bill', ['name' => $bill->name])); app('preferences')->mark(); /** @var array $files */ @@ -133,7 +136,7 @@ class EditController extends Controller $this->attachments->saveAttachmentsForModel($bill, $files); } if (null !== $files && auth()->user()->hasRole('demo')) { - session()->flash('info',(string)trans('firefly.no_att_demo_user')); + session()->flash('info', (string)trans('firefly.no_att_demo_user')); } // flash messages @@ -142,7 +145,7 @@ class EditController extends Controller } $redirect = redirect($this->getPreviousUri('bills.edit.uri')); - if (1 === (int) $request->get('return_to_edit')) { + if (1 === (int)$request->get('return_to_edit')) { // @codeCoverageIgnoreStart $request->session()->put('bills.edit.fromUpdate', true); diff --git a/app/Http/Controllers/Bill/IndexController.php b/app/Http/Controllers/Bill/IndexController.php index ab5c394c71..84b15d9e4f 100644 --- a/app/Http/Controllers/Bill/IndexController.php +++ b/app/Http/Controllers/Bill/IndexController.php @@ -57,7 +57,7 @@ class IndexController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.bills')); + app('view')->share('title', (string)trans('firefly.bills')); app('view')->share('mainTitleIcon', 'fa-calendar-o'); $this->repository = app(BillRepositoryInterface::class); @@ -96,7 +96,7 @@ class IndexController extends Controller $bills = [ 0 => [ // the index is the order, not the ID. 'object_group_id' => 0, - 'object_group_title' => (string) trans('firefly.default_group_title_name'), + 'object_group_title' => (string)trans('firefly.default_group_title_name'), 'bills' => [], ], ]; @@ -105,7 +105,7 @@ class IndexController extends Controller /** @var Bill $bill */ foreach ($collection as $bill) { $array = $transformer->transform($bill); - $groupOrder = (int) $array['object_group_order']; + $groupOrder = (int)$array['object_group_order']; // make group array if necessary: $bills[$groupOrder] = $bills[$groupOrder] ?? [ 'object_group_id' => $array['object_group_id'], @@ -179,8 +179,8 @@ class IndexController extends Controller ]; // only fill in avg when bill is active. if (count($bill['pay_dates']) > 0) { - $avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2'); - $avg = bcmul($avg, (string) count($bill['pay_dates'])); + $avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2'); + $avg = bcmul($avg, (string)count($bill['pay_dates'])); $sums[$groupOrder][$currencyId]['avg'] = bcadd($sums[$groupOrder][$currencyId]['avg'], $avg); } // fill in per period regardless: @@ -199,7 +199,7 @@ class IndexController extends Controller */ private function amountPerPeriod(array $bill, string $range): string { - $avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2'); + $avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2'); Log::debug(sprintf('Amount per period for bill #%d "%s"', $bill['id'], $bill['name'])); Log::debug(sprintf(sprintf('Average is %s', $avg))); @@ -211,7 +211,7 @@ class IndexController extends Controller 'monthly' => '12', 'weekly' => '52.17', ]; - $yearAmount = bcmul($avg, bcdiv($multiplies[$bill['repeat_freq']], (string)($bill['skip'] + 1))); + $yearAmount = bcmul($avg, bcdiv($multiplies[$bill['repeat_freq']], (string)($bill['skip'] + 1))); Log::debug(sprintf('Amount per year is %s (%s * %s / %s)', $yearAmount, $avg, $multiplies[$bill['repeat_freq']], (string)($bill['skip'] + 1))); // per period: @@ -230,31 +230,9 @@ class IndexController extends Controller return $perPeriod; } - /** - * Set the order of a bill. - * - * @param Request $request - * @param Bill $bill - * - * @return JsonResponse - */ - public function setOrder(Request $request, Bill $bill): JsonResponse - { - $objectGroupTitle = (string) $request->get('objectGroupTitle'); - $newOrder = (int) $request->get('order'); - $this->repository->setOrder($bill, $newOrder); - if ('' !== $objectGroupTitle) { - $this->repository->setObjectGroup($bill, $objectGroupTitle); - } - if ('' === $objectGroupTitle) { - $this->repository->removeObjectGroup($bill); - } - - return response()->json(['data' => 'OK']); - } - /** * @param array $sums + * * @return array */ private function getTotals(array $sums): array @@ -289,4 +267,27 @@ class IndexController extends Controller return $totals; } + + /** + * Set the order of a bill. + * + * @param Request $request + * @param Bill $bill + * + * @return JsonResponse + */ + public function setOrder(Request $request, Bill $bill): JsonResponse + { + $objectGroupTitle = (string)$request->get('objectGroupTitle'); + $newOrder = (int)$request->get('order'); + $this->repository->setOrder($bill, $newOrder); + if ('' !== $objectGroupTitle) { + $this->repository->setObjectGroup($bill, $objectGroupTitle); + } + if ('' === $objectGroupTitle) { + $this->repository->removeObjectGroup($bill); + } + + return response()->json(['data' => 'OK']); + } } diff --git a/app/Http/Controllers/Bill/ShowController.php b/app/Http/Controllers/Bill/ShowController.php index 5197bb6cd4..c8c9484eaf 100644 --- a/app/Http/Controllers/Bill/ShowController.php +++ b/app/Http/Controllers/Bill/ShowController.php @@ -65,7 +65,7 @@ class ShowController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.bills')); + app('view')->share('title', (string)trans('firefly.bills')); app('view')->share('mainTitleIcon', 'fa-calendar-o'); $this->repository = app(BillRepositoryInterface::class); @@ -87,7 +87,7 @@ class ShowController extends Controller { $total = 0; if (false === $bill->active) { - $request->session()->flash('warning', (string) trans('firefly.cannot_scan_inactive_bill')); + $request->session()->flash('warning', (string)trans('firefly.cannot_scan_inactive_bill')); return redirect(route('bills.show', [$bill->id])); } @@ -97,7 +97,7 @@ class ShowController extends Controller $total = 0; } if (0 === $set->count()) { - $request->session()->flash('error', (string) trans('firefly.no_rules_for_bill')); + $request->session()->flash('error', (string)trans('firefly.no_rules_for_bill')); return redirect(route('bills.show', [$bill->id])); } @@ -113,7 +113,7 @@ class ShowController extends Controller // file the rule(s) $ruleEngine->fire(); - $request->session()->flash('success', (string) trans_choice('firefly.rescanned_bill', $total)); + $request->session()->flash('success', (string)trans_choice('firefly.rescanned_bill', $total)); app('preferences')->mark(); return redirect(route('bills.show', [$bill->id])); @@ -138,8 +138,8 @@ class ShowController extends Controller /** @var Carbon $end */ $end = session('end'); $year = $start->year; - $page = (int) $request->get('page'); - $pageSize = (int) app('preferences')->get('listPageSize', 50)->data; + $page = (int)$request->get('page'); + $pageSize = (int)app('preferences')->get('listPageSize', 50)->data; $yearAverage = $this->repository->getYearAverage($bill, $start); $overallAverage = $this->repository->getOverallAverage($bill); $manager = new Manager(); diff --git a/app/Http/Controllers/Json/AutoCompleteController.php b/app/Http/Controllers/Json/AutoCompleteController.php index e842a68460..552733d74f 100644 --- a/app/Http/Controllers/Json/AutoCompleteController.php +++ b/app/Http/Controllers/Json/AutoCompleteController.php @@ -50,7 +50,7 @@ class AutoCompleteController extends Controller */ public function allJournalsWithID(Request $request): JsonResponse { - $search = (string) $request->get('search'); + $search = (string)$request->get('search'); /** @var JournalRepositoryInterface $repository */ $repository = app(JournalRepositoryInterface::class); @@ -61,7 +61,7 @@ class AutoCompleteController extends Controller $array = []; if (is_numeric($search)) { // search for group, not journal. - $firstResult = $groupRepos->find((int) $search); + $firstResult = $groupRepos->find((int)$search); if (null !== $firstResult) { // group may contain multiple journals, each a result: foreach ($firstResult->transactionJournals as $journal) { diff --git a/app/Http/Controllers/Json/BoxController.php b/app/Http/Controllers/Json/BoxController.php index 31fd5e9d4b..98df9ede43 100644 --- a/app/Http/Controllers/Json/BoxController.php +++ b/app/Http/Controllers/Json/BoxController.php @@ -69,7 +69,7 @@ class BoxController extends Controller $end = session('end', Carbon::now()->endOfMonth()); $today = today(config('app.timezone')); $display = 2; // see method docs. - $boxTitle = (string) trans('firefly.spent'); + $boxTitle = (string)trans('firefly.spent'); $cache = new CacheProperties; $cache->addProperty($start); @@ -96,21 +96,21 @@ class BoxController extends Controller // spent in this period, in budgets, for default currency. // also calculate spent per day. $spent = $opsRepository->sumExpenses($start, $end, null, null, $currency); - $spentAmount = $spent[(int) $currency->id]['sum'] ?? '0'; + $spentAmount = $spent[(int)$currency->id]['sum'] ?? '0'; - $days = $today->between($start, $end) ? $today->diffInDays($start) + 1 : $end->diffInDays($start) + 1; - $spentPerDay = bcdiv($spentAmount, (string) $days); + $days = $today->between($start, $end) ? $today->diffInDays($start) + 1 : $end->diffInDays($start) + 1; + $spentPerDay = bcdiv($spentAmount, (string)$days); if ($availableBudgets->count() > 0) { $display = 0; // assume user overspent - $boxTitle = (string) trans('firefly.overspent'); - $totalAvailableSum = (string) $availableBudgets->sum('amount'); + $boxTitle = (string)trans('firefly.overspent'); + $totalAvailableSum = (string)$availableBudgets->sum('amount'); // calculate with available budget. $leftToSpendAmount = bcadd($totalAvailableSum, $spentAmount); if (1 === bccomp($leftToSpendAmount, '0')) { - $boxTitle = (string) trans('firefly.left_to_spend'); + $boxTitle = (string)trans('firefly.left_to_spend'); $days = $today->diffInDays($end) + 1; $display = 1; // not overspent - $leftPerDayAmount = bcdiv($leftToSpendAmount, (string) $days); + $leftPerDayAmount = bcdiv($leftToSpendAmount, (string)$days); } } @@ -164,7 +164,7 @@ class BoxController extends Controller $set = $collector->getExtractedJournals(); /** @var array $journal */ foreach ($set as $journal) { - $currencyId = (int) $journal['currency_id']; + $currencyId = (int)$journal['currency_id']; $amount = $journal['amount'] ?? '0'; $incomes[$currencyId] = $incomes[$currencyId] ?? '0'; $incomes[$currencyId] = bcadd($incomes[$currencyId], app('steam')->positive($amount)); @@ -180,7 +180,7 @@ class BoxController extends Controller $set = $collector->getExtractedJournals(); /** @var array $journal */ foreach ($set as $journal) { - $currencyId = (int) $journal['currency_id']; + $currencyId = (int)$journal['currency_id']; $expenses[$currencyId] = $expenses[$currencyId] ?? '0'; $expenses[$currencyId] = bcadd($expenses[$currencyId], $journal['amount'] ?? '0'); $sums[$currencyId] = $sums[$currencyId] ?? '0'; diff --git a/app/Http/Controllers/Json/BudgetController.php b/app/Http/Controllers/Json/BudgetController.php index 93aade6c00..ff5bbc7814 100644 --- a/app/Http/Controllers/Json/BudgetController.php +++ b/app/Http/Controllers/Json/BudgetController.php @@ -42,6 +42,7 @@ use Illuminate\Http\JsonResponse; class BudgetController extends Controller { use DateCalculation; + /** @var AvailableBudgetRepositoryInterface */ private $abRepository; /** @var BudgetLimitRepositoryInterface */ @@ -64,7 +65,7 @@ class BudgetController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.budgets')); + app('view')->share('title', (string)trans('firefly.budgets')); app('view')->share('mainTitleIcon', 'fa-pie-chart'); $this->repository = app(BudgetRepositoryInterface::class); $this->opsRepository = app(OperationsRepositoryInterface::class); diff --git a/app/Http/Controllers/Json/IntroController.php b/app/Http/Controllers/Json/IntroController.php index f0c92f55bd..1f28f3a82a 100644 --- a/app/Http/Controllers/Json/IntroController.php +++ b/app/Http/Controllers/Json/IntroController.php @@ -115,7 +115,7 @@ class IntroController app('preferences')->set($key, false); app('preferences')->mark(); - return response()->json(['message' => (string) trans('firefly.intro_boxes_after_refresh')]); + return response()->json(['message' => (string)trans('firefly.intro_boxes_after_refresh')]); } /** diff --git a/app/Http/Controllers/Json/ReconcileController.php b/app/Http/Controllers/Json/ReconcileController.php index 948b5dc720..fdcea33607 100644 --- a/app/Http/Controllers/Json/ReconcileController.php +++ b/app/Http/Controllers/Json/ReconcileController.php @@ -64,7 +64,7 @@ class ReconcileController extends Controller $this->middleware( function ($request, $next) { app('view')->share('mainTitleIcon', 'fa-credit-card'); - app('view')->share('title', (string) trans('firefly.accounts')); + app('view')->share('title', (string)trans('firefly.accounts')); $this->repository = app(JournalRepositoryInterface::class); $this->accountRepos = app(AccountRepositoryInterface::class); $this->currencyRepos = app(CurrencyRepositoryInterface::class); @@ -172,61 +172,6 @@ class ReconcileController extends Controller return response()->json($return); } - - /** - * Returns a list of transactions in a modal. - * - * @param Account $account - * @param Carbon $start - * @param Carbon $end - * - * @return mixed - * - */ - public function transactions(Account $account, Carbon $start, Carbon $end) - { - if ($end->lt($start)) { - [$end, $start] = [$start, $end]; - } - $startDate = clone $start; - $startDate->subDay(); - - $currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency(); - $startBalance = round((float) app('steam')->balance($account, $startDate), $currency->decimal_places); - $endBalance = round((float) app('steam')->balance($account, $end), $currency->decimal_places); - - // get the transactions - $selectionStart = clone $start; - $selectionStart->subDays(3); - $selectionEnd = clone $end; - $selectionEnd->addDays(3); - - // grab transactions: - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - - $collector->setAccounts(new Collection([$account])) - ->setRange($selectionStart, $selectionEnd) - ->withBudgetInformation()->withCategoryInformation()->withAccountInformation(); - $array = $collector->getExtractedJournals(); - $journals = $this->processTransactions($account, $array); - - try { - $html = prefixView( - 'accounts.reconcile.transactions', - compact('account', 'journals', 'currency', 'start', 'end', 'selectionStart', 'selectionEnd') - )->render(); - // @codeCoverageIgnoreStart - } catch (Throwable $e) { - Log::debug(sprintf('Could not render: %s', $e->getMessage())); - $html = sprintf('Could not render accounts.reconcile.transactions: %s', $e->getMessage()); - } - - // @codeCoverageIgnoreEnd - - return response()->json(['html' => $html, 'startBalance' => $startBalance, 'endBalance' => $endBalance]); - } - /** * @param Account $account * @param TransactionCurrency $currency @@ -267,11 +212,66 @@ class ReconcileController extends Controller return $amount; } + /** + * Returns a list of transactions in a modal. + * + * @param Account $account + * @param Carbon $start + * @param Carbon $end + * + * @return mixed + * + */ + public function transactions(Account $account, Carbon $start, Carbon $end) + { + if ($end->lt($start)) { + [$end, $start] = [$start, $end]; + } + $startDate = clone $start; + $startDate->subDay(); + + $currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency(); + $startBalance = round((float)app('steam')->balance($account, $startDate), $currency->decimal_places); + $endBalance = round((float)app('steam')->balance($account, $end), $currency->decimal_places); + + // get the transactions + $selectionStart = clone $start; + $selectionStart->subDays(3); + $selectionEnd = clone $end; + $selectionEnd->addDays(3); + + // grab transactions: + /** @var GroupCollectorInterface $collector */ + $collector = app(GroupCollectorInterface::class); + + $collector->setAccounts(new Collection([$account])) + ->setRange($selectionStart, $selectionEnd) + ->withBudgetInformation()->withCategoryInformation()->withAccountInformation(); + $array = $collector->getExtractedJournals(); + $journals = $this->processTransactions($account, $array); + + try { + $html = prefixView( + 'accounts.reconcile.transactions', + compact('account', 'journals', 'currency', 'start', 'end', 'selectionStart', 'selectionEnd') + )->render(); + // @codeCoverageIgnoreStart + } catch (Throwable $e) { + Log::debug(sprintf('Could not render: %s', $e->getMessage())); + $html = sprintf('Could not render accounts.reconcile.transactions: %s', $e->getMessage()); + } + + // @codeCoverageIgnoreEnd + + return response()->json(['html' => $html, 'startBalance' => $startBalance, 'endBalance' => $endBalance]); + } + /** * "fix" amounts to make it easier on the reconciliation overview: * * @param Account $account * @param array $array + * * @return array */ private function processTransactions(Account $account, array $array): array @@ -305,6 +305,7 @@ class ReconcileController extends Controller $journals[] = $journal; } + return $journals; } } diff --git a/app/Http/Controllers/Json/RecurrenceController.php b/app/Http/Controllers/Json/RecurrenceController.php index 451c2a7169..3c647a4682 100644 --- a/app/Http/Controllers/Json/RecurrenceController.php +++ b/app/Http/Controllers/Json/RecurrenceController.php @@ -63,9 +63,9 @@ class RecurrenceController extends Controller * * @param Request $request * - * @throws FireflyException * @return JsonResponse * + * @throws FireflyException */ public function events(Request $request): JsonResponse { @@ -73,10 +73,10 @@ class RecurrenceController extends Controller $start = Carbon::createFromFormat('Y-m-d', $request->get('start')); $end = Carbon::createFromFormat('Y-m-d', $request->get('end')); $firstDate = Carbon::createFromFormat('Y-m-d', $request->get('first_date')); - $endDate = '' !== (string) $request->get('end_date') ? Carbon::createFromFormat('Y-m-d', $request->get('end_date')) : null; - $endsAt = (string) $request->get('ends'); + $endDate = '' !== (string)$request->get('end_date') ? Carbon::createFromFormat('Y-m-d', $request->get('end_date')) : null; + $endsAt = (string)$request->get('ends'); $repetitionType = explode(',', $request->get('type'))[0]; - $repetitions = (int) $request->get('reps'); + $repetitions = (int)$request->get('reps'); $repetitionMoment = ''; $start->startOfDay(); @@ -100,8 +100,8 @@ class RecurrenceController extends Controller $repetition = new RecurrenceRepetition; $repetition->repetition_type = $repetitionType; $repetition->repetition_moment = $repetitionMoment; - $repetition->repetition_skip = (int) $request->get('skip'); - $repetition->weekend = (int) $request->get('weekend'); + $repetition->repetition_skip = (int)$request->get('skip'); + $repetition->weekend = (int)$request->get('weekend'); $actualEnd = clone $end; switch ($endsAt) { @@ -151,30 +151,30 @@ class RecurrenceController extends Controller $string = $request->get('date') ?? date('Y-m-d'); $today = Carbon::now()->startOfDay(); $date = Carbon::createFromFormat('Y-m-d', $string)->startOfDay(); - $preSelected = (string) $request->get('pre_select'); - $locale = app('steam')->getLocale(); + $preSelected = (string)$request->get('pre_select'); + $locale = app('steam')->getLocale(); Log::debug(sprintf('date = %s, today = %s. date > today? %s', $date->toAtomString(), $today->toAtomString(), var_export($date > $today, true))); - Log::debug(sprintf('past = true? %s', var_export('true' === (string) $request->get('past'), true))); + Log::debug(sprintf('past = true? %s', var_export('true' === (string)$request->get('past'), true))); $result = []; - if ($date > $today || 'true' === (string) $request->get('past')) { + if ($date > $today || 'true' === (string)$request->get('past')) { Log::debug('Will fill dropdown.'); $weekly = sprintf('weekly,%s', $date->dayOfWeekIso); $monthly = sprintf('monthly,%s', $date->day); - $dayOfWeek = (string) trans(sprintf('config.dow_%s', $date->dayOfWeekIso)); + $dayOfWeek = (string)trans(sprintf('config.dow_%s', $date->dayOfWeekIso)); $ndom = sprintf('ndom,%s,%s', $date->weekOfMonth, $date->dayOfWeekIso); $yearly = sprintf('yearly,%s', $date->format('Y-m-d')); - $yearlyDate = $date->formatLocalized((string) trans('config.month_and_day_no_year', [], $locale)); + $yearlyDate = $date->formatLocalized((string)trans('config.month_and_day_no_year', [], $locale)); $result = [ - 'daily' => ['label' => (string) trans('firefly.recurring_daily'), 'selected' => 0 === strpos($preSelected, 'daily')], - $weekly => ['label' => (string) trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek]), + 'daily' => ['label' => (string)trans('firefly.recurring_daily'), 'selected' => 0 === strpos($preSelected, 'daily')], + $weekly => ['label' => (string)trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek]), 'selected' => 0 === strpos($preSelected, 'weekly')], - $monthly => ['label' => (string) trans('firefly.recurring_monthly', ['dayOfMonth' => $date->day]), + $monthly => ['label' => (string)trans('firefly.recurring_monthly', ['dayOfMonth' => $date->day]), 'selected' => 0 === strpos($preSelected, 'monthly')], - $ndom => ['label' => (string) trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $date->weekOfMonth]), + $ndom => ['label' => (string)trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $date->weekOfMonth]), 'selected' => 0 === strpos($preSelected, 'ndom')], - $yearly => ['label' => (string) trans('firefly.recurring_yearly', ['date' => $yearlyDate]), + $yearly => ['label' => (string)trans('firefly.recurring_yearly', ['date' => $yearlyDate]), 'selected' => 0 === strpos($preSelected, 'yearly')], ]; } diff --git a/app/Http/Controllers/Json/RuleController.php b/app/Http/Controllers/Json/RuleController.php index 4d24d91fca..5a070e7b29 100644 --- a/app/Http/Controllers/Json/RuleController.php +++ b/app/Http/Controllers/Json/RuleController.php @@ -44,11 +44,11 @@ class RuleController extends Controller */ public function action(Request $request): JsonResponse { - $count = (int) $request->get('count') > 0 ? (int) $request->get('count') : 1; + $count = (int)$request->get('count') > 0 ? (int)$request->get('count') : 1; $keys = array_keys(config('firefly.rule-actions')); $actions = []; foreach ($keys as $key) { - $actions[$key] = (string) trans('firefly.rule_action_' . $key . '_choice'); + $actions[$key] = (string)trans('firefly.rule_action_' . $key . '_choice'); } try { $view = prefixView('rules.partials.action', compact('actions', 'count'))->render(); @@ -72,13 +72,13 @@ class RuleController extends Controller */ public function trigger(Request $request): JsonResponse { - $count = (int) $request->get('count') > 0 ? (int) $request->get('count') : 1; + $count = (int)$request->get('count') > 0 ? (int)$request->get('count') : 1; $operators = config('firefly.search.operators'); $triggers = []; foreach ($operators as $key => $operator) { if ('user_action' !== $key && false === $operator['alias']) { - $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); + $triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key)); } } asort($triggers); diff --git a/app/Http/Controllers/Rule/CreateController.php b/app/Http/Controllers/Rule/CreateController.php index 880bcc7838..d993936df4 100644 --- a/app/Http/Controllers/Rule/CreateController.php +++ b/app/Http/Controllers/Rule/CreateController.php @@ -59,7 +59,7 @@ class CreateController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.rules')); + app('view')->share('title', (string)trans('firefly.rules')); app('view')->share('mainTitleIcon', 'fa-random'); $this->ruleRepos = app(RuleRepositoryInterface::class); @@ -88,7 +88,7 @@ class CreateController extends Controller $oldActions = []; // build triggers from query, if present. - $query = (string) $request->get('from_query'); + $query = (string)$request->get('from_query'); if ('' !== $query) { $search = app(SearchInterface::class); $search->parseQuery($query); @@ -112,9 +112,9 @@ class CreateController extends Controller $subTitleIcon = 'fa-clone'; // title depends on whether or not there is a rule group: - $subTitle = (string) trans('firefly.make_new_rule_no_group'); + $subTitle = (string)trans('firefly.make_new_rule_no_group'); if (null !== $ruleGroup) { - $subTitle = (string) trans('firefly.make_new_rule', ['title' => $ruleGroup->title]); + $subTitle = (string)trans('firefly.make_new_rule', ['title' => $ruleGroup->title]); } // flash old data @@ -142,14 +142,14 @@ class CreateController extends Controller */ public function createFromBill(Request $request, Bill $bill) { - $request->session()->flash('info', (string) trans('firefly.instructions_rule_from_bill', ['name' => e($bill->name)])); + $request->session()->flash('info', (string)trans('firefly.instructions_rule_from_bill', ['name' => e($bill->name)])); $this->createDefaultRuleGroup(); $this->createDefaultRule(); $preFilled = [ 'strict' => true, - 'title' => (string) trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]), - 'description' => (string) trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]), + 'title' => (string)trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]), + 'description' => (string)trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]), ]; // make triggers and actions from the bill itself. @@ -169,7 +169,7 @@ class CreateController extends Controller $subTitleIcon = 'fa-clone'; // title depends on whether or not there is a rule group: - $subTitle = (string) trans('firefly.make_new_rule_no_group'); + $subTitle = (string)trans('firefly.make_new_rule_no_group'); // flash old data $request->session()->flash('preFilled', $preFilled); @@ -192,10 +192,10 @@ class CreateController extends Controller */ public function createFromJournal(Request $request, TransactionJournal $journal) { - $request->session()->flash('info', (string) trans('firefly.instructions_rule_from_journal', ['name' => e($journal->name)])); + $request->session()->flash('info', (string)trans('firefly.instructions_rule_from_journal', ['name' => e($journal->name)])); $subTitleIcon = 'fa-clone'; - $subTitle = (string) trans('firefly.make_new_rule_no_group'); + $subTitle = (string)trans('firefly.make_new_rule_no_group'); // get triggers and actions for journal. $oldTriggers = $this->getTriggersForJournal($journal); @@ -207,8 +207,8 @@ class CreateController extends Controller // collect pre-filled information: $preFilled = [ 'strict' => true, - 'title' => (string) trans('firefly.new_rule_for_journal_title', ['description' => $journal->description]), - 'description' => (string) trans('firefly.new_rule_for_journal_description', ['description' => $journal->description]), + 'title' => (string)trans('firefly.new_rule_for_journal_title', ['description' => $journal->description]), + 'description' => (string)trans('firefly.new_rule_for_journal_description', ['description' => $journal->description]), ]; // restore actions and triggers from old input: @@ -262,22 +262,22 @@ class CreateController extends Controller { $data = $request->getRuleData(); $rule = $this->ruleRepos->store($data); - session()->flash('success', (string) trans('firefly.stored_new_rule', ['title' => $rule->title])); + session()->flash('success', (string)trans('firefly.stored_new_rule', ['title' => $rule->title])); app('preferences')->mark(); // redirect to show bill. - if ('true' === $request->get('return_to_bill') && (int) $request->get('bill_id') > 0) { - return redirect(route('bills.show', [(int) $request->get('bill_id')])); // @codeCoverageIgnore + if ('true' === $request->get('return_to_bill') && (int)$request->get('bill_id') > 0) { + return redirect(route('bills.show', [(int)$request->get('bill_id')])); // @codeCoverageIgnore } // redirect to new bill creation. - if ((int) $request->get('bill_id') > 0) { + if ((int)$request->get('bill_id') > 0) { return redirect($this->getPreviousUri('bills.create.uri')); // @codeCoverageIgnore } $redirect = redirect($this->getPreviousUri('rules.create.uri')); - if (1 === (int) $request->get('create_another')) { + if (1 === (int)$request->get('create_another')) { // @codeCoverageIgnoreStart session()->put('rules.create.fromStore', true); $redirect = redirect(route('rules.create', [$data['rule_group_id']]))->withInput(); diff --git a/app/Http/Controllers/Rule/DeleteController.php b/app/Http/Controllers/Rule/DeleteController.php index a80ec188a1..c2b5e6f8b0 100644 --- a/app/Http/Controllers/Rule/DeleteController.php +++ b/app/Http/Controllers/Rule/DeleteController.php @@ -50,7 +50,7 @@ class DeleteController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.rules')); + app('view')->share('title', (string)trans('firefly.rules')); app('view')->share('mainTitleIcon', 'fa-random'); $this->ruleRepos = app(RuleRepositoryInterface::class); @@ -69,7 +69,7 @@ class DeleteController extends Controller */ public function delete(Rule $rule) { - $subTitle = (string) trans('firefly.delete_rule', ['title' => $rule->title]); + $subTitle = (string)trans('firefly.delete_rule', ['title' => $rule->title]); // put previous url in session $this->rememberPreviousUri('rules.delete.uri'); @@ -89,7 +89,7 @@ class DeleteController extends Controller $title = $rule->title; $this->ruleRepos->destroy($rule); - session()->flash('success', (string) trans('firefly.deleted_rule', ['title' => $title])); + session()->flash('success', (string)trans('firefly.deleted_rule', ['title' => $title])); app('preferences')->mark(); return redirect($this->getPreviousUri('rules.delete.uri')); diff --git a/app/Http/Controllers/Rule/EditController.php b/app/Http/Controllers/Rule/EditController.php index bd3ad98ad2..873a040549 100644 --- a/app/Http/Controllers/Rule/EditController.php +++ b/app/Http/Controllers/Rule/EditController.php @@ -37,8 +37,8 @@ use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Redirector; use Illuminate\View\View; -use Throwable; use Log; +use Throwable; /** * Class EditController @@ -60,7 +60,7 @@ class EditController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.rules')); + app('view')->share('title', (string)trans('firefly.rules')); app('view')->share('mainTitleIcon', 'fa-random'); $this->ruleRepos = app(RuleRepositoryInterface::class); @@ -86,7 +86,7 @@ class EditController extends Controller $oldTriggers = []; // build triggers from query, if present. - $query = (string) $request->get('from_query'); + $query = (string)$request->get('from_query'); if ('' !== $query) { $search = app(SearchInterface::class); $search->parseQuery($query); @@ -102,8 +102,8 @@ class EditController extends Controller // has old input? if (count($request->old()) > 0) { - $oldTriggers = $this->getPreviousTriggers($request); - $oldActions = $this->getPreviousActions($request); + $oldTriggers = $this->getPreviousTriggers($request); + $oldActions = $this->getPreviousActions($request); } $triggerCount = count($oldTriggers); $actionCount = count($oldActions); @@ -118,15 +118,15 @@ class EditController extends Controller $hasOldInput = null !== $request->old('_token'); $preFilled = [ - 'active' => $hasOldInput ? (bool) $request->old('active') : $rule->active, - 'stop_processing' => $hasOldInput ? (bool) $request->old('stop_processing') : $rule->stop_processing, - 'strict' => $hasOldInput ? (bool) $request->old('strict') : $rule->strict, + 'active' => $hasOldInput ? (bool)$request->old('active') : $rule->active, + 'stop_processing' => $hasOldInput ? (bool)$request->old('stop_processing') : $rule->stop_processing, + 'strict' => $hasOldInput ? (bool)$request->old('strict') : $rule->strict, ]; // get rule trigger for update / store-journal: $primaryTrigger = $this->ruleRepos->getPrimaryTrigger($rule); - $subTitle = (string) trans('firefly.edit_rule', ['title' => $rule->title]); + $subTitle = (string)trans('firefly.edit_rule', ['title' => $rule->title]); // put previous url in session if not redirect from store (not "return_to_edit"). if (true !== session('rules.edit.fromUpdate')) { @@ -139,35 +139,9 @@ class EditController extends Controller return prefixView('rules.rule.edit', compact('rule', 'subTitle', 'primaryTrigger', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount')); } - /** - * Update the rule. - * - * @param RuleFormRequest $request - * @param Rule $rule - * - * @return RedirectResponse|Redirector - */ - public function update(RuleFormRequest $request, Rule $rule) - { - $data = $request->getRuleData(); - $this->ruleRepos->update($rule, $data); - - session()->flash('success', (string) trans('firefly.updated_rule', ['title' => $rule->title])); - app('preferences')->mark(); - $redirect = redirect($this->getPreviousUri('rules.edit.uri')); - if (1 === (int) $request->get('return_to_edit')) { - // @codeCoverageIgnoreStart - session()->put('rules.edit.fromUpdate', true); - - $redirect = redirect(route('rules.edit', [$rule->id]))->withInput(['return_to_edit' => 1]); - // @codeCoverageIgnoreEnd - } - - return $redirect; - } - /** * @param array $submittedOperators + * * @return array */ private function parseFromOperators(array $submittedOperators): array @@ -179,7 +153,7 @@ class EditController extends Controller foreach ($operators as $key => $operator) { if ('user_action' !== $key && false === $operator['alias']) { - $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); + $triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key)); } } asort($triggers); @@ -206,4 +180,31 @@ class EditController extends Controller return $renderedEntries; } + + /** + * Update the rule. + * + * @param RuleFormRequest $request + * @param Rule $rule + * + * @return RedirectResponse|Redirector + */ + public function update(RuleFormRequest $request, Rule $rule) + { + $data = $request->getRuleData(); + $this->ruleRepos->update($rule, $data); + + session()->flash('success', (string)trans('firefly.updated_rule', ['title' => $rule->title])); + app('preferences')->mark(); + $redirect = redirect($this->getPreviousUri('rules.edit.uri')); + if (1 === (int)$request->get('return_to_edit')) { + // @codeCoverageIgnoreStart + session()->put('rules.edit.fromUpdate', true); + + $redirect = redirect(route('rules.edit', [$rule->id]))->withInput(['return_to_edit' => 1]); + // @codeCoverageIgnoreEnd + } + + return $redirect; + } } diff --git a/app/Http/Controllers/Rule/IndexController.php b/app/Http/Controllers/Rule/IndexController.php index 3c0229fa5a..7731fea3f6 100644 --- a/app/Http/Controllers/Rule/IndexController.php +++ b/app/Http/Controllers/Rule/IndexController.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Rule; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Rule; use FireflyIII\Models\RuleGroup; @@ -55,7 +56,7 @@ class IndexController extends Controller parent::__construct(); $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.rules')); + app('view')->share('title', (string)trans('firefly.rules')); app('view')->share('mainTitleIcon', 'fa-random'); $this->ruleGroupRepos = app(RuleGroupRepositoryInterface::class); $this->ruleRepos = app(RuleRepositoryInterface::class); @@ -82,10 +83,26 @@ class IndexController extends Controller return prefixView('rules.index', compact('ruleGroups')); } + /** + * @param Request $request + * @param Rule $rule + * @param RuleGroup $ruleGroup + * + * @return JsonResponse + */ + public function moveRule(Request $request, Rule $rule, RuleGroup $ruleGroup): JsonResponse + { + $order = (int)$request->get('order'); + $this->ruleRepos->moveRule($rule, $ruleGroup, (int)$order); + + return response()->json([]); + } + /** * @param Rule $rule + * * @return RedirectResponse - * @throws \FireflyIII\Exceptions\FireflyException + * @throws FireflyException */ public function search(Rule $rule): RedirectResponse { @@ -96,19 +113,4 @@ class IndexController extends Controller return redirect($route); } - /** - * @param Request $request - * @param Rule $rule - * @param RuleGroup $ruleGroup - * - * @return JsonResponse - */ - public function moveRule(Request $request, Rule $rule, RuleGroup $ruleGroup): JsonResponse - { - $order = (int) $request->get('order'); - $this->ruleRepos->moveRule($rule, $ruleGroup, (int) $order); - - return response()->json([]); - } - } diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index 87e9e2cc0c..d6bbca217c 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -62,10 +62,10 @@ class Authenticate * @param Closure $next * @param string[] ...$guards * - * @throws AuthenticationException - * @throws FireflyException * @return mixed * + * @throws FireflyException + * @throws AuthenticationException */ public function handle($request, Closure $next, ...$guards) { @@ -81,9 +81,9 @@ class Authenticate * @param $request * @param array $guards * - * @throws AuthenticationException - * @throws FireflyException * @return mixed + * @throws FireflyException + * @throws AuthenticationException */ protected function authenticate($request, array $guards) { @@ -97,10 +97,10 @@ class Authenticate // do an extra check on user object. /** @noinspection PhpUndefinedMethodInspection */ $user = $this->auth->authenticate(); - if (1 === (int) $user->blocked) { - $message = (string) trans('firefly.block_account_logout'); + if (1 === (int)$user->blocked) { + $message = (string)trans('firefly.block_account_logout'); if ('email_changed' === $user->blocked_code) { - $message = (string) trans('firefly.email_changed_logout'); + $message = (string)trans('firefly.email_changed_logout'); } app('session')->flash('logoutMessage', $message); /** @noinspection PhpUndefinedMethodInspection */ diff --git a/app/Http/Middleware/InstallationId.php b/app/Http/Middleware/InstallationId.php index cbcc0e1368..20a8177349 100644 --- a/app/Http/Middleware/InstallationId.php +++ b/app/Http/Middleware/InstallationId.php @@ -27,6 +27,7 @@ namespace FireflyIII\Http\Middleware; use Closure; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Support\System\GeneratesInstallationId; +use Illuminate\Http\Request; /** * @@ -39,7 +40,7 @@ class InstallationId /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request + * @param Request $request * @param Closure $next * * @return mixed @@ -51,7 +52,6 @@ class InstallationId { - $this->generateInstallationId(); return $next($request); diff --git a/app/Http/Middleware/Installer.php b/app/Http/Middleware/Installer.php index 613af9d41e..ea0b291e23 100644 --- a/app/Http/Middleware/Installer.php +++ b/app/Http/Middleware/Installer.php @@ -44,12 +44,12 @@ class Installer * Handle an incoming request. * * @param Request $request - * @param Closure $next - * - * @throws FireflyException + * @param Closure $next * * @return mixed * + * @throws FireflyException + * */ public function handle($request, Closure $next) { @@ -81,35 +81,11 @@ class Installer return $next($request); } - /** - * Is access denied error. - * - * @param string $message - * - * @return bool - */ - protected function isAccessDenied(string $message): bool - { - return false !== stripos($message, 'Access denied'); - } - - /** - * Is no tables exist error. - * - * @param string $message - * - * @return bool - */ - protected function noTablesExist(string $message): bool - { - return false !== stripos($message, 'Base table or view not found'); - } - /** * Check if the tables are created and accounted for. * - * @throws FireflyException * @return bool + * @throws FireflyException */ private function hasNoTables(): bool { @@ -136,6 +112,30 @@ class Installer return false; } + /** + * Is access denied error. + * + * @param string $message + * + * @return bool + */ + protected function isAccessDenied(string $message): bool + { + return false !== stripos($message, 'Access denied'); + } + + /** + * Is no tables exist error. + * + * @param string $message + * + * @return bool + */ + protected function noTablesExist(string $message): bool + { + return false !== stripos($message, 'Base table or view not found'); + } + /** * Check if the "db_version" variable is correct. * @@ -144,8 +144,8 @@ class Installer private function oldDBVersion(): bool { // older version in config than database? - $configVersion = (int) config('firefly.db_version'); - $dbVersion = (int) app('fireflyconfig')->getFresh('db_version', 1)->data; + $configVersion = (int)config('firefly.db_version'); + $dbVersion = (int)app('fireflyconfig')->getFresh('db_version', 1)->data; if ($configVersion > $dbVersion) { Log::warning( sprintf( @@ -170,8 +170,8 @@ class Installer private function oldVersion(): bool { // version compare thing. - $configVersion = (string) config('firefly.version'); - $dbVersion = (string) app('fireflyconfig')->getFresh('ff3_version', '1.0')->data; + $configVersion = (string)config('firefly.version'); + $dbVersion = (string)app('fireflyconfig')->getFresh('ff3_version', '1.0')->data; if (1 === version_compare($configVersion, $dbVersion)) { Log::warning( sprintf( diff --git a/app/Http/Middleware/InterestingMessage.php b/app/Http/Middleware/InterestingMessage.php index fd49d04d21..f6fafd89c9 100644 --- a/app/Http/Middleware/InterestingMessage.php +++ b/app/Http/Middleware/InterestingMessage.php @@ -58,6 +58,15 @@ class InterestingMessage return $next($request); } + /** + * @return bool + */ + private function testing(): bool + { + // ignore middleware in test environment. + return 'testing' === config('app.env') || !auth()->check(); + } + /** * @param Request $request * @@ -84,7 +93,7 @@ class InterestingMessage // send message about newly created transaction group. /** @var TransactionGroup $group */ - $group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int) $transactionGroupId); + $group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int)$transactionGroupId); if (null === $group) { return; @@ -100,21 +109,12 @@ class InterestingMessage $title = $count > 1 ? $group->title : $journal->description; if ('created' === $message) { session()->flash('success_uri', route('transactions.show', [$transactionGroupId])); - session()->flash('success', (string) trans('firefly.stored_journal', ['description' => $title])); + session()->flash('success', (string)trans('firefly.stored_journal', ['description' => $title])); } if ('updated' === $message) { $type = strtolower($journal->transactionType->type); session()->flash('success_uri', route('transactions.show', [$transactionGroupId])); - session()->flash('success', (string) trans(sprintf('firefly.updated_%s', $type), ['description' => $title])); + session()->flash('success', (string)trans(sprintf('firefly.updated_%s', $type), ['description' => $title])); } } - - /** - * @return bool - */ - private function testing(): bool - { - // ignore middleware in test environment. - return 'testing' === config('app.env') || !auth()->check(); - } } diff --git a/app/Http/Middleware/IsDemoUser.php b/app/Http/Middleware/IsDemoUser.php index 8d419b4bc0..1ee13d555b 100644 --- a/app/Http/Middleware/IsDemoUser.php +++ b/app/Http/Middleware/IsDemoUser.php @@ -53,7 +53,7 @@ class IsDemoUser $repository = app(UserRepositoryInterface::class); if ($repository->hasRole($user, 'demo')) { Log::info('User is a demo user.'); - $request->session()->flash('info', (string) trans('firefly.not_available_demo_user')); + $request->session()->flash('info', (string)trans('firefly.not_available_demo_user')); $current = $request->url(); $previous = $request->session()->previousUrl(); if ($current !== $previous) { diff --git a/app/Http/Middleware/Range.php b/app/Http/Middleware/Range.php index d847587b2e..a58d45405c 100644 --- a/app/Http/Middleware/Range.php +++ b/app/Http/Middleware/Range.php @@ -36,6 +36,7 @@ use Log; class Range { use RequestInformation; + /** * Handle an incoming request. * @@ -61,51 +62,6 @@ class Range return $next($request); } - /** - * Configure the list length. - */ - private function configureList(): void - { - $pref = app('preferences')->get('list-length', config('firefly.list_length', 10))->data; - app('view')->share('listLength', $pref); - } - - /** - * Configure the user's view. - */ - private function configureView(): void - { - // get locale preference: - $language = app('steam')->getLanguage(); - $locale = app('steam')->getLocale(); - App::setLocale($language); - Carbon::setLocale(substr($locale, 0, 2)); - - $localeArray = app('steam')->getLocaleArray($locale); - - setlocale(LC_TIME, $localeArray); - $moneyResult = setlocale(LC_MONETARY, $localeArray); - - // send error to view if could not set money format - if (false === $moneyResult) { - Log::error('Could not set locale. The following array doesnt work: ', $localeArray); - app('view')->share('invalidMonetaryLocale', true); // @codeCoverageIgnore - } - - // save some formats: - $monthAndDayFormat = (string) trans('config.month_and_day', [], $locale); - $dateTimeFormat = (string) trans('config.date_time', [], $locale); - $defaultCurrency = app('amount')->getDefaultCurrency(); - - // also format for moment JS: - $madMomentJS = (string) trans('config.month_and_day_moment_js', [], $locale); - - app('view')->share('madMomentJS', $madMomentJS); - app('view')->share('monthAndDayFormat', $monthAndDayFormat); - app('view')->share('dateTimeFormat', $dateTimeFormat); - app('view')->share('defaultCurrency', $defaultCurrency); - } - /** * Set the range for the current view. */ @@ -133,4 +89,49 @@ class Range app('session')->put('first', $first); } } + + /** + * Configure the user's view. + */ + private function configureView(): void + { + // get locale preference: + $language = app('steam')->getLanguage(); + $locale = app('steam')->getLocale(); + App::setLocale($language); + Carbon::setLocale(substr($locale, 0, 2)); + + $localeArray = app('steam')->getLocaleArray($locale); + + setlocale(LC_TIME, $localeArray); + $moneyResult = setlocale(LC_MONETARY, $localeArray); + + // send error to view if could not set money format + if (false === $moneyResult) { + Log::error('Could not set locale. The following array doesnt work: ', $localeArray); + app('view')->share('invalidMonetaryLocale', true); // @codeCoverageIgnore + } + + // save some formats: + $monthAndDayFormat = (string)trans('config.month_and_day', [], $locale); + $dateTimeFormat = (string)trans('config.date_time', [], $locale); + $defaultCurrency = app('amount')->getDefaultCurrency(); + + // also format for moment JS: + $madMomentJS = (string)trans('config.month_and_day_moment_js', [], $locale); + + app('view')->share('madMomentJS', $madMomentJS); + app('view')->share('monthAndDayFormat', $monthAndDayFormat); + app('view')->share('dateTimeFormat', $dateTimeFormat); + app('view')->share('defaultCurrency', $defaultCurrency); + } + + /** + * Configure the list length. + */ + private function configureList(): void + { + $pref = app('preferences')->get('list-length', config('firefly.list_length', 10))->data; + app('view')->share('listLength', $pref); + } } diff --git a/app/Http/Middleware/SecureHeaders.php b/app/Http/Middleware/SecureHeaders.php index f4725c2abe..f32c81c336 100644 --- a/app/Http/Middleware/SecureHeaders.php +++ b/app/Http/Middleware/SecureHeaders.php @@ -39,8 +39,8 @@ class SecureHeaders * @param Request $request * @param Closure $next * - * @throws Exception * @return mixed + * @throws Exception */ public function handle(Request $request, Closure $next) { @@ -48,9 +48,9 @@ class SecureHeaders $nonce = base64_encode(random_bytes(16)); app('view')->share('JS_NONCE', $nonce); - $response = $next($request); + $response = $next($request); $trackingScriptSrc = $this->getTrackingScriptSource(); - $csp = [ + $csp = [ "default-src 'none'", "object-src 'self'", sprintf("script-src 'unsafe-inline' 'nonce-%1s' %2s", $nonce, $trackingScriptSrc), @@ -58,7 +58,10 @@ class SecureHeaders "base-uri 'self'", "font-src 'self' data:", "connect-src 'self'", - sprintf("img-src 'self' data: https://a.tile.openstreetmap.org https://b.tile.openstreetmap.org https://c.tile.openstreetmap.org https://api.tiles.mapbox.com %s", $trackingScriptSrc), + sprintf( + "img-src 'self' data: https://a.tile.openstreetmap.org https://b.tile.openstreetmap.org https://c.tile.openstreetmap.org https://api.tiles.mapbox.com %s", + $trackingScriptSrc + ), "manifest-src 'self'", ]; @@ -106,8 +109,8 @@ class SecureHeaders */ private function getTrackingScriptSource(): string { - if ('' !== (string) config('firefly.tracker_site_id') && '' !== (string) config('firefly.tracker_url')) { - return (string) config('firefly.tracker_url'); + if ('' !== (string)config('firefly.tracker_site_id') && '' !== (string)config('firefly.tracker_url')) { + return (string)config('firefly.tracker_url'); } return ''; diff --git a/app/Http/Middleware/StartFireflySession.php b/app/Http/Middleware/StartFireflySession.php index 7d205367c1..88e1d10ff9 100644 --- a/app/Http/Middleware/StartFireflySession.php +++ b/app/Http/Middleware/StartFireflySession.php @@ -25,7 +25,6 @@ namespace FireflyIII\Http\Middleware; use Illuminate\Contracts\Session\Session; use Illuminate\Http\Request; use Illuminate\Session\Middleware\StartSession; -use Log; /** * Class StartFireflySession. diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php index 4be207df25..67336284f9 100644 --- a/app/Http/Middleware/TrustProxies.php +++ b/app/Http/Middleware/TrustProxies.php @@ -43,7 +43,7 @@ class TrustProxies extends Middleware */ public function __construct(Repository $config) { - $trustedProxies = (string) config('firefly.trusted_proxies'); + $trustedProxies = (string)config('firefly.trusted_proxies'); $this->proxies = explode(',', $trustedProxies); if ('**' === $trustedProxies) { $this->proxies = '**'; diff --git a/app/Http/Requests/PiggyBankStoreRequest.php b/app/Http/Requests/PiggyBankStoreRequest.php index bf5eac7c5e..a0014784a2 100644 --- a/app/Http/Requests/PiggyBankStoreRequest.php +++ b/app/Http/Requests/PiggyBankStoreRequest.php @@ -41,12 +41,12 @@ class PiggyBankStoreRequest extends FormRequest public function getPiggyBankData(): array { return [ - 'name' => $this->string('name'), - 'startdate' => $this->date('startdate'), - 'account_id' => $this->integer('account_id'), - 'targetamount' => $this->string('targetamount'), - 'targetdate' => $this->date('targetdate'), - 'notes' => $this->nlString('notes'), + 'name' => $this->string('name'), + 'startdate' => $this->date('startdate'), + 'account_id' => $this->integer('account_id'), + 'targetamount' => $this->string('targetamount'), + 'targetdate' => $this->date('targetdate'), + 'notes' => $this->nlString('notes'), 'object_group_title' => $this->string('object_group'), ]; } diff --git a/app/Http/Requests/RecurrenceFormRequest.php b/app/Http/Requests/RecurrenceFormRequest.php index 2f9a3faadd..61f07ec599 100644 --- a/app/Http/Requests/RecurrenceFormRequest.php +++ b/app/Http/Requests/RecurrenceFormRequest.php @@ -127,11 +127,11 @@ class RecurrenceFormRequest extends FormRequest // replace category name with a new category: $factory = app(CategoryFactory::class); $factory->setUser(auth()->user()); - foreach($return['transactions'] as $index => $transaction) { - $categoryName =$transaction['category_name'] ??null; - if(null !== $categoryName) { + foreach ($return['transactions'] as $index => $transaction) { + $categoryName = $transaction['category_name'] ?? null; + if (null !== $categoryName) { $category = $factory->findOrCreate(null, $categoryName); - if(null !== $category) { + if (null !== $category) { $return['transactions'][$index]['category_id'] = $category->id; } } diff --git a/app/Jobs/CreateAutoBudgetLimits.php b/app/Jobs/CreateAutoBudgetLimits.php index 4d216f0e01..e0bf7515f4 100644 --- a/app/Jobs/CreateAutoBudgetLimits.php +++ b/app/Jobs/CreateAutoBudgetLimits.php @@ -78,122 +78,6 @@ class CreateAutoBudgetLimits implements ShouldQueue } } - /** - * @param Carbon $date - */ - public function setDate(Carbon $date): void - { - $date->startOfDay(); - $this->date = $date; - } - - /** - * @param AutoBudget $autoBudget - * @param Carbon $start - * @param Carbon $end - * @param string|null $amount - */ - private function createBudgetLimit(AutoBudget $autoBudget, Carbon $start, Carbon $end, ?string $amount = null) - { - Log::debug(sprintf('No budget limit exist. Must create one for auto-budget #%d', $autoBudget->id)); - if (null !== $amount) { - Log::debug(sprintf('Amount is overruled and will be set to %s', $amount)); - } - $budgetLimit = new BudgetLimit; - $budgetLimit->budget()->associate($autoBudget->budget); - $budgetLimit->transactionCurrency()->associate($autoBudget->transactionCurrency); - $budgetLimit->start_date = $start; - $budgetLimit->end_date = $end; - $budgetLimit->amount = $amount ?? $autoBudget->amount; - $budgetLimit->period = $autoBudget->period; - $budgetLimit->generated = true; - $budgetLimit->save(); - - Log::debug(sprintf('Created budget limit #%d.', $budgetLimit->id)); - } - - /** - * @param AutoBudget $autoBudget - */ - private function createRollover(AutoBudget $autoBudget): void - { - Log::debug(sprintf('Will now manage rollover for auto budget #%d', $autoBudget->id)); - // current period: - $start = app('navigation')->startOfPeriod($this->date, $autoBudget->period); - $end = app('navigation')->endOfPeriod($start, $autoBudget->period); - - // which means previous period: - $previousStart = app('navigation')->subtractPeriod($start, $autoBudget->period); - $previousEnd = app('navigation')->endOfPeriod($previousStart, $autoBudget->period); - - Log::debug( - sprintf( - 'Current period is %s-%s, so previous period is %s-%s', - $start->format('Y-m-d'), - $end->format('Y-m-d'), - $previousStart->format('Y-m-d'), - $previousEnd->format('Y-m-d') - ) - ); - - // has budget limit in previous period? - $budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd); - - if (null === $budgetLimit) { - Log::debug('No budget limit exists in previous period, so create one.'); - // if not, create it and we're done. - $this->createBudgetLimit($autoBudget, $start, $end); - Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id)); - - return; - } - Log::debug('Budget limit exists for previous period.'); - // if has one, calculate expenses and use that as a base. - $repository = app(OperationsRepositoryInterface::class); - $repository->setUser($autoBudget->budget->user); - $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection([$autoBudget->budget]), $autoBudget->transactionCurrency); - $currencyId = (int)$autoBudget->transaction_currency_id; - $spentAmount = $spent[$currencyId]['sum'] ?? '0'; - Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); - - // previous budget limit + this period + spent - $totalAmount = bcadd(bcadd($budgetLimit->amount, $autoBudget->amount), $spentAmount); - Log::debug(sprintf('Total amount for current budget period will be %s', $totalAmount)); - - if (1 !== bccomp($totalAmount, '0')) { - Log::info(sprintf('The total amount is negative, so it will be reset to %s.', $totalAmount)); - $totalAmount = $autoBudget->amount; - } - - // create budget limit: - $this->createBudgetLimit($autoBudget, $start, $end, $totalAmount); - Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id)); - } - - /** - * @param Budget $budget - * @param Carbon $start - * @param Carbon $end - * - * @return BudgetLimit|null - */ - private function findBudgetLimit(Budget $budget, Carbon $start, Carbon $end): ?BudgetLimit - { - Log::debug( - sprintf( - 'Going to find a budget limit for budget #%d ("%s") between %s and %s', - $budget->id, - $budget->name, - $start->format('Y-m-d'), - $end->format('Y-m-d') - ) - ); - - return $budget->budgetlimits() - ->where('start_date', $start->format('Y-m-d')) - ->where('end_date', $end->format('Y-m-d'))->first(); - } - /** * @param AutoBudget $autoBudget * @@ -296,4 +180,120 @@ class CreateAutoBudgetLimits implements ShouldQueue return '01-01' === $value; } } + + /** + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * + * @return BudgetLimit|null + */ + private function findBudgetLimit(Budget $budget, Carbon $start, Carbon $end): ?BudgetLimit + { + Log::debug( + sprintf( + 'Going to find a budget limit for budget #%d ("%s") between %s and %s', + $budget->id, + $budget->name, + $start->format('Y-m-d'), + $end->format('Y-m-d') + ) + ); + + return $budget->budgetlimits() + ->where('start_date', $start->format('Y-m-d')) + ->where('end_date', $end->format('Y-m-d'))->first(); + } + + /** + * @param AutoBudget $autoBudget + * @param Carbon $start + * @param Carbon $end + * @param string|null $amount + */ + private function createBudgetLimit(AutoBudget $autoBudget, Carbon $start, Carbon $end, ?string $amount = null) + { + Log::debug(sprintf('No budget limit exist. Must create one for auto-budget #%d', $autoBudget->id)); + if (null !== $amount) { + Log::debug(sprintf('Amount is overruled and will be set to %s', $amount)); + } + $budgetLimit = new BudgetLimit; + $budgetLimit->budget()->associate($autoBudget->budget); + $budgetLimit->transactionCurrency()->associate($autoBudget->transactionCurrency); + $budgetLimit->start_date = $start; + $budgetLimit->end_date = $end; + $budgetLimit->amount = $amount ?? $autoBudget->amount; + $budgetLimit->period = $autoBudget->period; + $budgetLimit->generated = true; + $budgetLimit->save(); + + Log::debug(sprintf('Created budget limit #%d.', $budgetLimit->id)); + } + + /** + * @param AutoBudget $autoBudget + */ + private function createRollover(AutoBudget $autoBudget): void + { + Log::debug(sprintf('Will now manage rollover for auto budget #%d', $autoBudget->id)); + // current period: + $start = app('navigation')->startOfPeriod($this->date, $autoBudget->period); + $end = app('navigation')->endOfPeriod($start, $autoBudget->period); + + // which means previous period: + $previousStart = app('navigation')->subtractPeriod($start, $autoBudget->period); + $previousEnd = app('navigation')->endOfPeriod($previousStart, $autoBudget->period); + + Log::debug( + sprintf( + 'Current period is %s-%s, so previous period is %s-%s', + $start->format('Y-m-d'), + $end->format('Y-m-d'), + $previousStart->format('Y-m-d'), + $previousEnd->format('Y-m-d') + ) + ); + + // has budget limit in previous period? + $budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd); + + if (null === $budgetLimit) { + Log::debug('No budget limit exists in previous period, so create one.'); + // if not, create it and we're done. + $this->createBudgetLimit($autoBudget, $start, $end); + Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id)); + + return; + } + Log::debug('Budget limit exists for previous period.'); + // if has one, calculate expenses and use that as a base. + $repository = app(OperationsRepositoryInterface::class); + $repository->setUser($autoBudget->budget->user); + $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection([$autoBudget->budget]), $autoBudget->transactionCurrency); + $currencyId = (int)$autoBudget->transaction_currency_id; + $spentAmount = $spent[$currencyId]['sum'] ?? '0'; + Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); + + // previous budget limit + this period + spent + $totalAmount = bcadd(bcadd($budgetLimit->amount, $autoBudget->amount), $spentAmount); + Log::debug(sprintf('Total amount for current budget period will be %s', $totalAmount)); + + if (1 !== bccomp($totalAmount, '0')) { + Log::info(sprintf('The total amount is negative, so it will be reset to %s.', $totalAmount)); + $totalAmount = $autoBudget->amount; + } + + // create budget limit: + $this->createBudgetLimit($autoBudget, $start, $end, $totalAmount); + Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id)); + } + + /** + * @param Carbon $date + */ + public function setDate(Carbon $date): void + { + $date->startOfDay(); + $this->date = $date; + } } diff --git a/app/Jobs/CreateRecurringTransactions.php b/app/Jobs/CreateRecurringTransactions.php index c982deb974..e217eefe7f 100644 --- a/app/Jobs/CreateRecurringTransactions.php +++ b/app/Jobs/CreateRecurringTransactions.php @@ -129,35 +129,6 @@ class CreateRecurringTransactions implements ShouldQueue app('preferences')->mark(); } - /** - * @param Carbon $date - */ - public function setDate(Carbon $date): void - { - $date->startOfDay(); - $this->date = $date; - } - - /** - * @param bool $force - */ - public function setForce(bool $force): void - { - $this->force = $force; - } - - /** - * Return recurring transaction is active. - * - * @param Recurrence $recurrence - * - * @return bool - */ - private function active(Recurrence $recurrence): bool - { - return $recurrence->active; - } - /** * @param Collection $recurrences * @@ -172,238 +143,6 @@ class CreateRecurringTransactions implements ShouldQueue ); } - /** - * Get the start date of a recurrence. - * - * @param Recurrence $recurrence - * - * @return Carbon - */ - private function getStartDate(Recurrence $recurrence): Carbon - { - $startDate = clone $recurrence->first_date; - if (null !== $recurrence->latest_date && $recurrence->latest_date->gte($startDate)) { - $startDate = clone $recurrence->latest_date; - } - - return $startDate; - } - - /** - * Get transaction information from a recurring transaction. - * - * @param Recurrence $recurrence - * @param RecurrenceRepetition $repetition - * @param Carbon $date - * - * @return array - * - */ - private function getTransactionData(Recurrence $recurrence, RecurrenceRepetition $repetition, Carbon $date): array - { - // total transactions expected for this recurrence: - $total = $this->repository->totalTransactions($recurrence, $repetition); - $count = $this->repository->getJournalCount($recurrence) + 1; - $transactions = $recurrence->recurrenceTransactions()->get(); - $return = []; - /** @var RecurrenceTransaction $transaction */ - foreach ($transactions as $index => $transaction) { - $single = [ - 'type' => strtolower($recurrence->transactionType->type), - 'date' => $date, - 'user' => $recurrence->user_id, - 'currency_id' => (int)$transaction->transaction_currency_id, - 'currency_code' => null, - 'description' => $recurrence->recurrenceTransactions()->first()->description, - 'amount' => $transaction->amount, - 'budget_id' => $this->repository->getBudget($transaction), - 'budget_name' => null, - 'category_id' => null, - 'category_name' => $this->repository->getCategory($transaction), - 'source_id' => $transaction->source_id, - 'source_name' => null, - 'destination_id' => $transaction->destination_id, - 'destination_name' => null, - 'foreign_currency_id' => $transaction->foreign_currency_id, - 'foreign_currency_code' => null, - 'foreign_amount' => $transaction->foreign_amount, - 'reconciled' => false, - 'identifier' => $index, - 'recurrence_id' => (int)$recurrence->id, - 'order' => $index, - 'notes' => (string)trans('firefly.created_from_recurrence', ['id' => $recurrence->id, 'title' => $recurrence->title]), - 'tags' => $this->repository->getTags($transaction), - 'piggy_bank_id' => $this->repository->getPiggyBank($transaction), - 'piggy_bank_name' => null, - 'bill_id' => null, - 'bill_name' => null, - 'recurrence_total' => $total, - 'recurrence_count' => $count, - ]; - $return[] = $single; - } - - return $return; - } - - /** - * @param Recurrence $recurrence - * @param RecurrenceRepetition $repetition - * @param Carbon $date - * - * @return TransactionGroup|null - */ - private function handleOccurrence(Recurrence $recurrence, RecurrenceRepetition $repetition, Carbon $date): ?TransactionGroup - { - $date->startOfDay(); - if ($date->ne($this->date)) { - - return null; - } - Log::debug(sprintf('%s IS today (%s)', $date->format('Y-m-d'), $this->date->format('Y-m-d'))); - - // count created journals on THIS day. - $journalCount = $this->repository->getJournalCount($recurrence, $date, $date); - if ($journalCount > 0 && false === $this->force) { - Log::info(sprintf('Already created %d journal(s) for date %s', $journalCount, $date->format('Y-m-d'))); - - return null; - } - - if ($journalCount > 0 && true === $this->force) { - Log::warning(sprintf('Already created %d groups for date %s but FORCED to continue.', $journalCount, $date->format('Y-m-d'))); - } - - // create transaction array and send to factory. - $groupTitle = null; - if ($recurrence->recurrenceTransactions->count() > 1) { - /** @var RecurrenceTransaction $first */ - // @codeCoverageIgnoreStart - $first = $recurrence->recurrenceTransactions()->first(); - $groupTitle = $first->description; - // @codeCoverageIgnoreEnd - } - - $array = [ - 'user' => $recurrence->user_id, - 'group_title' => $groupTitle, - 'transactions' => $this->getTransactionData($recurrence, $repetition, $date), - ]; - /** @var TransactionGroup $group */ - $group = $this->groupRepository->store($array); - $this->created++; - Log::info(sprintf('Created new transaction group #%d', $group->id)); - - // trigger event: - event(new StoredTransactionGroup($group, $recurrence->apply_rules)); - - // update recurring thing: - $recurrence->latest_date = $date; - $recurrence->save(); - - return $group; - } - - /** - * Check if the occurences should be executed. - * - * @param Recurrence $recurrence - * @param RecurrenceRepetition $repetition - * @param array $occurrences - * - * @return Collection - */ - private function handleOccurrences(Recurrence $recurrence, RecurrenceRepetition $repetition, array $occurrences): Collection - { - $collection = new Collection; - /** @var Carbon $date */ - foreach ($occurrences as $date) { - $result = $this->handleOccurrence($recurrence, $repetition, $date); - if (null !== $result) { - $collection->push($result); - } - } - - return $collection; - } - - /** - * Separate method that will loop all repetitions and do something with it. Will return - * all created transaction journals. - * - * @param Recurrence $recurrence - * - * @return Collection - */ - private function handleRepetitions(Recurrence $recurrence): Collection - { - $collection = new Collection; - /** @var RecurrenceRepetition $repetition */ - foreach ($recurrence->recurrenceRepetitions as $repetition) { - Log::debug( - sprintf( - 'Now repeating %s with value "%s", skips every %d time(s)', - $repetition->repetition_type, - $repetition->repetition_moment, - $repetition->repetition_skip - ) - ); - - // start looping from $startDate to today perhaps we have a hit? - // add two days to $this->date so we always include the weekend. - $includeWeekend = clone $this->date; - $includeWeekend->addDays(2); - $occurrences = $this->repository->getOccurrencesInRange($repetition, $recurrence->first_date, $includeWeekend); - - unset($includeWeekend); - - $result = $this->handleOccurrences($recurrence, $repetition, $occurrences); - $collection = $collection->merge($result); - } - - return $collection; - } - - /** - * Has the recurrence fired today. - * - * @param Recurrence $recurrence - * - * @return bool - */ - private function hasFiredToday(Recurrence $recurrence): bool - { - return null !== $recurrence->latest_date && $recurrence->latest_date->eq($this->date); - } - - /** - * Has the reuccrence started yet. - * - * @param $recurrence - * - * @return bool - */ - private function hasNotStartedYet(Recurrence $recurrence): bool - { - $startDate = $this->getStartDate($recurrence); - - return $startDate->gt($this->date); - } - - - /** - * Return true if the $repeat_until date is in the past. - * - * @param Recurrence $recurrence - * - * @return bool - */ - private function repeatUntilHasPassed(Recurrence $recurrence): bool - { - // date has passed - return null !== $recurrence->repeat_until && $recurrence->repeat_until->lt($this->date); - } - /** * Is the info in the recurrence valid? * @@ -467,4 +206,264 @@ class CreateRecurringTransactions implements ShouldQueue return true; } + + /** + * Return recurring transaction is active. + * + * @param Recurrence $recurrence + * + * @return bool + */ + private function active(Recurrence $recurrence): bool + { + return $recurrence->active; + } + + /** + * Return true if the $repeat_until date is in the past. + * + * @param Recurrence $recurrence + * + * @return bool + */ + private function repeatUntilHasPassed(Recurrence $recurrence): bool + { + // date has passed + return null !== $recurrence->repeat_until && $recurrence->repeat_until->lt($this->date); + } + + /** + * Has the reuccrence started yet. + * + * @param $recurrence + * + * @return bool + */ + private function hasNotStartedYet(Recurrence $recurrence): bool + { + $startDate = $this->getStartDate($recurrence); + + return $startDate->gt($this->date); + } + + /** + * Get the start date of a recurrence. + * + * @param Recurrence $recurrence + * + * @return Carbon + */ + private function getStartDate(Recurrence $recurrence): Carbon + { + $startDate = clone $recurrence->first_date; + if (null !== $recurrence->latest_date && $recurrence->latest_date->gte($startDate)) { + $startDate = clone $recurrence->latest_date; + } + + return $startDate; + } + + /** + * Has the recurrence fired today. + * + * @param Recurrence $recurrence + * + * @return bool + */ + private function hasFiredToday(Recurrence $recurrence): bool + { + return null !== $recurrence->latest_date && $recurrence->latest_date->eq($this->date); + } + + /** + * Separate method that will loop all repetitions and do something with it. Will return + * all created transaction journals. + * + * @param Recurrence $recurrence + * + * @return Collection + */ + private function handleRepetitions(Recurrence $recurrence): Collection + { + $collection = new Collection; + /** @var RecurrenceRepetition $repetition */ + foreach ($recurrence->recurrenceRepetitions as $repetition) { + Log::debug( + sprintf( + 'Now repeating %s with value "%s", skips every %d time(s)', + $repetition->repetition_type, + $repetition->repetition_moment, + $repetition->repetition_skip + ) + ); + + // start looping from $startDate to today perhaps we have a hit? + // add two days to $this->date so we always include the weekend. + $includeWeekend = clone $this->date; + $includeWeekend->addDays(2); + $occurrences = $this->repository->getOccurrencesInRange($repetition, $recurrence->first_date, $includeWeekend); + + unset($includeWeekend); + + $result = $this->handleOccurrences($recurrence, $repetition, $occurrences); + $collection = $collection->merge($result); + } + + return $collection; + } + + /** + * Check if the occurences should be executed. + * + * @param Recurrence $recurrence + * @param RecurrenceRepetition $repetition + * @param array $occurrences + * + * @return Collection + */ + private function handleOccurrences(Recurrence $recurrence, RecurrenceRepetition $repetition, array $occurrences): Collection + { + $collection = new Collection; + /** @var Carbon $date */ + foreach ($occurrences as $date) { + $result = $this->handleOccurrence($recurrence, $repetition, $date); + if (null !== $result) { + $collection->push($result); + } + } + + return $collection; + } + + /** + * @param Recurrence $recurrence + * @param RecurrenceRepetition $repetition + * @param Carbon $date + * + * @return TransactionGroup|null + */ + private function handleOccurrence(Recurrence $recurrence, RecurrenceRepetition $repetition, Carbon $date): ?TransactionGroup + { + $date->startOfDay(); + if ($date->ne($this->date)) { + + return null; + } + Log::debug(sprintf('%s IS today (%s)', $date->format('Y-m-d'), $this->date->format('Y-m-d'))); + + // count created journals on THIS day. + $journalCount = $this->repository->getJournalCount($recurrence, $date, $date); + if ($journalCount > 0 && false === $this->force) { + Log::info(sprintf('Already created %d journal(s) for date %s', $journalCount, $date->format('Y-m-d'))); + + return null; + } + + if ($journalCount > 0 && true === $this->force) { + Log::warning(sprintf('Already created %d groups for date %s but FORCED to continue.', $journalCount, $date->format('Y-m-d'))); + } + + // create transaction array and send to factory. + $groupTitle = null; + if ($recurrence->recurrenceTransactions->count() > 1) { + /** @var RecurrenceTransaction $first */ + // @codeCoverageIgnoreStart + $first = $recurrence->recurrenceTransactions()->first(); + $groupTitle = $first->description; + // @codeCoverageIgnoreEnd + } + + $array = [ + 'user' => $recurrence->user_id, + 'group_title' => $groupTitle, + 'transactions' => $this->getTransactionData($recurrence, $repetition, $date), + ]; + /** @var TransactionGroup $group */ + $group = $this->groupRepository->store($array); + $this->created++; + Log::info(sprintf('Created new transaction group #%d', $group->id)); + + // trigger event: + event(new StoredTransactionGroup($group, $recurrence->apply_rules)); + + // update recurring thing: + $recurrence->latest_date = $date; + $recurrence->save(); + + return $group; + } + + /** + * Get transaction information from a recurring transaction. + * + * @param Recurrence $recurrence + * @param RecurrenceRepetition $repetition + * @param Carbon $date + * + * @return array + * + */ + private function getTransactionData(Recurrence $recurrence, RecurrenceRepetition $repetition, Carbon $date): array + { + // total transactions expected for this recurrence: + $total = $this->repository->totalTransactions($recurrence, $repetition); + $count = $this->repository->getJournalCount($recurrence) + 1; + $transactions = $recurrence->recurrenceTransactions()->get(); + $return = []; + /** @var RecurrenceTransaction $transaction */ + foreach ($transactions as $index => $transaction) { + $single = [ + 'type' => strtolower($recurrence->transactionType->type), + 'date' => $date, + 'user' => $recurrence->user_id, + 'currency_id' => (int)$transaction->transaction_currency_id, + 'currency_code' => null, + 'description' => $recurrence->recurrenceTransactions()->first()->description, + 'amount' => $transaction->amount, + 'budget_id' => $this->repository->getBudget($transaction), + 'budget_name' => null, + 'category_id' => null, + 'category_name' => $this->repository->getCategory($transaction), + 'source_id' => $transaction->source_id, + 'source_name' => null, + 'destination_id' => $transaction->destination_id, + 'destination_name' => null, + 'foreign_currency_id' => $transaction->foreign_currency_id, + 'foreign_currency_code' => null, + 'foreign_amount' => $transaction->foreign_amount, + 'reconciled' => false, + 'identifier' => $index, + 'recurrence_id' => (int)$recurrence->id, + 'order' => $index, + 'notes' => (string)trans('firefly.created_from_recurrence', ['id' => $recurrence->id, 'title' => $recurrence->title]), + 'tags' => $this->repository->getTags($transaction), + 'piggy_bank_id' => $this->repository->getPiggyBank($transaction), + 'piggy_bank_name' => null, + 'bill_id' => null, + 'bill_name' => null, + 'recurrence_total' => $total, + 'recurrence_count' => $count, + ]; + $return[] = $single; + } + + return $return; + } + + /** + * @param Carbon $date + */ + public function setDate(Carbon $date): void + { + $date->startOfDay(); + $this->date = $date; + } + + /** + * @param bool $force + */ + public function setForce(bool $force): void + { + $this->force = $force; + } } diff --git a/app/Jobs/SendWebhookMessage.php b/app/Jobs/SendWebhookMessage.php index e0e9b94f41..408345a367 100644 --- a/app/Jobs/SendWebhookMessage.php +++ b/app/Jobs/SendWebhookMessage.php @@ -39,7 +39,7 @@ class SendWebhookMessage implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - private WebhookMessage $message; + private WebhookMessage $message; /** * Create a new job instance. diff --git a/app/Jobs/SubmitTelemetryData.php b/app/Jobs/SubmitTelemetryData.php index 71ac5fe04c..c29623bdae 100644 --- a/app/Jobs/SubmitTelemetryData.php +++ b/app/Jobs/SubmitTelemetryData.php @@ -26,6 +26,7 @@ namespace FireflyIII\Jobs; use Carbon\Carbon; +use Exception; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Telemetry; use GuzzleHttp\Client; @@ -38,7 +39,6 @@ use Illuminate\Queue\SerializesModels; use Illuminate\Support\Collection; use JsonException; use Log; -use Exception; /** * Class SubmitTelemetryData @@ -102,13 +102,13 @@ class SubmitTelemetryData implements ShouldQueue ]; try { $result = $client->post($url, $options); - } catch (GuzzleException|Exception $e) { + } catch (GuzzleException | Exception $e) { Log::error($e->getMessage()); Log::error($e->getTraceAsString()); Log::error('Could not submit telemetry.'); throw new FireflyException(sprintf('Could not submit telemetry: %s', $e->getMessage())); } - $body = (string) $result->getBody(); + $body = (string)$result->getBody(); $statusCode = $result->getStatusCode(); Log::info(sprintf('Result of submission [%d]: %s', $statusCode, $body)); if (200 === $statusCode) { @@ -117,22 +117,6 @@ class SubmitTelemetryData implements ShouldQueue } } - /** - * @param Carbon $date - */ - public function setDate(Carbon $date): void - { - $this->date = $date; - } - - /** - * @param bool $force - */ - public function setForce(bool $force): void - { - $this->force = $force; - } - /** * @return Collection */ @@ -144,19 +128,6 @@ class SubmitTelemetryData implements ShouldQueue return $collection; } - /** - * @param Collection $telemetry - */ - private function markAsSubmitted(Collection $telemetry): void - { - $telemetry->each( - static function (Telemetry $entry) { - $entry->submitted = today(config('app.timezone')); - $entry->save(); - } - ); - } - /** * @param Collection $telemetry * @@ -179,4 +150,33 @@ class SubmitTelemetryData implements ShouldQueue return $array; } + /** + * @param Collection $telemetry + */ + private function markAsSubmitted(Collection $telemetry): void + { + $telemetry->each( + static function (Telemetry $entry) { + $entry->submitted = today(config('app.timezone')); + $entry->save(); + } + ); + } + + /** + * @param Carbon $date + */ + public function setDate(Carbon $date): void + { + $this->date = $date; + } + + /** + * @param bool $force + */ + public function setForce(bool $force): void + { + $this->force = $force; + } + } diff --git a/app/Mail/AccessTokenCreatedMail.php b/app/Mail/AccessTokenCreatedMail.php index abc626f4ae..848dfbac58 100644 --- a/app/Mail/AccessTokenCreatedMail.php +++ b/app/Mail/AccessTokenCreatedMail.php @@ -63,6 +63,6 @@ class AccessTokenCreatedMail extends Mailable public function build(): self { return $this->view('v1.emails.access-token-created-html')->text('v1.emails.access-token-created-text') - ->subject((string) trans('email.access_token_created_subject')); + ->subject((string)trans('email.access_token_created_subject')); } } diff --git a/app/Mail/AdminTestMail.php b/app/Mail/AdminTestMail.php index 406e4cb88d..d9f0e06b75 100644 --- a/app/Mail/AdminTestMail.php +++ b/app/Mail/AdminTestMail.php @@ -62,6 +62,6 @@ class AdminTestMail extends Mailable public function build(): self { return $this->view('v1.emails.admin-test-html')->text('v1.emails.admin-test-text') - ->subject((string) trans('email.admin_test_subject')); + ->subject((string)trans('email.admin_test_subject')); } } diff --git a/app/Mail/ConfirmEmailChangeMail.php b/app/Mail/ConfirmEmailChangeMail.php index 7f8694da23..ae3a613494 100644 --- a/app/Mail/ConfirmEmailChangeMail.php +++ b/app/Mail/ConfirmEmailChangeMail.php @@ -70,6 +70,6 @@ class ConfirmEmailChangeMail extends Mailable public function build(): self { return $this->view('v1.emails.confirm-email-change-html')->text('v1.emails.confirm-email-change-text') - ->subject((string) trans('email.email_change_subject')); + ->subject((string)trans('email.email_change_subject')); } } diff --git a/app/Mail/NewIPAddressWarningMail.php b/app/Mail/NewIPAddressWarningMail.php index 58cf46620e..855b97076b 100644 --- a/app/Mail/NewIPAddressWarningMail.php +++ b/app/Mail/NewIPAddressWarningMail.php @@ -55,9 +55,10 @@ class NewIPAddressWarningMail extends Mailable { use Queueable, SerializesModels; + public string $host; public string $ipAddress; public string $time; - public string $host; + /** * OAuthTokenCreatedMail constructor. * @@ -78,12 +79,12 @@ class NewIPAddressWarningMail extends Mailable // time $this->time = now()->formatLocalized((string)trans('config.date_time')); $this->host = ''; - $hostName = gethostbyaddr($this->ipAddress); - if($hostName !== $this->ipAddress) { + $hostName = gethostbyaddr($this->ipAddress); + if ($hostName !== $this->ipAddress) { $this->host = $hostName; } return $this->view('v1.emails.new-ip-html')->text('v1.emails.new-ip-text') - ->subject((string) trans('email.login_from_new_ip')); + ->subject((string)trans('email.login_from_new_ip')); } } diff --git a/app/Mail/OAuthTokenCreatedMail.php b/app/Mail/OAuthTokenCreatedMail.php index dd7b169574..2e2e8e2d7e 100644 --- a/app/Mail/OAuthTokenCreatedMail.php +++ b/app/Mail/OAuthTokenCreatedMail.php @@ -67,6 +67,6 @@ class OAuthTokenCreatedMail extends Mailable public function build(): self { return $this->view('v1.emails.oauth-client-created-html')->text('v1.emails.oauth-client-created-text') - ->subject((string) trans('email.oauth_created_subject')); + ->subject((string)trans('email.oauth_created_subject')); } } diff --git a/app/Mail/RegisteredUser.php b/app/Mail/RegisteredUser.php index d56180f336..c0c8a051e4 100644 --- a/app/Mail/RegisteredUser.php +++ b/app/Mail/RegisteredUser.php @@ -37,6 +37,7 @@ use Illuminate\Queue\SerializesModels; class RegisteredUser extends Mailable { use Queueable, SerializesModels; + /** @var string Email address of user */ public $address; /** @var string IP address of user */ @@ -61,6 +62,6 @@ class RegisteredUser extends Mailable */ public function build(): self { - return $this->view('v1.emails.registered-html')->text('v1.emails.registered-text')->subject((string) trans('email.registered_subject')); + return $this->view('v1.emails.registered-html')->text('v1.emails.registered-text')->subject((string)trans('email.registered_subject')); } } diff --git a/app/Mail/ReportNewJournalsMail.php b/app/Mail/ReportNewJournalsMail.php index 36b1c3fe1c..244d380f80 100644 --- a/app/Mail/ReportNewJournalsMail.php +++ b/app/Mail/ReportNewJournalsMail.php @@ -40,10 +40,10 @@ class ReportNewJournalsMail extends Mailable { use Queueable, SerializesModels; - public string $email; + public string $email; public Collection $groups; - public string $ipAddress; - public array $transformed; + public string $ipAddress; + public array $transformed; /** * ConfirmEmailChangeMail constructor. @@ -69,7 +69,7 @@ class ReportNewJournalsMail extends Mailable $this->transform(); return $this->view('v1.emails.report-new-journals-html')->text('v1.emails.report-new-journals-text') - ->subject((string) trans_choice('email.new_journals_subject', $this->groups->count())); + ->subject((string)trans_choice('email.new_journals_subject', $this->groups->count())); } private function transform(): void diff --git a/app/Mail/RequestedNewPassword.php b/app/Mail/RequestedNewPassword.php index 19833e195d..f7d3a51db1 100644 --- a/app/Mail/RequestedNewPassword.php +++ b/app/Mail/RequestedNewPassword.php @@ -36,6 +36,7 @@ use Illuminate\Queue\SerializesModels; class RequestedNewPassword extends Mailable { use Queueable, SerializesModels; + /** @var string IP address of user */ public $ipAddress; /** @var string URI of password change link */ @@ -60,6 +61,6 @@ class RequestedNewPassword extends Mailable */ public function build(): self { - return $this->view('v1.emails.password-html')->text('v1.emails.password-text')->subject((string) trans('email.reset_pw_subject')); + return $this->view('v1.emails.password-html')->text('v1.emails.password-text')->subject((string)trans('email.reset_pw_subject')); } } diff --git a/app/Mail/UndoEmailChangeMail.php b/app/Mail/UndoEmailChangeMail.php index 3cdfdca396..c5e8a33b0a 100644 --- a/app/Mail/UndoEmailChangeMail.php +++ b/app/Mail/UndoEmailChangeMail.php @@ -68,6 +68,6 @@ class UndoEmailChangeMail extends Mailable public function build(): self { return $this->view('v1.emails.undo-email-change-html')->text('v1.emails.undo-email-change-text') - ->subject((string) trans('email.email_change_subject')); + ->subject((string)trans('email.email_change_subject')); } } diff --git a/app/Models/Bill.php b/app/Models/Bill.php index 972c30938b..ee6c10be43 100644 --- a/app/Models/Bill.php +++ b/app/Models/Bill.php @@ -37,36 +37,36 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * FireflyIII\Models\Bill * - * @property int $id - * @property \Illuminate\Support\Carbon|null $created_at - * @property \Illuminate\Support\Carbon|null $updated_at - * @property \Illuminate\Support\Carbon|null $deleted_at - * @property int $user_id - * @property int|null $transaction_currency_id - * @property string $name - * @property string $match - * @property string $amount_min - * @property string $amount_max - * @property \Illuminate\Support\Carbon $date - * @property string|null $end_date - * @property string|null $extension_date - * @property string $repeat_freq - * @property int $skip - * @property bool $automatch - * @property bool $active - * @property bool $name_encrypted - * @property bool $match_encrypted - * @property int $order - * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Attachment[] $attachments - * @property-read int|null $attachments_count - * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Note[] $notes - * @property-read int|null $notes_count - * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\ObjectGroup[] $objectGroups - * @property-read int|null $object_groups_count - * @property-read \FireflyIII\Models\TransactionCurrency|null $transactionCurrency + * @property int $id + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property \Illuminate\Support\Carbon|null $deleted_at + * @property int $user_id + * @property int|null $transaction_currency_id + * @property string $name + * @property string $match + * @property string $amount_min + * @property string $amount_max + * @property \Illuminate\Support\Carbon $date + * @property string|null $end_date + * @property string|null $extension_date + * @property string $repeat_freq + * @property int $skip + * @property bool $automatch + * @property bool $active + * @property bool $name_encrypted + * @property bool $match_encrypted + * @property int $order + * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Attachment[] $attachments + * @property-read int|null $attachments_count + * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Note[] $notes + * @property-read int|null $notes_count + * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\ObjectGroup[] $objectGroups + * @property-read int|null $object_groups_count + * @property-read \FireflyIII\Models\TransactionCurrency|null $transactionCurrency * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionJournals - * @property-read int|null $transaction_journals_count - * @property-read User $user + * @property-read int|null $transaction_journals_count + * @property-read User $user * @method static \Illuminate\Database\Eloquent\Builder|Bill newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|Bill newQuery() * @method static Builder|Bill onlyTrashed() @@ -98,6 +98,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class Bill extends Model { use SoftDeletes; + /** * The attributes that should be casted to native types. * @@ -128,13 +129,13 @@ class Bill extends Model * * @param string $value * - * @throws NotFoundHttpException * @return Bill + * @throws NotFoundHttpException */ public static function routeBinder(string $value): Bill { if (auth()->check()) { - $billId = (int) $value; + $billId = (int)$value; /** @var User $user */ $user = auth()->user(); /** @var Bill $bill */ @@ -179,7 +180,7 @@ class Bill extends Model */ public function setAmountMaxAttribute($value): void { - $this->attributes['amount_max'] = (string) $value; + $this->attributes['amount_max'] = (string)$value; } /** @@ -189,7 +190,7 @@ class Bill extends Model */ public function setAmountMinAttribute($value): void { - $this->attributes['amount_min'] = (string) $value; + $this->attributes['amount_min'] = (string)$value; } /** diff --git a/app/Models/Tag.php b/app/Models/Tag.php index 22cc77723f..fda812145d 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -22,40 +22,40 @@ declare(strict_types=1); namespace FireflyIII\Models; -use Carbon\Carbon; use Eloquent; use FireflyIII\User; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Query\Builder; -use Illuminate\Support\Collection; +use Illuminate\Support\Carbon; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * FireflyIII\Models\Tag * - * @property int $id - * @property \Illuminate\Support\Carbon|null $created_at - * @property \Illuminate\Support\Carbon|null $updated_at - * @property \Illuminate\Support\Carbon|null $deleted_at - * @property int $user_id - * @property string $tag - * @property string $tagMode - * @property \Illuminate\Support\Carbon|null $date - * @property string|null $description - * @property float|null $latitude - * @property float|null $longitude - * @property int|null $zoomLevel - * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Attachment[] $attachments - * @property-read int|null $attachments_count - * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Location[] $locations - * @property-read int|null $locations_count - * @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionJournals - * @property-read int|null $transaction_journals_count - * @property-read User $user + * @property int $id + * @property Carbon|null $created_at + * @property Carbon|null $updated_at + * @property Carbon|null $deleted_at + * @property int $user_id + * @property string $tag + * @property string $tagMode + * @property Carbon|null $date + * @property string|null $description + * @property float|null $latitude + * @property float|null $longitude + * @property int|null $zoomLevel + * @property-read Collection|Attachment[] $attachments + * @property-read int|null $attachments_count + * @property-read Collection|Location[] $locations + * @property-read int|null $locations_count + * @property-read Collection|TransactionJournal[] $transactionJournals + * @property-read int|null $transaction_journals_count + * @property-read User $user * @method static \Illuminate\Database\Eloquent\Builder|Tag newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|Tag newQuery() * @method static Builder|Tag onlyTrashed() @@ -105,13 +105,13 @@ class Tag extends Model * * @param string $value * - * @throws NotFoundHttpException * @return Tag + * @throws NotFoundHttpException */ public static function routeBinder(string $value): Tag { if (auth()->check()) { - $tagId = (int) $value; + $tagId = (int)$value; /** @var User $user */ $user = auth()->user(); /** @var Tag $tag */ @@ -127,18 +127,18 @@ class Tag extends Model * @codeCoverageIgnore * @return MorphMany */ - public function locations(): MorphMany + public function attachments(): MorphMany { - return $this->morphMany(Location::class, 'locatable'); + return $this->morphMany(Attachment::class, 'attachable'); } /** * @codeCoverageIgnore * @return MorphMany */ - public function attachments(): MorphMany + public function locations(): MorphMany { - return $this->morphMany(Attachment::class, 'attachable'); + return $this->morphMany(Location::class, 'locatable'); } /** diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 3a66b72d3c..7548e10fc9 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -22,11 +22,11 @@ declare(strict_types=1); namespace FireflyIII\Providers; +use Adldap\Laravel\Middleware\WindowsAuthenticate; use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider; use Laravel\Passport\Passport; use URL; -use Adldap\Laravel\Middleware\WindowsAuthenticate; /** * @codeCoverageIgnore diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index e1e2fd2456..0a3d376d66 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -49,6 +49,7 @@ use Session; /** * Class EventServiceProvider. + * * @codeCoverageIgnore */ class EventServiceProvider extends ServiceProvider @@ -61,55 +62,55 @@ class EventServiceProvider extends ServiceProvider protected $listen = [ // is a User related event. - RegisteredUser::class => [ + RegisteredUser::class => [ 'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationMail', 'FireflyIII\Handlers\Events\UserEventHandler@attachUserRole', ], // is a User related event. - Login::class => [ + Login::class => [ 'FireflyIII\Handlers\Events\UserEventHandler@checkSingleUserIsAdmin', 'FireflyIII\Handlers\Events\UserEventHandler@demoUserBackToEnglish', 'FireflyIII\Handlers\Events\UserEventHandler@storeUserIPAddress', ], - DetectedNewIPAddress::class => [ + DetectedNewIPAddress::class => [ 'FireflyIII\Handlers\Events\UserEventHandler@notifyNewIPAddress', ], - RequestedVersionCheckStatus::class => [ + RequestedVersionCheckStatus::class => [ 'FireflyIII\Handlers\Events\VersionCheckEventHandler@checkForUpdates', ], - RequestedReportOnJournals::class => [ + RequestedReportOnJournals::class => [ 'FireflyIII\Handlers\Events\AutomationHandler@reportJournals', ], // is a User related event. - RequestedNewPassword::class => [ + RequestedNewPassword::class => [ 'FireflyIII\Handlers\Events\UserEventHandler@sendNewPassword', ], // is a User related event. - UserChangedEmail::class => [ + UserChangedEmail::class => [ 'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeConfirmMail', 'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeUndoMail', ], // admin related - AdminRequestedTestMessage::class => [ + AdminRequestedTestMessage::class => [ 'FireflyIII\Handlers\Events\AdminEventHandler@sendTestMessage', ], // is a Transaction Journal related event. - StoredTransactionGroup::class => [ + StoredTransactionGroup::class => [ 'FireflyIII\Handlers\Events\StoredGroupEventHandler@processRules', 'FireflyIII\Handlers\Events\StoredGroupEventHandler@triggerWebhooks', ], // is a Transaction Journal related event. - UpdatedTransactionGroup::class => [ + UpdatedTransactionGroup::class => [ 'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@unifyAccounts', 'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@processRules', 'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@triggerWebhooks', ], - DestroyedTransactionGroup::class => [ + DestroyedTransactionGroup::class => [ 'FireflyIII\Handlers\Events\DestroyedGroupEventHandler@triggerWebhooks', ], // API related events: - AccessTokenCreated::class => [ + AccessTokenCreated::class => [ 'FireflyIII\Handlers\Events\APIEventHandler@accessTokenCreated', ], diff --git a/app/Providers/FireflyServiceProvider.php b/app/Providers/FireflyServiceProvider.php index e62983bae9..2707e8f906 100644 --- a/app/Providers/FireflyServiceProvider.php +++ b/app/Providers/FireflyServiceProvider.php @@ -234,7 +234,7 @@ class FireflyServiceProvider extends ServiceProvider // webhooks: $this->app->bind(MessageGeneratorInterface::class, StandardMessageGenerator::class); - $this->app->bind(SignatureGeneratorInterface::class,Sha3SignatureGenerator::class); + $this->app->bind(SignatureGeneratorInterface::class, Sha3SignatureGenerator::class); $this->app->bind(WebhookSenderInterface::class, StandardWebhookSender::class); // password verifier thing diff --git a/app/Providers/FireflySessionProvider.php b/app/Providers/FireflySessionProvider.php index 0e5379339d..6021e5d9ba 100644 --- a/app/Providers/FireflySessionProvider.php +++ b/app/Providers/FireflySessionProvider.php @@ -44,6 +44,19 @@ class FireflySessionProvider extends ServiceProvider $this->app->singleton(StartFireflySession::class); } + /** + * Register the session manager instance. + */ + protected function registerSessionManager(): void + { + $this->app->singleton( + 'session', + function ($app) { + return new SessionManager($app); + } + ); + } + /** * Register the session driver instance. */ @@ -59,17 +72,4 @@ class FireflySessionProvider extends ServiceProvider } ); } - - /** - * Register the session manager instance. - */ - protected function registerSessionManager(): void - { - $this->app->singleton( - 'session', - function ($app) { - return new SessionManager($app); - } - ); - } } diff --git a/app/Providers/JournalServiceProvider.php b/app/Providers/JournalServiceProvider.php index 183e63f524..cf8eb35024 100644 --- a/app/Providers/JournalServiceProvider.php +++ b/app/Providers/JournalServiceProvider.php @@ -58,44 +58,6 @@ class JournalServiceProvider extends ServiceProvider $this->registerGroupCollector(); } - /** - * - */ - private function registerGroupCollector(): void - { - $this->app->bind( - GroupCollectorInterface::class, - static function (Application $app) { - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollector::class); - if ($app->auth->check()) { - $collector->setUser(auth()->user()); - } - - return $collector; - } - ); - } - - /** - * Register group repos. - */ - private function registerGroupRepository(): void - { - $this->app->bind( - TransactionGroupRepositoryInterface::class, - static function (Application $app) { - /** @var TransactionGroupRepositoryInterface $repository */ - $repository = app(TransactionGroupRepository::class); - if ($app->auth->check()) { - $repository->setUser(auth()->user()); - } - - return $repository; - } - ); - } - /** * Register repository. */ @@ -142,4 +104,42 @@ class JournalServiceProvider extends ServiceProvider } ); } + + /** + * Register group repos. + */ + private function registerGroupRepository(): void + { + $this->app->bind( + TransactionGroupRepositoryInterface::class, + static function (Application $app) { + /** @var TransactionGroupRepositoryInterface $repository */ + $repository = app(TransactionGroupRepository::class); + if ($app->auth->check()) { + $repository->setUser(auth()->user()); + } + + return $repository; + } + ); + } + + /** + * + */ + private function registerGroupCollector(): void + { + $this->app->bind( + GroupCollectorInterface::class, + static function (Application $app) { + /** @var GroupCollectorInterface $collector */ + $collector = app(GroupCollector::class); + if ($app->auth->check()) { + $collector->setUser(auth()->user()); + } + + return $collector; + } + ); + } } diff --git a/app/Repositories/Account/AccountRepository.php b/app/Repositories/Account/AccountRepository.php index e3e7741cc4..0e0529f081 100644 --- a/app/Repositories/Account/AccountRepository.php +++ b/app/Repositories/Account/AccountRepository.php @@ -545,6 +545,33 @@ class AccountRepository implements AccountRepositoryInterface return in_array($account->accountType->type, [AccountType::CREDITCARD, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], true); } + /** + * @inheritDoc + */ + public function maxOrder(string $type): int + { + $sets = [ + AccountType::ASSET => [AccountType::DEFAULT, AccountType::ASSET], + AccountType::EXPENSE => [AccountType::EXPENSE, AccountType::BENEFICIARY], + AccountType::REVENUE => [AccountType::REVENUE], + AccountType::LOAN => [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], + AccountType::DEBT => [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], + AccountType::MORTGAGE => [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], + ]; + if (array_key_exists(ucfirst($type), $sets)) { + $order = (int)$this->getAccountsByType($sets[ucfirst($type)])->max('order'); + Log::debug(sprintf('Return max order of "%s" set: %d', $type, $order)); + + return $order; + } + $specials = [AccountType::CASH, AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION]; + + $order = (int)$this->getAccountsByType($specials)->max('order'); + Log::debug(sprintf('Return max order of "%s" set (specials!): %d', $type, $order)); + + return $order; + } + /** * Returns the date of the very first transaction in this account. * @@ -720,31 +747,4 @@ class AccountRepository implements AccountRepositoryInterface return $service->update($account, $data); } - - /** - * @inheritDoc - */ - public function maxOrder(string $type): int - { - $sets = [ - AccountType::ASSET => [AccountType::DEFAULT, AccountType::ASSET], - AccountType::EXPENSE => [AccountType::EXPENSE, AccountType::BENEFICIARY], - AccountType::REVENUE => [AccountType::REVENUE], - AccountType::LOAN => [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], - AccountType::DEBT => [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], - AccountType::MORTGAGE => [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], - ]; - if (array_key_exists(ucfirst($type), $sets)) { - $order = (int)$this->getAccountsByType($sets[ucfirst($type)])->max('order'); - Log::debug(sprintf('Return max order of "%s" set: %d', $type, $order)); - - return $order; - } - $specials = [AccountType::CASH, AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION]; - - $order = (int)$this->getAccountsByType($specials)->max('order'); - Log::debug(sprintf('Return max order of "%s" set (specials!): %d', $type, $order)); - - return $order; - } } diff --git a/app/Repositories/Account/AccountRepositoryInterface.php b/app/Repositories/Account/AccountRepositoryInterface.php index a26e9a1afe..b4e973d808 100644 --- a/app/Repositories/Account/AccountRepositoryInterface.php +++ b/app/Repositories/Account/AccountRepositoryInterface.php @@ -47,13 +47,6 @@ interface AccountRepositoryInterface */ public function count(array $types): int; - /** - * @param string $type - * - * @return int - */ - public function maxOrder(string $type): int; - /** * Moved here from account CRUD. * @@ -243,6 +236,13 @@ interface AccountRepositoryInterface */ public function isLiability(Account $account): bool; + /** + * @param string $type + * + * @return int + */ + public function maxOrder(string $type): int; + /** * Returns the date of the very first transaction in this account. * diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 3ae8d29bde..3ce432a28a 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -468,27 +468,6 @@ class BudgetRepository implements BudgetRepositoryInterface return $budget; } - /** - * @param string $oldName - * @param string $newName - */ - private function updateRuleTriggers(string $oldName, string $newName): void - { - $types = ['budget_is',]; - $triggers = RuleTrigger::leftJoin('rules', 'rules.id', '=', 'rule_triggers.rule_id') - ->where('rules.user_id', $this->user->id) - ->whereIn('rule_triggers.trigger_type', $types) - ->where('rule_triggers.trigger_value', $oldName) - ->get(['rule_triggers.*']); - Log::debug(sprintf('Found %d triggers to update.', $triggers->count())); - /** @var RuleTrigger $trigger */ - foreach ($triggers as $trigger) { - $trigger->trigger_value = $newName; - $trigger->save(); - Log::debug(sprintf('Updated trigger %d: %s', $trigger->id, $trigger->trigger_value)); - } - } - /** * @param string $oldName * @param string $newName @@ -509,4 +488,25 @@ class BudgetRepository implements BudgetRepositoryInterface Log::debug(sprintf('Updated action %d: %s', $action->id, $action->action_value)); } } + + /** + * @param string $oldName + * @param string $newName + */ + private function updateRuleTriggers(string $oldName, string $newName): void + { + $types = ['budget_is',]; + $triggers = RuleTrigger::leftJoin('rules', 'rules.id', '=', 'rule_triggers.rule_id') + ->where('rules.user_id', $this->user->id) + ->whereIn('rule_triggers.trigger_type', $types) + ->where('rule_triggers.trigger_value', $oldName) + ->get(['rule_triggers.*']); + Log::debug(sprintf('Found %d triggers to update.', $triggers->count())); + /** @var RuleTrigger $trigger */ + foreach ($triggers as $trigger) { + $trigger->trigger_value = $newName; + $trigger->save(); + Log::debug(sprintf('Updated trigger %d: %s', $trigger->id, $trigger->trigger_value)); + } + } } diff --git a/app/Repositories/ObjectGroup/ObjectGroupRepository.php b/app/Repositories/ObjectGroup/ObjectGroupRepository.php index ef16cff48e..75c00e1ac2 100644 --- a/app/Repositories/ObjectGroup/ObjectGroupRepository.php +++ b/app/Repositories/ObjectGroup/ObjectGroupRepository.php @@ -108,6 +108,27 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface return $objectGroup->piggyBanks; } + /** + * @inheritDoc + */ + public function resetOrder(): void + { + Log::debug('Now in resetOrder'); + $list = $this->get(); + $index = 1; + /** @var ObjectGroup $objectGroup */ + foreach ($list as $objectGroup) { + if ($index !== (int)$objectGroup->order) { + Log::debug( + sprintf('objectGroup #%d ("%s"): order should %d be but is %d.', $objectGroup->id, $objectGroup->title, $index, $objectGroup->order) + ); + $objectGroup->order = $index; + $objectGroup->save(); + } + $index++; + } + } + /** * @param string $query * @param int $limit @@ -164,11 +185,11 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface */ public function update(ObjectGroup $objectGroup, array $data): ObjectGroup { - if(array_key_exists('title', $data)) { + if (array_key_exists('title', $data)) { $objectGroup->title = $data['title']; } - if(array_key_exists('order', $data)) { + if (array_key_exists('order', $data)) { $this->setOrder($objectGroup, (int)$data['order']); } @@ -184,25 +205,4 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface { $this->user = $user; } - - /** - * @inheritDoc - */ - public function resetOrder(): void - { - Log::debug('Now in resetOrder'); - $list = $this->get(); - $index = 1; - /** @var ObjectGroup $objectGroup */ - foreach ($list as $objectGroup) { - if ($index !== (int)$objectGroup->order) { - Log::debug( - sprintf('objectGroup #%d ("%s"): order should %d be but is %d.', $objectGroup->id, $objectGroup->title, $index, $objectGroup->order) - ); - $objectGroup->order = $index; - $objectGroup->save(); - } - $index++; - } - } } diff --git a/app/Repositories/ObjectGroup/ObjectGroupRepositoryInterface.php b/app/Repositories/ObjectGroup/ObjectGroupRepositoryInterface.php index be3c9a84a4..fce3a6bb68 100644 --- a/app/Repositories/ObjectGroup/ObjectGroupRepositoryInterface.php +++ b/app/Repositories/ObjectGroup/ObjectGroupRepositoryInterface.php @@ -37,11 +37,6 @@ interface ObjectGroupRepositoryInterface */ public function deleteAll(): void; - /** - * Delete all. - */ - public function resetOrder(): void; - /** * Delete empty ones. */ @@ -71,6 +66,11 @@ interface ObjectGroupRepositoryInterface */ public function getPiggyBanks(ObjectGroup $objectGroup): Collection; + /** + * Delete all. + */ + public function resetOrder(): void; + /** * @param string $query * @param int $limit diff --git a/app/Repositories/PiggyBank/ModifiesPiggyBanks.php b/app/Repositories/PiggyBank/ModifiesPiggyBanks.php index 5aad8ddb3f..76eba29447 100644 --- a/app/Repositories/PiggyBank/ModifiesPiggyBanks.php +++ b/app/Repositories/PiggyBank/ModifiesPiggyBanks.php @@ -122,23 +122,6 @@ trait ModifiesPiggyBanks return bccomp($amount, $savedSoFar) <= 0; } - /** - * Correct order of piggies in case of issues. - */ - public function resetOrder(): void - { - $set = $this->user->piggyBanks()->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']); - $current = 1; - foreach ($set as $piggyBank) { - if ((int)$piggyBank->order !== $current) { - Log::debug(sprintf('Piggy bank #%d ("%s") was at place %d but should be on %d', $piggyBank->id, $piggyBank->name, $piggyBank->order, $current)); - $piggyBank->order = $current; - $piggyBank->save(); - } - $current++; - } - } - /** * @param PiggyBank $piggyBank * @param string $amount @@ -217,6 +200,23 @@ trait ModifiesPiggyBanks return $piggyBank; } + /** + * Correct order of piggies in case of issues. + */ + public function resetOrder(): void + { + $set = $this->user->piggyBanks()->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']); + $current = 1; + foreach ($set as $piggyBank) { + if ((int)$piggyBank->order !== $current) { + Log::debug(sprintf('Piggy bank #%d ("%s") was at place %d but should be on %d', $piggyBank->id, $piggyBank->name, $piggyBank->order, $current)); + $piggyBank->order = $current; + $piggyBank->save(); + } + $current++; + } + } + /** * @param PiggyBank $piggyBank * @param string $amount diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php index 3f891f2c94..9e16a57b6f 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -68,11 +68,6 @@ interface PiggyBankRepositoryInterface */ public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool; - /** - * Correct order of piggies in case of issues. - */ - public function resetOrder(): void; - /** * Create a new event. * @@ -237,6 +232,11 @@ interface PiggyBankRepositoryInterface */ public function removeObjectGroup(PiggyBank $piggyBank): PiggyBank; + /** + * Correct order of piggies in case of issues. + */ + public function resetOrder(): void; + /** * Search for piggy banks. * diff --git a/app/Repositories/Recurring/RecurringRepository.php b/app/Repositories/Recurring/RecurringRepository.php index 80ba813e26..05780c8bbe 100644 --- a/app/Repositories/Recurring/RecurringRepository.php +++ b/app/Repositories/Recurring/RecurringRepository.php @@ -570,6 +570,7 @@ class RecurringRepository implements RecurringRepositoryInterface { /** @var RecurrenceUpdateService $service */ $service = app(RecurrenceUpdateService::class); + return $service->update($recurrence, $data); } diff --git a/app/Repositories/Rule/RuleRepository.php b/app/Repositories/Rule/RuleRepository.php index af089ffcdf..9cb50e7af9 100644 --- a/app/Repositories/Rule/RuleRepository.php +++ b/app/Repositories/Rule/RuleRepository.php @@ -258,6 +258,14 @@ class RuleRepository implements RuleRepositoryInterface return $filtered; } + /** + * @inheritDoc + */ + public function maxOrder(RuleGroup $ruleGroup): int + { + return (int)$ruleGroup->rules()->max('order'); + } + /** * @inheritDoc */ @@ -302,15 +310,6 @@ class RuleRepository implements RuleRepositoryInterface return $search->take($limit)->get(['id', 'title', 'description']); } - /** - * @param User $user - */ - public function setUser(User $user): void - { - $this->user = $user; - } - - /** * @inheritDoc */ @@ -347,6 +346,14 @@ class RuleRepository implements RuleRepositoryInterface $rule->save(); } + /** + * @param User $user + */ + public function setUser(User $user): void + { + $this->user = $user; + } + /** * @param array $data * @@ -489,6 +496,30 @@ class RuleRepository implements RuleRepositoryInterface return $rule; } + /** + * @param string $moment + * @param Rule $rule + */ + private function setRuleTrigger(string $moment, Rule $rule): void + { + /** @var RuleTrigger $trigger */ + $trigger = $rule->ruleTriggers()->where('trigger_type', 'user_action')->first(); + if (null !== $trigger) { + $trigger->trigger_value = $moment; + $trigger->save(); + + return; + } + $trigger = new RuleTrigger; + $trigger->order = 0; + $trigger->trigger_type = 'user_action'; + $trigger->trigger_value = $moment; + $trigger->rule_id = $rule->id; + $trigger->active = true; + $trigger->stop_processing = false; + $trigger->save(); + } + /** * @param Rule $rule * @param array $data @@ -547,36 +578,4 @@ class RuleRepository implements RuleRepositoryInterface return true; } - - /** - * @param string $moment - * @param Rule $rule - */ - private function setRuleTrigger(string $moment, Rule $rule): void - { - /** @var RuleTrigger $trigger */ - $trigger = $rule->ruleTriggers()->where('trigger_type', 'user_action')->first(); - if (null !== $trigger) { - $trigger->trigger_value = $moment; - $trigger->save(); - - return; - } - $trigger = new RuleTrigger; - $trigger->order = 0; - $trigger->trigger_type = 'user_action'; - $trigger->trigger_value = $moment; - $trigger->rule_id = $rule->id; - $trigger->active = true; - $trigger->stop_processing = false; - $trigger->save(); - } - - /** - * @inheritDoc - */ - public function maxOrder(RuleGroup $ruleGroup): int - { - return (int)$ruleGroup->rules()->max('order'); - } } diff --git a/app/Repositories/Rule/RuleRepositoryInterface.php b/app/Repositories/Rule/RuleRepositoryInterface.php index d6591a22eb..0fc7c4bf5e 100644 --- a/app/Repositories/Rule/RuleRepositoryInterface.php +++ b/app/Repositories/Rule/RuleRepositoryInterface.php @@ -123,6 +123,13 @@ interface RuleRepositoryInterface */ public function getUpdateRules(): Collection; + /** + * @param RuleGroup $ruleGroup + * + * @return int + */ + public function maxOrder(RuleGroup $ruleGroup): int; + /** * @param Rule $rule * @param RuleGroup $ruleGroup @@ -147,6 +154,12 @@ interface RuleRepositoryInterface */ public function searchRule(string $query, int $limit): Collection; + /** + * @param Rule $rule + * @param int $newOrder + */ + public function setOrder(Rule $rule, int $newOrder): void; + /** * @param User $user */ @@ -159,19 +172,6 @@ interface RuleRepositoryInterface */ public function store(array $data): Rule; - /** - * @param Rule $rule - * @param int $newOrder - */ - public function setOrder(Rule $rule, int $newOrder): void; - - /** - * @param RuleGroup $ruleGroup - * - * @return int - */ - public function maxOrder(RuleGroup $ruleGroup): int; - /** * @param Rule $rule * @param array $values diff --git a/app/Repositories/RuleGroup/RuleGroupRepository.php b/app/Repositories/RuleGroup/RuleGroupRepository.php index ffc1ab3d2e..c6747145ca 100644 --- a/app/Repositories/RuleGroup/RuleGroupRepository.php +++ b/app/Repositories/RuleGroup/RuleGroupRepository.php @@ -337,51 +337,6 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface return true; } - /** - * @param Rule $rule - */ - private function resetRuleActionOrder(Rule $rule): void - { - $actions = $rule->ruleActions() - ->orderBy('order', 'ASC') - ->orderBy('active', 'DESC') - ->orderBy('action_type', 'ASC') - ->get(); - $index = 1; - /** @var RuleAction $action */ - foreach ($actions as $action) { - if ((int)$action->order !== $index) { - $action->order = $index; - $action->save(); - Log::debug(sprintf('Rule action #%d was on spot %d but must be on spot %d', $action->id, $action->order, $index)); - } - $index++; - } - } - - /** - * @param Rule $rule - */ - private function resetRuleTriggerOrder(Rule $rule): void - { - $triggers = $rule->ruleTriggers() - ->orderBy('order', 'ASC') - ->orderBy('active', 'DESC') - ->orderBy('trigger_type', 'ASC') - ->get(); - $index = 1; - /** @var RuleTrigger $trigger */ - foreach ($triggers as $trigger) { - $order = (int)$trigger->order; - if ($order !== $index) { - $trigger->order = $index; - $trigger->save(); - Log::debug(sprintf('Rule trigger #%d was on spot %d but must be on spot %d', $trigger->id, $order, $index)); - } - $index++; - } - } - /** * @inheritDoc */ @@ -397,6 +352,32 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface return $search->take($limit)->get(['id', 'title', 'description']); } + /** + * @inheritDoc + */ + public function setOrder(RuleGroup $ruleGroup, int $newOrder): void + { + $oldOrder = (int)$ruleGroup->order; + + if ($newOrder > $oldOrder) { + $this->user->ruleGroups()->where('rule_groups.order', '<=', $newOrder)->where('rule_groups.order', '>', $oldOrder) + ->where('rule_groups.id', '!=', $ruleGroup->id) + ->decrement('order', 1); + $ruleGroup->order = $newOrder; + Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder)); + $ruleGroup->save(); + + return; + } + + $this->user->ruleGroups()->where('rule_groups.order', '>=', $newOrder)->where('rule_groups.order', '<', $oldOrder) + ->where('rule_groups.id', '!=', $ruleGroup->id) + ->increment('order', 1); + $ruleGroup->order = $newOrder; + Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder)); + $ruleGroup->save(); + } + /** * @param User $user */ @@ -459,30 +440,48 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface return $ruleGroup; } + /** + * @param Rule $rule + */ + private function resetRuleActionOrder(Rule $rule): void + { + $actions = $rule->ruleActions() + ->orderBy('order', 'ASC') + ->orderBy('active', 'DESC') + ->orderBy('action_type', 'ASC') + ->get(); + $index = 1; + /** @var RuleAction $action */ + foreach ($actions as $action) { + if ((int)$action->order !== $index) { + $action->order = $index; + $action->save(); + Log::debug(sprintf('Rule action #%d was on spot %d but must be on spot %d', $action->id, $action->order, $index)); + } + $index++; + } + } /** - * @inheritDoc + * @param Rule $rule */ - public function setOrder(RuleGroup $ruleGroup, int $newOrder): void + private function resetRuleTriggerOrder(Rule $rule): void { - $oldOrder = (int)$ruleGroup->order; - - if ($newOrder > $oldOrder) { - $this->user->ruleGroups()->where('rule_groups.order', '<=', $newOrder)->where('rule_groups.order', '>', $oldOrder) - ->where('rule_groups.id', '!=', $ruleGroup->id) - ->decrement('order', 1); - $ruleGroup->order = $newOrder; - Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder)); - $ruleGroup->save(); - - return; + $triggers = $rule->ruleTriggers() + ->orderBy('order', 'ASC') + ->orderBy('active', 'DESC') + ->orderBy('trigger_type', 'ASC') + ->get(); + $index = 1; + /** @var RuleTrigger $trigger */ + foreach ($triggers as $trigger) { + $order = (int)$trigger->order; + if ($order !== $index) { + $trigger->order = $index; + $trigger->save(); + Log::debug(sprintf('Rule trigger #%d was on spot %d but must be on spot %d', $trigger->id, $order, $index)); + } + $index++; } - - $this->user->ruleGroups()->where('rule_groups.order', '>=', $newOrder)->where('rule_groups.order', '<', $oldOrder) - ->where('rule_groups.id', '!=', $ruleGroup->id) - ->increment('order', 1); - $ruleGroup->order = $newOrder; - Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder)); - $ruleGroup->save(); } } diff --git a/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php b/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php index 0e0295eb09..7d4f7a64de 100644 --- a/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php +++ b/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php @@ -140,12 +140,6 @@ interface RuleGroupRepositoryInterface */ public function resetRuleOrder(RuleGroup $ruleGroup): bool; - /** - * @param RuleGroup $ruleGroup - * @param int $newOrder - */ - public function setOrder(RuleGroup $ruleGroup, int $newOrder): void; - /** * @param string $query * @param int $limit @@ -154,6 +148,12 @@ interface RuleGroupRepositoryInterface */ public function searchRuleGroup(string $query, int $limit): Collection; + /** + * @param RuleGroup $ruleGroup + * @param int $newOrder + */ + public function setOrder(RuleGroup $ruleGroup, int $newOrder): void; + /** * @param User $user */ diff --git a/app/Repositories/TransactionGroup/TransactionGroupRepository.php b/app/Repositories/TransactionGroup/TransactionGroupRepository.php index 724cef96b3..bc5ea3ff35 100644 --- a/app/Repositories/TransactionGroup/TransactionGroupRepository.php +++ b/app/Repositories/TransactionGroup/TransactionGroupRepository.php @@ -329,7 +329,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface ::table('tag_transaction_journal') ->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id') ->where('tag_transaction_journal.transaction_journal_id', $journalId) - ->orderBy('tags.tag','ASC') + ->orderBy('tags.tag', 'ASC') ->get(['tags.tag']); return $result->pluck('tag')->toArray(); diff --git a/app/Rules/BelongsUser.php b/app/Rules/BelongsUser.php index f8e85d6b6e..7140206e60 100644 --- a/app/Rules/BelongsUser.php +++ b/app/Rules/BelongsUser.php @@ -101,6 +101,50 @@ class BelongsUser implements Rule } } + /** + * @param string $attribute + * + * @return string + */ + private function parseAttribute(string $attribute): string + { + $parts = explode('.', $attribute); + if (1 === count($parts)) { + return $attribute; + } + if (3 === count($parts)) { + return $parts[2]; + } + + return $attribute; // @codeCoverageIgnore + } + + /** + * @param int $value + * + * @return bool + */ + private function validatePiggyBankId(int $value): bool + { + $count = PiggyBank::leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') + ->where('piggy_banks.id', '=', $value) + ->where('accounts.user_id', '=', auth()->user()->id)->count(); + + return 1 === $count; + } + + /** + * @param string $value + * + * @return bool + */ + private function validatePiggyBankName(string $value): bool + { + $count = $this->countField(PiggyBank::class, 'name', $value); + + return 1 === $count; + } + /** * @param string $class * @param string $field @@ -135,40 +179,6 @@ class BelongsUser implements Rule return $count; } - /** - * @param string $attribute - * - * @return string - */ - private function parseAttribute(string $attribute): string - { - $parts = explode('.', $attribute); - if (1 === count($parts)) { - return $attribute; - } - if (3 === count($parts)) { - return $parts[2]; - } - - return $attribute; // @codeCoverageIgnore - } - - /** - * @param int $value - * - * @return bool - */ - private function validateAccountId(int $value): bool - { - if (0 === $value) { - // its ok to submit 0. other checks will fail. - return true; - } - $count = Account::where('id', '=', $value)->where('user_id', '=', auth()->user()->id)->count(); - - return 1 === $count; - } - /** * @param int $value * @@ -209,6 +219,18 @@ class BelongsUser implements Rule return 1 === $count; } + /** + * @param int $value + * + * @return bool + */ + private function validateCategoryId(int $value): bool + { + $count = Category::where('id', '=', $value)->where('user_id', '=', auth()->user()->id)->count(); + + return 1 === $count; + } + /** * @param string $value * @@ -226,35 +248,13 @@ class BelongsUser implements Rule * * @return bool */ - private function validateCategoryId(int $value): bool + private function validateAccountId(int $value): bool { - $count = Category::where('id', '=', $value)->where('user_id', '=', auth()->user()->id)->count(); - - return 1 === $count; - } - - /** - * @param int $value - * - * @return bool - */ - private function validatePiggyBankId(int $value): bool - { - $count = PiggyBank::leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') - ->where('piggy_banks.id', '=', $value) - ->where('accounts.user_id', '=', auth()->user()->id)->count(); - - return 1 === $count; - } - - /** - * @param string $value - * - * @return bool - */ - private function validatePiggyBankName(string $value): bool - { - $count = $this->countField(PiggyBank::class, 'name', $value); + if (0 === $value) { + // its ok to submit 0. other checks will fail. + return true; + } + $count = Account::where('id', '=', $value)->where('user_id', '=', auth()->user()->id)->count(); return 1 === $count; } diff --git a/app/Rules/IsAssetAccountId.php b/app/Rules/IsAssetAccountId.php index e52562fffb..ebf1659cd3 100644 --- a/app/Rules/IsAssetAccountId.php +++ b/app/Rules/IsAssetAccountId.php @@ -46,8 +46,8 @@ class IsAssetAccountId implements Rule /** * Determine if the validation rule passes. * - * @param string $attribute - * @param mixed $value + * @param string $attribute + * @param mixed $value * * @return bool */ diff --git a/app/Rules/IsBoolean.php b/app/Rules/IsBoolean.php index f75a27b05f..f2157f1abd 100644 --- a/app/Rules/IsBoolean.php +++ b/app/Rules/IsBoolean.php @@ -33,6 +33,7 @@ class IsBoolean implements Rule { /** * Get the validation error message. + * * @codeCoverageIgnore * @return string */ @@ -44,8 +45,8 @@ class IsBoolean implements Rule /** * Determine if the validation rule passes. * - * @param string $attribute - * @param mixed $value + * @param string $attribute + * @param mixed $value * * @return bool */ diff --git a/app/Rules/IsDateOrTime.php b/app/Rules/IsDateOrTime.php index 8aab4eba20..7247f8db84 100644 --- a/app/Rules/IsDateOrTime.php +++ b/app/Rules/IsDateOrTime.php @@ -50,8 +50,8 @@ class IsDateOrTime implements Rule /** * Determine if the validation rule passes. * - * @param string $attribute - * @param mixed $value + * @param string $attribute + * @param mixed $value * * @return bool */ @@ -65,7 +65,7 @@ class IsDateOrTime implements Rule // probably a date format. try { Carbon::createFromFormat('Y-m-d', $value); - } catch (InvalidDateException|Exception $e) { + } catch (InvalidDateException | Exception $e) { Log::error(sprintf('"%s" is not a valid date: %s', $value, $e->getMessage())); return false; @@ -76,7 +76,7 @@ class IsDateOrTime implements Rule // is an atom string, I hope? try { Carbon::parse($value); - } catch (InvalidDateException|Exception $e) { + } catch (InvalidDateException | Exception $e) { Log::error(sprintf('"%s" is not a valid date or time: %s', $value, $e->getMessage())); return false; diff --git a/app/Rules/IsDuplicateTransaction.php b/app/Rules/IsDuplicateTransaction.php index d5dc158697..e47ab72012 100644 --- a/app/Rules/IsDuplicateTransaction.php +++ b/app/Rules/IsDuplicateTransaction.php @@ -56,17 +56,18 @@ class IsDuplicateTransaction implements Rule /** * @inheritDoc */ - public function passes($attribute, $value) + public function message() { - $this->value = $value; - return false; + return $this->value; } /** * @inheritDoc */ - public function message() + public function passes($attribute, $value) { - return $this->value; + $this->value = $value; + + return false; } } diff --git a/app/Rules/IsValidAttachmentModel.php b/app/Rules/IsValidAttachmentModel.php index 90560a3779..d75ecb9074 100644 --- a/app/Rules/IsValidAttachmentModel.php +++ b/app/Rules/IsValidAttachmentModel.php @@ -64,8 +64,23 @@ class IsValidAttachmentModel implements Rule $this->model = $model; } + /** + * @param string $model + * + * @return string + */ + private function normalizeModel(string $model): string + { + $search = ['FireflyIII\Models\\']; + $replace = ''; + $model = str_replace($search, $replace, $model); + + return sprintf('FireflyIII\Models\%s', $model); + } + /** * Get the validation error message. + * * @codeCoverageIgnore * @return string */ @@ -77,8 +92,8 @@ class IsValidAttachmentModel implements Rule /** * Determine if the validation rule passes. * - * @param string $attribute - * @param mixed $value + * @param string $attribute + * @param mixed $value * * @return bool */ @@ -104,7 +119,7 @@ class IsValidAttachmentModel implements Rule } $method = $methods[$this->model]; - return $this->$method((int) $value); + return $this->$method((int)$value); } /** @@ -112,10 +127,10 @@ class IsValidAttachmentModel implements Rule * * @return bool */ - private function validateTag(int $value): bool + private function validateAccount(int $value): bool { - /** @var TagRepositoryInterface $repository */ - $repository = app(TagRepositoryInterface::class); + /** @var AccountRepositoryInterface $repository */ + $repository = app(AccountRepositoryInterface::class); $repository->setUser(auth()->user()); return null !== $repository->findNull($value); @@ -126,13 +141,13 @@ class IsValidAttachmentModel implements Rule * * @return bool */ - private function validatePiggyBank(int $value): bool + private function validateBill(int $value): bool { - /** @var PiggyBankRepositoryInterface $repository */ - $repository = app(PiggyBankRepositoryInterface::class); + /** @var BillRepositoryInterface $repository */ + $repository = app(BillRepositoryInterface::class); $repository->setUser(auth()->user()); - return null !== $repository->findNull($value); + return null !== $repository->find($value); } /** @@ -168,10 +183,9 @@ class IsValidAttachmentModel implements Rule * * @return bool */ - private function validateAccount(int $value): bool + private function validateJournal(int $value): bool { - /** @var AccountRepositoryInterface $repository */ - $repository = app(AccountRepositoryInterface::class); + $repository = app(JournalRepositoryInterface::class); $repository->setUser(auth()->user()); return null !== $repository->findNull($value); @@ -182,9 +196,24 @@ class IsValidAttachmentModel implements Rule * * @return bool */ - private function validateJournal(int $value): bool + private function validatePiggyBank(int $value): bool { - $repository = app(JournalRepositoryInterface::class); + /** @var PiggyBankRepositoryInterface $repository */ + $repository = app(PiggyBankRepositoryInterface::class); + $repository->setUser(auth()->user()); + + return null !== $repository->findNull($value); + } + + /** + * @param int $value + * + * @return bool + */ + private function validateTag(int $value): bool + { + /** @var TagRepositoryInterface $repository */ + $repository = app(TagRepositoryInterface::class); $repository->setUser(auth()->user()); return null !== $repository->findNull($value); @@ -201,34 +230,6 @@ class IsValidAttachmentModel implements Rule $repository = app(JournalAPIRepositoryInterface::class); $repository->setUser(auth()->user()); - return null !== $repository->findTransaction((int) $value); - } - - /** - * @param int $value - * - * @return bool - */ - private function validateBill(int $value): bool - { - /** @var BillRepositoryInterface $repository */ - $repository = app(BillRepositoryInterface::class); - $repository->setUser(auth()->user()); - - return null !== $repository->find($value); - } - - /** - * @param string $model - * - * @return string - */ - private function normalizeModel(string $model): string - { - $search = ['FireflyIII\Models\\']; - $replace = ''; - $model = str_replace($search, $replace, $model); - - return sprintf('FireflyIII\Models\%s', $model); + return null !== $repository->findTransaction((int)$value); } } diff --git a/app/Rules/UniqueAccountNumber.php b/app/Rules/UniqueAccountNumber.php index 2051b65ff3..62cc70010c 100644 --- a/app/Rules/UniqueAccountNumber.php +++ b/app/Rules/UniqueAccountNumber.php @@ -35,7 +35,7 @@ use Log; class UniqueAccountNumber implements Rule { private ?Account $account; - private ?string $expectedType; + private ?string $expectedType; /** * Create a new rule instance. @@ -109,32 +109,10 @@ class UniqueAccountNumber implements Rule } } Log::debug('Account number is valid.'); + return true; } - /** - * @param string $type - * @param string $accountNumber - * - * @return int - */ - private function countHits(string $type, string $accountNumber): int - { - $query = AccountMeta - ::leftJoin('accounts','accounts.id','=','account_meta.account_id') - ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') - ->where('accounts.user_id', auth()->user()->id) - ->where('account_types.type', $type) - ->where('account_meta.name','=','account_number') - ->where('account_meta.data',json_encode($accountNumber)); - - if (null !== $this->account) { - $query->where('accounts.id', '!=', $this->account->id); - } - - return $query->count(); - } - /** * @return array * @@ -160,4 +138,27 @@ class UniqueAccountNumber implements Rule return $maxCounts; } + + /** + * @param string $type + * @param string $accountNumber + * + * @return int + */ + private function countHits(string $type, string $accountNumber): int + { + $query = AccountMeta + ::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id') + ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') + ->where('accounts.user_id', auth()->user()->id) + ->where('account_types.type', $type) + ->where('account_meta.name', '=', 'account_number') + ->where('account_meta.data', json_encode($accountNumber)); + + if (null !== $this->account) { + $query->where('accounts.id', '!=', $this->account->id); + } + + return $query->count(); + } } diff --git a/app/Rules/UniqueIban.php b/app/Rules/UniqueIban.php index 6afb487518..325a6ef689 100644 --- a/app/Rules/UniqueIban.php +++ b/app/Rules/UniqueIban.php @@ -34,7 +34,7 @@ use Log; class UniqueIban implements Rule { private ?Account $account; - private ?string $expectedType; + private ?string $expectedType; /** * Create a new rule instance. @@ -109,28 +109,6 @@ class UniqueIban implements Rule return true; } - /** - * @param string $type - * @param string $iban - * - * @return int - */ - private function countHits(string $type, string $iban): int - { - $query - = auth()->user() - ->accounts() - ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') - ->where('accounts.iban', $iban) - ->where('account_types.type', $type); - - if (null !== $this->account) { - $query->where('accounts.id', '!=', $this->account->id); - } - - return $query->count(); - } - /** * @return array * @@ -156,4 +134,26 @@ class UniqueIban implements Rule return $maxCounts; } + + /** + * @param string $type + * @param string $iban + * + * @return int + */ + private function countHits(string $type, string $iban): int + { + $query + = auth()->user() + ->accounts() + ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') + ->where('accounts.iban', $iban) + ->where('account_types.type', $type); + + if (null !== $this->account) { + $query->where('accounts.id', '!=', $this->account->id); + } + + return $query->count(); + } } diff --git a/app/Rules/ValidJournals.php b/app/Rules/ValidJournals.php index 7568987cf5..4ad6509e5b 100644 --- a/app/Rules/ValidJournals.php +++ b/app/Rules/ValidJournals.php @@ -31,6 +31,7 @@ use Log; /** * Class ValidJournals + * * @codeCoverageIgnore */ class ValidJournals implements Rule @@ -49,7 +50,7 @@ class ValidJournals implements Rule * Determine if the validation rule passes. * * @param string $attribute - * @param mixed $value + * @param mixed $value * * @return bool * diff --git a/app/Rules/ValidRecurrenceRepetitionType.php b/app/Rules/ValidRecurrenceRepetitionType.php index 47b23ce29e..e7211060ae 100644 --- a/app/Rules/ValidRecurrenceRepetitionType.php +++ b/app/Rules/ValidRecurrenceRepetitionType.php @@ -27,6 +27,7 @@ use Illuminate\Contracts\Validation\Rule; /** * Class ValidRecurrenceRepetitionType + * * @codeCoverageIgnore */ class ValidRecurrenceRepetitionType implements Rule @@ -45,8 +46,8 @@ class ValidRecurrenceRepetitionType implements Rule /** * Determine if the validation rule passes. * - * @param string $attribute - * @param mixed $value + * @param string $attribute + * @param mixed $value * * @return bool * diff --git a/app/Rules/ValidRecurrenceRepetitionValue.php b/app/Rules/ValidRecurrenceRepetitionValue.php index 91d830af37..06d2e4c0c1 100644 --- a/app/Rules/ValidRecurrenceRepetitionValue.php +++ b/app/Rules/ValidRecurrenceRepetitionValue.php @@ -31,6 +31,7 @@ use Log; /** * Class ValidRecurrenceRepetitionValue + * * @codeCoverageIgnore */ class ValidRecurrenceRepetitionValue implements Rule @@ -49,8 +50,8 @@ class ValidRecurrenceRepetitionValue implements Rule /** * Determine if the validation rule passes. * - * @param string $attribute - * @param mixed $value + * @param string $attribute + * @param mixed $value * * @return bool * diff --git a/app/Scopes/LdapFilterScope.php b/app/Scopes/LdapFilterScope.php index 5b9fa51b6a..38ba147852 100644 --- a/app/Scopes/LdapFilterScope.php +++ b/app/Scopes/LdapFilterScope.php @@ -24,19 +24,22 @@ declare(strict_types=1); namespace FireflyIII\Scopes; -use Adldap\Query\Builder; use Adldap\Laravel\Scopes\ScopeInterface; +use Adldap\Query\Builder; -class LdapFilterScope implements ScopeInterface { +class LdapFilterScope implements ScopeInterface +{ /** * If the ADLDAP_AUTH_FILTER is provided, apply the filter to the LDAP query. + * * @param Builder $query + * * @return void */ public function apply(Builder $query) { - $filter = (string) config('ldap_auth.custom_filter'); - if ( '' !== $filter ) { + $filter = (string)config('ldap_auth.custom_filter'); + if ('' !== $filter) { $query->rawFilter($filter); } } diff --git a/app/Services/FireflyIIIOrg/Update/UpdateRequest.php b/app/Services/FireflyIIIOrg/Update/UpdateRequest.php index a675421892..2f2d4d2866 100644 --- a/app/Services/FireflyIIIOrg/Update/UpdateRequest.php +++ b/app/Services/FireflyIIIOrg/Update/UpdateRequest.php @@ -64,6 +64,77 @@ class UpdateRequest implements UpdateRequestInterface return $this->parseResult($updateInfo); } + /** + * @param string $channel + * + * @return array + */ + private function contactServer(string $channel): array + { + Log::debug(sprintf('Now in contactServer(%s)', $channel)); + // always fall back to current version: + $return = [ + 'version' => config('firefly.version'), + 'date' => Carbon::today()->startOfDay(), + 'level' => 'error', + 'message' => (string)trans('firefly.unknown_error'), + ]; + + $uri = config('firefly.update_endpoint'); + Log::debug(sprintf('Going to call %s', $uri)); + try { + $client = new Client; + $options = [ + 'headers' => [ + 'User-Agent' => sprintf('FireflyIII/%s/%s', config('firefly.version'), $channel), + ], + 'timeout' => 3.1415, + ]; + $res = $client->request('GET', $uri, $options); + } catch (GuzzleException | Exception $e) { + Log::error('Ran into Guzzle error.'); + Log::error($e->getMessage()); + Log::error($e->getTraceAsString()); + $return['message'] = sprintf('Guzzle: %s', strip_tags($e->getMessage())); + + return $return; + } + + if (200 !== $res->getStatusCode()) { + Log::error(sprintf('Response status from server is %d.', $res->getStatusCode())); + Log::error((string)$res->getBody()); + $return['message'] = sprintf('Error: %d', $res->getStatusCode()); + + return $return; + } + $body = (string)$res->getBody(); + try { + $json = json_decode($body, true, 512, JSON_THROW_ON_ERROR); + + } catch (JsonException | Exception $e) { + Log::error('Body is not valid JSON'); + Log::error($body); + $return['message'] = 'Invalid JSON :('; + + return $return; + } + + if (!isset($json['firefly_iii'][$channel])) { + Log::error(sprintf('No valid update channel "%s"', $channel)); + Log::error($body); + $return['message'] = sprintf('Unknown update channel "%s" :(', $channel); + } + + // parse response a bit. No message yet. + $response = $json['firefly_iii'][$channel]; + $return['version'] = $response['version']; + $return['level'] = 'success'; + $return['date'] = Carbon::createFromFormat('Y-m-d', $response['date'])->startOfDay(); + Log::info('Response from update server', $response); + + return $return; + } + /** * @param array $information * @@ -149,75 +220,4 @@ class UpdateRequest implements UpdateRequestInterface return $return; } - - /** - * @param string $channel - * - * @return array - */ - private function contactServer(string $channel): array - { - Log::debug(sprintf('Now in contactServer(%s)', $channel)); - // always fall back to current version: - $return = [ - 'version' => config('firefly.version'), - 'date' => Carbon::today()->startOfDay(), - 'level' => 'error', - 'message' => (string)trans('firefly.unknown_error'), - ]; - - $uri = config('firefly.update_endpoint'); - Log::debug(sprintf('Going to call %s', $uri)); - try { - $client = new Client; - $options = [ - 'headers' => [ - 'User-Agent' => sprintf('FireflyIII/%s/%s', config('firefly.version'), $channel), - ], - 'timeout' => 3.1415 - ]; - $res = $client->request('GET', $uri, $options); - } catch (GuzzleException|Exception $e) { - Log::error('Ran into Guzzle error.'); - Log::error($e->getMessage()); - Log::error($e->getTraceAsString()); - $return['message'] = sprintf('Guzzle: %s', strip_tags($e->getMessage())); - - return $return; - } - - if (200 !== $res->getStatusCode()) { - Log::error(sprintf('Response status from server is %d.', $res->getStatusCode())); - Log::error((string)$res->getBody()); - $return['message'] = sprintf('Error: %d', $res->getStatusCode()); - - return $return; - } - $body = (string)$res->getBody(); - try { - $json = json_decode($body, true, 512, JSON_THROW_ON_ERROR); - - } catch (JsonException|Exception $e) { - Log::error('Body is not valid JSON'); - Log::error($body); - $return['message'] = 'Invalid JSON :('; - - return $return; - } - - if (!isset($json['firefly_iii'][$channel])) { - Log::error(sprintf('No valid update channel "%s"', $channel)); - Log::error($body); - $return['message'] = sprintf('Unknown update channel "%s" :(', $channel); - } - - // parse response a bit. No message yet. - $response = $json['firefly_iii'][$channel]; - $return['version'] = $response['version']; - $return['level'] = 'success'; - $return['date'] = Carbon::createFromFormat('Y-m-d', $response['date'])->startOfDay(); - Log::info('Response from update server', $response); - - return $return; - } } diff --git a/app/Services/Internal/Update/AccountUpdateService.php b/app/Services/Internal/Update/AccountUpdateService.php index e93c506240..2226e5ff77 100644 --- a/app/Services/Internal/Update/AccountUpdateService.php +++ b/app/Services/Internal/Update/AccountUpdateService.php @@ -119,21 +119,21 @@ class AccountUpdateService private function updateAccount(Account $account, array $data): Account { // update the account itself: - if(array_key_exists('name', $data)) { - $account->name = $data['name']; + if (array_key_exists('name', $data)) { + $account->name = $data['name']; } - if(array_key_exists('active', $data)) { + if (array_key_exists('active', $data)) { $account->active = $data['active']; } - if(array_key_exists('iban', $data)) { - $account->iban = $data['iban']; + if (array_key_exists('iban', $data)) { + $account->iban = $data['iban']; } // set liability, but account must already be a liability. //$liabilityType = $data['liability_type'] ?? ''; if ($this->isLiability($account) && array_key_exists('liability_type', $data)) { - $type = $this->getAccountType($data['liability_type']); - if(null !== $type) { + $type = $this->getAccountType($data['liability_type']); + if (null !== $type) { $account->account_type_id = $type->id; } } @@ -160,20 +160,6 @@ class AccountUpdateService return in_array($type, [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE], true); } - /** - * @param string $type - * - * @return bool - */ - private function isLiabilityType(string $type): bool - { - if ('' === $type) { - return false; - } - - return 1 === AccountType::whereIn('type', [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE])->where('type', ucfirst($type))->count(); - } - /** * @param string $type */ @@ -334,4 +320,18 @@ class AccountUpdateService } Log::debug('Account was not marked as inactive, do nothing.'); } + + /** + * @param string $type + * + * @return bool + */ + private function isLiabilityType(string $type): bool + { + if ('' === $type) { + return false; + } + + return 1 === AccountType::whereIn('type', [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE])->where('type', ucfirst($type))->count(); + } } diff --git a/app/Services/Password/PwndVerifierV2.php b/app/Services/Password/PwndVerifierV2.php index 5afdb5e27c..8566ba7dbf 100644 --- a/app/Services/Password/PwndVerifierV2.php +++ b/app/Services/Password/PwndVerifierV2.php @@ -30,6 +30,7 @@ use RuntimeException; /** * Class PwndVerifierV2. + * * @codeCoverageIgnore */ class PwndVerifierV2 implements Verifier @@ -50,7 +51,7 @@ class PwndVerifierV2 implements Verifier $uri = sprintf('https://api.pwnedpasswords.com/range/%s', $prefix); $opt = [ 'headers' => [ - 'User-Agent' => 'Firefly III v' . config('firefly.version'), + 'User-Agent' => 'Firefly III v' . config('firefly.version'), 'Add-Padding' => 'true', ], 'timeout' => 3.1415]; @@ -61,7 +62,7 @@ class PwndVerifierV2 implements Verifier try { $client = new Client(); $res = $client->request('GET', $uri, $opt); - } catch (GuzzleException|Exception $e) { + } catch (GuzzleException | Exception $e) { Log::error(sprintf('Could not verify password security: %s', $e->getMessage())); return true; diff --git a/app/Services/Webhook/StandardWebhookSender.php b/app/Services/Webhook/StandardWebhookSender.php index 9f3e720050..22fd2136c9 100644 --- a/app/Services/Webhook/StandardWebhookSender.php +++ b/app/Services/Webhook/StandardWebhookSender.php @@ -68,14 +68,6 @@ class StandardWebhookSender implements WebhookSenderInterface return $this->version; } - /** - * @inheritDoc - */ - public function setMessage(WebhookMessage $message): void - { - $this->message = $message; - } - /** * @inheritDoc */ @@ -144,4 +136,12 @@ class StandardWebhookSender implements WebhookSenderInterface Log::debug(sprintf('Webhook request body size: %d bytes', strlen($json))); Log::debug(sprintf('Response body: %s', $res->getBody())); } + + /** + * @inheritDoc + */ + public function setMessage(WebhookMessage $message): void + { + $this->message = $message; + } } diff --git a/app/Services/Webhook/WebhookSenderInterface.php b/app/Services/Webhook/WebhookSenderInterface.php index 381dd23904..646a68b865 100644 --- a/app/Services/Webhook/WebhookSenderInterface.php +++ b/app/Services/Webhook/WebhookSenderInterface.php @@ -55,13 +55,13 @@ interface WebhookSenderInterface */ public function getVersion(): int; - /** - * @param WebhookMessage $message - */ - public function setMessage(WebhookMessage $message): void; - /** * */ public function send(): void; + + /** + * @param WebhookMessage $message + */ + public function setMessage(WebhookMessage $message): void; } diff --git a/app/Support/Amount.php b/app/Support/Amount.php index f7b73cd0a2..d2280d48f0 100644 --- a/app/Support/Amount.php +++ b/app/Support/Amount.php @@ -27,7 +27,6 @@ use FireflyIII\Models\TransactionCurrency; use FireflyIII\User; use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Support\Collection; -use Log; use NumberFormatter; /** @@ -37,6 +36,225 @@ use NumberFormatter; */ class Amount { + /** + * This method will properly format the given number, in color or "black and white", + * as a currency, given two things: the currency required and the current locale. + * + * @param TransactionCurrency $format + * @param string $amount + * @param bool $coloured + * + * @return string + * + */ + public function formatAnything(TransactionCurrency $format, string $amount, bool $coloured = null): string + { + return $this->formatFlat($format->symbol, (int)$format->decimal_places, $amount, $coloured); + } + + /** + * This method will properly format the given number, in color or "black and white", + * as a currency, given two things: the currency required and the current locale. + * + * @param string $symbol + * @param int $decimalPlaces + * @param string $amount + * @param bool $coloured + * + * @return string + * + * @noinspection MoreThanThreeArgumentsInspection + */ + public function formatFlat(string $symbol, int $decimalPlaces, string $amount, bool $coloured = null): string + { + $locale = app('steam')->getLocale(); + + $coloured = $coloured ?? true; + + $fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY); + $fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol); + $fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces); + $fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces); + $result = $fmt->format((float)$amount); + + if (true === $coloured) { + if ($amount > 0) { + return sprintf('%s', $result); + } + if ($amount < 0) { + return sprintf('%s', $result); + } + + return sprintf('%s', $result); + } + + return $result; + } + + /** + * @return Collection + */ + public function getAllCurrencies(): Collection + { + return TransactionCurrency::orderBy('code', 'ASC')->get(); + } + + /** + * @return Collection + */ + public function getCurrencies(): Collection + { + return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get(); + } + + /** + * @return string + */ + public function getCurrencyCode(): string + { + $cache = new CacheProperties; + $cache->addProperty('getCurrencyCode'); + if ($cache->has()) { + return $cache->get(); // @codeCoverageIgnore + } + $currencyPreference = app('preferences')->get('currencyPreference', config('firefly.default_currency', 'EUR')); + + $currency = TransactionCurrency::where('code', $currencyPreference->data)->first(); + if ($currency) { + $cache->store($currency->code); + + return $currency->code; + } + $cache->store(config('firefly.default_currency', 'EUR')); + + return (string)config('firefly.default_currency', 'EUR'); + } + + /** + * @return TransactionCurrency + */ + public function getDefaultCurrency(): TransactionCurrency + { + /** @var User $user */ + $user = auth()->user(); + + return $this->getDefaultCurrencyByUser($user); + } + + /** + * @param User $user + * + * @return TransactionCurrency + */ + public function getDefaultCurrencyByUser(User $user): TransactionCurrency + { + $cache = new CacheProperties; + $cache->addProperty('getDefaultCurrency'); + $cache->addProperty($user->id); + if ($cache->has()) { + return $cache->get(); // @codeCoverageIgnore + } + $currencyPreference = app('preferences')->getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR')); + $currencyPrefStr = $currencyPreference ? $currencyPreference->data : 'EUR'; + + // at this point the currency preference could be encrypted, if coming from an old version. + $currencyCode = $this->tryDecrypt((string)$currencyPrefStr); + + // could still be json encoded: + if (strlen($currencyCode) > 3) { + $currencyCode = json_decode($currencyCode, true, 512, JSON_THROW_ON_ERROR) ?? 'EUR'; + } + /** @var TransactionCurrency $currency */ + $currency = TransactionCurrency::where('code', $currencyCode)->first(); + if (null === $currency) { + // get EUR + $currency = TransactionCurrency::where('code', 'EUR')->first(); + } + $cache->store($currency); + + return $currency; + } + + /** + * @param string $value + * + * @return string + */ + private function tryDecrypt(string $value): string + { + try { + $value = Crypt::decrypt($value); // verified + } catch (DecryptException $e) { + // ignore decryption error. + } + + return $value; + } + + /** + * This method returns the correct format rules required by accounting.js, + * the library used to format amounts in charts. + * + * Used only in one place. + * + * @return array + */ + public function getJsConfig(): array + { + $config = $this->getLocaleInfo(); + $negative = self::getAmountJsConfig($config['n_sep_by_space'], $config['n_sign_posn'], $config['negative_sign'], $config['n_cs_precedes']); + $positive = self::getAmountJsConfig($config['p_sep_by_space'], $config['p_sign_posn'], $config['positive_sign'], $config['p_cs_precedes']); + + return [ + 'mon_decimal_point' => $config['mon_decimal_point'], + 'mon_thousands_sep' => $config['mon_thousands_sep'], + 'format' => [ + 'pos' => $positive, + 'neg' => $negative, + 'zero' => $positive, + ], + ]; + } + + /** + * @return array + */ + private function getLocaleInfo(): array + { + // get config from preference, not from translation: + $locale = app('steam')->getLocale(); + $array = app('steam')->getLocaleArray($locale); + + setlocale(LC_MONETARY, $array); + $info = localeconv(); + + // correct variables + $info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes'); + $info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes'); + + $info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space'); + $info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space'); + + $fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY); + + $info['mon_decimal_point'] = $fmt->getSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL); + $info['mon_thousands_sep'] = $fmt->getSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL); + + return $info; + } + + /** + * @param array $info + * @param string $field + * + * @return bool + */ + private function getLocaleField(array $info, string $field): bool + { + return (is_bool($info[$field]) && true === $info[$field]) + || (is_int($info[$field]) && 1 === $info[$field]); + } + /** * bool $sepBySpace is $localeconv['n_sep_by_space'] * int $signPosn = $localeconv['n_sign_posn'] @@ -111,230 +329,11 @@ class Amount return $format; } - /** - * This method returns the correct format rules required by accounting.js, - * the library used to format amounts in charts. - * - * Used only in one place. - * - * @return array - */ - public function getJsConfig(): array - { - $config = $this->getLocaleInfo(); - $negative = self::getAmountJsConfig($config['n_sep_by_space'], $config['n_sign_posn'], $config['negative_sign'], $config['n_cs_precedes']); - $positive = self::getAmountJsConfig($config['p_sep_by_space'], $config['p_sign_posn'], $config['positive_sign'], $config['p_cs_precedes']); - - return [ - 'mon_decimal_point' => $config['mon_decimal_point'], - 'mon_thousands_sep' => $config['mon_thousands_sep'], - 'format' => [ - 'pos' => $positive, - 'neg' => $negative, - 'zero' => $positive, - ], - ]; - } - - /** - * @return array - */ - private function getLocaleInfo(): array - { - // get config from preference, not from translation: - $locale = app('steam')->getLocale(); - $array = app('steam')->getLocaleArray($locale); - - setlocale(LC_MONETARY, $array); - $info = localeconv(); - - // correct variables - $info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes'); - $info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes'); - - $info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space'); - $info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space'); - - $fmt = new NumberFormatter( $locale, NumberFormatter::CURRENCY); - - $info['mon_decimal_point'] = $fmt->getSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL); - $info['mon_thousands_sep'] = $fmt->getSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL); - - return $info; - } - - /** - * This method will properly format the given number, in color or "black and white", - * as a currency, given two things: the currency required and the current locale. - * - * @param TransactionCurrency $format - * @param string $amount - * @param bool $coloured - * - * @return string - * - */ - public function formatAnything(TransactionCurrency $format, string $amount, bool $coloured = null): string - { - return $this->formatFlat($format->symbol, (int)$format->decimal_places, $amount, $coloured); - } - - /** - * This method will properly format the given number, in color or "black and white", - * as a currency, given two things: the currency required and the current locale. - * - * @param string $symbol - * @param int $decimalPlaces - * @param string $amount - * @param bool $coloured - * - * @return string - * - * @noinspection MoreThanThreeArgumentsInspection - */ - public function formatFlat(string $symbol, int $decimalPlaces, string $amount, bool $coloured = null): string - { - $locale = app('steam')->getLocale(); - - $coloured = $coloured ?? true; - - $fmt = new NumberFormatter( $locale, NumberFormatter::CURRENCY ); - $fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol); - $fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces); - $fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces); - $result = $fmt->format((float) $amount); - - if (true === $coloured) { - if ($amount > 0) { - return sprintf('%s', $result); - } - if ($amount < 0) { - return sprintf('%s', $result); - } - - return sprintf('%s', $result); - } - - return $result; - } - - /** - * @return Collection - */ - public function getAllCurrencies(): Collection - { - return TransactionCurrency::orderBy('code', 'ASC')->get(); - } - - /** - * @return Collection - */ - public function getCurrencies(): Collection - { - return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get(); - } - - /** - * @return string - */ - public function getCurrencyCode(): string - { - $cache = new CacheProperties; - $cache->addProperty('getCurrencyCode'); - if ($cache->has()) { - return $cache->get(); // @codeCoverageIgnore - } - $currencyPreference = app('preferences')->get('currencyPreference', config('firefly.default_currency', 'EUR')); - - $currency = TransactionCurrency::where('code', $currencyPreference->data)->first(); - if ($currency) { - $cache->store($currency->code); - - return $currency->code; - } - $cache->store(config('firefly.default_currency', 'EUR')); - - return (string)config('firefly.default_currency', 'EUR'); - } - - /** - * @return TransactionCurrency - */ - public function getDefaultCurrency(): TransactionCurrency - { - /** @var User $user */ - $user = auth()->user(); - - return $this->getDefaultCurrencyByUser($user); - } - /** * @return TransactionCurrency */ public function getSystemCurrency(): TransactionCurrency { - return TransactionCurrency::where('code', 'EUR')->first(); - } - - /** - * @param User $user - * - * @return TransactionCurrency - */ - public function getDefaultCurrencyByUser(User $user): TransactionCurrency - { - $cache = new CacheProperties; - $cache->addProperty('getDefaultCurrency'); - $cache->addProperty($user->id); - if ($cache->has()) { - return $cache->get(); // @codeCoverageIgnore - } - $currencyPreference = app('preferences')->getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR')); - $currencyPrefStr = $currencyPreference ? $currencyPreference->data : 'EUR'; - - // at this point the currency preference could be encrypted, if coming from an old version. - $currencyCode = $this->tryDecrypt((string) $currencyPrefStr); - - // could still be json encoded: - if (strlen($currencyCode) > 3) { - $currencyCode = json_decode($currencyCode, true, 512, JSON_THROW_ON_ERROR) ?? 'EUR'; - } - /** @var TransactionCurrency $currency */ - $currency = TransactionCurrency::where('code', $currencyCode)->first(); - if (null === $currency) { - // get EUR - $currency = TransactionCurrency::where('code', 'EUR')->first(); - } - $cache->store($currency); - - return $currency; - } - - /** - * @param array $info - * @param string $field - * - * @return bool - */ - private function getLocaleField(array $info, string $field): bool - { - return (is_bool($info[$field]) && true === $info[$field]) - || (is_int($info[$field]) && 1 === $info[$field]); - } - - /** - * @param string $value - * - * @return string - */ - private function tryDecrypt(string $value): string - { - try { - $value = Crypt::decrypt($value); // verified - } catch (DecryptException $e) { - // ignore decryption error. - } - - return $value; + return TransactionCurrency::where('code', 'EUR')->first(); } } diff --git a/app/Support/Authentication/RemoteUserGuard.php b/app/Support/Authentication/RemoteUserGuard.php index 42432e25ba..fc8e28bbd7 100644 --- a/app/Support/Authentication/RemoteUserGuard.php +++ b/app/Support/Authentication/RemoteUserGuard.php @@ -45,7 +45,7 @@ class RemoteUserGuard implements Guard /** * Create a new authentication guard. * - * @param \Illuminate\Contracts\Auth\UserProvider $provider + * @param UserProvider $provider * * @return void */ @@ -79,10 +79,10 @@ class RemoteUserGuard implements Guard $retrievedUser = $this->provider->retrieveById($userID); // store email address if present in header and not already set. - $header = config('auth.guard_email'); + $header = config('auth.guard_email'); if (null !== $header) { - $emailAddress = (string) (request()->server($header) ?? null); + $emailAddress = (string)(request()->server($header) ?? null); $preference = app('preferences')->getForUser($retrievedUser, 'remote_guard_alt_email', null); if (null !== $emailAddress && null === $preference && $emailAddress !== $userID) { diff --git a/app/Support/Binder/Date.php b/app/Support/Binder/Date.php index ea4b6e7826..423b699a7d 100644 --- a/app/Support/Binder/Date.php +++ b/app/Support/Binder/Date.php @@ -39,7 +39,7 @@ class Date implements BinderInterface * @param Route $route * * @return Carbon - * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * @throws NotFoundHttpException */ public static function routeBinder(string $value, Route $route): Carbon { diff --git a/app/Support/Binder/TagList.php b/app/Support/Binder/TagList.php index 3f7bf64d1e..ba4d06f60f 100644 --- a/app/Support/Binder/TagList.php +++ b/app/Support/Binder/TagList.php @@ -39,7 +39,7 @@ class TagList implements BinderInterface * @param Route $route * * @return Collection - * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * @throws NotFoundHttpException */ public static function routeBinder(string $value, Route $route): Collection { diff --git a/app/Support/CacheProperties.php b/app/Support/CacheProperties.php index 7472bc91c9..4d7c36ab15 100644 --- a/app/Support/CacheProperties.php +++ b/app/Support/CacheProperties.php @@ -23,10 +23,13 @@ declare(strict_types=1); namespace FireflyIII\Support; use Cache; +use Carbon\Carbon; +use FireflyIII\Models\Category; use Illuminate\Support\Collection; /** * Class CacheProperties. + * * @codeCoverageIgnore */ class CacheProperties @@ -49,8 +52,8 @@ class CacheProperties } /** - * @param $property - * @param Collection|\Carbon\Carbon|\FireflyIII\Models\Category|array|int|string $property + * @param $property + * @param Collection|Carbon|Category|array|int|string $property */ public function addProperty($property): void { @@ -86,15 +89,6 @@ class CacheProperties return Cache::has($this->hash); } - /** - * @param $data - * @param (array|mixed)[]|Collection|\Carbon\Carbon|string $data - */ - public function store($data): void - { - Cache::forever($this->hash, $data); - } - /** */ private function hash(): void @@ -105,4 +99,13 @@ class CacheProperties } $this->hash = substr(hash('sha256', $content), 0, 16); } + + /** + * @param $data + * @param (array|mixed)[]|Collection|\Carbon\Carbon|string $data + */ + public function store($data): void + { + Cache::forever($this->hash, $data); + } } diff --git a/app/Support/Chart/Budget/FrontpageChartGenerator.php b/app/Support/Chart/Budget/FrontpageChartGenerator.php index 89c75126fc..5496e0305b 100644 --- a/app/Support/Chart/Budget/FrontpageChartGenerator.php +++ b/app/Support/Chart/Budget/FrontpageChartGenerator.php @@ -37,13 +37,13 @@ use Illuminate\Support\Collection; */ class FrontpageChartGenerator { - private User $user; - private Carbon $start; - private Carbon $end; - private BudgetRepositoryInterface $budgetRepository; - private BudgetLimitRepositoryInterface $blRepository; protected OperationsRepositoryInterface $opsRepository; + private BudgetLimitRepositoryInterface $blRepository; + private BudgetRepositoryInterface $budgetRepository; + private Carbon $end; private string $monthAndDayFormat; + private Carbon $start; + private User $user; /** * FrontpageChartGenerator constructor. @@ -79,38 +79,6 @@ class FrontpageChartGenerator return $data; } - /** - * A basic setter for the user. Also updates the repositories with the right user. - * - * @param User $user - */ - public function setUser(User $user): void - { - $this->user = $user; - $this->budgetRepository->setUser($user); - $this->blRepository->setUser($user); - $this->opsRepository->setUser($user); - - $locale = app('steam')->getLocale(); - $this->monthAndDayFormat = (string)trans('config.month_and_day', [], $locale); - } - - /** - * @param Carbon $start - */ - public function setStart(Carbon $start): void - { - $this->start = $start; - } - - /** - * @param Carbon $end - */ - public function setEnd(Carbon $end): void - { - $this->end = $end; - } - /** * For each budget, gets all budget limits for the current time range. * When no limits are present, the time range is used to collect information on money spent. @@ -238,5 +206,37 @@ class FrontpageChartGenerator return $data; } + /** + * @param Carbon $end + */ + public function setEnd(Carbon $end): void + { + $this->end = $end; + } + + /** + * @param Carbon $start + */ + public function setStart(Carbon $start): void + { + $this->start = $start; + } + + /** + * A basic setter for the user. Also updates the repositories with the right user. + * + * @param User $user + */ + public function setUser(User $user): void + { + $this->user = $user; + $this->budgetRepository->setUser($user); + $this->blRepository->setUser($user); + $this->opsRepository->setUser($user); + + $locale = app('steam')->getLocale(); + $this->monthAndDayFormat = (string)trans('config.month_and_day', [], $locale); + } + } diff --git a/app/Support/Chart/Category/FrontpageChartGenerator.php b/app/Support/Chart/Category/FrontpageChartGenerator.php index 1df9f7e456..1969448183 100644 --- a/app/Support/Chart/Category/FrontpageChartGenerator.php +++ b/app/Support/Chart/Category/FrontpageChartGenerator.php @@ -99,6 +99,29 @@ class FrontpageChartGenerator return $this->insertValues($currencyData, $tempData); } + /** + * @param Category $category + * @param Collection $accounts + * + * @return array + */ + private function collectExpenses(Category $category, Collection $accounts): array + { + $spent = $this->opsRepos->sumExpenses($this->start, $this->end, $accounts, new Collection([$category])); + $tempData = []; + foreach ($spent as $currency) { + $this->addCurrency($currency); + $tempData[] = [ + 'name' => $category->name, + 'sum' => $currency['sum'], + 'sum_float' => round((float)$currency['sum'], $currency['currency_decimal_places']), + 'currency_id' => (int)$currency['currency_id'], + ]; + } + + return $tempData; + } + /** * @param array $currency */ @@ -115,29 +138,6 @@ class FrontpageChartGenerator ]; } - /** - * @param Category $category - * @param Collection $accounts - * - * @return array - */ - private function collectExpenses(Category $category, Collection $accounts): array - { - $spent = $this->opsRepos->sumExpenses($this->start, $this->end, $accounts, new Collection([$category])); - $tempData = []; - foreach ($spent as $currency) { - $this->addCurrency($currency); - $tempData[] = [ - 'name' => $category->name, - 'sum' => $currency['sum'], - 'sum_float' => round((float) $currency['sum'], $currency['currency_decimal_places']), - 'currency_id' => (int)$currency['currency_id'], - ]; - } - - return $tempData; - } - /** * @param Collection $accounts * @@ -152,7 +152,7 @@ class FrontpageChartGenerator $tempData[] = [ 'name' => trans('firefly.no_category'), 'sum' => $currency['sum'], - 'sum_float' => round((float) $currency['sum'], $currency['currency_decimal_places'] ?? 2), + 'sum_float' => round((float)$currency['sum'], $currency['currency_decimal_places'] ?? 2), 'currency_id' => (int)$currency['currency_id'], ]; } diff --git a/app/Support/Chart/Category/WholePeriodChartGenerator.php b/app/Support/Chart/Category/WholePeriodChartGenerator.php index e957d83384..b79592cf19 100644 --- a/app/Support/Chart/Category/WholePeriodChartGenerator.php +++ b/app/Support/Chart/Category/WholePeriodChartGenerator.php @@ -27,10 +27,8 @@ use Carbon\Carbon; use FireflyIII\Models\AccountType; use FireflyIII\Models\Category; use FireflyIII\Repositories\Account\AccountRepositoryInterface; -use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\OperationsRepositoryInterface; use Illuminate\Support\Collection; -use Log; /** * Class WholePeriodChartGenerator @@ -109,8 +107,8 @@ class WholePeriodChartGenerator $earnedInfoKey = sprintf('earned-in-%s', $code); $spentAmount = $spent[$key][$currencyId]['sum'] ?? '0'; $earnedAmount = $earned[$key][$currencyId]['sum'] ?? '0'; - $chartData[$spentInfoKey]['entries'][$label] = round((float) $spentAmount, $currency['currency_decimal_places']); - $chartData[$earnedInfoKey]['entries'][$label] = round((float) $earnedAmount, $currency['currency_decimal_places']); + $chartData[$spentInfoKey]['entries'][$label] = round((float)$spentAmount, $currency['currency_decimal_places']); + $chartData[$earnedInfoKey]['entries'][$label] = round((float)$earnedAmount, $currency['currency_decimal_places']); } $current = app('navigation')->addPeriod($current, $step, 0); } diff --git a/app/Support/ChartColour.php b/app/Support/ChartColour.php index 518a834bcd..2969a496d3 100644 --- a/app/Support/ChartColour.php +++ b/app/Support/ChartColour.php @@ -24,6 +24,7 @@ namespace FireflyIII\Support; /** * Class ChartColour. + * * @codeCoverageIgnore */ class ChartColour diff --git a/app/Support/Cronjobs/AbstractCronjob.php b/app/Support/Cronjobs/AbstractCronjob.php index b5ab855754..e9f815dbd9 100644 --- a/app/Support/Cronjobs/AbstractCronjob.php +++ b/app/Support/Cronjobs/AbstractCronjob.php @@ -25,6 +25,7 @@ namespace FireflyIII\Support\Cronjobs; use Carbon\Carbon; use Exception; + /** * Class AbstractCronjob * @@ -34,12 +35,10 @@ abstract class AbstractCronjob { /** @var int */ public $timeBetweenRuns = 43200; - - /** @var bool */ - protected $force; - /** @var Carbon */ protected $date; + /** @var bool */ + protected $force; /** * AbstractCronjob constructor. @@ -52,15 +51,10 @@ abstract class AbstractCronjob $this->date = today(config('app.timezone')); } - - /** - * @param bool $force + * @return bool */ - public function setForce(bool $force): void - { - $this->force = $force; - } + abstract public function fire(): bool; /** * @param Carbon $date @@ -71,8 +65,11 @@ abstract class AbstractCronjob } /** - * @return bool + * @param bool $force */ - abstract public function fire(): bool; + public function setForce(bool $force): void + { + $this->force = $force; + } } diff --git a/app/Support/Cronjobs/RecurringCronjob.php b/app/Support/Cronjobs/RecurringCronjob.php index 6e5cd4b7a3..ebf4f73525 100644 --- a/app/Support/Cronjobs/RecurringCronjob.php +++ b/app/Support/Cronjobs/RecurringCronjob.php @@ -86,7 +86,7 @@ class RecurringCronjob extends AbstractCronjob $job->setForce($this->force); $job->handle(); app('fireflyconfig')->set('last_rt_job', (int)$this->date->format('U')); - Log::info(sprintf('Marked the last time this job has run as "%s" (%d)',$this->date->format('Y-m-d H:i:s'),(int)$this->date->format('U'))); + Log::info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int)$this->date->format('U'))); Log::info('Done with recurring cron job task.'); } } diff --git a/app/Support/Cronjobs/TelemetryCronjob.php b/app/Support/Cronjobs/TelemetryCronjob.php index c659166384..de4df4adae 100644 --- a/app/Support/Cronjobs/TelemetryCronjob.php +++ b/app/Support/Cronjobs/TelemetryCronjob.php @@ -45,13 +45,14 @@ class TelemetryCronjob extends AbstractCronjob // do not fire if telemetry is disabled. if (false === config('firefly.send_telemetry') || false === config('firefly.feature_flags.telemetry')) { Log::warning('Telemetry is disabled. The cron job will do nothing.'); + return false; } /** @var Configuration $config */ $config = app('fireflyconfig')->get('last_tm_job', 0); - $lastTime = (int) $config->data; + $lastTime = (int)$config->data; $diff = time() - $lastTime; $diffForHumans = Carbon::now()->diffForHumans(Carbon::createFromTimestamp($lastTime), true); if (0 === $lastTime) { @@ -98,7 +99,7 @@ class TelemetryCronjob extends AbstractCronjob // TODO remove old, submitted telemetry data. - app('fireflyconfig')->set('last_tm_job', (int) $this->date->format('U')); + app('fireflyconfig')->set('last_tm_job', (int)$this->date->format('U')); Log::info('Done with telemetry cron job task.'); } } diff --git a/app/Support/Domain.php b/app/Support/Domain.php index e06821b560..94beefa05e 100644 --- a/app/Support/Domain.php +++ b/app/Support/Domain.php @@ -24,6 +24,7 @@ namespace FireflyIII\Support; /** * Class Domain. + * * @codeCoverageIgnore */ class Domain diff --git a/app/Support/ExpandedForm.php b/app/Support/ExpandedForm.php index 7a48c38b11..d5fb36f40a 100644 --- a/app/Support/ExpandedForm.php +++ b/app/Support/ExpandedForm.php @@ -39,10 +39,11 @@ use Throwable; class ExpandedForm { use FormSupport; + /** * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string * @@ -59,7 +60,7 @@ class ExpandedForm // make sure value is formatted nicely: if (null !== $value && '' !== $value) { - $value = round((float) $value, 8); + $value = round((float)$value, 8); } try { $html = prefixView('form.amount-no-currency', compact('classes', 'name', 'label', 'value', 'options'))->render(); @@ -73,9 +74,9 @@ class ExpandedForm /** * @param string $name - * @param int $value - * @param mixed $checked - * @param array $options + * @param int $value + * @param mixed $checked + * @param array $options * * @return string * @@ -109,8 +110,8 @@ class ExpandedForm /** * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string * @@ -134,7 +135,7 @@ class ExpandedForm /** * @param string $name - * @param array $options + * @param array $options * * @return string * @@ -157,8 +158,8 @@ class ExpandedForm /** * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string * @@ -183,8 +184,8 @@ class ExpandedForm /** * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string * @@ -207,7 +208,7 @@ class ExpandedForm } /** - * @param \Illuminate\Support\Collection $set + * @param Collection $set * * @return array * @@ -235,8 +236,8 @@ class ExpandedForm /** * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string */ @@ -252,7 +253,7 @@ class ExpandedForm // make sure value is formatted nicely: if (null !== $value && '' !== $value) { - $value = round((float) $value, $selectedCurrency->decimal_places); + $value = round((float)$value, $selectedCurrency->decimal_places); } try { $html = prefixView('form.non-selectable-amount', compact('selectedCurrency', 'classes', 'name', 'label', 'value', 'options'))->render(); @@ -266,8 +267,8 @@ class ExpandedForm /** * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string * @@ -290,153 +291,6 @@ class ExpandedForm return $html; } - /** - * @param string $type - * @param string $name - * - * @return string - * - */ - public function optionsList(string $type, string $name): string - { - try { - $html = prefixView('form.options', compact('type', 'name'))->render(); - } catch (Throwable $e) { - Log::debug(sprintf('Could not render select(): %s', $e->getMessage())); - $html = 'Could not render optionsList.'; - } - - return $html; - } - - /** - * @param string $name - * @param array $options - * - * @return string - * - */ - public function password(string $name, array $options = null): string - { - - $label = $this->label($name, $options); - $options = $this->expandOptionArray($name, $label, $options); - $classes = $this->getHolderClasses($name); - try { - $html = prefixView('form.password', compact('classes', 'name', 'label', 'options'))->render(); - } catch (Throwable $e) { - Log::debug(sprintf('Could not render password(): %s', $e->getMessage())); - $html = 'Could not render password.'; - } - - return $html; - } - - /** - * Function to render a percentage. - * - * @param string $name - * @param mixed $value - * @param array $options - * - * @return string - * - */ - public function percentage(string $name, $value = null, array $options = null): string - { - $label = $this->label($name, $options); - $options = $this->expandOptionArray($name, $label, $options); - $classes = $this->getHolderClasses($name); - $value = $this->fillFieldValue($name, $value); - $options['step'] = 'any'; - unset($options['placeholder']); - try { - $html = prefixView('form.percentage', compact('classes', 'name', 'label', 'value', 'options'))->render(); - } catch (Throwable $e) { - Log::debug(sprintf('Could not render percentage(): %s', $e->getMessage())); - $html = 'Could not render percentage.'; - } - - return $html; - } - - /** - * @param string $name - * @param mixed $value - * @param array $options - * - * @return string - * - */ - public function staticText(string $name, $value, array $options = null): string - { - $label = $this->label($name, $options); - $options = $this->expandOptionArray($name, $label, $options); - $classes = $this->getHolderClasses($name); - try { - $html = prefixView('form.static', compact('classes', 'name', 'label', 'value', 'options'))->render(); - } catch (Throwable $e) { - Log::debug(sprintf('Could not render staticText(): %s', $e->getMessage())); - $html = 'Could not render staticText.'; - } - - return $html; - } - - /** - * @param string $name - * @param mixed $value - * @param array $options - * - * @return string - * - */ - public function text(string $name, $value = null, array $options = null): string - { - $label = $this->label($name, $options); - $options = $this->expandOptionArray($name, $label, $options); - $classes = $this->getHolderClasses($name); - $value = $this->fillFieldValue($name, $value); - try { - $html = prefixView('form.text', compact('classes', 'name', 'label', 'value', 'options'))->render(); - } catch (Throwable $e) { - Log::debug(sprintf('Could not render text(): %s', $e->getMessage())); - $html = 'Could not render text.'; - } - - return $html; - } - - /** - * @param string $name - * @param mixed $value - * @param array $options - * - * @return string - * - */ - public function textarea(string $name, $value = null, array $options = null): string - { - $label = $this->label($name, $options); - $options = $this->expandOptionArray($name, $label, $options); - $classes = $this->getHolderClasses($name); - $value = $this->fillFieldValue($name, $value); - $options['rows'] = 4; - - if (null === $value) { - $value = ''; - } - - try { - $html = prefixView('form.textarea', compact('classes', 'name', 'label', 'value', 'options'))->render(); - } catch (Throwable $e) { - Log::debug(sprintf('Could not render textarea(): %s', $e->getMessage())); - $html = 'Could not render textarea.'; - } - - return $html; - } - /** * @param null $value * @param array|null $options @@ -465,4 +319,151 @@ class ExpandedForm return $html; } + + /** + * @param string $type + * @param string $name + * + * @return string + * + */ + public function optionsList(string $type, string $name): string + { + try { + $html = prefixView('form.options', compact('type', 'name'))->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Could not render select(): %s', $e->getMessage())); + $html = 'Could not render optionsList.'; + } + + return $html; + } + + /** + * @param string $name + * @param array $options + * + * @return string + * + */ + public function password(string $name, array $options = null): string + { + + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + try { + $html = prefixView('form.password', compact('classes', 'name', 'label', 'options'))->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Could not render password(): %s', $e->getMessage())); + $html = 'Could not render password.'; + } + + return $html; + } + + /** + * Function to render a percentage. + * + * @param string $name + * @param mixed $value + * @param array $options + * + * @return string + * + */ + public function percentage(string $name, $value = null, array $options = null): string + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $options['step'] = 'any'; + unset($options['placeholder']); + try { + $html = prefixView('form.percentage', compact('classes', 'name', 'label', 'value', 'options'))->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Could not render percentage(): %s', $e->getMessage())); + $html = 'Could not render percentage.'; + } + + return $html; + } + + /** + * @param string $name + * @param mixed $value + * @param array $options + * + * @return string + * + */ + public function staticText(string $name, $value, array $options = null): string + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + try { + $html = prefixView('form.static', compact('classes', 'name', 'label', 'value', 'options'))->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Could not render staticText(): %s', $e->getMessage())); + $html = 'Could not render staticText.'; + } + + return $html; + } + + /** + * @param string $name + * @param mixed $value + * @param array $options + * + * @return string + * + */ + public function text(string $name, $value = null, array $options = null): string + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + try { + $html = prefixView('form.text', compact('classes', 'name', 'label', 'value', 'options'))->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Could not render text(): %s', $e->getMessage())); + $html = 'Could not render text.'; + } + + return $html; + } + + /** + * @param string $name + * @param mixed $value + * @param array $options + * + * @return string + * + */ + public function textarea(string $name, $value = null, array $options = null): string + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $options['rows'] = 4; + + if (null === $value) { + $value = ''; + } + + try { + $html = prefixView('form.textarea', compact('classes', 'name', 'label', 'value', 'options'))->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Could not render textarea(): %s', $e->getMessage())); + $html = 'Could not render textarea.'; + } + + return $html; + } } diff --git a/app/Support/Export/ExportDataGenerator.php b/app/Support/Export/ExportDataGenerator.php index e54ce6c6d8..612c10b818 100644 --- a/app/Support/Export/ExportDataGenerator.php +++ b/app/Support/Export/ExportDataGenerator.php @@ -51,6 +51,7 @@ use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; use FireflyIII\User; use Illuminate\Support\Collection; +use League\Csv\CannotInsertRecord; use League\Csv\Writer; /** @@ -58,19 +59,19 @@ use League\Csv\Writer; */ class ExportDataGenerator { + private Collection $accounts; private Carbon $end; - private bool $exportTransactions; - private Carbon $start; private bool $exportAccounts; + private bool $exportBills; private bool $exportBudgets; private bool $exportCategories; - private bool $exportTags; + private bool $exportPiggies; private bool $exportRecurring; private bool $exportRules; - private bool $exportBills; - private bool $exportPiggies; + private bool $exportTags; + private bool $exportTransactions; + private Carbon $start; private User $user; - private Collection $accounts; public function __construct() { @@ -89,25 +90,9 @@ class ExportDataGenerator $this->exportPiggies = false; } - /** - * @param User $user - */ - public function setUser(User $user): void - { - $this->user = $user; - } - - /** - * @param Collection $accounts - */ - public function setAccounts(Collection $accounts): void - { - $this->accounts = $accounts; - } - /** * @return array - * @throws \League\Csv\CannotInsertRecord + * @throws CannotInsertRecord */ public function export(): array { @@ -143,150 +128,6 @@ class ExportDataGenerator return $return; } - /** - * @param bool $exportAccounts - */ - public function setExportAccounts(bool $exportAccounts): void - { - $this->exportAccounts = $exportAccounts; - } - - /** - * @param bool $exportBudgets - */ - public function setExportBudgets(bool $exportBudgets): void - { - $this->exportBudgets = $exportBudgets; - } - - /** - * @param bool $exportCategories - */ - public function setExportCategories(bool $exportCategories): void - { - $this->exportCategories = $exportCategories; - } - - /** - * @param bool $exportTags - */ - public function setExportTags(bool $exportTags): void - { - $this->exportTags = $exportTags; - } - - /** - * @param bool $exportRecurring - */ - public function setExportRecurring(bool $exportRecurring): void - { - $this->exportRecurring = $exportRecurring; - } - - /** - * @param bool $exportRules - */ - public function setExportRules(bool $exportRules): void - { - $this->exportRules = $exportRules; - } - - /** - * @param bool $exportBills - */ - public function setExportBills(bool $exportBills): void - { - $this->exportBills = $exportBills; - } - - /** - * @param bool $exportPiggies - */ - public function setExportPiggies(bool $exportPiggies): void - { - $this->exportPiggies = $exportPiggies; - } - - /** - * @param Carbon $end - */ - public function setEnd(Carbon $end): void - { - $this->end = $end; - } - - /** - * @param bool $exportTransactions - */ - public function setExportTransactions(bool $exportTransactions): void - { - $this->exportTransactions = $exportTransactions; - } - - /** - * @param Carbon $start - */ - public function setStart(Carbon $start): void - { - $this->start = $start; - } - - /** - * @return string - */ - private function exportRules(): string - { - $header = ['user_id', 'rule_id', 'row_contains', 'created_at', 'updated_at', 'group_id', 'group_name', 'title', 'description', 'order', 'active', - 'stop_processing', 'strict', 'trigger_type', 'trigger_value', 'trigger_order', 'trigger_active', 'trigger_stop_processing', 'action_type', - 'action_value', 'action_order', 'action_active', 'action_stop_processing',]; - $ruleRepos = app(RuleRepositoryInterface::class); - $ruleRepos->setUser($this->user); - $rules = $ruleRepos->getAll(); - $records = []; - /** @var Rule $rule */ - foreach ($rules as $rule) { - $records[] = [ - $this->user->id, $rule->id, 'rule', - $rule->created_at->toAtomString(), $rule->updated_at->toAtomString(), - $rule->ruleGroup->id, $rule->ruleGroup->name, - $rule->title, $rule->description, $rule->order, $rule->active, $rule->stop_processing, $rule->strict, - ]; - /** @var RuleTrigger $trigger */ - foreach ($rule->ruleTriggers as $trigger) { - $records[] = [ - $this->user->id, $rule->id, 'trigger', - null, null, - null, null, - null, null, null, null, null, null, - $trigger->trigger_type, $trigger->trigger_value, $trigger->order, $trigger->active, $trigger->stop_processing, - ]; - } - - /** @var RuleAction $action */ - foreach ($rule->ruleActions as $action) { - $records[] = [ - $this->user->id, $rule->id, 'action', - null, null, - null, null, - null, null, null, null, null, null, - null, null, null, null, null, - $action->action_type, $action->action_value, $action->order, $action->active, $action->stop_processing, - ]; - } - } - - //load the CSV document from a string - $csv = Writer::createFromString(''); - - //insert the header - $csv->insertOne($header); - - //insert all the records - $csv->insertAll($records); - - return $csv->getContent(); //returns the CSV document as a string - } - /** * @return string */ @@ -380,7 +221,7 @@ class ExportDataGenerator /** * @return string - * @throws \League\Csv\CannotInsertRecord + * @throws CannotInsertRecord */ private function exportBudgets(): string { @@ -610,6 +451,62 @@ class ExportDataGenerator return $csv->getContent(); //returns the CSV document as a string } + /** + * @return string + */ + private function exportRules(): string + { + $header = ['user_id', 'rule_id', 'row_contains', 'created_at', 'updated_at', 'group_id', 'group_name', 'title', 'description', 'order', 'active', + 'stop_processing', 'strict', 'trigger_type', 'trigger_value', 'trigger_order', 'trigger_active', 'trigger_stop_processing', 'action_type', + 'action_value', 'action_order', 'action_active', 'action_stop_processing',]; + $ruleRepos = app(RuleRepositoryInterface::class); + $ruleRepos->setUser($this->user); + $rules = $ruleRepos->getAll(); + $records = []; + /** @var Rule $rule */ + foreach ($rules as $rule) { + $records[] = [ + $this->user->id, $rule->id, 'rule', + $rule->created_at->toAtomString(), $rule->updated_at->toAtomString(), + $rule->ruleGroup->id, $rule->ruleGroup->name, + $rule->title, $rule->description, $rule->order, $rule->active, $rule->stop_processing, $rule->strict, + ]; + /** @var RuleTrigger $trigger */ + foreach ($rule->ruleTriggers as $trigger) { + $records[] = [ + $this->user->id, $rule->id, 'trigger', + null, null, + null, null, + null, null, null, null, null, null, + $trigger->trigger_type, $trigger->trigger_value, $trigger->order, $trigger->active, $trigger->stop_processing, + ]; + } + + /** @var RuleAction $action */ + foreach ($rule->ruleActions as $action) { + $records[] = [ + $this->user->id, $rule->id, 'action', + null, null, + null, null, + null, null, null, null, null, null, + null, null, null, null, null, + $action->action_type, $action->action_value, $action->order, $action->active, $action->stop_processing, + ]; + } + } + + //load the CSV document from a string + $csv = Writer::createFromString(''); + + //insert the header + $csv->insertOne($header); + + //insert all the records + $csv->insertAll($records); + + return $csv->getContent(); //returns the CSV document as a string + } + /** * @return string */ @@ -668,7 +565,7 @@ class ExportDataGenerator $collector->setUser($this->user); $collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation() ->withBudgetInformation()->withTagInformation()->withNotes(); - if(0 !== $this->accounts->count()) { + if (0 !== $this->accounts->count()) { $collector->setAccounts($this->accounts); } @@ -776,4 +673,108 @@ class ExportDataGenerator return implode(',', $smol); } + /** + * @param Collection $accounts + */ + public function setAccounts(Collection $accounts): void + { + $this->accounts = $accounts; + } + + /** + * @param Carbon $end + */ + public function setEnd(Carbon $end): void + { + $this->end = $end; + } + + /** + * @param bool $exportAccounts + */ + public function setExportAccounts(bool $exportAccounts): void + { + $this->exportAccounts = $exportAccounts; + } + + /** + * @param bool $exportBills + */ + public function setExportBills(bool $exportBills): void + { + $this->exportBills = $exportBills; + } + + /** + * @param bool $exportBudgets + */ + public function setExportBudgets(bool $exportBudgets): void + { + $this->exportBudgets = $exportBudgets; + } + + /** + * @param bool $exportCategories + */ + public function setExportCategories(bool $exportCategories): void + { + $this->exportCategories = $exportCategories; + } + + /** + * @param bool $exportPiggies + */ + public function setExportPiggies(bool $exportPiggies): void + { + $this->exportPiggies = $exportPiggies; + } + + /** + * @param bool $exportRecurring + */ + public function setExportRecurring(bool $exportRecurring): void + { + $this->exportRecurring = $exportRecurring; + } + + /** + * @param bool $exportRules + */ + public function setExportRules(bool $exportRules): void + { + $this->exportRules = $exportRules; + } + + /** + * @param bool $exportTags + */ + public function setExportTags(bool $exportTags): void + { + $this->exportTags = $exportTags; + } + + /** + * @param bool $exportTransactions + */ + public function setExportTransactions(bool $exportTransactions): void + { + $this->exportTransactions = $exportTransactions; + } + + /** + * @param Carbon $start + */ + public function setStart(Carbon $start): void + { + $this->start = $start; + } + + /** + * @param User $user + */ + public function setUser(User $user): void + { + $this->user = $user; + } + } diff --git a/app/Support/Facades/Preferences.php b/app/Support/Facades/Preferences.php index 4c1fc36bbc..049ea2f34a 100644 --- a/app/Support/Facades/Preferences.php +++ b/app/Support/Facades/Preferences.php @@ -27,6 +27,7 @@ use FireflyIII\User; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Facade; use Log; + /** * @codeCoverageIgnore * Class Preferences. diff --git a/app/Support/FireflyConfig.php b/app/Support/FireflyConfig.php index 97504e757a..de5e3cd02f 100644 --- a/app/Support/FireflyConfig.php +++ b/app/Support/FireflyConfig.php @@ -31,6 +31,7 @@ use Log; /** * Class FireflyConfig. + * * @codeCoverageIgnore */ class FireflyConfig @@ -67,8 +68,8 @@ class FireflyConfig * @param string $name * @param null $default * - * @throws FireflyException * @return Configuration|null + * @throws FireflyException */ public function get(string $name, $default = null): ?Configuration { @@ -80,7 +81,7 @@ class FireflyConfig try { /** @var Configuration $config */ $config = Configuration::where('name', $name)->first(['id', 'name', 'data']); - } catch (QueryException|Exception $e) { + } catch (QueryException | Exception $e) { throw new FireflyException(sprintf('Could not poll the database: %s', $e->getMessage())); } @@ -99,7 +100,7 @@ class FireflyConfig /** * @param string $name - * @param mixed $default + * @param mixed $default * * @return \FireflyIII\Models\Configuration|null */ @@ -132,8 +133,8 @@ class FireflyConfig } /** - * @param string $name - * @param $value + * @param string $name + * @param $value * @param int|string|true $value * * @return Configuration @@ -143,7 +144,7 @@ class FireflyConfig /** @var Configuration $config */ try { $config = Configuration::whereName($name)->first(); - } catch (QueryException|Exception $e) { + } catch (QueryException | Exception $e) { $item = new Configuration; $item->name = $name; $item->data = $value; diff --git a/app/Support/Form/AccountForm.php b/app/Support/Form/AccountForm.php index edf9cea406..d1bff36c9e 100644 --- a/app/Support/Form/AccountForm.php +++ b/app/Support/Form/AccountForm.php @@ -42,18 +42,39 @@ class AccountForm { use FormSupport; + /** + * Grouped dropdown list of all accounts that are valid as the destination of a withdrawal. + * + * @param string $name + * @param mixed $value + * @param array $options + * + * @return string + */ + public function activeDepositDestinations(string $name, $value = null, array $options = null): string + { + $types = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN, AccountType::REVENUE,]; + $repository = $this->getAccountRepository(); + $grouped = $this->getAccountsGrouped($types, $repository); + $cash = $repository->getCashAccount(); + $key = (string)trans('firefly.cash_account_type'); + $grouped[$key][$cash->id] = sprintf('(%s)', (string)trans('firefly.cash')); + + return $this->select($name, $grouped, $value, $options); + } + private function getAccountsGrouped(array $types, AccountRepositoryInterface $repository = null): array { if (null === $repository) { $repository = $this->getAccountRepository(); } - $accountList = $repository->getActiveAccountsByType($types); - $liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,]; - $grouped = []; + $accountList = $repository->getActiveAccountsByType($types); + $liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,]; + $grouped = []; /** @var Account $account */ foreach ($accountList as $account) { - $role = (string)$repository->getMetaValue($account, 'account_role'); + $role = (string)$repository->getMetaValue($account, 'account_role'); if (in_array($account->accountType->type, $liabilityTypes, true)) { $role = sprintf('l_%s', $account->accountType->type); } elseif ('' === $role) { @@ -65,7 +86,7 @@ class AccountForm $role = 'no_account_type'; } } - $key = (string) trans(sprintf('firefly.opt_group_%s', $role)); + $key = (string)trans(sprintf('firefly.opt_group_%s', $role)); $grouped[$key][$account->id] = $account->name; } @@ -76,8 +97,8 @@ class AccountForm * Grouped dropdown list of all accounts that are valid as the destination of a withdrawal. * * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string */ @@ -94,33 +115,11 @@ class AccountForm return $this->select($name, $grouped, $value, $options); } - /** - * Grouped dropdown list of all accounts that are valid as the destination of a withdrawal. - * - * @param string $name - * @param mixed $value - * @param array $options - * - * @return string - */ - public function activeDepositDestinations(string $name, $value = null, array $options = null): string - { - $types = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN, AccountType::REVENUE,]; - $repository = $this->getAccountRepository(); - $grouped = $this->getAccountsGrouped($types, $repository); - $cash = $repository->getCashAccount(); - $key = (string)trans('firefly.cash_account_type'); - $grouped[$key][$cash->id] = sprintf('(%s)', (string)trans('firefly.cash')); - - return $this->select($name, $grouped, $value, $options); - } - - /** * Check list of asset accounts. * * @param string $name - * @param array $options + * @param array $options * * @return string * @@ -134,8 +133,8 @@ class AccountForm $selected = request()->old($name) ?? []; // get all asset accounts: - $types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT]; - $grouped = $this->getAccountsGrouped($types); + $types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT]; + $grouped = $this->getAccountsGrouped($types); unset($options['class']); try { @@ -152,8 +151,8 @@ class AccountForm * Basic list of asset accounts. * * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string */ @@ -170,8 +169,8 @@ class AccountForm * Same list but all liabilities as well. * * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string */ diff --git a/app/Support/Form/CurrencyForm.php b/app/Support/Form/CurrencyForm.php index c75f270579..907d7b867a 100644 --- a/app/Support/Form/CurrencyForm.php +++ b/app/Support/Form/CurrencyForm.php @@ -44,56 +44,67 @@ class CurrencyForm use FormSupport; /** - * TODO cleanup and describe. * @param string $name * @param mixed $value * @param array $options * * @return string */ - public function currencyList(string $name, $value = null, array $options = null): string + public function amount(string $name, $value = null, array $options = null): string { - /** @var CurrencyRepositoryInterface $currencyRepos */ - $currencyRepos = app(CurrencyRepositoryInterface::class); - - // get all currencies: - $list = $currencyRepos->get(); - $array = []; - /** @var TransactionCurrency $currency */ - foreach ($list as $currency) { - $array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')'; - } - - return $this->select($name, $array, $value, $options); + return $this->currencyField($name, 'amount', $value, $options); } /** - * TODO cleanup and describe. - * * @param string $name + * @param string $view * @param mixed $value * @param array $options * * @return string + * */ - public function currencyListEmpty(string $name, $value = null, array $options = null): string + protected function currencyField(string $name, string $view, $value = null, array $options = null): string { - /** @var CurrencyRepositoryInterface $currencyRepos */ - $currencyRepos = app(CurrencyRepositoryInterface::class); + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $options['step'] = 'any'; + $defaultCurrency = $options['currency'] ?? Amt::getDefaultCurrency(); + /** @var Collection $currencies */ + $currencies = app('amount')->getCurrencies(); + unset($options['currency'], $options['placeholder']); - // get all currencies: - $list = $currencyRepos->get(); - $array = [ - 0 => (string)trans('firefly.no_currency'), - ]; - /** @var TransactionCurrency $currency */ - foreach ($list as $currency) { - $array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')'; + // perhaps the currency has been sent to us in the field $amount_currency_id_$name (amount_currency_id_amount) + $preFilled = session('preFilled'); + $key = 'amount_currency_id_' . $name; + $sentCurrencyId = isset($preFilled[$key]) ? (int)$preFilled[$key] : $defaultCurrency->id; + + Log::debug(sprintf('Sent currency ID is %d', $sentCurrencyId)); + + // find this currency in set of currencies: + foreach ($currencies as $currency) { + if ($currency->id === $sentCurrencyId) { + $defaultCurrency = $currency; + Log::debug(sprintf('default currency is now %s', $defaultCurrency->code)); + break; + } } - return $this->select($name, $array, $value, $options); - } + // make sure value is formatted nicely: + if (null !== $value && '' !== $value) { + $value = round((float)$value, $defaultCurrency->decimal_places); + } + try { + $html = prefixView('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Could not render currencyField(): %s', $e->getMessage())); + $html = 'Could not render currencyField.'; + } + return $html; + } /** * TODO describe and cleanup. @@ -151,7 +162,7 @@ class CurrencyForm // make sure value is formatted nicely: if (null !== $value && '' !== $value) { - $value = round((float) $value, $defaultCurrency->decimal_places); + $value = round((float)$value, $defaultCurrency->decimal_places); } try { $html = prefixView('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); @@ -164,66 +175,55 @@ class CurrencyForm } /** + * TODO cleanup and describe. + * * @param string $name - * @param string $view * @param mixed $value * @param array $options * * @return string - * */ - protected function currencyField(string $name, string $view, $value = null, array $options = null): string + public function currencyList(string $name, $value = null, array $options = null): string { - $label = $this->label($name, $options); - $options = $this->expandOptionArray($name, $label, $options); - $classes = $this->getHolderClasses($name); - $value = $this->fillFieldValue($name, $value); - $options['step'] = 'any'; - $defaultCurrency = $options['currency'] ?? Amt::getDefaultCurrency(); - /** @var Collection $currencies */ - $currencies = app('amount')->getCurrencies(); - unset($options['currency'], $options['placeholder']); + /** @var CurrencyRepositoryInterface $currencyRepos */ + $currencyRepos = app(CurrencyRepositoryInterface::class); - // perhaps the currency has been sent to us in the field $amount_currency_id_$name (amount_currency_id_amount) - $preFilled = session('preFilled'); - $key = 'amount_currency_id_' . $name; - $sentCurrencyId = isset($preFilled[$key]) ? (int)$preFilled[$key] : $defaultCurrency->id; - - Log::debug(sprintf('Sent currency ID is %d', $sentCurrencyId)); - - // find this currency in set of currencies: - foreach ($currencies as $currency) { - if ($currency->id === $sentCurrencyId) { - $defaultCurrency = $currency; - Log::debug(sprintf('default currency is now %s', $defaultCurrency->code)); - break; - } + // get all currencies: + $list = $currencyRepos->get(); + $array = []; + /** @var TransactionCurrency $currency */ + foreach ($list as $currency) { + $array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')'; } - // make sure value is formatted nicely: - if (null !== $value && '' !== $value) { - $value = round((float) $value, $defaultCurrency->decimal_places); - } - try { - $html = prefixView('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); - } catch (Throwable $e) { - Log::debug(sprintf('Could not render currencyField(): %s', $e->getMessage())); - $html = 'Could not render currencyField.'; - } - - return $html; + return $this->select($name, $array, $value, $options); } /** + * TODO cleanup and describe. + * * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string */ - public function amount(string $name, $value = null, array $options = null): string + public function currencyListEmpty(string $name, $value = null, array $options = null): string { - return $this->currencyField($name, 'amount', $value, $options); + /** @var CurrencyRepositoryInterface $currencyRepos */ + $currencyRepos = app(CurrencyRepositoryInterface::class); + + // get all currencies: + $list = $currencyRepos->get(); + $array = [ + 0 => (string)trans('firefly.no_currency'), + ]; + /** @var TransactionCurrency $currency */ + foreach ($list as $currency) { + $array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')'; + } + + return $this->select($name, $array, $value, $options); } } diff --git a/app/Support/Form/FormSupport.php b/app/Support/Form/FormSupport.php index 00e09cd728..af8a30ca7d 100644 --- a/app/Support/Form/FormSupport.php +++ b/app/Support/Form/FormSupport.php @@ -38,30 +38,6 @@ trait FormSupport { - /** - * @return AccountRepositoryInterface - */ - protected function getAccountRepository(): AccountRepositoryInterface - { - return app(AccountRepositoryInterface::class); - } - - /** - * @return Carbon - */ - protected function getDate(): Carbon - { - /** @var Carbon $date */ - $date = null; - try { - $date = today(config('app.timezone')); - } catch (Exception $e) { - $e->getMessage(); - } - - return $date; - } - /** * @param string $name * @param array $list @@ -88,6 +64,23 @@ trait FormSupport return $html; } + /** + * @param $name + * @param $options + * + * @return string + */ + protected function label(string $name, array $options = null): string + { + $options = $options ?? []; + if (isset($options['label'])) { + return $options['label']; + } + $name = str_replace('[]', '', $name); + + return (string)trans('form.' . $name); + } + /** * @param $name * @param $label @@ -107,6 +100,25 @@ trait FormSupport return $options; } + /** + * @param $name + * + * @return string + */ + protected function getHolderClasses(string $name): string + { + // Get errors from session: + /** @var MessageBag $errors */ + $errors = session('errors'); + $classes = 'form-group'; + + if (null !== $errors && $errors->has($name)) { + $classes = 'form-group has-error has-feedback'; + } + + return $classes; + } + /** * @param string $name * @param $value @@ -137,38 +149,26 @@ trait FormSupport } /** - * @param $name - * - * @return string + * @return AccountRepositoryInterface */ - protected function getHolderClasses(string $name): string + protected function getAccountRepository(): AccountRepositoryInterface { - // Get errors from session: - /** @var MessageBag $errors */ - $errors = session('errors'); - $classes = 'form-group'; - - if (null !== $errors && $errors->has($name)) { - $classes = 'form-group has-error has-feedback'; - } - - return $classes; + return app(AccountRepositoryInterface::class); } /** - * @param $name - * @param $options - * - * @return string + * @return Carbon */ - protected function label(string $name, array $options = null): string + protected function getDate(): Carbon { - $options = $options ?? []; - if (isset($options['label'])) { - return $options['label']; + /** @var Carbon $date */ + $date = null; + try { + $date = today(config('app.timezone')); + } catch (Exception $e) { + $e->getMessage(); } - $name = str_replace('[]', '', $name); - return (string)trans('form.' . $name); + return $date; } } diff --git a/app/Support/Form/PiggyBankForm.php b/app/Support/Form/PiggyBankForm.php index 017e01ac50..900b15a6b1 100644 --- a/app/Support/Form/PiggyBankForm.php +++ b/app/Support/Form/PiggyBankForm.php @@ -40,8 +40,8 @@ class PiggyBankForm * TODO cleanup and describe. * * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string */ @@ -51,7 +51,7 @@ class PiggyBankForm /** @var PiggyBankRepositoryInterface $repository */ $repository = app(PiggyBankRepositoryInterface::class); $piggyBanks = $repository->getPiggyBanksWithAmount(); - $title = (string) trans('firefly.default_group_title_name'); + $title = (string)trans('firefly.default_group_title_name'); $array = []; $subList = [ 0 => [ @@ -59,7 +59,7 @@ class PiggyBankForm 'title' => $title, ], 'piggies' => [ - (string) trans('firefly.none_in_select_list'), + (string)trans('firefly.none_in_select_list'), ], ], ]; diff --git a/app/Support/Form/RuleForm.php b/app/Support/Form/RuleForm.php index f8e277dc4b..b2ca38920e 100644 --- a/app/Support/Form/RuleForm.php +++ b/app/Support/Form/RuleForm.php @@ -36,10 +36,11 @@ use Illuminate\Support\HtmlString; class RuleForm { use FormSupport; + /** * @param string $name - * @param mixed $value - * @param array $options + * @param mixed $value + * @param array $options * * @return string */ @@ -60,8 +61,8 @@ class RuleForm } /** - * @param string $name - * @param null $value + * @param string $name + * @param null $value * @param array|null $options * * @return HtmlString diff --git a/app/Support/Http/Api/AccountFilter.php b/app/Support/Http/Api/AccountFilter.php index 3c7378aec2..8624181e5d 100644 --- a/app/Support/Http/Api/AccountFilter.php +++ b/app/Support/Http/Api/AccountFilter.php @@ -27,6 +27,7 @@ use FireflyIII\Models\AccountType; /** * Trait AccountFilter + * * @codeCoverageIgnore */ trait AccountFilter @@ -40,7 +41,7 @@ trait AccountFilter */ protected function mapAccountTypes(string $type): array { - $types = [ + $types = [ 'all' => [AccountType::DEFAULT, AccountType::CASH, AccountType::ASSET, AccountType::EXPENSE, AccountType::REVENUE, AccountType::INITIAL_BALANCE, AccountType::BENEFICIARY, AccountType::IMPORT, AccountType::RECONCILIATION, diff --git a/app/Support/Http/Api/ApiSupport.php b/app/Support/Http/Api/ApiSupport.php index 1f33b3074c..afe8de3b9e 100644 --- a/app/Support/Http/Api/ApiSupport.php +++ b/app/Support/Http/Api/ApiSupport.php @@ -28,6 +28,7 @@ use Illuminate\Support\Collection; /** * Trait ApiSupport + * * @codeCoverageIgnore */ trait ApiSupport diff --git a/app/Support/Http/Api/TransactionFilter.php b/app/Support/Http/Api/TransactionFilter.php index e6491a7ade..5dacf96b94 100644 --- a/app/Support/Http/Api/TransactionFilter.php +++ b/app/Support/Http/Api/TransactionFilter.php @@ -27,6 +27,7 @@ use FireflyIII\Models\TransactionType; /** * Trait TransactionFilter + * * @codeCoverageIgnore */ trait TransactionFilter @@ -40,7 +41,7 @@ trait TransactionFilter */ protected function mapTransactionTypes(string $type): array { - $types = [ + $types = [ 'all' => [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,], 'withdrawal' => [TransactionType::WITHDRAWAL,], @@ -59,6 +60,7 @@ trait TransactionFilter 'specials' => [TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,], 'default' => [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER,], ]; + return $types[$type] ?? $types['default']; diff --git a/app/Support/Http/Controllers/AugumentData.php b/app/Support/Http/Controllers/AugumentData.php index 6c1bcb637d..00709a4fe6 100644 --- a/app/Support/Http/Controllers/AugumentData.php +++ b/app/Support/Http/Controllers/AugumentData.php @@ -208,7 +208,7 @@ trait AugumentData $cache->addProperty('get-limits'); if ($cache->has()) { - return $cache->get(); // @codeCoverageIgnore + return $cache->get(); // @codeCoverageIgnore } $set = $blRepository->getBudgetLimits($budget, $start, $end); diff --git a/app/Support/Http/Controllers/CreateStuff.php b/app/Support/Http/Controllers/CreateStuff.php index 7343fcb892..adc307e205 100644 --- a/app/Support/Http/Controllers/CreateStuff.php +++ b/app/Support/Http/Controllers/CreateStuff.php @@ -30,6 +30,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\User; use Laravel\Passport\Passport; use Log; +use phpseclib3\Crypt\RSA; /** * Trait CreateStuff @@ -41,7 +42,7 @@ trait CreateStuff /** * Creates an asset account. * - * @param NewUserFormRequest $request + * @param NewUserFormRequest $request * @param TransactionCurrency $currency * * @return bool @@ -57,7 +58,7 @@ trait CreateStuff 'virtual_balance' => 0, 'account_type_id' => null, 'active' => true, - 'account_role' => 'defaultAsset', + 'account_role' => 'defaultAsset', 'opening_balance' => $request->input('bank_balance'), 'opening_balance_date' => new Carbon, 'currency_id' => $currency->id, @@ -72,7 +73,7 @@ trait CreateStuff * Creates a cash wallet. * * @param TransactionCurrency $currency - * @param string $language + * @param string $language * * @return bool */ @@ -87,7 +88,7 @@ trait CreateStuff 'virtual_balance' => 0, 'account_type_id' => null, 'active' => true, - 'account_role' => 'cashWalletAsset', + 'account_role' => 'cashWalletAsset', 'opening_balance' => null, 'opening_balance_date' => null, 'currency_id' => $currency->id, @@ -109,7 +110,7 @@ trait CreateStuff $keys = $rsa->createKey(4096); } if (8 === PHP_MAJOR_VERSION) { - $keys = \phpseclib3\Crypt\RSA::createKeys(4096); + $keys = RSA::createKeys(4096); } [$publicKey, $privateKey] = [ @@ -130,9 +131,9 @@ trait CreateStuff /** * Create a savings account. * - * @param NewUserFormRequest $request + * @param NewUserFormRequest $request * @param TransactionCurrency $currency - * @param string $language + * @param string $language * * @return bool */ @@ -162,7 +163,7 @@ trait CreateStuff * * @param array $data * - * @return \FireflyIII\User + * @return User */ protected function createUser(array $data): User // create object { diff --git a/app/Support/Http/Controllers/CronRunner.php b/app/Support/Http/Controllers/CronRunner.php index 7d298fba3e..58a28932b1 100644 --- a/app/Support/Http/Controllers/CronRunner.php +++ b/app/Support/Http/Controllers/CronRunner.php @@ -33,6 +33,25 @@ use FireflyIII\Support\Cronjobs\TelemetryCronjob; */ trait CronRunner { + /** + * @return string + */ + protected function runAutoBudget(): string + { + /** @var AutoBudgetCronjob $autoBudget */ + $autoBudget = app(AutoBudgetCronjob::class); + try { + $result = $autoBudget->fire(); + } catch (FireflyException $e) { + return $e->getMessage(); + } + if (false === $result) { + return 'The auto budget cron job did not fire.'; + } + + return 'The auto budget cron job fired successfully.'; + } + /** * @return string */ @@ -55,7 +74,8 @@ trait CronRunner /** * @return string */ - protected function runTelemetry(): string { + protected function runTelemetry(): string + { /** @var TelemetryCronjob $telemetry */ $telemetry = app(TelemetryCronjob::class); try { @@ -70,23 +90,4 @@ trait CronRunner return 'The telemetry cron job fired successfully.'; } - /** - * @return string - */ - protected function runAutoBudget(): string - { - /** @var AutoBudgetCronjob $autoBudget */ - $autoBudget = app(AutoBudgetCronjob::class); - try { - $result = $autoBudget->fire(); - } catch (FireflyException $e) { - return $e->getMessage(); - } - if (false === $result) { - return 'The auto budget cron job did not fire.'; - } - - return 'The auto budget cron job fired successfully.'; - } - } diff --git a/app/Support/Http/Controllers/DateCalculation.php b/app/Support/Http/Controllers/DateCalculation.php index f82a2954e0..c699cd6c63 100644 --- a/app/Support/Http/Controllers/DateCalculation.php +++ b/app/Support/Http/Controllers/DateCalculation.php @@ -50,6 +50,7 @@ trait DateCalculation if ($start->lte($today) && $end->gte($today)) { $difference = $today->diffInDays($end); } + return 0 === $difference ? 1 : $difference; } diff --git a/app/Support/Http/Controllers/GetConfigurationData.php b/app/Support/Http/Controllers/GetConfigurationData.php index 2e1a5c32ba..6aa4cc6888 100644 --- a/app/Support/Http/Controllers/GetConfigurationData.php +++ b/app/Support/Http/Controllers/GetConfigurationData.php @@ -42,7 +42,7 @@ trait GetConfigurationData */ protected function errorReporting(int $value): string // get configuration { - $array = [ + $array = [ -1 => 'ALL errors', E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED => 'E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED', E_ALL => 'E_ALL', @@ -51,6 +51,7 @@ trait GetConfigurationData E_ALL & ~E_NOTICE & ~E_STRICT => 'E_ALL & ~E_NOTICE & ~E_STRICT', E_COMPILE_ERROR | E_RECOVERABLE_ERROR | E_ERROR | E_CORE_ERROR => 'E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR', ]; + return $array[$value] ?? (string)$value; } @@ -90,7 +91,7 @@ trait GetConfigurationData */ protected function getDateRangeConfig(): array // get configuration + get preferences. { - $viewRange = (string) app('preferences')->get('viewRange', '1M')->data; + $viewRange = (string)app('preferences')->get('viewRange', '1M')->data; /** @var Carbon $start */ $start = session('start'); /** @var Carbon $end */ @@ -197,6 +198,7 @@ trait GetConfigurationData return $steps; } + /** * */ diff --git a/app/Support/Http/Controllers/ModelInformation.php b/app/Support/Http/Controllers/ModelInformation.php index 9d486e5e6c..ca35c4de5c 100644 --- a/app/Support/Http/Controllers/ModelInformation.php +++ b/app/Support/Http/Controllers/ModelInformation.php @@ -86,9 +86,9 @@ trait ModelInformation $mortgage = $repository->getAccountTypeByType(AccountType::MORTGAGE); /** @noinspection NullPointerExceptionInspection */ $liabilityTypes = [ - $debt->id => (string) trans(sprintf('firefly.account_type_%s', AccountType::DEBT)), - $loan->id => (string) trans(sprintf('firefly.account_type_%s', AccountType::LOAN)), - $mortgage->id => (string) trans(sprintf('firefly.account_type_%s', AccountType::MORTGAGE)), + $debt->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::DEBT)), + $loan->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::LOAN)), + $mortgage->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::MORTGAGE)), ]; asort($liabilityTypes); @@ -103,7 +103,7 @@ trait ModelInformation { $roles = []; foreach (config('firefly.accountRoles') as $role) { - $roles[$role] = (string) trans(sprintf('firefly.account_role_%s', $role)); + $roles[$role] = (string)trans(sprintf('firefly.account_role_%s', $role)); } return $roles; @@ -124,7 +124,7 @@ trait ModelInformation foreach ($operators as $key => $operator) { if ('user_action' !== $key && false === $operator['alias']) { - $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); + $triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key)); } } asort($triggers); @@ -133,8 +133,8 @@ trait ModelInformation $billTriggers = ['currency_is', 'amount_more', 'amount_less', 'description_contains']; $values = [ $bill->transactionCurrency()->first()->name, - round((float) $bill->amount_min, 12), - round((float) $bill->amount_max, 12), + round((float)$bill->amount_min, 12), + round((float)$bill->amount_max, 12), $bill->name, ]; foreach ($billTriggers as $index => $trigger) { @@ -178,7 +178,7 @@ trait ModelInformation foreach ($operators as $key => $operator) { if ('user_action' !== $key && false === $operator['alias']) { - $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); + $triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key)); } } asort($triggers); diff --git a/app/Support/Http/Controllers/PeriodOverview.php b/app/Support/Http/Controllers/PeriodOverview.php index 7d887c2de2..fecdf36b28 100644 --- a/app/Support/Http/Controllers/PeriodOverview.php +++ b/app/Support/Http/Controllers/PeriodOverview.php @@ -70,8 +70,8 @@ trait PeriodOverview * performance reasons. * * @param Account $account The account involved - * @param Carbon $date The start date. - * @param Carbon $end The end date. + * @param Carbon $date The start date. + * @param Carbon $end The end date. * * @return array */ @@ -124,30 +124,145 @@ trait PeriodOverview $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); $transferredAway = $this->filterTransferredAway($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end'])); $transferredIn = $this->filterTransferredIn($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end'])); - $entries[] = - [ - 'title' => $title, - 'route' => - route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + $entries[] + = [ + 'title' => $title, + 'route' => + route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred_away' => $this->groupByCurrency($transferredAway), - 'transferred_in' => $this->groupByCurrency($transferredIn), - ]; + 'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred_away' => $this->groupByCurrency($transferredAway), + 'transferred_in' => $this->groupByCurrency($transferredIn), + ]; } $cache->store($entries); return $entries; } + /** + * Filter a list of journals by a set of dates, and then group them by currency. + * + * @param array $array + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + private function filterJournalsByDate(array $array, Carbon $start, Carbon $end): array + { + $result = []; + /** @var array $journal */ + foreach ($array as $journal) { + if ($journal['date'] <= $end && $journal['date'] >= $start) { + $result[] = $journal; + } + } + + return $result; + } + + /** + * Return only transactions where $account is the source. + * + * @param Account $account + * @param array $journals + * + * @return array + */ + private function filterTransferredAway(Account $account, array $journals): array + { + $return = []; + /** @var array $journal */ + foreach ($journals as $journal) { + if ($account->id === (int)$journal['source_account_id']) { + $return[] = $journal; + } + } + + return $return; + } + + /** + * Return only transactions where $account is the source. + * + * @param Account $account + * @param array $journals + * + * @return array + * @codeCoverageIgnore + */ + private function filterTransferredIn(Account $account, array $journals): array + { + $return = []; + /** @var array $journal */ + foreach ($journals as $journal) { + if ($account->id === (int)$journal['destination_account_id']) { + $return[] = $journal; + } + } + + return $return; + } + + /** + * @param array $journals + * + * @return array + * @codeCoverageIgnore + */ + private function groupByCurrency(array $journals): array + { + $return = []; + /** @var array $journal */ + foreach ($journals as $journal) { + $currencyId = (int)$journal['currency_id']; + $foreignCurrencyId = $journal['foreign_currency_id']; + if (!isset($return[$currencyId])) { + $return[$currencyId] = [ + 'amount' => '0', + 'count' => 0, + 'currency_id' => $currencyId, + 'currency_name' => $journal['currency_name'], + 'currency_code' => $journal['currency_code'], + 'currency_symbol' => $journal['currency_symbol'], + 'currency_decimal_places' => $journal['currency_decimal_places'], + ]; + } + $return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $journal['amount'] ?? '0'); + $return[$currencyId]['count']++; + + if (null !== $foreignCurrencyId && null !== $journal['foreign_amount']) { + if (!isset($return[$foreignCurrencyId])) { + $return[$foreignCurrencyId] = [ + 'amount' => '0', + 'count' => 0, + 'currency_id' => (int)$foreignCurrencyId, + 'currency_name' => $journal['foreign_currency_name'], + 'currency_code' => $journal['foreign_currency_code'], + 'currency_symbol' => $journal['foreign_currency_symbol'], + 'currency_decimal_places' => $journal['foreign_currency_decimal_places'], + ]; + + } + $return[$foreignCurrencyId]['count']++; + $return[$foreignCurrencyId]['amount'] = bcadd($return[$foreignCurrencyId]['amount'], $journal['foreign_amount']); + } + + } + + return $return; + } + /** * Overview for single category. Has been refactored recently. * * @param Category $category - * @param Carbon $start - * @param Carbon $end + * @param Carbon $start + * @param Carbon $end + * * @return array */ protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array @@ -200,17 +315,19 @@ trait PeriodOverview $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); $transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); - $entries[] = - [ - 'transactions' => 0, - 'title' => $title, - 'route' => route('categories.show', - [$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'total_transactions' => count($spent) + count($earned) + count($transferred), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred' => $this->groupByCurrency($transferred), - ]; + $entries[] + = [ + 'transactions' => 0, + 'title' => $title, + 'route' => route( + 'categories.show', + [$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')] + ), + 'total_transactions' => count($spent) + count($earned) + count($transferred), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred' => $this->groupByCurrency($transferred), + ]; } $cache->store($entries); @@ -254,18 +371,18 @@ trait PeriodOverview $journals = $collector->getExtractedJournals(); foreach ($dates as $currentDate) { - $set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']); - $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); - $entries[] = - [ - 'title' => $title, - 'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'total_transactions' => count($set), - 'spent' => $this->groupByCurrency($set), - 'earned' => [], - 'transferred_away' => [], - 'transferred_in' => [], - ]; + $set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']); + $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); + $entries[] + = [ + 'title' => $title, + 'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + 'total_transactions' => count($set), + 'spent' => $this->groupByCurrency($set), + 'earned' => [], + 'transferred_away' => [], + 'transferred_in' => [], + ]; } $cache->store($entries); @@ -336,15 +453,15 @@ trait PeriodOverview $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); $transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); - $entries[] = - [ - 'title' => $title, - 'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'total_transactions' => count($spent) + count($earned) + count($transferred), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred' => $this->groupByCurrency($transferred), - ]; + $entries[] + = [ + 'title' => $title, + 'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + 'total_transactions' => count($spent) + count($earned) + count($transferred), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred' => $this->groupByCurrency($transferred), + ]; } Log::debug('End of loops'); $cache->store($entries); @@ -355,7 +472,7 @@ trait PeriodOverview /** * This shows a period overview for a tag. It goes back in time and lists all relevant transactions and sums. * - * @param Tag $tag + * @param Tag $tag * * @param Carbon $date * @@ -374,7 +491,7 @@ trait PeriodOverview $cache->addProperty('tag-period-entries'); $cache->addProperty($tag->id); if ($cache->has()) { - return $cache->get(); // @codeCoverageIgnore + return $cache->get(); // @codeCoverageIgnore } /** @var array $dates */ $dates = app('navigation')->blockPeriods($start, $end, $range); @@ -409,17 +526,19 @@ trait PeriodOverview $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); $transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); - $entries[] = - [ - 'transactions' => 0, - 'title' => $title, - 'route' => route('tags.show', - [$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'total_transactions' => count($spent) + count($earned) + count($transferred), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred' => $this->groupByCurrency($transferred), - ]; + $entries[] + = [ + 'transactions' => 0, + 'title' => $title, + 'route' => route( + 'tags.show', + [$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')] + ), + 'total_transactions' => count($spent) + count($earned) + count($transferred), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred' => $this->groupByCurrency($transferred), + ]; } return $entries; @@ -473,127 +592,18 @@ trait PeriodOverview } - $entries[] = - [ - 'title' => $title, - 'route' => - route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'total_transactions' => count($spent) + count($earned) + count($transferred), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred' => $this->groupByCurrency($transferred), - ]; + $entries[] + = [ + 'title' => $title, + 'route' => + route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + 'total_transactions' => count($spent) + count($earned) + count($transferred), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred' => $this->groupByCurrency($transferred), + ]; } return $entries; } - - /** - * Return only transactions where $account is the source. - * @param Account $account - * @param array $journals - * @return array - */ - private function filterTransferredAway(Account $account, array $journals): array - { - $return = []; - /** @var array $journal */ - foreach ($journals as $journal) { - if ($account->id === (int)$journal['source_account_id']) { - $return[] = $journal; - } - } - - return $return; - } - - /** - * Return only transactions where $account is the source. - * @param Account $account - * @param array $journals - * @return array - * @codeCoverageIgnore - */ - private function filterTransferredIn(Account $account, array $journals): array - { - $return = []; - /** @var array $journal */ - foreach ($journals as $journal) { - if ($account->id === (int)$journal['destination_account_id']) { - $return[] = $journal; - } - } - - return $return; - } - - /** - * Filter a list of journals by a set of dates, and then group them by currency. - * - * @param array $array - * @param Carbon $start - * @param Carbon $end - * @return array - */ - private function filterJournalsByDate(array $array, Carbon $start, Carbon $end): array - { - $result = []; - /** @var array $journal */ - foreach ($array as $journal) { - if ($journal['date'] <= $end && $journal['date'] >= $start) { - $result[] = $journal; - } - } - - return $result; - } - - /** - * @param array $journals - * - * @return array - * @codeCoverageIgnore - */ - private function groupByCurrency(array $journals): array - { - $return = []; - /** @var array $journal */ - foreach ($journals as $journal) { - $currencyId = (int)$journal['currency_id']; - $foreignCurrencyId = $journal['foreign_currency_id']; - if (!isset($return[$currencyId])) { - $return[$currencyId] = [ - 'amount' => '0', - 'count' => 0, - 'currency_id' => $currencyId, - 'currency_name' => $journal['currency_name'], - 'currency_code' => $journal['currency_code'], - 'currency_symbol' => $journal['currency_symbol'], - 'currency_decimal_places' => $journal['currency_decimal_places'], - ]; - } - $return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $journal['amount'] ?? '0'); - $return[$currencyId]['count']++; - - if (null !== $foreignCurrencyId && null !== $journal['foreign_amount']) { - if (!isset($return[$foreignCurrencyId])) { - $return[$foreignCurrencyId] = [ - 'amount' => '0', - 'count' => 0, - 'currency_id' => (int)$foreignCurrencyId, - 'currency_name' => $journal['foreign_currency_name'], - 'currency_code' => $journal['foreign_currency_code'], - 'currency_symbol' => $journal['foreign_currency_symbol'], - 'currency_decimal_places' => $journal['foreign_currency_decimal_places'], - ]; - - } - $return[$foreignCurrencyId]['count']++; - $return[$foreignCurrencyId]['amount'] = bcadd($return[$foreignCurrencyId]['amount'], $journal['foreign_amount']); - } - - } - - return $return; - } } diff --git a/app/Support/Http/Controllers/RenderPartialViews.php b/app/Support/Http/Controllers/RenderPartialViews.php index 6703547548..66ee8e5dc9 100644 --- a/app/Support/Http/Controllers/RenderPartialViews.php +++ b/app/Support/Http/Controllers/RenderPartialViews.php @@ -45,50 +45,6 @@ use Throwable; trait RenderPartialViews { - /** - * Get options for double report. - * - * @return string - */ - protected function doubleReportOptions(): string // render a view - { - /** @var AccountRepositoryInterface $repository */ - $repository = app(AccountRepositoryInterface::class); - $expense = $repository->getActiveAccountsByType([AccountType::EXPENSE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]); - $revenue = $repository->getActiveAccountsByType([AccountType::REVENUE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]); - $set = []; - - /** @var Account $account */ - foreach ($expense as $account) { - // loop revenue, find same account: - /** @var Account $otherAccount */ - foreach ($revenue as $otherAccount) { - if ( - ( - ($otherAccount->name === $account->name) - || - (null !== $account->iban && null !== $otherAccount->iban && $otherAccount->iban === $account->iban) - ) - && $otherAccount->id !== $account->id - ) { - $set[] = $account; - } - } - } - - // @codeCoverageIgnoreStart - try { - $result = prefixView('reports.options.double', compact('set'))->render(); - } catch (Throwable $e) { - Log::error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage())); - $result = 'Could not render view.'; - } - - // @codeCoverageIgnoreEnd - - return $result; - } - /** * View for transactions in a budget for an account. * @@ -103,10 +59,10 @@ trait RenderPartialViews /** @var BudgetRepositoryInterface $budgetRepository */ $budgetRepository = app(BudgetRepositoryInterface::class); - $budget = $budgetRepository->findNull((int) $attributes['budgetId']); + $budget = $budgetRepository->findNull((int)$attributes['budgetId']); $accountRepos = app(AccountRepositoryInterface::class); - $account = $accountRepos->findNull((int) $attributes['accountId']); + $account = $accountRepos->findNull((int)$attributes['accountId']); $journals = $popupHelper->balanceForBudget($budget, $account, $attributes); // @codeCoverageIgnoreStart @@ -160,7 +116,7 @@ trait RenderPartialViews /** @var PopupReportInterface $popupHelper */ $popupHelper = app(PopupReportInterface::class); - $budget = $budgetRepository->findNull((int) $attributes['budgetId']); + $budget = $budgetRepository->findNull((int)$attributes['budgetId']); if (null === $budget) { $budget = new Budget; } @@ -192,7 +148,7 @@ trait RenderPartialViews /** @var CategoryRepositoryInterface $categoryRepository */ $categoryRepository = app(CategoryRepositoryInterface::class); - $category = $categoryRepository->findNull((int) $attributes['categoryId']); + $category = $categoryRepository->findNull((int)$attributes['categoryId']); $journals = $popupHelper->byCategory($category, $attributes); try { @@ -228,6 +184,49 @@ trait RenderPartialViews return $result; } + /** + * Get options for double report. + * + * @return string + */ + protected function doubleReportOptions(): string // render a view + { + /** @var AccountRepositoryInterface $repository */ + $repository = app(AccountRepositoryInterface::class); + $expense = $repository->getActiveAccountsByType([AccountType::EXPENSE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]); + $revenue = $repository->getActiveAccountsByType([AccountType::REVENUE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]); + $set = []; + + /** @var Account $account */ + foreach ($expense as $account) { + // loop revenue, find same account: + /** @var Account $otherAccount */ + foreach ($revenue as $otherAccount) { + if ( + ( + ($otherAccount->name === $account->name) + || (null !== $account->iban && null !== $otherAccount->iban && $otherAccount->iban === $account->iban) + ) + && $otherAccount->id !== $account->id + ) { + $set[] = $account; + } + } + } + + // @codeCoverageIgnoreStart + try { + $result = prefixView('reports.options.double', compact('set'))->render(); + } catch (Throwable $e) { + Log::error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage())); + $result = 'Could not render view.'; + } + + // @codeCoverageIgnoreEnd + + return $result; + } + /** * Returns all the expenses that went to the given expense account. * @@ -243,7 +242,7 @@ trait RenderPartialViews /** @var PopupReportInterface $popupHelper */ $popupHelper = app(PopupReportInterface::class); - $account = $accountRepository->findNull((int) $attributes['accountId']); + $account = $accountRepository->findNull((int)$attributes['accountId']); if (null === $account) { return 'This is an unknown account. Apologies.'; @@ -317,7 +316,7 @@ trait RenderPartialViews foreach ($operators as $key => $operator) { if ('user_action' !== $key && false === $operator['alias']) { - $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); + $triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key)); } } asort($triggers); @@ -369,7 +368,7 @@ trait RenderPartialViews /** @var PopupReportInterface $popupHelper */ $popupHelper = app(PopupReportInterface::class); - $account = $accountRepository->findNull((int) $attributes['accountId']); + $account = $accountRepository->findNull((int)$attributes['accountId']); if (null === $account) { return 'This is an unknown category. Apologies.'; diff --git a/app/Support/Http/Controllers/RequestInformation.php b/app/Support/Http/Controllers/RequestInformation.php index 32f3167c0b..0d465859b3 100644 --- a/app/Support/Http/Controllers/RequestInformation.php +++ b/app/Support/Http/Controllers/RequestInformation.php @@ -98,6 +98,7 @@ trait RequestInformation // also check cache first: if ($help->inCache($route, $language)) { Log::debug(sprintf('Help text %s was in cache.', $language)); + return $help->getFromCache($route, $language); } $baseHref = route('index'); @@ -117,6 +118,24 @@ trait RequestInformation return '

' . trans('firefly.route_has_no_help') . '

'; // @codeCoverageIgnore } + /** + * @return string + */ + protected function getPageName(): string // get request info + { + return str_replace('.', '_', RouteFacade::currentRouteName()); + } + + /** + * Get the specific name of a page for intro. + * + * @return string + */ + protected function getSpecificPageName(): string // get request info + { + return null === RouteFacade::current()->parameter('objectType') ? '' : '_' . RouteFacade::current()->parameter('objectType'); + } + /** * Get a list of triggers. * @@ -152,7 +171,6 @@ trait RequestInformation $specificPage = $this->getSpecificPageName(); - // indicator if user has seen the help for this page ( + special page): $key = sprintf('shown_demo_%s%s', $page, $specificPage); // is there an intro for this route? @@ -172,24 +190,6 @@ trait RequestInformation return $shownDemo; } - /** - * @return string - */ - protected function getPageName(): string // get request info - { - return str_replace('.', '_', RouteFacade::currentRouteName()); - } - - /** - * Get the specific name of a page for intro. - * - * @return string - */ - protected function getSpecificPageName(): string // get request info - { - return null === RouteFacade::current()->parameter('objectType') ? '' : '_' . RouteFacade::current()->parameter('objectType'); - } - /** * Check if date is outside session range. * @@ -249,7 +249,7 @@ trait RequestInformation /** * Validate users new password. * - * @param User $user + * @param User $user * @param string $current * @param string $new * diff --git a/app/Support/Http/Controllers/RuleManagement.php b/app/Support/Http/Controllers/RuleManagement.php index ae6ff1e9a7..2ead11c60f 100644 --- a/app/Support/Http/Controllers/RuleManagement.php +++ b/app/Support/Http/Controllers/RuleManagement.php @@ -36,8 +36,138 @@ use Throwable; */ trait RuleManagement { + /** + * + */ + protected function createDefaultRule(): void + { + /** @var RuleRepositoryInterface $ruleRepository */ + $ruleRepository = app(RuleRepositoryInterface::class); + if (0 === $ruleRepository->count()) { + $data = [ + 'rule_group_id' => $ruleRepository->getFirstRuleGroup()->id, + 'stop_processing' => 0, + 'title' => (string)trans('firefly.default_rule_name'), + 'description' => (string)trans('firefly.default_rule_description'), + 'trigger' => 'store-journal', + 'strict' => true, + 'active' => true, + 'triggers' => [ + [ + 'type' => 'description_is', + 'value' => (string)trans('firefly.default_rule_trigger_description'), + 'stop_processing' => false, + + ], + [ + 'type' => 'from_account_is', + 'value' => (string)trans('firefly.default_rule_trigger_from_account'), + 'stop_processing' => false, + + ], + + ], + 'actions' => [ + [ + 'type' => 'prepend_description', + 'value' => (string)trans('firefly.default_rule_action_prepend'), + 'stop_processing' => false, + ], + [ + 'type' => 'set_category', + 'value' => (string)trans('firefly.default_rule_action_set_category'), + 'stop_processing' => false, + ], + ], + ]; + + $ruleRepository->store($data); + } + } + + /** + * @param Request $request + * + * @return array + * @codeCoverageIgnore + */ + protected function getPreviousActions(Request $request): array + { + $index = 0; + $triggers = []; + $oldInput = $request->old('actions'); + if (is_array($oldInput)) { + foreach ($oldInput as $oldAction) { + try { + $triggers[] = prefixView( + 'rules.partials.action', + [ + 'oldAction' => $oldAction['type'], + 'oldValue' => $oldAction['value'], + 'oldChecked' => 1 === (int)($oldAction['stop_processing'] ?? '0'), + 'count' => $index + 1, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage())); + Log::error($e->getTraceAsString()); + } + $index++; + } + } + + return $triggers; + } + + /** + * @param Request $request + * + * @return array + * @codeCoverageIgnore + */ + protected function getPreviousTriggers(Request $request): array + { + // TODO duplicated code. + $operators = config('firefly.search.operators'); + $triggers = []; + foreach ($operators as $key => $operator) { + if ('user_action' !== $key && false === $operator['alias']) { + + $triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key)); + } + } + asort($triggers); + + $index = 0; + $renderedEntries = []; + $oldInput = $request->old('triggers'); + if (is_array($oldInput)) { + foreach ($oldInput as $oldTrigger) { + try { + $renderedEntries[] = prefixView( + 'rules.partials.trigger', + [ + 'oldTrigger' => OperatorQuerySearch::getRootOperator($oldTrigger['type']), + 'oldValue' => $oldTrigger['value'], + 'oldChecked' => 1 === (int)($oldTrigger['stop_processing'] ?? '0'), + 'count' => $index + 1, + 'triggers' => $triggers, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); + Log::error($e->getTraceAsString()); + } + $index++; + } + } + + return $renderedEntries; + } + /** * @param array $submittedOperators + * * @return array */ protected function parseFromOperators(array $submittedOperators): array @@ -49,7 +179,7 @@ trait RuleManagement foreach ($operators as $key => $operator) { if ('user_action' !== $key && false === $operator['alias']) { - $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); + $triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key)); } } asort($triggers); @@ -77,135 +207,6 @@ trait RuleManagement return $renderedEntries; } - /** - * - */ - protected function createDefaultRule(): void - { - /** @var RuleRepositoryInterface $ruleRepository */ - $ruleRepository = app(RuleRepositoryInterface::class); - if (0 === $ruleRepository->count()) { - $data = [ - 'rule_group_id' => $ruleRepository->getFirstRuleGroup()->id, - 'stop_processing' => 0, - 'title' => (string) trans('firefly.default_rule_name'), - 'description' => (string) trans('firefly.default_rule_description'), - 'trigger' => 'store-journal', - 'strict' => true, - 'active' => true, - 'triggers' => [ - [ - 'type' => 'description_is', - 'value' => (string) trans('firefly.default_rule_trigger_description'), - 'stop_processing' => false, - - ], - [ - 'type' => 'from_account_is', - 'value' => (string) trans('firefly.default_rule_trigger_from_account'), - 'stop_processing' => false, - - ], - - ], - 'actions' => [ - [ - 'type' => 'prepend_description', - 'value' => (string) trans('firefly.default_rule_action_prepend'), - 'stop_processing' => false, - ], - [ - 'type' => 'set_category', - 'value' => (string) trans('firefly.default_rule_action_set_category'), - 'stop_processing' => false, - ], - ], - ]; - - $ruleRepository->store($data); - } - } - - /** - * @param Request $request - * - * @return array - * @codeCoverageIgnore - */ - protected function getPreviousActions(Request $request): array - { - $index = 0; - $triggers = []; - $oldInput = $request->old('actions'); - if (is_array($oldInput)) { - foreach ($oldInput as $oldAction) { - try { - $triggers[] = prefixView( - 'rules.partials.action', - [ - 'oldAction' => $oldAction['type'], - 'oldValue' => $oldAction['value'], - 'oldChecked' => 1 === (int) ($oldAction['stop_processing'] ?? '0'), - 'count' => $index + 1, - ] - )->render(); - } catch (Throwable $e) { - Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage())); - Log::error($e->getTraceAsString()); - } - $index++; - } - } - - return $triggers; - } - - /** - * @param Request $request - * - * @return array - * @codeCoverageIgnore - */ - protected function getPreviousTriggers(Request $request): array - { - // TODO duplicated code. - $operators = config('firefly.search.operators'); - $triggers = []; - foreach ($operators as $key => $operator) { - if ('user_action' !== $key && false === $operator['alias']) { - - $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); - } - } - asort($triggers); - - $index = 0; - $renderedEntries = []; - $oldInput = $request->old('triggers'); - if (is_array($oldInput)) { - foreach ($oldInput as $oldTrigger) { - try { - $renderedEntries[] = prefixView( - 'rules.partials.trigger', - [ - 'oldTrigger' => OperatorQuerySearch::getRootOperator($oldTrigger['type']), - 'oldValue' => $oldTrigger['value'], - 'oldChecked' => 1 === (int) ($oldTrigger['stop_processing'] ?? '0'), - 'count' => $index + 1, - 'triggers' => $triggers, - ] - )->render(); - } catch (Throwable $e) { - Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); - Log::error($e->getTraceAsString()); - } - $index++; - } - } - - return $renderedEntries; - } - /** * */ @@ -215,8 +216,8 @@ trait RuleManagement $repository = app(RuleGroupRepositoryInterface::class); if (0 === $repository->count()) { $data = [ - 'title' => (string) trans('firefly.default_rule_group_name'), - 'description' => (string) trans('firefly.default_rule_group_description'), + 'title' => (string)trans('firefly.default_rule_group_name'), + 'description' => (string)trans('firefly.default_rule_group_description'), 'active' => true, ]; diff --git a/app/Support/Http/Controllers/TransactionCalculation.php b/app/Support/Http/Controllers/TransactionCalculation.php index 782b715d91..533434a967 100644 --- a/app/Support/Http/Controllers/TransactionCalculation.php +++ b/app/Support/Http/Controllers/TransactionCalculation.php @@ -39,8 +39,8 @@ trait TransactionCalculation * * @param Collection $accounts * @param Collection $opposing - * @param Carbon $start - * @param Carbon $end + * @param Carbon $start + * @param Carbon $end * * @return array */ @@ -63,8 +63,8 @@ trait TransactionCalculation * * @param Collection $accounts * @param Collection $tags - * @param Carbon $start - * @param Carbon $end + * @param Carbon $start + * @param Carbon $end * * @return array * @@ -85,8 +85,8 @@ trait TransactionCalculation * * @param Collection $accounts * @param Collection $budgets - * @param Carbon $start - * @param Carbon $end + * @param Carbon $start + * @param Carbon $end * * @return array */ @@ -105,8 +105,8 @@ trait TransactionCalculation * * @param Collection $accounts * @param Collection $categories - * @param Carbon $start - * @param Carbon $end + * @param Carbon $start + * @param Carbon $end * * @return array */ @@ -129,8 +129,8 @@ trait TransactionCalculation * * @param Collection $accounts * @param Collection $categories - * @param Carbon $start - * @param Carbon $end + * @param Carbon $start + * @param Carbon $end * * @return array */ @@ -149,14 +149,14 @@ trait TransactionCalculation * * @param Collection $accounts * @param Collection $opposing - * @param Carbon $start - * @param Carbon $end + * @param Carbon $start + * @param Carbon $end * * @return array */ protected function getIncomeForOpposing(Collection $accounts, Collection $opposing, Carbon $start, Carbon $end): array { - $total =$accounts->merge($opposing); + $total = $accounts->merge($opposing); /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setAccounts($total)->setRange($start, $end)->withAccountInformation()->setTypes([TransactionType::DEPOSIT]); @@ -169,8 +169,8 @@ trait TransactionCalculation * * @param Collection $accounts * @param Collection $tags - * @param Carbon $start - * @param Carbon $end + * @param Carbon $start + * @param Carbon $end * * @return array */ diff --git a/app/Support/Http/Controllers/UserNavigation.php b/app/Support/Http/Controllers/UserNavigation.php index c324434c92..5bf7c550cc 100644 --- a/app/Support/Http/Controllers/UserNavigation.php +++ b/app/Support/Http/Controllers/UserNavigation.php @@ -29,6 +29,8 @@ use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; +use Illuminate\Http\RedirectResponse; +use Illuminate\Routing\Redirector; use Illuminate\Support\Str; use Illuminate\Support\ViewErrorBag; use Log; @@ -40,6 +42,33 @@ use Log; trait UserNavigation { + /** + * Functionality:. + * + * - If the $identifier contains the word "delete" then a remembered uri with the text "/show/" in it will not be returned but instead the index (/) + * will be returned. + * - If the remembered uri contains "jscript/" the remembered uri will not be returned but instead the index (/) will be returned. + * + * @param string $identifier + * + * @return string + */ + protected function getPreviousUri(string $identifier): string + { + Log::debug(sprintf('Trying to retrieve URL stored under "%s"', $identifier)); + $uri = (string)session($identifier); + Log::debug(sprintf('The URI is %s', $uri)); + + if (false !== strpos($uri, 'jscript')) { + $uri = $this->redirectUri; // @codeCoverageIgnore + Log::debug(sprintf('URI is now %s (uri contains jscript)', $uri)); + } + + Log::debug(sprintf('Return direct link %s', $uri)); + + return $uri; + } + /** * Will return false if you cant edit this account type. * @@ -73,38 +102,10 @@ trait UserNavigation return in_array($type, $editable, true); } - /** - * @param TransactionGroup $group - * - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - protected function redirectGroupToAccount(TransactionGroup $group) - { - /** @var TransactionJournal $journal */ - $journal = $group->transactionJournals()->first(); - if (null === $journal) { - Log::error(sprintf('No journals in group #%d', $group->id)); - - return redirect(route('index')); - } - // prefer redirect to everything but expense and revenue: - $transactions = $journal->transactions; - $ignore = [AccountType::REVENUE, AccountType::EXPENSE, AccountType::RECONCILIATION, AccountType::INITIAL_BALANCE]; - /** @var Transaction $transaction */ - foreach ($transactions as $transaction) { - $type = $transaction->account->accountType->type; - if (!in_array($type, $ignore, true)) { - return redirect(route('accounts.edit', [$transaction->account_id])); - } - } - - return redirect(route('index')); - } - /** * @param Account $account * - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + * @return RedirectResponse|Redirector */ protected function redirectAccountToAccount(Account $account) { @@ -136,31 +137,32 @@ trait UserNavigation return redirect(route('index')); } - /** - * Functionality:. + * @param TransactionGroup $group * - * - If the $identifier contains the word "delete" then a remembered uri with the text "/show/" in it will not be returned but instead the index (/) - * will be returned. - * - If the remembered uri contains "jscript/" the remembered uri will not be returned but instead the index (/) will be returned. - * - * @param string $identifier - * - * @return string + * @return RedirectResponse|Redirector */ - protected function getPreviousUri(string $identifier): string + protected function redirectGroupToAccount(TransactionGroup $group) { - Log::debug(sprintf('Trying to retrieve URL stored under "%s"', $identifier)); - $uri = (string)session($identifier); - Log::debug(sprintf('The URI is %s', $uri)); + /** @var TransactionJournal $journal */ + $journal = $group->transactionJournals()->first(); + if (null === $journal) { + Log::error(sprintf('No journals in group #%d', $group->id)); - if (false !== strpos($uri, 'jscript')) { - $uri = $this->redirectUri; // @codeCoverageIgnore - Log::debug(sprintf('URI is now %s (uri contains jscript)', $uri)); + return redirect(route('index')); + } + // prefer redirect to everything but expense and revenue: + $transactions = $journal->transactions; + $ignore = [AccountType::REVENUE, AccountType::EXPENSE, AccountType::RECONCILIATION, AccountType::INITIAL_BALANCE]; + /** @var Transaction $transaction */ + foreach ($transactions as $transaction) { + $type = $transaction->account->accountType->type; + if (!in_array($type, $ignore, true)) { + return redirect(route('accounts.edit', [$transaction->account_id])); + } } - Log::debug(sprintf('Return direct link %s', $uri)); - return $uri; + return redirect(route('index')); } /** @@ -178,6 +180,7 @@ trait UserNavigation Log::debug(sprintf('Saving URL %s under key %s', $return, $identifier)); session()->put($identifier, $return); } + return $return; } } diff --git a/app/Support/Logging/AuditLogger.php b/app/Support/Logging/AuditLogger.php index 7732823add..01eecf70e4 100644 --- a/app/Support/Logging/AuditLogger.php +++ b/app/Support/Logging/AuditLogger.php @@ -30,6 +30,7 @@ use Monolog\Handler\AbstractProcessingHandler; /** * Class AuditLogger + * * @codeCoverageIgnore */ class AuditLogger @@ -37,7 +38,7 @@ class AuditLogger /** * Customize the given logger instance. * - * @param Logger $logger + * @param Logger $logger * * @return void */ diff --git a/app/Support/Logging/AuditProcessor.php b/app/Support/Logging/AuditProcessor.php index e8e6bdc245..b3651b6357 100644 --- a/app/Support/Logging/AuditProcessor.php +++ b/app/Support/Logging/AuditProcessor.php @@ -26,6 +26,7 @@ namespace FireflyIII\Support\Logging; /** * Class AuditProcessor + * * @codeCoverageIgnore */ class AuditProcessor @@ -39,21 +40,24 @@ class AuditProcessor { if (auth()->check()) { - $record['message'] = sprintf('AUDIT: %s (%s (%s) -> %s:%s)', - $record['message'], - app('request')->ip(), - auth()->user()->email, - request()->method(), request()->url() + $record['message'] = sprintf( + 'AUDIT: %s (%s (%s) -> %s:%s)', + $record['message'], + app('request')->ip(), + auth()->user()->email, + request()->method(), request()->url() ); return $record; } - $record['message'] = sprintf('AUDIT: %s (%s -> %s:%s)', - $record['message'], - app('request')->ip(), - request()->method(), request()->url() + $record['message'] = sprintf( + 'AUDIT: %s (%s -> %s:%s)', + $record['message'], + app('request')->ip(), + request()->method(), request()->url() ); + return $record; } } diff --git a/app/Support/Report/Budget/BudgetReportGenerator.php b/app/Support/Report/Budget/BudgetReportGenerator.php index 40b1e24fa9..c3cd5ce743 100644 --- a/app/Support/Report/Budget/BudgetReportGenerator.php +++ b/app/Support/Report/Budget/BudgetReportGenerator.php @@ -310,10 +310,10 @@ class BudgetReportGenerator $budgetedPct = '0'; if (0 !== bccomp($spent, '0') && 0 !== bccomp($totalSpent, '0')) { - $spentPct = round((float) bcmul(bcdiv($spent, $totalSpent), '100')); + $spentPct = round((float)bcmul(bcdiv($spent, $totalSpent), '100')); } if (0 !== bccomp($budgeted, '0') && 0 !== bccomp($totalBudgeted, '0')) { - $budgetedPct = round((float) bcmul(bcdiv($budgeted, $totalBudgeted), '100')); + $budgetedPct = round((float)bcmul(bcdiv($budgeted, $totalBudgeted), '100')); } $this->report['sums'][$currencyId]['budgeted'] = $this->report['sums'][$currencyId]['budgeted'] ?? '0'; $this->report['budgets'][$budgetId]['budget_limits'][$limitId]['spent_pct'] = $spentPct; diff --git a/app/Support/Report/Category/CategoryReportGenerator.php b/app/Support/Report/Category/CategoryReportGenerator.php index 34431affd5..229c765a80 100644 --- a/app/Support/Report/Category/CategoryReportGenerator.php +++ b/app/Support/Report/Category/CategoryReportGenerator.php @@ -151,7 +151,7 @@ class CategoryReportGenerator */ private function processCategoryRow(int $currencyId, array $currencyRow, int $categoryId, array $categoryRow): void { - $key = sprintf('%s-%s', $currencyId, $categoryId); + $key = sprintf('%s-%s', $currencyId, $categoryId); $this->report['categories'][$key] = $this->report['categories'][$key] ?? [ 'id' => $categoryId, 'title' => $categoryRow['name'], diff --git a/app/Support/Repositories/Recurring/CalculateRangeOccurrences.php b/app/Support/Repositories/Recurring/CalculateRangeOccurrences.php index 9bef93fbcb..655222d6ae 100644 --- a/app/Support/Repositories/Recurring/CalculateRangeOccurrences.php +++ b/app/Support/Repositories/Recurring/CalculateRangeOccurrences.php @@ -80,7 +80,7 @@ trait CalculateRangeOccurrences } while ($start < $end) { $domCorrected = min($dayOfMonth, $start->daysInMonth); - $start->day = $domCorrected; + $start->day = $domCorrected; if (0 === $attempts % $skipMod && $start->lte($start) && $end->gte($start)) { $return[] = clone $start; } @@ -92,7 +92,6 @@ trait CalculateRangeOccurrences } - /** * Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences. * diff --git a/app/Support/Repositories/Recurring/CalculateXOccurrences.php b/app/Support/Repositories/Recurring/CalculateXOccurrences.php index b77ebc857a..c5b8f42e46 100644 --- a/app/Support/Repositories/Recurring/CalculateXOccurrences.php +++ b/app/Support/Repositories/Recurring/CalculateXOccurrences.php @@ -62,7 +62,6 @@ trait CalculateXOccurrences } - /** * Calculates the number of monthly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip * over $skipMod -1 recurrences. @@ -140,7 +139,6 @@ trait CalculateXOccurrences } - /** * Calculates the number of weekly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip * over $skipMod -1 recurrences. @@ -184,7 +182,6 @@ trait CalculateXOccurrences } - /** * Calculates the number of yearly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip * over $skipMod -1 recurrences. diff --git a/app/Support/Request/AppendsLocationData.php b/app/Support/Request/AppendsLocationData.php index 49c77fc4d0..87da9c5c35 100644 --- a/app/Support/Request/AppendsLocationData.php +++ b/app/Support/Request/AppendsLocationData.php @@ -30,41 +30,6 @@ use Log; */ trait AppendsLocationData { - /** - * Abstract method stolen from "InteractsWithInput". - * - * @param null $key - * @param bool $default - * - * @return mixed - */ - abstract public function boolean($key = null, $default = false); - - /** - * Abstract method. - * - * @param $key - * - * @return bool - */ - abstract public function has($key); - - /** - * Abstract method. - * - * @return string - */ - abstract public function method(); - - /** - * Abstract method. - * - * @param mixed ...$patterns - * - * @return mixed - */ - abstract public function routeIs(...$patterns); - /** * Read the submitted Request data and add new or updated Location data to the array. * @@ -125,15 +90,6 @@ trait AppendsLocationData return $data; } - /** - * Abstract method to ensure filling later. - * - * @param string $field - * - * @return string|null - */ - abstract protected function nullableString(string $field): ?string; - /** * @param string|null $prefix * @param string $key @@ -192,6 +148,41 @@ trait AppendsLocationData return false; } + /** + * Abstract method stolen from "InteractsWithInput". + * + * @param null $key + * @param bool $default + * + * @return mixed + */ + abstract public function boolean($key = null, $default = false); + + /** + * Abstract method. + * + * @param $key + * + * @return bool + */ + abstract public function has($key); + + /** + * Abstract method. + * + * @return string + */ + abstract public function method(); + + /** + * Abstract method. + * + * @param mixed ...$patterns + * + * @return mixed + */ + abstract public function routeIs(...$patterns); + /** * @param string|null $prefix * @@ -199,18 +190,19 @@ trait AppendsLocationData */ private function isValidPUT(?string $prefix): bool { - $longitudeKey = $this->getLocationKey($prefix, 'longitude'); - $latitudeKey = $this->getLocationKey($prefix, 'latitude'); - $zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level'); + $longitudeKey = $this->getLocationKey($prefix, 'longitude'); + $latitudeKey = $this->getLocationKey($prefix, 'latitude'); + $zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level'); $hasLocationKey = $this->getLocationKey($prefix, 'has_location'); Log::debug('Now in isValidPUT()'); // all fields must be set: - if( null !== $this->get($longitudeKey) && null !== $this->get($latitudeKey) && null !== $this->get($zoomLevelKey)) { + if (null !== $this->get($longitudeKey) && null !== $this->get($latitudeKey) && null !== $this->get($zoomLevelKey)) { Log::debug('All fields present.'); // must be PUT and API route: if ('PUT' === $this->method() && $this->routeIs('api.v1.*')) { Log::debug('Is API location'); + return true; } // if POST and not API route, must also have "has_location" @@ -257,4 +249,13 @@ trait AppendsLocationData } + /** + * Abstract method to ensure filling later. + * + * @param string $field + * + * @return string|null + */ + abstract protected function nullableString(string $field): ?string; + } diff --git a/app/Support/Request/ConvertsDataTypes.php b/app/Support/Request/ConvertsDataTypes.php index e2ff0e08fa..032dd4fbea 100644 --- a/app/Support/Request/ConvertsDataTypes.php +++ b/app/Support/Request/ConvertsDataTypes.php @@ -33,46 +33,6 @@ use Log; trait ConvertsDataTypes { - /** - * Returns all data in the request, or omits the field if not set, - * according to the config from the request. This is the way. - * - * @param array $fields - * - * @return array - */ - protected function getAllData(array $fields): array - { - $return = []; - foreach ($fields as $field => $info) { - if ($this->has($info[0])) { - $method = $info[1]; - $return[$field] = $this->$method($info[0]); - } - } - - return $return; - } - - /** - * Return date or NULL. - * - * @param string $field - * - * @return Carbon|null - */ - protected function date(string $field): ?Carbon - { - $result = null; - try { - $result = $this->get($field) ? new Carbon($this->get($field)) : null; - } catch (Exception $e) { - Log::debug(sprintf('Exception when parsing date. Not interesting: %s', $e->getMessage())); - } - - return $result; - } - /** * Return integer value. * @@ -85,41 +45,28 @@ trait ConvertsDataTypes return (int)$this->get($field); } - /** - * Return floating value. + * Return string value, but keep newlines. * * @param string $field * - * @return float|null + * @return string */ - protected function float(string $field): ?float + public function nlString(string $field): string { - $res = $this->get($field); - if (null === $res) { - return null; - } - - return (float)$res; + return app('steam')->nlCleanString((string)($this->get($field) ?? '')); } - /** - * Parse and clean a string, but keep the newlines. + * Return string value. * - * @param string|null $string + * @param string $field * - * @return string|null + * @return string */ - protected function nlStringFromValue(?string $string): ?string + public function string(string $field): string { - if (null === $string) { - return null; - } - $result = app('steam')->nlCleanString($string); - - return '' === $result ? null : $result; - + return app('steam')->cleanString((string)($this->get($field) ?? '')); } /** @@ -142,6 +89,56 @@ trait ConvertsDataTypes return null; } + /** + * @param string $value + * + * @return bool + */ + protected function convertBoolean(?string $value): bool + { + if (null === $value) { + return false; + } + if ('' === $value) { + return false; + } + if ('true' === $value) { + return true; + } + if ('yes' === $value) { + return true; + } + if (1 === $value) { + return true; + } + if ('1' === $value) { + return true; + } + if (true === $value) { + return true; + } + + return false; + } + + /** + * Return date or NULL. + * + * @param string $field + * + * @return Carbon|null + */ + protected function date(string $field): ?Carbon + { + $result = null; + try { + $result = $this->get($field) ? new Carbon($this->get($field)) : null; + } catch (Exception $e) { + Log::debug(sprintf('Exception when parsing date. Not interesting: %s', $e->getMessage())); + } + + return $result; + } /** * @param string|null $string @@ -169,22 +166,42 @@ trait ConvertsDataTypes } /** - * Parse and clean a string. + * Return floating value. * - * @param string|null $string + * @param string $field * - * @return string|null + * @return float|null */ - protected function stringFromValue(?string $string): ?string + protected function float(string $field): ?float { - if (null === $string) { + $res = $this->get($field); + if (null === $res) { return null; } - $result = app('steam')->cleanString($string); - return '' === $result ? null : $result; + return (float)$res; } + /** + * Returns all data in the request, or omits the field if not set, + * according to the config from the request. This is the way. + * + * @param array $fields + * + * @return array + */ + protected function getAllData(array $fields): array + { + $return = []; + foreach ($fields as $field => $info) { + if ($this->has($info[0])) { + $method = $info[1]; + $return[$field] = $this->$method($info[0]); + } + } + + return $return; + } /** * Parse to integer @@ -206,15 +223,21 @@ trait ConvertsDataTypes } /** - * Return string value, but keep newlines. + * Parse and clean a string, but keep the newlines. * - * @param string $field + * @param string|null $string * - * @return string + * @return string|null */ - public function nlString(string $field): string + protected function nlStringFromValue(?string $string): ?string { - return app('steam')->nlCleanString((string)($this->get($field) ?? '')); + if (null === $string) { + return null; + } + $result = app('steam')->nlCleanString($string); + + return '' === $result ? null : $result; + } /** @@ -254,39 +277,6 @@ trait ConvertsDataTypes return app('steam')->nlCleanString((string)($this->get($field) ?? '')); } - - /** - * @param string $value - * - * @return bool - */ - protected function convertBoolean(?string $value): bool - { - if (null === $value) { - return false; - } - if ('' === $value) { - return false; - } - if ('true' === $value) { - return true; - } - if ('yes' === $value) { - return true; - } - if (1 === $value) { - return true; - } - if ('1' === $value) { - return true; - } - if (true === $value) { - return true; - } - - return false; - } - /** * Return string value, or NULL if empty. * @@ -308,14 +298,19 @@ trait ConvertsDataTypes } /** - * Return string value. + * Parse and clean a string. * - * @param string $field + * @param string|null $string * - * @return string + * @return string|null */ - public function string(string $field): string + protected function stringFromValue(?string $string): ?string { - return app('steam')->cleanString((string)($this->get($field) ?? '')); + if (null === $string) { + return null; + } + $result = app('steam')->cleanString($string); + + return '' === $result ? null : $result; } } diff --git a/app/Support/Request/GetRuleConfiguration.php b/app/Support/Request/GetRuleConfiguration.php index a852550c38..18c11d6688 100644 --- a/app/Support/Request/GetRuleConfiguration.php +++ b/app/Support/Request/GetRuleConfiguration.php @@ -69,6 +69,7 @@ trait GetRuleConfiguration $return[] = $key; } } + return $return; } } diff --git a/app/Support/Search/AccountSearch.php b/app/Support/Search/AccountSearch.php index 1b781771d4..4f22a75030 100644 --- a/app/Support/Search/AccountSearch.php +++ b/app/Support/Search/AccountSearch.php @@ -61,7 +61,7 @@ class AccountSearch implements GenericSearchInterface public function search(): Collection { - $searchQuery = $this->user->accounts() + $searchQuery = $this->user->accounts() ->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id') ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') ->whereIn('account_types.type', $this->types); diff --git a/app/Support/Search/OperatorQuerySearch.php b/app/Support/Search/OperatorQuerySearch.php index 966e2905df..9188dba8df 100644 --- a/app/Support/Search/OperatorQuerySearch.php +++ b/app/Support/Search/OperatorQuerySearch.php @@ -86,21 +86,21 @@ class OperatorQuerySearch implements SearchInterface private BillRepositoryInterface $billRepository; private BudgetRepositoryInterface $budgetRepository; private CategoryRepositoryInterface $categoryRepository; - private TagRepositoryInterface $tagRepository; - private CurrencyRepositoryInterface $currencyRepository; - private TransactionTypeRepositoryInterface $typeRepository; - private User $user; - private ParsedQuery $query; - private int $page; - private int $limit; - private array $words; - private array $validOperators; private GroupCollectorInterface $collector; - private float $startTime; - private Collection $modifiers; // obsolete + private CurrencyRepositoryInterface $currencyRepository; + private Carbon $date; + private int $limit; +private Collection $modifiers; private Collection $operators; private string $originalQuery; - private Carbon $date; + private int $page; + private ParsedQuery $query; + private float $startTime; + private TagRepositoryInterface $tagRepository; + private TransactionTypeRepositoryInterface $typeRepository; // obsolete + private User $user; + private array $validOperators; + private array $words; /** * OperatorQuerySearch constructor. @@ -146,14 +146,6 @@ class OperatorQuerySearch implements SearchInterface return $this->operators; } - /** - * @param Carbon $date - */ - public function setDate(Carbon $date): void - { - $this->date = $date; - } - /** * @inheritDoc * @codeCoverageIgnore @@ -163,24 +155,6 @@ class OperatorQuerySearch implements SearchInterface return implode(' ', $this->words); } - /** - * @return array - */ - public function getWords(): array - { - return $this->words; - } - - /** - * @inheritDoc - * @codeCoverageIgnore - */ - public function setPage(int $page): void - { - $this->page = $page; - $this->collector->setPage($this->page); - } - /** * @inheritDoc * @codeCoverageIgnore @@ -231,6 +205,33 @@ class OperatorQuerySearch implements SearchInterface return $this->collector->getPaginatedGroups(); } + /** + * @param Carbon $date + */ + public function setDate(Carbon $date): void + { + $this->date = $date; + } + + /** + * @param int $limit + */ + public function setLimit(int $limit): void + { + $this->limit = $limit; + $this->collector->setLimit($this->limit); + } + + /** + * @inheritDoc + * @codeCoverageIgnore + */ + public function setPage(int $page): void + { + $this->page = $page; + $this->collector->setPage($this->page); + } + /** * @inheritDoc * @codeCoverageIgnore @@ -644,6 +645,28 @@ class OperatorQuerySearch implements SearchInterface return true; } + /** + * @param string $operator + * + * @return string + * @throws FireflyException + */ + public static function getRootOperator(string $operator): string + { + $config = config(sprintf('firefly.search.operators.%s', $operator)); + if (null === $config) { + throw new FireflyException(sprintf('No configuration for search operator "%s"', $operator)); + } + if (true === $config['alias']) { + Log::debug(sprintf('"%s" is an alias for "%s", so return that instead.', $operator, $config['alias_for'])); + + return $config['alias_for']; + } + Log::debug(sprintf('"%s" is not an alias.', $operator)); + + return $operator; + } + /** * searchDirection: 1 = source (default), 2 = destination * stringPosition: 1 = start (default), 2 = end, 3 = contains, 4 = is @@ -709,7 +732,6 @@ class OperatorQuerySearch implements SearchInterface $this->collector->$collectorMethod($filtered); } - /** * searchDirection: 1 = source (default), 2 = destination * stringPosition: 1 = start (default), 2 = end, 3 = contains, 4 = is @@ -787,6 +809,14 @@ class OperatorQuerySearch implements SearchInterface $this->collector->$collectorMethod($filtered); } + /** + * @return Account + */ + private function getCashAccount(): Account + { + return $this->accountRepository->getCashAccount(); + } + /** * @param string $value * @@ -809,28 +839,6 @@ class OperatorQuerySearch implements SearchInterface return $result; } - /** - * @param string $operator - * - * @return string - * @throws FireflyException - */ - public static function getRootOperator(string $operator): string - { - $config = config(sprintf('firefly.search.operators.%s', $operator)); - if (null === $config) { - throw new FireflyException(sprintf('No configuration for search operator "%s"', $operator)); - } - if (true === $config['alias']) { - Log::debug(sprintf('"%s" is an alias for "%s", so return that instead.', $operator, $config['alias_for'])); - - return $config['alias_for']; - } - Log::debug(sprintf('"%s" is not an alias.', $operator)); - - return $operator; - } - /** * @param string $value * @@ -852,19 +860,10 @@ class OperatorQuerySearch implements SearchInterface } /** - * @param int $limit + * @return array */ - public function setLimit(int $limit): void + public function getWords(): array { - $this->limit = $limit; - $this->collector->setLimit($this->limit); - } - - /** - * @return Account - */ - private function getCashAccount(): Account - { - return $this->accountRepository->getCashAccount(); + return $this->words; } } diff --git a/app/Support/Search/SearchInterface.php b/app/Support/Search/SearchInterface.php index 0dcfcc0f7d..fe5a44fa9c 100644 --- a/app/Support/Search/SearchInterface.php +++ b/app/Support/Search/SearchInterface.php @@ -47,16 +47,6 @@ interface SearchInterface */ public function getWordsAsString(): string; - /** - * @param int $page - */ - public function setPage(int $page): void; - - /** - * @param int $limit - */ - public function setLimit(int $limit): void; - /** * @return bool */ @@ -77,13 +67,23 @@ interface SearchInterface */ public function searchTransactions(): LengthAwarePaginator; - /** - * @param User $user - */ - public function setUser(User $user); - /** * @param Carbon $date */ public function setDate(Carbon $date): void; + + /** + * @param int $limit + */ + public function setLimit(int $limit): void; + + /** + * @param int $page + */ + public function setPage(int $page): void; + + /** + * @param User $user + */ + public function setUser(User $user); } diff --git a/app/Support/System/GeneratesInstallationId.php b/app/Support/System/GeneratesInstallationId.php index 15ea57d3e7..f4e468e791 100644 --- a/app/Support/System/GeneratesInstallationId.php +++ b/app/Support/System/GeneratesInstallationId.php @@ -39,9 +39,10 @@ trait GeneratesInstallationId protected function generateInstallationId(): void { try { - $config = app('fireflyconfig')->get('installation_id', null); - } catch(FireflyException $e) { + $config = app('fireflyconfig')->get('installation_id', null); + } catch (FireflyException $e) { Log::info('Could not create or generate installation ID. Do not continue.'); + return; } @@ -52,7 +53,7 @@ trait GeneratesInstallationId if (null === $config) { $uuid4 = Uuid::uuid4(); - $uniqueId = (string) $uuid4; + $uniqueId = (string)$uuid4; Log::info(sprintf('Created Firefly III installation ID %s', $uniqueId)); app('fireflyconfig')->set('installation_id', $uniqueId); } diff --git a/app/Support/System/OAuthKeys.php b/app/Support/System/OAuthKeys.php index e6cb83dfa0..7817af69e7 100644 --- a/app/Support/System/OAuthKeys.php +++ b/app/Support/System/OAuthKeys.php @@ -36,58 +36,6 @@ class OAuthKeys private const PRIVATE_KEY = 'oauth_private_key'; private const PUBLIC_KEY = 'oauth_public_key'; - /** - * - */ - public static function generateKeys(): void - { - Artisan::registerCommand(new KeysCommand()); - Artisan::call('passport:keys'); - } - - /** - * @return bool - */ - public static function hasKeyFiles(): bool - { - $private = storage_path('oauth-private.key'); - $public = storage_path('oauth-public.key'); - - return file_exists($private) && file_exists($public); - } - - /** - * @return bool - */ - public static function keysInDatabase(): bool - { - return app('fireflyconfig')->has(self::PRIVATE_KEY) && app('fireflyconfig')->has(self::PUBLIC_KEY); - } - - /** - * - */ - public static function restoreKeysFromDB(): void - { - $privateContent = Crypt::decrypt(app('fireflyconfig')->get(self::PRIVATE_KEY)->data); - $publicContent = Crypt::decrypt(app('fireflyconfig')->get(self::PUBLIC_KEY)->data); - $private = storage_path('oauth-private.key'); - $public = storage_path('oauth-public.key'); - file_put_contents($private, $privateContent); - file_put_contents($public, $publicContent); - } - - /** - * - */ - public static function storeKeysInDB(): void - { - $private = storage_path('oauth-private.key'); - $public = storage_path('oauth-public.key'); - app('fireflyconfig')->set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private))); - app('fireflyconfig')->set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public))); - } - /** * */ @@ -109,4 +57,56 @@ class OAuthKeys } } + /** + * @return bool + */ + public static function keysInDatabase(): bool + { + return app('fireflyconfig')->has(self::PRIVATE_KEY) && app('fireflyconfig')->has(self::PUBLIC_KEY); + } + + /** + * @return bool + */ + public static function hasKeyFiles(): bool + { + $private = storage_path('oauth-private.key'); + $public = storage_path('oauth-public.key'); + + return file_exists($private) && file_exists($public); + } + + /** + * + */ + public static function generateKeys(): void + { + Artisan::registerCommand(new KeysCommand()); + Artisan::call('passport:keys'); + } + + /** + * + */ + public static function storeKeysInDB(): void + { + $private = storage_path('oauth-private.key'); + $public = storage_path('oauth-public.key'); + app('fireflyconfig')->set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private))); + app('fireflyconfig')->set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public))); + } + + /** + * + */ + public static function restoreKeysFromDB(): void + { + $privateContent = Crypt::decrypt(app('fireflyconfig')->get(self::PRIVATE_KEY)->data); + $publicContent = Crypt::decrypt(app('fireflyconfig')->get(self::PUBLIC_KEY)->data); + $private = storage_path('oauth-private.key'); + $public = storage_path('oauth-public.key'); + file_put_contents($private, $privateContent); + file_put_contents($public, $publicContent); + } + } diff --git a/app/Support/Twig/AmountFormat.php b/app/Support/Twig/AmountFormat.php index 233d991385..11303f80e0 100644 --- a/app/Support/Twig/AmountFormat.php +++ b/app/Support/Twig/AmountFormat.php @@ -25,9 +25,9 @@ namespace FireflyIII\Support\Twig; use FireflyIII\Models\Account as AccountModel; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Account\AccountRepositoryInterface; -use Twig\TwigFunction; -use Twig\TwigFilter; use Twig\Extension\AbstractExtension; +use Twig\TwigFilter; +use Twig\TwigFunction; /** * Contains all amount formatting routines. @@ -73,6 +73,22 @@ class AmountFormat extends AbstractExtension ); } + /** + * @return TwigFilter + */ + protected function formatAmountPlain(): TwigFilter + { + return new TwigFilter( + 'formatAmountPlain', + static function (string $string): string { + $currency = app('amount')->getDefaultCurrency(); + + return app('amount')->formatAnything($currency, $string, false); + }, + ['is_safe' => ['html']] + ); + } + /** * Will format the amount by the currency related to the given account. * @@ -96,24 +112,6 @@ class AmountFormat extends AbstractExtension ); } - /** - * Will format the amount by the currency related to the given account. - * - * @return TwigFunction - */ - protected function formatAmountByCurrency(): TwigFunction - { - return new TwigFunction( - 'formatAmountByCurrency', - static function (TransactionCurrency $currency, string $amount, bool $coloured = null): string { - $coloured = $coloured ?? true; - - return app('amount')->formatAnything($currency, $amount, $coloured); - }, - ['is_safe' => ['html']] - ); - } - /** * Will format the amount by the currency related to the given account. * @@ -138,16 +136,18 @@ class AmountFormat extends AbstractExtension } /** - * @return TwigFilter + * Will format the amount by the currency related to the given account. + * + * @return TwigFunction */ - protected function formatAmountPlain(): TwigFilter + protected function formatAmountByCurrency(): TwigFunction { - return new TwigFilter( - 'formatAmountPlain', - static function (string $string): string { - $currency = app('amount')->getDefaultCurrency(); + return new TwigFunction( + 'formatAmountByCurrency', + static function (TransactionCurrency $currency, string $amount, bool $coloured = null): string { + $coloured = $coloured ?? true; - return app('amount')->formatAnything($currency, $string, false); + return app('amount')->formatAnything($currency, $amount, $coloured); }, ['is_safe' => ['html']] ); diff --git a/app/Support/Twig/General.php b/app/Support/Twig/General.php index 7812e9434a..58da41788b 100644 --- a/app/Support/Twig/General.php +++ b/app/Support/Twig/General.php @@ -72,109 +72,6 @@ class General extends AbstractExtension ]; } - protected function getRootSearchOperator(): TwigFunction - { - return new TwigFunction( - 'getRootSearchOperator', - static function (string $operator): string { - return OperatorQuerySearch::getRootOperator($operator); - } - ); - } - - /** - * Will return "active" when a part of the route matches the argument. - * ie. "accounts" will match "accounts.index". - * - * @return TwigFunction - */ - protected function activeRoutePartial(): TwigFunction - { - return new TwigFunction( - 'activeRoutePartial', - static function (): string { - $args = func_get_args(); - $route = $args[0]; // name of the route. - $name = Route::getCurrentRoute()->getName() ?? ''; - if (false !== strpos($name, $route)) { - return 'active'; - } - - return ''; - } - ); - } - - /** - * Will return "menu-open" when a part of the route matches the argument. - * ie. "accounts" will match "accounts.index". - * - * @return TwigFunction - */ - protected function menuOpenRoutePartial(): TwigFunction - { - return new TwigFunction( - 'menuOpenRoutePartial', - static function (): string { - $args = func_get_args(); - $route = $args[0]; // name of the route. - $name = Route::getCurrentRoute()->getName() ?? ''; - if (false !== strpos($name, $route)) { - return 'menu-open'; - } - - return ''; - } - ); - } - - /** - * This function will return "active" when the current route matches the first argument (even partly) - * but, the variable $objectType has been set and matches the second argument. - * - * @return TwigFunction - */ - protected function activeRoutePartialObjectType(): TwigFunction - { - return new TwigFunction( - 'activeRoutePartialObjectType', - static function ($context): string { - [, $route, $objectType] = func_get_args(); - $activeObjectType = $context['objectType'] ?? false; - - if ($objectType === $activeObjectType && false !== stripos(Route::getCurrentRoute()->getName(), $route)) { - return 'active'; - } - - return ''; - }, - ['needs_context' => true] - ); - } - - /** - * Will return "active" when the current route matches the given argument - * exactly. - * - * @return TwigFunction - */ - protected function activeRouteStrict(): TwigFunction - { - return new TwigFunction( - 'activeRouteStrict', - static function (): string { - $args = func_get_args(); - $route = $args[0]; // name of the route. - - if (Route::getCurrentRoute()->getName() === $route) { - return 'active'; - } - - return ''; - } - ); - } - /** * Show account balance. Only used on the front page of Firefly III. * @@ -196,23 +93,6 @@ class General extends AbstractExtension ); } - /** - * Formats a string as a thing by converting it to a Carbon first. - * - * @return TwigFunction - */ - protected function formatDate(): TwigFunction - { - return new TwigFunction( - 'formatDate', - function (string $date, string $format): string { - $carbon = new Carbon($date); - - return $carbon->formatLocalized($format); - } - ); - } - /** * Used to convert 1024 to 1kb etc. * @@ -238,79 +118,6 @@ class General extends AbstractExtension ); } - /** - * @return TwigFunction - * @deprecated because it uses a query in a view - * TODO remove me. - */ - protected function getMetaField(): TwigFunction - { - return new TwigFunction( - 'accountGetMetaField', - static function (Account $account, string $field): string { - /** @var AccountRepositoryInterface $repository */ - $repository = app(AccountRepositoryInterface::class); - $result = $repository->getMetaValue($account, $field); - if (null === $result) { - return ''; - } - - return $result; - } - ); - } - - /** - * Will return true if the user is of role X. - * - * @return TwigFunction - */ - protected function hasRole(): TwigFunction - { - return new TwigFunction( - 'hasRole', - static function (string $role): bool { - $repository = app(UserRepositoryInterface::class); - if ($repository->hasRole(auth()->user(), $role)) { - return true; - } - - return false; - } - ); - } - - /** - * @return TwigFilter - */ - protected function markdown(): TwigFilter - { - return new TwigFilter( - 'markdown', - static function (string $text): string { - $environment = Environment::createCommonMarkEnvironment(); - $environment->addExtension(new GithubFlavoredMarkdownExtension()); - - $converter = new CommonMarkConverter(['allow_unsafe_links' => false, 'max_nesting_level' => 3, 'html_input' => 'escape'], $environment); - - return $converter->convertToHtml($text); - }, ['is_safe' => ['html']] - ); - } - - /** - * @return TwigFilter - */ - protected function floatval(): TwigFilter - { - return new TwigFilter( - 'floatval', - static function ($value): float { - return (float)$value; - } - ); - } - /** * Show icon with attachment. * @@ -390,6 +197,37 @@ class General extends AbstractExtension ); } + /** + * @return TwigFilter + */ + protected function markdown(): TwigFilter + { + return new TwigFilter( + 'markdown', + static function (string $text): string { + $environment = Environment::createCommonMarkEnvironment(); + $environment->addExtension(new GithubFlavoredMarkdownExtension()); + + $converter = new CommonMarkConverter(['allow_unsafe_links' => false, 'max_nesting_level' => 3, 'html_input' => 'escape'], $environment); + + return $converter->convertToHtml($text); + }, ['is_safe' => ['html']] + ); + } + + /** + * @return TwigFilter + */ + protected function floatval(): TwigFilter + { + return new TwigFilter( + 'floatval', + static function ($value): float { + return (float)$value; + } + ); + } + /** * Basic example thing for some views. * @@ -404,4 +242,166 @@ class General extends AbstractExtension } ); } + + /** + * Will return "active" when the current route matches the given argument + * exactly. + * + * @return TwigFunction + */ + protected function activeRouteStrict(): TwigFunction + { + return new TwigFunction( + 'activeRouteStrict', + static function (): string { + $args = func_get_args(); + $route = $args[0]; // name of the route. + + if (Route::getCurrentRoute()->getName() === $route) { + return 'active'; + } + + return ''; + } + ); + } + + /** + * Will return "active" when a part of the route matches the argument. + * ie. "accounts" will match "accounts.index". + * + * @return TwigFunction + */ + protected function activeRoutePartial(): TwigFunction + { + return new TwigFunction( + 'activeRoutePartial', + static function (): string { + $args = func_get_args(); + $route = $args[0]; // name of the route. + $name = Route::getCurrentRoute()->getName() ?? ''; + if (false !== strpos($name, $route)) { + return 'active'; + } + + return ''; + } + ); + } + + /** + * This function will return "active" when the current route matches the first argument (even partly) + * but, the variable $objectType has been set and matches the second argument. + * + * @return TwigFunction + */ + protected function activeRoutePartialObjectType(): TwigFunction + { + return new TwigFunction( + 'activeRoutePartialObjectType', + static function ($context): string { + [, $route, $objectType] = func_get_args(); + $activeObjectType = $context['objectType'] ?? false; + + if ($objectType === $activeObjectType && false !== stripos(Route::getCurrentRoute()->getName(), $route)) { + return 'active'; + } + + return ''; + }, + ['needs_context' => true] + ); + } + + /** + * Will return "menu-open" when a part of the route matches the argument. + * ie. "accounts" will match "accounts.index". + * + * @return TwigFunction + */ + protected function menuOpenRoutePartial(): TwigFunction + { + return new TwigFunction( + 'menuOpenRoutePartial', + static function (): string { + $args = func_get_args(); + $route = $args[0]; // name of the route. + $name = Route::getCurrentRoute()->getName() ?? ''; + if (false !== strpos($name, $route)) { + return 'menu-open'; + } + + return ''; + } + ); + } + + /** + * Formats a string as a thing by converting it to a Carbon first. + * + * @return TwigFunction + */ + protected function formatDate(): TwigFunction + { + return new TwigFunction( + 'formatDate', + function (string $date, string $format): string { + $carbon = new Carbon($date); + + return $carbon->formatLocalized($format); + } + ); + } + + /** + * @return TwigFunction + * @deprecated because it uses a query in a view + * TODO remove me. + */ + protected function getMetaField(): TwigFunction + { + return new TwigFunction( + 'accountGetMetaField', + static function (Account $account, string $field): string { + /** @var AccountRepositoryInterface $repository */ + $repository = app(AccountRepositoryInterface::class); + $result = $repository->getMetaValue($account, $field); + if (null === $result) { + return ''; + } + + return $result; + } + ); + } + + /** + * Will return true if the user is of role X. + * + * @return TwigFunction + */ + protected function hasRole(): TwigFunction + { + return new TwigFunction( + 'hasRole', + static function (string $role): bool { + $repository = app(UserRepositoryInterface::class); + if ($repository->hasRole(auth()->user(), $role)) { + return true; + } + + return false; + } + ); + } + + protected function getRootSearchOperator(): TwigFunction + { + return new TwigFunction( + 'getRootSearchOperator', + static function (string $operator): string { + return OperatorQuerySearch::getRootOperator($operator); + } + ); + } } diff --git a/app/Support/Twig/Rule.php b/app/Support/Twig/Rule.php index b09f891e61..45e197a9bd 100644 --- a/app/Support/Twig/Rule.php +++ b/app/Support/Twig/Rule.php @@ -32,25 +32,15 @@ use Twig\TwigFunction; class Rule extends AbstractExtension { /** - * @return TwigFunction + * @return array */ - public function allActionTriggers(): TwigFunction + public function getFunctions(): array { - return new TwigFunction( - 'allRuleActions', - static function () { - // array of valid values for actions - $ruleActions = array_keys(Config::get('firefly.rule-actions')); - $possibleActions = []; - foreach ($ruleActions as $key) { - $possibleActions[$key] = (string)trans('firefly.rule_action_' . $key . '_choice'); - } - unset($ruleActions); - asort($possibleActions); - - return $possibleActions; - } - ); + return [ + $this->allJournalTriggers(), + $this->allRuleTriggers(), + $this->allActionTriggers(), + ]; } /** @@ -93,14 +83,24 @@ class Rule extends AbstractExtension } /** - * @return array + * @return TwigFunction */ - public function getFunctions(): array + public function allActionTriggers(): TwigFunction { - return [ - $this->allJournalTriggers(), - $this->allRuleTriggers(), - $this->allActionTriggers(), - ]; + return new TwigFunction( + 'allRuleActions', + static function () { + // array of valid values for actions + $ruleActions = array_keys(Config::get('firefly.rule-actions')); + $possibleActions = []; + foreach ($ruleActions as $key) { + $possibleActions[$key] = (string)trans('firefly.rule_action_' . $key . '_choice'); + } + unset($ruleActions); + asort($possibleActions); + + return $possibleActions; + } + ); } } diff --git a/app/Support/Twig/TransactionGroupTwig.php b/app/Support/Twig/TransactionGroupTwig.php index 934411517e..31e9c558b1 100644 --- a/app/Support/Twig/TransactionGroupTwig.php +++ b/app/Support/Twig/TransactionGroupTwig.php @@ -29,7 +29,6 @@ use FireflyIII\Models\AccountType; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; -use Log; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; @@ -54,6 +53,226 @@ class TransactionGroupTwig extends AbstractExtension ]; } + /** + * Shows the amount for a single journal array. + * + * @return TwigFunction + */ + public function journalArrayAmount(): TwigFunction + { + return new TwigFunction( + 'journalArrayAmount', + function (array $array): string { + // if is not a withdrawal, amount positive. + $result = $this->normalJournalArrayAmount($array); + // now append foreign amount, if any. + if (null !== $array['foreign_amount']) { + $foreign = $this->foreignJournalArrayAmount($array); + $result = sprintf('%s (%s)', $result, $foreign); + } + + return $result; + }, + ['is_safe' => ['html']] + ); + } + + /** + * Generate normal amount for transaction from a transaction group. + * + * @param array $array + * + * @return string + */ + private function normalJournalArrayAmount(array $array): string + { + $type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL; + $amount = $array['amount'] ?? '0'; + $colored = true; + $sourceType = $array['source_account_type'] ?? 'invalid'; + $amount = $this->signAmount($amount, $type, $sourceType); + + if ($type === TransactionType::TRANSFER) { + $colored = false; + } + + $result = app('amount')->formatFlat($array['currency_symbol'], (int)$array['currency_decimal_places'], $amount, $colored); + if ($type === TransactionType::TRANSFER) { + $result = sprintf('%s', $result); + } + + return $result; + } + + /** + * @param string $amount + * @param string $transactionType + * @param string $sourceType + * + * @return string + */ + private function signAmount(string $amount, string $transactionType, string $sourceType): string + { + + // withdrawals stay negative + if ($transactionType !== TransactionType::WITHDRAWAL) { + $amount = bcmul($amount, '-1'); + } + + // opening balance and it comes from initial balance? its expense. + if ($transactionType === TransactionType::OPENING_BALANCE && AccountType::INITIAL_BALANCE !== $sourceType) { + $amount = bcmul($amount, '-1'); + } + + // reconciliation and it comes from reconciliation? + if ($transactionType === TransactionType::RECONCILIATION && AccountType::RECONCILIATION !== $sourceType) { + $amount = bcmul($amount, '-1'); + } + + return $amount; + } + + /** + * Generate foreign amount for transaction from a transaction group. + * + * @param array $array + * + * @return string + */ + private function foreignJournalArrayAmount(array $array): string + { + $type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL; + $amount = $array['foreign_amount'] ?? '0'; + $colored = true; + + $sourceType = $array['source_account_type'] ?? 'invalid'; + $amount = $this->signAmount($amount, $type, $sourceType); + + if ($type === TransactionType::TRANSFER) { + $colored = false; + } + $result = app('amount')->formatFlat($array['foreign_currency_symbol'], (int)$array['foreign_currency_decimal_places'], $amount, $colored); + if ($type === TransactionType::TRANSFER) { + $result = sprintf('%s', $result); + } + + return $result; + } + + /** + * Shows the amount for a single journal object. + * + * @return TwigFunction + */ + public function journalObjectAmount(): TwigFunction + { + return new TwigFunction( + 'journalObjectAmount', + function (TransactionJournal $journal): string { + $result = $this->normalJournalObjectAmount($journal); + // now append foreign amount, if any. + if ($this->journalObjectHasForeign($journal)) { + $foreign = $this->foreignJournalObjectAmount($journal); + $result = sprintf('%s (%s)', $result, $foreign); + } + + return $result; + }, + ['is_safe' => ['html']] + ); + } + + /** + * Generate normal amount for transaction from a transaction group. + * + * @param TransactionJournal $journal + * + * @return string + */ + private function normalJournalObjectAmount(TransactionJournal $journal): string + { + $type = $journal->transactionType->type; + $first = $journal->transactions()->where('amount', '<', 0)->first(); + $currency = $journal->transactionCurrency; + $amount = $first->amount ?? '0'; + $colored = true; + $sourceType = $first->account()->first()->accountType()->first()->type; + + $amount = $this->signAmount($amount, $type, $sourceType); + + if ($type === TransactionType::TRANSFER) { + $colored = false; + } + $result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored); + if ($type === TransactionType::TRANSFER) { + $result = sprintf('%s', $result); + } + + return $result; + } + + /** + * @param TransactionJournal $journal + * + * @return bool + */ + private function journalObjectHasForeign(TransactionJournal $journal): bool + { + /** @var Transaction $first */ + $first = $journal->transactions()->where('amount', '<', 0)->first(); + + return null !== $first->foreign_amount; + } + + /** + * Generate foreign amount for journal from a transaction group. + * + * @param TransactionJournal $journal + * + * @return string + */ + private function foreignJournalObjectAmount(TransactionJournal $journal): string + { + $type = $journal->transactionType->type; + /** @var Transaction $first */ + $first = $journal->transactions()->where('amount', '<', 0)->first(); + $currency = $first->foreignCurrency; + $amount = $first->foreign_amount ?? '0'; + $colored = true; + $sourceType = $first->account()->first()->accountType()->first()->type; + + $amount = $this->signAmount($amount, $type, $sourceType); + + if ($type === TransactionType::TRANSFER) { + $colored = false; + } + $result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored); + if ($type === TransactionType::TRANSFER) { + $result = sprintf('%s', $result); + } + + return $result; + } + + /** + * @return TwigFunction + */ + public function journalHasMeta(): TwigFunction + { + return new TwigFunction( + 'journalHasMeta', + static function (int $journalId, string $metaField) { + $count = DB::table('journal_meta') + ->where('name', $metaField) + ->where('transaction_journal_id', $journalId) + ->whereNull('deleted_at') + ->count(); + + return 1 === $count; + } + ); + } + /** * @return TwigFunction */ @@ -97,222 +316,4 @@ class TransactionGroupTwig extends AbstractExtension } ); } - - /** - * @return TwigFunction - */ - public function journalHasMeta(): TwigFunction - { - return new TwigFunction( - 'journalHasMeta', - static function (int $journalId, string $metaField) { - $count = DB::table('journal_meta') - ->where('name', $metaField) - ->where('transaction_journal_id', $journalId) - ->whereNull('deleted_at') - ->count(); - - return 1 === $count; - } - ); - } - - /** - * Shows the amount for a single journal array. - * - * @return TwigFunction - */ - public function journalArrayAmount(): TwigFunction - { - return new TwigFunction( - 'journalArrayAmount', - function (array $array): string { - // if is not a withdrawal, amount positive. - $result = $this->normalJournalArrayAmount($array); - // now append foreign amount, if any. - if (null !== $array['foreign_amount']) { - $foreign = $this->foreignJournalArrayAmount($array); - $result = sprintf('%s (%s)', $result, $foreign); - } - - return $result; - }, - ['is_safe' => ['html']] - ); - } - - /** - * Shows the amount for a single journal object. - * - * @return TwigFunction - */ - public function journalObjectAmount(): TwigFunction - { - return new TwigFunction( - 'journalObjectAmount', - function (TransactionJournal $journal): string { - $result = $this->normalJournalObjectAmount($journal); - // now append foreign amount, if any. - if ($this->journalObjectHasForeign($journal)) { - $foreign = $this->foreignJournalObjectAmount($journal); - $result = sprintf('%s (%s)', $result, $foreign); - } - - return $result; - }, - ['is_safe' => ['html']] - ); - } - - /** - * Generate foreign amount for transaction from a transaction group. - * - * @param array $array - * - * @return string - */ - private function foreignJournalArrayAmount(array $array): string - { - $type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL; - $amount = $array['foreign_amount'] ?? '0'; - $colored = true; - - $sourceType = $array['source_account_type'] ?? 'invalid'; - $amount = $this->signAmount($amount, $type, $sourceType); - - if ($type === TransactionType::TRANSFER) { - $colored = false; - } - $result = app('amount')->formatFlat($array['foreign_currency_symbol'], (int) $array['foreign_currency_decimal_places'], $amount, $colored); - if ($type === TransactionType::TRANSFER) { - $result = sprintf('%s', $result); - } - - return $result; - } - - /** - * Generate foreign amount for journal from a transaction group. - * - * @param TransactionJournal $journal - * - * @return string - */ - private function foreignJournalObjectAmount(TransactionJournal $journal): string - { - $type = $journal->transactionType->type; - /** @var Transaction $first */ - $first = $journal->transactions()->where('amount', '<', 0)->first(); - $currency = $first->foreignCurrency; - $amount = $first->foreign_amount ?? '0'; - $colored = true; - $sourceType = $first->account()->first()->accountType()->first()->type; - - $amount = $this->signAmount($amount, $type, $sourceType); - - if ($type === TransactionType::TRANSFER) { - $colored = false; - } - $result = app('amount')->formatFlat($currency->symbol, (int) $currency->decimal_places, $amount, $colored); - if ($type === TransactionType::TRANSFER) { - $result = sprintf('%s', $result); - } - - return $result; - } - - /** - * Generate normal amount for transaction from a transaction group. - * - * @param array $array - * - * @return string - */ - private function normalJournalArrayAmount(array $array): string - { - $type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL; - $amount = $array['amount'] ?? '0'; - $colored = true; - $sourceType = $array['source_account_type'] ?? 'invalid'; - $amount = $this->signAmount($amount, $type, $sourceType); - - if ($type === TransactionType::TRANSFER) { - $colored = false; - } - - $result = app('amount')->formatFlat($array['currency_symbol'], (int) $array['currency_decimal_places'], $amount, $colored); - if ($type === TransactionType::TRANSFER) { - $result = sprintf('%s', $result); - } - - return $result; - } - - /** - * Generate normal amount for transaction from a transaction group. - * - * @param TransactionJournal $journal - * - * @return string - */ - private function normalJournalObjectAmount(TransactionJournal $journal): string - { - $type = $journal->transactionType->type; - $first = $journal->transactions()->where('amount', '<', 0)->first(); - $currency = $journal->transactionCurrency; - $amount = $first->amount ?? '0'; - $colored = true; - $sourceType = $first->account()->first()->accountType()->first()->type; - - $amount = $this->signAmount($amount, $type, $sourceType); - - if ($type === TransactionType::TRANSFER) { - $colored = false; - } - $result = app('amount')->formatFlat($currency->symbol, (int) $currency->decimal_places, $amount, $colored); - if ($type === TransactionType::TRANSFER) { - $result = sprintf('%s', $result); - } - - return $result; - } - - /** - * @param TransactionJournal $journal - * @return bool - */ - private function journalObjectHasForeign(TransactionJournal $journal): bool - { - /** @var Transaction $first */ - $first = $journal->transactions()->where('amount', '<', 0)->first(); - - return null !== $first->foreign_amount; - } - - /** - * @param string $amount - * @param string $transactionType - * @param string $sourceType - * @return string - */ - private function signAmount(string $amount, string $transactionType, string $sourceType): string - { - - // withdrawals stay negative - if ($transactionType !== TransactionType::WITHDRAWAL) { - $amount = bcmul($amount, '-1'); - } - - // opening balance and it comes from initial balance? its expense. - if ($transactionType === TransactionType::OPENING_BALANCE && AccountType::INITIAL_BALANCE !== $sourceType) { - $amount = bcmul($amount, '-1'); - } - - // reconciliation and it comes from reconciliation? - if ($transactionType === TransactionType::RECONCILIATION && AccountType::RECONCILIATION !== $sourceType) { - $amount = bcmul($amount, '-1'); - } - - return $amount; - } } diff --git a/app/TransactionRules/Actions/AddTag.php b/app/TransactionRules/Actions/AddTag.php index e7c0d40290..db64b8adfd 100644 --- a/app/TransactionRules/Actions/AddTag.php +++ b/app/TransactionRules/Actions/AddTag.php @@ -74,7 +74,9 @@ class AddTag implements ActionInterface return true; } - Log::debug(sprintf('RuleAction AddTag fired but tag %d ("%s") was already added to journal %d.', $tag->id, $tag->tag, $journal['transaction_journal_id'])); + Log::debug( + sprintf('RuleAction AddTag fired but tag %d ("%s") was already added to journal %d.', $tag->id, $tag->tag, $journal['transaction_journal_id']) + ); return false; } diff --git a/app/TransactionRules/Actions/RemoveTag.php b/app/TransactionRules/Actions/RemoveTag.php index 80832ab7f4..f67a785dd3 100644 --- a/app/TransactionRules/Actions/RemoveTag.php +++ b/app/TransactionRules/Actions/RemoveTag.php @@ -26,6 +26,7 @@ use FireflyIII\Models\RuleAction; use FireflyIII\User; use Log; use DB; + /** * Class RemoveTag. */ @@ -57,12 +58,14 @@ class RemoveTag implements ActionInterface Log::debug(sprintf('RuleAction RemoveTag removed tag #%d ("%s") from journal #%d.', $tag->id, $tag->tag, $journal['transaction_journal_id'])); DB::table('tag_transaction_journal') ->where('transaction_journal_id', $journal['transaction_journal_id']) - ->where('tag_id', $tag->id) + ->where('tag_id', $tag->id) ->delete(); return true; } - Log::debug(sprintf('RuleAction RemoveTag tried to remove tag "%s" from journal #%d but no such tag exists.', $name, $journal['transaction_journal_id'])); + Log::debug( + sprintf('RuleAction RemoveTag tried to remove tag "%s" from journal #%d but no such tag exists.', $name, $journal['transaction_journal_id']) + ); return true; } diff --git a/app/TransactionRules/Actions/SetNotes.php b/app/TransactionRules/Actions/SetNotes.php index e86f53082d..4bf792e0bb 100644 --- a/app/TransactionRules/Actions/SetNotes.php +++ b/app/TransactionRules/Actions/SetNotes.php @@ -61,7 +61,12 @@ class SetNotes implements ActionInterface $dbNote->text = $this->action->action_value; $dbNote->save(); - Log::debug(sprintf('RuleAction SetNotes changed the notes of journal #%d from "%s" to "%s".', $journal['transaction_journal_id'], $oldNotes, $this->action->action_value)); + Log::debug( + sprintf( + 'RuleAction SetNotes changed the notes of journal #%d from "%s" to "%s".', $journal['transaction_journal_id'], $oldNotes, + $this->action->action_value + ) + ); return true; } diff --git a/app/TransactionRules/Engine/RuleEngineInterface.php b/app/TransactionRules/Engine/RuleEngineInterface.php index b61f175255..6f00d01350 100644 --- a/app/TransactionRules/Engine/RuleEngineInterface.php +++ b/app/TransactionRules/Engine/RuleEngineInterface.php @@ -52,16 +52,28 @@ use Illuminate\Support\Collection; interface RuleEngineInterface { /** - * @param User $user + * Add operators added to each search by the rule engine. + * + * @param array $operator */ - public function setUser(User $user): void; + public function addOperator(array $operator): void; /** - * Add rules for the engine to execute. - * - * @param Collection $rules + * Find all transactions only, dont apply anything. */ - public function setRules(Collection $rules): void; + public function find(): Collection; + + /** + * Fire the rule engine. + */ + public function fire(): void; + + /** + * Return the number of changed transactions from the previous "fire" action. + * + * @return int + */ + public function getResults(): int; /** * Add entire rule groups for the engine to execute. @@ -71,27 +83,15 @@ interface RuleEngineInterface public function setRuleGroups(Collection $ruleGroups): void; /** - * Add operators added to each search by the rule engine. + * Add rules for the engine to execute. * - * @param array $operator + * @param Collection $rules */ - public function addOperator(array $operator): void; + public function setRules(Collection $rules): void; /** - * Fire the rule engine. + * @param User $user */ - public function fire(): void; - - /** - * Find all transactions only, dont apply anything. - */ - public function find(): Collection; - - /** - * Return the number of changed transactions from the previous "fire" action. - * - * @return int - */ - public function getResults(): int; + public function setUser(User $user): void; } diff --git a/app/TransactionRules/Engine/SearchRuleEngine.php b/app/TransactionRules/Engine/SearchRuleEngine.php index b7f1477366..8474d58ea6 100644 --- a/app/TransactionRules/Engine/SearchRuleEngine.php +++ b/app/TransactionRules/Engine/SearchRuleEngine.php @@ -42,11 +42,11 @@ use Log; */ class SearchRuleEngine implements RuleEngineInterface { - private User $user; - private Collection $rules; - private array $operators; private Collection $groups; + private array $operators; private array $resultCount; + private Collection $rules; + private User $user; public function __construct() { @@ -56,43 +56,6 @@ class SearchRuleEngine implements RuleEngineInterface $this->resultCount = []; } - /** - * @inheritDoc - */ - public function setUser(User $user): void - { - $this->user = $user; - $this->operators = []; - } - - /** - * @inheritDoc - */ - public function setRules(Collection $rules): void - { - Log::debug(__METHOD__); - foreach ($rules as $rule) { - if ($rule instanceof Rule) { - Log::debug(sprintf('Adding a rule to the SearchRuleEngine: #%d ("%s")', $rule->id, $rule->title)); - $this->rules->push($rule); - } - } - } - - /** - * @inheritDoc - */ - public function setRuleGroups(Collection $ruleGroups): void - { - Log::debug(__METHOD__); - foreach ($ruleGroups as $group) { - if ($group instanceof RuleGroup) { - Log::debug(sprintf('Adding a rule group to the SearchRuleEngine: #%d ("%s")', $group->id, $group->title)); - $this->groups->push($group); - } - } - } - /** * @inheritDoc */ @@ -102,6 +65,27 @@ class SearchRuleEngine implements RuleEngineInterface $this->operators[] = $operator; } + /** + * + */ + public function find(): Collection + { + Log::debug('SearchRuleEngine::find()'); + $collection = new Collection; + foreach ($this->rules as $rule) { + $found = new Collection; + if (true === $rule->strict) { + $found = $this->findStrictRule($rule); + } + if (false === $rule->strict) { + $found = $this->findNonStrictRule($rule); + } + $collection = $collection->merge($found); + } + + return $collection->unique(); + } + /** * @inheritDoc * @throws FireflyException @@ -132,27 +116,6 @@ class SearchRuleEngine implements RuleEngineInterface Log::debug('SearchRuleEngine:: done processing all rules!'); } - /** - * - */ - public function find(): Collection - { - Log::debug('SearchRuleEngine::find()'); - $collection = new Collection; - foreach ($this->rules as $rule) { - $found = new Collection; - if (true === $rule->strict) { - $found = $this->findStrictRule($rule); - } - if (false === $rule->strict) { - $found = $this->findNonStrictRule($rule); - } - $collection = $collection->merge($found); - } - - return $collection->unique(); - } - /** * Return the number of changed transactions from the previous "fire" action. * @@ -163,6 +126,43 @@ class SearchRuleEngine implements RuleEngineInterface return count($this->resultCount); } + /** + * @inheritDoc + */ + public function setRuleGroups(Collection $ruleGroups): void + { + Log::debug(__METHOD__); + foreach ($ruleGroups as $group) { + if ($group instanceof RuleGroup) { + Log::debug(sprintf('Adding a rule group to the SearchRuleEngine: #%d ("%s")', $group->id, $group->title)); + $this->groups->push($group); + } + } + } + + /** + * @inheritDoc + */ + public function setRules(Collection $rules): void + { + Log::debug(__METHOD__); + foreach ($rules as $rule) { + if ($rule instanceof Rule) { + Log::debug(sprintf('Adding a rule to the SearchRuleEngine: #%d ("%s")', $rule->id, $rule->title)); + $this->rules->push($rule); + } + } + } + + /** + * @inheritDoc + */ + public function setUser(User $user): void + { + $this->user = $user; + $this->operators = []; + } + /** * Returns true if the rule has been triggered. * @@ -184,6 +184,152 @@ class SearchRuleEngine implements RuleEngineInterface return $this->fireNonStrictRule($rule); } + /** + * Return true if the rule is fired (the collection is larger than zero). + * + * @param Rule $rule + * + * @return bool + * @throws FireflyException + */ + private function fireStrictRule(Rule $rule): bool + { + Log::debug(sprintf('SearchRuleEngine::fireStrictRule(%d)!', $rule->id)); + $collection = $this->findStrictRule($rule); + + $this->processResults($rule, $collection); + Log::debug(sprintf('SearchRuleEngine:: done processing strict rule #%d', $rule->id)); + + $result = $collection->count() > 0; + if (true === $result) { + Log::debug(sprintf('SearchRuleEngine:: rule #%d was triggered (on %d transaction(s)).', $rule->id, $collection->count())); + + return true; + } + Log::debug(sprintf('SearchRuleEngine:: rule #%d was not triggered (on %d transaction(s)).', $rule->id, $collection->count())); + + return false; + } + + /** + * Finds the transactions a strict rule will execute on. + * + * @param Rule $rule + * + * @return Collection + */ + private function findStrictRule(Rule $rule): Collection + { + Log::debug(sprintf('Now in findStrictRule(#%d)', $rule->id ?? 0)); + $searchArray = []; + /** @var RuleTrigger $ruleTrigger */ + foreach ($rule->ruleTriggers as $ruleTrigger) { + // if needs no context, value is different: + $needsContext = config(sprintf('firefly.search.operators.%s.needs_context', $ruleTrigger->trigger_type)) ?? true; + if (false === $needsContext) { + Log::debug(sprintf('SearchRuleEngine:: add a rule trigger: %s:true', $ruleTrigger->trigger_type)); + $searchArray[$ruleTrigger->trigger_type][] = 'true'; + } + if (true === $needsContext) { + Log::debug(sprintf('SearchRuleEngine:: add a rule trigger: %s:"%s"', $ruleTrigger->trigger_type, $ruleTrigger->trigger_value)); + $searchArray[$ruleTrigger->trigger_type][] = sprintf('"%s"', $ruleTrigger->trigger_value); + } + } + + // add local operators: + foreach ($this->operators as $operator) { + Log::debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value'])); + $searchArray[$operator['type']][] = sprintf('"%s"', $operator['value']); + } + $date = today(config('app.timezone')); + if ($this->hasSpecificJournalTrigger($searchArray)) { + $date = $this->setDateFromJournalTrigger($searchArray); + } + + + // build and run the search engine. + $searchEngine = app(SearchInterface::class); + $searchEngine->setUser($this->user); + $searchEngine->setPage(1); + $searchEngine->setLimit(31337); + $searchEngine->setDate($date); + + foreach ($searchArray as $type => $searches) { + foreach ($searches as $value) { + $searchEngine->parseQuery(sprintf('%s:%s', $type, $value)); + } + } + + $result = $searchEngine->searchTransactions(); + + return $result->getCollection(); + } + + /** + * Search in the triggers of this particular search and if it contains + * one search operator for "journal_id" it means the date ranges + * in the search may need to be updated. + * + * @param array $array + * + * @return bool + */ + private function hasSpecificJournalTrigger(array $array): bool + { + Log::debug('Now in hasSpecificJournalTrigger.'); + $journalTrigger = false; + $dateTrigger = false; + foreach ($array as $triggerName => $values) { + if ('journal_id' === $triggerName) { + if (is_array($values) && 1 === count($values)) { + Log::debug('Found a journal_id trigger with 1 journal, true.'); + $journalTrigger = true; + } + } + if (in_array($triggerName, ['date_is', 'date', 'on', 'date_before', 'before', 'date_after', 'after'], true)) { + Log::debug('Found a date related trigger, set to true.'); + $dateTrigger = true; + } + } + $result = $journalTrigger && $dateTrigger; + Log::debug(sprintf('Result of hasSpecificJournalTrigger is %s.', var_export($result, true))); + + return $result; + } + + /** + * @param array $array + * + * @return Carbon + */ + private function setDateFromJournalTrigger(array $array): Carbon + { + Log::debug('Now in setDateFromJournalTrigger()'); + $journalId = 0; + foreach ($array as $triggerName => $values) { + if ('journal_id' === $triggerName) { + if (is_array($values) && 1 === count($values)) { + $journalId = (int)trim(($values[0] ?? '"0"'), '"'); // follows format "123". + Log::debug(sprintf('Found journal ID #%d', $journalId)); + } + } + } + if (0 !== $journalId) { + $repository = app(JournalRepositoryInterface::class); + $repository->setUser($this->user); + $journal = $repository->findNull($journalId); + if (null !== $journal) { + $date = $journal->date; + Log::debug(sprintf('Found journal #%d with date %s.', $journal->id, $journal->date->format('Y-m-d'))); + + return $date; + } + } + Log::debug('Found no journal, return default date.'); + + return today(config('app.timezone')); + } + /** * @param Rule $rule * @param Collection $collection @@ -272,33 +418,6 @@ class SearchRuleEngine implements RuleEngineInterface return false; } - /** - * Return true if the rule is fired (the collection is larger than zero). - * - * @param Rule $rule - * - * @return bool - * @throws FireflyException - */ - private function fireStrictRule(Rule $rule): bool - { - Log::debug(sprintf('SearchRuleEngine::fireStrictRule(%d)!', $rule->id)); - $collection = $this->findStrictRule($rule); - - $this->processResults($rule, $collection); - Log::debug(sprintf('SearchRuleEngine:: done processing strict rule #%d', $rule->id)); - - $result = $collection->count() > 0; - if (true === $result) { - Log::debug(sprintf('SearchRuleEngine:: rule #%d was triggered (on %d transaction(s)).', $rule->id, $collection->count())); - - return true; - } - Log::debug(sprintf('SearchRuleEngine:: rule #%d was not triggered (on %d transaction(s)).', $rule->id, $collection->count())); - - return false; - } - /** * Return true if the rule is fired (the collection is larger than zero). * @@ -318,60 +437,6 @@ class SearchRuleEngine implements RuleEngineInterface return $collection->count() > 0; } - /** - * Finds the transactions a strict rule will execute on. - * - * @param Rule $rule - * - * @return Collection - */ - private function findStrictRule(Rule $rule): Collection - { - Log::debug(sprintf('Now in findStrictRule(#%d)', $rule->id ?? 0)); - $searchArray = []; - /** @var RuleTrigger $ruleTrigger */ - foreach ($rule->ruleTriggers as $ruleTrigger) { - // if needs no context, value is different: - $needsContext = config(sprintf('firefly.search.operators.%s.needs_context', $ruleTrigger->trigger_type)) ?? true; - if (false === $needsContext) { - Log::debug(sprintf('SearchRuleEngine:: add a rule trigger: %s:true', $ruleTrigger->trigger_type)); - $searchArray[$ruleTrigger->trigger_type][] = 'true'; - } - if (true === $needsContext) { - Log::debug(sprintf('SearchRuleEngine:: add a rule trigger: %s:"%s"', $ruleTrigger->trigger_type, $ruleTrigger->trigger_value)); - $searchArray[$ruleTrigger->trigger_type][] = sprintf('"%s"', $ruleTrigger->trigger_value); - } - } - - // add local operators: - foreach ($this->operators as $operator) { - Log::debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value'])); - $searchArray[$operator['type']][] = sprintf('"%s"', $operator['value']); - } - $date = today(config('app.timezone')); - if ($this->hasSpecificJournalTrigger($searchArray)) { - $date = $this->setDateFromJournalTrigger($searchArray); - } - - - // build and run the search engine. - $searchEngine = app(SearchInterface::class); - $searchEngine->setUser($this->user); - $searchEngine->setPage(1); - $searchEngine->setLimit(31337); - $searchEngine->setDate($date); - - foreach ($searchArray as $type => $searches) { - foreach ($searches as $value) { - $searchEngine->parseQuery(sprintf('%s:%s', $type, $value)); - } - } - - $result = $searchEngine->searchTransactions(); - - return $result->getCollection(); - } - /** * @param Rule $rule * @@ -444,38 +509,6 @@ class SearchRuleEngine implements RuleEngineInterface return $unique; } - /** - * Search in the triggers of this particular search and if it contains - * one search operator for "journal_id" it means the date ranges - * in the search may need to be updated. - * - * @param array $array - * - * @return bool - */ - private function hasSpecificJournalTrigger(array $array): bool - { - Log::debug('Now in hasSpecificJournalTrigger.'); - $journalTrigger = false; - $dateTrigger = false; - foreach ($array as $triggerName => $values) { - if ('journal_id' === $triggerName) { - if (is_array($values) && 1 === count($values)) { - Log::debug('Found a journal_id trigger with 1 journal, true.'); - $journalTrigger = true; - } - } - if (in_array($triggerName, ['date_is', 'date', 'on', 'date_before', 'before', 'date_after', 'after'], true)) { - Log::debug('Found a date related trigger, set to true.'); - $dateTrigger = true; - } - } - $result = $journalTrigger && $dateTrigger; - Log::debug(sprintf('Result of hasSpecificJournalTrigger is %s.', var_export($result, true))); - - return $result; - } - /** * @param RuleGroup $group * @@ -501,37 +534,4 @@ class SearchRuleEngine implements RuleEngineInterface return $all; } - - /** - * @param array $array - * - * @return Carbon - */ - private function setDateFromJournalTrigger(array $array): Carbon - { - Log::debug('Now in setDateFromJournalTrigger()'); - $journalId = 0; - foreach ($array as $triggerName => $values) { - if ('journal_id' === $triggerName) { - if (is_array($values) && 1 === count($values)) { - $journalId = (int)trim(($values[0] ?? '"0"'), '"'); // follows format "123". - Log::debug(sprintf('Found journal ID #%d', $journalId)); - } - } - } - if (0 !== $journalId) { - $repository = app(JournalRepositoryInterface::class); - $repository->setUser($this->user); - $journal = $repository->findNull($journalId); - if (null !== $journal) { - $date = $journal->date; - Log::debug(sprintf('Found journal #%d with date %s.', $journal->id, $journal->date->format('Y-m-d'))); - - return $date; - } - } - Log::debug('Found no journal, return default date.'); - - return today(config('app.timezone')); - } } diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index 711f134c9d..79436a89c6 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -149,22 +149,16 @@ class AccountTransformer extends AbstractTransformer } /** - * @param Account $account - * @param string|null $accountRole - * @param string $accountType - * - * @return array + * @return Carbon */ - private function getCCInfo(Account $account, ?string $accountRole, string $accountType): array + private function getDate(): Carbon { - $monthlyPaymentDate = null; - $creditCardType = null; - if ('ccAsset' === $accountRole && 'asset' === $accountType) { - $creditCardType = $this->repository->getMetaValue($account, 'cc_type'); - $monthlyPaymentDate = $this->repository->getMetaValue($account, 'cc_monthly_payment_date'); + $date = today(config('app.timezone')); + if (null !== $this->parameters->get('date')) { + $date = $this->parameters->get('date'); } - return [$creditCardType, $monthlyPaymentDate]; + return $date; } /** @@ -189,34 +183,22 @@ class AccountTransformer extends AbstractTransformer } /** - * @return Carbon - */ - private function getDate(): Carbon - { - $date = today(config('app.timezone')); - if (null !== $this->parameters->get('date')) { - $date = $this->parameters->get('date'); - } - - return $date; - } - - /** - * @param Account $account - * @param string $accountType + * @param Account $account + * @param string|null $accountRole + * @param string $accountType * * @return array */ - private function getInterest(Account $account, string $accountType): array + private function getCCInfo(Account $account, ?string $accountRole, string $accountType): array { - $interest = null; - $interestPeriod = null; - if ('liabilities' === $accountType) { - $interest = $this->repository->getMetaValue($account, 'interest'); - $interestPeriod = $this->repository->getMetaValue($account, 'interest_period'); + $monthlyPaymentDate = null; + $creditCardType = null; + if ('ccAsset' === $accountRole && 'asset' === $accountType) { + $creditCardType = $this->repository->getMetaValue($account, 'cc_type'); + $monthlyPaymentDate = $this->repository->getMetaValue($account, 'cc_monthly_payment_date'); } - return [$interest, $interestPeriod]; + return [$creditCardType, $monthlyPaymentDate]; } /** @@ -241,4 +223,22 @@ class AccountTransformer extends AbstractTransformer return [$openingBalance, $openingBalanceDate]; } + + /** + * @param Account $account + * @param string $accountType + * + * @return array + */ + private function getInterest(Account $account, string $accountType): array + { + $interest = null; + $interestPeriod = null; + if ('liabilities' === $accountType) { + $interest = $this->repository->getMetaValue($account, 'interest'); + $interestPeriod = $this->repository->getMetaValue($account, 'interest_period'); + } + + return [$interest, $interestPeriod]; + } } diff --git a/app/Transformers/AttachmentTransformer.php b/app/Transformers/AttachmentTransformer.php index 34d2f4ade1..d410c8dd88 100644 --- a/app/Transformers/AttachmentTransformer.php +++ b/app/Transformers/AttachmentTransformer.php @@ -26,7 +26,6 @@ namespace FireflyIII\Transformers; use FireflyIII\Models\Attachment; use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface; -use Log; /** * Class AttachmentTransformer diff --git a/app/Transformers/AvailableBudgetTransformer.php b/app/Transformers/AvailableBudgetTransformer.php index 538a18547f..f6f504f9e1 100644 --- a/app/Transformers/AvailableBudgetTransformer.php +++ b/app/Transformers/AvailableBudgetTransformer.php @@ -29,16 +29,15 @@ use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\NoBudgetRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use Illuminate\Support\Collection; -use Log; /** * Class AvailableBudgetTransformer */ class AvailableBudgetTransformer extends AbstractTransformer { - private NoBudgetRepositoryInterface $noBudgetRepository; + private NoBudgetRepositoryInterface $noBudgetRepository; private OperationsRepositoryInterface $opsRepository; - private BudgetRepositoryInterface $repository; + private BudgetRepositoryInterface $repository; /** * CurrencyTransformer constructor. @@ -68,11 +67,11 @@ class AvailableBudgetTransformer extends AbstractTransformer 'id' => (string)$availableBudget->id, 'created_at' => $availableBudget->created_at->toAtomString(), 'updated_at' => $availableBudget->updated_at->toAtomString(), - 'currency_id' => (string) $currency->id, + 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int) $currency->decimal_places, - 'amount' => number_format((float) $availableBudget->amount, $currency->decimal_places, '.', ''), + 'currency_decimal_places' => (int)$currency->decimal_places, + 'amount' => number_format((float)$availableBudget->amount, $currency->decimal_places, '.', ''), 'start' => $availableBudget->start_date->format('Y-m-d'), 'end' => $availableBudget->end_date->format('Y-m-d'), 'spent_in_budgets' => [], diff --git a/app/Transformers/BillTransformer.php b/app/Transformers/BillTransformer.php index 1f5da82d73..4af76d1fb9 100644 --- a/app/Transformers/BillTransformer.php +++ b/app/Transformers/BillTransformer.php @@ -29,7 +29,6 @@ use FireflyIII\Models\ObjectGroup; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Bill\BillRepositoryInterface; use Illuminate\Support\Collection; -use Log; /** * Class BillTransformer @@ -72,8 +71,8 @@ class BillTransformer extends AbstractTransformer /** @var ObjectGroup $objectGroup */ $objectGroup = $bill->objectGroups->first(); if (null !== $objectGroup) { - $objectGroupId = (int) $objectGroup->id; - $objectGroupOrder = (int) $objectGroup->order; + $objectGroupId = (int)$objectGroup->id; + $objectGroupOrder = (int)$objectGroup->order; $objectGroupTitle = $objectGroup->title; } @@ -81,18 +80,18 @@ class BillTransformer extends AbstractTransformer 'id' => (int)$bill->id, 'created_at' => $bill->created_at->toAtomString(), 'updated_at' => $bill->updated_at->toAtomString(), - 'currency_id' => (string) $bill->transaction_currency_id, + 'currency_id' => (string)$bill->transaction_currency_id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int) $currency->decimal_places, + 'currency_decimal_places' => (int)$currency->decimal_places, 'name' => $bill->name, - 'amount_min' => number_format((float) $bill->amount_min, $currency->decimal_places, '.', ''), - 'amount_max' => number_format((float) $bill->amount_max, $currency->decimal_places, '.', ''), + 'amount_min' => number_format((float)$bill->amount_min, $currency->decimal_places, '.', ''), + 'amount_max' => number_format((float)$bill->amount_max, $currency->decimal_places, '.', ''), 'date' => $bill->date->format('Y-m-d'), 'repeat_freq' => $bill->repeat_freq, - 'skip' => (int) $bill->skip, + 'skip' => (int)$bill->skip, 'active' => $bill->active, - 'order' => (int) $bill->order, + 'order' => (int)$bill->order, 'notes' => $notes, 'next_expected_match' => $paidData['next_expected_match'], 'pay_dates' => $payDates, @@ -109,52 +108,6 @@ class BillTransformer extends AbstractTransformer ]; } - /** - * Returns the latest date in the set, or start when set is empty. - * - * @param Collection $dates - * @param Carbon $default - * - * @return Carbon - */ - protected function lastPaidDate(Collection $dates, Carbon $default): Carbon - { - if (0 === $dates->count()) { - return $default; // @codeCoverageIgnore - } - $latest = $dates->first()->date; - /** @var TransactionJournal $date */ - foreach ($dates as $journal) { - if ($journal->date->gte($latest)) { - $latest = $journal->date; - } - } - - return $latest; - } - - /** - * Given a bill and a date, this method will tell you at which moment this bill expects its next - * transaction. Whether or not it is there already, is not relevant. - * - * @param Bill $bill - * @param Carbon $date - * - * @return Carbon - */ - protected function nextDateMatch(Bill $bill, Carbon $date): Carbon - { - //Log::debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d'))); - $start = clone $bill->date; - //Log::debug(sprintf('Bill start date is %s', $start->format('Y-m-d'))); - while ($start < $date) { - $start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); - } - //Log::debug(sprintf('End of loop, bill start date is now %s', $start->format('Y-m-d'))); - - return $start; - } - /** * Get the data the bill was paid and predict the next expected match. * @@ -166,7 +119,7 @@ class BillTransformer extends AbstractTransformer { //Log::debug(sprintf('Now in paidData for bill #%d', $bill->id)); if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) { - // Log::debug('parameters are NULL, return empty array'); + // Log::debug('parameters are NULL, return empty array'); return [ 'paid_dates' => [], @@ -202,7 +155,7 @@ class BillTransformer extends AbstractTransformer $nextMatch = app('navigation')->addPeriod($nextMatch, $bill->repeat_freq, $bill->skip); //Log::debug(sprintf('Next match is now %s.', $nextMatch->format('Y-m-d'))); } - if($nextMatch->isSameDay($lastPaidDate)) { + if ($nextMatch->isSameDay($lastPaidDate)) { /* * Add another period because its the same day as the last paid date. */ @@ -224,11 +177,36 @@ class BillTransformer extends AbstractTransformer 'paid_dates' => $result, 'next_expected_match' => $nextMatch->format('Y-m-d'), ]; + //Log::debug('Result', $result); return $result; } + /** + * Returns the latest date in the set, or start when set is empty. + * + * @param Collection $dates + * @param Carbon $default + * + * @return Carbon + */ + protected function lastPaidDate(Collection $dates, Carbon $default): Carbon + { + if (0 === $dates->count()) { + return $default; // @codeCoverageIgnore + } + $latest = $dates->first()->date; + /** @var TransactionJournal $date */ + foreach ($dates as $journal) { + if ($journal->date->gte($latest)) { + $latest = $journal->date; + } + } + + return $latest; + } + /** * @param Bill $bill * @@ -262,8 +240,31 @@ class BillTransformer extends AbstractTransformer return $date->format('Y-m-d'); } ); - $array = $simple->toArray(); + $array = $simple->toArray(); return $array; } + + /** + * Given a bill and a date, this method will tell you at which moment this bill expects its next + * transaction. Whether or not it is there already, is not relevant. + * + * @param Bill $bill + * @param Carbon $date + * + * @return Carbon + */ + protected function nextDateMatch(Bill $bill, Carbon $date): Carbon + { + //Log::debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d'))); + $start = clone $bill->date; + //Log::debug(sprintf('Bill start date is %s', $start->format('Y-m-d'))); + while ($start < $date) { + $start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); + } + + //Log::debug(sprintf('End of loop, bill start date is now %s', $start->format('Y-m-d'))); + + return $start; + } } diff --git a/app/Transformers/BudgetLimitTransformer.php b/app/Transformers/BudgetLimitTransformer.php index 0e81a6dc2a..7bf3a04280 100644 --- a/app/Transformers/BudgetLimitTransformer.php +++ b/app/Transformers/BudgetLimitTransformer.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace FireflyIII\Transformers; use FireflyIII\Models\BudgetLimit; -use FireflyIII\Repositories\Budget\BudgetLimitRepository; use FireflyIII\Repositories\Budget\OperationsRepository; use Illuminate\Support\Collection; use League\Fractal\Resource\Item; @@ -63,7 +62,9 @@ class BudgetLimitTransformer extends AbstractTransformer { $repository = app(OperationsRepository::class); $repository->setUser($budgetLimit->budget->user); - $expenses = $repository->sumExpenses($budgetLimit->start_date, $budgetLimit->end_date, null, new Collection([$budgetLimit->budget]), $budgetLimit->transactionCurrency); + $expenses = $repository->sumExpenses( + $budgetLimit->start_date, $budgetLimit->end_date, null, new Collection([$budgetLimit->budget]), $budgetLimit->transactionCurrency + ); $currency = $budgetLimit->transactionCurrency; @@ -84,13 +85,13 @@ class BudgetLimitTransformer extends AbstractTransformer $amount = number_format((float)$amount, $currencyDecimalPlaces, '.', ''); return [ - 'id' => (string) $budgetLimit->id, + 'id' => (string)$budgetLimit->id, 'created_at' => $budgetLimit->created_at->toAtomString(), 'updated_at' => $budgetLimit->updated_at->toAtomString(), 'start' => $budgetLimit->start_date->format('Y-m-d'), 'end' => $budgetLimit->end_date->format('Y-m-d'), 'budget_id' => (string)$budgetLimit->budget_id, - 'currency_id' => (string) $currencyId, + 'currency_id' => (string)$currencyId, 'currency_code' => $currencyCode, 'currency_name' => $currencyName, 'currency_decimal_places' => $currencyDecimalPlaces, diff --git a/app/Transformers/BudgetTransformer.php b/app/Transformers/BudgetTransformer.php index 4b32c539ff..2be1ba1e36 100644 --- a/app/Transformers/BudgetTransformer.php +++ b/app/Transformers/BudgetTransformer.php @@ -87,6 +87,7 @@ class BudgetTransformer extends AbstractTransformer $abAmount = number_format((float)$autoBudget->amount, $autoBudget->transactionCurrency->decimal_places, '.', ''); $abPeriod = $autoBudget->period; } + return [ 'id' => (string)$budget->id, 'created_at' => $budget->created_at->toAtomString(), diff --git a/app/Transformers/CurrencyExchangeRateTransformer.php b/app/Transformers/CurrencyExchangeRateTransformer.php index 5b8a6e905e..d7fdbdea63 100644 --- a/app/Transformers/CurrencyExchangeRateTransformer.php +++ b/app/Transformers/CurrencyExchangeRateTransformer.php @@ -38,22 +38,23 @@ class CurrencyExchangeRateTransformer extends AbstractTransformer */ public function transform(CurrencyExchangeRate $rate): array { - $result = number_format((float) $rate->rate * (float) $this->parameters->get('amount'), $rate->toCurrency->decimal_places, '.', ''); + $result = number_format((float)$rate->rate * (float)$this->parameters->get('amount'), $rate->toCurrency->decimal_places, '.', ''); $result = 0.0 === $result ? null : $result; + return [ 'id' => (int)$rate->id, 'created_at' => $rate->created_at->toAtomString(), 'updated_at' => $rate->updated_at->toAtomString(), - 'from_currency_id' => (int) $rate->fromCurrency->id, + 'from_currency_id' => (int)$rate->fromCurrency->id, 'from_currency_name' => $rate->fromCurrency->name, 'from_currency_code' => $rate->fromCurrency->code, 'from_currency_symbol' => $rate->fromCurrency->symbol, - 'from_currency_decimal_places' => (int) $rate->fromCurrency->decimal_places, - 'to_currency_id' => (int) $rate->toCurrency->id, + 'from_currency_decimal_places' => (int)$rate->fromCurrency->decimal_places, + 'to_currency_id' => (int)$rate->toCurrency->id, 'to_currency_name' => $rate->toCurrency->name, 'to_currency_code' => $rate->toCurrency->code, 'to_currency_symbol' => $rate->toCurrency->symbol, - 'to_currency_decimal_places' => (int) $rate->toCurrency->decimal_places, + 'to_currency_decimal_places' => (int)$rate->toCurrency->decimal_places, 'date' => $rate->date->format('Y-m-d'), 'rate' => (float)$rate->rate, 'amount' => $result, diff --git a/app/Transformers/CurrencyTransformer.php b/app/Transformers/CurrencyTransformer.php index bf9ecedec1..0c3e1b7966 100644 --- a/app/Transformers/CurrencyTransformer.php +++ b/app/Transformers/CurrencyTransformer.php @@ -43,10 +43,11 @@ class CurrencyTransformer extends AbstractTransformer $isDefault = false; $defaultCurrency = $this->parameters->get('defaultCurrency'); if (null !== $defaultCurrency) { - $isDefault = (int) $defaultCurrency->id === (int) $currency->id; + $isDefault = (int)$defaultCurrency->id === (int)$currency->id; } + return [ - 'id' => (int) $currency->id, + 'id' => (int)$currency->id, 'created_at' => $currency->created_at->toAtomString(), 'updated_at' => $currency->updated_at->toAtomString(), 'default' => $isDefault, @@ -54,7 +55,7 @@ class CurrencyTransformer extends AbstractTransformer 'name' => $currency->name, 'code' => $currency->code, 'symbol' => $currency->symbol, - 'decimal_places' => (int) $currency->decimal_places, + 'decimal_places' => (int)$currency->decimal_places, 'links' => [ [ 'rel' => 'self', diff --git a/app/Transformers/ObjectGroupTransformer.php b/app/Transformers/ObjectGroupTransformer.php index 7641fb341a..e71da4d0c1 100644 --- a/app/Transformers/ObjectGroupTransformer.php +++ b/app/Transformers/ObjectGroupTransformer.php @@ -26,7 +26,6 @@ namespace FireflyIII\Transformers; use FireflyIII\Models\ObjectGroup; use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface; -use Log; /** * Class AccountTransformer @@ -58,11 +57,11 @@ class ObjectGroupTransformer extends AbstractTransformer $this->repository->setUser($objectGroup->user); return [ - 'id' => (string) $objectGroup->id, + 'id' => (string)$objectGroup->id, 'created_at' => $objectGroup->created_at->toAtomString(), 'updated_at' => $objectGroup->updated_at->toAtomString(), 'title' => $objectGroup->title, - 'order' => (int) $objectGroup->order, + 'order' => (int)$objectGroup->order, 'links' => [ [ 'rel' => 'self', diff --git a/app/Transformers/PiggyBankEventTransformer.php b/app/Transformers/PiggyBankEventTransformer.php index e34e4ae714..c5a9e4f48e 100644 --- a/app/Transformers/PiggyBankEventTransformer.php +++ b/app/Transformers/PiggyBankEventTransformer.php @@ -88,7 +88,7 @@ class PiggyBankEventTransformer extends AbstractTransformer 'currency_symbol' => $currency->symbol, 'currency_decimal_places' => (int)$currency->decimal_places, 'transaction_journal_id' => $journalId ? (string)$journalId : null, - 'transaction_group_id' => $groupId ? (string)$groupId: null, + 'transaction_group_id' => $groupId ? (string)$groupId : null, 'links' => [ [ 'rel' => 'self', diff --git a/app/Transformers/PiggyBankTransformer.php b/app/Transformers/PiggyBankTransformer.php index 6f07503aa1..41fac2d3bb 100644 --- a/app/Transformers/PiggyBankTransformer.php +++ b/app/Transformers/PiggyBankTransformer.php @@ -36,8 +36,8 @@ use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; */ class PiggyBankTransformer extends AbstractTransformer { - private AccountRepositoryInterface $accountRepos; - private CurrencyRepositoryInterface $currencyRepos; + private AccountRepositoryInterface $accountRepos; + private CurrencyRepositoryInterface $currencyRepos; private PiggyBankRepositoryInterface $piggyRepos; /** @@ -83,14 +83,14 @@ class PiggyBankTransformer extends AbstractTransformer /** @var ObjectGroup $objectGroup */ $objectGroup = $piggyBank->objectGroups->first(); if (null !== $objectGroup) { - $objectGroupId = (int) $objectGroup->id; - $objectGroupOrder = (int) $objectGroup->order; + $objectGroupId = (int)$objectGroup->id; + $objectGroupOrder = (int)$objectGroup->order; $objectGroupTitle = $objectGroup->title; } // get currently saved amount: $currentAmountStr = $this->piggyRepos->getCurrentAmount($piggyBank); - $currentAmount = number_format((float) $currentAmountStr, $currency->decimal_places, '.', ''); + $currentAmount = number_format((float)$currentAmountStr, $currency->decimal_places, '.', ''); // left to save: $leftToSave = bcsub($piggyBank->targetamount, $currentAmountStr); @@ -99,27 +99,28 @@ class PiggyBankTransformer extends AbstractTransformer // target and percentage: $targetAmount = $piggyBank->targetamount; - $targetAmount = 1 === bccomp('0.01', (string) $targetAmount) ? '0.01' : $targetAmount; - $percentage = (int) (0 !== bccomp('0', $currentAmountStr) ? $currentAmountStr / $targetAmount * 100 : 0); + $targetAmount = 1 === bccomp('0.01', (string)$targetAmount) ? '0.01' : $targetAmount; + $percentage = (int)(0 !== bccomp('0', $currentAmountStr) ? $currentAmountStr / $targetAmount * 100 : 0); + return [ - 'id' => (string) $piggyBank->id, + 'id' => (string)$piggyBank->id, 'created_at' => $piggyBank->created_at->toAtomString(), 'updated_at' => $piggyBank->updated_at->toAtomString(), - 'account_id' => (string) $piggyBank->account_id, + 'account_id' => (string)$piggyBank->account_id, 'account_name' => $piggyBank->account->name, 'name' => $piggyBank->name, - 'currency_id' => (string) $currency->id, + 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int) $currency->decimal_places, - 'target_amount' => number_format((float) $targetAmount, $currency->decimal_places, '.', ''), + 'currency_decimal_places' => (int)$currency->decimal_places, + 'target_amount' => number_format((float)$targetAmount, $currency->decimal_places, '.', ''), 'percentage' => $percentage, 'current_amount' => $currentAmount, - 'left_to_save' => number_format((float) $leftToSave, $currency->decimal_places, '.', ''), - 'save_per_month' => number_format((float) $this->piggyRepos->getSuggestedMonthlyAmount($piggyBank), $currency->decimal_places, '.', ''), + 'left_to_save' => number_format((float)$leftToSave, $currency->decimal_places, '.', ''), + 'save_per_month' => number_format((float)$this->piggyRepos->getSuggestedMonthlyAmount($piggyBank), $currency->decimal_places, '.', ''), 'start_date' => $startDate, 'target_date' => $targetDate, - 'order' => (int) $piggyBank->order, + 'order' => (int)$piggyBank->order, 'active' => true, 'notes' => $notes, 'object_group_id' => $objectGroupId ? (string)$objectGroupId : null, diff --git a/app/Transformers/PreferenceTransformer.php b/app/Transformers/PreferenceTransformer.php index 89c6db70e8..1455cc0cd8 100644 --- a/app/Transformers/PreferenceTransformer.php +++ b/app/Transformers/PreferenceTransformer.php @@ -25,7 +25,6 @@ namespace FireflyIII\Transformers; use FireflyIII\Models\Preference; -use Log; /** * Class PreferenceTransformer diff --git a/app/Transformers/RecurrenceTransformer.php b/app/Transformers/RecurrenceTransformer.php index 0894d4eb4f..c8e063a96e 100644 --- a/app/Transformers/RecurrenceTransformer.php +++ b/app/Transformers/RecurrenceTransformer.php @@ -148,69 +148,6 @@ class RecurrenceTransformer extends AbstractTransformer return $return; } - /** - * @param RecurrenceTransaction $transaction - * @param array $array - * - * @return array - * @throws FireflyException - */ - private function getTransactionMeta(RecurrenceTransaction $transaction, array $array): array - { - Log::debug(sprintf('Now in %s', __METHOD__)); - $array['tags'] = []; - $array['category_id'] = null; - $array['category_name'] = null; - $array['budget_id'] = null; - $array['budget_name'] = null; - $array['piggy_bank_id'] = null; - $array['piggy_bank_name'] = null; - - /** @var RecurrenceTransactionMeta $transactionMeta */ - foreach ($transaction->recurrenceTransactionMeta as $transactionMeta) { - switch ($transactionMeta->name) { - default: - throw new FireflyException(sprintf('Recurrence transformer cant handle field "%s"', $transactionMeta->name)); - case 'bill_id': - break; - case 'tags': - $array['tags'] = json_decode($transactionMeta->value); - break; - case 'piggy_bank_id': - $piggy = $this->piggyRepos->findNull((int)$transactionMeta->value); - if (null !== $piggy) { - $array['piggy_bank_id'] = (string)$piggy->id; - $array['piggy_bank_name'] = $piggy->name; - } - break; - case 'category_id': - $category = $this->factory->findOrCreate((int)$transactionMeta->value, null); - if (null !== $category) { - $array['category_id'] = (string)$category->id; - $array['category_name'] = $category->name; - } - break; - break; - case 'category_name': - $category = $this->factory->findOrCreate(null, $transactionMeta->value); - if (null !== $category) { - $array['category_id'] = (string)$category->id; - $array['category_name'] = $category->name; - } - break; - case 'budget_id': - $budget = $this->budgetRepos->findNull((int)$transactionMeta->value); - if (null !== $budget) { - $array['budget_id'] = (string)$budget->id; - $array['budget_name'] = $budget->name; - } - break; - } - } - - return $array; - } - /** * @param Recurrence $recurrence * @@ -301,4 +238,67 @@ class RecurrenceTransformer extends AbstractTransformer return $return; } + /** + * @param RecurrenceTransaction $transaction + * @param array $array + * + * @return array + * @throws FireflyException + */ + private function getTransactionMeta(RecurrenceTransaction $transaction, array $array): array + { + Log::debug(sprintf('Now in %s', __METHOD__)); + $array['tags'] = []; + $array['category_id'] = null; + $array['category_name'] = null; + $array['budget_id'] = null; + $array['budget_name'] = null; + $array['piggy_bank_id'] = null; + $array['piggy_bank_name'] = null; + + /** @var RecurrenceTransactionMeta $transactionMeta */ + foreach ($transaction->recurrenceTransactionMeta as $transactionMeta) { + switch ($transactionMeta->name) { + default: + throw new FireflyException(sprintf('Recurrence transformer cant handle field "%s"', $transactionMeta->name)); + case 'bill_id': + break; + case 'tags': + $array['tags'] = json_decode($transactionMeta->value); + break; + case 'piggy_bank_id': + $piggy = $this->piggyRepos->findNull((int)$transactionMeta->value); + if (null !== $piggy) { + $array['piggy_bank_id'] = (string)$piggy->id; + $array['piggy_bank_name'] = $piggy->name; + } + break; + case 'category_id': + $category = $this->factory->findOrCreate((int)$transactionMeta->value, null); + if (null !== $category) { + $array['category_id'] = (string)$category->id; + $array['category_name'] = $category->name; + } + break; + break; + case 'category_name': + $category = $this->factory->findOrCreate(null, $transactionMeta->value); + if (null !== $category) { + $array['category_id'] = (string)$category->id; + $array['category_name'] = $category->name; + } + break; + case 'budget_id': + $budget = $this->budgetRepos->findNull((int)$transactionMeta->value); + if (null !== $budget) { + $array['budget_id'] = (string)$budget->id; + $array['budget_name'] = $budget->name; + } + break; + } + } + + return $array; + } + } diff --git a/app/Transformers/RuleTransformer.php b/app/Transformers/RuleTransformer.php index c715d8570f..202df6e659 100644 --- a/app/Transformers/RuleTransformer.php +++ b/app/Transformers/RuleTransformer.php @@ -64,7 +64,7 @@ class RuleTransformer extends AbstractTransformer 'id' => (string)$rule->id, 'created_at' => $rule->created_at->toAtomString(), 'updated_at' => $rule->updated_at->toAtomString(), - 'rule_group_id' => (string) $rule->rule_group_id, + 'rule_group_id' => (string)$rule->rule_group_id, 'title' => $rule->title, 'description' => $rule->description, 'order' => (int)$rule->order, @@ -83,32 +83,6 @@ class RuleTransformer extends AbstractTransformer ]; } - /** - * @param Rule $rule - * - * @return array - */ - private function actions(Rule $rule): array - { - $result = []; - $actions = $this->ruleRepository->getRuleActions($rule); - /** @var RuleAction $ruleAction */ - foreach ($actions as $ruleAction) { - $result[] = [ - 'id' => (string)$ruleAction->id, - 'created_at' => $ruleAction->created_at->toAtomString(), - 'updated_at' => $ruleAction->updated_at->toAtomString(), - 'type' => $ruleAction->action_type, - 'value' => $ruleAction->action_value, - 'order' => $ruleAction->order, - 'active' => $ruleAction->active, - 'stop_processing' => $ruleAction->stop_processing, - ]; - } - - return $result; - } - /** * @param Rule $rule * @@ -160,4 +134,30 @@ class RuleTransformer extends AbstractTransformer return $result; } + + /** + * @param Rule $rule + * + * @return array + */ + private function actions(Rule $rule): array + { + $result = []; + $actions = $this->ruleRepository->getRuleActions($rule); + /** @var RuleAction $ruleAction */ + foreach ($actions as $ruleAction) { + $result[] = [ + 'id' => (string)$ruleAction->id, + 'created_at' => $ruleAction->created_at->toAtomString(), + 'updated_at' => $ruleAction->updated_at->toAtomString(), + 'type' => $ruleAction->action_type, + 'value' => $ruleAction->action_value, + 'order' => $ruleAction->order, + 'active' => $ruleAction->active, + 'stop_processing' => $ruleAction->stop_processing, + ]; + } + + return $result; + } } diff --git a/app/Transformers/TagTransformer.php b/app/Transformers/TagTransformer.php index 8f5c6114e3..c63918027e 100644 --- a/app/Transformers/TagTransformer.php +++ b/app/Transformers/TagTransformer.php @@ -55,6 +55,7 @@ class TagTransformer extends AbstractTransformer $longitude = $location->longitude; $zoomLevel = (int)$location->zoom_level; } + return [ 'id' => (int)$tag->id, 'created_at' => $tag->created_at->toAtomString(), diff --git a/app/Transformers/TransactionGroupTransformer.php b/app/Transformers/TransactionGroupTransformer.php index 92f3ebf5c6..2c74cfda85 100644 --- a/app/Transformers/TransactionGroupTransformer.php +++ b/app/Transformers/TransactionGroupTransformer.php @@ -90,6 +90,194 @@ class TransactionGroupTransformer extends AbstractTransformer ]; } + /** + * @param NullArrayObject $data + * + * @return array + */ + private function transformTransactions(NullArrayObject $data): array + { + $result = []; + $transactions = $data['transactions'] ?? []; + foreach ($transactions as $transaction) { + $result[] = $this->transformTransaction($transaction); + } + + return $result; + } + + /** + * @param array $transaction + * + * @return array + */ + private function transformTransaction(array $transaction): array + { + $row = new NullArrayObject($transaction); + + // amount: + $type = $this->stringFromArray($transaction, 'transaction_type_type', TransactionType::WITHDRAWAL); + $amount = app('steam')->positive($row['amount'] ?? '0'); + $foreignAmount = null; + if (null !== $row['foreign_amount']) { + $foreignAmount = app('steam')->positive($row['foreign_amount']); + } + + $metaFieldData = $this->groupRepos->getMetaFields((int)$row['transaction_journal_id'], $this->metaFields); + $metaDateData = $this->groupRepos->getMetaDateFields((int)$row['transaction_journal_id'], $this->metaDateFields); + + $longitude = null; + $latitude = null; + $zoomLevel = null; + $location = $this->getLocationById((int)$row['transaction_journal_id']); + if (null !== $location) { + $longitude = $location->longitude; + $latitude = $location->latitude; + $zoomLevel = $location->zoom_level; + } + + return [ + 'user' => (string)$row['user_id'], + 'transaction_journal_id' => (int)$row['transaction_journal_id'], + 'type' => strtolower($type), + 'date' => $row['date']->toAtomString(), + 'order' => $row['order'], + + 'currency_id' => (string)$row['currency_id'], + 'currency_code' => $row['currency_code'], + 'currency_name' => $row['currency_name'], + 'currency_symbol' => $row['currency_symbol'], + 'currency_decimal_places' => (int)$row['currency_decimal_places'], + + 'foreign_currency_id' => $this->stringFromArray($transaction, 'foreign_currency_id', null), + 'foreign_currency_code' => $row['foreign_currency_code'], + 'foreign_currency_symbol' => $row['foreign_currency_symbol'], + 'foreign_currency_decimal_places' => $row['foreign_currency_decimal_places'], + + 'amount' => $amount, + 'foreign_amount' => $foreignAmount, + + 'description' => $row['description'], + + 'source_id' => (string)$row['source_account_id'], + 'source_name' => $row['source_account_name'], + 'source_iban' => $row['source_account_iban'], + 'source_type' => $row['source_account_type'], + + 'destination_id' => (string)$row['destination_account_id'], + 'destination_name' => $row['destination_account_name'], + 'destination_iban' => $row['destination_account_iban'], + 'destination_type' => $row['destination_account_type'], + + 'budget_id' => $this->stringFromArray($transaction, 'budget_id', null), + 'budget_name' => $row['budget_name'], + + 'category_id' => $this->stringFromArray($transaction, 'category_id', null), + 'category_name' => $row['category_name'], + + 'bill_id' => $this->stringFromArray($transaction, 'bill_id', null), + 'bill_name' => $row['bill_name'], + + 'reconciled' => $row['reconciled'], + 'notes' => $this->groupRepos->getNoteText((int)$row['transaction_journal_id']), + 'tags' => $this->groupRepos->getTags((int)$row['transaction_journal_id']), + + 'internal_reference' => $metaFieldData['internal_reference'], + 'external_id' => $metaFieldData['external_id'], + 'original_source' => $metaFieldData['original_source'], + 'recurrence_id' => $this->stringFromArray($metaFieldData->getArrayCopy(), 'recurrence_id', null), + 'recurrence_total' => $this->integerFromArray($metaFieldData->getArrayCopy(), 'recurrence_total'), + 'recurrence_count' => $this->integerFromArray($metaFieldData->getArrayCopy(), 'recurrence_count'), + 'bunq_payment_id' => $metaFieldData['bunq_payment_id'], + 'external_uri' => $metaFieldData['external_uri'], + 'import_hash_v2' => $metaFieldData['import_hash_v2'], + + 'sepa_cc' => $metaFieldData['sepa_cc'], + 'sepa_ct_op' => $metaFieldData['sepa_ct_op'], + 'sepa_ct_id' => $metaFieldData['sepa_ct_id'], + 'sepa_db' => $metaFieldData['sepa_db'], + 'sepa_country' => $metaFieldData['sepa_country'], + 'sepa_ep' => $metaFieldData['sepa_ep'], + 'sepa_ci' => $metaFieldData['sepa_ci'], + 'sepa_batch_id' => $metaFieldData['sepa_batch_id'], + + 'interest_date' => $this->dateFromArray($metaDateData, 'interest_date'), + 'book_date' => $this->dateFromArray($metaDateData, 'book_date'), + 'process_date' => $this->dateFromArray($metaDateData, 'process_date'), + 'due_date' => $this->dateFromArray($metaDateData, 'due_date'), + 'payment_date' => $this->dateFromArray($metaDateData, 'payment_date'), + 'invoice_date' => $this->dateFromArray($metaDateData, 'invoice_date'), + + // location data + 'longitude' => $longitude, + 'latitude' => $latitude, + 'zoom_level' => $zoomLevel, + ]; + } + + /** + * @param array $array + * @param string $key + * @param string|null $default + * + * @return string|null + */ + private function stringFromArray(array $array, string $key, ?string $default): ?string + { + if (array_key_exists($key, $array) && null === $array[$key]) { + return null; + } + if (array_key_exists($key, $array) && null !== $array[$key]) { + return (string)$array[$key]; + } + + if (null !== $default) { + return (string)$default; + } + + return null; + } + + /** + * @param int $journalId + * + * @return Location|null + */ + private function getLocationById(int $journalId): ?Location + { + return $this->groupRepos->getLocation($journalId); + } + + /** + * @param array $array + * @param string $key + * + * @return int|null + */ + private function integerFromArray(array $array, string $key): ?int + { + if (array_key_exists($key, $array)) { + return (int)$array[$key]; + } + + return null; + } + + /** + * @param NullArrayObject $object + * @param string $key + * + * @return string|null + */ + private function dateFromArray(NullArrayObject $object, string $key): ?string + { + if (null === $object[$key]) { + return null; + } + + return $object[$key]->toAtomString(); + } + /** * @param TransactionGroup $group * @@ -125,182 +313,17 @@ class TransactionGroupTransformer extends AbstractTransformer } /** - * @param string $type - * @param string $amount - * - * @return string - */ - private function getAmount(string $type, string $amount): string - { - $amount = app('steam')->positive($amount); - if (TransactionType::WITHDRAWAL !== $type) { - $amount = app('steam')->negative($amount); - } - - return $amount; - } - - /** - * @param Bill|null $bill + * @param Collection $transactionJournals * * @return array - */ - private function getBill(?Bill $bill): array - { - $array = [ - 'id' => null, - 'name' => null, - ]; - if (null === $bill) { - return $array; - } - $array['id'] = (string)$bill->id; - $array['name'] = $bill->name; - - return $array; - } - - /** - * @param Budget|null $budget - * - * @return array - */ - private function getBudget(?Budget $budget): array - { - $array = [ - 'id' => null, - 'name' => null, - ]; - if (null === $budget) { - return $array; - } - $array['id'] = (int)$budget->id; - $array['name'] = $budget->name; - - return $array; - } - - /** - * @param Category|null $category - * - * @return array - */ - private function getCategory(?Category $category): array - { - $array = [ - 'id' => null, - 'name' => null, - ]; - if (null === $category) { - return $array; - } - $array['id'] = (int)$category->id; - $array['name'] = $category->name; - - return $array; - } - - /** - * @param NullArrayObject $dates - * - * @return array - */ - private function getDates(NullArrayObject $dates): array - { - $fields = [ - 'interest_date', - 'book_date', - 'process_date', - 'due_date', - 'payment_date', - 'invoice_date', - ]; - $return = []; - foreach ($fields as $field) { - $return[$field] = null; - if (null !== $dates[$field]) { - $return[$field] = $dates[$field]->toAtomString(); - } - } - - return $return; - } - - /** - * @param TransactionJournal $journal - * - * @return Transaction * @throws FireflyException */ - private function getDestinationTransaction(TransactionJournal $journal): Transaction + private function transformJournals(Collection $transactionJournals): array { - $result = $journal->transactions->first( - static function (Transaction $transaction) { - return (float)$transaction->amount > 0; - } - ); - if (null === $result) { - throw new FireflyException(sprintf('Journal #%d unexpectedly has no destination transaction.', $journal->id)); - } - - return $result; - } - - /** - * @param string $type - * @param string|null $foreignAmount - * - * @return string|null - */ - private function getForeignAmount(string $type, ?string $foreignAmount): ?string - { - $result = null; - if (null !== $foreignAmount) { - $result = TransactionType::WITHDRAWAL !== $type ? app('steam')->negative($foreignAmount) : app('steam')->positive($foreignAmount); - } - - return $result; - } - - /** - * @param TransactionCurrency|null $currency - * - * @return array - */ - private function getForeignCurrency(?TransactionCurrency $currency): array - { - $array = [ - 'id' => null, - 'code' => null, - 'symbol' => null, - 'decimal_places' => null, - ]; - if (null === $currency) { - return $array; - } - $array['id'] = (int)$currency->id; - $array['code'] = $currency->code; - $array['symbol'] = $currency->symbol; - $array['decimal_places'] = (int)$currency->decimal_places; - - return $array; - } - - /** - * @param TransactionJournal $journal - * - * @return Transaction - * @throws FireflyException - */ - private function getSourceTransaction(TransactionJournal $journal): Transaction - { - $result = $journal->transactions->first( - static function (Transaction $transaction) { - return (float)$transaction->amount < 0; - } - ); - if (null === $result) { - throw new FireflyException(sprintf('Journal #%d unexpectedly has no source transaction.', $journal->id)); + $result = []; + /** @var TransactionJournal $journal */ + foreach ($transactionJournals as $journal) { + $result[] = $this->transformJournal($journal); } return $result; @@ -417,198 +440,185 @@ class TransactionGroupTransformer extends AbstractTransformer } /** - * @param Collection $transactionJournals + * @param TransactionJournal $journal * - * @return array + * @return Transaction * @throws FireflyException */ - private function transformJournals(Collection $transactionJournals): array + private function getSourceTransaction(TransactionJournal $journal): Transaction { - $result = []; - /** @var TransactionJournal $journal */ - foreach ($transactionJournals as $journal) { - $result[] = $this->transformJournal($journal); + $result = $journal->transactions->first( + static function (Transaction $transaction) { + return (float)$transaction->amount < 0; + } + ); + if (null === $result) { + throw new FireflyException(sprintf('Journal #%d unexpectedly has no source transaction.', $journal->id)); } return $result; } /** - * @param NullArrayObject $data + * @param TransactionJournal $journal * - * @return array + * @return Transaction + * @throws FireflyException */ - private function transformTransactions(NullArrayObject $data): array + private function getDestinationTransaction(TransactionJournal $journal): Transaction { - $result = []; - $transactions = $data['transactions'] ?? []; - foreach ($transactions as $transaction) { - $result[] = $this->transformTransaction($transaction); + $result = $journal->transactions->first( + static function (Transaction $transaction) { + return (float)$transaction->amount > 0; + } + ); + if (null === $result) { + throw new FireflyException(sprintf('Journal #%d unexpectedly has no destination transaction.', $journal->id)); } return $result; } /** - * @param array $transaction + * @param string $type + * @param string $amount + * + * @return string + */ + private function getAmount(string $type, string $amount): string + { + $amount = app('steam')->positive($amount); + if (TransactionType::WITHDRAWAL !== $type) { + $amount = app('steam')->negative($amount); + } + + return $amount; + } + + /** + * @param string $type + * @param string|null $foreignAmount + * + * @return string|null + */ + private function getForeignAmount(string $type, ?string $foreignAmount): ?string + { + $result = null; + if (null !== $foreignAmount) { + $result = TransactionType::WITHDRAWAL !== $type ? app('steam')->negative($foreignAmount) : app('steam')->positive($foreignAmount); + } + + return $result; + } + + /** + * @param NullArrayObject $dates * * @return array */ - private function transformTransaction(array $transaction): array + private function getDates(NullArrayObject $dates): array { - $row = new NullArrayObject($transaction); - - // amount: - $type = $this->stringFromArray($transaction, 'transaction_type_type', TransactionType::WITHDRAWAL); - $amount = app('steam')->positive($row['amount'] ?? '0'); - $foreignAmount = null; - if (null !== $row['foreign_amount']) { - $foreignAmount = app('steam')->positive($row['foreign_amount']); - } - - $metaFieldData = $this->groupRepos->getMetaFields((int)$row['transaction_journal_id'], $this->metaFields); - $metaDateData = $this->groupRepos->getMetaDateFields((int)$row['transaction_journal_id'], $this->metaDateFields); - - $longitude = null; - $latitude = null; - $zoomLevel = null; - $location = $this->getLocationById((int)$row['transaction_journal_id']); - if (null !== $location) { - $longitude = $location->longitude; - $latitude = $location->latitude; - $zoomLevel = $location->zoom_level; - } - - return [ - 'user' => (string)$row['user_id'], - 'transaction_journal_id' => (int)$row['transaction_journal_id'], - 'type' => strtolower($type), - 'date' => $row['date']->toAtomString(), - 'order' => $row['order'], - - 'currency_id' => (string)$row['currency_id'], - 'currency_code' => $row['currency_code'], - 'currency_name' => $row['currency_name'], - 'currency_symbol' => $row['currency_symbol'], - 'currency_decimal_places' => (int)$row['currency_decimal_places'], - - 'foreign_currency_id' => $this->stringFromArray($transaction, 'foreign_currency_id', null), - 'foreign_currency_code' => $row['foreign_currency_code'], - 'foreign_currency_symbol' => $row['foreign_currency_symbol'], - 'foreign_currency_decimal_places' => $row['foreign_currency_decimal_places'], - - 'amount' => $amount, - 'foreign_amount' => $foreignAmount, - - 'description' => $row['description'], - - 'source_id' => (string)$row['source_account_id'], - 'source_name' => $row['source_account_name'], - 'source_iban' => $row['source_account_iban'], - 'source_type' => $row['source_account_type'], - - 'destination_id' => (string)$row['destination_account_id'], - 'destination_name' => $row['destination_account_name'], - 'destination_iban' => $row['destination_account_iban'], - 'destination_type' => $row['destination_account_type'], - - 'budget_id' => $this->stringFromArray($transaction, 'budget_id', null), - 'budget_name' => $row['budget_name'], - - 'category_id' => $this->stringFromArray($transaction, 'category_id', null), - 'category_name' => $row['category_name'], - - 'bill_id' => $this->stringFromArray($transaction, 'bill_id', null), - 'bill_name' => $row['bill_name'], - - 'reconciled' => $row['reconciled'], - 'notes' => $this->groupRepos->getNoteText((int)$row['transaction_journal_id']), - 'tags' => $this->groupRepos->getTags((int)$row['transaction_journal_id']), - - 'internal_reference' => $metaFieldData['internal_reference'], - 'external_id' => $metaFieldData['external_id'], - 'original_source' => $metaFieldData['original_source'], - 'recurrence_id' => $this->stringFromArray($metaFieldData->getArrayCopy(), 'recurrence_id', null), - 'recurrence_total' => $this->integerFromArray($metaFieldData->getArrayCopy(), 'recurrence_total'), - 'recurrence_count' => $this->integerFromArray($metaFieldData->getArrayCopy(), 'recurrence_count'), - 'bunq_payment_id' => $metaFieldData['bunq_payment_id'], - 'external_uri' => $metaFieldData['external_uri'], - 'import_hash_v2' => $metaFieldData['import_hash_v2'], - - 'sepa_cc' => $metaFieldData['sepa_cc'], - 'sepa_ct_op' => $metaFieldData['sepa_ct_op'], - 'sepa_ct_id' => $metaFieldData['sepa_ct_id'], - 'sepa_db' => $metaFieldData['sepa_db'], - 'sepa_country' => $metaFieldData['sepa_country'], - 'sepa_ep' => $metaFieldData['sepa_ep'], - 'sepa_ci' => $metaFieldData['sepa_ci'], - 'sepa_batch_id' => $metaFieldData['sepa_batch_id'], - - 'interest_date' => $this->dateFromArray($metaDateData, 'interest_date'), - 'book_date' => $this->dateFromArray($metaDateData, 'book_date'), - 'process_date' => $this->dateFromArray($metaDateData, 'process_date'), - 'due_date' => $this->dateFromArray($metaDateData, 'due_date'), - 'payment_date' => $this->dateFromArray($metaDateData, 'payment_date'), - 'invoice_date' => $this->dateFromArray($metaDateData, 'invoice_date'), - - // location data - 'longitude' => $longitude, - 'latitude' => $latitude, - 'zoom_level' => $zoomLevel, + $fields = [ + 'interest_date', + 'book_date', + 'process_date', + 'due_date', + 'payment_date', + 'invoice_date', ]; + $return = []; + foreach ($fields as $field) { + $return[$field] = null; + if (null !== $dates[$field]) { + $return[$field] = $dates[$field]->toAtomString(); + } + } + + return $return; } /** - * @param array $array - * @param string $key - * @param string|null $default + * @param TransactionCurrency|null $currency * - * @return string|null + * @return array */ - private function stringFromArray(array $array, string $key, ?string $default): ?string + private function getForeignCurrency(?TransactionCurrency $currency): array { - if (array_key_exists($key, $array) && null === $array[$key]) { - return null; - } - if (array_key_exists($key, $array) && null !== $array[$key]) { - return (string) $array[$key]; + $array = [ + 'id' => null, + 'code' => null, + 'symbol' => null, + 'decimal_places' => null, + ]; + if (null === $currency) { + return $array; } + $array['id'] = (int)$currency->id; + $array['code'] = $currency->code; + $array['symbol'] = $currency->symbol; + $array['decimal_places'] = (int)$currency->decimal_places; - if (null !== $default) { - return (string) $default; - } - - return null; + return $array; } /** - * @param array $array - * @param string $key + * @param Budget|null $budget * - * @return int|null + * @return array */ - private function integerFromArray(array $array, string $key): ?int + private function getBudget(?Budget $budget): array { - if (array_key_exists($key, $array)) { - return (int)$array[$key]; + $array = [ + 'id' => null, + 'name' => null, + ]; + if (null === $budget) { + return $array; } + $array['id'] = (int)$budget->id; + $array['name'] = $budget->name; - return null; + return $array; } /** - * @param NullArrayObject $object - * @param string $key + * @param Category|null $category * - * @return string|null + * @return array */ - private function dateFromArray(NullArrayObject $object, string $key): ?string + private function getCategory(?Category $category): array { - if (null === $object[$key]) { - return null; + $array = [ + 'id' => null, + 'name' => null, + ]; + if (null === $category) { + return $array; } + $array['id'] = (int)$category->id; + $array['name'] = $category->name; - return $object[$key]->toAtomString(); + return $array; + } + + /** + * @param Bill|null $bill + * + * @return array + */ + private function getBill(?Bill $bill): array + { + $array = [ + 'id' => null, + 'name' => null, + ]; + if (null === $bill) { + return $array; + } + $array['id'] = (string)$bill->id; + $array['name'] = $bill->name; + + return $array; } /** @@ -620,14 +630,4 @@ class TransactionGroupTransformer extends AbstractTransformer { return $journal->locations()->first(); } - - /** - * @param int $journalId - * - * @return Location|null - */ - private function getLocationById(int $journalId): ?Location - { - return $this->groupRepos->getLocation($journalId); - } } diff --git a/app/Transformers/UserTransformer.php b/app/Transformers/UserTransformer.php index 5d10e45b42..161caa997b 100644 --- a/app/Transformers/UserTransformer.php +++ b/app/Transformers/UserTransformer.php @@ -26,7 +26,6 @@ namespace FireflyIII\Transformers; use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\User; -use Log; /** * Class UserTransformer @@ -46,6 +45,7 @@ class UserTransformer extends AbstractTransformer public function transform(User $user): array { $this->repository = $this->repository ?? app(UserRepositoryInterface::class); + return [ 'id' => (int)$user->id, 'created_at' => $user->created_at->toAtomString(), diff --git a/app/Validation/Account/AccountValidatorProperties.php b/app/Validation/Account/AccountValidatorProperties.php index 172fea5212..61197490ab 100644 --- a/app/Validation/Account/AccountValidatorProperties.php +++ b/app/Validation/Account/AccountValidatorProperties.php @@ -24,10 +24,6 @@ declare(strict_types=1); namespace FireflyIII\Validation\Account; -use FireflyIII\Models\Account; -use FireflyIII\Repositories\Account\AccountRepositoryInterface; -use FireflyIII\User; - /** * I have no idea what made me do this. I'll reverse it some day. * diff --git a/app/Validation/Account/DepositValidation.php b/app/Validation/Account/DepositValidation.php index 65e02abceb..c9661a2c33 100644 --- a/app/Validation/Account/DepositValidation.php +++ b/app/Validation/Account/DepositValidation.php @@ -32,22 +32,6 @@ use Log; */ trait DepositValidation { - /** - * @param array $accountTypes - * - * @return bool - */ - abstract protected function canCreateTypes(array $accountTypes): bool; - - /** - * @param array $validTypes - * @param int $accountId - * @param string $accountName - * - * @return Account|null - */ - abstract protected function findExistingAccount(array $validTypes, int $accountId, string $accountName): ?Account; - /** * @param int|null $accountId * @param $accountName @@ -64,7 +48,7 @@ trait DepositValidation if (null === $accountId && null === $accountName && false === $this->canCreateTypes($validTypes)) { // if both values are NULL we return false, // because the destination of a deposit can't be created. - $this->destError = (string) trans('validation.deposit_dest_need_data'); + $this->destError = (string)trans('validation.deposit_dest_need_data'); Log::error('Both values are NULL, cant create deposit destination.'); $result = false; } @@ -76,10 +60,10 @@ trait DepositValidation if (null === $result) { // otherwise try to find the account: - $search = $this->findExistingAccount($validTypes, (int) $accountId, (string) $accountName); + $search = $this->findExistingAccount($validTypes, (int)$accountId, (string)$accountName); if (null === $search) { Log::debug('findExistingAccount() returned NULL, so the result is false.'); - $this->destError = (string) trans('validation.deposit_dest_bad_data', ['id' => $accountId, 'name' => $accountName]); + $this->destError = (string)trans('validation.deposit_dest_bad_data', ['id' => $accountId, 'name' => $accountName]); $result = false; } if (null !== $search) { @@ -94,6 +78,22 @@ trait DepositValidation return $result; } + /** + * @param array $accountTypes + * + * @return bool + */ + abstract protected function canCreateTypes(array $accountTypes): bool; + + /** + * @param array $validTypes + * @param int $accountId + * @param string $accountName + * + * @return Account|null + */ + abstract protected function findExistingAccount(array $validTypes, int $accountId, string $accountName): ?Account; + /** * @param int|null $accountId * @param string|null $accountName @@ -110,7 +110,7 @@ trait DepositValidation // if both values are NULL return false, // because the source of a deposit can't be created. // (this never happens). - $this->sourceError = (string) trans('validation.deposit_source_need_data'); + $this->sourceError = (string)trans('validation.deposit_source_need_data'); $result = false; } @@ -134,6 +134,7 @@ trait DepositValidation $account->accountType = $accountType; $this->source = $account; } + return $result ?? false; } } diff --git a/app/Validation/Account/OBValidation.php b/app/Validation/Account/OBValidation.php index 86c358a80c..3efabe83cc 100644 --- a/app/Validation/Account/OBValidation.php +++ b/app/Validation/Account/OBValidation.php @@ -33,13 +33,6 @@ use Log; */ trait OBValidation { - /** - * @param array $accountTypes - * - * @return bool - */ - abstract protected function canCreateTypes(array $accountTypes): bool; - /** * @param int|null $accountId * @param $accountName @@ -56,7 +49,7 @@ trait OBValidation if (null === $accountId && null === $accountName && false === $this->canCreateTypes($validTypes)) { // if both values are NULL we return false, // because the destination of a deposit can't be created. - $this->destError = (string) trans('validation.ob_dest_need_data'); + $this->destError = (string)trans('validation.ob_dest_need_data'); Log::error('Both values are NULL, cant create OB destination.'); $result = false; } @@ -68,10 +61,10 @@ trait OBValidation if (null === $result) { // otherwise try to find the account: - $search = $this->findExistingAccount($validTypes, (int) $accountId, (string) $accountName); + $search = $this->findExistingAccount($validTypes, (int)$accountId, (string)$accountName); if (null === $search) { Log::debug('findExistingAccount() returned NULL, so the result is false.', $validTypes); - $this->destError = (string) trans('validation.ob_dest_bad_data', ['id' => $accountId, 'name' => $accountName]); + $this->destError = (string)trans('validation.ob_dest_bad_data', ['id' => $accountId, 'name' => $accountName]); $result = false; } if (null !== $search) { @@ -86,6 +79,13 @@ trait OBValidation return $result; } + /** + * @param array $accountTypes + * + * @return bool + */ + abstract protected function canCreateTypes(array $accountTypes): bool; + /** * Source of an opening balance can either be an asset account * or an "initial balance account". The latter can be created. @@ -107,7 +107,7 @@ trait OBValidation // if both values are NULL return false, // because the source of a deposit can't be created. // (this never happens). - $this->sourceError = (string) trans('validation.ob_source_need_data'); + $this->sourceError = (string)trans('validation.ob_source_need_data'); $result = false; } @@ -143,6 +143,7 @@ trait OBValidation $account->accountType = $accountType; $this->source = $account; } + return $result ?? false; } } diff --git a/app/Validation/Account/ReconciliationValidation.php b/app/Validation/Account/ReconciliationValidation.php index 63c9a21f57..450c9977ed 100644 --- a/app/Validation/Account/ReconciliationValidation.php +++ b/app/Validation/Account/ReconciliationValidation.php @@ -24,8 +24,8 @@ declare(strict_types=1); namespace FireflyIII\Validation\Account; -use Log; use FireflyIII\Models\AccountType; +use Log; /** * Trait ReconciliationValidation @@ -89,20 +89,24 @@ trait ReconciliationValidation Log::debug('In validateReconciliationSource'); if (null === $accountId) { Log::debug('Return FALSE'); + return false; } $result = $this->accountRepository->findNull($accountId); $types = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE, AccountType::RECONCILIATION]; if (null === $result) { Log::debug('Return FALSE'); + return false; } if (in_array($result->accountType->type, $types, true)) { $this->source = $result; Log::debug('Return TRUE'); + return true; } Log::debug('Return FALSE'); + return false; } diff --git a/app/Validation/Account/TransferValidation.php b/app/Validation/Account/TransferValidation.php index c0570e65b1..44459963aa 100644 --- a/app/Validation/Account/TransferValidation.php +++ b/app/Validation/Account/TransferValidation.php @@ -31,22 +31,6 @@ use Log; */ trait TransferValidation { - /** - * @param array $accountTypes - * - * @return bool - */ - abstract protected function canCreateTypes(array $accountTypes): bool; - - /** - * @param array $validTypes - * @param int $accountId - * @param string $accountName - * - * @return Account|null - */ - abstract protected function findExistingAccount(array $validTypes, int $accountId, string $accountName): ?Account; - /** * @param int|null $accountId * @param $accountName @@ -61,16 +45,16 @@ trait TransferValidation if (null === $accountId && null === $accountName && false === $this->canCreateTypes($validTypes)) { // if both values are NULL we return false, // because the destination of a transfer can't be created. - $this->destError = (string) trans('validation.transfer_dest_need_data'); + $this->destError = (string)trans('validation.transfer_dest_need_data'); Log::error('Both values are NULL, cant create transfer destination.'); return false; } // otherwise try to find the account: - $search = $this->findExistingAccount($validTypes, (int) $accountId, (string) $accountName); + $search = $this->findExistingAccount($validTypes, (int)$accountId, (string)$accountName); if (null === $search) { - $this->destError = (string) trans('validation.transfer_dest_bad_data', ['id' => $accountId, 'name' => $accountName]); + $this->destError = (string)trans('validation.transfer_dest_bad_data', ['id' => $accountId, 'name' => $accountName]); return false; } @@ -87,6 +71,22 @@ trait TransferValidation return true; } + /** + * @param array $accountTypes + * + * @return bool + */ + abstract protected function canCreateTypes(array $accountTypes): bool; + + /** + * @param array $validTypes + * @param int $accountId + * @param string $accountName + * + * @return Account|null + */ + abstract protected function findExistingAccount(array $validTypes, int $accountId, string $accountName): ?Account; + /** * @param int|null $accountId * @param string|null $accountName @@ -101,16 +101,16 @@ trait TransferValidation if (null === $accountId && null === $accountName && false === $this->canCreateTypes($validTypes)) { // if both values are NULL we return false, // because the source of a withdrawal can't be created. - $this->sourceError = (string) trans('validation.transfer_source_need_data'); + $this->sourceError = (string)trans('validation.transfer_source_need_data'); Log::warning('Not a valid source, need more data.'); return false; } // otherwise try to find the account: - $search = $this->findExistingAccount($validTypes, (int) $accountId, (string) $accountName); + $search = $this->findExistingAccount($validTypes, (int)$accountId, (string)$accountName); if (null === $search) { - $this->sourceError = (string) trans('validation.transfer_source_bad_data', ['id' => $accountId, 'name' => $accountName]); + $this->sourceError = (string)trans('validation.transfer_source_bad_data', ['id' => $accountId, 'name' => $accountName]); Log::warning('Not a valid source, cant find it.', $validTypes); return false; diff --git a/app/Validation/Account/WithdrawalValidation.php b/app/Validation/Account/WithdrawalValidation.php index 6b41fb9c51..1dc5d4293b 100644 --- a/app/Validation/Account/WithdrawalValidation.php +++ b/app/Validation/Account/WithdrawalValidation.php @@ -33,20 +33,38 @@ use Log; trait WithdrawalValidation { /** - * @param array $accountTypes + * @param int|null $accountId + * @param string|null $accountName * * @return bool */ - abstract protected function canCreateTypes(array $accountTypes): bool; + protected function validateGenericSource(?int $accountId, ?string $accountName): bool + { + Log::debug(sprintf('Now in validateGenericSource(%d, "%s")', $accountId, $accountName)); + // source can be any of the following types. + $validTypes = [AccountType::ASSET, AccountType::REVENUE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]; + if (null === $accountId && null === $accountName && false === $this->canCreateTypes($validTypes)) { + // if both values are NULL we return TRUE + // because we assume the user doesnt want to submit / change anything. + $this->sourceError = (string)trans('validation.withdrawal_source_need_data'); + Log::warning('Not a valid source. Need more data.'); - /** - * @param array $validTypes - * @param int $accountId - * @param string $accountName - * - * @return Account|null - */ - abstract protected function findExistingAccount(array $validTypes, int $accountId, string $accountName): ?Account; + return false; + } + + // otherwise try to find the account: + $search = $this->findExistingAccount($validTypes, (int)$accountId, (string)$accountName); + if (null === $search) { + $this->sourceError = (string)trans('validation.withdrawal_source_bad_data', ['id' => $accountId, 'name' => $accountName]); + Log::warning('Not a valid source. Cant find it.', $validTypes); + + return false; + } + $this->source = $search; + Log::debug('Valid source account!'); + + return true; + } /** * @param int|null $accountId @@ -62,7 +80,7 @@ trait WithdrawalValidation if (null === $accountId && null === $accountName && false === $this->canCreateTypes($validTypes)) { // if both values are NULL return false, // because the destination of a withdrawal can never be created automatically. - $this->destError = (string) trans('validation.withdrawal_dest_need_data'); + $this->destError = (string)trans('validation.withdrawal_dest_need_data'); return false; } @@ -75,7 +93,7 @@ trait WithdrawalValidation if (in_array($type, $validTypes, true)) { return true; } - $this->destError = (string) trans('validation.withdrawal_dest_bad_data', ['id' => $accountId, 'name' => $accountName]); + $this->destError = (string)trans('validation.withdrawal_dest_bad_data', ['id' => $accountId, 'name' => $accountName]); return false; } @@ -85,6 +103,13 @@ trait WithdrawalValidation return true === $this->canCreateTypes($validTypes); } + /** + * @param array $accountTypes + * + * @return bool + */ + abstract protected function canCreateTypes(array $accountTypes): bool; + /** * @param int|null $accountId * @param string|null $accountName @@ -99,16 +124,16 @@ trait WithdrawalValidation if (null === $accountId && null === $accountName && false === $this->canCreateTypes($validTypes)) { // if both values are NULL we return false, // because the source of a withdrawal can't be created. - $this->sourceError = (string) trans('validation.withdrawal_source_need_data'); + $this->sourceError = (string)trans('validation.withdrawal_source_need_data'); Log::warning('Not a valid source. Need more data.'); return false; } // otherwise try to find the account: - $search = $this->findExistingAccount($validTypes, (int) $accountId, (string) $accountName); + $search = $this->findExistingAccount($validTypes, (int)$accountId, (string)$accountName); if (null === $search) { - $this->sourceError = (string) trans('validation.withdrawal_source_bad_data', ['id' => $accountId, 'name' => $accountName]); + $this->sourceError = (string)trans('validation.withdrawal_source_bad_data', ['id' => $accountId, 'name' => $accountName]); Log::warning('Not a valid source. Cant find it.', $validTypes); return false; @@ -120,36 +145,11 @@ trait WithdrawalValidation } /** - * @param int|null $accountId - * @param string|null $accountName + * @param array $validTypes + * @param int $accountId + * @param string $accountName * - * @return bool + * @return Account|null */ - protected function validateGenericSource(?int $accountId, ?string $accountName): bool - { - Log::debug(sprintf('Now in validateGenericSource(%d, "%s")', $accountId, $accountName)); - // source can be any of the following types. - $validTypes = [AccountType::ASSET, AccountType::REVENUE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]; - if (null === $accountId && null === $accountName && false === $this->canCreateTypes($validTypes)) { - // if both values are NULL we return TRUE - // because we assume the user doesnt want to submit / change anything. - $this->sourceError = (string) trans('validation.withdrawal_source_need_data'); - Log::warning('Not a valid source. Need more data.'); - - return false; - } - - // otherwise try to find the account: - $search = $this->findExistingAccount($validTypes, (int) $accountId, (string) $accountName); - if (null === $search) { - $this->sourceError = (string) trans('validation.withdrawal_source_bad_data', ['id' => $accountId, 'name' => $accountName]); - Log::warning('Not a valid source. Cant find it.', $validTypes); - - return false; - } - $this->source = $search; - Log::debug('Valid source account!'); - - return true; - } + abstract protected function findExistingAccount(array $validTypes, int $accountId, string $accountName): ?Account; } diff --git a/app/Validation/AccountValidator.php b/app/Validation/AccountValidator.php index c544da6e8e..f70d860706 100644 --- a/app/Validation/AccountValidator.php +++ b/app/Validation/AccountValidator.php @@ -45,8 +45,8 @@ class AccountValidator public bool $createMode; public string $destError; - public ?Account $destination; - public ?Account $source; + public ?Account $destination; + public ?Account $source; public string $sourceError; private AccountRepositoryInterface $accountRepository; private array $combinations; @@ -69,6 +69,14 @@ class AccountValidator $this->accountRepository = app(AccountRepositoryInterface::class); } + /** + * @return Account|null + */ + public function getSource(): ?Account + { + return $this->source; + } + /** * @param string $transactionType */ @@ -167,21 +175,6 @@ class AccountValidator return $result; } - /** - * @param string $accountType - * - * @return bool - */ - protected function canCreateType(string $accountType): bool - { - $canCreate = [AccountType::EXPENSE, AccountType::REVENUE, AccountType::INITIAL_BALANCE]; - if (in_array($accountType, $canCreate, true)) { - return true; - } - - return false; - } - /** * @param array $accountTypes * @@ -203,6 +196,21 @@ class AccountValidator return false; } + /** + * @param string $accountType + * + * @return bool + */ + protected function canCreateType(string $accountType): bool + { + $canCreate = [AccountType::EXPENSE, AccountType::REVENUE, AccountType::INITIAL_BALANCE]; + if (in_array($accountType, $canCreate, true)) { + return true; + } + + return false; + } + /** * @param array $validTypes * @param int $accountId @@ -228,12 +236,4 @@ class AccountValidator return null; } - /** - * @return Account|null - */ - public function getSource(): ?Account - { - return $this->source; - } - } diff --git a/app/Validation/AutoBudget/ValidatesAutoBudgetRequest.php b/app/Validation/AutoBudget/ValidatesAutoBudgetRequest.php index 13ce60046c..1555bf35ed 100644 --- a/app/Validation/AutoBudget/ValidatesAutoBudgetRequest.php +++ b/app/Validation/AutoBudget/ValidatesAutoBudgetRequest.php @@ -39,27 +39,27 @@ trait ValidatesAutoBudgetRequest $data = $validator->getData(); $type = $data['auto_budget_type'] ?? ''; $amount = $data['auto_budget_amount'] ?? ''; - $period = (string) ($data['auto_budget_period'] ?? ''); + $period = (string)($data['auto_budget_period'] ?? ''); $currencyId = $data['auto_budget_currency_id'] ?? ''; $currencyCode = $data['auto_budget_currency_code'] ?? ''; if (is_numeric($type)) { - $type = (int) $type; + $type = (int)$type; } if (0 === $type || 'none' === $type || '' === $type) { return; } // basic float check: if ('' === $amount) { - $validator->errors()->add('auto_budget_amount', (string) trans('validation.amount_required_for_auto_budget')); + $validator->errors()->add('auto_budget_amount', (string)trans('validation.amount_required_for_auto_budget')); } - if (1 !== bccomp((string) $amount, '0')) { - $validator->errors()->add('auto_budget_amount', (string) trans('validation.auto_budget_amount_positive')); + if (1 !== bccomp((string)$amount, '0')) { + $validator->errors()->add('auto_budget_amount', (string)trans('validation.auto_budget_amount_positive')); } if ('' === $period) { - $validator->errors()->add('auto_budget_period', (string) trans('validation.auto_budget_period_mandatory')); + $validator->errors()->add('auto_budget_period', (string)trans('validation.auto_budget_period_mandatory')); } if ('' === $currencyCode && '' === $currencyId) { - $validator->errors()->add('auto_budget_amount', (string) trans('validation.require_currency_info')); + $validator->errors()->add('auto_budget_amount', (string)trans('validation.require_currency_info')); } } } diff --git a/app/Validation/CurrencyValidation.php b/app/Validation/CurrencyValidation.php index 6dc42b2944..1220d103d0 100644 --- a/app/Validation/CurrencyValidation.php +++ b/app/Validation/CurrencyValidation.php @@ -35,13 +35,6 @@ use Log; */ trait CurrencyValidation { - /** - * @param Validator $validator - * - * @return array - */ - abstract protected function getTransactionsArray(Validator $validator): array; - /** * If the transactions contain foreign amounts, there must also be foreign currency information. * @@ -59,16 +52,23 @@ trait CurrencyValidation ) { $validator->errors()->add( 'transactions.' . $index . '.foreign_amount', - (string) trans('validation.require_currency_info') + (string)trans('validation.require_currency_info') ); } // if the currency is present, then the amount must be present as well. if ((isset($transaction['foreign_currency_id']) || isset($transaction['foreign_currency_code'])) && !isset($transaction['foreign_amount'])) { $validator->errors()->add( 'transactions.' . $index . '.foreign_amount', - (string) trans('validation.require_currency_amount') + (string)trans('validation.require_currency_amount') ); } } } + + /** + * @param Validator $validator + * + * @return array + */ + abstract protected function getTransactionsArray(Validator $validator): array; } diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php index dda899058a..dffebe32d2 100644 --- a/app/Validation/FireflyValidator.php +++ b/app/Validation/FireflyValidator.php @@ -44,6 +44,7 @@ use Google2FA; use Illuminate\Support\Collection; use Illuminate\Validation\Validator; use Log; +use function is_string; /** * Class FireflyValidator. @@ -58,7 +59,7 @@ class FireflyValidator extends Validator */ public function validate2faCode($attribute, $value): bool { - if (!\is_string($value) || null === $value || 6 !== strlen($value)) { + if (!is_string($value) || null === $value || 6 !== strlen($value)) { return false; } @@ -114,7 +115,7 @@ class FireflyValidator extends Validator */ public function validateIban($attribute, $value): bool { - if (!\is_string($value) || null === $value || strlen($value) < 6) { + if (!is_string($value) || null === $value || strlen($value) < 6) { return false; } // strip spaces @@ -431,6 +432,141 @@ class FireflyValidator extends Validator return $this->validateByAccountName($value); } + /** + * @return bool + */ + private function validateAccountAnonymously(): bool + { + if (!isset($this->data['user_id'])) { + return false; + } + + $user = User::find($this->data['user_id']); + $type = AccountType::find($this->data['account_type_id'])->first(); + $value = $this->data['name']; + + $set = $user->accounts()->where('account_type_id', $type->id)->get(); + // TODO no longer need to loop like this + /** @var Account $entry */ + foreach ($set as $entry) { + if ($entry->name === $value) { + return false; + } + } + + return true; + } + + /** + * @param string $value + * @param array $parameters + * @param string $type + * + * @return bool + */ + private function validateByAccountTypeString(string $value, array $parameters, string $type): bool + { + /** @var array $search */ + $search = Config::get('firefly.accountTypeByIdentifier.' . $type); + + if (null === $search) { + return false; + } + + /** @var Collection $accountTypes */ + $accountTypes = AccountType::whereIn('type', $search)->get(); + $ignore = (int)($parameters[0] ?? 0.0); + $accountTypeIds = $accountTypes->pluck('id')->toArray(); + /** @var Collection $set */ + $set = auth()->user()->accounts()->whereIn('account_type_id', $accountTypeIds)->where('id', '!=', $ignore)->get(); + // TODO no longer need to loop like this + /** @var Account $entry */ + foreach ($set as $entry) { + if ($entry->name === $value) { + return false; + } + } + + return true; + } + + /** + * @param $value + * @param $parameters + * + * @return bool + */ + private function validateByAccountTypeId($value, $parameters): bool + { + $type = AccountType::find($this->data['account_type_id'])->first(); + $ignore = (int)($parameters[0] ?? 0.0); + + /** @var Collection $set */ + $set = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)->get(); + // TODO no longer need to loop like this + /** @var Account $entry */ + foreach ($set as $entry) { + // TODO no longer need to loop like this. + if ($entry->name === $value) { + return false; + } + } + + return true; + } + + /** + * @param $value + * + * @return bool + */ + private function validateByParameterId(int $accountId, $value): bool + { + /** @var Account $existingAccount */ + $existingAccount = Account::find($accountId); + + $type = $existingAccount->accountType; + $ignore = $existingAccount->id; + + /** @var Collection $set */ + $entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore) + ->where('name', $value) + ->first(); + + return null === $entry; + } + + /** + * @param $value + * + * @return bool + */ + private function validateByAccountId($value): bool + { + /** @var Account $existingAccount */ + $existingAccount = Account::find($this->data['id']); + + $type = $existingAccount->accountType; + $ignore = $existingAccount->id; + + /** @var Collection $set */ + $entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore) + ->where('name', $value) + ->first(); + + return null === $entry; + } + + /** + * @param string $value + * + * @return bool + */ + private function validateByAccountName(string $value): bool + { + return auth()->user()->accounts()->where('name', $value)->count() === 0; + } + /** * @param $attribute * @param $value @@ -466,6 +602,49 @@ class FireflyValidator extends Validator return true; } + public function validateUniqueExistingWebhook($value, $parameters, $something): bool + { + $existingId = (int)($something[0] ?? 0); + $trigger = 0; + $response = 0; + $delivery = 0; + $triggers = array_flip(config('firefly.webhooks.triggers')); + $responses = array_flip(config('firefly.webhooks.responses')); + $deliveries = array_flip(config('firefly.webhooks.deliveries')); + if (auth()->check()) { + // get existing webhook value: + if (0 !== $existingId) { + /** @var Webhook $webhook */ + $webhook = auth()->user()->webhooks()->find($existingId); + if (null === $webhook) { + return false; + } + // set triggers etc. + $trigger = $triggers[$webhook->trigger] ?? 0; + $response = $responses[$webhook->response] ?? 0; + $delivery = $deliveries[$webhook->delivery] ?? 0; + } + if (0 === $existingId) { + $trigger = $triggers[$this->data['trigger']] ?? 0; + $response = $responses[$this->data['response']] ?? 0; + $delivery = $deliveries[$this->data['delivery']] ?? 0; + } + + + $url = $this->data['url']; + $userId = auth()->user()->id; + + return 0 === Webhook::whereUserId($userId) + ->where('trigger', $trigger) + ->where('response', $response) + ->where('delivery', $delivery) + ->where('id', '!=', $existingId) + ->where('url', $url)->count(); + } + + return false; + } + /** * * Validate an object and its unicity. Checks for encryption / encrypted values as well. @@ -531,7 +710,6 @@ class FireflyValidator extends Validator return 0 === $query->count(); } - /** * @param $attribute * @param $value @@ -563,118 +741,6 @@ class FireflyValidator extends Validator return true; } - /** - * @return bool - */ - private function validateAccountAnonymously(): bool - { - if (!isset($this->data['user_id'])) { - return false; - } - - $user = User::find($this->data['user_id']); - $type = AccountType::find($this->data['account_type_id'])->first(); - $value = $this->data['name']; - - $set = $user->accounts()->where('account_type_id', $type->id)->get(); - // TODO no longer need to loop like this - /** @var Account $entry */ - foreach ($set as $entry) { - if ($entry->name === $value) { - return false; - } - } - - return true; - } - - /** - * @param $value - * - * @return bool - */ - private function validateByAccountId($value): bool - { - /** @var Account $existingAccount */ - $existingAccount = Account::find($this->data['id']); - - $type = $existingAccount->accountType; - $ignore = $existingAccount->id; - - /** @var Collection $set */ - $entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore) - ->where('name', $value) - ->first(); - - return null === $entry; - } - - - /** - * @param $value - * - * @return bool - */ - private function validateByParameterId(int $accountId, $value): bool - { - /** @var Account $existingAccount */ - $existingAccount = Account::find($accountId); - - $type = $existingAccount->accountType; - $ignore = $existingAccount->id; - - /** @var Collection $set */ - $entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore) - ->where('name', $value) - ->first(); - - return null === $entry; - } - - public function validateUniqueExistingWebhook($value, $parameters, $something): bool - { - $existingId = (int)($something[0] ?? 0); - $trigger = 0; - $response = 0; - $delivery = 0; - $triggers = array_flip(config('firefly.webhooks.triggers')); - $responses = array_flip(config('firefly.webhooks.responses')); - $deliveries = array_flip(config('firefly.webhooks.deliveries')); - if (auth()->check()) { - // get existing webhook value: - if(0!== $existingId) { - /** @var Webhook $webhook */ - $webhook = auth()->user()->webhooks()->find($existingId); - if(null === $webhook) { - return false; - } - // set triggers etc. - $trigger = $triggers[$webhook->trigger] ?? 0; - $response = $responses[$webhook->response] ?? 0; - $delivery = $deliveries[$webhook->delivery] ?? 0; - } - if(0=== $existingId) { - $trigger = $triggers[$this->data['trigger']] ?? 0; - $response = $responses[$this->data['response']] ?? 0; - $delivery = $deliveries[$this->data['delivery']] ?? 0; - } - - - - $url = $this->data['url']; - $userId = auth()->user()->id; - - return 0 === Webhook::whereUserId($userId) - ->where('trigger', $trigger) - ->where('response', $response) - ->where('delivery', $delivery) - ->where('id', '!=', $existingId) - ->where('url', $url)->count(); - } - - return false; - } - /** * @param $value * @param $parameters @@ -708,72 +774,4 @@ class FireflyValidator extends Validator return false; } - - /** - * @param $value - * @param $parameters - * - * @return bool - */ - private function validateByAccountTypeId($value, $parameters): bool - { - $type = AccountType::find($this->data['account_type_id'])->first(); - $ignore = (int)($parameters[0] ?? 0.0); - - /** @var Collection $set */ - $set = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)->get(); - // TODO no longer need to loop like this - /** @var Account $entry */ - foreach ($set as $entry) { - // TODO no longer need to loop like this. - if ($entry->name === $value) { - return false; - } - } - - return true; - } - - /** - * @param string $value - * @param array $parameters - * @param string $type - * - * @return bool - */ - private function validateByAccountTypeString(string $value, array $parameters, string $type): bool - { - /** @var array $search */ - $search = Config::get('firefly.accountTypeByIdentifier.' . $type); - - if (null === $search) { - return false; - } - - /** @var Collection $accountTypes */ - $accountTypes = AccountType::whereIn('type', $search)->get(); - $ignore = (int)($parameters[0] ?? 0.0); - $accountTypeIds = $accountTypes->pluck('id')->toArray(); - /** @var Collection $set */ - $set = auth()->user()->accounts()->whereIn('account_type_id', $accountTypeIds)->where('id', '!=', $ignore)->get(); - // TODO no longer need to loop like this - /** @var Account $entry */ - foreach ($set as $entry) { - if ($entry->name === $value) { - return false; - } - } - - return true; - } - - /** - * @param string $value - * - * @return bool - */ - private function validateByAccountName(string $value): bool - { - return auth()->user()->accounts()->where('name', $value)->count() === 0; - } } diff --git a/app/Validation/GroupValidation.php b/app/Validation/GroupValidation.php index 0b6013bd40..2e150db636 100644 --- a/app/Validation/GroupValidation.php +++ b/app/Validation/GroupValidation.php @@ -36,40 +36,6 @@ use Log; trait GroupValidation { - /** - * @param Validator $validator - * - * @return array - */ - abstract protected function getTransactionsArray(Validator $validator): array; - - /** - * This method validates if the user has submitted transaction journal ID's for each array they submit, if they've submitted more than 1 transaction - * journal. This check is necessary because Firefly III isn't able to distinguish between journals without the ID. - * - * @param Validator $validator - * @param TransactionGroup $transactionGroup - */ - protected function validateJournalIds(Validator $validator, TransactionGroup $transactionGroup): void - { - Log::debug(sprintf('Now in GroupValidation::validateJournalIds(%d)', $transactionGroup->id)); - $transactions = $this->getTransactionsArray($validator); - - if (count($transactions) < 2) { - // no need for validation. - Log::debug(sprintf('%d transaction(s) in submission, can skip this check.', count($transactions))); - return; - } - // check each array: - /** - * @var int $index - * @var array $transaction - */ - foreach ($transactions as $index => $transaction) { - $this->validateJournalId($validator, $index, $transaction, $transactionGroup); - } - } - /** * Adds an error to the "description" field when the user has submitted no descriptions and no * journal description. @@ -95,6 +61,56 @@ trait GroupValidation } } + /** + * @param Validator $validator + */ + protected function validateGroupDescription(Validator $validator): void + { + Log::debug('Now in validateGroupDescription()'); + $data = $validator->getData(); + $transactions = $this->getTransactionsArray($validator); + + $groupTitle = $data['group_title'] ?? ''; + if ('' === $groupTitle && count($transactions) > 1) { + $validator->errors()->add('group_title', (string)trans('validation.group_title_mandatory')); + } + } + + /** + * This method validates if the user has submitted transaction journal ID's for each array they submit, if they've submitted more than 1 transaction + * journal. This check is necessary because Firefly III isn't able to distinguish between journals without the ID. + * + * @param Validator $validator + * @param TransactionGroup $transactionGroup + */ + protected function validateJournalIds(Validator $validator, TransactionGroup $transactionGroup): void + { + Log::debug(sprintf('Now in GroupValidation::validateJournalIds(%d)', $transactionGroup->id)); + $transactions = $this->getTransactionsArray($validator); + + if (count($transactions) < 2) { + // no need for validation. + Log::debug(sprintf('%d transaction(s) in submission, can skip this check.', count($transactions))); + + return; + } + // check each array: + /** + * @var int $index + * @var array $transaction + */ + foreach ($transactions as $index => $transaction) { + $this->validateJournalId($validator, $index, $transaction, $transactionGroup); + } + } + + /** + * @param Validator $validator + * + * @return array + */ + abstract protected function getTransactionsArray(Validator $validator): array; + /** * Do the validation required by validateJournalIds. * @@ -110,27 +126,11 @@ trait GroupValidation $journalId = $transaction['transaction_journal_id'] ?? null; Log::debug(sprintf('Now in validateJournalId(%d, %d)', $index, $journalId)); - $journalId = null === $journalId ? null : (int) $journalId; + $journalId = null === $journalId ? null : (int)$journalId; $count = $transactionGroup->transactionJournals()->where('id', $journalId)->count(); if (null === $journalId || (null !== $journalId && 0 !== $journalId && 0 === $count)) { Log::warning('Invalid submission: Each split must have transaction_journal_id (either valid ID or 0).'); - $validator->errors()->add(sprintf('transactions.%d.source_name', $index), (string) trans('validation.need_id_in_edit')); - } - } - - - /** - * @param Validator $validator - */ - protected function validateGroupDescription(Validator $validator): void - { - Log::debug('Now in validateGroupDescription()'); - $data = $validator->getData(); - $transactions = $this->getTransactionsArray($validator); - - $groupTitle = $data['group_title'] ?? ''; - if ('' === $groupTitle && count($transactions) > 1) { - $validator->errors()->add('group_title', (string) trans('validation.group_title_mandatory')); + $validator->errors()->add(sprintf('transactions.%d.source_name', $index), (string)trans('validation.need_id_in_edit')); } } diff --git a/app/Validation/RecurrenceValidation.php b/app/Validation/RecurrenceValidation.php index 20985393c0..35f10bf622 100644 --- a/app/Validation/RecurrenceValidation.php +++ b/app/Validation/RecurrenceValidation.php @@ -38,26 +38,6 @@ use Log; */ trait RecurrenceValidation { - public function validateRecurringConfig(Validator $validator) - { - $data = $validator->getData(); - $reps = array_key_exists('nr_of_repetitions', $data) ? (int)$data['nr_of_repetitions'] : null; - $repeatUntil = array_key_exists('repeat_until', $data) ? new Carbon($data['repeat_until']) : null; - - if (null === $reps && null === $repeatUntil) { - $validator->errors()->add('nr_of_repetitions', trans('validation.require_repeat_until')); - $validator->errors()->add('repeat_until', trans('validation.require_repeat_until')); - - return; - } - if ($reps > 0 && null !== $repeatUntil) { - $validator->errors()->add('nr_of_repetitions', trans('validation.require_repeat_until')); - $validator->errors()->add('repeat_until', trans('validation.require_repeat_until')); - - return; - } - } - /** * Validate account information input for recurrences which are being updated. * @@ -85,7 +65,7 @@ trait RecurrenceValidation $transactionType = $first->transactionType ? $first->transactionType->type : 'withdrawal'; Log::debug(sprintf('Determined type to be %s.', $transactionType)); } - if(null === $first) { + if (null === $first) { Log::warning('Just going to assume type is a withdrawal.'); $transactionType = 'withdrawal'; } @@ -102,11 +82,11 @@ trait RecurrenceValidation $transactionType = $transaction['type'] ?? $transactionType; $accountValidator->setTransactionType($transactionType); - if( - !array_key_exists('source_id', $transaction) && - !array_key_exists('destination_id', $transaction) && - !array_key_exists('source_name', $transaction) && - !array_key_exists('destination_name', $transaction) + if ( + !array_key_exists('source_id', $transaction) + && !array_key_exists('destination_id', $transaction) + && !array_key_exists('source_name', $transaction) + && !array_key_exists('destination_name', $transaction) ) { continue; } @@ -189,6 +169,26 @@ trait RecurrenceValidation } } + public function validateRecurringConfig(Validator $validator) + { + $data = $validator->getData(); + $reps = array_key_exists('nr_of_repetitions', $data) ? (int)$data['nr_of_repetitions'] : null; + $repeatUntil = array_key_exists('repeat_until', $data) ? new Carbon($data['repeat_until']) : null; + + if (null === $reps && null === $repeatUntil) { + $validator->errors()->add('nr_of_repetitions', trans('validation.require_repeat_until')); + $validator->errors()->add('repeat_until', trans('validation.require_repeat_until')); + + return; + } + if ($reps > 0 && null !== $repeatUntil) { + $validator->errors()->add('nr_of_repetitions', trans('validation.require_repeat_until')); + $validator->errors()->add('repeat_until', trans('validation.require_repeat_until')); + + return; + } + } + /** * @param Validator $validator */ diff --git a/app/Validation/TransactionValidation.php b/app/Validation/TransactionValidation.php index 28010f45f6..5c04015d40 100644 --- a/app/Validation/TransactionValidation.php +++ b/app/Validation/TransactionValidation.php @@ -61,6 +61,30 @@ trait TransactionValidation } } + /** + * @param Validator $validator + * + * @return array + */ + protected function getTransactionsArray(Validator $validator): array + { + $data = $validator->getData(); + $transactions = $data['transactions'] ?? []; + if (!is_countable($transactions)) { + Log::error(sprintf('Transactions array is not countable, because its a %s', gettype($transactions))); + + return []; + } + // a superfluous check but you never know. + if (!is_array($transactions)) { + Log::error(sprintf('Transactions array is not an array, because its a %s', gettype($transactions))); + + return []; + } + + return $transactions; + } + /** * @param Validator $validator * @param int $index @@ -193,6 +217,40 @@ trait TransactionValidation Log::debug('Done with validateSingleUpdate().'); } + /** + * @param TransactionGroup $group + * @param array $transactions + * + * @return string + */ + private function getTransactionType(TransactionGroup $group, array $transactions): string + { + return $transactions[0]['type'] ?? strtolower($group->transactionJournals()->first()->transactionType->type); + } + + /** + * @param array $transaction + * @param TransactionGroup $transactionGroup + * + * @return Account|null + */ + private function getOriginalSource(array $transaction, TransactionGroup $transactionGroup): ?Account + { + if (1 === $transactionGroup->transactionJournals->count()) { + $journal = $transactionGroup->transactionJournals->first(); + + return $journal->transactions()->where('amount', '<', 0)->first()->account; + } + /** @var TransactionJournal $journal */ + foreach ($transactionGroup->transactionJournals as $journal) { + if ((int)$journal->id === (int)$transaction['transaction_journal_id']) { + return $journal->transactions()->where('amount', '<', 0)->first()->account; + } + } + + return null; + } + /** * Adds an error to the validator when there are no transactions in the array of data. * @@ -209,22 +267,6 @@ trait TransactionValidation } } - /** - * @param Validator $validator - */ - public function validateTransactionArray(Validator $validator): void - { - $transactions = $this->getTransactionsArray($validator); - foreach ($transactions as $key => $value) { - if (!is_int($key)) { - $validator->errors()->add('transactions.0.description', (string)trans('validation.at_least_one_transaction')); - Log::debug('Added error: at_least_one_transaction.'); - - return; - } - } - } - /** * Adds an error to the validator when there are no transactions in the array of data. * @@ -244,6 +286,22 @@ trait TransactionValidation Log::debug('Added NO errors.'); } + /** + * @param Validator $validator + */ + public function validateTransactionArray(Validator $validator): void + { + $transactions = $this->getTransactionsArray($validator); + foreach ($transactions as $key => $value) { + if (!is_int($key)) { + $validator->errors()->add('transactions.0.description', (string)trans('validation.at_least_one_transaction')); + Log::debug('Added error: at_least_one_transaction.'); + + return; + } + } + } + /** * All types of splits must be equal. * @@ -296,48 +354,6 @@ trait TransactionValidation Log::debug('No errors in validateTransactionTypesForUpdate()'); } - /** - * @param array $array - * - * @return bool - */ - private function arrayEqual(array $array): bool - { - return 1 === count(array_unique($array)); - } - - /** - * @param int $journalId - * - * @return array - */ - private function getOriginalData(int $journalId): array - { - $return = [ - 'source_id' => 0, - 'source_name' => '', - 'destination_id' => 0, - 'destination_name' => '', - ]; - if (0 === $journalId) { - return $return; - } - /** @var Transaction $source */ - $source = Transaction::where('transaction_journal_id', $journalId)->where('amount', '<', 0)->with(['account'])->first(); - if (null !== $source) { - $return['source_id'] = $source->account_id; - $return['source_name'] = $source->account->name; - } - /** @var Transaction $destination */ - $destination = Transaction::where('transaction_journal_id', $journalId)->where('amount', '>', 0)->with(['account'])->first(); - if (null !== $source) { - $return['destination_id'] = $destination->account_id; - $return['destination_name'] = $destination->account->name; - } - - return $return; - } - /** * @param int $journalId * @@ -357,30 +373,6 @@ trait TransactionValidation return 'invalid'; } - /** - * @param Validator $validator - * - * @return array - */ - protected function getTransactionsArray(Validator $validator): array - { - $data = $validator->getData(); - $transactions = $data['transactions'] ?? []; - if (!is_countable($transactions)) { - Log::error(sprintf('Transactions array is not countable, because its a %s', gettype($transactions))); - - return []; - } - // a superfluous check but you never know. - if (!is_array($transactions)) { - Log::error(sprintf('Transactions array is not an array, because its a %s', gettype($transactions))); - - return []; - } - - return $transactions; - } - /** * @param Validator $validator */ @@ -423,125 +415,6 @@ trait TransactionValidation } } - /** - * @param TransactionGroup $group - * @param array $transactions - * - * @return string - */ - private function getTransactionType(TransactionGroup $group, array $transactions): string - { - return $transactions[0]['type'] ?? strtolower($group->transactionJournals()->first()->transactionType->type); - } - - /** - * @param array $transactions - * - * @return array - */ - private function collectComparisonData(array $transactions): array - { - $fields = ['source_id', 'destination_id', 'source_name', 'destination_name']; - $comparison = []; - foreach ($fields as $field) { - $comparison[$field] = []; - /** @var array $transaction */ - foreach ($transactions as $transaction) { - // source or destination may be omitted. If this is the case, use the original source / destination name + ID. - $originalData = $this->getOriginalData((int)($transaction['transaction_journal_id'] ?? 0)); - - // get field. - $comparison[$field][] = $transaction[$field] ?? $originalData[$field]; - } - } - - return $comparison; - } - - /** - * @param string $type - * @param array $comparison - * - * @return bool - */ - private function compareAccountData(string $type, array $comparison): bool - { - switch ($type) { - default: - case 'withdrawal': - return $this->compareAccountDataWithdrawal($comparison); - case 'deposit': - return $this->compareAccountDataDeposit($comparison); - case 'transfer': - return $this->compareAccountDataTransfer($comparison); - } - } - - /** - * @param array $comparison - * - * @return bool - */ - private function compareAccountDataTransfer(array $comparison): bool - { - if ($this->arrayEqual($comparison['source_id'])) { - // source ID's are equal, return void. - return true; - } - if ($this->arrayEqual($comparison['source_name'])) { - // source names are equal, return void. - return true; - } - if ($this->arrayEqual($comparison['destination_id'])) { - // destination ID's are equal, return void. - return true; - } - if ($this->arrayEqual($comparison['destination_name'])) { - // destination names are equal, return void. - return true; - } - - return false; - } - - /** - * @param array $comparison - * - * @return bool - */ - private function compareAccountDataWithdrawal(array $comparison): bool - { - if ($this->arrayEqual($comparison['source_id'])) { - // source ID's are equal, return void. - return true; - } - if ($this->arrayEqual($comparison['source_name'])) { - // source names are equal, return void. - return true; - } - - return false; - } - - /** - * @param array $comparison - * - * @return bool - */ - private function compareAccountDataDeposit(array $comparison): bool - { - if ($this->arrayEqual($comparison['destination_id'])) { - // destination ID's are equal, return void. - return true; - } - if ($this->arrayEqual($comparison['destination_name'])) { - // destination names are equal, return void. - return true; - } - - return false; - } - /** * @param Validator $validator * @param TransactionGroup $transactionGroup @@ -584,25 +457,152 @@ trait TransactionValidation } /** - * @param array $transaction - * @param TransactionGroup $transactionGroup + * @param array $transactions * - * @return Account|null + * @return array */ - private function getOriginalSource(array $transaction, TransactionGroup $transactionGroup): ?Account + private function collectComparisonData(array $transactions): array { - if (1 === $transactionGroup->transactionJournals->count()) { - $journal = $transactionGroup->transactionJournals->first(); + $fields = ['source_id', 'destination_id', 'source_name', 'destination_name']; + $comparison = []; + foreach ($fields as $field) { + $comparison[$field] = []; + /** @var array $transaction */ + foreach ($transactions as $transaction) { + // source or destination may be omitted. If this is the case, use the original source / destination name + ID. + $originalData = $this->getOriginalData((int)($transaction['transaction_journal_id'] ?? 0)); - return $journal->transactions()->where('amount', '<', 0)->first()->account; - } - /** @var TransactionJournal $journal */ - foreach ($transactionGroup->transactionJournals as $journal) { - if ((int)$journal->id === (int)$transaction['transaction_journal_id']) { - return $journal->transactions()->where('amount', '<', 0)->first()->account; + // get field. + $comparison[$field][] = $transaction[$field] ?? $originalData[$field]; } } - return null; + return $comparison; + } + + /** + * @param int $journalId + * + * @return array + */ + private function getOriginalData(int $journalId): array + { + $return = [ + 'source_id' => 0, + 'source_name' => '', + 'destination_id' => 0, + 'destination_name' => '', + ]; + if (0 === $journalId) { + return $return; + } + /** @var Transaction $source */ + $source = Transaction::where('transaction_journal_id', $journalId)->where('amount', '<', 0)->with(['account'])->first(); + if (null !== $source) { + $return['source_id'] = $source->account_id; + $return['source_name'] = $source->account->name; + } + /** @var Transaction $destination */ + $destination = Transaction::where('transaction_journal_id', $journalId)->where('amount', '>', 0)->with(['account'])->first(); + if (null !== $source) { + $return['destination_id'] = $destination->account_id; + $return['destination_name'] = $destination->account->name; + } + + return $return; + } + + /** + * @param string $type + * @param array $comparison + * + * @return bool + */ + private function compareAccountData(string $type, array $comparison): bool + { + switch ($type) { + default: + case 'withdrawal': + return $this->compareAccountDataWithdrawal($comparison); + case 'deposit': + return $this->compareAccountDataDeposit($comparison); + case 'transfer': + return $this->compareAccountDataTransfer($comparison); + } + } + + /** + * @param array $comparison + * + * @return bool + */ + private function compareAccountDataWithdrawal(array $comparison): bool + { + if ($this->arrayEqual($comparison['source_id'])) { + // source ID's are equal, return void. + return true; + } + if ($this->arrayEqual($comparison['source_name'])) { + // source names are equal, return void. + return true; + } + + return false; + } + + /** + * @param array $array + * + * @return bool + */ + private function arrayEqual(array $array): bool + { + return 1 === count(array_unique($array)); + } + + /** + * @param array $comparison + * + * @return bool + */ + private function compareAccountDataDeposit(array $comparison): bool + { + if ($this->arrayEqual($comparison['destination_id'])) { + // destination ID's are equal, return void. + return true; + } + if ($this->arrayEqual($comparison['destination_name'])) { + // destination names are equal, return void. + return true; + } + + return false; + } + + /** + * @param array $comparison + * + * @return bool + */ + private function compareAccountDataTransfer(array $comparison): bool + { + if ($this->arrayEqual($comparison['source_id'])) { + // source ID's are equal, return void. + return true; + } + if ($this->arrayEqual($comparison['source_name'])) { + // source names are equal, return void. + return true; + } + if ($this->arrayEqual($comparison['destination_id'])) { + // destination ID's are equal, return void. + return true; + } + if ($this->arrayEqual($comparison['destination_name'])) { + // destination names are equal, return void. + return true; + } + + return false; } } diff --git a/database/factories/FireflyIII/Models/AccountFactory.php b/database/factories/FireflyIII/Models/AccountFactory.php index 0f7d20e7c0..1d3ebf9771 100644 --- a/database/factories/FireflyIII/Models/AccountFactory.php +++ b/database/factories/FireflyIII/Models/AccountFactory.php @@ -39,6 +39,20 @@ class AccountFactory extends Factory */ protected $model = Account::class; + /** + * @return AccountFactory + */ + public function asset() + { + return $this->state( + function () { + return [ + 'account_type_id' => 3, + ]; + } + ); + } + /** * @inheritDoc */ @@ -58,12 +72,12 @@ class AccountFactory extends Factory /** * @return AccountFactory */ - public function asset() + public function expense() { return $this->state( function () { return [ - 'account_type_id' => 3, + 'account_type_id' => 4, ]; } ); @@ -83,19 +97,5 @@ class AccountFactory extends Factory ); } - /** - * @return AccountFactory - */ - public function expense() - { - return $this->state( - function () { - return [ - 'account_type_id' => 4, - ]; - } - ); - } - } diff --git a/database/factories/FireflyIII/Models/TransactionJournalFactory.php b/database/factories/FireflyIII/Models/TransactionJournalFactory.php index ec0e7daf32..20cb16769b 100644 --- a/database/factories/FireflyIII/Models/TransactionJournalFactory.php +++ b/database/factories/FireflyIII/Models/TransactionJournalFactory.php @@ -41,53 +41,7 @@ class TransactionJournalFactory extends Factory protected $model = TransactionJournal::class; /** - * Define the model's default state. - * - * @return array - */ - public function definition() - { - return [ - 'user_id' => 1, - 'transaction_type_id' => 1, - 'description' => $this->faker->words(3, true), - 'tag_count' => 0, - 'date' => $this->faker->date('Y-m-d'), - ]; - } - - /** - * @return \Illuminate\Database\Eloquent\Factories\Factory - */ - public function openingBalance() - { - return $this - ->state(fn () => ['transaction_type_id' => 4]) - ->afterCreating( - function (TransactionJournal $journal) { - // fix factory - $obAccount = Account::factory(Account::class)->initialBalance()->create(); - $assetAccount = Account::factory(Account::class)->asset()->create(); - Transaction::factory()->create( - [ - 'account_id' => $obAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => '5', - ] - ); - Transaction::factory()->create( - [ - 'account_id' => $assetAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => '-5', - ] - ); - } - ); - } - - /** - * @return \Illuminate\Database\Eloquent\Factories\Factory + * @return Factory */ public function brokenOpeningBalance() { @@ -120,4 +74,50 @@ class TransactionJournalFactory extends Factory } ); } + + /** + * Define the model's default state. + * + * @return array + */ + public function definition() + { + return [ + 'user_id' => 1, + 'transaction_type_id' => 1, + 'description' => $this->faker->words(3, true), + 'tag_count' => 0, + 'date' => $this->faker->date('Y-m-d'), + ]; + } + + /** + * @return Factory + */ + public function openingBalance() + { + return $this + ->state(fn() => ['transaction_type_id' => 4]) + ->afterCreating( + function (TransactionJournal $journal) { + // fix factory + $obAccount = Account::factory(Account::class)->initialBalance()->create(); + $assetAccount = Account::factory(Account::class)->asset()->create(); + Transaction::factory()->create( + [ + 'account_id' => $obAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => '5', + ] + ); + Transaction::factory()->create( + [ + 'account_id' => $assetAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => '-5', + ] + ); + } + ); + } } diff --git a/database/seeders/TransactionTypeSeeder.php b/database/seeders/TransactionTypeSeeder.php index 97eb6c19d0..adab1d38c8 100644 --- a/database/seeders/TransactionTypeSeeder.php +++ b/database/seeders/TransactionTypeSeeder.php @@ -39,7 +39,7 @@ class TransactionTypeSeeder extends Seeder TransactionType::TRANSFER, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION, - TransactionType::INVALID + TransactionType::INVALID, ]; foreach ($types as $type) { diff --git a/resources/assets/js/locales/ru.json b/resources/assets/js/locales/ru.json index 5897a8841d..a4f970ce33 100644 --- a/resources/assets/js/locales/ru.json +++ b/resources/assets/js/locales/ru.json @@ -30,7 +30,7 @@ "category": "\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f", "attachments": "\u0412\u043b\u043e\u0436\u0435\u043d\u0438\u044f", "notes": "\u0417\u0430\u043c\u0435\u0442\u043a\u0438", - "external_uri": "External URL", + "external_uri": "\u0412\u043d\u0435\u0448\u043d\u0438\u0439 URL", "update_transaction": "\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e", "after_update_create_another": "\u041f\u043e\u0441\u043b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0435\u0440\u043d\u0438\u0442\u0435\u0441\u044c \u0441\u044e\u0434\u0430, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.", "store_as_new": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a \u043d\u043e\u0432\u0443\u044e \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.", diff --git a/resources/lang/it_IT/validation.php b/resources/lang/it_IT/validation.php index de15e1efb0..89fac7030c 100644 --- a/resources/lang/it_IT/validation.php +++ b/resources/lang/it_IT/validation.php @@ -183,7 +183,7 @@ return [ 'withdrawal_dest_need_data' => 'È necessario ottenere un ID e/o un nome del conto di destinazione validi per continuare.', 'withdrawal_dest_bad_data' => 'Non è stato possibile trovare un conto di destinazione valido effettuando la ricerca con l\'ID ":id" o il nome ":name".', - 'generic_source_bad_data' => 'Could not find a valid source account when searching for ID ":id" or name ":name".', + 'generic_source_bad_data' => 'Non è stato possibile trovare un conto d\'origine valido effettuando la ricerca con l\'ID ":id" o il nome ":name".', 'deposit_source_need_data' => 'È necessario ottenere un ID e/o un nome del conto di origine validi per continuare.', 'deposit_source_bad_data' => 'Non è stato possibile trovare un conto d\'origine valido effettuando la ricerca con l\'ID ":id" o il nome ":name".',