mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Merge branch 'develop' into l10n_develop
This commit is contained in:
commit
a0cb51ff70
@ -41,6 +41,8 @@ SHOW_INCOMPLETE_TRANSLATIONS=false
|
||||
|
||||
CACHE_PREFIX=firefly
|
||||
|
||||
EXCHANGE_RATE_SERVICE=fixerio
|
||||
|
||||
GOOGLE_MAPS_API_KEY=
|
||||
ANALYTICS_ID=
|
||||
SITE_OWNER=mail@example.com
|
||||
|
@ -3,6 +3,7 @@ APP_DEBUG=true
|
||||
APP_FORCE_SSL=false
|
||||
APP_FORCE_ROOT=
|
||||
APP_KEY=TestTestTestTestTestTestTestTest
|
||||
APP_LOG=daily
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_URL=http://localhost
|
||||
|
||||
@ -25,7 +26,7 @@ REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_DRIVER=log
|
||||
MAIL_HOST=mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_FROM=changeme@example.com
|
||||
|
4
.github/CONTRIBUTING.md
vendored
4
.github/CONTRIBUTING.md
vendored
@ -17,3 +17,7 @@ Take the time to read the [installation guide FAQ](https://firefly-iii.github.io
|
||||
## Pull requests
|
||||
|
||||
I can only accept pull requests against the `develop` branch, never the `master` branch.
|
||||
|
||||
## Translations :us: :fr: :de:
|
||||
|
||||
If you see a spelling error, grammatical error or a weird translation in your language, please join [our CrowdIn](https://crowdin.com/project/firefly-iii) project. There, you can submit your translations and fixes. The GitHub repository will download these automatically and they will be included in the next release.
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,14 +1,7 @@
|
||||
/node_modules
|
||||
/public/storage
|
||||
/vendor
|
||||
/.idea
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
.env
|
||||
_development
|
||||
.env.local
|
||||
result.html
|
||||
test-import.sh
|
||||
test-import-report.txt
|
||||
public/google*.html
|
||||
.env.backup
|
||||
|
@ -232,27 +232,52 @@ opt/app/app/Console/Kernel.php
|
||||
opt/app/app/Exceptions/Handler.php
|
||||
opt/app/app/Generator/Chart/Basic/ChartJsGenerator.php
|
||||
opt/app/app/Generator/Chart/Basic/GeneratorInterface.php
|
||||
opt/app/app/Generator/Report/ReportGeneratorFactory.php
|
||||
opt/app/app/Generator/Report/ReportGeneratorInterface.php
|
||||
opt/app/app/Generator/Report/Standard/MonthReportGenerator.php
|
||||
opt/app/app/Helpers/Attachments/AttachmentHelper.php
|
||||
opt/app/app/Helpers/Attachments/AttachmentHelperInterface.php
|
||||
opt/app/app/Helpers/Collection/Balance.php
|
||||
opt/app/app/Helpers/Collection/BalanceEntry.php
|
||||
opt/app/app/Helpers/Collection/BalanceHeader.php
|
||||
opt/app/app/Helpers/Collection/BalanceLine.php
|
||||
opt/app/app/Helpers/Collection/Bill.php
|
||||
opt/app/app/Helpers/Collector/JournalCollector.php
|
||||
opt/app/app/Helpers/Collector/JournalCollectorInterface.php
|
||||
opt/app/app/Helpers/FiscalHelper.php
|
||||
opt/app/app/Helpers/FiscalHelperInterface.php
|
||||
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/ReportHelper.php
|
||||
opt/app/app/Helpers/Report/ReportHelperInterface.php
|
||||
opt/app/app/Http/Controllers/AccountController.php
|
||||
opt/app/app/Http/Controllers/Auth/LoginController.php
|
||||
opt/app/app/Http/Controllers/BillController.php
|
||||
opt/app/app/Http/Controllers/BudgetController.php
|
||||
opt/app/app/Http/Controllers/CategoryController.php
|
||||
opt/app/app/Http/Controllers/Chart/AccountController.php
|
||||
opt/app/app/Http/Controllers/Chart/BudgetController.php
|
||||
opt/app/app/Http/Controllers/Chart/CategoryController.php
|
||||
opt/app/app/Http/Controllers/Controller.php
|
||||
opt/app/app/Http/Controllers/HomeController.php
|
||||
opt/app/app/Http/Controllers/ImportController.php
|
||||
opt/app/app/Http/Controllers/JavascriptController.php
|
||||
opt/app/app/Http/Controllers/JsonController.php
|
||||
opt/app/app/Http/Controllers/NewUserController.php
|
||||
opt/app/app/Http/Controllers/PiggyBankController.php
|
||||
opt/app/app/Http/Controllers/ProfileController.php
|
||||
opt/app/app/Http/Controllers/Report/AccountController.php
|
||||
opt/app/app/Http/Controllers/Report/BalanceController.php
|
||||
opt/app/app/Http/Controllers/Report/BudgetController.php
|
||||
opt/app/app/Http/Controllers/Report/CategoryController.php
|
||||
opt/app/app/Http/Controllers/Report/OperationsController.php
|
||||
opt/app/app/Http/Controllers/ReportController.php
|
||||
opt/app/app/Http/Controllers/RuleController.php
|
||||
opt/app/app/Http/Controllers/TagController.php
|
||||
opt/app/app/Http/Controllers/Transaction/SingleController.php
|
||||
opt/app/app/Http/Controllers/TransactionController.php
|
||||
opt/app/app/Http/Kernel.php
|
||||
opt/app/app/Http/Middleware/Authenticate.php
|
||||
opt/app/app/Http/Middleware/AuthenticateTwoFactor.php
|
||||
@ -263,10 +288,16 @@ opt/app/app/Http/Middleware/RedirectIfAuthenticated.php
|
||||
opt/app/app/Http/Middleware/Sandstorm.php
|
||||
opt/app/app/Http/Middleware/StartFireflySession.php
|
||||
opt/app/app/Http/Middleware/VerifyCsrfToken.php
|
||||
opt/app/app/Http/Requests/BudgetFormRequest.php
|
||||
opt/app/app/Http/Requests/BudgetIncomeRequest.php
|
||||
opt/app/app/Http/Requests/CategoryFormRequest.php
|
||||
opt/app/app/Http/Requests/JournalFormRequest.php
|
||||
opt/app/app/Http/Requests/NewUserFormRequest.php
|
||||
opt/app/app/Http/Requests/PiggyBankFormRequest.php
|
||||
opt/app/app/Http/Requests/ProfileFormRequest.php
|
||||
opt/app/app/Http/Requests/ReportFormRequest.php
|
||||
opt/app/app/Http/Requests/Request.php
|
||||
opt/app/app/Http/Requests/TagFormRequest.php
|
||||
opt/app/app/Http/breadcrumbs.php
|
||||
opt/app/app/Jobs/Job.php
|
||||
opt/app/app/Jobs/MailError.php
|
||||
@ -279,9 +310,15 @@ opt/app/app/Models/Budget.php
|
||||
opt/app/app/Models/BudgetLimit.php
|
||||
opt/app/app/Models/Category.php
|
||||
opt/app/app/Models/Configuration.php
|
||||
opt/app/app/Models/Note.php
|
||||
opt/app/app/Models/PiggyBank.php
|
||||
opt/app/app/Models/PiggyBankRepetition.php
|
||||
opt/app/app/Models/Preference.php
|
||||
opt/app/app/Models/Role.php
|
||||
opt/app/app/Models/Rule.php
|
||||
opt/app/app/Models/RuleAction.php
|
||||
opt/app/app/Models/RuleGroup.php
|
||||
opt/app/app/Models/RuleTrigger.php
|
||||
opt/app/app/Models/Tag.php
|
||||
opt/app/app/Models/Transaction.php
|
||||
opt/app/app/Models/TransactionCurrency.php
|
||||
@ -317,14 +354,24 @@ opt/app/app/Repositories/Budget/BudgetRepository.php
|
||||
opt/app/app/Repositories/Budget/BudgetRepositoryInterface.php
|
||||
opt/app/app/Repositories/Category/CategoryRepository.php
|
||||
opt/app/app/Repositories/Category/CategoryRepositoryInterface.php
|
||||
opt/app/app/Repositories/Currency/CurrencyRepository.php
|
||||
opt/app/app/Repositories/Currency/CurrencyRepositoryInterface.php
|
||||
opt/app/app/Repositories/Journal/JournalRepository.php
|
||||
opt/app/app/Repositories/Journal/JournalRepositoryInterface.php
|
||||
opt/app/app/Repositories/PiggyBank/PiggyBankRepository.php
|
||||
opt/app/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php
|
||||
opt/app/app/Repositories/Rule/RuleRepository.php
|
||||
opt/app/app/Repositories/Rule/RuleRepositoryInterface.php
|
||||
opt/app/app/Repositories/RuleGroup/RuleGroupRepository.php
|
||||
opt/app/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php
|
||||
opt/app/app/Repositories/Tag/TagRepository.php
|
||||
opt/app/app/Repositories/Tag/TagRepositoryInterface.php
|
||||
opt/app/app/Repositories/User/UserRepository.php
|
||||
opt/app/app/Repositories/User/UserRepositoryInterface.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/Date.php
|
||||
opt/app/app/Support/CacheProperties.php
|
||||
opt/app/app/Support/Domain.php
|
||||
opt/app/app/Support/ExpandedForm.php
|
||||
@ -386,25 +433,40 @@ opt/app/database/seeds/PermissionSeeder.php
|
||||
opt/app/database/seeds/TransactionCurrencySeeder.php
|
||||
opt/app/database/seeds/TransactionTypeSeeder.php
|
||||
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/bootstrap-tour.min.css
|
||||
opt/app/public/css/daterangepicker.css
|
||||
opt/app/public/css/firefly.css
|
||||
opt/app/public/css/jquery-ui/jquery-ui.structure.min.css
|
||||
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/index.php
|
||||
opt/app/public/js/ff/accounts/edit.js
|
||||
opt/app/public/js/ff/bills/create.js
|
||||
opt/app/public/js/ff/budgets/index.js
|
||||
opt/app/public/js/ff/categories/index.js
|
||||
opt/app/public/js/ff/charts.defaults.js
|
||||
opt/app/public/js/ff/charts.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/index.js
|
||||
opt/app/public/js/ff/piggy-banks/create.js
|
||||
opt/app/public/js/ff/piggy-banks/index.js
|
||||
opt/app/public/js/ff/reports/default/all.js
|
||||
opt/app/public/js/ff/reports/default/month.js
|
||||
opt/app/public/js/ff/reports/index.js
|
||||
opt/app/public/js/ff/rules/index.js
|
||||
opt/app/public/js/ff/tags/create-edit.js
|
||||
opt/app/public/js/ff/tags/index.js
|
||||
opt/app/public/js/ff/transactions/list.js
|
||||
opt/app/public/js/ff/transactions/single/create.js
|
||||
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
|
||||
opt/app/public/js/lib/bootstrap-sortable.js
|
||||
opt/app/public/js/lib/bootstrap-tagsinput.min.js
|
||||
opt/app/public/js/lib/bootstrap-tour.min.js
|
||||
opt/app/public/js/lib/bootstrap3-typeahead.min.js
|
||||
@ -417,6 +479,7 @@ opt/app/public/lib/adminlte/css/AdminLTE.min.css
|
||||
opt/app/public/lib/adminlte/css/skins/skin-blue-light.min.css
|
||||
opt/app/public/lib/adminlte/js/app.min.js
|
||||
opt/app/public/lib/bootstrap/css/bootstrap.min.css
|
||||
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2
|
||||
opt/app/public/lib/bootstrap/js/bootstrap.min.js
|
||||
opt/app/public/lib/font-awesome/css/font-awesome.min.css
|
||||
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.woff2
|
||||
@ -425,9 +488,19 @@ opt/app/resources/lang/en_US/config.php
|
||||
opt/app/resources/lang/en_US/firefly.php
|
||||
opt/app/resources/lang/en_US/form.php
|
||||
opt/app/resources/lang/en_US/help.php
|
||||
opt/app/resources/lang/en_US/list.php
|
||||
opt/app/resources/lang/en_US/validation.php
|
||||
opt/app/resources/views/accounts/delete.twig
|
||||
opt/app/resources/views/accounts/edit.twig
|
||||
opt/app/resources/views/accounts/index.twig
|
||||
opt/app/resources/views/auth/login.twig
|
||||
opt/app/resources/views/bills/create.twig
|
||||
opt/app/resources/views/bills/index.twig
|
||||
opt/app/resources/views/budgets/create.twig
|
||||
opt/app/resources/views/budgets/income.twig
|
||||
opt/app/resources/views/budgets/index.twig
|
||||
opt/app/resources/views/categories/create.twig
|
||||
opt/app/resources/views/categories/index.twig
|
||||
opt/app/resources/views/emails/error-html.twig
|
||||
opt/app/resources/views/emails/error-text.twig
|
||||
opt/app/resources/views/emails/footer-html.twig
|
||||
@ -437,18 +510,31 @@ opt/app/resources/views/emails/header-text.twig
|
||||
opt/app/resources/views/error.twig
|
||||
opt/app/resources/views/form/amount.twig
|
||||
opt/app/resources/views/form/balance.twig
|
||||
opt/app/resources/views/form/checkbox.twig
|
||||
opt/app/resources/views/form/date.twig
|
||||
opt/app/resources/views/form/feedback.twig
|
||||
opt/app/resources/views/form/file.twig
|
||||
opt/app/resources/views/form/help.twig
|
||||
opt/app/resources/views/form/integer.twig
|
||||
opt/app/resources/views/form/location.twig
|
||||
opt/app/resources/views/form/multiRadio.twig
|
||||
opt/app/resources/views/form/options.twig
|
||||
opt/app/resources/views/form/select.twig
|
||||
opt/app/resources/views/form/tags.twig
|
||||
opt/app/resources/views/form/text.twig
|
||||
opt/app/resources/views/form/textarea.twig
|
||||
opt/app/resources/views/import/index.twig
|
||||
opt/app/resources/views/index.twig
|
||||
opt/app/resources/views/javascript/variables.twig
|
||||
opt/app/resources/views/json/tour.twig
|
||||
opt/app/resources/views/layout/default.twig
|
||||
opt/app/resources/views/layout/guest.twig
|
||||
opt/app/resources/views/list/accounts.twig
|
||||
opt/app/resources/views/list/bills.twig
|
||||
opt/app/resources/views/list/categories.twig
|
||||
opt/app/resources/views/list/journals-tasker.twig
|
||||
opt/app/resources/views/list/journals-tiny-tasker.twig
|
||||
opt/app/resources/views/list/piggy-banks.twig
|
||||
opt/app/resources/views/new-user/index.twig
|
||||
opt/app/resources/views/partials/boxes.twig
|
||||
opt/app/resources/views/partials/control-bar.twig
|
||||
@ -456,11 +542,25 @@ opt/app/resources/views/partials/favicons.twig
|
||||
opt/app/resources/views/partials/flashes.twig
|
||||
opt/app/resources/views/partials/menu-sidebar.twig
|
||||
opt/app/resources/views/partials/page-header.twig
|
||||
opt/app/resources/views/piggy-banks/create.twig
|
||||
opt/app/resources/views/piggy-banks/index.twig
|
||||
opt/app/resources/views/profile/change-password.twig
|
||||
opt/app/resources/views/profile/delete-account.twig
|
||||
opt/app/resources/views/profile/index.twig
|
||||
opt/app/resources/views/reports/default/month.twig
|
||||
opt/app/resources/views/reports/index.twig
|
||||
opt/app/resources/views/reports/options/no-options.twig
|
||||
opt/app/resources/views/reports/partials/accounts.twig
|
||||
opt/app/resources/views/reports/partials/balance.twig
|
||||
opt/app/resources/views/reports/partials/bills.twig
|
||||
opt/app/resources/views/reports/partials/budgets.twig
|
||||
opt/app/resources/views/reports/partials/categories.twig
|
||||
opt/app/resources/views/reports/partials/income-expenses.twig
|
||||
opt/app/resources/views/reports/partials/operations.twig
|
||||
opt/app/resources/views/rules/index.twig
|
||||
opt/app/resources/views/tags/create.twig
|
||||
opt/app/resources/views/tags/index.twig
|
||||
opt/app/resources/views/transactions/index.twig
|
||||
opt/app/resources/views/transactions/single/create.twig
|
||||
opt/app/routes/api.php
|
||||
opt/app/routes/console.php
|
||||
@ -612,6 +712,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Http/Kernel.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Logging/Log.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Mail/MailQueue.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Mail/Mailer.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Pagination/LengthAwarePaginator.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Pagination/Paginator.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Pipeline/Pipeline.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Queue/Factory.php
|
||||
@ -682,6 +783,8 @@ opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Conc
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/HasMany.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/MorphMany.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Scope.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/SoftDeletes.php
|
||||
@ -808,8 +911,11 @@ opt/app/vendor/laravel/framework/src/Illuminate/Notifications/Notifiable.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Notifications/NotificationServiceProvider.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Notifications/RoutesNotifications.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Pagination/AbstractPaginator.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Pagination/LengthAwarePaginator.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Pagination/PaginationServiceProvider.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Pagination/Paginator.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Pagination/UrlWindow.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Pagination/resources/views/default.blade.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Pipeline/PipelineServiceProvider.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php
|
||||
@ -884,12 +990,14 @@ opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/App.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Auth.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Cache.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Config.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Cookie.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Crypt.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/DB.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Event.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Gate.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Input.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Lang.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Log.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Mail.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Request.php
|
||||
@ -914,6 +1022,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Support/ViewErrorBag.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Support/helpers.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Translation/FileLoader.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Translation/LoaderInterface.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Translation/MessageSelector.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Translation/TranslationServiceProvider.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Translation/Translator.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Validation/Concerns/FormatsMessages.php
|
||||
@ -1214,14 +1323,17 @@ opt/app/vendor/twig/twig/lib/Twig/Node/Expression.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Array.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Call.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php
|
||||
opt/app/vendor/twig/twig/lib/Twig/Node/Expression/Constant.php
|
||||
|
@ -16,7 +16,7 @@ const pkgdef :Spk.PackageDefinition = (
|
||||
manifest = (
|
||||
appTitle = (defaultText = "Firefly III"),
|
||||
appVersion = 1,
|
||||
appMarketingVersion = (defaultText = "3.4.3"),
|
||||
appMarketingVersion = (defaultText = "3.4.6"),
|
||||
actions = [
|
||||
# Define your "new document" handlers here.
|
||||
( nounPhrase = (defaultText = "administration"),
|
||||
@ -97,7 +97,7 @@ const pkgdef :Spk.PackageDefinition = (
|
||||
# `spk dev` will write a list of all the files your app uses to this file.
|
||||
# You should review it later, before shipping your app.
|
||||
|
||||
alwaysInclude = [],
|
||||
alwaysInclude = ["app","bootstrap","config","database","public","resources","routes"],
|
||||
# Fill this list with more names of files or directories that should be
|
||||
# included in your package, even if not listed in sandstorm-files.list.
|
||||
# Use this to force-include stuff that you know you need but which may
|
||||
|
@ -9,7 +9,6 @@ cache:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
install:
|
||||
- if [[ "$(php -v | grep 'PHP 7')" ]]; then phpenv config-rm xdebug.ini; fi
|
||||
- rm composer.lock
|
||||
- composer update --no-scripts
|
||||
- cp .env.testing .env
|
||||
@ -18,9 +17,13 @@ install:
|
||||
- php artisan env
|
||||
- cp .env.testing .env
|
||||
- mv storage/database/databasecopy.sqlite storage/database/database.sqlite
|
||||
- mkdir -p build/logs
|
||||
|
||||
script:
|
||||
- phpunit
|
||||
- phpunit -c phpunit.xml
|
||||
|
||||
#after_success:
|
||||
# - travis_retry php vendor/bin/coveralls -x storage/build/clover.xml
|
||||
|
||||
# safelist
|
||||
branches:
|
||||
|
112
CHANGELOG.md
112
CHANGELOG.md
@ -2,10 +2,95 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [4.4.3] - 2017-05-03
|
||||
### Added
|
||||
- Added support for Slovenian
|
||||
- Removed support for Spanish. No translations whatsoever by the guy who requested it.
|
||||
- Removed support for Russian. Same thing.
|
||||
- Removed support for Croatian. Same thing.
|
||||
- Removed support for Chinese Traditional, Hong Kong. Same thing.
|
||||
|
||||
### Changed
|
||||
- The journal collector, an internal piece of code to collect transactions, now uses a slightly different method of collecting journals. This may cause problems.
|
||||
|
||||
### Fixed
|
||||
- Issue #638 as reported by [worldworm](https://github.com/worldworm).
|
||||
- Possible fix for #624
|
||||
|
||||
## [4.4.2] - 2017-04-27
|
||||
### Fixed
|
||||
- Fixed a bug where the opening balance could not be stored.
|
||||
|
||||
## [4.4.1] - 2017-04-27
|
||||
|
||||
### Added
|
||||
- Support for deployment on Heroku
|
||||
|
||||
### Fixed
|
||||
- Bug in new-user routine.
|
||||
|
||||
## [4.4.0] - 2017-04-23
|
||||
### Added
|
||||
- Firefly III can now handle foreign currencies better, including some code to get the exchange rate live from the web.
|
||||
- Can now make rules for attachments, see #608, as suggested by dzaikos.
|
||||
|
||||
### Fixed
|
||||
- Fixed #629, reported by forcaeluz
|
||||
- Fixed #630, reported by welbert
|
||||
- And more various bug fixes.
|
||||
|
||||
## [4.3.8] - 2017-04-08
|
||||
|
||||
### Added
|
||||
- Better overview / show pages.
|
||||
- #628, as reported by [xzaz](https://github.com/xzaz).
|
||||
- Greatly expanded test coverage
|
||||
|
||||
### Fixed
|
||||
- #619, as reported by [dfiel](https://github.com/dfiel).
|
||||
- #620, as reported by [forcaeluz](https://github.com/forcaeluz).
|
||||
- Attempt to fix #624, as reported by [TheSerenin](https://github.com/TheSerenin).
|
||||
- Favicon link is relative now, fixed by [welbert](https://github.com/welbert).
|
||||
- Some search bugs
|
||||
|
||||
## [4.3.7] - 2017-03-06
|
||||
### Added
|
||||
- Nice user friendly views for empty lists.
|
||||
- Extended contribution guidelines.
|
||||
- First version of financial report filtered on tags.
|
||||
- Suggested monthly savings for piggy banks, by [Zsub](https://github.com/Zsub)
|
||||
- Better test coverage.
|
||||
|
||||
### Changed
|
||||
- Slightly changed tag overview.
|
||||
- Consistent icon for bill in list.
|
||||
- Slightly changed account overview.
|
||||
|
||||
### Removed
|
||||
- Removed IDE specific views from .gitignore, issue #598
|
||||
|
||||
### Fixed
|
||||
- Force key generation during installation.
|
||||
- The `date` function takes the fieldname where a date is stored, not the literal date by [Zsub](https://github.com/Zsub)
|
||||
- Improved budget frontpage chart, as suggested by [skibbipl](https://github.com/skibbipl)
|
||||
- Issue #602 and #607, as reported by [skibbipl](https://github.com/skibbipl) and [dzaikos](https://github.com/dzaikos).
|
||||
- Issue #605, as reported by [Zsub](https://github.com/Zsub).
|
||||
- Issue #599, as reported by [leander091](https://github.com/leander091).
|
||||
- Issue #610, as reported by [skibbipl](https://github.com/skibbipl).
|
||||
- Issue #611, as reported by [ragnarkarlsson](https://github.com/ragnarkarlsson).
|
||||
- Issue #612, as reported by [ragnarkarlsson](https://github.com/ragnarkarlsson).
|
||||
- Issue #614, as reported by [worldworm](https://github.com/worldworm).
|
||||
- Various other bug fixes.
|
||||
|
||||
## [4.3.6] - 2017-02-20
|
||||
### Fixed
|
||||
- #578, reported by [xpfgsyb](https://github.com/xpfgsyb).
|
||||
|
||||
## [4.3.5] - 2017-02-19
|
||||
### Added
|
||||
- Beta support for Sandstorm.IO
|
||||
- Docker support by [@schoentoon](https://github.com/schoentoon), [@elohmeier](https://github.com/elohmeier), [@patrickkostjens](https://github.com/patrickkostjens) and [@crash7](https://github.com/crash7)!
|
||||
- Can now use special keywords in the search to search for specic dates, categories, etc.
|
||||
|
||||
### Changed
|
||||
- Updated to laravel 5.4!
|
||||
@ -153,13 +238,6 @@ An intermediate release because something in the Twig and Twigbridge libraries i
|
||||
- Updated all email messages.
|
||||
- Made some fonts local
|
||||
|
||||
|
||||
### Deprecated
|
||||
- Initial release.
|
||||
|
||||
### Removed
|
||||
- Initial release.
|
||||
|
||||
### Fixed
|
||||
- Issue #408
|
||||
- Various issues with split journals
|
||||
@ -168,11 +246,6 @@ An intermediate release because something in the Twig and Twigbridge libraries i
|
||||
- Issue #422, thx [xzaz](https://github.com/xzaz)
|
||||
- Various import bugs, such as #416 ([zjean](https://github.com/zjean))
|
||||
|
||||
|
||||
### Security
|
||||
- Initial release.
|
||||
|
||||
|
||||
## [4.1.7] - 2016-11-19
|
||||
### Added
|
||||
- Check for database table presence in console commands.
|
||||
@ -295,15 +368,6 @@ An intermediate release because something in the Twig and Twigbridge libraries i
|
||||
- New Presidents Choice specific to fix #307
|
||||
- Added some trimming (#335)
|
||||
|
||||
### Changed
|
||||
- Initial release.
|
||||
|
||||
### Deprecated
|
||||
- Initial release.
|
||||
|
||||
### Removed
|
||||
- Initial release.
|
||||
|
||||
### Fixed
|
||||
- Fixed a bug where incoming transactions would not be properly filtered in several reports.
|
||||
- #334 by [cyberkov](https://github.com/cyberkov)
|
||||
@ -311,12 +375,6 @@ An intermediate release because something in the Twig and Twigbridge libraries i
|
||||
- #336
|
||||
- #338 found by [roberthorlings](https://github.com/roberthorlings)
|
||||
|
||||
### Security
|
||||
- Initial release.
|
||||
|
||||
|
||||
|
||||
|
||||
## [4.0.0] - 2015-09-26
|
||||
### Added
|
||||
- Upgraded to Laravel 5.3, most other libraries upgraded as well.
|
||||
|
1
Procfile
Normal file
1
Procfile
Normal file
@ -0,0 +1 @@
|
||||
web: vendor/bin/heroku-php-nginx -C nginx_app.conf public/
|
12
README.md
12
README.md
@ -1,6 +1,6 @@
|
||||
# Firefly III: A personal finances manager
|
||||
|
||||
[](https://secure.php.net/downloads.php#v7.0.4) [](https://packagist.org/packages/grumpydictator/firefly-iii) [](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/?branch=master) [](https://travis-ci.org/firefly-iii/firefly-iii) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA)
|
||||
[](https://secure.php.net/downloads.php) [](https://packagist.org/packages/grumpydictator/firefly-iii) [](https://creativecommons.org/licenses/by-sa/4.0/) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA)
|
||||
|
||||
[](https://i.nder.be/h2b37243) [](https://i.nder.be/hv70pbwc)
|
||||
|
||||
@ -10,11 +10,15 @@
|
||||
|
||||
## Try it out!
|
||||
|
||||
Try out Firefly III on the [demo site](https://firefly-iii.nder.be/).
|
||||
[](https://heroku.com/deploy?template=https://github.com/firefly-iii/firefly-iii/tree/master)
|
||||
|
||||
Firefly III can be run on Heroku. Register for a free Heroku account and instantly run Firefly III on your very own cloud instance.
|
||||
|
||||
There is also a [demo site](https://firefly-iii.nder.be) with an example financial administration already present.
|
||||
|
||||
## Installation
|
||||
|
||||
To install Firefly III, you'll need a web server (preferrably on Linux) and access to the command line. Then, please read the [installation guide](https://firefly-iii.github.io/installation-guide/).
|
||||
To install Firefly III, you'll need a web server (preferrably on Linux) and access to the command line. Then, please read the [installation guide](https://firefly-iii.github.io/using-installing.html).
|
||||
|
||||
## More about Firefly III
|
||||
|
||||
@ -34,3 +38,5 @@ Firefly is pretty awesome. [You can read more about Firefly III, and its feature
|
||||
If you like Firefly and if it helps you save lots of money, why not send me [a dime for every dollar saved](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA) (this is a joke, although the Paypal form works just fine, try it!)
|
||||
|
||||
If you want to contact me, please open an issue or [email me](mailto:thegrumpydictator@gmail.com).
|
||||
|
||||
[](https://travis-ci.org/firefly-iii/firefly-iii) [](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/?branch=master) [](https://coveralls.io/github/firefly-iii/firefly-iii?branch=master)
|
||||
|
59
app.json
Normal file
59
app.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "Firefly III",
|
||||
"description": "A free and open source personal finances manager",
|
||||
"repository": "https://github.com/firefly-iii/firefly-iii",
|
||||
"logo": "https://raw.githubusercontent.com/firefly-iii/firefly-iii/master/public/mstile-150x150.png",
|
||||
"keywords": [
|
||||
"finance",
|
||||
"finances",
|
||||
"manager",
|
||||
"management",
|
||||
"euro",
|
||||
"dollar",
|
||||
"laravel",
|
||||
"money",
|
||||
"currency",
|
||||
"financials",
|
||||
"financial",
|
||||
"budgets",
|
||||
"administration",
|
||||
"tool",
|
||||
"tooling",
|
||||
"help",
|
||||
"helper",
|
||||
"assistant",
|
||||
"planning",
|
||||
"organizing",
|
||||
"bills",
|
||||
"personal finance",
|
||||
"budgets",
|
||||
"budgeting",
|
||||
"budgeting tool",
|
||||
"budgeting application",
|
||||
"transactions",
|
||||
"self hosted",
|
||||
"self-hosted",
|
||||
"transfers",
|
||||
"management"
|
||||
],
|
||||
"website": "https://firefly-iii.github.io/",
|
||||
"addons": [
|
||||
{
|
||||
"plan": "heroku-postgresql"
|
||||
}
|
||||
],
|
||||
"scripts": {
|
||||
"postdeploy": "export APP_KEY=$(php artisan --no-ansi key:generate --show)"
|
||||
},
|
||||
"buildpacks": [
|
||||
{
|
||||
"url": "heroku/php"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"APP_KEY": {
|
||||
"description": "This key is used to encrypt your data.",
|
||||
"value": "base64:If1gJN4pyycXTq+WS5TjneDympKuu+8SKvTl6RZnhJg="
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* ConfigureLogging.php
|
||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This software may be modified and distributed under the terms of the
|
||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace FireflyIII\Bootstrap;
|
||||
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Foundation\Bootstrap\ConfigureLogging as IlluminateConfigureLogging;
|
||||
use Illuminate\Log\Writer;
|
||||
|
||||
/**
|
||||
* Class ConfigureLogging
|
||||
*
|
||||
* @package FireflyIII\Bootstrap
|
||||
*/
|
||||
class ConfigureLogging extends IlluminateConfigureLogging
|
||||
{
|
||||
|
||||
/**
|
||||
* Configure the Monolog handlers for the application.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @param \Illuminate\Log\Writer $log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configureDailyHandler(Application $app, Writer $log)
|
||||
{
|
||||
$config = $app->make('config');
|
||||
|
||||
$maxFiles = $config->get('app.log_max_files');
|
||||
|
||||
$log->useDailyFiles(
|
||||
$app->storagePath() . '/logs/firefly-iii.log', is_null($maxFiles) ? 5 : $maxFiles,
|
||||
$config->get('app.log_level', 'debug')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the Monolog handlers for the application.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @param \Illuminate\Log\Writer $log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configureSingleHandler(Application $app, Writer $log)
|
||||
{
|
||||
$log->useFiles(
|
||||
$app->storagePath() . '/logs/firefly-iii.log',
|
||||
$app->make('config')->get('app.log_level', 'debug')
|
||||
);
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
@ -81,10 +81,10 @@ class CreateImport extends Command
|
||||
/** @var ImportJobRepositoryInterface $jobRepository */
|
||||
$jobRepository = app(ImportJobRepositoryInterface::class);
|
||||
$jobRepository->setUser($user);
|
||||
$job = $jobRepository->create($type);
|
||||
$job = $jobRepository->create($type);
|
||||
$this->line(sprintf('Created job "%s"...', $job->key));
|
||||
|
||||
Artisan::call('firefly:encrypt', ['file' => $file, 'key' => $job->key]);
|
||||
Artisan::call('firefly:encrypt-file', ['file' => $file, 'key' => $job->key]);
|
||||
$this->line('Stored import data...');
|
||||
|
||||
$job->configuration = $configurationData;
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
@ -58,7 +58,12 @@ class Import extends Command
|
||||
{
|
||||
Log::debug('Start start-import command');
|
||||
$jobKey = $this->argument('key');
|
||||
$job = ImportJob::whereKey($jobKey)->first();
|
||||
$job = ImportJob::where('key', $jobKey)->first();
|
||||
if (is_null($job)) {
|
||||
$this->error(sprintf('No job found with key "%s"', $jobKey));
|
||||
|
||||
return;
|
||||
}
|
||||
if (!$this->isValid($job)) {
|
||||
Log::error('Job is not valid for some reason. Exit.');
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
|
@ -9,19 +9,28 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Schema;
|
||||
|
||||
/**
|
||||
@ -60,8 +69,15 @@ class UpgradeDatabase extends Command
|
||||
{
|
||||
$this->setTransactionIdentifier();
|
||||
$this->migrateRepetitions();
|
||||
$this->repairPiggyBanks();
|
||||
$this->updateAccountCurrencies();
|
||||
$this->updateJournalCurrencies();
|
||||
$this->info('Firefly III database is up to date.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate budget repetitions to new format.
|
||||
*/
|
||||
private function migrateRepetitions()
|
||||
{
|
||||
if (!Schema::hasTable('budget_limits')) {
|
||||
@ -69,7 +85,9 @@ class UpgradeDatabase extends Command
|
||||
}
|
||||
// get all budget limits with end_date NULL
|
||||
$set = BudgetLimit::whereNull('end_date')->get();
|
||||
$this->line(sprintf('Found %d budget limit(s) to update', $set->count()));
|
||||
if ($set->count() > 0) {
|
||||
$this->line(sprintf('Found %d budget limit(s) to update', $set->count()));
|
||||
}
|
||||
/** @var BudgetLimit $budgetLimit */
|
||||
foreach ($set as $budgetLimit) {
|
||||
// get limit repetition (should be just one):
|
||||
@ -84,6 +102,37 @@ class UpgradeDatabase extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure there are only transfers linked to piggy bank events.
|
||||
*/
|
||||
private function repairPiggyBanks()
|
||||
{
|
||||
// if table does not exist, return false
|
||||
if (!Schema::hasTable('piggy_bank_events')) {
|
||||
return;
|
||||
}
|
||||
$set = PiggyBankEvent::with(['PiggyBank', 'TransactionJournal', 'TransactionJournal.TransactionType'])->get();
|
||||
/** @var PiggyBankEvent $event */
|
||||
foreach ($set as $event) {
|
||||
|
||||
if (is_null($event->transaction_journal_id)) {
|
||||
continue;
|
||||
}
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $event->transactionJournal()->first();
|
||||
if (is_null($journal)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = $journal->transactionType->type;
|
||||
if ($type !== TransactionType::TRANSFER) {
|
||||
$event->transaction_journal_id = null;
|
||||
$event->save();
|
||||
$this->line(sprintf('Piggy bank #%d was referenced by an invalid event. This has been fixed.', $event->piggy_bank_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is strangely complex, because the HAVING modifier is a no-no. And subqueries in Laravel are weird.
|
||||
*/
|
||||
@ -112,6 +161,57 @@ class UpgradeDatabase extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function updateAccountCurrencies()
|
||||
{
|
||||
$accounts = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||
->whereIn('account_types.type', [AccountType::DEFAULT, AccountType::ASSET])->get(['accounts.*']);
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
// get users preference, fall back to system pref.
|
||||
$defaultCurrencyCode = Preferences::getForUser($account->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
|
||||
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
|
||||
$accountCurrency = intval($account->getMeta('currency_id'));
|
||||
$openingBalance = $account->getOpeningBalance();
|
||||
$openingBalanceCurrency = intval($openingBalance->transaction_currency_id);
|
||||
|
||||
// both 0? set to default currency:
|
||||
if ($accountCurrency === 0 && $openingBalanceCurrency === 0) {
|
||||
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $defaultCurrency->id]);
|
||||
$this->line(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $defaultCurrencyCode));
|
||||
continue;
|
||||
}
|
||||
|
||||
// opening balance 0, account not zero? just continue:
|
||||
if ($accountCurrency > 0 && $openingBalanceCurrency === 0) {
|
||||
continue;
|
||||
}
|
||||
// account is set to 0, opening balance is not?
|
||||
if ($accountCurrency === 0 && $openingBalanceCurrency > 0) {
|
||||
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $openingBalanceCurrency]);
|
||||
$this->line(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $defaultCurrencyCode));
|
||||
continue;
|
||||
}
|
||||
|
||||
// both are equal, just continue:
|
||||
if ($accountCurrency === $openingBalanceCurrency) {
|
||||
continue;
|
||||
}
|
||||
// do not match:
|
||||
if ($accountCurrency !== $openingBalanceCurrency) {
|
||||
// update opening balance:
|
||||
$openingBalance->transaction_currency_id = $accountCurrency;
|
||||
$openingBalance->save();
|
||||
$this->line(sprintf('Account #%d ("%s") now has a correct currency for opening balance.', $account->id, $account->name));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* grab all positive transactiosn from this journal that are not deleted. for each one, grab the negative opposing one
|
||||
* which has 0 as an identifier and give it the same identifier.
|
||||
@ -151,9 +251,87 @@ class UpgradeDatabase extends Command
|
||||
$opposing->save();
|
||||
$processed[] = $transaction->id;
|
||||
$processed[] = $opposing->id;
|
||||
$this->line(sprintf('Database upgrade for journal #%d, transactions #%d and #%d', $journalId, $transaction->id, $opposing->id));
|
||||
}
|
||||
$identifier++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that withdrawals, deposits and transfers have
|
||||
* a currency setting matching their respective accounts
|
||||
*/
|
||||
private function updateJournalCurrencies()
|
||||
{
|
||||
$types = [
|
||||
TransactionType::WITHDRAWAL => '<',
|
||||
TransactionType::DEPOSIT => '>',
|
||||
];
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$notification = '%s #%d uses %s but should use %s. It has been updated. Please verify this in Firefly III.';
|
||||
$transfer = 'Transfer #%d has been updated to use the correct currencies. Please verify this in Firefly III.';
|
||||
|
||||
foreach ($types as $type => $operator) {
|
||||
$set = TransactionJournal
|
||||
::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')->leftJoin(
|
||||
'transactions', function (JoinClause $join) use ($operator) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', $operator, '0');
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
|
||||
->where('transaction_types.type', $type)
|
||||
->where('account_meta.name', 'currency_id')
|
||||
->where('transaction_journals.transaction_currency_id', '!=', DB::raw('account_meta.data'))
|
||||
->get(['transaction_journals.*', 'account_meta.data as expected_currency_id', 'transactions.amount as transaction_amount']);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($set as $journal) {
|
||||
$expectedCurrency = $repository->find(intval($journal->expected_currency_id));
|
||||
$line = sprintf($notification, $type, $journal->id, $journal->transactionCurrency->code, $expectedCurrency->code);
|
||||
|
||||
$journal->setMeta('foreign_amount', $journal->transaction_amount);
|
||||
$journal->setMeta('foreign_currency_id', $journal->transaction_currency_id);
|
||||
$journal->transaction_currency_id = $expectedCurrency->id;
|
||||
$journal->save();
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* For transfers it's slightly different. Both source and destination
|
||||
* must match the respective currency preference. So we must verify ALL
|
||||
* transactions.
|
||||
*/
|
||||
$set = TransactionJournal
|
||||
::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->where('transaction_types.type', TransactionType::TRANSFER)
|
||||
->get(['transaction_journals.*']);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($set as $journal) {
|
||||
$updated = false;
|
||||
/** @var Transaction $sourceTransaction */
|
||||
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
$sourceCurrency = $repository->find(intval($sourceTransaction->account->getMeta('currency_id')));
|
||||
|
||||
if ($sourceCurrency->id !== $journal->transaction_currency_id) {
|
||||
$updated = true;
|
||||
$journal->transaction_currency_id = $sourceCurrency->id;
|
||||
$journal->save();
|
||||
}
|
||||
|
||||
// destination
|
||||
$destinationTransaction = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
$destinationCurrency = $repository->find(intval($destinationTransaction->account->getMeta('currency_id')));
|
||||
|
||||
if ($destinationCurrency->id !== $journal->transaction_currency_id) {
|
||||
$updated = true;
|
||||
$journal->deleteMeta('foreign_amount');
|
||||
$journal->deleteMeta('foreign_currency_id');
|
||||
$journal->setMeta('foreign_amount', $destinationTransaction->amount);
|
||||
$journal->setMeta('foreign_currency_id', $destinationCurrency->id);
|
||||
}
|
||||
if ($updated) {
|
||||
$line = sprintf($transfer, $journal->id);
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
@ -84,21 +84,8 @@ class UpgradeFireflyInstructions extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a line
|
||||
*/
|
||||
private function showLine()
|
||||
private function installInstructions()
|
||||
{
|
||||
$line = '+';
|
||||
for ($i = 0; $i < 78; $i++) {
|
||||
$line .= '-';
|
||||
}
|
||||
$line .= '+';
|
||||
$this->line($line);
|
||||
|
||||
}
|
||||
|
||||
private function installInstructions() {
|
||||
/** @var string $version */
|
||||
$version = config('firefly.version');
|
||||
$config = config('upgrade.text.install');
|
||||
@ -120,6 +107,7 @@ class UpgradeFireflyInstructions extends Command
|
||||
$this->boxed('Firefly III should be ready for use.');
|
||||
$this->boxed('');
|
||||
$this->showLine();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -129,6 +117,20 @@ class UpgradeFireflyInstructions extends Command
|
||||
$this->showLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a line
|
||||
*/
|
||||
private function showLine()
|
||||
{
|
||||
$line = '+';
|
||||
for ($i = 0; $i < 78; $i++) {
|
||||
$line .= '-';
|
||||
}
|
||||
$line .= '+';
|
||||
$this->line($line);
|
||||
|
||||
}
|
||||
|
||||
private function updateInstructions()
|
||||
{
|
||||
/** @var string $version */
|
||||
@ -152,6 +154,7 @@ class UpgradeFireflyInstructions extends Command
|
||||
$this->boxed('Firefly III should be ready for use.');
|
||||
$this->boxed('');
|
||||
$this->showLine();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
@ -93,6 +93,7 @@ class VerifyDatabase extends Command
|
||||
|
||||
// report on journals with the wrong types of accounts.
|
||||
$this->reportIncorrectJournals();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,7 +132,7 @@ class VerifyDatabase extends Command
|
||||
/** @var Budget $entry */
|
||||
foreach ($set as $entry) {
|
||||
$line = sprintf(
|
||||
'Notice: User #%d (%s) has budget #%d ("%s") which has no budget limits.',
|
||||
'User #%d (%s) has budget #%d ("%s") which has no budget limits.',
|
||||
$entry->user_id, $entry->email, $entry->id, $entry->name
|
||||
);
|
||||
$this->line($line);
|
||||
@ -277,7 +278,7 @@ class VerifyDatabase extends Command
|
||||
}
|
||||
|
||||
$line = sprintf(
|
||||
'Notice: User #%d (%s) has %s #%d ("%s") which has no transactions.',
|
||||
'User #%d (%s) has %s #%d ("%s") which has no transactions.',
|
||||
$entry->user_id, $entry->email, $name, $entry->id, $objName
|
||||
);
|
||||
$this->line($line);
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console;
|
||||
|
||||
@ -41,7 +41,6 @@ class Kernel extends ConsoleKernel
|
||||
= [
|
||||
'Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables',
|
||||
'Illuminate\Foundation\Bootstrap\LoadConfiguration',
|
||||
//'FireflyIII\Bootstrap\ConfigureLogging',
|
||||
'Illuminate\Foundation\Bootstrap\HandleExceptions',
|
||||
'Illuminate\Foundation\Bootstrap\RegisterFacades',
|
||||
'Illuminate\Foundation\Bootstrap\SetRequestForConsole',
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
@ -26,7 +26,9 @@ class StoredTransactionJournal extends Event
|
||||
|
||||
use SerializesModels;
|
||||
|
||||
/** @var TransactionJournal */
|
||||
public $journal;
|
||||
/** @var int */
|
||||
public $piggyBankId;
|
||||
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
@ -26,6 +26,7 @@ class UpdatedTransactionJournal extends Event
|
||||
|
||||
use SerializesModels;
|
||||
|
||||
/** @var TransactionJournal */
|
||||
public $journal;
|
||||
|
||||
/**
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
use ErrorException;
|
||||
@ -97,6 +98,7 @@ class Handler extends ExceptionHandler
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'code' => $exception->getCode(),
|
||||
'version' => config('firefly.version'),
|
||||
];
|
||||
|
||||
// create job that will mail.
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
/**
|
||||
|
@ -9,14 +9,13 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\ExportJob;
|
||||
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Collection;
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
@ -33,13 +33,6 @@ interface CollectorInterface
|
||||
*/
|
||||
public function run(): bool;
|
||||
|
||||
/**
|
||||
* @param ExportJob $job
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function setJob(ExportJob $job);
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
@ -48,4 +41,11 @@ interface CollectorInterface
|
||||
*/
|
||||
public function setEntries(Collection $entries);
|
||||
|
||||
/**
|
||||
* @param ExportJob $job
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function setJob(ExportJob $job);
|
||||
|
||||
}
|
||||
|
@ -9,16 +9,16 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use DB;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class JournalExportCollector
|
||||
@ -118,7 +118,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
|
||||
);
|
||||
$set->each(
|
||||
function ($obj) {
|
||||
$obj->name = $obj->encrypted === 1 ? Crypt::decrypt($obj->name) : $obj->name;
|
||||
$obj->name = Steam::decrypt(intval($obj->encrypted), $obj->name);
|
||||
}
|
||||
);
|
||||
$array = [];
|
||||
@ -159,7 +159,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
|
||||
);
|
||||
$set->each(
|
||||
function ($obj) {
|
||||
$obj->name = $obj->encrypted === 1 ? Crypt::decrypt($obj->name) : $obj->name;
|
||||
$obj->name = Steam::decrypt(intval($obj->encrypted), $obj->name);
|
||||
}
|
||||
);
|
||||
$array = [];
|
||||
@ -202,7 +202,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
|
||||
);
|
||||
$set->each(
|
||||
function ($obj) {
|
||||
$obj->name = $obj->encrypted === 1 ? Crypt::decrypt($obj->name) : $obj->name;
|
||||
$obj->name = Steam::decrypt(intval($obj->encrypted), $obj->name);
|
||||
}
|
||||
);
|
||||
$array = [];
|
||||
@ -243,7 +243,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
|
||||
);
|
||||
$set->each(
|
||||
function ($obj) {
|
||||
$obj->name = $obj->encrypted === 1 ? Crypt::decrypt($obj->name) : $obj->name;
|
||||
$obj->name = Steam::decrypt(intval($obj->encrypted), $obj->name);
|
||||
}
|
||||
);
|
||||
$array = [];
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
|
@ -9,11 +9,11 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Entry;
|
||||
|
||||
use Crypt;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* To extend the exported object, in case of new features in Firefly III for example,
|
||||
@ -73,15 +73,15 @@ final class Entry
|
||||
{
|
||||
$entry = new self;
|
||||
$entry->journal_id = $object->transaction_journal_id;
|
||||
$entry->description = self::decrypt(intval($object->journal_encrypted), $object->journal_description);
|
||||
$entry->description = Steam::decrypt(intval($object->journal_encrypted), $object->journal_description);
|
||||
$entry->amount = $object->amount;
|
||||
$entry->date = $object->date;
|
||||
$entry->transaction_type = $object->transaction_type;
|
||||
$entry->currency_code = $object->transaction_currency_code;
|
||||
$entry->source_account_id = $object->account_id;
|
||||
$entry->source_account_name = self::decrypt(intval($object->account_name_encrypted), $object->account_name);
|
||||
$entry->source_account_name = Steam::decrypt(intval($object->account_name_encrypted), $object->account_name);
|
||||
$entry->destination_account_id = $object->opposing_account_id;
|
||||
$entry->destination_account_name = self::decrypt(intval($object->opposing_account_encrypted), $object->opposing_account_name);
|
||||
$entry->destination_account_name = Steam::decrypt(intval($object->opposing_account_encrypted), $object->opposing_account_name);
|
||||
$entry->category_id = $object->category_id ?? '';
|
||||
$entry->category_name = $object->category_name ?? '';
|
||||
$entry->budget_id = $object->budget_id ?? '';
|
||||
@ -95,19 +95,5 @@ final class Entry
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $isEncrypted
|
||||
* @param $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function decrypt(int $isEncrypted, $value)
|
||||
{
|
||||
if ($isEncrypted === 1) {
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Exporter;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Exporter;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Exporter;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Basic;
|
||||
|
||||
@ -81,6 +81,9 @@ class ChartJsGenerator implements GeneratorInterface
|
||||
if (isset($set['fill'])) {
|
||||
$currentSet['fill'] = $set['fill'];
|
||||
}
|
||||
if (isset($set['currency_symbol'])) {
|
||||
$currentSet['currency_symbol'] = $set['currency_symbol'];
|
||||
}
|
||||
|
||||
$chartData['datasets'][] = $currentSet;
|
||||
}
|
||||
@ -105,6 +108,10 @@ class ChartJsGenerator implements GeneratorInterface
|
||||
],
|
||||
'labels' => [],
|
||||
];
|
||||
|
||||
// sort by value, keep keys.
|
||||
asort($data);
|
||||
|
||||
$index = 0;
|
||||
foreach ($data as $key => $value) {
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Basic;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Audit;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Audit;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Audit;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Budget;
|
||||
|
||||
@ -18,6 +18,9 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Generator\Report\ReportGeneratorInterface;
|
||||
use FireflyIII\Generator\Report\Support;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
|
||||
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\TransferFilter;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -141,52 +144,10 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
* @param int $sortFlag
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getAverages(Collection $collection, int $sortFlag): array
|
||||
{
|
||||
$result = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($collection as $transaction) {
|
||||
// opposing name and ID:
|
||||
$opposingId = $transaction->opposing_account_id;
|
||||
|
||||
// is not set?
|
||||
if (!isset($result[$opposingId])) {
|
||||
$name = $transaction->opposing_account_name;
|
||||
$result[$opposingId] = [
|
||||
'name' => $name,
|
||||
'count' => 1,
|
||||
'id' => $opposingId,
|
||||
'average' => $transaction->transaction_amount,
|
||||
'sum' => $transaction->transaction_amount,
|
||||
];
|
||||
continue;
|
||||
}
|
||||
$result[$opposingId]['count']++;
|
||||
$result[$opposingId]['sum'] = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
|
||||
$result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
|
||||
}
|
||||
|
||||
// sort result by average:
|
||||
$average = [];
|
||||
foreach ($result as $key => $row) {
|
||||
$average[$key] = floatval($row['average']);
|
||||
}
|
||||
|
||||
array_multisort($average, $sortFlag, $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getExpenses(): Collection
|
||||
protected function getExpenses(): Collection
|
||||
{
|
||||
if ($this->expenses->count() > 0) {
|
||||
Log::debug('Return previous set of expenses.');
|
||||
@ -198,44 +159,18 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->setBudgets($this->budgets)->withOpposingAccount()->disableFilter();
|
||||
->setBudgets($this->budgets)->withOpposingAccount();
|
||||
$collector->removeFilter(TransferFilter::class);
|
||||
|
||||
$collector->addFilter(OpposingAccountFilter::class);
|
||||
$collector->addFilter(PositiveAmountFilter::class);
|
||||
|
||||
$accountIds = $this->accounts->pluck('id')->toArray();
|
||||
$transactions = $collector->getJournals();
|
||||
$transactions = self::filterExpenses($transactions, $accountIds);
|
||||
$this->expenses = $transactions;
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getTopExpenses(): Collection
|
||||
{
|
||||
$transactions = $this->getExpenses()->sortBy('transaction_amount');
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function summarizeByAccount(Collection $collection): array
|
||||
{
|
||||
$result = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($collection as $transaction) {
|
||||
$accountId = $transaction->account_id;
|
||||
$result[$accountId] = $result[$accountId] ?? '0';
|
||||
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
*
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Budget;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Budget;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Category;
|
||||
|
||||
@ -18,6 +18,10 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Generator\Report\ReportGeneratorInterface;
|
||||
use FireflyIII\Generator\Report\Support;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
|
||||
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\TransferFilter;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -151,52 +155,10 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
* @param int $sortFlag
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getAverages(Collection $collection, int $sortFlag): array
|
||||
{
|
||||
$result = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($collection as $transaction) {
|
||||
// opposing name and ID:
|
||||
$opposingId = $transaction->opposing_account_id;
|
||||
|
||||
// is not set?
|
||||
if (!isset($result[$opposingId])) {
|
||||
$name = $transaction->opposing_account_name;
|
||||
$result[$opposingId] = [
|
||||
'name' => $name,
|
||||
'count' => 1,
|
||||
'id' => $opposingId,
|
||||
'average' => $transaction->transaction_amount,
|
||||
'sum' => $transaction->transaction_amount,
|
||||
];
|
||||
continue;
|
||||
}
|
||||
$result[$opposingId]['count']++;
|
||||
$result[$opposingId]['sum'] = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
|
||||
$result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
|
||||
}
|
||||
|
||||
// sort result by average:
|
||||
$average = [];
|
||||
foreach ($result as $key => $row) {
|
||||
$average[$key] = floatval($row['average']);
|
||||
}
|
||||
|
||||
array_multisort($average, $sortFlag, $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getExpenses(): Collection
|
||||
protected function getExpenses(): Collection
|
||||
{
|
||||
if ($this->expenses->count() > 0) {
|
||||
Log::debug('Return previous set of expenses.');
|
||||
@ -208,11 +170,13 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
|
||||
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
||||
->setCategories($this->categories)->withOpposingAccount()->disableFilter();
|
||||
->setCategories($this->categories)->withOpposingAccount();
|
||||
$collector->removeFilter(TransferFilter::class);
|
||||
|
||||
$collector->addFilter(OpposingAccountFilter::class);
|
||||
$collector->addFilter(PositiveAmountFilter::class);
|
||||
|
||||
$accountIds = $this->accounts->pluck('id')->toArray();
|
||||
$transactions = $collector->getJournals();
|
||||
$transactions = self::filterExpenses($transactions, $accountIds);
|
||||
$this->expenses = $transactions;
|
||||
|
||||
return $transactions;
|
||||
@ -221,7 +185,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getIncome(): Collection
|
||||
protected function getIncome(): Collection
|
||||
{
|
||||
if ($this->income->count() > 0) {
|
||||
return $this->income;
|
||||
@ -232,93 +196,16 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
|
||||
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
|
||||
->setCategories($this->categories)->withOpposingAccount();
|
||||
$accountIds = $this->accounts->pluck('id')->toArray();
|
||||
|
||||
$collector->addFilter(OpposingAccountFilter::class);
|
||||
$collector->addFilter(NegativeAmountFilter::class);
|
||||
|
||||
$transactions = $collector->getJournals();
|
||||
$transactions = self::filterIncome($transactions, $accountIds);
|
||||
$this->income = $transactions;
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly five.
|
||||
* @param array $spent
|
||||
* @param array $earned
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getObjectSummary(array $spent, array $earned): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
/**
|
||||
* @var int $accountId
|
||||
* @var string $entry
|
||||
*/
|
||||
foreach ($spent as $objectId => $entry) {
|
||||
if (!isset($return[$objectId])) {
|
||||
$return[$objectId] = ['spent' => 0, 'earned' => 0];
|
||||
}
|
||||
|
||||
$return[$objectId]['spent'] = $entry;
|
||||
}
|
||||
unset($entry);
|
||||
|
||||
/**
|
||||
* @var int $accountId
|
||||
* @var string $entry
|
||||
*/
|
||||
foreach ($earned as $objectId => $entry) {
|
||||
if (!isset($return[$objectId])) {
|
||||
$return[$objectId] = ['spent' => 0, 'earned' => 0];
|
||||
}
|
||||
|
||||
$return[$objectId]['earned'] = $entry;
|
||||
}
|
||||
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getTopExpenses(): Collection
|
||||
{
|
||||
$transactions = $this->getExpenses()->sortBy('transaction_amount');
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getTopIncome(): Collection
|
||||
{
|
||||
$transactions = $this->getIncome()->sortByDesc('transaction_amount');
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function summarizeByAccount(Collection $collection): array
|
||||
{
|
||||
$result = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($collection as $transaction) {
|
||||
$accountId = $transaction->account_id;
|
||||
$result[$accountId] = $result[$accountId] ?? '0';
|
||||
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
*
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Category;
|
||||
|
||||
@ -17,7 +17,7 @@ namespace FireflyIII\Generator\Report\Category;
|
||||
/**
|
||||
* Class MultiYearReportGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Report\Audit
|
||||
* @package FireflyIII\Generator\Report\Category
|
||||
*/
|
||||
class MultiYearReportGenerator extends MonthReportGenerator
|
||||
{
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Category;
|
||||
|
||||
@ -17,7 +17,7 @@ namespace FireflyIII\Generator\Report\Category;
|
||||
/**
|
||||
* Class YearReportGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Report\Audit
|
||||
* @package FireflyIII\Generator\Report\Category
|
||||
*/
|
||||
class YearReportGenerator extends MonthReportGenerator
|
||||
{
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report;
|
||||
|
||||
@ -49,7 +49,7 @@ class ReportGeneratorFactory
|
||||
$class = sprintf('FireflyIII\Generator\Report\%s\%sReportGenerator', $type, $period);
|
||||
if (class_exists($class)) {
|
||||
/** @var ReportGeneratorInterface $obj */
|
||||
$obj = new $class;
|
||||
$obj = app($class);
|
||||
$obj->setStartDate($start);
|
||||
$obj->setEndDate($end);
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Standard;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Standard;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Standard;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report;
|
||||
|
||||
@ -25,57 +25,122 @@ use Log;
|
||||
*/
|
||||
class Support
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
* @param array $accounts
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public static function filterExpenses(Collection $collection, array $accounts): Collection
|
||||
public function getTopExpenses(): Collection
|
||||
{
|
||||
return self::filterTransactions($collection, $accounts, 1);
|
||||
$transactions = $this->getExpenses()->sortBy('transaction_amount');
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getTopIncome(): Collection
|
||||
{
|
||||
$transactions = $this->getIncome()->sortByDesc('transaction_amount');
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
* @param array $accounts
|
||||
* @param int $sortFlag
|
||||
*
|
||||
* @return Collection
|
||||
* @return array
|
||||
*/
|
||||
public static function filterIncome(Collection $collection, array $accounts): Collection
|
||||
protected function getAverages(Collection $collection, int $sortFlag): array
|
||||
{
|
||||
return self::filterTransactions($collection, $accounts, -1);
|
||||
}
|
||||
$result = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($collection as $transaction) {
|
||||
// opposing name and ID:
|
||||
$opposingId = $transaction->opposing_account_id;
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
* @param array $accounts
|
||||
* @param int $modifier
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public static function filterTransactions(Collection $collection, array $accounts, int $modifier): Collection
|
||||
{
|
||||
$result = $collection->filter(
|
||||
function (Transaction $transaction) use ($accounts, $modifier) {
|
||||
$opposing = $transaction->opposing_account_id;
|
||||
// remove internal transfer
|
||||
if (in_array($opposing, $accounts)) {
|
||||
Log::debug(sprintf('Filtered #%d because its opposite is in accounts.', $transaction->id));
|
||||
|
||||
return null;
|
||||
}
|
||||
// remove positive amount
|
||||
if (bccomp($transaction->transaction_amount, '0') === $modifier) {
|
||||
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
// is not set?
|
||||
if (!isset($result[$opposingId])) {
|
||||
$name = $transaction->opposing_account_name;
|
||||
$result[$opposingId] = [
|
||||
'name' => $name,
|
||||
'count' => 1,
|
||||
'id' => $opposingId,
|
||||
'average' => $transaction->transaction_amount,
|
||||
'sum' => $transaction->transaction_amount,
|
||||
];
|
||||
continue;
|
||||
}
|
||||
);
|
||||
$result[$opposingId]['count']++;
|
||||
$result[$opposingId]['sum'] = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
|
||||
$result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
|
||||
}
|
||||
|
||||
// sort result by average:
|
||||
$average = [];
|
||||
foreach ($result as $key => $row) {
|
||||
$average[$key] = floatval($row['average']);
|
||||
}
|
||||
|
||||
array_multisort($average, $sortFlag, $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly five.
|
||||
* @param array $spent
|
||||
* @param array $earned
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getObjectSummary(array $spent, array $earned): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
/**
|
||||
* @var int $accountId
|
||||
* @var string $entry
|
||||
*/
|
||||
foreach ($spent as $objectId => $entry) {
|
||||
if (!isset($return[$objectId])) {
|
||||
$return[$objectId] = ['spent' => 0, 'earned' => 0];
|
||||
}
|
||||
|
||||
$return[$objectId]['spent'] = $entry;
|
||||
}
|
||||
unset($entry);
|
||||
|
||||
/**
|
||||
* @var int $accountId
|
||||
* @var string $entry
|
||||
*/
|
||||
foreach ($earned as $objectId => $entry) {
|
||||
if (!isset($return[$objectId])) {
|
||||
$return[$objectId] = ['spent' => 0, 'earned' => 0];
|
||||
}
|
||||
|
||||
$return[$objectId]['earned'] = $entry;
|
||||
}
|
||||
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function summarizeByAccount(Collection $collection): array
|
||||
{
|
||||
$result = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($collection as $transaction) {
|
||||
$accountId = $transaction->account_id;
|
||||
$result[$accountId] = $result[$accountId] ?? '0';
|
||||
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
227
app/Generator/Report/Tag/MonthReportGenerator.php
Normal file
227
app/Generator/Report/Tag/MonthReportGenerator.php
Normal file
@ -0,0 +1,227 @@
|
||||
<?php
|
||||
/**
|
||||
* MonthReportGenerator.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Tag;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Generator\Report\ReportGeneratorInterface;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
|
||||
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\TransferFilter;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class MonthReportGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Report\Tag
|
||||
*/
|
||||
class MonthReportGenerator implements ReportGeneratorInterface
|
||||
{
|
||||
|
||||
/** @var Collection */
|
||||
private $accounts;
|
||||
/** @var Carbon */
|
||||
private $end;
|
||||
/** @var Collection */
|
||||
private $expenses;
|
||||
/** @var Collection */
|
||||
private $income;
|
||||
/** @var Carbon */
|
||||
private $start;
|
||||
/** @var Collection */
|
||||
private $tags;
|
||||
|
||||
/**
|
||||
* MonthReportGenerator constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->expenses = new Collection;
|
||||
$this->income = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function generate(): string
|
||||
{
|
||||
$accountIds = join(',', $this->accounts->pluck('id')->toArray());
|
||||
$tagTags = join(',', $this->tags->pluck('tag')->toArray());
|
||||
$reportType = 'tag';
|
||||
$expenses = $this->getExpenses();
|
||||
$income = $this->getIncome();
|
||||
$accountSummary = $this->getObjectSummary($this->summarizeByAccount($expenses), $this->summarizeByAccount($income));
|
||||
$tagSummary = $this->getObjectSummary($this->summarizeByTag($expenses), $this->summarizeByTag($income));
|
||||
$averageExpenses = $this->getAverages($expenses, SORT_ASC);
|
||||
$averageIncome = $this->getAverages($income, SORT_DESC);
|
||||
$topExpenses = $this->getTopExpenses();
|
||||
$topIncome = $this->getTopIncome();
|
||||
|
||||
|
||||
// render!
|
||||
return view(
|
||||
'reports.tag.month', compact(
|
||||
'accountIds', 'tagTags', 'reportType', 'accountSummary', 'tagSummary', 'averageExpenses', 'averageIncome', 'topIncome',
|
||||
'topExpenses'
|
||||
)
|
||||
)->with('start', $this->start)->with('end', $this->end)->with('tags', $this->tags)->with('accounts', $this->accounts)->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return ReportGeneratorInterface
|
||||
*/
|
||||
public function setAccounts(Collection $accounts): ReportGeneratorInterface
|
||||
{
|
||||
$this->accounts = $accounts;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $budgets
|
||||
*
|
||||
* @return ReportGeneratorInterface
|
||||
*/
|
||||
public function setBudgets(Collection $budgets): ReportGeneratorInterface
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $categories
|
||||
*
|
||||
* @return ReportGeneratorInterface
|
||||
*/
|
||||
public function setCategories(Collection $categories): ReportGeneratorInterface
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return ReportGeneratorInterface
|
||||
*/
|
||||
public function setEndDate(Carbon $date): ReportGeneratorInterface
|
||||
{
|
||||
$this->end = $date;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return ReportGeneratorInterface
|
||||
*/
|
||||
public function setStartDate(Carbon $date): ReportGeneratorInterface
|
||||
{
|
||||
$this->start = $date;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $tags
|
||||
*
|
||||
* @return ReportGeneratorInterface
|
||||
*/
|
||||
public function setTags(Collection $tags): ReportGeneratorInterface
|
||||
{
|
||||
$this->tags = $tags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
protected function getExpenses(): Collection
|
||||
{
|
||||
if ($this->expenses->count() > 0) {
|
||||
Log::debug('Return previous set of expenses.');
|
||||
|
||||
return $this->expenses;
|
||||
}
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
|
||||
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
||||
->setTags($this->tags)->withOpposingAccount();
|
||||
$collector->removeFilter(TransferFilter::class);
|
||||
|
||||
$collector->addFilter(OpposingAccountFilter::class);
|
||||
$collector->addFilter(PositiveAmountFilter::class);
|
||||
|
||||
$transactions = $collector->getJournals();
|
||||
|
||||
$this->expenses = $transactions;
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
protected function getIncome(): Collection
|
||||
{
|
||||
if ($this->income->count() > 0) {
|
||||
return $this->income;
|
||||
}
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
|
||||
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
|
||||
->setTags($this->tags)->withOpposingAccount();
|
||||
|
||||
$collector->addFilter(OpposingAccountFilter::class);
|
||||
$collector->addFilter(NegativeAmountFilter::class);
|
||||
|
||||
$transactions = $collector->getJournals();
|
||||
$this->income = $transactions;
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function summarizeByTag(Collection $collection): array
|
||||
{
|
||||
$result = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($collection as $transaction) {
|
||||
$journal = $transaction->transactionJournal;
|
||||
$journalTags = $journal->tags;
|
||||
/** @var Tag $journalTag */
|
||||
foreach ($journalTags as $journalTag) {
|
||||
$journalTagId = $journalTag->id;
|
||||
$result[$journalTagId] = $result[$journalTagId] ?? '0';
|
||||
$result[$journalTagId] = bcadd($transaction->transaction_amount, $result[$journalTagId]);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
25
app/Generator/Report/Tag/MultiYearReportGenerator.php
Normal file
25
app/Generator/Report/Tag/MultiYearReportGenerator.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* MultiYearReportGenerator.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Tag;
|
||||
|
||||
|
||||
/**
|
||||
* Class MultiYearReportGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Report\Tag
|
||||
*/
|
||||
class MultiYearReportGenerator extends MonthReportGenerator
|
||||
{
|
||||
/**
|
||||
* Doesn't do anything different.
|
||||
*/
|
||||
}
|
26
app/Generator/Report/Tag/YearReportGenerator.php
Normal file
26
app/Generator/Report/Tag/YearReportGenerator.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* YearReportGenerator.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Tag;
|
||||
|
||||
|
||||
/**
|
||||
* Class YearReportGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Report\Tag
|
||||
*/
|
||||
class YearReportGenerator extends MonthReportGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* Doesn't do anything different.
|
||||
*/
|
||||
}
|
@ -9,64 +9,96 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Events\StoredTransactionJournal;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\PiggyBankRepetition;
|
||||
use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface as JRI;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface as PRI;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface as RGRI;
|
||||
use FireflyIII\Rules\Processor;
|
||||
use FireflyIII\Support\Events\BillScanner;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class StoredJournalEventHandler
|
||||
*
|
||||
* @package FireflyIII\Handlers\Events
|
||||
*/
|
||||
class StoredJournalEventHandler
|
||||
{
|
||||
/** @var JRI */
|
||||
public $journalRepository;
|
||||
/** @var PRI */
|
||||
public $repository;
|
||||
|
||||
/** @var RGRI */
|
||||
public $ruleGroupRepository;
|
||||
|
||||
/**
|
||||
* StoredJournalEventHandler constructor.
|
||||
*/
|
||||
public function __construct(PRI $repository, JRI $journalRepository, RGRI $ruleGroupRepository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->journalRepository = $journalRepository;
|
||||
$this->ruleGroupRepository = $ruleGroupRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method connects a new transfer to a piggy bank.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param StoredTransactionJournal $event
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function connectToPiggyBank(StoredTransactionJournal $event): bool
|
||||
{
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $event->journal;
|
||||
$piggyBankId = $event->piggyBankId;
|
||||
Log::debug(sprintf('Trying to connect journal %d to piggy bank %d.', $journal->id, $piggyBankId));
|
||||
$piggyBank = $this->repository->find($piggyBankId);
|
||||
|
||||
/*
|
||||
* Verify existence of piggy bank:
|
||||
*/
|
||||
if (!$this->verifyExistence($event)) {
|
||||
Log::error(sprintf('No such piggy bank or no repetition on %s', $journal->date->format('Y-m-d')));
|
||||
// is a transfer?
|
||||
if (!$this->journalRepository->isTransfer($journal)) {
|
||||
Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get relevant data:
|
||||
*/
|
||||
$piggyBank = $journal->user->piggyBanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
|
||||
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
|
||||
$amount = $this->getExactAmount($journal, $piggyBank, $repetition);
|
||||
$repetition->currentamount = bcadd($repetition->currentamount, $amount);
|
||||
$repetition->save();
|
||||
// piggy exists?
|
||||
if (is_null($piggyBank->id)) {
|
||||
Log::error(sprintf('There is no piggy bank with ID #%d', $piggyBankId));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// repetition exists?
|
||||
$repetition = $this->repository->getRepetition($piggyBank, $journal->date);
|
||||
if (is_null($repetition->id)) {
|
||||
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the amount
|
||||
$amount = $this->repository->getExactAmount($piggyBank, $repetition, $journal);
|
||||
if (bccomp($amount, '0') === 0) {
|
||||
Log::debug('Amount is zero, will not create event.');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// update amount
|
||||
$this->repository->addAmountToRepetition($repetition, $amount);
|
||||
$event = $this->repository->createEventWithJournal($piggyBank, $amount, $journal);
|
||||
|
||||
/** @var PiggyBankEvent $event */
|
||||
$event = PiggyBankEvent::create(
|
||||
['piggy_bank_id' => $piggyBank->id, 'transaction_journal_id' => $journal->id, 'date' => $journal->date, 'amount' => $amount]
|
||||
);
|
||||
Log::debug(sprintf('Created piggy bank event #%d', $event->id));
|
||||
|
||||
return true;
|
||||
@ -83,16 +115,11 @@ class StoredJournalEventHandler
|
||||
{
|
||||
// get all the user's rule groups, with the rules, order by 'order'.
|
||||
$journal = $storedJournalEvent->journal;
|
||||
$groups = $journal->user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
|
||||
//
|
||||
$groups = $this->ruleGroupRepository->getActiveGroups($journal->user);
|
||||
|
||||
/** @var RuleGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
$rules = $group->rules()
|
||||
->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
|
||||
->where('rule_triggers.trigger_type', 'user_action')
|
||||
->where('rule_triggers.trigger_value', 'store-journal')
|
||||
->where('rules.active', 1)
|
||||
->get(['rules.*']);
|
||||
$rules = $this->ruleGroupRepository->getActiveStoreRules($group);
|
||||
/** @var Rule $rule */
|
||||
foreach ($rules as $rule) {
|
||||
|
||||
@ -100,9 +127,8 @@ class StoredJournalEventHandler
|
||||
$processor->handleTransactionJournal($journal);
|
||||
|
||||
if ($rule->stop_processing) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,81 +149,4 @@ class StoredJournalEventHandler
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's 6 but I can live with it.
|
||||
* @param TransactionJournal $journal
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param PiggyBankRepetition $repetition
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getExactAmount(TransactionJournal $journal, PiggyBank $piggyBank, PiggyBankRepetition $repetition): string
|
||||
{
|
||||
$amount = TransactionJournal::amountPositive($journal);
|
||||
$sources = TransactionJournal::sourceAccountList($journal)->pluck('id')->toArray();
|
||||
$room = bcsub(strval($piggyBank->targetamount), strval($repetition->currentamount));
|
||||
$compare = bcmul($repetition->currentamount, '-1');
|
||||
|
||||
Log::debug(sprintf('Will add/remove %f to piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name));
|
||||
|
||||
// if piggy account matches source account, the amount is positive
|
||||
if (in_array($piggyBank->account_id, $sources)) {
|
||||
$amount = bcmul($amount, '-1');
|
||||
Log::debug(sprintf('Account #%d is the source, so will remove amount from piggy bank.', $piggyBank->account_id));
|
||||
}
|
||||
|
||||
|
||||
// if the amount is positive, make sure it fits in piggy bank:
|
||||
if (bccomp($amount, '0') === 1 && bccomp($room, $amount) === -1) {
|
||||
// amount is positive and $room is smaller than $amount
|
||||
Log::debug(sprintf('Room in piggy bank for extra money is %f', $room));
|
||||
Log::debug(sprintf('There is NO room to add %f to piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name));
|
||||
Log::debug(sprintf('New amount is %f', $room));
|
||||
|
||||
return $room;
|
||||
}
|
||||
|
||||
// amount is negative and $currentamount is smaller than $amount
|
||||
if (bccomp($amount, '0') === -1 && bccomp($compare, $amount) === 1) {
|
||||
Log::debug(sprintf('Max amount to remove is %f', $repetition->currentamount));
|
||||
Log::debug(sprintf('Cannot remove %f from piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name));
|
||||
Log::debug(sprintf('New amount is %f', $compare));
|
||||
|
||||
return $compare;
|
||||
}
|
||||
|
||||
return $amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StoredTransactionJournal $event
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function verifyExistence(StoredTransactionJournal $event): bool
|
||||
{
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $event->journal;
|
||||
$piggyBankId = $event->piggyBankId;
|
||||
|
||||
/** @var PiggyBank $piggyBank */
|
||||
$piggyBank = $journal->user->piggyBanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
|
||||
|
||||
if (is_null($piggyBank)) {
|
||||
Log::error('No such piggy bank!');
|
||||
|
||||
return false;
|
||||
}
|
||||
Log::debug(sprintf('Found piggy bank #%d: "%s"', $piggyBank->id, $piggyBank->name));
|
||||
// update piggy bank rep for date of transaction journal.
|
||||
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
|
||||
if (is_null($repetition)) {
|
||||
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
@ -17,16 +17,29 @@ namespace FireflyIII\Handlers\Events;
|
||||
use FireflyIII\Events\UpdatedTransactionJournal;
|
||||
use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleGroup;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||
use FireflyIII\Rules\Processor;
|
||||
use FireflyIII\Support\Events\BillScanner;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class UpdatedJournalEventHandler
|
||||
*
|
||||
* @package FireflyIII\Handlers\Events
|
||||
*/
|
||||
class UpdatedJournalEventHandler
|
||||
{
|
||||
/** @var RuleGroupRepositoryInterface */
|
||||
public $repository;
|
||||
|
||||
/**
|
||||
* StoredJournalEventHandler constructor.
|
||||
*/
|
||||
public function __construct(RuleGroupRepositoryInterface $ruleGroupRepository)
|
||||
{
|
||||
$this->repository = $ruleGroupRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will check all the rules when a journal is updated.
|
||||
@ -39,16 +52,11 @@ class UpdatedJournalEventHandler
|
||||
{
|
||||
// get all the user's rule groups, with the rules, order by 'order'.
|
||||
$journal = $updatedJournalEvent->journal;
|
||||
$groups = $journal->user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
|
||||
//
|
||||
$groups = $this->repository->getActiveGroups($journal->user);
|
||||
|
||||
/** @var RuleGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
$rules = $group->rules()
|
||||
->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
|
||||
->where('rule_triggers.trigger_type', 'user_action')
|
||||
->where('rule_triggers.trigger_value', 'update-journal')
|
||||
->where('rules.active', 1)
|
||||
->get(['rules.*']);
|
||||
$rules = $this->repository->getActiveUpdateRules($group);
|
||||
/** @var Rule $rule */
|
||||
foreach ($rules as $rule) {
|
||||
$processor = Processor::make($rule);
|
||||
|
@ -9,17 +9,17 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Events\RegisteredUser;
|
||||
use FireflyIII\Events\RequestedNewPassword;
|
||||
use FireflyIII\Mail\RegisteredUser as RegisteredUserMail;
|
||||
use FireflyIII\Mail\RequestedNewPassword as RequestedNewPasswordMail;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Illuminate\Mail\Message;
|
||||
use Log;
|
||||
use Mail;
|
||||
use Session;
|
||||
use Swift_TransportException;
|
||||
|
||||
/**
|
||||
@ -54,20 +54,6 @@ class UserEventHandler
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle user logout events.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function logoutUser(): bool
|
||||
{
|
||||
// dump stuff from the session:
|
||||
Session::forget('twofactor-authenticated');
|
||||
Session::forget('twofactor-authenticated-date');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestedNewPassword $event
|
||||
*
|
||||
@ -83,14 +69,12 @@ class UserEventHandler
|
||||
|
||||
// send email.
|
||||
try {
|
||||
Mail::send(
|
||||
['emails.password-html', 'emails.password-text'], ['url' => $url, 'ip' => $ipAddress], function (Message $message) use ($email) {
|
||||
$message->to($email, $email)->subject('Your password reset request');
|
||||
}
|
||||
);
|
||||
Mail::to($email)->send(new RequestedNewPasswordMail($url, $ipAddress));
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Swift_TransportException $e) {
|
||||
Log::error($e->getMessage());
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -108,22 +92,21 @@ class UserEventHandler
|
||||
|
||||
$sendMail = env('SEND_REGISTRATION_MAIL', true);
|
||||
if (!$sendMail) {
|
||||
return true;
|
||||
return true; // @codeCoverageIgnore
|
||||
}
|
||||
// get the email address
|
||||
$email = $event->user->email;
|
||||
$address = route('index');
|
||||
$ipAddress = $event->ipAddress;
|
||||
|
||||
// send email.
|
||||
try {
|
||||
Mail::send(
|
||||
['emails.registered-html', 'emails.registered-text'], ['address' => $address, 'ip' => $ipAddress], function (Message $message) use ($email) {
|
||||
$message->to($email, $email)->subject('Welcome to Firefly III!');
|
||||
}
|
||||
);
|
||||
Mail::to($email)->send(new RegisteredUserMail($address, $ipAddress));
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Swift_TransportException $e) {
|
||||
Log::error($e->getMessage());
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -9,16 +9,18 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Attachments;
|
||||
|
||||
use Crypt;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use Storage;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
use Log;
|
||||
/**
|
||||
* Class AttachmentHelper
|
||||
*
|
||||
@ -27,6 +29,8 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
class AttachmentHelper implements AttachmentHelperInterface
|
||||
{
|
||||
|
||||
/** @var Collection */
|
||||
public $attachments;
|
||||
/** @var MessageBag */
|
||||
public $errors;
|
||||
/** @var MessageBag */
|
||||
@ -45,9 +49,10 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
public function __construct()
|
||||
{
|
||||
$this->maxUploadSize = intval(config('firefly.maxUploadSize'));
|
||||
$this->allowedMimes = (array) config('firefly.allowedMimes');
|
||||
$this->allowedMimes = (array)config('firefly.allowedMimes');
|
||||
$this->errors = new MessageBag;
|
||||
$this->messages = new MessageBag;
|
||||
$this->attachments = new Collection;
|
||||
$this->uploadDisk = Storage::disk('upload');
|
||||
}
|
||||
|
||||
@ -63,6 +68,14 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAttachments(): Collection
|
||||
{
|
||||
return $this->attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MessageBag
|
||||
*/
|
||||
@ -109,7 +122,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
$md5 = md5_file($file->getRealPath());
|
||||
$name = $file->getClientOriginalName();
|
||||
$class = get_class($model);
|
||||
$count = auth()->user()->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
|
||||
$count = $model->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
|
||||
|
||||
if ($count > 0) {
|
||||
$msg = (string)trans('validation.file_already_attached', ['name' => $name]);
|
||||
@ -136,7 +149,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
}
|
||||
|
||||
$attachment = new Attachment; // create Attachment object.
|
||||
$attachment->user()->associate(auth()->user());
|
||||
$attachment->user()->associate($model->user);
|
||||
$attachment->attachable()->associate($model);
|
||||
$attachment->md5 = md5_file($file->getRealPath());
|
||||
$attachment->filename = $file->getClientOriginalName();
|
||||
@ -155,6 +168,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
|
||||
$attachment->uploaded = 1; // update attachment
|
||||
$attachment->save();
|
||||
$this->attachments->push($attachment);
|
||||
|
||||
$name = e($file->getClientOriginalName()); // add message:
|
||||
$msg = (string)trans('validation.file_attached', ['name' => $name]);
|
||||
@ -187,6 +201,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @param UploadedFile $file
|
||||
*
|
||||
* @return bool
|
||||
@ -217,7 +232,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
return false;
|
||||
}
|
||||
if (!$this->validSize($file)) {
|
||||
return false;
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
if ($this->hasFile($file, $model)) {
|
||||
return false;
|
||||
|
@ -9,11 +9,13 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Attachments;
|
||||
|
||||
use FireflyIII\Models\Attachment;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
|
||||
/**
|
||||
@ -31,6 +33,11 @@ interface AttachmentHelperInterface
|
||||
*/
|
||||
public function getAttachmentLocation(Attachment $attachment): string;
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAttachments(): Collection;
|
||||
|
||||
/**
|
||||
* @return MessageBag
|
||||
*/
|
||||
@ -42,7 +49,9 @@ interface AttachmentHelperInterface
|
||||
public function getMessages(): MessageBag;
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
* @param Model $model
|
||||
*
|
||||
* @param null|array $files
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -7,18 +7,23 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Chart;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Generator\Report\Support;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
|
||||
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\TransferFilter;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Steam;
|
||||
@ -46,19 +51,20 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
'account' => ['opposing_account_id'],
|
||||
'budget' => ['transaction_journal_budget_id', 'transaction_budget_id'],
|
||||
'category' => ['transaction_journal_category_id', 'transaction_category_id'],
|
||||
'tag' => [],
|
||||
];
|
||||
|
||||
/** @var array */
|
||||
protected $repositories
|
||||
= [
|
||||
'account' => AccountRepositoryInterface::class,
|
||||
'budget' => BudgetRepositoryInterface::class,
|
||||
'category' => CategoryRepositoryInterface::class,
|
||||
'tag' => TagRepositoryInterface::class,
|
||||
];
|
||||
|
||||
|
||||
/** @var Carbon */
|
||||
protected $start;
|
||||
/** @var Collection */
|
||||
protected $tags;
|
||||
/** @var string */
|
||||
protected $total = '0';
|
||||
/** @var User */
|
||||
@ -69,6 +75,7 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
$this->accounts = new Collection;
|
||||
$this->budgets = new Collection;
|
||||
$this->categories = new Collection;
|
||||
$this->tags = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,6 +106,7 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
if ($this->collectOtherObjects && $direction === 'income') {
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setUser($this->user);
|
||||
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)->setTypes([TransactionType::DEPOSIT]);
|
||||
$journals = $collector->getJournals();
|
||||
$sum = strval($journals->sum('transaction_amount'));
|
||||
@ -111,6 +119,8 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return MetaPieChartInterface
|
||||
@ -123,6 +133,8 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Collection $budgets
|
||||
*
|
||||
* @return MetaPieChartInterface
|
||||
@ -135,6 +147,8 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Collection $categories
|
||||
*
|
||||
* @return MetaPieChartInterface
|
||||
@ -147,6 +161,8 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param bool $collectOtherObjects
|
||||
*
|
||||
* @return MetaPieChartInterface
|
||||
@ -159,6 +175,8 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return MetaPieChartInterface
|
||||
@ -171,6 +189,8 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Carbon $start
|
||||
*
|
||||
* @return MetaPieChartInterface
|
||||
@ -183,6 +203,22 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Collection $tags
|
||||
*
|
||||
* @return MetaPieChartInterface
|
||||
*/
|
||||
public function setTags(Collection $tags): MetaPieChartInterface
|
||||
{
|
||||
$this->tags = $tags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @return MetaPieChartInterface
|
||||
@ -194,23 +230,32 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getTransactions(string $direction)
|
||||
/**
|
||||
* @param string $direction
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
protected function getTransactions(string $direction): Collection
|
||||
{
|
||||
$types = [TransactionType::DEPOSIT, TransactionType::TRANSFER];
|
||||
$modifier = -1;
|
||||
if ($direction === 'expense') {
|
||||
$types = [TransactionType::WITHDRAWAL, TransactionType::TRANSFER];
|
||||
$modifier = 1;
|
||||
}
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$types = [TransactionType::DEPOSIT, TransactionType::TRANSFER];
|
||||
$collector->addFilter(NegativeAmountFilter::class);
|
||||
if ($direction === 'expense') {
|
||||
$types = [TransactionType::WITHDRAWAL, TransactionType::TRANSFER];
|
||||
$collector->addFilter(PositiveAmountFilter::class);
|
||||
$collector->removeFilter(NegativeAmountFilter::class);
|
||||
}
|
||||
|
||||
$collector->setUser($this->user);
|
||||
$collector->setAccounts($this->accounts);
|
||||
$collector->setRange($this->start, $this->end);
|
||||
$collector->setTypes($types);
|
||||
$collector->withOpposingAccount();
|
||||
$collector->addFilter(OpposingAccountFilter::class);
|
||||
|
||||
if ($direction === 'income') {
|
||||
$collector->disableFilter();
|
||||
$collector->removeFilter(TransferFilter::class);
|
||||
}
|
||||
|
||||
if ($this->budgets->count() > 0) {
|
||||
@ -219,12 +264,13 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
if ($this->categories->count() > 0) {
|
||||
$collector->setCategories($this->categories);
|
||||
}
|
||||
if ($this->tags->count() > 0) {
|
||||
$collector->setTags($this->tags);
|
||||
$collector->withCategoryInformation();
|
||||
$collector->withBudgetInformation();
|
||||
}
|
||||
|
||||
$accountIds = $this->accounts->pluck('id')->toArray();
|
||||
$transactions = $collector->getJournals();
|
||||
$set = Support::filterTransactions($transactions, $accountIds, $modifier);
|
||||
|
||||
return $set;
|
||||
return $collector->getJournals();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -233,8 +279,13 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function groupByFields(Collection $set, array $fields)
|
||||
protected function groupByFields(Collection $set, array $fields): array
|
||||
{
|
||||
if (count($fields) === 0 && $this->tags->count() > 0) {
|
||||
// do a special group on tags:
|
||||
return $this->groupByTag($set);
|
||||
}
|
||||
|
||||
$grouped = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
@ -261,10 +312,11 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
$chartData = [];
|
||||
$names = [];
|
||||
$repository = app($this->repositories[$type]);
|
||||
$repository->setUser($this->user);
|
||||
foreach ($array as $objectId => $amount) {
|
||||
if (!isset($names[$objectId])) {
|
||||
$object = $repository->find(intval($objectId));
|
||||
$names[$objectId] = $object->name;
|
||||
$names[$objectId] = $object->name ?? $object->tag;
|
||||
}
|
||||
$amount = Steam::positive($amount);
|
||||
$this->total = bcadd($this->total, $amount);
|
||||
@ -274,4 +326,27 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
return $chartData;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function groupByTag(Collection $set): array
|
||||
{
|
||||
$grouped = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
$journal = $transaction->transactionJournal;
|
||||
$tags = $journal->tags;
|
||||
/** @var Tag $tag */
|
||||
foreach ($tags as $tag) {
|
||||
$tagId = $tag->id;
|
||||
$grouped[$tagId] = $grouped[$tagId] ?? '0';
|
||||
$grouped[$tagId] = bcadd($transaction->transaction_amount, $grouped[$tagId]);
|
||||
}
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Chart;
|
||||
|
||||
@ -72,6 +72,13 @@ interface MetaPieChartInterface
|
||||
*/
|
||||
public function setStart(Carbon $start): MetaPieChartInterface;
|
||||
|
||||
/**
|
||||
* @param Collection $tags
|
||||
*
|
||||
* @return MetaPieChartInterface
|
||||
*/
|
||||
public function setTags(Collection $tags): MetaPieChartInterface;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Account as AccountModel;
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Account as AccountModel;
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Category as CategoryModel;
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector;
|
||||
|
||||
@ -18,12 +18,17 @@ use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use DB;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Filter\FilterInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
|
||||
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\TransferFilter;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
@ -74,6 +79,9 @@ class JournalCollector implements JournalCollectorInterface
|
||||
private $filterInternalTransfers;
|
||||
/** @var bool */
|
||||
private $filterTransfers = false;
|
||||
/** @var array */
|
||||
private $filters = [InternalTransferFilter::class];
|
||||
|
||||
/** @var bool */
|
||||
private $joinedBudget = false;
|
||||
/** @var bool */
|
||||
@ -95,6 +103,22 @@ class JournalCollector implements JournalCollectorInterface
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @param string $filter
|
||||
*
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function addFilter(string $filter): JournalCollectorInterface
|
||||
{
|
||||
$interfaces = class_implements($filter);
|
||||
if (in_array(FilterInterface::class, $interfaces)) {
|
||||
Log::debug(sprintf('Enabled filter %s', $filter));
|
||||
$this->filters[] = $filter;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @throws FireflyException
|
||||
@ -119,36 +143,6 @@ class JournalCollector implements JournalCollectorInterface
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function disableFilter(): JournalCollectorInterface
|
||||
{
|
||||
$this->filterTransfers = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function disableInternalFilter(): JournalCollectorInterface
|
||||
{
|
||||
$this->filterInternalTransfers = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function enableInternalFilter(): JournalCollectorInterface
|
||||
{
|
||||
$this->filterInternalTransfers = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@ -157,23 +151,18 @@ class JournalCollector implements JournalCollectorInterface
|
||||
$this->run = true;
|
||||
/** @var Collection $set */
|
||||
$set = $this->query->get(array_values($this->fields));
|
||||
Log::debug(sprintf('Count of set is %d', $set->count()));
|
||||
$set = $this->filterTransfers($set);
|
||||
Log::debug(sprintf('Count of set after filterTransfers() is %d', $set->count()));
|
||||
|
||||
// possibly filter "internal" transfers:
|
||||
$set = $this->filterInternalTransfers($set);
|
||||
Log::debug(sprintf('Count of set after filterInternalTransfers() is %d', $set->count()));
|
||||
|
||||
// run all filters:
|
||||
$set = $this->filter($set);
|
||||
|
||||
// loop for decryption.
|
||||
$set->each(
|
||||
function (Transaction $transaction) {
|
||||
$transaction->date = new Carbon($transaction->date);
|
||||
$transaction->description = $transaction->encrypted ? Crypt::decrypt($transaction->description) : $transaction->description;
|
||||
$transaction->description = Steam::decrypt(intval($transaction->encrypted), $transaction->description);
|
||||
|
||||
if (!is_null($transaction->bill_name)) {
|
||||
$transaction->bill_name = $transaction->bill_name_encrypted ? Crypt::decrypt($transaction->bill_name) : $transaction->bill_name;
|
||||
$transaction->bill_name = Steam::decrypt(intval($transaction->bill_name_encrypted), $transaction->bill_name);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -204,6 +193,22 @@ class JournalCollector implements JournalCollectorInterface
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filter
|
||||
*
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function removeFilter(string $filter): JournalCollectorInterface
|
||||
{
|
||||
$key = array_search($filter, $this->filters, true);
|
||||
if (!($key === false)) {
|
||||
Log::debug(sprintf('Removed filter %s', $filter));
|
||||
unset($this->filters[$key]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
*
|
||||
@ -219,6 +224,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
}
|
||||
|
||||
if ($accounts->count() > 1) {
|
||||
$this->addFilter(TransferFilter::class);
|
||||
$this->filterTransfers = true;
|
||||
}
|
||||
|
||||
@ -242,6 +248,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
}
|
||||
|
||||
if ($accounts->count() > 1) {
|
||||
$this->addFilter(TransferFilter::class);
|
||||
$this->filterTransfers = true;
|
||||
}
|
||||
|
||||
@ -430,6 +437,20 @@ class JournalCollector implements JournalCollectorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $tags
|
||||
*
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function setTags(Collection $tags): JournalCollectorInterface
|
||||
{
|
||||
$this->joinTagTables();
|
||||
$tagIds = $tags->pluck('id')->toArray();
|
||||
$this->query->whereIn('tag_transaction_journal.tag_id', $tagIds);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
@ -450,7 +471,9 @@ class JournalCollector implements JournalCollectorInterface
|
||||
*/
|
||||
public function setUser(User $user)
|
||||
{
|
||||
Log::debug(sprintf('Journal collector now collecting for user #%d', $user->id));
|
||||
$this->user = $user;
|
||||
$this->startQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -458,6 +481,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
*/
|
||||
public function startQuery()
|
||||
{
|
||||
Log::debug('journalCollector::startQuery');
|
||||
/** @var EloquentBuilder $query */
|
||||
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
|
||||
@ -503,6 +527,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
public function withOpposingAccount(): JournalCollectorInterface
|
||||
{
|
||||
$this->joinOpposingTables();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -545,79 +570,23 @@ class JournalCollector implements JournalCollectorInterface
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function filterInternalTransfers(Collection $set): Collection
|
||||
private function filter(Collection $set): Collection
|
||||
{
|
||||
if ($this->filterInternalTransfers === false) {
|
||||
Log::debug('Did NO filtering for internal transfers on given set.');
|
||||
|
||||
return $set;
|
||||
}
|
||||
if ($this->joinedOpposing === false) {
|
||||
Log::info('Cannot filter internal transfers because no opposing information is present.');
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
$accountIds = $this->accountIds;
|
||||
$set = $set->filter(
|
||||
function (Transaction $transaction) use ($accountIds) {
|
||||
// both id's in $accountids?
|
||||
if (in_array($transaction->account_id, $accountIds) && in_array($transaction->opposing_account_id, $accountIds)) {
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Transaction #%d has #%d and #%d in set, so removed',
|
||||
$transaction->id, $transaction->account_id, $transaction->opposing_account_id
|
||||
), $accountIds
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
|
||||
// create all possible filters:
|
||||
$filters = [
|
||||
InternalTransferFilter::class => new InternalTransferFilter($this->accountIds),
|
||||
OpposingAccountFilter::class => new OpposingAccountFilter($this->accountIds),
|
||||
TransferFilter::class => new TransferFilter,
|
||||
PositiveAmountFilter::class => new PositiveAmountFilter,
|
||||
NegativeAmountFilter::class => new NegativeAmountFilter,
|
||||
];
|
||||
Log::debug(sprintf('Will run %d filters on the set.', count($this->filters)));
|
||||
foreach ($this->filters as $enabled) {
|
||||
if (isset($filters[$enabled])) {
|
||||
Log::debug(sprintf('Before filter %s: %d', $enabled, $set->count()));
|
||||
$set = $filters[$enabled]->filter($set);
|
||||
Log::debug(sprintf('After filter %s: %d', $enabled, $set->count()));
|
||||
}
|
||||
);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the set of accounts used by the collector includes more than one asset
|
||||
* account, chances are the set include double entries: transfers get selected
|
||||
* on both the source, and then again on the destination account.
|
||||
*
|
||||
* This method filters them out by removing transfers that have been selected twice.
|
||||
*
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function filterTransfers(Collection $set): Collection
|
||||
{
|
||||
if ($this->filterTransfers) {
|
||||
$count = [];
|
||||
$new = new Collection;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
if ($transaction->transaction_type_type !== TransactionType::TRANSFER) {
|
||||
$new->push($transaction);
|
||||
continue;
|
||||
}
|
||||
// make property string:
|
||||
$journalId = $transaction->transaction_journal_id;
|
||||
$amount = Steam::positive($transaction->transaction_amount);
|
||||
$accountIds = [intval($transaction->account_id), intval($transaction->opposing_account_id)];
|
||||
sort($accountIds);
|
||||
$key = $journalId . '-' . join(',', $accountIds) . '-' . $amount;
|
||||
Log::debug(sprintf('Key is %s', $key));
|
||||
if (!isset($count[$key])) {
|
||||
// not yet counted? add to new set and count it:
|
||||
$new->push($transaction);
|
||||
$count[$key] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
return $set;
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector;
|
||||
|
||||
@ -28,26 +28,18 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface JournalCollectorInterface
|
||||
{
|
||||
/**
|
||||
* @param string $filter
|
||||
*
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function addFilter(string $filter): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int;
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function disableFilter(): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function disableInternalFilter(): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function enableInternalFilter(): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@ -58,6 +50,13 @@ interface JournalCollectorInterface
|
||||
*/
|
||||
public function getPaginatedJournals(): LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* @param string $filter
|
||||
*
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function removeFilter(string $filter): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
*
|
||||
@ -141,6 +140,13 @@ interface JournalCollectorInterface
|
||||
*/
|
||||
public function setTag(Tag $tag): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @param Collection $tags
|
||||
*
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function setTags(Collection $tags): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
|
56
app/Helpers/Filter/AmountFilter.php
Normal file
56
app/Helpers/Filter/AmountFilter.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* AmountFilter.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Filter;
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class AmountFilter
|
||||
*
|
||||
* This filter removes transactions with either a positive amount ($parameters = 1) or a negative amount
|
||||
* ($parameter = -1). This is helpful when a Collection has you with both transactions in a journal.
|
||||
*
|
||||
* @package FireflyIII\Helpers\Filter
|
||||
*/
|
||||
class AmountFilter implements FilterInterface
|
||||
{
|
||||
/** @var int */
|
||||
private $modifier = 0;
|
||||
|
||||
public function __construct(int $modifier)
|
||||
{
|
||||
$this->modifier = $modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter(Collection $set): Collection
|
||||
{
|
||||
return $set->filter(
|
||||
function (Transaction $transaction) {
|
||||
// remove by amount
|
||||
if (bccomp($transaction->transaction_amount, '0') === $this->modifier) {
|
||||
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
34
app/Helpers/Filter/EmptyFilter.php
Normal file
34
app/Helpers/Filter/EmptyFilter.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* EmptyFilter.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Filter;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class EmptyFilter
|
||||
*
|
||||
* @package FireflyIII\Helpers\Filter
|
||||
*/
|
||||
class EmptyFilter implements FilterInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter(Collection $set): Collection
|
||||
{
|
||||
return $set;
|
||||
}
|
||||
}
|
26
app/Helpers/Filter/FilterInterface.php
Normal file
26
app/Helpers/Filter/FilterInterface.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* FilterInterface.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Filter;
|
||||
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface FilterInterface
|
||||
{
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter(Collection $set): Collection;
|
||||
|
||||
}
|
73
app/Helpers/Filter/InternalTransferFilter.php
Normal file
73
app/Helpers/Filter/InternalTransferFilter.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* InternalTransferFilter.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Filter;
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class InternalTransferFilter
|
||||
*
|
||||
* This filter removes any filters that are from A to B or from B to A given a set of
|
||||
* account id's (in $parameters) where A and B are mentioned. So transfers between the mentioned
|
||||
* accounts will be removed.
|
||||
*
|
||||
* @package FireflyIII\Helpers\Filter
|
||||
*/
|
||||
class InternalTransferFilter implements FilterInterface
|
||||
{
|
||||
/** @var array */
|
||||
private $accounts = [];
|
||||
|
||||
/**
|
||||
* InternalTransferFilter constructor.
|
||||
*
|
||||
* @param array $accounts
|
||||
*/
|
||||
public function __construct(array $accounts)
|
||||
{
|
||||
$this->accounts = $accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter(Collection $set): Collection
|
||||
{
|
||||
return $set->filter(
|
||||
function (Transaction $transaction) {
|
||||
if (is_null($transaction->opposing_account_id)) {
|
||||
return $transaction;
|
||||
}
|
||||
// both id's in $parameters?
|
||||
if (in_array($transaction->account_id, $this->accounts) && in_array($transaction->opposing_account_id, $this->accounts)) {
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Transaction #%d has #%d and #%d in set, so removed',
|
||||
$transaction->id, $transaction->account_id, $transaction->opposing_account_id
|
||||
), $this->accounts
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
}
|
47
app/Helpers/Filter/NegativeAmountFilter.php
Normal file
47
app/Helpers/Filter/NegativeAmountFilter.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* NegativeAmountFilter.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Filter;
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class NegativeAmountFilter
|
||||
*
|
||||
* This filter removes entries with a negative amount (the original modifier is -1).
|
||||
*
|
||||
* @package FireflyIII\Helpers\Filter
|
||||
*/
|
||||
class NegativeAmountFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter(Collection $set): Collection
|
||||
{
|
||||
return $set->filter(
|
||||
function (Transaction $transaction) {
|
||||
// remove by amount
|
||||
if (bccomp($transaction->transaction_amount, '0') === -1) {
|
||||
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
63
app/Helpers/Filter/OpposingAccountFilter.php
Normal file
63
app/Helpers/Filter/OpposingAccountFilter.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* OpposingAccountFilter.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Filter;
|
||||
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class OpposingAccountFilter
|
||||
*
|
||||
* This filter is similar to the internal transfer filter but only removes transactions when the opposing account is
|
||||
* amongst $parameters (list of account ID's).
|
||||
*
|
||||
* @package FireflyIII\Helpers\Filter
|
||||
*/
|
||||
class OpposingAccountFilter implements FilterInterface
|
||||
{
|
||||
/** @var array */
|
||||
private $accounts = [];
|
||||
|
||||
/**
|
||||
* InternalTransferFilter constructor.
|
||||
*
|
||||
* @param array $accounts
|
||||
*/
|
||||
public function __construct(array $accounts)
|
||||
{
|
||||
$this->accounts = $accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter(Collection $set): Collection
|
||||
{
|
||||
return $set->filter(
|
||||
function (Transaction $transaction) {
|
||||
$opposing = $transaction->opposing_account_id;
|
||||
// remove internal transfer
|
||||
if (in_array($opposing, $this->accounts)) {
|
||||
Log::debug(sprintf('Filtered #%d because its opposite is in accounts.', $transaction->id), $this->accounts);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
50
app/Helpers/Filter/PositiveAmountFilter.php
Normal file
50
app/Helpers/Filter/PositiveAmountFilter.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* PositiveAmountFilter.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Filter;
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class PositiveAmountFilter
|
||||
*
|
||||
* This filter removes entries with a negative amount (the original modifier is -1).
|
||||
*
|
||||
* This filter removes transactions with either a positive amount ($parameters = 1) or a negative amount
|
||||
* ($parameter = -1). This is helpful when a Collection has you with both transactions in a journal.
|
||||
*
|
||||
* @package FireflyIII\Helpers\Filter
|
||||
*/
|
||||
class PositiveAmountFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter(Collection $set): Collection
|
||||
{
|
||||
return $set->filter(
|
||||
function (Transaction $transaction) {
|
||||
// remove by amount
|
||||
if (bccomp($transaction->transaction_amount, '0') === 1) {
|
||||
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
58
app/Helpers/Filter/TransferFilter.php
Normal file
58
app/Helpers/Filter/TransferFilter.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* TransferFilter.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Filter;
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class TransferFilter
|
||||
*
|
||||
* This filter removes any transfers that are in the collection twice (from A to B and from B to A).
|
||||
*
|
||||
* @package FireflyIII\Helpers\Filter
|
||||
*/
|
||||
class TransferFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter(Collection $set): Collection
|
||||
{
|
||||
$count = [];
|
||||
$new = new Collection;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
if ($transaction->transaction_type_type !== TransactionType::TRANSFER) {
|
||||
$new->push($transaction);
|
||||
continue;
|
||||
}
|
||||
// make property string:
|
||||
$journalId = $transaction->transaction_journal_id;
|
||||
$amount = Steam::positive($transaction->transaction_amount);
|
||||
$accountIds = [intval($transaction->account_id), intval($transaction->opposing_account_id)];
|
||||
sort($accountIds);
|
||||
$key = $journalId . '-' . join(',', $accountIds) . '-' . $amount;
|
||||
if (!isset($count[$key])) {
|
||||
// not yet counted? add to new set and count it:
|
||||
$new->push($transaction);
|
||||
$count[$key] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers;
|
||||
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
use Cache;
|
||||
@ -43,12 +44,12 @@ class Help implements HelpInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $language
|
||||
* @param string $route
|
||||
* @param string $language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromGithub(string $language, string $route): string
|
||||
public function getFromGithub(string $route, string $language): string
|
||||
{
|
||||
|
||||
$uri = sprintf('https://raw.githubusercontent.com/firefly-iii/help/master/%s/%s.md', $language, $route);
|
||||
@ -123,6 +124,7 @@ class Help implements HelpInterface
|
||||
if (strlen($content) > 0) {
|
||||
Log::debug(sprintf('Will store entry in cache: %s', $key));
|
||||
Cache::put($key, $content, 10080); // a week.
|
||||
|
||||
return;
|
||||
}
|
||||
Log::info(sprintf('Will not cache %s because content is empty.', $key));
|
||||
|
@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
/**
|
||||
@ -29,12 +30,12 @@ interface HelpInterface
|
||||
public function getFromCache(string $route, string $language): string;
|
||||
|
||||
/**
|
||||
* @param string $language
|
||||
* @param string $route
|
||||
* @param string $language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromGithub(string $language, string $route): string;
|
||||
public function getFromGithub(string $route, string $language): string;
|
||||
|
||||
/**
|
||||
* @param string $route
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
@ -158,7 +158,9 @@ class BalanceReportHelper implements BalanceReportHelperInterface
|
||||
foreach ($accounts as $account) {
|
||||
$balanceEntry = new BalanceEntry;
|
||||
$balanceEntry->setAccount($account);
|
||||
$spent = $this->budgetRepository->spentInPeriod(new Collection([$budgetLimit->budget]), new Collection([$account]), $budgetLimit->start_date, $budgetLimit->end_date);
|
||||
$spent = $this->budgetRepository->spentInPeriod(
|
||||
new Collection([$budgetLimit->budget]), new Collection([$account]), $budgetLimit->start_date, $budgetLimit->end_date
|
||||
);
|
||||
$balanceEntry->setSpent($spent);
|
||||
$line->addBalanceEntry($balanceEntry);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
|
199
app/Helpers/Report/PopupReport.php
Normal file
199
app/Helpers/Report/PopupReport.php
Normal file
@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/**
|
||||
* PopupReport.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class PopupReport
|
||||
*
|
||||
* @package FireflyIII\Helpers\Report
|
||||
*/
|
||||
class PopupReport implements PopupReportInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param $account
|
||||
* @param $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceDifference($account, $attributes): Collection
|
||||
{
|
||||
// row that displays difference
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->withoutBudget();
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
|
||||
return $journals->filter(
|
||||
function (Transaction $transaction) {
|
||||
$tags = $transaction->transactionJournal->tags()->where('tagMode', 'balancingAct')->count();
|
||||
if ($tags === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceForBudget(Budget $budget, Account $account, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])->setBudget($budget);
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceForNoBudget(Account $account, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->withoutBudget();
|
||||
|
||||
return $collector->getJournals();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byBudget(Budget $budget, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
|
||||
$collector->setAccounts($attributes['accounts'])->setRange($attributes['startDate'], $attributes['endDate']);
|
||||
|
||||
if (is_null($budget->id)) {
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL])->withoutBudget();
|
||||
}
|
||||
if (!is_null($budget->id)) {
|
||||
$collector->setBudget($budget);
|
||||
}
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byCategory(Category $category, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts($attributes['accounts'])->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->setCategory($category);
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byExpenses(Account $account, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]);
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
|
||||
|
||||
// filter for transfers and withdrawals TO the given $account
|
||||
$journals = $journals->filter(
|
||||
function (Transaction $transaction) use ($report) {
|
||||
// get the destinations:
|
||||
$sources = $transaction->transactionJournal->sourceAccountList()->pluck('id')->toArray();
|
||||
|
||||
// do these intersect with the current list?
|
||||
return !empty(array_intersect($report, $sources));
|
||||
}
|
||||
);
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byIncome(Account $account, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$journals = $collector->getJournals();
|
||||
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
|
||||
|
||||
// filter the set so the destinations outside of $attributes['accounts'] are not included.
|
||||
$journals = $journals->filter(
|
||||
function (Transaction $transaction) use ($report) {
|
||||
// get the destinations:
|
||||
$destinations = $transaction->destinationAccountList($transaction->transactionJournal)->pluck('id')->toArray();
|
||||
|
||||
// do these intersect with the current list?
|
||||
return !empty(array_intersect($report, $destinations));
|
||||
}
|
||||
);
|
||||
|
||||
return $journals;
|
||||
}
|
||||
}
|
83
app/Helpers/Report/PopupReportInterface.php
Normal file
83
app/Helpers/Report/PopupReportInterface.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* PopupReportInterface.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface PopupReportInterface
|
||||
*
|
||||
* @package FireflyIII\Helpers\Report
|
||||
*/
|
||||
interface PopupReportInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $account
|
||||
* @param $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceDifference($account, $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceForBudget(Budget $budget, Account $account, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceForNoBudget(Account $account, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byBudget(Budget $budget, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byCategory(Category $category, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byExpenses(Account $account, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byIncome(Account $account, array $attributes): Collection;
|
||||
}
|
@ -9,22 +9,19 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collection\Bill as BillCollection;
|
||||
use FireflyIII\Helpers\Collection\BillLine;
|
||||
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\FiscalHelperInterface;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
|
@ -9,13 +9,12 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collection\Bill as BillCollection;
|
||||
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
|
||||
use FireflyIII\Helpers\Collection\Expense;
|
||||
use FireflyIII\Helpers\Collection\Income;
|
||||
use Illuminate\Support\Collection;
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
@ -22,16 +22,16 @@ use FireflyIII\Http\Requests\AccountFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Account\AccountTaskerInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use Steam;
|
||||
use View;
|
||||
|
||||
@ -61,46 +61,49 @@ class AccountController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $what
|
||||
* @param Request $request
|
||||
* @param string $what
|
||||
*
|
||||
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory|View
|
||||
* @return View
|
||||
*/
|
||||
public function create(string $what = 'asset')
|
||||
public function create(Request $request, string $what = 'asset')
|
||||
{
|
||||
/** @var CurrencyRepositoryInterface $repository */
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$currencies = ExpandedForm::makeSelectList($repository->get());
|
||||
$defaultCurrency = Amount::getDefaultCurrency();
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
||||
$roles = [];
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$allCurrencies = $repository->get();
|
||||
$currencySelectList = ExpandedForm::makeSelectList($allCurrencies);
|
||||
$defaultCurrency = Amount::getDefaultCurrency();
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
||||
$roles = [];
|
||||
foreach (config('firefly.accountRoles') as $role) {
|
||||
$roles[$role] = strval(trans('firefly.account_role_' . $role));
|
||||
}
|
||||
|
||||
|
||||
// pre fill some data
|
||||
Session::flash('preFilled', ['currency_id' => $defaultCurrency->id,]);
|
||||
$request->session()->flash('preFilled', ['currency_id' => $defaultCurrency->id,]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (session('accounts.create.fromStore') !== true) {
|
||||
$this->rememberPreviousUri('accounts.create.uri');
|
||||
}
|
||||
Session::forget('accounts.create.fromStore');
|
||||
Session::flash('gaEventCategory', 'accounts');
|
||||
Session::flash('gaEventAction', 'create-' . $what);
|
||||
$request->session()->forget('accounts.create.fromStore');
|
||||
$request->session()->flash('gaEventCategory', 'accounts');
|
||||
$request->session()->flash('gaEventAction', 'create-' . $what);
|
||||
|
||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'currencies', 'roles'));
|
||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'currencySelectList', 'allCurrencies', 'roles'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function delete(AccountRepositoryInterface $repository, Account $account)
|
||||
public function delete(Request $request, AccountRepositoryInterface $repository, Account $account)
|
||||
{
|
||||
$typeName = config('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
$subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
|
||||
@ -109,16 +112,16 @@ class AccountController extends Controller
|
||||
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('accounts.delete.uri');
|
||||
Session::flash('gaEventCategory', 'accounts');
|
||||
Session::flash('gaEventAction', 'delete-' . $typeName);
|
||||
$request->session()->flash('gaEventCategory', 'accounts');
|
||||
$request->session()->flash('gaEventAction', 'delete-' . $typeName);
|
||||
|
||||
return view('accounts.delete', compact('account', 'subTitle', 'accountList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
* @param Request $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
@ -131,27 +134,28 @@ class AccountController extends Controller
|
||||
|
||||
$repository->destroy($account, $moveTo);
|
||||
|
||||
Session::flash('success', strval(trans('firefly.' . $typeName . '_deleted', ['name' => $name])));
|
||||
$request->session()->flash('success', strval(trans('firefly.' . $typeName . '_deleted', ['name' => $name])));
|
||||
Preferences::mark();
|
||||
|
||||
return redirect($this->getPreviousUri('accounts.delete.uri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function edit(Account $account)
|
||||
public function edit(Request $request, Account $account)
|
||||
{
|
||||
|
||||
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
|
||||
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
/** @var CurrencyRepositoryInterface $repository */
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$currencies = ExpandedForm::makeSelectList($repository->get());
|
||||
$roles = [];
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
|
||||
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$allCurrencies = $repository->get();
|
||||
$currencySelectList = ExpandedForm::makeSelectList($allCurrencies);
|
||||
$roles = [];
|
||||
foreach (config('firefly.accountRoles') as $role) {
|
||||
$roles[$role] = strval(trans('firefly.account_role_' . $role));
|
||||
}
|
||||
@ -161,7 +165,7 @@ class AccountController extends Controller
|
||||
if (session('accounts.edit.fromUpdate') !== true) {
|
||||
$this->rememberPreviousUri('accounts.edit.uri');
|
||||
}
|
||||
Session::forget('accounts.edit.fromUpdate');
|
||||
$request->session()->forget('accounts.edit.fromUpdate');
|
||||
|
||||
// pre fill some useful values.
|
||||
|
||||
@ -170,6 +174,7 @@ class AccountController extends Controller
|
||||
$openingBalanceAmount = $account->getOpeningBalanceAmount() === '0' ? '' : $openingBalanceAmount;
|
||||
$openingBalanceDate = $account->getOpeningBalanceDate();
|
||||
$openingBalanceDate = $openingBalanceDate->year === 1900 ? null : $openingBalanceDate->format('Y-m-d');
|
||||
$currency = $repository->find(intval($account->getMeta('currency_id')));
|
||||
|
||||
$preFilled = [
|
||||
'accountNumber' => $account->getMeta('accountNumber'),
|
||||
@ -180,18 +185,23 @@ class AccountController extends Controller
|
||||
'openingBalanceDate' => $openingBalanceDate,
|
||||
'openingBalance' => $openingBalanceAmount,
|
||||
'virtualBalance' => $account->virtual_balance,
|
||||
'currency_id' => $account->getMeta('currency_id'),
|
||||
];
|
||||
Session::flash('preFilled', $preFilled);
|
||||
Session::flash('gaEventCategory', 'accounts');
|
||||
Session::flash('gaEventAction', 'edit-' . $what);
|
||||
'currency_id' => $currency->id,
|
||||
|
||||
return view('accounts.edit', compact('currencies', 'account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what', 'roles'));
|
||||
];
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
$request->session()->flash('gaEventCategory', 'accounts');
|
||||
$request->session()->flash('gaEventAction', 'edit-' . $what);
|
||||
|
||||
return view(
|
||||
'accounts.edit', compact(
|
||||
'allCurrencies', 'currencySelectList', 'account', 'currency', 'subTitle', 'subTitleIcon', 'openingBalance', 'what', 'roles'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param string $what
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param string $what
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
@ -225,106 +235,104 @@ class AccountController extends Controller
|
||||
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param JournalCollectorInterface $collector
|
||||
* @param Account $account
|
||||
* @param Request $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
* @param string $moment
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
*/
|
||||
public function show(Request $request, JournalCollectorInterface $collector, Account $account)
|
||||
public function show(Request $request, JournalRepositoryInterface $repository, Account $account, string $moment = '')
|
||||
{
|
||||
if ($account->accountType->type === AccountType::INITIAL_BALANCE) {
|
||||
return $this->redirectToOriginalAccount($account);
|
||||
}
|
||||
// show journals from current period only:
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||
$subTitle = $account->name;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$chartUri = route('chart.account.single', [$account->id]);
|
||||
$accountType = $account->accountType->type;
|
||||
/** @var CurrencyRepositoryInterface $currencyRepos */
|
||||
$currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$chartUri = route('chart.account.single', [$account->id]);
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
$currency = $currencyRepos->find(intval($account->getMeta('currency_id')));
|
||||
|
||||
// grab those journals:
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->setLimit($pageSize)->setPage($page);
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('accounts/show/' . $account->id);
|
||||
// prep for "all" view.
|
||||
if ($moment === 'all') {
|
||||
$subTitle = trans('firefly.all_journals_for_account', ['name' => $account->name]);
|
||||
$chartUri = route('chart.account.all', [$account->id]);
|
||||
$first = $repository->first();
|
||||
$start = $first->date ?? new Carbon;
|
||||
$end = new Carbon;
|
||||
}
|
||||
|
||||
// generate entries for each period (and cache those)
|
||||
$entries = $this->periodEntries($account);
|
||||
// prep for "specific date" view.
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$start = new Carbon($moment);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d')]);
|
||||
$periods = $this->getPeriodOverview($account);
|
||||
}
|
||||
|
||||
return view('accounts.show', compact('account', 'accountType', 'entries', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
|
||||
// prep for current period
|
||||
if (strlen($moment) === 0) {
|
||||
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getPeriodOverview($account);
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$loop = 0;
|
||||
// grab journals, but be prepared to jump a period back to get the right ones:
|
||||
Log::info('Now at loop start.');
|
||||
while ($count === 0 && $loop < 3) {
|
||||
$loop++;
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
Log::info('Count is zero, search for journals.');
|
||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
|
||||
if (!is_null($start)) {
|
||||
$collector->setRange($start, $end);
|
||||
}
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('accounts/show/' . $account->id . '/' . $moment);
|
||||
$count = $journals->getCollection()->count();
|
||||
if ($count === 0) {
|
||||
$start->subDay();
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
}
|
||||
}
|
||||
|
||||
if ($moment != 'all' && $loop > 1) {
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return view(
|
||||
'accounts.show',
|
||||
compact('account', 'currency', 'moment', 'periods', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function showAll(Request $request, AccountRepositoryInterface $repository, Account $account)
|
||||
{
|
||||
$subTitle = sprintf('%s (%s)', $account->name, strtolower(trans('firefly.everything')));
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$chartUri = route('chart.account.all', [$account->id]);
|
||||
|
||||
// replace with journal collector:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setUser(auth()->user());
|
||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('accounts/show/' . $account->id . '/all');
|
||||
|
||||
// get oldest and newest journal for account:
|
||||
$start = $repository->oldestJournalDate($account);
|
||||
$end = $repository->newestJournalDate($account);
|
||||
|
||||
// same call, except "entries".
|
||||
return view('accounts.show', compact('account', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
* @param string $date
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function showByDate(Request $request, Account $account, string $date)
|
||||
{
|
||||
$carbon = new Carbon($date);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($carbon, $range);
|
||||
$end = Navigation::endOfPeriod($carbon, $range);
|
||||
$subTitle = $account->name . ' (' . Navigation::periodShow($start, $range) . ')';
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$chartUri = route('chart.account.period', [$account->id, $carbon->format('Y-m-d')]);
|
||||
$accountType = $account->accountType->type;
|
||||
|
||||
// replace with journal collector:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->setLimit($pageSize)->setPage($page);
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('accounts/show/' . $account->id . '/' . $date);
|
||||
|
||||
// generate entries for each period (and cache those)
|
||||
$entries = $this->periodEntries($account);
|
||||
|
||||
// same call, except "entries".
|
||||
return view('accounts.show', compact('account', 'accountType', 'entries', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountFormRequest $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param AccountFormRequest $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*
|
||||
@ -333,8 +341,7 @@ class AccountController extends Controller
|
||||
{
|
||||
$data = $request->getAccountData();
|
||||
$account = $repository->store($data);
|
||||
|
||||
Session::flash('success', strval(trans('firefly.stored_new_account', ['name' => $account->name])));
|
||||
$request->session()->flash('success', strval(trans('firefly.stored_new_account', ['name' => $account->name])));
|
||||
Preferences::mark();
|
||||
|
||||
// update preferences if necessary:
|
||||
@ -346,7 +353,7 @@ class AccountController extends Controller
|
||||
|
||||
if (intval($request->get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('accounts.create.fromStore', true);
|
||||
$request->session()->put('accounts.create.fromStore', true);
|
||||
|
||||
return redirect(route('accounts.create', [$request->input('what')]))->withInput();
|
||||
}
|
||||
@ -356,9 +363,9 @@ class AccountController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountFormRequest $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
* @param AccountFormRequest $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
@ -367,12 +374,12 @@ class AccountController extends Controller
|
||||
$data = $request->getAccountData();
|
||||
$repository->update($account, $data);
|
||||
|
||||
Session::flash('success', strval(trans('firefly.updated_account', ['name' => $account->name])));
|
||||
$request->session()->flash('success', strval(trans('firefly.updated_account', ['name' => $account->name])));
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('accounts.edit.fromUpdate', true);
|
||||
$request->session()->put('accounts.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('accounts.edit', [$account->id]))->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
@ -407,18 +414,15 @@ class AccountController extends Controller
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function periodEntries(Account $account): Collection
|
||||
private function getPeriodOverview(Account $account): Collection
|
||||
{
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
/** @var AccountTaskerInterface $tasker */
|
||||
$tasker = app(AccountTaskerInterface::class);
|
||||
|
||||
$start = $repository->oldestJournalDate($account);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfX(new Carbon, $range);
|
||||
$entries = new Collection;
|
||||
$start = $repository->oldestJournalDate($account);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfX(new Carbon, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
@ -428,25 +432,39 @@ class AccountController extends Controller
|
||||
$cache->addProperty($account->id);
|
||||
|
||||
if ($cache->has()) {
|
||||
Log::debug('Entries are cached, return cache.');
|
||||
|
||||
return $cache->get();
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// only include asset accounts when this account is an asset:
|
||||
$assets = new Collection;
|
||||
if (in_array($account->accountType->type, [AccountType::ASSET, AccountType::DEFAULT])) {
|
||||
$assets = $repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]);
|
||||
}
|
||||
Log::debug('Going to get period expenses and incomes.');
|
||||
while ($end >= $start) {
|
||||
$end = Navigation::startOfPeriod($end, $range);
|
||||
$currentEnd = Navigation::endOfPeriod($end, $range);
|
||||
$spent = $tasker->amountOutInPeriod(new Collection([$account]), $assets, $end, $currentEnd);
|
||||
$earned = $tasker->amountInInPeriod(new Collection([$account]), $assets, $end, $currentEnd);
|
||||
$dateStr = $end->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($end, $range);
|
||||
$entries->push([$dateStr, $dateName, $spent, $earned, clone $end]);
|
||||
|
||||
// try a collector for income:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($end, $currentEnd)
|
||||
->setTypes([TransactionType::DEPOSIT])
|
||||
->withOpposingAccount();
|
||||
$earned = strval($collector->getJournals()->sum('transaction_amount'));
|
||||
|
||||
// try a collector for expenses:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($end, $currentEnd)
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->withOpposingAccount();
|
||||
$spent = strval($collector->getJournals()->sum('transaction_amount'));
|
||||
$dateStr = $end->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($end, $range);
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'date' => clone $end]
|
||||
);
|
||||
$end = Navigation::subtractPeriod($end, $range, 1);
|
||||
|
||||
}
|
||||
@ -474,7 +492,7 @@ class AccountController extends Controller
|
||||
$opposingTransaction = $journal->transactions()->where('transactions.id', '!=', $transaction->id)->first();
|
||||
|
||||
if (is_null($opposingTransaction)) {
|
||||
throw new FireflyException('Expected an opposing transaction. This account has none. BEEP, error.');
|
||||
throw new FireflyException('Expected an opposing transaction. This account has none. BEEP, error.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return redirect(route('accounts.show', [$opposingTransaction->account_id]));
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
@ -18,6 +18,7 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\UserFormRequest;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use View;
|
||||
@ -124,34 +125,34 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserFormRequest $request
|
||||
* @param User $user
|
||||
* @param UserFormRequest $request
|
||||
* @param User $user
|
||||
*
|
||||
* @param UserRepositoryInterface $repository
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function update(UserFormRequest $request, User $user)
|
||||
public function update(UserFormRequest $request, User $user, UserRepositoryInterface $repository)
|
||||
{
|
||||
Log::debug('Actually here');
|
||||
$data = $request->getUserData();
|
||||
|
||||
// update password
|
||||
if (strlen($data['password']) > 0) {
|
||||
$user->password = bcrypt($data['password']);
|
||||
$user->save();
|
||||
$repository->changePassword($user, $data['password']);
|
||||
}
|
||||
|
||||
// change blocked status and code:
|
||||
$user->blocked = $data['blocked'];
|
||||
$user->blocked_code = $data['blocked_code'];
|
||||
$user->save();
|
||||
$repository->changeStatus($user, $data['blocked'], $data['blocked_code']);
|
||||
|
||||
Session::flash('success', strval(trans('firefly.updated_user', ['email' => $user->email])));
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('users.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('admin.users.edit', [$user->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user