From 949304621207fa3ef912e7ca422db1052cce03b2 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 16 Jul 2022 09:25:10 +0200 Subject: [PATCH] Add strict types, add debug info --- .../Autocomplete/AccountController.php | 3 +- .../Controllers/Chart/AccountController.php | 1 + app/Api/V2/Controllers/Controller.php | 6 + .../Data/Bulk/AccountController.php | 3 +- .../Data/Export/AccountController.php | 3 +- .../Data/MassDestroy/AccountController.php | 3 +- .../Model/Account/ShowController.php | 1 + .../Controllers/Model/Bill/SumController.php | 1 + .../Model/Budget/SumController.php | 1 + app/Api/V2/Controllers/NetWorthController.php | 1 + .../Controllers/Search/AccountController.php | 3 +- .../System/ConfigurationController.php | 3 +- .../V2/Controllers/System/DebugController.php | 3 +- .../System/PreferencesController.php | 1 + .../Transaction/List/AccountController.php | 1 + .../Transaction/Sum/BillController.php | 1 + .../Controllers/VersionUpdateController.php | 3 +- .../V2/Request/Transaction/ListRequest.php | 1 + app/Api/V2/Response/Sum/AutoSum.php | 1 + app/Console/Commands/Tools/Cron.php | 16 +- app/Enums/AccountTypeEnum.php | 3 +- app/Enums/AutoBudgetType.php | 3 +- app/Enums/RecurrenceRepetitionWeekend.php | 3 +- app/Enums/TransactionTypeEnum.php | 3 +- app/Enums/UserRoleEnum.php | 3 +- app/Enums/WebhookDelivery.php | 3 +- app/Enums/WebhookResponse.php | 3 +- app/Enums/WebhookTrigger.php | 3 +- app/Exceptions/BadHttpHeaderException.php | 3 +- app/Http/Middleware/AcceptHeaders.php | 3 +- app/Jobs/DownloadExchangeRates.php | 4 +- app/Support/Cronjobs/ExchangeRatesCronjob.php | 4 +- .../Http/Api/ConvertsExchangeRates.php | 1 + app/Transformers/V2/AbstractTransformer.php | 7 + app/Transformers/V2/AccountTransformer.php | 1 + .../V2/TransactionGroupTransformer.php | 203 +++++++++++++----- config/cer.php | 1 + database/seeders/ExchangeRateSeeder.php | 1 + 38 files changed, 222 insertions(+), 86 deletions(-) diff --git a/app/Api/V2/Controllers/Autocomplete/AccountController.php b/app/Api/V2/Controllers/Autocomplete/AccountController.php index 1e35e7463a..6876d9a65d 100644 --- a/app/Api/V2/Controllers/Autocomplete/AccountController.php +++ b/app/Api/V2/Controllers/Autocomplete/AccountController.php @@ -1,4 +1,5 @@ setSerializer(new JsonApiSerializer($baseUrl)); $objects = $paginator->getCollection(); + + // the transformer, at this point, needs to collect information that ALL items in the collection + // require, like meta data and stuff like that, and save it for later. + $transformer->collectMetaData($objects); + $resource = new FractalCollection($objects, $transformer, $key); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); diff --git a/app/Api/V2/Controllers/Data/Bulk/AccountController.php b/app/Api/V2/Controllers/Data/Bulk/AccountController.php index 2307ab3856..0c190f34d2 100644 --- a/app/Api/V2/Controllers/Data/Bulk/AccountController.php +++ b/app/Api/V2/Controllers/Data/Bulk/AccountController.php @@ -1,4 +1,5 @@ error(sprintf('Error in "create recurring transactions" cron: %s', $recurring->message)); } if ($recurring->jobFired) { - $this->error(sprintf('"Create recurring transactions" cron fired: %s', $recurring->message)); + $this->line(sprintf('"Create recurring transactions" cron fired: %s', $recurring->message)); } if ($recurring->jobSucceeded) { - $this->error(sprintf('"Create recurring transactions" cron ran with success: %s', $recurring->message)); + $this->info(sprintf('"Create recurring transactions" cron ran with success: %s', $recurring->message)); } } @@ -169,10 +169,10 @@ class Cron extends Command $this->error(sprintf('Error in "create auto budgets" cron: %s', $autoBudget->message)); } if ($autoBudget->jobFired) { - $this->error(sprintf('"Create auto budgets" cron fired: %s', $autoBudget->message)); + $this->line(sprintf('"Create auto budgets" cron fired: %s', $autoBudget->message)); } if ($autoBudget->jobSucceeded) { - $this->error(sprintf('"Create auto budgets" cron ran with success: %s', $autoBudget->message)); + $this->info(sprintf('"Create auto budgets" cron ran with success: %s', $autoBudget->message)); } } @@ -197,10 +197,10 @@ class Cron extends Command $this->error(sprintf('Error in "bill warnings" cron: %s', $autoBudget->message)); } if ($autoBudget->jobFired) { - $this->error(sprintf('"Send bill warnings" cron fired: %s', $autoBudget->message)); + $this->line(sprintf('"Send bill warnings" cron fired: %s', $autoBudget->message)); } if ($autoBudget->jobSucceeded) { - $this->error(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message)); + $this->info(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message)); } } @@ -225,10 +225,10 @@ class Cron extends Command $this->error(sprintf('Error in "exchange rates" cron: %s', $exchangeRates->message)); } if ($exchangeRates->jobFired) { - $this->error(sprintf('"Exchange rates" cron fired: %s', $exchangeRates->message)); + $this->line(sprintf('"Exchange rates" cron fired: %s', $exchangeRates->message)); } if ($exchangeRates->jobSucceeded) { - $this->error(sprintf('"Exchange rates" cron ran with success: %s', $exchangeRates->message)); + $this->info(sprintf('"Exchange rates" cron ran with success: %s', $exchangeRates->message)); } } diff --git a/app/Enums/AccountTypeEnum.php b/app/Enums/AccountTypeEnum.php index 48ea7741fd..e0e29da27a 100644 --- a/app/Enums/AccountTypeEnum.php +++ b/app/Enums/AccountTypeEnum.php @@ -1,4 +1,5 @@ repository->get(); /** @var TransactionCurrency $currency */ @@ -108,7 +110,7 @@ class DownloadExchangeRates implements ShouldQueue $res = $client->get($url); $statusCode = $res->getStatusCode(); if (200 !== $statusCode) { - Log::warning(sprintf('Trying to grab "%s" resulted in %d.', $url, $statusCode)); + Log::warning(sprintf('Trying to grab "%s" resulted in status code %d.', $url, $statusCode)); return; } $body = (string) $res->getBody(); diff --git a/app/Support/Cronjobs/ExchangeRatesCronjob.php b/app/Support/Cronjobs/ExchangeRatesCronjob.php index 18d67b896f..5d76db6354 100644 --- a/app/Support/Cronjobs/ExchangeRatesCronjob.php +++ b/app/Support/Cronjobs/ExchangeRatesCronjob.php @@ -68,14 +68,14 @@ class ExchangeRatesCronjob extends AbstractCronjob Log::info(sprintf('It has been %s since the exchange rates cron-job has fired. It will fire now!', $diffForHumans)); } - $this->fireAutoBudget(); + $this->fireExchangeRateJob(); app('preferences')->mark(); } /** * */ - private function fireAutoBudget(): void + private function fireExchangeRateJob(): void { Log::info(sprintf('Will now fire exchange rates cron job task for date "%s".', $this->date->format('Y-m-d'))); /** @var DownloadExchangeRates $job */ diff --git a/app/Support/Http/Api/ConvertsExchangeRates.php b/app/Support/Http/Api/ConvertsExchangeRates.php index 7a773bcf9d..e788765735 100644 --- a/app/Support/Http/Api/ConvertsExchangeRates.php +++ b/app/Support/Http/Api/ConvertsExchangeRates.php @@ -1,4 +1,5 @@ stringFromArray($transaction, 'transaction_type_type', TransactionType::WITHDRAWAL); - $amount = app('steam')->positive((string) ($row['amount'] ?? '0')); - $foreignAmount = null; + $transaction = new NullArrayObject($transaction); + $journalId = (int) $transaction['transaction_journal_id']; + $meta = new NullArrayObject($this->meta[$journalId] ?? []); + $type = $this->stringFromArray($transaction, 'transaction_type_type', TransactionType::WITHDRAWAL); + $amount = app('steam')->positive((string) ($transaction['amount'] ?? '0')); + $foreignAmount = null; + $foreignNativeAmount = null; if (null !== $transaction['foreign_amount']) { - $foreignAmount = app('steam')->positive($transaction['foreign_amount']); + $foreignAmount = app('steam')->positive($transaction['foreign_amount']); + $foreignNativeAmount = $foreignAmount; + if ($transaction['foreign_currency_id'] !== $this->default->id) { + $rate = $this->getRate($this->currencies[$transaction['foreign_currency_id']], $this->default, $transaction['date']); + $foreignNativeAmount = bcmul($foreignAmount, $rate); + } + } + + $nativeAmount = $amount; + if ($transaction['currency_id'] !== $this->default->id) { + $rate = $this->getRate($this->currencies[$transaction['currency_id']], $this->default, $transaction['date']); + $nativeAmount = bcmul($amount, $rate); } return [ - 'user' => (string) $transaction['user_id'], - 'transaction_journal_id' => (string) $transaction['transaction_journal_id'], - 'type' => strtolower($type), - 'date' => $transaction['date']->toAtomString(), - 'order' => $transaction['order'], - 'currency_id' => (string) $transaction['currency_id'], - 'currency_code' => $transaction['currency_code'], - 'currency_name' => $transaction['currency_name'], - 'currency_symbol' => $transaction['currency_symbol'], - 'currency_decimal_places' => (int) $transaction['currency_decimal_places'], + 'user' => (string) $transaction['user_id'], + 'transaction_journal_id' => (string) $transaction['transaction_journal_id'], + 'type' => strtolower($type), + 'date' => $transaction['date']->toAtomString(), + 'order' => $transaction['order'], + 'currency_id' => (string) $transaction['currency_id'], + 'currency_code' => $transaction['currency_code'], + 'currency_name' => $transaction['currency_name'], + 'currency_symbol' => $transaction['currency_symbol'], + 'currency_decimal_places' => (int) $transaction['currency_decimal_places'], + + // converted to native currency + 'native_currency_converted' => $transaction['currency_id'] !== $this->default->id, + 'native_currency_id' => (string) $this->default->id, + 'native_currency_code' => $this->default->code, + 'native_currency_name' => $this->default->name, + 'native_currency_symbol' => $this->default->symbol, + 'native_currency_decimal_places' => (int) $this->default->decimal_places, + 'foreign_currency_id' => $this->stringFromArray($transaction, 'foreign_currency_id', null), 'foreign_currency_code' => $transaction['foreign_currency_code'], + 'foreign_currency_name' => $transaction['foreign_currency_name'], 'foreign_currency_symbol' => $transaction['foreign_currency_symbol'], 'foreign_currency_decimal_places' => $transaction['foreign_currency_decimal_places'], - 'amount' => $amount, - 'foreign_amount' => $foreignAmount, - 'description' => $transaction['description'], - 'source_id' => (string) $transaction['source_account_id'], - 'source_name' => $transaction['source_account_name'], - 'source_iban' => $transaction['source_account_iban'], - 'source_type' => $transaction['source_account_type'], - 'destination_id' => (string) $transaction['destination_account_id'], - 'destination_name' => $transaction['destination_account_name'], - 'destination_iban' => $transaction['destination_account_iban'], - 'destination_type' => $transaction['destination_account_type'], - 'budget_id' => $this->stringFromArray($transaction, 'budget_id', null), - 'budget_name' => $transaction['budget_name'], - 'category_id' => $this->stringFromArray($transaction, 'category_id', null), - 'category_name' => $transaction['category_name'], - 'bill_id' => $this->stringFromArray($transaction, 'bill_id', null), - 'bill_name' => $transaction['bill_name'], - 'reconciled' => $transaction['reconciled'], + + // foreign converted to native currency: + 'foreign_currency_converted' => null !== $transaction['foreign_currency_id'] && $transaction['foreign_currency_id'] !== $this->default->id, + + 'amount' => $amount, + 'native_amount' => $nativeAmount, + 'foreign_amount' => $foreignAmount, + 'foreign_native_amount' => $foreignNativeAmount, + 'description' => $transaction['description'], + 'source_id' => (string) $transaction['source_account_id'], + 'source_name' => $transaction['source_account_name'], + 'source_iban' => $transaction['source_account_iban'], + 'source_type' => $transaction['source_account_type'], + 'destination_id' => (string) $transaction['destination_account_id'], + 'destination_name' => $transaction['destination_account_name'], + 'destination_iban' => $transaction['destination_account_iban'], + 'destination_type' => $transaction['destination_account_type'], + 'budget_id' => $this->stringFromArray($transaction, 'budget_id', null), + 'budget_name' => $transaction['budget_name'], + 'category_id' => $this->stringFromArray($transaction, 'category_id', null), + 'category_name' => $transaction['category_name'], + 'bill_id' => $this->stringFromArray($transaction, 'bill_id', null), + 'bill_name' => $transaction['bill_name'], + 'reconciled' => $transaction['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_url' => $metaFieldData['external_url'], - // 'import_hash_v2' => $metaFieldData['import_hash_v2'], + 'internal_reference' => $meta['internal_reference'], + 'external_id' => $meta['external_id'], + 'original_source' => $meta['original_source'], + 'recurrence_id' => $meta['recurrence_id'], + 'recurrence_total' => $meta['recurrence_total'], + 'recurrence_count' => $meta['recurrence_count'], + 'bunq_payment_id' => $meta['bunq_payment_id'], + 'external_url' => $meta['external_url'], + 'import_hash_v2' => $meta['import_hash_v2'], + 'sepa_cc' => $meta['sepa_cc'], + 'sepa_ct_op' => $meta['sepa_ct_op'], + 'sepa_ct_id' => $meta['sepa_ct_id'], + 'sepa_db' => $meta['sepa_db'], + 'sepa_country' => $meta['sepa_country'], + 'sepa_ep' => $meta['sepa_ep'], + 'sepa_ci' => $meta['sepa_ci'], + 'sepa_batch_id' => $meta['sepa_batch_id'], - // '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'), + 'interest_date' => $this->date($meta['interest_date']), + 'book_date' => $this->date($meta['book_date']), + 'process_date' => $this->date($meta['process_date']), + 'due_date' => $this->date($meta['due_date']), + 'payment_date' => $this->date($meta['payment_date']), + 'invoice_date' => $this->date($meta['invoice_date']), // location data // 'longitude' => $longitude, @@ -174,4 +217,50 @@ class TransactionGroupTransformer extends AbstractTransformer return null; } + /** + * @inheritDoc + */ + public function collectMetaData(Collection $objects): void + { + // start with currencies: + $currencies = []; + $journals = []; + /** @var array $object */ + foreach ($objects as $object) { + foreach ($object['sums'] as $sum) { + $id = $sum['currency_id']; + if (!array_key_exists($id, $currencies)) { + $currencyObject = TransactionCurrency::find($sum['currency_id']); + $currencies[$id] = $currencyObject; + } + } + /** @var array $transaction */ + foreach ($object['transactions'] as $transaction) { + $id = $transaction['transaction_journal_id']; + $journals[$id] = []; + } + } + $this->currencies = $currencies; + $this->default = app('amount')->getDefaultCurrency(); + + // grab meta for all journals: + $meta = TransactionJournalMeta::whereIn('transaction_journal_id', array_keys($journals))->get(); + /** @var TransactionJournalMeta $entry */ + foreach ($meta as $entry) { + $id = (int) $entry->transaction_journal_id; + $this->meta[$id][$entry->name] = $entry->data; + } + } + + /** + * @param string|null $string + * @return Carbon|null + */ + private function date(?string $string): ?Carbon + { + if(null === $string) { + return null; + } + return Carbon::createFromFormat('Y-m-d', $string); + } } diff --git a/config/cer.php b/config/cer.php index 4614277cdb..6580378fb5 100644 --- a/config/cer.php +++ b/config/cer.php @@ -1,4 +1,5 @@