Merge pull request #4 from firefly-iii/develop

Get last commits
This commit is contained in:
HamuZ HamuZ 2018-09-09 13:25:06 +03:00 committed by GitHub
commit c83d93971f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
423 changed files with 8235 additions and 1932 deletions

View File

@ -15,7 +15,7 @@ APP_KEY=${FF_APP_KEY}
# Change this value to your preferred time zone.
# Example: Europe/Amsterdam
TZ=UTC
TZ=${TZ}
# This variable must match your installation's external address but keep in mind that
# it's only used on the command line as a fallback value.

View File

@ -15,7 +15,7 @@ APP_KEY=SomeRandomStringOf32CharsExactly
# Change this value to your preferred time zone.
# Example: Europe/Amsterdam
TZ=${TZ}
TZ=Europe/Amsterdam
# This variable must match your installation's external address but keep in mind that
# it's only used on the command line as a fallback value.

View File

@ -22,7 +22,7 @@ TZ=UTC
APP_URL=http://localhost
# TRUSTED_PROXIES is a useful variable when using Docker and/or a reverse proxy.
TRUSTED_PROXIES=
TRUSTED_PROXIES=**
# The log channel defines where your log entries go to.
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.

View File

@ -34,7 +34,7 @@ LOG_CHANNEL=dailytest
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=debug
APP_LOG_LEVEL=info
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# For other database types, please see the FAQ: http://firefly-iii.readthedocs.io/en/latest/support/faq.html

View File

@ -1,3 +1,55 @@
# 4.7.6.2
- Docker file builds again.
- Fix CSS of OAuth2 authorization view.
# 4.7.6.1
- An issue where I switched variables from the Docker `.env` file to the normal `.env` file and vice versa -- breaking both.
- [Issue 1649](https://github.com/firefly-iii/firefly-iii/issues/1649) 2FA QR code would not show up due to very strict security policy headers
- Docker build gave a cURL error whenever it runs PHP commands.
# 4.7.6
- [Issue 145](https://github.com/firefly-iii/firefly-iii/issues/145) You can now download transactions from YNAB.
- [Issue 306](https://github.com/firefly-iii/firefly-iii/issues/306) You can now add liabilities to Firefly III.
- [Issue 740](https://github.com/firefly-iii/firefly-iii/issues/740) Various charts are now currency aware.
- [Issue 833](https://github.com/firefly-iii/firefly-iii/issues/833) Bills can use non-default currencies.
- [Issue 1578](https://github.com/firefly-iii/firefly-iii/issues/1578) Firefly III will notify you if the cron job hasn't fired.
- [Issue 1623](https://github.com/firefly-iii/firefly-iii/issues/1623) New transactions will link back from the success message.
- [Issue 1624](https://github.com/firefly-iii/firefly-iii/issues/1624) transactions will link to the object.
- You can call the cron job over the web now (see docs).
- You don't need to call the cron job every minute any more.
- Various charts are now red/green to signify income and expenses.
- Option to add or remove accounts from the net worth calculations.
- This will be the last release on PHP 7.1. Future versions will require PHP 7.2.
- [Issue 1460](https://github.com/firefly-iii/firefly-iii/issues/1460) Downloading transactions from bunq should go more smoothly.
- [Issue 1464](https://github.com/firefly-iii/firefly-iii/issues/1464) Fixed the docker file to work on Raspberry Pi's.
- [Issue 1540](https://github.com/firefly-iii/firefly-iii/issues/1540) The Docker file now has a working cron job for recurring transactions.
- [Issue 1564](https://github.com/firefly-iii/firefly-iii/issues/1564) Fix double transfers when importing from bunq.
- [Issue 1575](https://github.com/firefly-iii/firefly-iii/issues/1575) Some views would give a XSRF token warning
- [Issue 1576](https://github.com/firefly-iii/firefly-iii/issues/1576) Fix assigning budgets
- [Issue 1580](https://github.com/firefly-iii/firefly-iii/issues/1580) Missing string for translation
- [Issue 1581](https://github.com/firefly-iii/firefly-iii/issues/1581) Expand help text
- [Issue 1584](https://github.com/firefly-iii/firefly-iii/issues/1584) Link to administration is back.
- [Issue 1586](https://github.com/firefly-iii/firefly-iii/issues/1586) Date fields in import were mislabeled.
- [Issue 1593](https://github.com/firefly-iii/firefly-iii/issues/1593) Link types are translatable.
- [Issue 1594](https://github.com/firefly-iii/firefly-iii/issues/1594) Very long breadcrumbs are weird.
- [Issue 1598](https://github.com/firefly-iii/firefly-iii/issues/1598) Fix budget calculations.
- [Issue 1597](https://github.com/firefly-iii/firefly-iii/issues/1597) Piggy banks are always inactive.
- [Issue 1605](https://github.com/firefly-iii/firefly-iii/issues/1605) System will ignore foreign currency setting if user doesn't indicate the amount.
- [Issue 1608](https://github.com/firefly-iii/firefly-iii/issues/1608) Spelling error in command line import.
- [Issue 1609](https://github.com/firefly-iii/firefly-iii/issues/1609) Link to budgets page was absolute.
- [Issue 1615](https://github.com/firefly-iii/firefly-iii/issues/1615) Fix currency bug in transactions.
- [Issue 1616](https://github.com/firefly-iii/firefly-iii/issues/1616) Fix null pointer exception in pie charts.
- [Issue 1617](https://github.com/firefly-iii/firefly-iii/issues/1617) Fix for complex tag names in URL's.
- [Issue 1620](https://github.com/firefly-iii/firefly-iii/issues/1620) Fixed index reference in API.
- [Issue 1639](https://github.com/firefly-iii/firefly-iii/issues/1639) Firefly III trusts the Heroku load balancer, fixing deployment on Heroku.
- [Issue 1642](https://github.com/firefly-iii/firefly-iii/issues/1642) Fix issue with split journals.
- [Issue 1643](https://github.com/firefly-iii/firefly-iii/issues/1643) Fix reconciliation issue.
- Users can no longer give income a budget.
- Fix bug in Spectre import.
- Heroku would not make you owner.
- Add `.htaccess` files to all public directories.
- New secure headers will make Firefly III slightly more secure.
# 4.7.5.3
- [Issue 1527](https://github.com/firefly-iii/firefly-iii/issues/1527), fixed views for transactions without a budget.
- [Issue 1553](https://github.com/firefly-iii/firefly-iii/issues/1553), report could not handle transactions before the first one in the system.

View File

@ -272,8 +272,10 @@ opt/app/app/Api/V1/Requests/RuleGroupRequest.php
opt/app/app/Api/V1/Requests/RuleRequest.php
opt/app/app/Api/V1/Requests/TransactionRequest.php
opt/app/app/Api/V1/Requests/UserRequest.php
opt/app/app/Console/Commands
opt/app/app/Console/Commands/CreateExport.php
opt/app/app/Console/Commands/CreateImport.php
opt/app/app/Console/Commands/Cron.php
opt/app/app/Console/Commands/DecryptAttachment.php
opt/app/app/Console/Commands/EncryptFile.php
opt/app/app/Console/Commands/Import.php
@ -363,8 +365,8 @@ opt/app/app/Helpers/Collection/BalanceLine.php
opt/app/app/Helpers/Collection/Bill.php
opt/app/app/Helpers/Collection/BillLine.php
opt/app/app/Helpers/Collection/Category.php
opt/app/app/Helpers/Collector/JournalCollector.php
opt/app/app/Helpers/Collector/JournalCollectorInterface.php
opt/app/app/Helpers/Collector/TransactionCollector.php
opt/app/app/Helpers/Collector/TransactionCollectorInterface.php
opt/app/app/Helpers/Filter/AmountFilter.php
opt/app/app/Helpers/Filter/CountAttachmentsFilter.php
opt/app/app/Helpers/Filter/EmptyFilter.php
@ -384,6 +386,8 @@ opt/app/app/Helpers/Report/BalanceReportHelper.php
opt/app/app/Helpers/Report/BalanceReportHelperInterface.php
opt/app/app/Helpers/Report/BudgetReportHelper.php
opt/app/app/Helpers/Report/BudgetReportHelperInterface.php
opt/app/app/Helpers/Report/NetWorth.php
opt/app/app/Helpers/Report/NetWorthInterface.php
opt/app/app/Helpers/Report/PopupReport.php
opt/app/app/Helpers/Report/PopupReportInterface.php
opt/app/app/Helpers/Report/ReportHelper.php
@ -432,6 +436,7 @@ opt/app/app/Http/Controllers/DebugController.php
opt/app/app/Http/Controllers/ExportController.php
opt/app/app/Http/Controllers/HelpController.php
opt/app/app/Http/Controllers/HomeController.php
opt/app/app/Http/Controllers/Import/CallbackController.php
opt/app/app/Http/Controllers/Import/IndexController.php
opt/app/app/Http/Controllers/Import/JobConfigurationController.php
opt/app/app/Http/Controllers/Import/JobStatusController.php
@ -468,6 +473,7 @@ opt/app/app/Http/Controllers/Rule/IndexController.php
opt/app/app/Http/Controllers/Rule/SelectController.php
opt/app/app/Http/Controllers/RuleGroupController.php
opt/app/app/Http/Controllers/SearchController.php
opt/app/app/Http/Controllers/System/CronController.php
opt/app/app/Http/Controllers/System/InstallController.php
opt/app/app/Http/Controllers/TagController.php
opt/app/app/Http/Controllers/Transaction/BulkController.php
@ -490,6 +496,7 @@ opt/app/app/Http/Middleware/Range.php
opt/app/app/Http/Middleware/RedirectIfAuthenticated.php
opt/app/app/Http/Middleware/RedirectIfTwoFactorAuthenticated.php
opt/app/app/Http/Middleware/Sandstorm.php
opt/app/app/Http/Middleware/SecureHeaders.php
opt/app/app/Http/Middleware/StartFireflySession.php
opt/app/app/Http/Middleware/TrimStrings.php
opt/app/app/Http/Middleware/TrustProxies.php
@ -539,6 +546,7 @@ opt/app/app/Import/JobConfiguration/FakeJobConfiguration.php
opt/app/app/Import/JobConfiguration/FileJobConfiguration.php
opt/app/app/Import/JobConfiguration/JobConfigurationInterface.php
opt/app/app/Import/JobConfiguration/SpectreJobConfiguration.php
opt/app/app/Import/JobConfiguration/YnabJobConfiguration.php
opt/app/app/Import/Mapper/AssetAccountIbans.php
opt/app/app/Import/Mapper/AssetAccounts.php
opt/app/app/Import/Mapper/Bills.php
@ -557,11 +565,13 @@ opt/app/app/Import/Prerequisites/FakePrerequisites.php
opt/app/app/Import/Prerequisites/FilePrerequisites.php
opt/app/app/Import/Prerequisites/PrerequisitesInterface.php
opt/app/app/Import/Prerequisites/SpectrePrerequisites.php
opt/app/app/Import/Prerequisites/YnabPrerequisites.php
opt/app/app/Import/Routine/BunqRoutine.php
opt/app/app/Import/Routine/FakeRoutine.php
opt/app/app/Import/Routine/FileRoutine.php
opt/app/app/Import/Routine/RoutineInterface.php
opt/app/app/Import/Routine/SpectreRoutine.php
opt/app/app/Import/Routine/YnabRoutine.php
opt/app/app/Import/Specifics/AbnAmroDescription.php
opt/app/app/Import/Specifics/IngDescription.php
opt/app/app/Import/Specifics/PresidentsChoice.php
@ -734,10 +744,15 @@ opt/app/app/Services/Spectre/Request/ListLoginsRequest.php
opt/app/app/Services/Spectre/Request/ListTransactionsRequest.php
opt/app/app/Services/Spectre/Request/NewCustomerRequest.php
opt/app/app/Services/Spectre/Request/SpectreRequest.php
opt/app/app/Services/Ynab/Request/GetAccountsRequest.php
opt/app/app/Services/Ynab/Request/GetBudgetsRequest.php
opt/app/app/Services/Ynab/Request/GetTransactionsRequest.php
opt/app/app/Services/Ynab/Request/YnabRequest.php
opt/app/app/Support/Amount.php
opt/app/app/Support/Binder/AccountList.php
opt/app/app/Support/Binder/BinderInterface.php
opt/app/app/Support/Binder/BudgetList.php
opt/app/app/Support/Binder/CLIToken.php
opt/app/app/Support/Binder/CategoryList.php
opt/app/app/Support/Binder/CurrencyCode.php
opt/app/app/Support/Binder/Date.php
@ -748,6 +763,8 @@ opt/app/app/Support/Binder/TagList.php
opt/app/app/Support/Binder/UnfinishedJournal.php
opt/app/app/Support/CacheProperties.php
opt/app/app/Support/ChartColour.php
opt/app/app/Support/Cronjobs/AbstractCronjob.php
opt/app/app/Support/Cronjobs/RecurringCronjob.php
opt/app/app/Support/Domain.php
opt/app/app/Support/ExpandedForm.php
opt/app/app/Support/Facades/Amount.php
@ -757,8 +774,18 @@ opt/app/app/Support/Facades/Navigation.php
opt/app/app/Support/Facades/Preferences.php
opt/app/app/Support/Facades/Steam.php
opt/app/app/Support/FireflyConfig.php
opt/app/app/Support/Http/Controllers/AugumentData.php
opt/app/app/Support/Http/Controllers/BasicDataSupport.php
opt/app/app/Support/Http/Controllers/CreateStuff.php
opt/app/app/Support/Http/Controllers/DateCalculation.php
opt/app/app/Support/Http/Controllers/GetConfigurationData.php
opt/app/app/Support/Http/Controllers/ModelInformation.php
opt/app/app/Support/Http/Controllers/PeriodOverview.php
opt/app/app/Support/Http/Controllers/RenderPartialViews.php
opt/app/app/Support/Http/Controllers/RequestInformation.php
opt/app/app/Support/Http/Controllers/RuleManagement.php
opt/app/app/Support/Http/Controllers/TransactionCalculation.php
opt/app/app/Support/Http/Controllers/UserNavigation.php
opt/app/app/Support/Import/Information/GetSpectreCustomerTrait.php
opt/app/app/Support/Import/Information/GetSpectreTokenTrait.php
opt/app/app/Support/Import/JobConfiguration/Bunq/BunqJobConfigurationInterface.php
@ -775,6 +802,10 @@ opt/app/app/Support/Import/JobConfiguration/Spectre/ChooseLoginHandler.php
opt/app/app/Support/Import/JobConfiguration/Spectre/DoAuthenticateHandler.php
opt/app/app/Support/Import/JobConfiguration/Spectre/NewSpectreJobHandler.php
opt/app/app/Support/Import/JobConfiguration/Spectre/SpectreJobConfigurationInterface.php
opt/app/app/Support/Import/JobConfiguration/Ynab/NewYnabJobHandler.php
opt/app/app/Support/Import/JobConfiguration/Ynab/SelectAccountsHandler.php
opt/app/app/Support/Import/JobConfiguration/Ynab/SelectBudgetHandler.php
opt/app/app/Support/Import/JobConfiguration/Ynab/YnabJobConfigurationInterface.php
opt/app/app/Support/Import/Placeholder/ColumnValue.php
opt/app/app/Support/Import/Placeholder/ImportTransaction.php
opt/app/app/Support/Import/Routine/Bunq/StageImportDataHandler.php
@ -795,6 +826,12 @@ opt/app/app/Support/Import/Routine/File/OpposingAccountMapper.php
opt/app/app/Support/Import/Routine/Spectre/StageAuthenticatedHandler.php
opt/app/app/Support/Import/Routine/Spectre/StageImportDataHandler.php
opt/app/app/Support/Import/Routine/Spectre/StageNewHandler.php
opt/app/app/Support/Import/Routine/Ynab/GetAccountsHandler.php
opt/app/app/Support/Import/Routine/Ynab/ImportDataHandler.php
opt/app/app/Support/Import/Routine/Ynab/StageGetAccessHandler.php
opt/app/app/Support/Import/Routine/Ynab/StageGetBudgetsHandler.php
opt/app/app/Support/Import/Routine/Ynab/StageGetTransactionsHandler.php
opt/app/app/Support/Import/Routine/Ynab/StageMatchAccountsHandler.php
opt/app/app/Support/Navigation.php
opt/app/app/Support/Preferences.php
opt/app/app/Support/Search/Modifier.php
@ -928,6 +965,7 @@ opt/app/config/twigbridge.php
opt/app/config/upgrade.php
opt/app/config/view.php
opt/app/database/factories/ModelFactory.php
opt/app/database/migrations
opt/app/database/migrations/2016_06_16_000000_create_support_tables.php
opt/app/database/migrations/2016_06_16_000001_create_users_table.php
opt/app/database/migrations/2016_06_16_000002_create_main_tables.php
@ -967,13 +1005,15 @@ opt/app/public/android-chrome-192x192.png
opt/app/public/android-chrome-512x512.png
opt/app/public/apple-touch-icon.png
opt/app/public/browserconfig.xml
opt/app/public/css/app.css
opt/app/public/css/.htaccess
opt/app/public/css/bootstrap-multiselect.css
opt/app/public/css/bootstrap-sortable.css
opt/app/public/css/bootstrap-tagsinput.css
opt/app/public/css/daterangepicker.css
opt/app/public/css/firefly.css
opt/app/public/css/google-fonts.css
opt/app/public/css/jquery-ui/.htaccess
opt/app/public/css/jquery-ui/images/.htaccess
opt/app/public/css/jquery-ui/images/ui-icons_444444_256x240.png
opt/app/public/css/jquery-ui/images/ui-icons_555555_256x240.png
opt/app/public/css/jquery-ui/images/ui-icons_777620_256x240.png
@ -985,6 +1025,7 @@ opt/app/public/css/jquery-ui/jquery-ui.theme.min.css
opt/app/public/favicon-16x16.png
opt/app/public/favicon-32x32.png
opt/app/public/favicon.ico
opt/app/public/fonts/.htaccess
opt/app/public/fonts/SourceSansPro-Bold-cyrillic-ext.woff
opt/app/public/fonts/SourceSansPro-Bold-cyrillic-ext.woff2
opt/app/public/fonts/SourceSansPro-Bold-cyrillic.woff
@ -1101,20 +1142,37 @@ opt/app/public/fonts/lato-100.woff
opt/app/public/fonts/lato-100.woff2
opt/app/public/fonts/roboto-light-300.woff
opt/app/public/fonts/roboto-light-300.woff2
opt/app/public/fonts/vendor/.htaccess
opt/app/public/fonts/vendor/bootstrap-sass/.htaccess
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/.htaccess
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.eot
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.svg
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.ttf
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.woff
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.woff2
opt/app/public/fonts/vendor/font-awesome/.htaccess
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.eot
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.svg
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.ttf
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.woff
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.woff2
opt/app/public/images/.htaccess
opt/app/public/images/error.png
opt/app/public/images/flags/.htaccess
opt/app/public/images/flags/de_DE.png
opt/app/public/images/flags/es_ES.png
opt/app/public/images/flags/fr_FR.png
opt/app/public/images/flags/id_ID.png
opt/app/public/images/flags/it_IT.png
opt/app/public/images/flags/nl_NL.png
opt/app/public/images/flags/pl_PL.png
opt/app/public/images/flags/pt_BR.png
opt/app/public/images/flags/ru_RU.png
opt/app/public/images/flags/tr_TR.png
opt/app/public/images/image.png
opt/app/public/images/loading-small.gif
opt/app/public/images/loading-wide.gif
opt/app/public/images/logos/.htaccess
opt/app/public/images/logos/bunq.png
opt/app/public/images/logos/csv.png
opt/app/public/images/logos/fake.png
@ -1122,37 +1180,52 @@ opt/app/public/images/logos/file.png
opt/app/public/images/logos/plaid.png
opt/app/public/images/logos/quovo.png
opt/app/public/images/logos/spectre.png
opt/app/public/images/logos/ynab.png
opt/app/public/images/logos/yodlee.png
opt/app/public/images/page_green.png
opt/app/public/images/page_white_acrobat.png
opt/app/public/index.php
opt/app/public/js/.htaccess
opt/app/public/js/app.js
opt/app/public/js/ff/.htaccess
opt/app/public/js/ff/accounts/.htaccess
opt/app/public/js/ff/accounts/create.js
opt/app/public/js/ff/accounts/edit-reconciliation.js
opt/app/public/js/ff/accounts/edit.js
opt/app/public/js/ff/accounts/reconcile.js
opt/app/public/js/ff/accounts/show.js
opt/app/public/js/ff/admin/.htaccess
opt/app/public/js/ff/admin/update/.htaccess
opt/app/public/js/ff/admin/update/index.js
opt/app/public/js/ff/bills/.htaccess
opt/app/public/js/ff/bills/create.js
opt/app/public/js/ff/bills/edit.js
opt/app/public/js/ff/bills/show.js
opt/app/public/js/ff/budgets/.htaccess
opt/app/public/js/ff/budgets/index.js
opt/app/public/js/ff/budgets/show.js
opt/app/public/js/ff/categories/.htaccess
opt/app/public/js/ff/categories/index.js
opt/app/public/js/ff/categories/show-by-date.js
opt/app/public/js/ff/categories/show.js
opt/app/public/js/ff/charts.defaults.js
opt/app/public/js/ff/charts.js
opt/app/public/js/ff/export/.htaccess
opt/app/public/js/ff/export/index.js
opt/app/public/js/ff/firefly.js
opt/app/public/js/ff/guest.js
opt/app/public/js/ff/help.js
opt/app/public/js/ff/import/.htaccess
opt/app/public/js/ff/import/file/.htaccess
opt/app/public/js/ff/import/file/configure-upload.js
opt/app/public/js/ff/import/status.js
opt/app/public/js/ff/import/status_v2.js
opt/app/public/js/ff/index.js
opt/app/public/js/ff/install/.htaccess
opt/app/public/js/ff/install/index.js
opt/app/public/js/ff/intro/.htaccess
opt/app/public/js/ff/intro/intro.js
opt/app/public/js/ff/moment/.htaccess
opt/app/public/js/ff/moment/de_DE.js
opt/app/public/js/ff/moment/en_US.js
opt/app/public/js/ff/moment/es_ES.js
@ -1164,39 +1237,57 @@ opt/app/public/js/ff/moment/pl_PL.js
opt/app/public/js/ff/moment/pt_BR.js
opt/app/public/js/ff/moment/ru_RU.js
opt/app/public/js/ff/moment/tr_TR.js
opt/app/public/js/ff/piggy-banks/.htaccess
opt/app/public/js/ff/piggy-banks/create.js
opt/app/public/js/ff/piggy-banks/edit.js
opt/app/public/js/ff/piggy-banks/index.js
opt/app/public/js/ff/piggy-banks/show.js
opt/app/public/js/ff/preferences/.htaccess
opt/app/public/js/ff/preferences/index.js
opt/app/public/js/ff/recurring/.htaccess
opt/app/public/js/ff/recurring/create.js
opt/app/public/js/ff/recurring/edit.js
opt/app/public/js/ff/reports/.htaccess
opt/app/public/js/ff/reports/account/.htaccess
opt/app/public/js/ff/reports/account/month.js
opt/app/public/js/ff/reports/all.js
opt/app/public/js/ff/reports/audit/.htaccess
opt/app/public/js/ff/reports/audit/all.js
opt/app/public/js/ff/reports/budget/.htaccess
opt/app/public/js/ff/reports/budget/month.js
opt/app/public/js/ff/reports/category/.htaccess
opt/app/public/js/ff/reports/category/month.js
opt/app/public/js/ff/reports/default/.htaccess
opt/app/public/js/ff/reports/default/all.js
opt/app/public/js/ff/reports/default/month.js
opt/app/public/js/ff/reports/default/multi-year.js
opt/app/public/js/ff/reports/default/year.js
opt/app/public/js/ff/reports/index.js
opt/app/public/js/ff/reports/tag/.htaccess
opt/app/public/js/ff/reports/tag/month.js
opt/app/public/js/ff/rules/.htaccess
opt/app/public/js/ff/rules/create-edit.js
opt/app/public/js/ff/rules/index.js
opt/app/public/js/ff/rules/select-transactions.js
opt/app/public/js/ff/search/.htaccess
opt/app/public/js/ff/search/index.js
opt/app/public/js/ff/tags/.htaccess
opt/app/public/js/ff/tags/create-edit.js
opt/app/public/js/ff/tags/index.js
opt/app/public/js/ff/tags/show.js
opt/app/public/js/ff/transactions/.htaccess
opt/app/public/js/ff/transactions/list.js
opt/app/public/js/ff/transactions/mass/.htaccess
opt/app/public/js/ff/transactions/mass/edit-bulk.js
opt/app/public/js/ff/transactions/mass/edit.js
opt/app/public/js/ff/transactions/show.js
opt/app/public/js/ff/transactions/single/.htaccess
opt/app/public/js/ff/transactions/single/common.js
opt/app/public/js/ff/transactions/single/create.js
opt/app/public/js/ff/transactions/single/edit.js
opt/app/public/js/ff/transactions/split/.htaccess
opt/app/public/js/ff/transactions/split/edit.js
opt/app/public/js/lib/.htaccess
opt/app/public/js/lib/Chart.bundle.min.js
opt/app/public/js/lib/accounting.min.js
opt/app/public/js/lib/bootstrap-multiselect.js
@ -1212,22 +1303,58 @@ opt/app/public/js/lib/jquery.color-2.1.2.min.js
opt/app/public/js/lib/modernizr-custom.js
opt/app/public/js/lib/moment.min.js
opt/app/public/js/lib/respond.min.js
opt/app/public/lib/.htaccess
opt/app/public/lib/adminlte/.htaccess
opt/app/public/lib/adminlte/css/.htaccess
opt/app/public/lib/adminlte/css/AdminLTE.css
opt/app/public/lib/adminlte/css/AdminLTE.min.css
opt/app/public/lib/adminlte/css/skins/.htaccess
opt/app/public/lib/adminlte/css/skins/skin-blue-light.css
opt/app/public/lib/adminlte/css/skins/skin-blue-light.min.css
opt/app/public/lib/adminlte/img/.htaccess
opt/app/public/lib/adminlte/img/icons.png
opt/app/public/lib/adminlte/js/.htaccess
opt/app/public/lib/adminlte/js/adminlte.js
opt/app/public/lib/adminlte/js/adminlte.min.js
opt/app/public/lib/adminlte/js/app.js
opt/app/public/lib/adminlte/js/app.min.js
opt/app/public/lib/bs/css/bootstrap-theme.css
opt/app/public/lib/bs/css/bootstrap-theme.css.map
opt/app/public/lib/bs/css/bootstrap-theme.min.css
opt/app/public/lib/bs/css/bootstrap-theme.min.css.map
opt/app/public/lib/bs/css/bootstrap.css
opt/app/public/lib/bs/css/bootstrap.css.map
opt/app/public/lib/bs/css/bootstrap.min.css
opt/app/public/lib/bs/css/bootstrap.min.css.map
opt/app/public/lib/bs/fonts/glyphicons-halflings-regular.eot
opt/app/public/lib/bs/fonts/glyphicons-halflings-regular.svg
opt/app/public/lib/bs/fonts/glyphicons-halflings-regular.ttf
opt/app/public/lib/bs/fonts/glyphicons-halflings-regular.woff
opt/app/public/lib/bs/fonts/glyphicons-halflings-regular.woff2
opt/app/public/lib/bs/js/bootstrap.js
opt/app/public/lib/bs/js/bootstrap.min.js
opt/app/public/lib/bs/js/npm.js
opt/app/public/lib/fa/css/font-awesome.css
opt/app/public/lib/fa/css/font-awesome.min.css
opt/app/public/lib/fa/fonts/FontAwesome.otf
opt/app/public/lib/fa/fonts/fontawesome-webfont.eot
opt/app/public/lib/fa/fonts/fontawesome-webfont.svg
opt/app/public/lib/fa/fonts/fontawesome-webfont.ttf
opt/app/public/lib/fa/fonts/fontawesome-webfont.woff
opt/app/public/lib/fa/fonts/fontawesome-webfont.woff2
opt/app/public/lib/fc/.htaccess
opt/app/public/lib/fc/fullcalendar.css
opt/app/public/lib/fc/fullcalendar.js
opt/app/public/lib/fc/fullcalendar.min.css
opt/app/public/lib/fc/fullcalendar.min.js
opt/app/public/lib/fc/fullcalendar.print.css
opt/app/public/lib/fc/fullcalendar.print.min.css
opt/app/public/lib/intro/.htaccess
opt/app/public/lib/intro/intro.min.js
opt/app/public/lib/intro/introjs-rtl.min.css
opt/app/public/lib/intro/introjs.min.css
opt/app/public/lib/leaflet/.htaccess
opt/app/public/lib/leaflet/images/.htaccess
opt/app/public/lib/leaflet/images/layers-2x.png
opt/app/public/lib/leaflet/images/layers.png
opt/app/public/lib/leaflet/images/marker-icon-2x.png
@ -1252,7 +1379,6 @@ opt/app/resources/assets/js/components/bills/Index.vue
opt/app/resources/assets/js/components/passport/AuthorizedClients.vue
opt/app/resources/assets/js/components/passport/Clients.vue
opt/app/resources/assets/js/components/passport/PersonalAccessTokens.vue
opt/app/resources/assets/js/lang.js
opt/app/resources/assets/sass/_variables.scss
opt/app/resources/assets/sass/app.scss
opt/app/resources/lang/de_DE/auth.php
@ -1541,6 +1667,7 @@ opt/app/resources/views/form/non-selectable-amount.twig
opt/app/resources/views/form/number.twig
opt/app/resources/views/form/options.twig
opt/app/resources/views/form/password.twig
opt/app/resources/views/form/percentage.twig
opt/app/resources/views/form/select.twig
opt/app/resources/views/form/static.twig
opt/app/resources/views/form/tags.twig
@ -1564,6 +1691,10 @@ opt/app/resources/views/import/spectre/choose-login.twig
opt/app/resources/views/import/spectre/prerequisites.twig
opt/app/resources/views/import/spectre/redirect.twig
opt/app/resources/views/import/status.twig
opt/app/resources/views/import/ynab/accounts.twig
opt/app/resources/views/import/ynab/prerequisites.twig
opt/app/resources/views/import/ynab/redirect.twig
opt/app/resources/views/import/ynab/select-budgets.twig
opt/app/resources/views/index.twig
opt/app/resources/views/install/index.twig
opt/app/resources/views/javascript/accounts.twig
@ -1581,6 +1712,7 @@ opt/app/resources/views/list/journals-tiny.twig
opt/app/resources/views/list/journals.twig
opt/app/resources/views/list/piggy-bank-events.twig
opt/app/resources/views/list/piggy-banks.twig
opt/app/resources/views/list/transactions.twig
opt/app/resources/views/new-user/index.twig
opt/app/resources/views/partials/boxes.twig
opt/app/resources/views/partials/breadcrumbs.twig
@ -1588,6 +1720,7 @@ opt/app/resources/views/partials/control-bar.twig
opt/app/resources/views/partials/empty.twig
opt/app/resources/views/partials/favicons.twig
opt/app/resources/views/partials/flashes.twig
opt/app/resources/views/partials/journal-row.twig
opt/app/resources/views/partials/menu-sidebar.twig
opt/app/resources/views/partials/page-header.twig
opt/app/resources/views/partials/password-modal.twig
@ -2144,6 +2277,7 @@ opt/app/vendor/doctrine/cache/LICENSE
opt/app/vendor/doctrine/cache/README.md
opt/app/vendor/doctrine/cache/UPGRADE.md
opt/app/vendor/doctrine/cache/composer.json
opt/app/vendor/doctrine/cache/docs/en/index.rst
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcuCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php
@ -2151,6 +2285,7 @@ opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ChainCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CouchbaseBucketCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CouchbaseCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ExtMongoDBCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FileCache.php
@ -3525,6 +3660,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Validation/Rules/Dimensions.php
opt/app/vendor/laravel/framework/src/Illuminate/Validation/Rules/Exists.php
opt/app/vendor/laravel/framework/src/Illuminate/Validation/Rules/In.php
opt/app/vendor/laravel/framework/src/Illuminate/Validation/Rules/NotIn.php
opt/app/vendor/laravel/framework/src/Illuminate/Validation/Rules/RequiredIf.php
opt/app/vendor/laravel/framework/src/Illuminate/Validation/Rules/Unique.php
opt/app/vendor/laravel/framework/src/Illuminate/Validation/UnauthorizedException.php
opt/app/vendor/laravel/framework/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php
@ -3883,6 +4019,7 @@ opt/app/vendor/league/event/src/ListenerProviderInterface.php
opt/app/vendor/league/event/src/OneTimeListener.php
opt/app/vendor/league/flysystem/LICENSE
opt/app/vendor/league/flysystem/composer.json
opt/app/vendor/league/flysystem/deprecations.md
opt/app/vendor/league/flysystem/src/Adapter/AbstractAdapter.php
opt/app/vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php
opt/app/vendor/league/flysystem/src/Adapter/CanOverwriteFiles.php
@ -5521,6 +5658,7 @@ opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PdoSessionH
opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PredisClusterSessionHandlerTest.php
opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PredisSessionHandlerTest.php
opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisArraySessionHandlerTest.php
opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisClusterSessionHandlerTest.php
opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisSessionHandlerTest.php
opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/StrictSessionHandlerTest.php
opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/MetadataBagTest.php
@ -5653,6 +5791,7 @@ opt/app/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategyInterface.php
opt/app/vendor/symfony/http-kernel/HttpCache/Ssi.php
opt/app/vendor/symfony/http-kernel/HttpCache/Store.php
opt/app/vendor/symfony/http-kernel/HttpCache/StoreInterface.php
opt/app/vendor/symfony/http-kernel/HttpCache/SubRequestHandler.php
opt/app/vendor/symfony/http-kernel/HttpCache/SurrogateInterface.php
opt/app/vendor/symfony/http-kernel/HttpKernel.php
opt/app/vendor/symfony/http-kernel/HttpKernelInterface.php
@ -5785,6 +5924,7 @@ opt/app/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php
opt/app/vendor/symfony/http-kernel/Tests/HttpCache/ResponseCacheStrategyTest.php
opt/app/vendor/symfony/http-kernel/Tests/HttpCache/SsiTest.php
opt/app/vendor/symfony/http-kernel/Tests/HttpCache/StoreTest.php
opt/app/vendor/symfony/http-kernel/Tests/HttpCache/SubRequestHandlerTest.php
opt/app/vendor/symfony/http-kernel/Tests/HttpCache/TestHttpKernel.php
opt/app/vendor/symfony/http-kernel/Tests/HttpCache/TestMultipleHttpKernel.php
opt/app/vendor/symfony/http-kernel/Tests/HttpKernelTest.php
@ -5807,6 +5947,7 @@ opt/app/vendor/symfony/polyfill-mbstring/LICENSE
opt/app/vendor/symfony/polyfill-mbstring/Mbstring.php
opt/app/vendor/symfony/polyfill-mbstring/README.md
opt/app/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php
opt/app/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php
opt/app/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php
opt/app/vendor/symfony/polyfill-mbstring/bootstrap.php
opt/app/vendor/symfony/polyfill-mbstring/composer.json
@ -5859,15 +6000,18 @@ opt/app/vendor/symfony/process/Tests/ProcessTest.php
opt/app/vendor/symfony/process/Tests/SignalListener.php
opt/app/vendor/symfony/process/composer.json
opt/app/vendor/symfony/process/phpunit.xml.dist
opt/app/vendor/symfony/psr-http-message-bridge/CHANGELOG
opt/app/vendor/symfony/psr-http-message-bridge/CHANGELOG.md
opt/app/vendor/symfony/psr-http-message-bridge/Factory/DiactorosFactory.php
opt/app/vendor/symfony/psr-http-message-bridge/Factory/HttpFoundationFactory.php
opt/app/vendor/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php
opt/app/vendor/symfony/psr-http-message-bridge/HttpFoundationFactoryInterface.php
opt/app/vendor/symfony/psr-http-message-bridge/HttpMessageFactoryInterface.php
opt/app/vendor/symfony/psr-http-message-bridge/LICENSE
opt/app/vendor/symfony/psr-http-message-bridge/README.md
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Factory/AbstractHttpMessageFactoryTest.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Factory/DiactorosFactoryTest.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Factory/HttpFoundationFactoryTest.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Factory/PsrHttpFactoryTest.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Message.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Response.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/ServerRequest.php

View File

@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = (
manifest = (
appTitle = (defaultText = "Firefly III"),
appVersion = 15,
appMarketingVersion = (defaultText = "4.7.5.3"),
appVersion = 16,
appMarketingVersion = (defaultText = "4.7.6.2"),
actions = [
# Define your "new document" handlers here.

View File

@ -78,7 +78,6 @@ RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local
# Generate locales supported by Firefly III
RUN echo "en_US.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\n\n" > /etc/locale.gen && locale-gen
# copy Apache config to correct spot.
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
@ -101,6 +100,9 @@ RUN chown -R www-data:www-data /var/www && chmod -R 775 $FIREFLY_PATH/storage
WORKDIR $FIREFLY_PATH
ADD . $FIREFLY_PATH
# Fix the link to curl:
RUN rm -rf /usr/local/lib/libcurl.so.4 && ln -s /usr/lib/x86_64-linux-gnu/libcurl.so.4.4.0 /usr/local/lib/libcurl.so.4
# Run composer
ENV COMPOSER_ALLOW_SUPERUSER 1
RUN composer install --prefer-dist --no-dev --no-scripts --no-suggest

View File

@ -50,14 +50,17 @@ class PiggyBankRequest extends Request
*/
public function getAll(): array
{
$current = $this->string('current_amount');
$current = '' === $current ? '0' : $current;
return [
'name' => $this->string('name'),
'account_id' => $this->integer('account_id'),
'targetamount' => $this->string('target_amount'),
'current_amount' => $this->string('current_amount'),
'current_amount' => $current,
'start_date' => $this->date('start_date'),
'target_date' => $this->date('target_date'),
'notes' => $this->string('notes'),
'notes' => $this->string('notes'),
];
}

View File

@ -73,6 +73,7 @@ class TransactionRequest extends Request
'invoice_date' => $this->date('invoice_date'),
'internal_reference' => $this->string('internal_reference'),
'notes' => $this->string('notes'),
'original-source' => sprintf('api-v%s', config('firefly.api_version')),
'transactions' => $this->getTransactionData(),
];

View File

@ -35,6 +35,7 @@ use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Bill;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\Note;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Rule;
@ -63,6 +64,7 @@ use UnexpectedValueException;
* Upgrade user database.
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
* @codeCoverageIgnore
*/
class UpgradeDatabase extends Command
@ -95,6 +97,7 @@ class UpgradeDatabase extends Command
$this->migrateNotes();
$this->migrateAttachmentData();
$this->migrateBillsToRules();
$this->budgetLimitCurrency();
$this->info('Firefly III database is up to date.');
@ -435,6 +438,31 @@ class UpgradeDatabase extends Command
);
}
/**
*
*/
private function budgetLimitCurrency(): void
{
$budgetLimits = BudgetLimit::get();
/** @var BudgetLimit $budgetLimit */
foreach ($budgetLimits as $budgetLimit) {
if (null === $budgetLimit->transaction_currency_id) {
$budget = $budgetLimit->budget;
if (null !== $budget) {
$user = $budget->user;
if (null !== $user) {
$currency = \Amount::getDefaultCurrencyByUser($user);
$budgetLimit->transaction_currency_id = $currency->id;
$budgetLimit->save();
$this->line(
sprintf('Budget limit #%d (part of budget "%s") now has a currency setting (%s).', $budgetLimit->id, $budget->name, $currency->name)
);
}
}
}
}
}
private function createNewTypes(): void
{
// create transaction type "Reconciliation".

View File

@ -41,6 +41,16 @@ use Log;
*/
class AccountFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
use AccountServiceTrait;
/** @var User */
private $user;

View File

@ -34,7 +34,15 @@ use Log;
*/
class AccountMetaFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param array $data
*

View File

@ -26,12 +26,22 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Note;
use FireflyIII\User;
use Log;
/**
* Class AttachmentFactory
*/
class AttachmentFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/** @var User */
private $user;

View File

@ -36,6 +36,16 @@ use Log;
*/
class BillFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
use BillServiceTrait;
/** @var User */
private $user;

View File

@ -27,12 +27,23 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\Budget;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
* Class BudgetFactory.
*/
class BudgetFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/** @var User */
private $user;

View File

@ -34,6 +34,16 @@ use Log;
*/
class CategoryFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/** @var User */
private $user;

View File

@ -37,6 +37,16 @@ use Log;
*/
class PiggyBankEventFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param TransactionJournal $journal
* @param PiggyBank|null $piggyBank

View File

@ -26,12 +26,23 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\PiggyBank;
use FireflyIII\User;
use Log;
/**
* Class PiggyBankFactory
*/
class PiggyBankFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/** @var User */
private $user;

View File

@ -39,6 +39,16 @@ use Log;
*/
class RecurrenceFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
use TransactionTypeTrait, TransactionServiceTrait, RecurringTransactionTrait;
/** @var User */

View File

@ -27,12 +27,23 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\Tag;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
* Class TagFactory
*/
class TagFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/** @var Collection */
private $tags;
/** @var User */

View File

@ -36,6 +36,16 @@ use Log;
*/
class TransactionCurrencyFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param array $data
*

View File

@ -40,6 +40,16 @@ use Log;
*/
class TransactionFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
use TransactionServiceTrait;
/** @var User */
@ -204,10 +214,11 @@ class TransactionFactory
throw new FireflyException(sprintf('Source and destination account cannot be both of the type "%s"', $destinationType));
}
// source must be in this list AND dest must be in this list:
$list = [AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT, AccountType::MORTGAGE, AccountType::LOAN, AccountType::MORTGAGE];
$list = [AccountType::DEFAULT, AccountType::ASSET, AccountType::CREDITCARD, AccountType::CASH, AccountType::DEBT, AccountType::MORTGAGE,
AccountType::LOAN, AccountType::MORTGAGE];
if (
!\in_array($sourceType, $list, true) &&
!\in_array($destinationType, $list, true)) {
!\in_array($sourceType, $list, true)
&& !\in_array($destinationType, $list, true)) {
throw new FireflyException(sprintf('At least one of the accounts must be an asset account (%s, %s).', $sourceType, $destinationType));
}
// either of these must be asset or default account.

View File

@ -36,6 +36,16 @@ use Log;
*/
class TransactionJournalFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
use JournalServiceTrait, TransactionTypeTrait;
/** @var User The user */
private $user;
@ -104,7 +114,7 @@ class TransactionJournalFactory
// store date meta fields (if present):
$fields = ['sepa-cc', 'sepa-ct-op', 'sepa-ct-id', 'sepa-db', 'sepa-country', 'sepa-ep', 'sepa-ci', 'interest_date', 'book_date', 'process_date',
'due_date', 'recurrence_id', 'payment_date', 'invoice_date', 'internal_reference', 'bunq_payment_id', 'importHash', 'importHashV2',
'external_id', 'sepa-batch-id'];
'external_id', 'sepa-batch-id','original-source'];
foreach ($fields as $field) {
$this->storeMeta($journal, $data, $field);

View File

@ -34,6 +34,16 @@ use Log;
*/
class TransactionJournalMetaFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param array $data
*

View File

@ -26,12 +26,22 @@ declare(strict_types=1);
namespace FireflyIII\Factory;
use FireflyIII\Models\TransactionType;
use Log;
/**
* Class TransactionTypeFactory
*/
class TransactionTypeFactory
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param string $type
*

View File

@ -23,12 +23,22 @@ declare(strict_types=1);
namespace FireflyIII\Generator\Chart\Basic;
use FireflyIII\Support\ChartColour;
use Log;
/**
* Class ChartJsGenerator.
*/
class ChartJsGenerator implements GeneratorInterface
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* Will generate a Chart JS compatible array from the given input. Expects this format.
*
@ -140,6 +150,46 @@ class ChartJsGenerator implements GeneratorInterface
return $chartData;
}
/**
* Expects data as:.
*
* key => [value => x, 'currency_symbol' => 'x']
*
* @param array $data
*
* @return array
*/
public function multiCurrencyPieChart(array $data): array
{
$chartData = [
'datasets' => [
0 => [],
],
'labels' => [],
];
$amounts = array_column($data, 'amount');
$next = next($amounts);
$sortFlag = SORT_ASC;
if (!\is_bool($next) && 1 === bccomp((string)$next, '0')) {
$sortFlag = SORT_DESC;
}
array_multisort($amounts, $sortFlag, $data);
unset($next, $sortFlag, $amounts);
$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]['backgroundColor'][] = ChartColour::getColour($index);
$chartData['datasets'][0]['currency_symbol'][] = $valueArray['currency_symbol'];
$chartData['labels'][] = $key;
++$index;
}
return $chartData;
}
/**
* Will generate a (ChartJS) compatible array from the given input. Expects this format:.
*

View File

@ -27,6 +27,13 @@ namespace FireflyIII\Generator\Chart\Basic;
*/
interface GeneratorInterface
{
/**
* @param array $data
*
* @return array
*/
public function multiCurrencyPieChart(array $data): array;
/**
* Will generate a Chart JS compatible array from the given input. Expects this format.
*

View File

@ -61,6 +61,7 @@ class UserEventHandler
// first user ever?
if (1 === $repository->count()) {
Log::debug('User count is one, attach role.');
$repository->attachRole($event->user, 'owner');
}

View File

@ -63,8 +63,13 @@ class AttachmentHelper implements AttachmentHelperInterface
$this->messages = new MessageBag;
$this->attachments = new Collection;
$this->uploadDisk = Storage::disk('upload');
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* Returns the content of an attachment.
*

View File

@ -38,6 +38,7 @@ use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
* Class MetaPieChart.
@ -88,6 +89,11 @@ class MetaPieChart implements MetaPieChartInterface
$this->budgets = new Collection;
$this->categories = new Collection;
$this->tags = new Collection;
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**

View File

@ -24,6 +24,7 @@ namespace FireflyIII\Helpers\Collection;
use Carbon\Carbon;
use FireflyIII\Models\Bill as BillModel;
use FireflyIII\Models\TransactionCurrency;
/**
* Class BillLine.
@ -42,6 +43,8 @@ class BillLine
protected $max;
/** @var string What was the min amount. */
protected $min;
/** @var TransactionCurrency The transaction currency */
private $currency;
/** @var Carbon Latest date that payment is expected. */
private $endOfPayDate;
/** @var Carbon Date of last hit */
@ -99,6 +102,22 @@ class BillLine
$this->bill = $bill;
}
/**
* @return TransactionCurrency
*/
public function getCurrency(): TransactionCurrency
{
return $this->currency;
}
/**
* @param TransactionCurrency $currency
*/
public function setCurrency(TransactionCurrency $currency): void
{
$this->currency = $currency;
}
/**
* End of pay date getter.
*

View File

@ -57,6 +57,16 @@ use Log;
*/
class TransactionCollector implements TransactionCollectorInterface
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/** @var array */
private $accountIds = [];

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Helpers;
use Carbon\Carbon;
use Log;
/**
* Class FiscalHelper.
@ -38,6 +39,10 @@ class FiscalHelper implements FiscalHelperInterface
public function __construct()
{
$this->useCustomFiscalYear = app('preferences')->get('customFiscalYear', false)->data;
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**

View File

@ -40,9 +40,21 @@ class Help implements HelpInterface
/** @var string The user agent. */
protected $userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36';
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* Get from cache.
*
* @codeCoverageIgnore
*
* @param string $route
* @param string $language
*
@ -70,7 +82,7 @@ class Help implements HelpInterface
$opt = ['headers' => ['User-Agent' => $this->userAgent]];
$content = '';
$statusCode = 500;
$client = new Client;
$client = app(Client::class);
try {
$res = $client->request('GET', $uri, $opt);
$statusCode = $res->getStatusCode();
@ -94,6 +106,8 @@ class Help implements HelpInterface
/**
* Do we have the route?
*
* @codeCoverageIgnore
*
* @param string $route
*
* @return bool
@ -106,6 +120,8 @@ class Help implements HelpInterface
/**
* Is in cache?
*
* @codeCoverageIgnore
*
* @param string $route
* @param string $language
*
@ -128,6 +144,8 @@ class Help implements HelpInterface
/**
* Put help text in cache.
*
* @codeCoverageIgnore
*
* @param string $route
* @param string $language
* @param string $content

View File

@ -34,6 +34,8 @@ use Log;
/**
* Class BalanceReportHelper.
*
* @codeCoverageIgnore
*/
class BalanceReportHelper implements BalanceReportHelperInterface
{
@ -49,6 +51,11 @@ class BalanceReportHelper implements BalanceReportHelperInterface
public function __construct(BudgetRepositoryInterface $budgetRepository)
{
$this->budgetRepository = $budgetRepository;
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**

View File

@ -27,9 +27,12 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
/**
* Class BudgetReportHelper.
*
* @codeCoverageIgnore
*/
class BudgetReportHelper implements BudgetReportHelperInterface
{
@ -44,6 +47,11 @@ class BudgetReportHelper implements BudgetReportHelperInterface
public function __construct(BudgetRepositoryInterface $repository)
{
$this->repository = $repository;
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**

View File

@ -48,6 +48,16 @@ class NetWorth implements NetWorthInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* Returns the user's net worth in an array with the following layout:
*

View File

@ -30,12 +30,24 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
/**
* Class PopupReport.
*
* @codeCoverageIgnore
*/
class PopupReport implements PopupReportInterface
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* Collect the tranactions for one account and one budget.
*

View File

@ -32,9 +32,11 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
/**
* Class ReportHelper.
*
* @codeCoverageIgnore
*/
class ReportHelper implements ReportHelperInterface
{
@ -50,6 +52,12 @@ class ReportHelper implements ReportHelperInterface
public function __construct(BudgetRepositoryInterface $budgetRepository)
{
$this->budgetRepository = $budgetRepository;
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
@ -90,6 +98,7 @@ class ReportHelper implements ReportHelperInterface
$billLine = new BillLine;
$billLine->setBill($bill);
$billLine->setCurrency($bill->transactionCurrency);
$billLine->setPayDate($payDate);
$billLine->setEndOfPayDate($endOfPayPeriod);
$billLine->setMin((string)$bill->amount_min);

View File

@ -29,6 +29,7 @@ use FireflyIII\Http\Requests\AccountFormRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Http\Request;
use Log;
/**
*
@ -132,6 +133,8 @@ class CreateController extends Controller
$request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name]));
app('preferences')->mark();
// update preferences if necessary:
$frontPage = app('preferences')->get('frontPageAccounts', [])->data;
if (AccountType::ASSET === $account->accountType->type && \count($frontPage) > 0) {

View File

@ -64,8 +64,8 @@ class LinkController extends Controller
$subTitleIcon = 'fa-link';
// put previous url in session if not redirect from store (not "create another").
if (true !== session('link_types.create.fromStore')) {
$this->rememberPreviousUri('link_types.create.uri');
if (true !== session('link-types.create.fromStore')) {
$this->rememberPreviousUri('link-types.create.uri');
}
return view('admin.link.create', compact('subTitle', 'subTitleIcon'));
@ -100,7 +100,7 @@ class LinkController extends Controller
}
}
// put previous url in session
$this->rememberPreviousUri('link_types.delete.uri');
$this->rememberPreviousUri('link-types.delete.uri');
return view('admin.link.delete', compact('linkType', 'subTitle', 'moveTo', 'count'));
}
@ -123,7 +123,7 @@ class LinkController extends Controller
$request->session()->flash('success', (string)trans('firefly.deleted_link_type', ['name' => $name]));
app('preferences')->mark();
return redirect($this->getPreviousUri('link_types.delete.uri'));
return redirect($this->getPreviousUri('link-types.delete.uri'));
}
/**
@ -145,10 +145,10 @@ class LinkController extends Controller
$subTitleIcon = 'fa-link';
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('link_types.edit.fromUpdate')) {
$this->rememberPreviousUri('link_types.edit.uri'); // @codeCoverageIgnore
if (true !== session('link-types.edit.fromUpdate')) {
$this->rememberPreviousUri('link-types.edit.uri'); // @codeCoverageIgnore
}
$request->session()->forget('link_types.edit.fromUpdate');
$request->session()->forget('link-types.edit.fromUpdate');
return view('admin.link.edit', compact('subTitle', 'subTitleIcon', 'linkType'));
}
@ -207,10 +207,10 @@ class LinkController extends Controller
];
$linkType = $repository->store($data);
$request->session()->flash('success', (string)trans('firefly.stored_new_link_type', ['name' => $linkType->name]));
$redirect = redirect($this->getPreviousUri('link_types.create.uri'));
$redirect = redirect($this->getPreviousUri('link-types.create.uri'));
if (1 === (int)$request->get('create_another')) {
// set value so create routine will not overwrite URL:
$request->session()->put('link_types.create.fromStore', true);
$request->session()->put('link-types.create.fromStore', true);
$redirect = redirect(route('admin.links.create'))->withInput();
}
@ -245,10 +245,10 @@ class LinkController extends Controller
$request->session()->flash('success', (string)trans('firefly.updated_link_type', ['name' => $linkType->name]));
app('preferences')->mark();
$redirect = redirect($this->getPreviousUri('link_types.edit.uri'));
$redirect = redirect($this->getPreviousUri('link-types.edit.uri'));
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);
$request->session()->put('link-types.edit.fromUpdate', true);
$redirect = redirect(route('admin.links.edit', [$linkType->id]))->withInput(['return_to_edit' => 1]);
}

View File

@ -36,6 +36,7 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Log;
/**
* Class AmountController
@ -160,6 +161,8 @@ class AmountController extends Controller
$average = $this->repository->getAverageAvailable($start, $end);
$available = bcmul($average, (string)$daysInPeriod);
Log::debug(sprintf('Average is %s, so total available is %s because days is %d.', $average, $available, $daysInPeriod));
// amount earned in this period:
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
@ -169,6 +172,8 @@ class AmountController extends Controller
// This is multiplied by the number of days in the current period, showing you the average.
$earnedAverage = bcmul(bcdiv($earned, (string)$daysInSearchPeriod), (string)$daysInPeriod);
Log::debug(sprintf('Earned is %s, earned average is %s', $earned, $earnedAverage));
// amount spent in period
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
@ -176,11 +181,16 @@ class AmountController extends Controller
$spent = (string)$collector->getTransactions()->sum('transaction_amount');
$spentAverage = app('steam')->positive(bcmul(bcdiv($spent, (string)$daysInSearchPeriod), (string)$daysInPeriod));
Log::debug(sprintf('Spent is %s, spent average is %s', $earned, $earnedAverage));
// the default suggestion is the money the user has spent, on average, over this period.
$suggested = $spentAverage;
Log::debug(sprintf('Suggested is now %s (spent average)',$suggested));
// if the user makes less per period, suggest that amount instead.
if (1 === bccomp($spentAverage, $earnedAverage)) {
Log::debug(sprintf('Because earned average (%s) is less than spent average (%s) will suggest earned average instead.', $earnedAverage, $spentAverage));
$suggested = $earnedAverage;
}

View File

@ -298,7 +298,7 @@ class AccountController extends Controller
foreach ($result as $row) {
$categoryId = $row['category_id'];
$name = $names[$categoryId];
$name = $names[$categoryId] ?? '(unknown)';
$label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency']]);
$chartData[$label] = $row['total'];
}
@ -329,8 +329,6 @@ class AccountController extends Controller
/**
* Shows the balances for all the user's frontpage accounts.
*
* TODO this chart is not multi-currency aware.
*
* @param AccountRepositoryInterface $repository
*
* @return JsonResponse

View File

@ -29,6 +29,7 @@ use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
@ -54,8 +55,6 @@ class BillController extends Controller
/**
* Shows all bills and whether or not they've been paid this month (pie chart).
*
* TODO this chart is not multi-currency aware.
*
* @param BillRepositoryInterface $repository
*
* @return JsonResponse
@ -69,17 +68,28 @@ class BillController extends Controller
$cache->addProperty($end);
$cache->addProperty('chart.bill.frontpage');
if ($cache->has()) {
return response()->json($cache->get()); // @codeCoverageIgnore
//return response()->json($cache->get()); // @codeCoverageIgnore
}
/** @var CurrencyRepositoryInterface $currencyRepository */
$currencyRepository = app(CurrencyRepositoryInterface::class);
$chartData = [];
$currencies = [];
$paid = $repository->getBillsPaidInRangePerCurrency($start, $end); // will be a negative amount.
$unpaid = $repository->getBillsUnpaidInRangePerCurrency($start, $end); // will be a positive amount.
foreach ($paid as $currencyId => $amount) {
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepository->findNull($currencyId);
$label = (string)trans('firefly.paid_in_currency', ['currency' => $currencies[$currencyId]->name]);
$chartData[$label] = ['amount' => $amount, 'currency_symbol' => $currencies[$currencyId]->symbol];
}
foreach ($unpaid as $currencyId => $amount) {
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepository->findNull($currencyId);
$label = (string)trans('firefly.unpaid_in_currency', ['currency' => $currencies[$currencyId]->name]);
$chartData[$label] = ['amount' => $amount, 'currency_symbol' => $currencies[$currencyId]->symbol];
}
$paid = $repository->getBillsPaidInRange($start, $end); // will be a negative amount.
$unpaid = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount.
$chartData = [
(string)trans('firefly.unpaid') => $unpaid,
(string)trans('firefly.paid') => $paid,
];
$data = $this->generator->pieChart($chartData);
$data = $this->generator->multiCurrencyPieChart($chartData);
$cache->store($data);
return response()->json($data);
@ -93,8 +103,6 @@ class BillController extends Controller
* @param Bill $bill
*
* @return JsonResponse
*
* TODO this chart is not multi-currency aware.
*/
public function single(TransactionCollectorInterface $collector, Bill $bill): JsonResponse
{

View File

@ -26,6 +26,8 @@ use Carbon\Carbon;
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
use FireflyIII\Helpers\Report\NetWorthInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Http\Controllers\BasicDataSupport;
@ -56,8 +58,6 @@ class ReportController extends Controller
* This chart, by default, is shown on the multi-year and year report pages,
* which means that giving it a 2 week "period" should be enough granularity.
*
* TODO this chart is not multi-currency aware.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
@ -81,9 +81,26 @@ class ReportController extends Controller
$helper = app(NetWorthInterface::class);
$helper->setUser(auth()->user());
// filter accounts on having the preference for being included.
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$filtered = $accounts->filter(
function (Account $account) use ($accountRepository) {
$includeNetWorth = $accountRepository->getMetaValue($account, 'include_net_worth');
$result = null === $includeNetWorth ? true : '1' === $includeNetWorth;
if (false === $result) {
Log::debug(sprintf('Will not include "%s" in net worth charts.', $account->name));
}
return $result;
}
);
while ($current < $end) {
// get balances by date, grouped by currency.
$result = $helper->getNetWorthByCurrency($accounts, $current);
$result = $helper->getNetWorthByCurrency($filtered, $current);
// loop result, add to array.
/** @var array $netWorthItem */

View File

@ -48,10 +48,13 @@ class CallbackController extends Controller
{
$code = (string)$request->get('code');
$jobKey = (string)$request->get('state');
$importJob = $repository->findByKey($jobKey);
if ('' === $code) {
return view('error')->with('message', 'You Need A Budget did not reply with a valid authorization code. Firefly III cannot continue.');
}
$importJob = $repository->findByKey($jobKey);
if ('' === $jobKey || null === $importJob) {
return view('error')->with('message', 'You Need A Budget did not reply with the correct state identifier. Firefly III cannot continue.');
}

View File

@ -76,29 +76,29 @@ class IndexController extends Controller
*/
public function create(string $importProvider)
{
Log::debug(sprintf('Will create job for provider "%s"', $importProvider));
$importJob = $this->repository->create($importProvider);
$hasPreReq = (bool)config(sprintf('import.has_prereq.%s', $importProvider));
$hasConfig = (bool)config(sprintf('import.has_job_config.%s', $importProvider));
$allowedForDemo = (bool)config(sprintf('import.allowed_for_demo.%s', $importProvider));
$isDemoUser = $this->userRepository->hasRole(auth()->user(), 'demo');
Log::debug(sprintf('Will create job for provider "%s"', $importProvider));
Log::debug(sprintf('Is demo user? %s',var_export($isDemoUser, true)));
Log::debug(sprintf('Is allowed for user? %s',var_export($allowedForDemo, true)));
Log::debug(sprintf('Has prerequisites? %s',var_export($hasPreReq, true)));
Log::debug(sprintf('Has config? %s',var_export($hasConfig, true)));
if ($isDemoUser && !$allowedForDemo) {
Log::debug('User is demo and this provider doesnt work for demo users.');
return redirect(route('import.index'));
}
$importJob = $this->repository->create($importProvider);
Log::debug(sprintf('Created job #%d for provider %s', $importJob->id, $importProvider));
// no prerequisites and no config:
if (false === $hasPreReq && false === $hasConfig) {
Log::debug('Provider needs no configuration for job. Job is ready to start.');
$this->repository->updateStatus($importJob, 'ready_to_run');
Log::debug('Redirect to status-page.');
return redirect(route('import.job.status.index', [$importJob->key]));
}
// no prerequisites but job has config:
if (false === $hasPreReq && false !== $hasConfig) {
Log::debug('Provider has no prerequisites. Continue.');
@ -130,7 +130,7 @@ class IndexController extends Controller
if (false === $hasConfig) {
// @codeCoverageIgnoreStart
Log::debug('Provider has no configuration. Job is ready to start.');
$this->repository->updateStatus($importJob, 'ready_to_run');
$this->repository->setStatus($importJob, 'ready_to_run');
Log::debug('Redirect to status-page.');
return redirect(route('import.job.status.index', [$importJob->key]));

View File

@ -88,7 +88,7 @@ class JobConfigurationController extends Controller
if (!(bool)config(sprintf('import.has_job_config.%s', $importProvider))) {
// @codeCoverageIgnoreStart
Log::debug('Job needs no config, is ready to run!');
$this->repository->updateStatus($importJob, 'ready_to_run');
$this->repository->setStatus($importJob, 'ready_to_run');
return redirect(route('import.job.status.index', [$importJob->key]));
// @codeCoverageIgnoreEnd
@ -97,7 +97,7 @@ class JobConfigurationController extends Controller
$configurator = $this->makeConfigurator($importJob);
if ($configurator->configurationComplete()) {
Log::debug('Config is complete, set status to ready_to_run.');
$this->repository->updateStatus($importJob, 'ready_to_run');
$this->repository->setStatus($importJob, 'ready_to_run');
return redirect(route('import.job.status.index', [$importJob->key]));
}
@ -137,7 +137,7 @@ class JobConfigurationController extends Controller
// is the job already configured?
if ($configurator->configurationComplete()) {
$this->repository->updateStatus($importJob, 'ready_to_run');
$this->repository->setStatus($importJob, 'ready_to_run');
return redirect(route('import.job.status.index', [$importJob->key]));
}

View File

@ -291,32 +291,4 @@ class BoxController extends Controller
return response()->json($return);
}
/**
* Get a currency or return default currency.
*
* @param Account $account
*
* @return TransactionCurrency
*/
protected function getCurrencyOrDefault(Account $account): TransactionCurrency // get a preference
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
$currency = app('amount')->getDefaultCurrency();
$accountCurrency = null;
$currencyId = (int)$repository->getMetaValue($account, 'currency_id');
if (0 !== $currencyId) {
$accountCurrency = $currencyRepos->findNull($currencyId);
}
if (null === $accountCurrency) {
$accountCurrency = $currency;
}
return $accountCurrency;
}
}

View File

@ -67,10 +67,12 @@ class FrontpageController extends Controller
if (\count($info) > 0) {
try {
$html = view('json.piggy-banks', compact('info'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Cannot render json.piggy-banks: %s', $e->getMessage()));
$html = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
}
return response()->json(['html' => $html]);

View File

@ -119,7 +119,7 @@ class ReconcileController extends Controller
/** @var Transaction $transaction */
foreach ($cleared as $transaction) {
if ($transaction->transactionJournal->date <= $end) {
$clearedAmount = bcadd($clearedAmount, $transaction->amount);
$clearedAmount = bcadd($clearedAmount, $transaction->amount); // @codeCoverageIgnore
++$countCleared;
}
}
@ -134,10 +134,12 @@ class ReconcileController extends Controller
'route', 'countCleared'
)
)->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('View error: %s', $e->getMessage()));
$view = 'Could not render accounts.reconcile.overview';
}
// @codeCoverageIgnoreEnd
$return = [
@ -194,10 +196,12 @@ class ReconcileController extends Controller
$html = view(
'accounts.reconcile.transactions', compact('account', 'transactions', 'currency', 'start', 'end', 'selectionStart', 'selectionEnd')
)->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('Could not render: %s', $e->getMessage()));
$html = 'Could not render accounts.reconcile.transactions';
}
// @codeCoverageIgnoreEnd
return response()->json(['html' => $html, 'startBalance' => $startBalance, 'endBalance' => $endBalance]);
}

View File

@ -103,10 +103,8 @@ class RecurrenceController extends Controller
$repetition->repetition_skip = (int)$request->get('skip');
$repetition->weekend = (int)$request->get('weekend');
$actualEnd = clone $end;
$occurrences = [];
switch ($endsAt) {
default:
throw new FireflyException(sprintf('Cannot generate events for type that ends at "%s".', $endsAt));
case 'forever':
// simply generate up until $end. No change from default behavior.
$occurrences = $this->recurring->getOccurrencesInRange($repetition, $actualStart, $actualEnd);

View File

@ -49,10 +49,12 @@ class JsonController extends Controller
}
try {
$view = view('rules.partials.action', compact('actions', 'count'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Cannot render rules.partials.action: %s', $e->getMessage()));
$view = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
return response()->json(['html' => $view]);
}
@ -78,10 +80,12 @@ class JsonController extends Controller
try {
$view = view('rules.partials.trigger', compact('triggers', 'count'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Cannot render rules.partials.trigger: %s', $e->getMessage()));
$view = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
return response()->json(['html' => $view]);
}

View File

@ -190,17 +190,10 @@ class ProfileController extends Controller
/**
* Enable 2FA screen.
*
* @param UserRepositoryInterface $repository
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function enable2FA(UserRepositoryInterface $repository)
public function enable2FA()
{
/** @var User $user */
$user = auth()->user();
if ($repository->hasRole($user, 'demo')) {
return redirect(route('profile.index'));
}
$hasSecret = (null !== app('preferences')->get('twoFactorAuthSecret'));
// if we don't have a valid secret yet, redirect to the code page to get one.

View File

@ -105,10 +105,10 @@ class EditController extends Controller
'times' => (string)trans('firefly.repeat_times'),
];
if (null !== $recurrence->repeat_until) {
$repetitionEnd = 'until_date';
$repetitionEnd = 'until_date'; // @codeCoverageIgnore
}
if ($recurrence->repetitions > 0) {
$repetitionEnd = 'times';
$repetitionEnd = 'times'; // @codeCoverageIgnore
}
$weekendResponses = [

View File

@ -63,10 +63,12 @@ class AccountController extends Controller
$accountReport = $accountTasker->getAccountReport($accounts, $start, $end);
try {
$result = view('reports.partials.accounts', compact('accountReport'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.accounts: %s', $e->getMessage()));
$result = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;

View File

@ -61,10 +61,12 @@ class BalanceController extends Controller
$balance = $helper->getBalanceReport($accounts, $start, $end);
try {
$result = view('reports.partials.balance', compact('balance'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.balance: %s', $e->getMessage()));
$result = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;

View File

@ -63,10 +63,12 @@ class BudgetController extends Controller
$budgets = $helper->getBudgetReport($start, $end, $accounts);
try {
$result = view('reports.partials.budgets', compact('budgets'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budgets: %s', $e->getMessage()));
$result = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;
@ -103,10 +105,12 @@ class BudgetController extends Controller
$periods = app('navigation')->listOfPeriods($start, $end);
try {
$result = view('reports.partials.budget-period', compact('report', 'periods'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
$result = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;

View File

@ -67,10 +67,12 @@ class CategoryController extends Controller
$periods = app('navigation')->listOfPeriods($start, $end);
try {
$result = view('reports.partials.category-period', compact('report', 'periods'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
$result = 'An error prevented Firefly III from rendering. Apologies.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
@ -107,10 +109,12 @@ class CategoryController extends Controller
$periods = app('navigation')->listOfPeriods($start, $end);
try {
$result = view('reports.partials.category-period', compact('report', 'periods'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
$result = 'An error prevented Firefly III from rendering. Apologies.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;
@ -160,10 +164,12 @@ class CategoryController extends Controller
try {
$result = view('reports.partials.categories', compact('report'))->render();
$cache->store($result);
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
$result = 'An error prevented Firefly III from rendering. Apologies.';
}
// @codeCoverageIgnoreEnd
return $result;
}

View File

@ -107,10 +107,12 @@ class ExpenseController extends Controller
}
try {
$result = view('reports.partials.exp-budgets', compact('together'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Could not render category::budget: %s', $e->getMessage()));
$result = 'An error prevented Firefly III from rendering. Apologies.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;
@ -170,10 +172,12 @@ class ExpenseController extends Controller
}
try {
$result = view('reports.partials.exp-categories', compact('together'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
$result = 'An error prevented Firefly III from rendering. Apologies.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;
@ -220,10 +224,12 @@ class ExpenseController extends Controller
}
try {
$result = view('reports.partials.exp-not-grouped', compact('result'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
$result = 'An error prevented Firefly III from rendering. Apologies.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;
@ -271,10 +277,12 @@ class ExpenseController extends Controller
);
try {
$result = view('reports.partials.top-transactions', compact('sorted'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Could not render category::topExpense: %s', $e->getMessage()));
$result = 'An error prevented Firefly III from rendering. Apologies.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;
@ -320,10 +328,12 @@ class ExpenseController extends Controller
);
try {
$result = view('reports.partials.top-transactions', compact('sorted'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Could not render category::topIncome: %s', $e->getMessage()));
$result = 'An error prevented Firefly III from rendering. Apologies.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;

View File

@ -81,10 +81,12 @@ class OperationsController extends Controller
$type = 'expense-entry';
try {
$result = view('reports.partials.income-expenses', compact('entries', 'type'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.income-expense: %s', $e->getMessage()));
$result = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;
@ -114,10 +116,12 @@ class OperationsController extends Controller
$type = 'income-entry';
try {
$result = view('reports.partials.income-expenses', compact('entries', 'type'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.income-expenses: %s', $e->getMessage()));
$result = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
@ -166,10 +170,12 @@ class OperationsController extends Controller
);
try {
$result = view('reports.partials.operations', compact('incomeSum', 'expensesSum'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.operations: %s', $e->getMessage()));
$result = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
$cache->store($result);
return $result;

View File

@ -258,10 +258,13 @@ class CreateController extends Controller
'count' => $index + 1,
]
)->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage()));
Log::debug($e->getTraceAsString());
$string = '';
// @codeCoverageIgnoreEnd
}
if ('' !== $string) {
$result[] = $string;

View File

@ -152,11 +152,13 @@ class SelectController extends Controller
$limit = (int)config('firefly.test-triggers.limit');
$range = (int)config('firefly.test-triggers.range');
$matchingTransactions = new Collection;
$strict = $request->get('strict') === '1';
/** @var TransactionMatcher $matcher */
$matcher = app(TransactionMatcher::class);
$matcher->setLimit($limit);
$matcher->setRange($range);
$matcher->setTriggers($triggers);
$matcher->setStrict($strict);
try {
$matchingTransactions = $matcher->findTransactionsByTriggers();
// @codeCoverageIgnoreStart

View File

@ -102,10 +102,12 @@ class SearchController extends Controller
}
try {
$html = view('search.search', compact('transactions'))->render();
// @codeCoverageIgnoreStart
} catch (Throwable $e) {
Log::error(sprintf('Cannot render search.search: %s', $e->getMessage()));
$html = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
return response()->json(['count' => $transactions->count(), 'html' => $html]);
}

View File

@ -49,7 +49,8 @@ class CronController
*/
private function runRecurring(): string
{
$recurring = new RecurringCronjob;
/** @var RecurringCronjob $recurring */
$recurring = app(RecurringCronjob::class);
try {
$result = $recurring->fire();
} catch (FireflyException $e) {

View File

@ -161,6 +161,7 @@ class ConvertController extends Controller
$errors = $this->repository->convert($journal, $destinationType, $source, $destination);
if ($errors->count() > 0) {
Log::error('Errors while converting: ', $errors->toArray());
return redirect(route('transactions.convert.index', [strtolower($destinationType->type), $journal->id]))->withErrors($errors)->withInput();
}

View File

@ -33,6 +33,8 @@ use Log;
/**
* Class Installer
* @codeCoverageIgnore
*
*/
class Installer
{
@ -48,6 +50,7 @@ class Installer
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
*/
public function handle($request, Closure $next)
{

View File

@ -60,7 +60,7 @@ class IsDemoUser
return response()->redirectTo($previous);
}
return response()->redirectTo(route('index'));
return response()->redirectTo(route('index')); // @codeCoverageIgnore
}
return $next($request);

View File

@ -108,9 +108,11 @@ class Range
private function loseItAll(Request $request): void
{
if ('sqlite' === getenv('DB_CONNECTION') && true === getenv('IS_DOCKER')) {
// @codeCoverageIgnoreStart
$request->session()->flash(
'error', 'You seem to be using SQLite in a Docker container. Don\'t do this. If the container restarts all your data will be gone.'
);
// @codeCoverageIgnoreEnd
}
}

View File

@ -87,6 +87,7 @@ class Sandstorm
* @param string $email
*
* @return User
* @codeCoverageIgnore
*/
private function createUser(string $email): User
{

View File

@ -47,7 +47,7 @@ class SecureHeaders
$google = '';
$analyticsId = env('ANALYTICS_ID', '');
if ('' !== $analyticsId) {
$google = 'https://www.google-analytics.com/analytics.js';
$google = 'https://www.google-analytics.com/analytics.js'; // @codeCoverageIgnore
}
$csp = [
"default-src 'none'",
@ -57,7 +57,7 @@ class SecureHeaders
"form-action 'self'",
"font-src 'self'",
"connect-src 'self'",
"img-src 'self'",
"img-src 'self' data:",
];
$featurePolicies = [
@ -85,4 +85,4 @@ class SecureHeaders
return $response;
}
}
}

View File

@ -75,6 +75,7 @@ class JournalFormRequest extends Request
'piggy_bank_name' => null,
'bill_id' => null,
'bill_name' => null,
'original-source' => sprintf('gui-v%s', config('firefly.version')),
// transaction data:
'transactions' => [

View File

@ -82,7 +82,6 @@ class JournalLinkRequest extends Request
// fixed
return [
'link_type' => sprintf('required|in:%s', $string),
'link_other' => 'belongsToUser:transaction_journals',
'link_journal_id' => 'belongsToUser:transaction_journals',
];
}

View File

@ -118,7 +118,7 @@ class RecurrenceFormRequest extends Request
// fill in source and destination account data
switch ($this->string('transaction_type')) {
default:
throw new FireflyException(sprintf('Cannot handle transaction type "%s"', $this->string('transaction_type')));
throw new FireflyException(sprintf('Cannot handle transaction type "%s"', $this->string('transaction_type'))); // @codeCoverageIgnore
case 'withdrawal':
$return['transactions'][0]['source_id'] = $this->integer('source_id');
$return['transactions'][0]['destination_name'] = $this->string('destination_name');
@ -227,8 +227,6 @@ class RecurrenceFormRequest extends Request
$rules['title'] = 'required|between:1,255|uniqueObjectForUser:recurrences,title,' . $recurrence->id;
$rules['first_date'] = 'required|date';
}
return $rules;
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests;
/**
* Class RuleFormRequest.
* Class TestRuleFormRequest.
*
* @codeCoverageIgnore
*/

View File

@ -77,10 +77,19 @@ class BunqRoutine implements RoutineInterface
$handler->setImportJob($this->importJob);
$handler->run();
$transactions = $handler->getTransactions();
// could be that more transactions will arrive in a second run.
if (true === $handler->stillRunning) {
Log::debug('Handler indicates that it is still working.');
$this->repository->setStatus($this->importJob, 'ready_to_run');
$this->repository->setStage($this->importJob, 'go-for-import');
}
$this->repository->appendTransactions($this->importJob, $transactions);
if (false === $handler->stillRunning) {
Log::info('Handler indicates that its done!');
$this->repository->setStatus($this->importJob, 'provider_finished');
$this->repository->setStage($this->importJob, 'final');
}
$this->repository->setTransactions($this->importJob, $transactions);
$this->repository->setStatus($this->importJob, 'provider_finished');
$this->repository->setStage($this->importJob, 'final');
return;
}

View File

@ -123,23 +123,6 @@ class YnabRoutine implements RoutineInterface
return;
}
// if ('match_accounts' === $this->importJob->stage) {
// // $this->repository->setStatus($this->importJob, 'running');
// /** @var StageGetBudgetsHandler $handler */
// $handler = app(StageGetBudgetsHandler::class);
// $handler->setImportJob($this->importJob);
// $handler->run();
// $this->repository->setStage($this->importJob, 'get_transactions');
// }
//
// if ('get_transactions' === $this->importJob->stage) {
// // $this->repository->setStatus($this->importJob, 'running');
// /** @var StageGetBudgetsHandler $handler */
// $handler = app(StageGetBudgetsHandler::class);
// $handler->setImportJob($this->importJob);
// $handler->run();
// $this->repository->setStage($this->importJob, 'get_transactions');
// }
throw new FireflyException(sprintf('YNAB import routine cannot handle stage "%s"', $this->importJob->stage));
}
}

View File

@ -190,7 +190,7 @@ class ImportArrayStorage
*/
private function getHash(array $transaction): string
{
unset($transaction['importHashV2']);
unset($transaction['importHashV2'], $transaction['original-source']);
$json = json_encode($transaction);
if (false === $json) {
/** @noinspection ForgottenDebugOutputInspection */

View File

@ -39,6 +39,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property string $amount
* @property int $budget_id
* @property string spent
* @property int $transaction_currency_id
*/
class BudgetLimit extends Model
{
@ -89,4 +90,13 @@ class BudgetLimit extends Model
{
return $this->belongsTo(Budget::class);
}
/**
* @codeCoverageIgnore
* @return BelongsTo
*/
public function transactionCurrency(): BelongsTo
{
return $this->belongsTo(TransactionCurrency::class);
}
}

View File

@ -46,6 +46,16 @@ class AccountRepository implements AccountRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param array $types
*

View File

@ -24,8 +24,10 @@ namespace FireflyIII\Repositories\Account;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
@ -38,6 +40,16 @@ class AccountTasker implements AccountTaskerInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param Collection $accounts
* @param Carbon $start
@ -58,18 +70,28 @@ class AccountTasker implements AccountTaskerInterface
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
/** @var CurrencyRepositoryInterface $currencyRepository */
$currencyRepository = app(CurrencyRepositoryInterface::class);
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
$return = [
'currencies' => [],
'start' => '0',
'end' => '0',
'difference' => '0',
'accounts' => [],
];
/** @var Account $account */
foreach ($accounts as $account) {
$id = $account->id;
$entry = [
$id = $account->id;
$currencyId = (int)$repository->getMetaValue($account, 'currency_id');
$currency = $currencyRepository->findNull($currencyId);
$return['currencies'][] = $currencyId;
$entry = [
'name' => $account->name,
'id' => $account->id,
'currency' => $currency ?? $defaultCurrency,
'start_balance' => '0',
'end_balance' => '0',
];
@ -90,7 +112,7 @@ class AccountTasker implements AccountTaskerInterface
$return['accounts'][$id] = $entry;
}
$return['currencies'] = count(array_unique($return['currencies']));
$return['difference'] = bcsub($return['end'], $return['start']);
return $return;
@ -196,29 +218,51 @@ class AccountTasker implements AccountTaskerInterface
*/
private function groupByOpposing(Collection $transactions): array
{
$expenses = [];
// join the result together:
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
$currencies = [$defaultCurrency->id => $defaultCurrency,];
$expenses = [];
$countAccounts = []; // if count remains 0 use original name, not the name with the currency.
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$opposingId = $transaction->opposing_account_id;
$name = $transaction->opposing_account_name;
if (!isset($expenses[$opposingId])) {
$expenses[$opposingId] = [
'id' => $opposingId,
'name' => $name,
'sum' => '0',
'average' => '0',
'count' => 0,
$opposingId = (int)$transaction->opposing_account_id;
$currencyId = (int)$transaction->transaction_currency_id;
$key = sprintf('%s-%s', $opposingId, $currencyId);
$name = sprintf('%s (%s)', $transaction->opposing_account_name, $transaction->transaction_currency_code);
$countAccounts[$opposingId] = isset($countAccounts[$opposingId]) ? $countAccounts[$opposingId] + 1 : 1;
if (!isset($expenses[$key])) {
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepos->findNull($currencyId);
$expenses[$key] = [
'id' => $opposingId,
'name' => $name,
'original' => $transaction->opposing_account_name,
'sum' => '0',
'average' => '0',
'currencies' => [],
'single_currency' => $currencies[$currencyId],
'count' => 0,
];
}
$expenses[$opposingId]['sum'] = bcadd($expenses[$opposingId]['sum'], $transaction->transaction_amount);
++$expenses[$opposingId]['count'];
$expenses[$key]['currencies'][] = (int)$transaction->transaction_currency_id;
$expenses[$key]['sum'] = bcadd($expenses[$key]['sum'], $transaction->transaction_amount);
++$expenses[$key]['count'];
}
// do averages:
$keys = array_keys($expenses);
foreach ($keys as $key) {
$opposingId = $expenses[$key]['id'];
if(1===$countAccounts[$opposingId]) {
$expenses[$key]['name'] = $expenses[$key]['original'];
}
if ($expenses[$key]['count'] > 1) {
$expenses[$key]['average'] = bcdiv($expenses[$key]['sum'], (string)$expenses[$key]['count']);
}
$expenses[$key]['currencies'] = \count(array_unique($expenses[$key]['currencies']));
$expenses[$key]['all_currencies'] = \count($currencies);
}
return $expenses;

View File

@ -45,6 +45,16 @@ class AttachmentRepository implements AttachmentRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param Attachment $attachment
*

View File

@ -48,6 +48,16 @@ class BillRepository implements BillRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param Bill $bill
*
@ -138,7 +148,7 @@ class BillRepository implements BillRepositoryInterface
public function getBillsForAccounts(Collection $accounts): Collection
{
$fields = ['bills.id', 'bills.created_at', 'bills.updated_at', 'bills.deleted_at', 'bills.user_id', 'bills.name', 'bills.match', 'bills.amount_min',
'bills.amount_max', 'bills.date', 'bills.repeat_freq', 'bills.skip', 'bills.automatch', 'bills.active', 'bills.name_encrypted',
'bills.amount_max', 'bills.date','bills.transaction_currency_id', 'bills.repeat_freq', 'bills.skip', 'bills.automatch', 'bills.active', 'bills.name_encrypted',
'bills.match_encrypted',];
$ids = $accounts->pluck('id')->toArray();
$set = $this->user->bills()
@ -199,6 +209,36 @@ class BillRepository implements BillRepositoryInterface
return $sum;
}
/**
* Get the total amount of money paid for the users active bills in the date range given,
* grouped per currency.
*
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getBillsPaidInRangePerCurrency(Carbon $start, Carbon $end): array
{
$bills = $this->getActiveBills();
$return = [];
/** @var Bill $bill */
foreach ($bills as $bill) {
/** @var Collection $set */
$set = $bill->transactionJournals()->after($start)->before($end)->get(['transaction_journals.*']);
$currencyId = (int)$bill->transaction_currency_id;
if ($set->count() > 0) {
$journalIds = $set->pluck('id')->toArray();
$amount = (string)Transaction::whereIn('transaction_journal_id', $journalIds)->where('amount', '<', 0)->sum('amount');
$return[$currencyId] = $return[$currencyId] ?? '0';
$return[$currencyId] = bcadd($amount, $return[$currencyId]);
Log::debug(sprintf('Total > 0, so add to sum %f, which becomes %f (currency %d)', $amount, $return[$currencyId], $currencyId));
}
}
return $return;
}
/**
* Get the total amount of money due for the users active bills in the date range given. This amount will be positive.
*
@ -231,6 +271,40 @@ class BillRepository implements BillRepositoryInterface
return $sum;
}
/**
* Get the total amount of money due for the users active bills in the date range given.
*
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getBillsUnpaidInRangePerCurrency(Carbon $start, Carbon $end): array
{
$bills = $this->getActiveBills();
$return = [];
/** @var Bill $bill */
foreach ($bills as $bill) {
Log::debug(sprintf('Now at bill #%d (%s)', $bill->id, $bill->name));
$dates = $this->getPayDatesInRange($bill, $start, $end);
$count = $bill->transactionJournals()->after($start)->before($end)->count();
$total = $dates->count() - $count;
$currencyId = (int)$bill->transaction_currency_id;
Log::debug(sprintf('Dates = %d, journalCount = %d, total = %d', $dates->count(), $count, $total));
if ($total > 0) {
$average = bcdiv(bcadd($bill->amount_max, $bill->amount_min), '2');
$multi = bcmul($average, (string)$total);
$return[$currencyId] = $return[$currencyId] ?? '0';
$return[$currencyId] = bcadd($return[$currencyId], $multi);
Log::debug(sprintf('Total > 0, so add to sum %f, which becomes %f (for currency %d)', $multi, $return[$currencyId], $currencyId));
}
}
return $return;
}
/**
* Get all bills with these ID's.
*

View File

@ -88,6 +88,17 @@ interface BillRepositoryInterface
*/
public function getBillsPaidInRange(Carbon $start, Carbon $end): string;
/**
* Get the total amount of money paid for the users active bills in the date range given,
* grouped per currency.
*
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getBillsPaidInRangePerCurrency(Carbon $start, Carbon $end): array;
/**
* Get the total amount of money due for the users active bills in the date range given.
*
@ -98,6 +109,16 @@ interface BillRepositoryInterface
*/
public function getBillsUnpaidInRange(Carbon $start, Carbon $end): string;
/**
* Get the total amount of money due for the users active bills in the date range given.
*
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getBillsUnpaidInRangePerCurrency(Carbon $start, Carbon $end): array;
/**
* Get all bills with these ID's.
*

View File

@ -54,6 +54,16 @@ class BudgetRepository implements BudgetRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* A method that returns the amount of money budgeted per day for this budget,
* on average.

View File

@ -47,6 +47,16 @@ class CategoryRepository implements CategoryRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param Category $category
*

View File

@ -43,10 +43,13 @@ class CurrencyRepository implements CurrencyRepositoryInterface
private $user;
/**
* CurrencyRepository constructor.
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**

View File

@ -39,6 +39,16 @@ class ExportJobRepository implements ExportJobRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param ExportJob $job
* @param string $status

View File

@ -53,6 +53,10 @@ class ImportJobRepository implements ImportJobRepositoryInterface
{
$this->maxUploadSize = (int)config('firefly.maxUploadSize');
$this->uploadDisk = Storage::disk('upload');
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
@ -73,6 +77,33 @@ class ImportJobRepository implements ImportJobRepositoryInterface
return $job;
}
/**
* Append transactions to array instead of replacing them.
*
* @param ImportJob $job
* @param array $transactions
*
* @return ImportJob
*/
public function appendTransactions(ImportJob $job, array $transactions): ImportJob
{
Log::debug(sprintf('Now in appendTransactions(%s)', $job->key));
$existingTransactions = $job->transactions;
if (!\is_array($existingTransactions)) {
$existingTransactions = [];
}
$new = array_merge($existingTransactions, $transactions);
Log::debug(sprintf('Old transaction count: %d', \count($existingTransactions)));
Log::debug(sprintf('To be added transaction count: %d', \count($transactions)));
Log::debug(sprintf('New count: %d', \count($new)));
$job->transactions = $new;
$job->save();
return $job;
}
/**
* @param string $importProvider
*
@ -352,19 +383,6 @@ class ImportJobRepository implements ImportJobRepositoryInterface
return new MessageBag;
}
/**
* @param ImportJob $job
* @param string $status
*
* @return ImportJob
*/
public function updateStatus(ImportJob $job, string $status): ImportJob
{
$job->status = $status;
$job->save();
return $job;
}
/**
* @codeCoverageIgnore

View File

@ -45,6 +45,16 @@ interface ImportJobRepositoryInterface
*/
public function addErrorMessage(ImportJob $job, string $error): ImportJob;
/**
* Append transactions to array instead of replacing them.
*
* @param ImportJob $job
* @param array $transactions
*
* @return ImportJob
*/
public function appendTransactions(ImportJob $job, array $transactions): ImportJob;
/**
* @param string $importProvider
*
@ -154,12 +164,5 @@ interface ImportJobRepositoryInterface
*/
public function storeFileUpload(ImportJob $job, string $name, UploadedFile $file): MessageBag;
/**
* @param ImportJob $job
* @param string $status
*
* @return ImportJob
*/
public function updateStatus(ImportJob $job, string $status): ImportJob;
}

View File

@ -54,6 +54,16 @@ class JournalRepository implements JournalRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/** @noinspection MoreThanThreeArgumentsInspection */
/**
* @param TransactionJournal $journal

View File

@ -40,6 +40,16 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param LinkType $linkType
*

View File

@ -44,6 +44,16 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param PiggyBank $piggyBank
* @param string $amount

View File

@ -56,6 +56,16 @@ class RecurringRepository implements RecurringRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* Destroy a recurring transaction.
*

View File

@ -29,6 +29,7 @@ use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
* Class RuleRepository.
@ -40,6 +41,16 @@ class RuleRepository implements RuleRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @return int
*/

View File

@ -27,6 +27,7 @@ use FireflyIII\Models\RuleGroup;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
use Log;
/**
* Class RuleGroupRepository.
@ -36,6 +37,16 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @return int
*/

View File

@ -43,6 +43,16 @@ class TagRepository implements TagRepositoryInterface
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @return int
*/

View File

@ -36,6 +36,16 @@ use Log;
*/
class UserRepository implements UserRepositoryInterface
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @return Collection
*/
@ -54,6 +64,8 @@ class UserRepository implements UserRepositoryInterface
{
$roleObject = Role::where('name', $role)->first();
if (null === $roleObject) {
Log::error(sprintf('Could not find role "%s" in attachRole()', $role));
return false;
}
@ -61,7 +73,7 @@ class UserRepository implements UserRepositoryInterface
$user->roles()->attach($roleObject);
} catch (QueryException $e) {
// don't care
Log::info(sprintf('Query exception when giving user a role: %s', $e->getMessage()));
Log::error(sprintf('Query exception when giving user a role: %s', $e->getMessage()));
}
return true;
@ -77,6 +89,7 @@ class UserRepository implements UserRepositoryInterface
* @see updateEmail
*
* @return bool
* @throws \Exception
*/
public function changeEmail(User $user, string $newEmail): bool
{

View File

@ -39,6 +39,16 @@ class FixerIOv2 implements ExchangeRateInterface
/** @var User */
protected $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/**
* @param TransactionCurrency $fromCurrency
* @param TransactionCurrency $toCurrency

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