mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Merge branch 'release/4.7.1'
This commit is contained in:
commit
03f46638e1
28
.env.docker
28
.env.docker
@ -3,10 +3,10 @@
|
||||
APP_ENV=${FF_APP_ENV}
|
||||
|
||||
# Set to true if you want to see debug information in error screens.
|
||||
APP_DEBUG=false
|
||||
APP_DEBUG=${APP_DEBUG}
|
||||
|
||||
# This should be your email address
|
||||
SITE_OWNER=mail@example.com
|
||||
SITE_OWNER=${SITE_OWNER}
|
||||
|
||||
# The encryption key for your database and sessions. Keep this very secure.
|
||||
# If you generate a new one all existing data must be considered LOST.
|
||||
@ -29,13 +29,13 @@ DB_PASSWORD=${FF_DB_PASSWORD}
|
||||
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
|
||||
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
|
||||
# Also available are 'syslog' and 'errorlog' which will log to the system itself.
|
||||
APP_LOG=daily
|
||||
APP_LOG=syslog
|
||||
|
||||
# Log level. You can set this from least severe to most severe:
|
||||
# debug, info, notice, warning, error, critical, alert, emergency
|
||||
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
|
||||
# nothing will get logged, ever.
|
||||
APP_LOG_LEVEL=warning
|
||||
APP_LOG_LEVEL=info
|
||||
|
||||
# If you're looking for performance improvements, you could install memcached.
|
||||
CACHE_DRIVER=file
|
||||
@ -47,23 +47,23 @@ COOKIE_DOMAIN=
|
||||
COOKIE_SECURE=false
|
||||
|
||||
# If you want Firefly III to mail you, update these settings
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_FROM=changeme@example.com
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_DRIVER=${MAIL_DRIVER}
|
||||
MAIL_HOST=${MAIL_HOST}
|
||||
MAIL_PORT=${MAIL_PORT}
|
||||
MAIL_FROM=${MAIL_FROM}
|
||||
MAIL_USERNAME=${MAIL_USERNAME}
|
||||
MAIL_PASSWORD=${MAIL_PASSWORD}
|
||||
MAIL_ENCRYPTION=${MAIL_ENCRYPTION}
|
||||
|
||||
# Firefly III can send you the following messages
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=true
|
||||
SEND_ERROR_MESSAGE=false
|
||||
|
||||
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
|
||||
MAPBOX_API_KEY=
|
||||
MAPBOX_API_KEY=${MAPBOX_API_KEY}
|
||||
|
||||
# If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here.
|
||||
ANALYTICS_ID=
|
||||
ANALYTICS_ID=${ANALYTICS_ID}
|
||||
|
||||
# Most parts of the database are encrypted by default, but you can turn this off if you want to.
|
||||
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
|
||||
|
@ -27,7 +27,7 @@ REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_DRIVER=log
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_FROM=changeme@example.com
|
||||
@ -36,7 +36,7 @@ MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=true
|
||||
SEND_ERROR_MESSAGE=false
|
||||
|
||||
CACHE_PREFIX=firefly
|
||||
|
||||
|
@ -1,3 +1,19 @@
|
||||
# 4.7.1
|
||||
- A brand new API. Read about it in the [documentation](http://firefly-iii.readthedocs.io/en/latest/).
|
||||
- Add support for Spanish. [issue 1194](https://github.com/firefly-iii/firefly-iii/issues/1194)
|
||||
- Some custom preferences are selected by default for a better user experience.
|
||||
- Some new currencies [issue 1211](https://github.com/firefly-iii/firefly-iii/issues/1211)
|
||||
- Fixed [issue 1155](https://github.com/firefly-iii/firefly-iii/issues/1155) (reported by [ndandanov](https://github.com/ndandanov))
|
||||
- [Issue 1156](https://github.com/firefly-iii/firefly-iii/issues/1156) [issue 1182](https://github.com/firefly-iii/firefly-iii/issues/1182) and other issues related to SQLite databases.
|
||||
- Multi-page budget overview was broken (reported by [jinformatique](https://github.com/jinformatique))
|
||||
- Importing CSV files with semi-colons in them did not work [issue 1172](https://github.com/firefly-iii/firefly-iii/issues/1172) [issue 1183](https://github.com/firefly-iii/firefly-iii/issues/1183) [issue 1210](https://github.com/firefly-iii/firefly-iii/issues/1210)
|
||||
- Could not use account number that was in use by a deleted account [issue 1174](https://github.com/firefly-iii/firefly-iii/issues/1174)
|
||||
- Fixed spelling error that lead to 404's [issue 1175](https://github.com/firefly-iii/firefly-iii/issues/1175) [issue 1190](https://github.com/firefly-iii/firefly-iii/issues/1190)
|
||||
- Fixed tag autocomplete [issue 1178](https://github.com/firefly-iii/firefly-iii/issues/1178)
|
||||
- Better links for "new transaction" buttons [issue 1185](https://github.com/firefly-iii/firefly-iii/issues/1185)
|
||||
- Cache errors in budget charts [issue 1192](https://github.com/firefly-iii/firefly-iii/issues/1192)
|
||||
- Deleting transactions that are linked to other other transactions would lead to errors [issue 1209](https://github.com/firefly-iii/firefly-iii/issues/1209)
|
||||
|
||||
# 4.7.0
|
||||
- Support for Russian and Portuguese (Brazil)
|
||||
- Support for the Spectre API (Salt Edge)
|
||||
|
@ -202,6 +202,7 @@ lib/x86_64-linux-gnu/libz.so.1.2.8
|
||||
lib64/ld-linux-x86-64.so.2
|
||||
opt/app/.codeclimate.yml
|
||||
opt/app/.env
|
||||
opt/app/.env.current
|
||||
opt/app/.env.docker
|
||||
opt/app/.env.example
|
||||
opt/app/.env.heroku
|
||||
@ -240,6 +241,17 @@ opt/app/.sandstorm/setup.sh
|
||||
opt/app/.sandstorm/stack
|
||||
opt/app/LICENSE
|
||||
opt/app/app.json
|
||||
opt/app/app/Api/V1/Controllers/AboutController.php
|
||||
opt/app/app/Api/V1/Controllers/AccountController.php
|
||||
opt/app/app/Api/V1/Controllers/BillController.php
|
||||
opt/app/app/Api/V1/Controllers/Controller.php
|
||||
opt/app/app/Api/V1/Controllers/TransactionController.php
|
||||
opt/app/app/Api/V1/Controllers/UserController.php
|
||||
opt/app/app/Api/V1/Requests/AccountRequest.php
|
||||
opt/app/app/Api/V1/Requests/BillRequest.php
|
||||
opt/app/app/Api/V1/Requests/Request.php
|
||||
opt/app/app/Api/V1/Requests/TransactionRequest.php
|
||||
opt/app/app/Api/V1/Requests/UserRequest.php
|
||||
opt/app/app/Console/Commands/CreateExport.php
|
||||
opt/app/app/Console/Commands/CreateImport.php
|
||||
opt/app/app/Console/Commands/DecryptAttachment.php
|
||||
@ -274,6 +286,19 @@ opt/app/app/Export/Exporter/BasicExporter.php
|
||||
opt/app/app/Export/Exporter/CsvExporter.php
|
||||
opt/app/app/Export/Exporter/ExporterInterface.php
|
||||
opt/app/app/Export/ProcessorInterface.php
|
||||
opt/app/app/Factory/AccountFactory.php
|
||||
opt/app/app/Factory/AccountMetaFactory.php
|
||||
opt/app/app/Factory/BillFactory.php
|
||||
opt/app/app/Factory/BudgetFactory.php
|
||||
opt/app/app/Factory/CategoryFactory.php
|
||||
opt/app/app/Factory/PiggyBankEventFactory.php
|
||||
opt/app/app/Factory/PiggyBankFactory.php
|
||||
opt/app/app/Factory/TagFactory.php
|
||||
opt/app/app/Factory/TransactionCurrencyFactory.php
|
||||
opt/app/app/Factory/TransactionFactory.php
|
||||
opt/app/app/Factory/TransactionJournalFactory.php
|
||||
opt/app/app/Factory/TransactionJournalMetaFactory.php
|
||||
opt/app/app/Factory/TransactionTypeFactory.php
|
||||
opt/app/app/Generator/Chart/Basic/ChartJsGenerator.php
|
||||
opt/app/app/Generator/Chart/Basic/GeneratorInterface.php
|
||||
opt/app/app/Generator/Report/Account/MonthReportGenerator.php
|
||||
@ -437,7 +462,8 @@ opt/app/app/Http/Requests/MassEditJournalRequest.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/ReconciliationFormRequest.php
|
||||
opt/app/app/Http/Requests/ReconciliationStoreRequest.php
|
||||
opt/app/app/Http/Requests/ReconciliationUpdateRequest.php
|
||||
opt/app/app/Http/Requests/ReportFormRequest.php
|
||||
opt/app/app/Http/Requests/Request.php
|
||||
opt/app/app/Http/Requests/RuleFormRequest.php
|
||||
@ -577,13 +603,10 @@ opt/app/app/Repositories/ExportJob/ExportJobRepository.php
|
||||
opt/app/app/Repositories/ExportJob/ExportJobRepositoryInterface.php
|
||||
opt/app/app/Repositories/ImportJob/ImportJobRepository.php
|
||||
opt/app/app/Repositories/ImportJob/ImportJobRepositoryInterface.php
|
||||
opt/app/app/Repositories/Journal/CreateJournalsTrait.php
|
||||
opt/app/app/Repositories/Journal/JournalRepository.php
|
||||
opt/app/app/Repositories/Journal/JournalRepositoryInterface.php
|
||||
opt/app/app/Repositories/Journal/JournalTasker.php
|
||||
opt/app/app/Repositories/Journal/JournalTaskerInterface.php
|
||||
opt/app/app/Repositories/Journal/SupportJournalsTrait.php
|
||||
opt/app/app/Repositories/Journal/UpdateJournalsTrait.php
|
||||
opt/app/app/Repositories/LinkType/LinkTypeRepository.php
|
||||
opt/app/app/Repositories/LinkType/LinkTypeRepositoryInterface.php
|
||||
opt/app/app/Repositories/PiggyBank/PiggyBankRepository.php
|
||||
@ -594,8 +617,13 @@ 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/TransactionType/TransactionTypeRepository.php
|
||||
opt/app/app/Repositories/TransactionType/TransactionTypeRepositoryInterface.php
|
||||
opt/app/app/Repositories/User/UserRepository.php
|
||||
opt/app/app/Repositories/User/UserRepositoryInterface.php
|
||||
opt/app/app/Rules/BelongsUser.php
|
||||
opt/app/app/Rules/UniqueIban.php
|
||||
opt/app/app/Rules/ValidTransactions.php
|
||||
opt/app/app/Services/Bunq/Id/BunqId.php
|
||||
opt/app/app/Services/Bunq/Id/DeviceServerId.php
|
||||
opt/app/app/Services/Bunq/Id/DeviceSessionId.php
|
||||
@ -630,6 +658,17 @@ opt/app/app/Services/Github/Object/GithubObject.php
|
||||
opt/app/app/Services/Github/Object/Release.php
|
||||
opt/app/app/Services/Github/Request/GithubRequest.php
|
||||
opt/app/app/Services/Github/Request/UpdateRequest.php
|
||||
opt/app/app/Services/Internal/Destroy/AccountDestroyService.php
|
||||
opt/app/app/Services/Internal/Destroy/BillDestroyService.php
|
||||
opt/app/app/Services/Internal/Destroy/JournalDestroyService.php
|
||||
opt/app/app/Services/Internal/Support/AccountServiceTrait.php
|
||||
opt/app/app/Services/Internal/Support/BillServiceTrait.php
|
||||
opt/app/app/Services/Internal/Support/JournalServiceTrait.php
|
||||
opt/app/app/Services/Internal/Support/TransactionServiceTrait.php
|
||||
opt/app/app/Services/Internal/Update/AccountUpdateService.php
|
||||
opt/app/app/Services/Internal/Update/BillUpdateService.php
|
||||
opt/app/app/Services/Internal/Update/JournalUpdateService.php
|
||||
opt/app/app/Services/Internal/Update/TransactionUpdateService.php
|
||||
opt/app/app/Services/Password/PwndVerifier.php
|
||||
opt/app/app/Services/Password/Verifier.php
|
||||
opt/app/app/Services/Spectre/Exception/DuplicatedCustomerException.php
|
||||
@ -754,6 +793,17 @@ opt/app/app/TransactionRules/Triggers/ToAccountStarts.php
|
||||
opt/app/app/TransactionRules/Triggers/TransactionType.php
|
||||
opt/app/app/TransactionRules/Triggers/TriggerInterface.php
|
||||
opt/app/app/TransactionRules/Triggers/UserAction.php
|
||||
opt/app/app/Transformers/AccountTransformer.php
|
||||
opt/app/app/Transformers/AttachmentTransformer.php
|
||||
opt/app/app/Transformers/BillTransformer.php
|
||||
opt/app/app/Transformers/BudgetTransformer.php
|
||||
opt/app/app/Transformers/CategoryTransformer.php
|
||||
opt/app/app/Transformers/JournalMetaTransformer.php
|
||||
opt/app/app/Transformers/PiggyBankEventTransformer.php
|
||||
opt/app/app/Transformers/PiggyBankTransformer.php
|
||||
opt/app/app/Transformers/TagTransformer.php
|
||||
opt/app/app/Transformers/TransactionTransformer.php
|
||||
opt/app/app/Transformers/UserTransformer.php
|
||||
opt/app/app/User.php
|
||||
opt/app/app/Validation/FireflyValidator.php
|
||||
opt/app/artisan
|
||||
@ -798,6 +848,11 @@ opt/app/database/migrations/2017_04_13_163623_changes_for_v440.php
|
||||
opt/app/database/migrations/2017_06_02_105232_changes_for_v450.php
|
||||
opt/app/database/migrations/2017_08_20_062014_changes_for_v470.php
|
||||
opt/app/database/migrations/2017_11_04_170844_changes_for_v470a.php
|
||||
opt/app/database/migrations/2018_01_01_000001_create_oauth_auth_codes_table.php
|
||||
opt/app/database/migrations/2018_01_01_000002_create_oauth_access_tokens_table.php
|
||||
opt/app/database/migrations/2018_01_01_000003_create_oauth_refresh_tokens_table.php
|
||||
opt/app/database/migrations/2018_01_01_000004_create_oauth_clients_table.php
|
||||
opt/app/database/migrations/2018_01_01_000005_create_oauth_personal_access_clients_table.php
|
||||
opt/app/database/seeds/AccountTypeSeeder.php
|
||||
opt/app/database/seeds/DatabaseSeeder.php
|
||||
opt/app/database/seeds/LinkTypeSeeder.php
|
||||
@ -806,11 +861,13 @@ opt/app/database/seeds/TransactionCurrencySeeder.php
|
||||
opt/app/database/seeds/TransactionTypeSeeder.php
|
||||
opt/app/docker-compose.yml
|
||||
opt/app/index.php
|
||||
opt/app/package-lock.json
|
||||
opt/app/public/.htaccess
|
||||
opt/app/public/android-chrome-192x192.png
|
||||
opt/app/public/android-chrome-512x512.png
|
||||
opt/app/public/apple-touch-icon.png
|
||||
opt/app/public/browserconfig.xml
|
||||
opt/app/public/css/app.css
|
||||
opt/app/public/css/bootstrap-multiselect.css
|
||||
opt/app/public/css/bootstrap-sortable.css
|
||||
opt/app/public/css/bootstrap-tagsinput.css
|
||||
@ -944,6 +1001,16 @@ opt/app/public/fonts/lato-100.woff
|
||||
opt/app/public/fonts/lato-100.woff2
|
||||
opt/app/public/fonts/roboto-light-300.woff
|
||||
opt/app/public/fonts/roboto-light-300.woff2
|
||||
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.eot
|
||||
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.svg
|
||||
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.ttf
|
||||
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.woff
|
||||
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.woff2
|
||||
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.eot
|
||||
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.svg
|
||||
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.ttf
|
||||
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.woff
|
||||
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.woff2
|
||||
opt/app/public/images/error.png
|
||||
opt/app/public/images/image.png
|
||||
opt/app/public/images/loading-small.gif
|
||||
@ -956,6 +1023,7 @@ opt/app/public/images/logos/spectre.png
|
||||
opt/app/public/images/page_green.png
|
||||
opt/app/public/images/page_white_acrobat.png
|
||||
opt/app/public/index.php
|
||||
opt/app/public/js/app.js
|
||||
opt/app/public/js/ff/accounts/create.js
|
||||
opt/app/public/js/ff/accounts/edit-reconciliation.js
|
||||
opt/app/public/js/ff/accounts/edit.js
|
||||
@ -1019,8 +1087,6 @@ opt/app/public/js/lib/bootstrap-tagsinput.min.js.map
|
||||
opt/app/public/js/lib/bootstrap3-typeahead.min.js
|
||||
opt/app/public/js/lib/daterangepicker.js
|
||||
opt/app/public/js/lib/html5shiv.min.js
|
||||
opt/app/public/js/lib/jquery-3.2.1.min.js
|
||||
opt/app/public/js/lib/jquery-3.2.1.min.map
|
||||
opt/app/public/js/lib/jquery-ui.min.js
|
||||
opt/app/public/js/lib/jquery.color-2.1.2.min.js
|
||||
opt/app/public/js/lib/modernizr-custom.js
|
||||
@ -1033,22 +1099,6 @@ opt/app/public/lib/adminlte/css/skins/skin-blue-light.min.css
|
||||
opt/app/public/lib/adminlte/img/icons.png
|
||||
opt/app/public/lib/adminlte/js/app.js
|
||||
opt/app/public/lib/adminlte/js/app.min.js
|
||||
opt/app/public/lib/bootstrap/config.json
|
||||
opt/app/public/lib/bootstrap/css/bootstrap.min.css
|
||||
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.eot
|
||||
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.svg
|
||||
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf
|
||||
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff
|
||||
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.css
|
||||
opt/app/public/lib/font-awesome/css/font-awesome.min.css
|
||||
opt/app/public/lib/font-awesome/fonts/FontAwesome.otf
|
||||
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.eot
|
||||
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.svg
|
||||
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.ttf
|
||||
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.woff
|
||||
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.woff2
|
||||
opt/app/public/lib/intro/intro.min.js
|
||||
opt/app/public/lib/intro/introjs-rtl.min.css
|
||||
opt/app/public/lib/intro/introjs.min.css
|
||||
@ -1063,15 +1113,28 @@ opt/app/public/lib/leaflet/leaflet.css
|
||||
opt/app/public/lib/leaflet/leaflet.js
|
||||
opt/app/public/lib/leaflet/leaflet.js.map
|
||||
opt/app/public/manifest.json
|
||||
opt/app/public/mix-manifest.json
|
||||
opt/app/public/mstile-150x150.png
|
||||
opt/app/public/report.html
|
||||
opt/app/public/robots.txt
|
||||
opt/app/public/safari-pinned-tab.svg
|
||||
opt/app/public/web.config
|
||||
opt/app/readme.md
|
||||
opt/app/resources/assets/js/app.js
|
||||
opt/app/resources/assets/js/bootstrap.js
|
||||
opt/app/resources/assets/js/components/ExampleComponent.vue
|
||||
opt/app/resources/assets/js/components/bills/Index.vue
|
||||
opt/app/resources/assets/js/components/passport/AuthorizedClients.vue
|
||||
opt/app/resources/assets/js/components/passport/Clients.vue
|
||||
opt/app/resources/assets/js/components/passport/PersonalAccessTokens.vue
|
||||
opt/app/resources/assets/js/lang.js
|
||||
opt/app/resources/assets/js/messages.js
|
||||
opt/app/resources/assets/sass/_variables.scss
|
||||
opt/app/resources/assets/sass/app.scss
|
||||
opt/app/resources/lang/de_DE/auth.php
|
||||
opt/app/resources/lang/de_DE/bank.php
|
||||
opt/app/resources/lang/de_DE/breadcrumbs.php
|
||||
opt/app/resources/lang/de_DE/components.php
|
||||
opt/app/resources/lang/de_DE/config.php
|
||||
opt/app/resources/lang/de_DE/csv.php
|
||||
opt/app/resources/lang/de_DE/demo.php
|
||||
@ -1087,6 +1150,7 @@ opt/app/resources/lang/de_DE/validation.php
|
||||
opt/app/resources/lang/en_US/auth.php
|
||||
opt/app/resources/lang/en_US/bank.php
|
||||
opt/app/resources/lang/en_US/breadcrumbs.php
|
||||
opt/app/resources/lang/en_US/components.php
|
||||
opt/app/resources/lang/en_US/config.php
|
||||
opt/app/resources/lang/en_US/csv.php
|
||||
opt/app/resources/lang/en_US/demo.php
|
||||
@ -1098,9 +1162,25 @@ opt/app/resources/lang/en_US/list.php
|
||||
opt/app/resources/lang/en_US/pagination.php
|
||||
opt/app/resources/lang/en_US/passwords.php
|
||||
opt/app/resources/lang/en_US/validation.php
|
||||
opt/app/resources/lang/es_ES/auth.php
|
||||
opt/app/resources/lang/es_ES/bank.php
|
||||
opt/app/resources/lang/es_ES/breadcrumbs.php
|
||||
opt/app/resources/lang/es_ES/components.php
|
||||
opt/app/resources/lang/es_ES/config.php
|
||||
opt/app/resources/lang/es_ES/csv.php
|
||||
opt/app/resources/lang/es_ES/demo.php
|
||||
opt/app/resources/lang/es_ES/firefly.php
|
||||
opt/app/resources/lang/es_ES/form.php
|
||||
opt/app/resources/lang/es_ES/import.php
|
||||
opt/app/resources/lang/es_ES/intro.php
|
||||
opt/app/resources/lang/es_ES/list.php
|
||||
opt/app/resources/lang/es_ES/pagination.php
|
||||
opt/app/resources/lang/es_ES/passwords.php
|
||||
opt/app/resources/lang/es_ES/validation.php
|
||||
opt/app/resources/lang/fr_FR/auth.php
|
||||
opt/app/resources/lang/fr_FR/bank.php
|
||||
opt/app/resources/lang/fr_FR/breadcrumbs.php
|
||||
opt/app/resources/lang/fr_FR/components.php
|
||||
opt/app/resources/lang/fr_FR/config.php
|
||||
opt/app/resources/lang/fr_FR/csv.php
|
||||
opt/app/resources/lang/fr_FR/demo.php
|
||||
@ -1116,6 +1196,7 @@ opt/app/resources/lang/fr_FR/validation.php
|
||||
opt/app/resources/lang/id_ID/auth.php
|
||||
opt/app/resources/lang/id_ID/bank.php
|
||||
opt/app/resources/lang/id_ID/breadcrumbs.php
|
||||
opt/app/resources/lang/id_ID/components.php
|
||||
opt/app/resources/lang/id_ID/config.php
|
||||
opt/app/resources/lang/id_ID/csv.php
|
||||
opt/app/resources/lang/id_ID/demo.php
|
||||
@ -1130,6 +1211,7 @@ opt/app/resources/lang/id_ID/validation.php
|
||||
opt/app/resources/lang/nl_NL/auth.php
|
||||
opt/app/resources/lang/nl_NL/bank.php
|
||||
opt/app/resources/lang/nl_NL/breadcrumbs.php
|
||||
opt/app/resources/lang/nl_NL/components.php
|
||||
opt/app/resources/lang/nl_NL/config.php
|
||||
opt/app/resources/lang/nl_NL/csv.php
|
||||
opt/app/resources/lang/nl_NL/demo.php
|
||||
@ -1145,6 +1227,7 @@ opt/app/resources/lang/nl_NL/validation.php
|
||||
opt/app/resources/lang/pl_PL/auth.php
|
||||
opt/app/resources/lang/pl_PL/bank.php
|
||||
opt/app/resources/lang/pl_PL/breadcrumbs.php
|
||||
opt/app/resources/lang/pl_PL/components.php
|
||||
opt/app/resources/lang/pl_PL/config.php
|
||||
opt/app/resources/lang/pl_PL/csv.php
|
||||
opt/app/resources/lang/pl_PL/demo.php
|
||||
@ -1160,6 +1243,7 @@ opt/app/resources/lang/pl_PL/validation.php
|
||||
opt/app/resources/lang/pt_BR/auth.php
|
||||
opt/app/resources/lang/pt_BR/bank.php
|
||||
opt/app/resources/lang/pt_BR/breadcrumbs.php
|
||||
opt/app/resources/lang/pt_BR/components.php
|
||||
opt/app/resources/lang/pt_BR/config.php
|
||||
opt/app/resources/lang/pt_BR/csv.php
|
||||
opt/app/resources/lang/pt_BR/demo.php
|
||||
@ -1174,6 +1258,7 @@ opt/app/resources/lang/pt_BR/validation.php
|
||||
opt/app/resources/lang/ru_RU/auth.php
|
||||
opt/app/resources/lang/ru_RU/bank.php
|
||||
opt/app/resources/lang/ru_RU/breadcrumbs.php
|
||||
opt/app/resources/lang/ru_RU/components.php
|
||||
opt/app/resources/lang/ru_RU/config.php
|
||||
opt/app/resources/lang/ru_RU/csv.php
|
||||
opt/app/resources/lang/ru_RU/demo.php
|
||||
@ -1188,6 +1273,7 @@ opt/app/resources/lang/ru_RU/validation.php
|
||||
opt/app/resources/lang/tr_TR/auth.php
|
||||
opt/app/resources/lang/tr_TR/bank.php
|
||||
opt/app/resources/lang/tr_TR/breadcrumbs.php
|
||||
opt/app/resources/lang/tr_TR/components.php
|
||||
opt/app/resources/lang/tr_TR/config.php
|
||||
opt/app/resources/lang/tr_TR/csv.php
|
||||
opt/app/resources/lang/tr_TR/demo.php
|
||||
@ -1431,6 +1517,7 @@ opt/app/resources/views/transactions/single/create.twig
|
||||
opt/app/resources/views/transactions/single/delete.twig
|
||||
opt/app/resources/views/transactions/single/edit.twig
|
||||
opt/app/resources/views/transactions/split/edit.twig
|
||||
opt/app/resources/views/vendor/passport/authorize.twig
|
||||
opt/app/routes/api.php
|
||||
opt/app/routes/breadcrumbs.php
|
||||
opt/app/routes/channels.php
|
||||
@ -1501,6 +1588,7 @@ opt/app/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php
|
||||
opt/app/vendor/bacon/bacon-qr-code/tests/bootstrap.php
|
||||
opt/app/vendor/bin/commonmark
|
||||
opt/app/vendor/bin/doctrine-dbal
|
||||
opt/app/vendor/bin/generate-defuse-key
|
||||
opt/app/vendor/composer/ClassLoader.php
|
||||
opt/app/vendor/composer/LICENSE
|
||||
opt/app/vendor/composer/autoload_classmap.php
|
||||
@ -1528,6 +1616,39 @@ opt/app/vendor/davejamesmiller/laravel-breadcrumbs/views/bulma.blade.php
|
||||
opt/app/vendor/davejamesmiller/laravel-breadcrumbs/views/foundation6.blade.php
|
||||
opt/app/vendor/davejamesmiller/laravel-breadcrumbs/views/json-ld.php
|
||||
opt/app/vendor/davejamesmiller/laravel-breadcrumbs/views/materialize.blade.php
|
||||
opt/app/vendor/defuse/php-encryption/.php_cs
|
||||
opt/app/vendor/defuse/php-encryption/LICENSE
|
||||
opt/app/vendor/defuse/php-encryption/README.md
|
||||
opt/app/vendor/defuse/php-encryption/bin/generate-defuse-key
|
||||
opt/app/vendor/defuse/php-encryption/composer.json
|
||||
opt/app/vendor/defuse/php-encryption/dist/Makefile
|
||||
opt/app/vendor/defuse/php-encryption/dist/box.json
|
||||
opt/app/vendor/defuse/php-encryption/dist/signingkey.asc
|
||||
opt/app/vendor/defuse/php-encryption/docs/CryptoDetails.md
|
||||
opt/app/vendor/defuse/php-encryption/docs/FAQ.md
|
||||
opt/app/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md
|
||||
opt/app/vendor/defuse/php-encryption/docs/InternalDeveloperDocs.md
|
||||
opt/app/vendor/defuse/php-encryption/docs/Tutorial.md
|
||||
opt/app/vendor/defuse/php-encryption/docs/UpgradingFromV1.2.md
|
||||
opt/app/vendor/defuse/php-encryption/docs/classes/Crypto.md
|
||||
opt/app/vendor/defuse/php-encryption/docs/classes/File.md
|
||||
opt/app/vendor/defuse/php-encryption/docs/classes/Key.md
|
||||
opt/app/vendor/defuse/php-encryption/docs/classes/KeyProtectedByPassword.md
|
||||
opt/app/vendor/defuse/php-encryption/psalm.xml
|
||||
opt/app/vendor/defuse/php-encryption/src/Core.php
|
||||
opt/app/vendor/defuse/php-encryption/src/Crypto.php
|
||||
opt/app/vendor/defuse/php-encryption/src/DerivedKeys.php
|
||||
opt/app/vendor/defuse/php-encryption/src/Encoding.php
|
||||
opt/app/vendor/defuse/php-encryption/src/Exception/BadFormatException.php
|
||||
opt/app/vendor/defuse/php-encryption/src/Exception/CryptoException.php
|
||||
opt/app/vendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php
|
||||
opt/app/vendor/defuse/php-encryption/src/Exception/IOException.php
|
||||
opt/app/vendor/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php
|
||||
opt/app/vendor/defuse/php-encryption/src/File.php
|
||||
opt/app/vendor/defuse/php-encryption/src/Key.php
|
||||
opt/app/vendor/defuse/php-encryption/src/KeyOrPassword.php
|
||||
opt/app/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php
|
||||
opt/app/vendor/defuse/php-encryption/src/RuntimeTests.php
|
||||
opt/app/vendor/doctrine/annotations/CHANGELOG.md
|
||||
opt/app/vendor/doctrine/annotations/LICENSE
|
||||
opt/app/vendor/doctrine/annotations/README.md
|
||||
@ -1995,6 +2116,101 @@ opt/app/vendor/fideloper/proxy/composer.json
|
||||
opt/app/vendor/fideloper/proxy/config/trustedproxy.php
|
||||
opt/app/vendor/fideloper/proxy/src/TrustProxies.php
|
||||
opt/app/vendor/fideloper/proxy/src/TrustedProxyServiceProvider.php
|
||||
opt/app/vendor/firebase/php-jwt/LICENSE
|
||||
opt/app/vendor/firebase/php-jwt/README.md
|
||||
opt/app/vendor/firebase/php-jwt/composer.json
|
||||
opt/app/vendor/firebase/php-jwt/src/BeforeValidException.php
|
||||
opt/app/vendor/firebase/php-jwt/src/ExpiredException.php
|
||||
opt/app/vendor/firebase/php-jwt/src/JWT.php
|
||||
opt/app/vendor/firebase/php-jwt/src/SignatureInvalidException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/CHANGELOG.md
|
||||
opt/app/vendor/guzzlehttp/guzzle/LICENSE
|
||||
opt/app/vendor/guzzlehttp/guzzle/README.md
|
||||
opt/app/vendor/guzzlehttp/guzzle/UPGRADING.md
|
||||
opt/app/vendor/guzzlehttp/guzzle/composer.json
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Client.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/ClientInterface.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/HandlerStack.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/MessageFormatter.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Middleware.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/Pool.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/RequestOptions.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/TransferStats.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/UriTemplate.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/functions.php
|
||||
opt/app/vendor/guzzlehttp/guzzle/src/functions_include.php
|
||||
opt/app/vendor/guzzlehttp/promises/CHANGELOG.md
|
||||
opt/app/vendor/guzzlehttp/promises/LICENSE
|
||||
opt/app/vendor/guzzlehttp/promises/Makefile
|
||||
opt/app/vendor/guzzlehttp/promises/README.md
|
||||
opt/app/vendor/guzzlehttp/promises/composer.json
|
||||
opt/app/vendor/guzzlehttp/promises/src/AggregateException.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/CancellationException.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/Coroutine.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/EachPromise.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/FulfilledPromise.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/Promise.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/PromiseInterface.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/PromisorInterface.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/RejectedPromise.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/RejectionException.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/TaskQueue.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/TaskQueueInterface.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/functions.php
|
||||
opt/app/vendor/guzzlehttp/promises/src/functions_include.php
|
||||
opt/app/vendor/guzzlehttp/psr7/CHANGELOG.md
|
||||
opt/app/vendor/guzzlehttp/psr7/LICENSE
|
||||
opt/app/vendor/guzzlehttp/psr7/README.md
|
||||
opt/app/vendor/guzzlehttp/psr7/composer.json
|
||||
opt/app/vendor/guzzlehttp/psr7/src/AppendStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/BufferStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/CachingStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/DroppingStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/FnStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/InflateStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/LazyOpenStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/LimitStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/MessageTrait.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/MultipartStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/NoSeekStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/PumpStream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/Request.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/Response.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/ServerRequest.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/Stream.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/StreamWrapper.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/UploadedFile.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/Uri.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/UriNormalizer.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/UriResolver.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/functions.php
|
||||
opt/app/vendor/guzzlehttp/psr7/src/functions_include.php
|
||||
opt/app/vendor/laravel/framework/LICENSE.md
|
||||
opt/app/vendor/laravel/framework/README.md
|
||||
opt/app/vendor/laravel/framework/composer.json
|
||||
@ -2894,6 +3110,70 @@ opt/app/vendor/laravel/framework/src/Illuminate/View/ViewFinderInterface.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/View/ViewName.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/View/ViewServiceProvider.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/View/composer.json
|
||||
opt/app/vendor/laravel/passport/LICENSE.txt
|
||||
opt/app/vendor/laravel/passport/composer.json
|
||||
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php
|
||||
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php
|
||||
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php
|
||||
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000004_create_oauth_clients_table.php
|
||||
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php
|
||||
opt/app/vendor/laravel/passport/readme.md
|
||||
opt/app/vendor/laravel/passport/resources/assets/js/components/AuthorizedClients.vue
|
||||
opt/app/vendor/laravel/passport/resources/assets/js/components/Clients.vue
|
||||
opt/app/vendor/laravel/passport/resources/assets/js/components/PersonalAccessTokens.vue
|
||||
opt/app/vendor/laravel/passport/resources/views/authorize.blade.php
|
||||
opt/app/vendor/laravel/passport/src/ApiTokenCookieFactory.php
|
||||
opt/app/vendor/laravel/passport/src/AuthCode.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/AccessToken.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/AccessTokenRepository.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/AuthCode.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/AuthCodeRepository.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/Client.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/ClientRepository.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/FormatsScopesForStorage.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/PersonalAccessGrant.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/RefreshToken.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/RefreshTokenRepository.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/Scope.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/ScopeRepository.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/User.php
|
||||
opt/app/vendor/laravel/passport/src/Bridge/UserRepository.php
|
||||
opt/app/vendor/laravel/passport/src/Client.php
|
||||
opt/app/vendor/laravel/passport/src/ClientRepository.php
|
||||
opt/app/vendor/laravel/passport/src/Console/ClientCommand.php
|
||||
opt/app/vendor/laravel/passport/src/Console/InstallCommand.php
|
||||
opt/app/vendor/laravel/passport/src/Console/KeysCommand.php
|
||||
opt/app/vendor/laravel/passport/src/Events/AccessTokenCreated.php
|
||||
opt/app/vendor/laravel/passport/src/Events/RefreshTokenCreated.php
|
||||
opt/app/vendor/laravel/passport/src/Exceptions/MissingScopeException.php
|
||||
opt/app/vendor/laravel/passport/src/Guards/TokenGuard.php
|
||||
opt/app/vendor/laravel/passport/src/HasApiTokens.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/AccessTokenController.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/ApproveAuthorizationController.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/AuthorizationController.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/AuthorizedAccessTokenController.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/ClientController.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/ConvertsPsrResponses.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/DenyAuthorizationController.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/HandlesOAuthErrors.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/PersonalAccessTokenController.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/RetrievesAuthRequestFromSession.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/ScopeController.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Controllers/TransientTokenController.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Middleware/CheckClientCredentials.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Middleware/CheckForAnyScope.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Middleware/CheckScopes.php
|
||||
opt/app/vendor/laravel/passport/src/Http/Middleware/CreateFreshApiToken.php
|
||||
opt/app/vendor/laravel/passport/src/Passport.php
|
||||
opt/app/vendor/laravel/passport/src/PassportServiceProvider.php
|
||||
opt/app/vendor/laravel/passport/src/PersonalAccessClient.php
|
||||
opt/app/vendor/laravel/passport/src/PersonalAccessTokenFactory.php
|
||||
opt/app/vendor/laravel/passport/src/PersonalAccessTokenResult.php
|
||||
opt/app/vendor/laravel/passport/src/RouteRegistrar.php
|
||||
opt/app/vendor/laravel/passport/src/Scope.php
|
||||
opt/app/vendor/laravel/passport/src/Token.php
|
||||
opt/app/vendor/laravel/passport/src/TokenRepository.php
|
||||
opt/app/vendor/laravel/passport/src/TransientToken.php
|
||||
opt/app/vendor/laravelcollective/html/CONTRIBUTING.md
|
||||
opt/app/vendor/laravelcollective/html/LICENSE.txt
|
||||
opt/app/vendor/laravelcollective/html/composer.json
|
||||
@ -2906,6 +3186,83 @@ opt/app/vendor/laravelcollective/html/src/HtmlBuilder.php
|
||||
opt/app/vendor/laravelcollective/html/src/HtmlFacade.php
|
||||
opt/app/vendor/laravelcollective/html/src/HtmlServiceProvider.php
|
||||
opt/app/vendor/laravelcollective/html/src/helpers.php
|
||||
opt/app/vendor/lcobucci/jwt/LICENSE
|
||||
opt/app/vendor/lcobucci/jwt/README.md
|
||||
opt/app/vendor/lcobucci/jwt/composer.json
|
||||
opt/app/vendor/lcobucci/jwt/composer.lock
|
||||
opt/app/vendor/lcobucci/jwt/phpunit.xml.dist
|
||||
opt/app/vendor/lcobucci/jwt/src/Builder.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Claim.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Claim/Basic.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Claim/EqualsTo.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Claim/Factory.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Claim/GreaterOrEqualsTo.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Claim/LesserOrEqualsTo.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Claim/Validatable.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Parser.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Parsing/Decoder.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Parsing/Encoder.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signature.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/BaseSigner.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa/KeyParser.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha384.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha512.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Hmac.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Hmac/Sha384.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Hmac/Sha512.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Key.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Keychain.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Rsa.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Rsa/Sha384.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Signer/Rsa/Sha512.php
|
||||
opt/app/vendor/lcobucci/jwt/src/Token.php
|
||||
opt/app/vendor/lcobucci/jwt/src/ValidationData.php
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/EcdsaTokenTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/HmacTokenTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/Keys.php
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/RsaTokenTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/UnsignedTokenTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/private.key
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/private2.key
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/public1.key
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/public2.key
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/public3.key
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/rsa/encrypted-private.key
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/rsa/encrypted-public.key
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/rsa/private.key
|
||||
opt/app/vendor/lcobucci/jwt/test/functional/rsa/public.key
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/BuilderTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Claim/BasicTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Claim/EqualsToTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Claim/FactoryTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Claim/GreaterOrEqualsToTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Claim/LesserOrEqualsToTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/ParserTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Parsing/DecoderTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Parsing/EncoderTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/SignatureTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/BaseSignerTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Ecdsa/KeyParserTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Ecdsa/Sha256Test.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Ecdsa/Sha384Test.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Ecdsa/Sha512Test.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/EcdsaTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Hmac/Sha256Test.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Hmac/Sha384Test.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Hmac/Sha512Test.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/HmacTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/KeyTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/KeychainTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Rsa/Sha256Test.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Rsa/Sha384Test.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Rsa/Sha512Test.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/TokenTest.php
|
||||
opt/app/vendor/lcobucci/jwt/test/unit/ValidationDataTest.php
|
||||
opt/app/vendor/league/commonmark/.styleci.yml
|
||||
opt/app/vendor/league/commonmark/CHANGELOG.md
|
||||
opt/app/vendor/league/commonmark/CONDUCT.md
|
||||
@ -3043,47 +3400,28 @@ opt/app/vendor/league/csv/src/Writer.php
|
||||
opt/app/vendor/league/csv/src/XMLConverter.php
|
||||
opt/app/vendor/league/csv/src/functions.php
|
||||
opt/app/vendor/league/csv/src/functions_include.php
|
||||
opt/app/vendor/league/event/LICENCE
|
||||
opt/app/vendor/league/event/composer.json
|
||||
opt/app/vendor/league/event/src/AbstractEvent.php
|
||||
opt/app/vendor/league/event/src/AbstractListener.php
|
||||
opt/app/vendor/league/event/src/CallbackListener.php
|
||||
opt/app/vendor/league/event/src/Emitter.php
|
||||
opt/app/vendor/league/event/src/EmitterAwareInterface.php
|
||||
opt/app/vendor/league/event/src/EmitterAwareTrait.php
|
||||
opt/app/vendor/league/event/src/EmitterInterface.php
|
||||
opt/app/vendor/league/event/src/EmitterTrait.php
|
||||
opt/app/vendor/league/event/src/Event.php
|
||||
opt/app/vendor/league/event/src/EventInterface.php
|
||||
opt/app/vendor/league/event/src/Generator.php
|
||||
opt/app/vendor/league/event/src/GeneratorInterface.php
|
||||
opt/app/vendor/league/event/src/GeneratorTrait.php
|
||||
opt/app/vendor/league/event/src/ListenerAcceptor.php
|
||||
opt/app/vendor/league/event/src/ListenerAcceptorInterface.php
|
||||
opt/app/vendor/league/event/src/ListenerInterface.php
|
||||
opt/app/vendor/league/event/src/ListenerProviderInterface.php
|
||||
opt/app/vendor/league/event/src/OneTimeListener.php
|
||||
opt/app/vendor/league/flysystem/LICENSE
|
||||
opt/app/vendor/league/flysystem/composer.json
|
||||
opt/app/vendor/league/flysystem/docs/CNAME
|
||||
opt/app/vendor/league/flysystem/docs/_data/images.yml
|
||||
opt/app/vendor/league/flysystem/docs/_data/menu.yml
|
||||
opt/app/vendor/league/flysystem/docs/_data/project.yml
|
||||
opt/app/vendor/league/flysystem/docs/_layouts/default.html
|
||||
opt/app/vendor/league/flysystem/docs/adapter/aws-s3-v2.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/aws-s3-v3.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/azure.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/copy.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/digitalocean-spaces.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/dropbox.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/ftp.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/gridfs.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/local.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/memory.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/null-test.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/phpcr.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/rackspace.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/replicate.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/sftp.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/webdav.md
|
||||
opt/app/vendor/league/flysystem/docs/adapter/zip-archive.md
|
||||
opt/app/vendor/league/flysystem/docs/api.md
|
||||
opt/app/vendor/league/flysystem/docs/caching.md
|
||||
opt/app/vendor/league/flysystem/docs/core-concepts.md
|
||||
opt/app/vendor/league/flysystem/docs/creating-an-adapter.md
|
||||
opt/app/vendor/league/flysystem/docs/index.md
|
||||
opt/app/vendor/league/flysystem/docs/installation.md
|
||||
opt/app/vendor/league/flysystem/docs/integrations.md
|
||||
opt/app/vendor/league/flysystem/docs/logo/become_a_patron_button.png
|
||||
opt/app/vendor/league/flysystem/docs/logo/become_a_patron_button@2x.png
|
||||
opt/app/vendor/league/flysystem/docs/logo/become_a_patron_button@3x.png
|
||||
opt/app/vendor/league/flysystem/docs/logo/laravel.svg
|
||||
opt/app/vendor/league/flysystem/docs/mount-manager.md
|
||||
opt/app/vendor/league/flysystem/docs/performance.md
|
||||
opt/app/vendor/league/flysystem/docs/plugins.md
|
||||
opt/app/vendor/league/flysystem/docs/recipes.md
|
||||
opt/app/vendor/league/flysystem/docs/sponsors.md
|
||||
opt/app/vendor/league/flysystem/docs/upgrade-to-1.0.0.md
|
||||
opt/app/vendor/league/flysystem/src/Adapter/AbstractAdapter.php
|
||||
opt/app/vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php
|
||||
opt/app/vendor/league/flysystem/src/Adapter/CanOverwriteFiles.php
|
||||
@ -3130,7 +3468,81 @@ opt/app/vendor/league/flysystem/src/Util.php
|
||||
opt/app/vendor/league/flysystem/src/Util/ContentListingFormatter.php
|
||||
opt/app/vendor/league/flysystem/src/Util/MimeType.php
|
||||
opt/app/vendor/league/flysystem/src/Util/StreamHasher.php
|
||||
opt/app/vendor/league/flysystem/wait_for_ftp_service.php
|
||||
opt/app/vendor/league/fractal/LICENSE
|
||||
opt/app/vendor/league/fractal/composer.json
|
||||
opt/app/vendor/league/fractal/src/Manager.php
|
||||
opt/app/vendor/league/fractal/src/Pagination/Cursor.php
|
||||
opt/app/vendor/league/fractal/src/Pagination/CursorInterface.php
|
||||
opt/app/vendor/league/fractal/src/Pagination/DoctrinePaginatorAdapter.php
|
||||
opt/app/vendor/league/fractal/src/Pagination/IlluminatePaginatorAdapter.php
|
||||
opt/app/vendor/league/fractal/src/Pagination/PagerfantaPaginatorAdapter.php
|
||||
opt/app/vendor/league/fractal/src/Pagination/PaginatorInterface.php
|
||||
opt/app/vendor/league/fractal/src/Pagination/PhalconFrameworkPaginatorAdapter.php
|
||||
opt/app/vendor/league/fractal/src/Pagination/ZendFrameworkPaginatorAdapter.php
|
||||
opt/app/vendor/league/fractal/src/ParamBag.php
|
||||
opt/app/vendor/league/fractal/src/Resource/Collection.php
|
||||
opt/app/vendor/league/fractal/src/Resource/Item.php
|
||||
opt/app/vendor/league/fractal/src/Resource/NullResource.php
|
||||
opt/app/vendor/league/fractal/src/Resource/Primitive.php
|
||||
opt/app/vendor/league/fractal/src/Resource/ResourceAbstract.php
|
||||
opt/app/vendor/league/fractal/src/Resource/ResourceInterface.php
|
||||
opt/app/vendor/league/fractal/src/Scope.php
|
||||
opt/app/vendor/league/fractal/src/ScopeFactory.php
|
||||
opt/app/vendor/league/fractal/src/ScopeFactoryInterface.php
|
||||
opt/app/vendor/league/fractal/src/Serializer/ArraySerializer.php
|
||||
opt/app/vendor/league/fractal/src/Serializer/DataArraySerializer.php
|
||||
opt/app/vendor/league/fractal/src/Serializer/JsonApiSerializer.php
|
||||
opt/app/vendor/league/fractal/src/Serializer/Serializer.php
|
||||
opt/app/vendor/league/fractal/src/Serializer/SerializerAbstract.php
|
||||
opt/app/vendor/league/fractal/src/TransformerAbstract.php
|
||||
opt/app/vendor/league/oauth2-server/.styleci.yml
|
||||
opt/app/vendor/league/oauth2-server/CONDUCT.md
|
||||
opt/app/vendor/league/oauth2-server/LICENSE
|
||||
opt/app/vendor/league/oauth2-server/composer.json
|
||||
opt/app/vendor/league/oauth2-server/src/AuthorizationServer.php
|
||||
opt/app/vendor/league/oauth2-server/src/AuthorizationValidators/AuthorizationValidatorInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/AuthorizationValidators/BearerTokenValidator.php
|
||||
opt/app/vendor/league/oauth2-server/src/CryptKey.php
|
||||
opt/app/vendor/league/oauth2-server/src/CryptTrait.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/AccessTokenEntityInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/AuthCodeEntityInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/ClientEntityInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/RefreshTokenEntityInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/ScopeEntityInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/TokenInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/Traits/AccessTokenTrait.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/Traits/AuthCodeTrait.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/Traits/ClientTrait.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/Traits/EntityTrait.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/Traits/RefreshTokenTrait.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/Traits/TokenEntityTrait.php
|
||||
opt/app/vendor/league/oauth2-server/src/Entities/UserEntityInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Exception/OAuthServerException.php
|
||||
opt/app/vendor/league/oauth2-server/src/Exception/UniqueTokenIdentifierConstraintViolationException.php
|
||||
opt/app/vendor/league/oauth2-server/src/Grant/AbstractAuthorizeGrant.php
|
||||
opt/app/vendor/league/oauth2-server/src/Grant/AbstractGrant.php
|
||||
opt/app/vendor/league/oauth2-server/src/Grant/AuthCodeGrant.php
|
||||
opt/app/vendor/league/oauth2-server/src/Grant/ClientCredentialsGrant.php
|
||||
opt/app/vendor/league/oauth2-server/src/Grant/GrantTypeInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Grant/ImplicitGrant.php
|
||||
opt/app/vendor/league/oauth2-server/src/Grant/PasswordGrant.php
|
||||
opt/app/vendor/league/oauth2-server/src/Grant/RefreshTokenGrant.php
|
||||
opt/app/vendor/league/oauth2-server/src/Middleware/AuthorizationServerMiddleware.php
|
||||
opt/app/vendor/league/oauth2-server/src/Middleware/ResourceServerMiddleware.php
|
||||
opt/app/vendor/league/oauth2-server/src/Repositories/AccessTokenRepositoryInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Repositories/AuthCodeRepositoryInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Repositories/ClientRepositoryInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Repositories/RefreshTokenRepositoryInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Repositories/RepositoryInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Repositories/ScopeRepositoryInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/Repositories/UserRepositoryInterface.php
|
||||
opt/app/vendor/league/oauth2-server/src/RequestEvent.php
|
||||
opt/app/vendor/league/oauth2-server/src/RequestTypes/AuthorizationRequest.php
|
||||
opt/app/vendor/league/oauth2-server/src/ResourceServer.php
|
||||
opt/app/vendor/league/oauth2-server/src/ResponseTypes/AbstractResponseType.php
|
||||
opt/app/vendor/league/oauth2-server/src/ResponseTypes/BearerTokenResponse.php
|
||||
opt/app/vendor/league/oauth2-server/src/ResponseTypes/RedirectResponse.php
|
||||
opt/app/vendor/league/oauth2-server/src/ResponseTypes/ResponseTypeInterface.php
|
||||
opt/app/vendor/monolog/monolog/.php_cs
|
||||
opt/app/vendor/monolog/monolog/CHANGELOG.md
|
||||
opt/app/vendor/monolog/monolog/LICENSE
|
||||
@ -3342,6 +3754,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/CarbonInterval.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidDateException.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/af.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ar.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ar_Shakl.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/az.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/bg.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/bn.php
|
||||
@ -3349,6 +3762,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ca.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/cs.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/da.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/de.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/dv_MV.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/el.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/en.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/eo.php
|
||||
@ -3368,15 +3782,18 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/id.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/it.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ja.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ka.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/kk.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/km.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ko.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/lt.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/lv.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/mk.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/mn.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ms.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/nl.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/no.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/pl.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ps.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/pt.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/pt_BR.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ro.php
|
||||
@ -3385,6 +3802,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sk.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sl.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sq.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_ME.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr_ME.php
|
||||
@ -3397,6 +3815,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/uz.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/vi.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/zh.php
|
||||
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/zh_TW.php
|
||||
opt/app/vendor/nesbot/carbon/trigger
|
||||
opt/app/vendor/paragonie/constant_time_encoding/LICENSE.txt
|
||||
opt/app/vendor/paragonie/constant_time_encoding/README.md
|
||||
opt/app/vendor/paragonie/constant_time_encoding/composer.json
|
||||
@ -3440,6 +3859,36 @@ opt/app/vendor/paragonie/random_compat/lib/random_int.php
|
||||
opt/app/vendor/paragonie/random_compat/other/build_phar.php
|
||||
opt/app/vendor/paragonie/random_compat/psalm-autoload.php
|
||||
opt/app/vendor/paragonie/random_compat/psalm.xml
|
||||
opt/app/vendor/phpseclib/phpseclib/AUTHORS
|
||||
opt/app/vendor/phpseclib/phpseclib/LICENSE
|
||||
opt/app/vendor/phpseclib/phpseclib/README.md
|
||||
opt/app/vendor/phpseclib/phpseclib/composer.json
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/AES.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/File/X509.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php
|
||||
opt/app/vendor/phpseclib/phpseclib/phpseclib/openssl.cnf
|
||||
opt/app/vendor/pragmarx/google2fa-laravel/LICENSE
|
||||
opt/app/vendor/pragmarx/google2fa-laravel/changelog.md
|
||||
opt/app/vendor/pragmarx/google2fa-laravel/composer.json
|
||||
@ -3487,6 +3936,17 @@ opt/app/vendor/psr/container/composer.json
|
||||
opt/app/vendor/psr/container/src/ContainerExceptionInterface.php
|
||||
opt/app/vendor/psr/container/src/ContainerInterface.php
|
||||
opt/app/vendor/psr/container/src/NotFoundExceptionInterface.php
|
||||
opt/app/vendor/psr/http-message/CHANGELOG.md
|
||||
opt/app/vendor/psr/http-message/LICENSE
|
||||
opt/app/vendor/psr/http-message/README.md
|
||||
opt/app/vendor/psr/http-message/composer.json
|
||||
opt/app/vendor/psr/http-message/src/MessageInterface.php
|
||||
opt/app/vendor/psr/http-message/src/RequestInterface.php
|
||||
opt/app/vendor/psr/http-message/src/ResponseInterface.php
|
||||
opt/app/vendor/psr/http-message/src/ServerRequestInterface.php
|
||||
opt/app/vendor/psr/http-message/src/StreamInterface.php
|
||||
opt/app/vendor/psr/http-message/src/UploadedFileInterface.php
|
||||
opt/app/vendor/psr/http-message/src/UriInterface.php
|
||||
opt/app/vendor/psr/log/LICENSE
|
||||
opt/app/vendor/psr/log/Psr/Log/AbstractLogger.php
|
||||
opt/app/vendor/psr/log/Psr/Log/InvalidArgumentException.php
|
||||
@ -4998,8 +5458,10 @@ opt/app/vendor/symfony/polyfill-util/Binary.php
|
||||
opt/app/vendor/symfony/polyfill-util/BinaryNoFuncOverload.php
|
||||
opt/app/vendor/symfony/polyfill-util/BinaryOnFuncOverload.php
|
||||
opt/app/vendor/symfony/polyfill-util/LICENSE
|
||||
opt/app/vendor/symfony/polyfill-util/LegacyTestListener.php
|
||||
opt/app/vendor/symfony/polyfill-util/README.md
|
||||
opt/app/vendor/symfony/polyfill-util/TestListener.php
|
||||
opt/app/vendor/symfony/polyfill-util/TestListenerTrait.php
|
||||
opt/app/vendor/symfony/polyfill-util/composer.json
|
||||
opt/app/vendor/symfony/process/CHANGELOG.md
|
||||
opt/app/vendor/symfony/process/Exception/ExceptionInterface.php
|
||||
@ -5033,6 +5495,23 @@ opt/app/vendor/symfony/process/Tests/ProcessUtilsTest.php
|
||||
opt/app/vendor/symfony/process/Tests/SignalListener.php
|
||||
opt/app/vendor/symfony/process/composer.json
|
||||
opt/app/vendor/symfony/process/phpunit.xml.dist
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/CHANGELOG
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Factory/DiactorosFactory.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Factory/HttpFoundationFactory.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/HttpFoundationFactoryInterface.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/HttpMessageFactoryInterface.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/LICENSE
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/README.md
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Factory/DiactorosFactoryTest.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Factory/HttpFoundationFactoryTest.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Message.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Response.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/ServerRequest.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Stream.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/UploadedFile.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Uri.php
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/composer.json
|
||||
opt/app/vendor/symfony/psr-http-message-bridge/phpunit.xml.dist
|
||||
opt/app/vendor/symfony/routing/Annotation/Route.php
|
||||
opt/app/vendor/symfony/routing/CHANGELOG.md
|
||||
opt/app/vendor/symfony/routing/CompiledRoute.php
|
||||
@ -5063,6 +5542,7 @@ opt/app/vendor/symfony/routing/Loader/Configurator/Traits/AddTrait.php
|
||||
opt/app/vendor/symfony/routing/Loader/Configurator/Traits/RouteTrait.php
|
||||
opt/app/vendor/symfony/routing/Loader/DependencyInjection/ServiceRouterLoader.php
|
||||
opt/app/vendor/symfony/routing/Loader/DirectoryLoader.php
|
||||
opt/app/vendor/symfony/routing/Loader/GlobFileLoader.php
|
||||
opt/app/vendor/symfony/routing/Loader/ObjectRouteLoader.php
|
||||
opt/app/vendor/symfony/routing/Loader/PhpFileLoader.php
|
||||
opt/app/vendor/symfony/routing/Loader/XmlFileLoader.php
|
||||
@ -5175,10 +5655,13 @@ opt/app/vendor/symfony/routing/Tests/Loader/AnnotationDirectoryLoaderTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Loader/AnnotationFileLoaderTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Loader/ClosureLoaderTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Loader/DirectoryLoaderTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Loader/GlobFileLoaderTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Loader/ObjectRouteLoaderTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Loader/PhpFileLoaderTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Loader/XmlFileLoaderTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Loader/YamlFileLoaderTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Matcher/DumpedRedirectableUrlMatcherTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Matcher/DumpedUrlMatcherTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Matcher/Dumper/DumperCollectionTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
|
||||
opt/app/vendor/symfony/routing/Tests/Matcher/Dumper/StaticPrefixCollectionTest.php
|
||||
@ -5337,6 +5820,7 @@ opt/app/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/packagelist
|
||||
opt/app/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/resources.dat
|
||||
opt/app/vendor/symfony/translation/Tests/fixtures/resourcebundle/res/en.res
|
||||
opt/app/vendor/symfony/translation/Tests/fixtures/resources-2.0-clean.xlf
|
||||
opt/app/vendor/symfony/translation/Tests/fixtures/resources-2.0-multi-segment-unit.xlf
|
||||
opt/app/vendor/symfony/translation/Tests/fixtures/resources-2.0.xlf
|
||||
opt/app/vendor/symfony/translation/Tests/fixtures/resources-clean.xlf
|
||||
opt/app/vendor/symfony/translation/Tests/fixtures/resources-notes-meta.xlf
|
||||
@ -5931,6 +6415,7 @@ opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_array_wit
|
||||
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_function_with_undefined_variable.test
|
||||
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_function_with_unknown_argument.test
|
||||
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_tag_with_undefined_variable.test
|
||||
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/strict_comparison_operator.test
|
||||
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/syntax_error_in_reused_template.test
|
||||
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test
|
||||
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_parent.test
|
||||
@ -6301,6 +6786,47 @@ opt/app/vendor/watson/validating/src/ValidatingModel.php
|
||||
opt/app/vendor/watson/validating/src/ValidatingObserver.php
|
||||
opt/app/vendor/watson/validating/src/ValidatingTrait.php
|
||||
opt/app/vendor/watson/validating/src/ValidationException.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/.coveralls.yml
|
||||
opt/app/vendor/zendframework/zend-diactoros/CHANGELOG.md
|
||||
opt/app/vendor/zendframework/zend-diactoros/CONDUCT.md
|
||||
opt/app/vendor/zendframework/zend-diactoros/CONTRIBUTING.md
|
||||
opt/app/vendor/zendframework/zend-diactoros/LICENSE.md
|
||||
opt/app/vendor/zendframework/zend-diactoros/README.md
|
||||
opt/app/vendor/zendframework/zend-diactoros/composer.json
|
||||
opt/app/vendor/zendframework/zend-diactoros/composer.lock
|
||||
opt/app/vendor/zendframework/zend-diactoros/mkdocs.yml
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/AbstractSerializer.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/CallbackStream.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Exception/DeprecatedMethodException.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Exception/ExceptionInterface.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/HeaderSecurity.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/MessageTrait.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/PhpInputStream.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/RelativeStream.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Request.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Request/ArraySerializer.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Request/Serializer.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/RequestTrait.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/ArraySerializer.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/EmitterInterface.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/EmptyResponse.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/HtmlResponse.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/InjectContentTypeTrait.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/JsonResponse.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/RedirectResponse.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/SapiEmitter.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/SapiEmitterTrait.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/SapiStreamEmitter.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/Serializer.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/TextResponse.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Response/XmlResponse.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Server.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/ServerRequest.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/ServerRequestFactory.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Stream.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/UploadedFile.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/Uri.php
|
||||
proc/cpuinfo
|
||||
sandstorm-http-bridge
|
||||
sandstorm-http-bridge-config
|
||||
|
@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = (
|
||||
|
||||
manifest = (
|
||||
appTitle = (defaultText = "Firefly III"),
|
||||
appVersion = 8,
|
||||
appMarketingVersion = (defaultText = "4.7.0"),
|
||||
appVersion = 9,
|
||||
appMarketingVersion = (defaultText = "4.7.1"),
|
||||
|
||||
actions = [
|
||||
# Define your "new document" handlers here.
|
||||
|
@ -1,7 +1,6 @@
|
||||
language: php
|
||||
php:
|
||||
- 7.1
|
||||
- 7.2
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
88
app/Api/V1/Controllers/AboutController.php
Normal file
88
app/Api/V1/Controllers/AboutController.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* AboutController.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Transformers\UserTransformer;
|
||||
use Illuminate\Http\Request;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
|
||||
|
||||
/**
|
||||
* Class AboutController
|
||||
*/
|
||||
class AboutController extends Controller
|
||||
{
|
||||
/**
|
||||
* AccountController constructor.
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function about()
|
||||
{
|
||||
$search = ['~', '#'];
|
||||
$replace = ['\~', '# '];
|
||||
$phpVersion = str_replace($search, $replace, PHP_VERSION);
|
||||
$phpOs = str_replace($search, $replace, php_uname());
|
||||
$currentDriver = DB::getDriverName();
|
||||
$data
|
||||
= [
|
||||
'version' => config('firefly.version'),
|
||||
'api_version' => config('firefly.api_version'),
|
||||
'php_version' => $phpVersion,
|
||||
'os' => $phpOs,
|
||||
'driver' => $currentDriver,
|
||||
|
||||
];
|
||||
|
||||
return response()->json(['data' => $data], 200)->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function user(Request $request)
|
||||
{
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
$resource = new Item(auth()->user(), new UserTransformer($this->parameters), 'users');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
}
|
263
app/Api/V1/Controllers/AccountController.php
Normal file
263
app/Api/V1/Controllers/AccountController.php
Normal file
@ -0,0 +1,263 @@
|
||||
<?php
|
||||
/**
|
||||
* AccountController.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\AccountRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Transformers\AccountTransformer;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class AccountController
|
||||
*/
|
||||
class AccountController extends Controller
|
||||
{
|
||||
|
||||
/** @var CurrencyRepositoryInterface */
|
||||
private $currencyRepository;
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* AccountController constructor.
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
/** @var AccountRepositoryInterface repository */
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
$this->repository->setUser(auth()->user());
|
||||
|
||||
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
|
||||
$this->currencyRepository->setUser(auth()->user());
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \FireflyIII\Models\Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function delete(Account $account)
|
||||
{
|
||||
$this->repository->destroy($account, null);
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// create some objects:
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
|
||||
// read type from URI
|
||||
$type = $request->get('type') ?? 'all';
|
||||
$this->parameters->set('type', $type);
|
||||
|
||||
// types to get, page size:
|
||||
$types = $this->mapTypes($this->parameters->get('type'));
|
||||
$pageSize = intval(Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data);
|
||||
|
||||
// get list of accounts. Count it and split it.
|
||||
$collection = $this->repository->getAccountsByType($types);
|
||||
$count = $collection->count();
|
||||
$accounts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.accounts.index') . $this->buildParams());
|
||||
|
||||
// present to user.
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
$resource = new FractalCollection($accounts, new AccountTransformer($this->parameters), 'accounts');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, Account $account)
|
||||
{
|
||||
$manager = new Manager();
|
||||
|
||||
// add include parameter:
|
||||
$include = $request->get('include') ?? '';
|
||||
$manager->parseIncludes($include);
|
||||
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
$resource = new Item($account, new AccountTransformer($this->parameters), 'accounts');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(AccountRequest $request)
|
||||
{
|
||||
$data = $request->getAll();
|
||||
// if currency ID is 0, find the currency by the code:
|
||||
if ($data['currency_id'] === 0) {
|
||||
$currency = $this->currencyRepository->findByCodeNull($data['currency_code']);
|
||||
$data['currency_id'] = is_null($currency) ? 0 : $currency->id;
|
||||
}
|
||||
$account = $this->repository->store($data);
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$resource = new Item($account, new AccountTransformer($this->parameters), 'accounts');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update account.
|
||||
*
|
||||
* @param AccountRequest $request
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(AccountRequest $request, Account $account)
|
||||
{
|
||||
$data = $request->getAll();
|
||||
// if currency ID is 0, find the currency by the code:
|
||||
if ($data['currency_id'] === 0) {
|
||||
$currency = $this->currencyRepository->findByCodeNull($data['currency_code']);
|
||||
$data['currency_id'] = is_null($currency) ? 0 : $currency->id;
|
||||
}
|
||||
// set correct type:
|
||||
$data['type'] = config('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
$this->repository->update($account, $data);
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$resource = new Item($account, new AccountTransformer($this->parameters), 'accounts');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function mapTypes(string $type): array
|
||||
{
|
||||
$types = [
|
||||
'all' => [
|
||||
AccountType::DEFAULT,
|
||||
AccountType::CASH,
|
||||
AccountType::ASSET,
|
||||
AccountType::EXPENSE,
|
||||
AccountType::REVENUE,
|
||||
AccountType::INITIAL_BALANCE,
|
||||
AccountType::BENEFICIARY,
|
||||
AccountType::IMPORT,
|
||||
AccountType::RECONCILIATION,
|
||||
AccountType::LOAN,
|
||||
],
|
||||
'asset' => [
|
||||
AccountType::DEFAULT,
|
||||
AccountType::ASSET,
|
||||
],
|
||||
'cash' => [
|
||||
AccountType::CASH,
|
||||
],
|
||||
'expense' => [
|
||||
AccountType::EXPENSE,
|
||||
AccountType::BENEFICIARY,
|
||||
],
|
||||
'revenue' => [
|
||||
AccountType::REVENUE,
|
||||
],
|
||||
'special' => [
|
||||
AccountType::CASH,
|
||||
AccountType::INITIAL_BALANCE,
|
||||
AccountType::IMPORT,
|
||||
AccountType::RECONCILIATION,
|
||||
AccountType::LOAN,
|
||||
],
|
||||
'hidden' => [
|
||||
AccountType::INITIAL_BALANCE,
|
||||
AccountType::IMPORT,
|
||||
AccountType::RECONCILIATION,
|
||||
AccountType::LOAN,
|
||||
],
|
||||
AccountType::DEFAULT => [AccountType::DEFAULT],
|
||||
AccountType::CASH => [AccountType::CASH],
|
||||
AccountType::ASSET => [AccountType::ASSET],
|
||||
AccountType::EXPENSE => [AccountType::EXPENSE],
|
||||
AccountType::REVENUE => [AccountType::REVENUE],
|
||||
AccountType::INITIAL_BALANCE => [AccountType::INITIAL_BALANCE],
|
||||
AccountType::BENEFICIARY => [AccountType::BENEFICIARY],
|
||||
AccountType::IMPORT => [AccountType::IMPORT],
|
||||
AccountType::RECONCILIATION => [AccountType::RECONCILIATION],
|
||||
AccountType::LOAN => [AccountType::LOAN],
|
||||
];
|
||||
if (isset($types[$type])) {
|
||||
return $types[$type];
|
||||
}
|
||||
|
||||
return $types['all']; // @codeCoverageIgnore
|
||||
}
|
||||
}
|
164
app/Api/V1/Controllers/BillController.php
Normal file
164
app/Api/V1/Controllers/BillController.php
Normal file
@ -0,0 +1,164 @@
|
||||
<?php
|
||||
/**
|
||||
* BillController.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\BillRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Transformers\BillTransformer;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class BillController
|
||||
*/
|
||||
class BillController extends Controller
|
||||
{
|
||||
/** @var BillRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* BillController constructor.
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
/** @var BillRepositoryInterface repository */
|
||||
$this->repository = app(BillRepositoryInterface::class);
|
||||
$this->repository->setUser(auth()->user());
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \FireflyIII\Models\Bill $bill
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function delete(Bill $bill)
|
||||
{
|
||||
$this->repository->destroy($bill);
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$pageSize = intval(Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data);
|
||||
$paginator = $this->repository->getPaginator($pageSize);
|
||||
/** @var Collection $bills */
|
||||
$bills = $paginator->getCollection();
|
||||
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$resource = new FractalCollection($bills, new BillTransformer($this->parameters), 'bills');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, Bill $bill)
|
||||
{
|
||||
$manager = new Manager();
|
||||
// add include parameter:
|
||||
$include = $request->get('include') ?? '';
|
||||
$manager->parseIncludes($include);
|
||||
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$resource = new Item($bill, new BillTransformer($this->parameters), 'bills');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BillRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(BillRequest $request)
|
||||
{
|
||||
$bill = $this->repository->store($request->getAll());
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$resource = new Item($bill, new BillTransformer($this->parameters), 'bills');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param BillRequest $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(BillRequest $request, Bill $bill)
|
||||
{
|
||||
$data = $request->getAll();
|
||||
$bill = $this->repository->update($bill, $data);
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$resource = new Item($bill, new BillTransformer($this->parameters), 'bills');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
121
app/Api/V1/Controllers/Controller.php
Normal file
121
app/Api/V1/Controllers/Controller.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* Controller.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Carbon\Exceptions\InvalidDateException;
|
||||
use FireflyConfig;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
|
||||
/**
|
||||
* Class Controller.
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
|
||||
/** @var ParameterBag */
|
||||
protected $parameters;
|
||||
|
||||
/**
|
||||
* Controller constructor.
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// is site a demo site?
|
||||
$isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data;
|
||||
|
||||
// do not expose API on demo site:
|
||||
if (true === $isDemoSite) {
|
||||
throw new FireflyException('The API is not available on the demo site.');
|
||||
}
|
||||
|
||||
// get global parameters
|
||||
$this->parameters = $this->getParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function buildParams(): string
|
||||
{
|
||||
$return = '?';
|
||||
$params = [];
|
||||
foreach ($this->parameters as $key => $value) {
|
||||
if($key === 'page') {
|
||||
continue;
|
||||
}
|
||||
if ($value instanceof Carbon) {
|
||||
$params[$key] = $value->format('Y-m-d');
|
||||
}
|
||||
if (!$value instanceof Carbon) {
|
||||
$params[$key] = $value;
|
||||
}
|
||||
}
|
||||
$return .= http_build_query($params);
|
||||
if (strlen($return) === 1) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
private function getParameters(): ParameterBag
|
||||
{
|
||||
$bag = new ParameterBag;
|
||||
$page = (int)request()->get('page');
|
||||
if ($page === 0) {
|
||||
$page = 1;
|
||||
}
|
||||
$bag->set('page', $page);
|
||||
|
||||
// some date fields:
|
||||
$dates = ['start', 'end', 'date'];
|
||||
foreach ($dates as $field) {
|
||||
$date = request()->get($field);
|
||||
$obj = null;
|
||||
if (!is_null($date)) {
|
||||
try {
|
||||
$obj = new Carbon($date);
|
||||
} catch (InvalidDateException $e) {
|
||||
// don't care
|
||||
}
|
||||
}
|
||||
$bag->set($field, $obj);
|
||||
}
|
||||
|
||||
return $bag;
|
||||
|
||||
}
|
||||
}
|
333
app/Api/V1/Controllers/TransactionController.php
Normal file
333
app/Api/V1/Controllers/TransactionController.php
Normal file
@ -0,0 +1,333 @@
|
||||
<?php
|
||||
/**
|
||||
* TransactionController.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\TransactionRequest;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Transformers\TransactionTransformer;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
use Log;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class TransactionController
|
||||
*/
|
||||
class TransactionController extends Controller
|
||||
{
|
||||
|
||||
/** @var JournalRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* TransactionController constructor.
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
/** @var JournalRepositoryInterface repository */
|
||||
$this->repository = app(JournalRepositoryInterface::class);
|
||||
$this->repository->setUser(auth()->user());
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \FireflyIII\Models\Transaction $transaction
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function delete(Transaction $transaction)
|
||||
{
|
||||
$journal = $transaction->transactionJournal;
|
||||
$this->repository->destroy($journal);
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$pageSize = intval(Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data);
|
||||
|
||||
// read type from URI
|
||||
$type = $request->get('type') ?? 'default';
|
||||
$this->parameters->set('type', $type);
|
||||
|
||||
// types to get, page size:
|
||||
$types = $this->mapTypes($this->parameters->get('type'));
|
||||
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// collect transactions using the journal collector
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setUser(auth()->user());
|
||||
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
|
||||
$collector->setAllAssetAccounts();
|
||||
|
||||
// remove internal transfer filter:
|
||||
if (in_array(TransactionType::TRANSFER, $types)) {
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
}
|
||||
|
||||
if (!is_null($this->parameters->get('start')) && !is_null($this->parameters->get('end'))) {
|
||||
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
|
||||
}
|
||||
$collector->setLimit($pageSize)->setPage($this->parameters->get('page'));
|
||||
$collector->setTypes($types);
|
||||
$paginator = $collector->getPaginatedJournals();
|
||||
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
|
||||
$transactions = $paginator->getCollection();
|
||||
|
||||
|
||||
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Transaction $transaction
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, Transaction $transaction)
|
||||
{
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// add include parameter:
|
||||
$include = $request->get('include') ?? '';
|
||||
$manager->parseIncludes($include);
|
||||
|
||||
// collect transactions using the journal collector
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setUser(auth()->user());
|
||||
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
|
||||
// filter on specific journals.
|
||||
$collector->setJournals(new Collection([$transaction->transactionJournal]));
|
||||
|
||||
// add filter to remove transactions:
|
||||
$transactionType = $transaction->transactionJournal->transactionType->type;
|
||||
if ($transactionType === TransactionType::WITHDRAWAL) {
|
||||
$collector->addFilter(PositiveAmountFilter::class);
|
||||
}
|
||||
if (!($transactionType === TransactionType::WITHDRAWAL)) {
|
||||
$collector->addFilter(NegativeAmountFilter::class);
|
||||
}
|
||||
|
||||
$transactions = $collector->getJournals();
|
||||
$resource = new Item($transactions->first(), new TransactionTransformer($this->parameters), 'transactions');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(TransactionRequest $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
$data = $request->getAll();
|
||||
$data['user'] = auth()->user()->id;
|
||||
$journal = $repository->store($data);
|
||||
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// add include parameter:
|
||||
$include = $request->get('include') ?? '';
|
||||
$manager->parseIncludes($include);
|
||||
|
||||
// collect transactions using the journal collector
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setUser(auth()->user());
|
||||
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
|
||||
// filter on specific journals.
|
||||
$collector->setJournals(new Collection([$journal]));
|
||||
|
||||
// add filter to remove transactions:
|
||||
$transactionType = $journal->transactionType->type;
|
||||
if ($transactionType === TransactionType::WITHDRAWAL) {
|
||||
$collector->addFilter(PositiveAmountFilter::class);
|
||||
}
|
||||
if (!($transactionType === TransactionType::WITHDRAWAL)) {
|
||||
$collector->addFilter(NegativeAmountFilter::class);
|
||||
}
|
||||
|
||||
$transactions = $collector->getJournals();
|
||||
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param TransactionRequest $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param Transaction $transaction
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(TransactionRequest $request, JournalRepositoryInterface $repository, Transaction $transaction)
|
||||
{
|
||||
$data = $request->getAll();
|
||||
$data['user'] = auth()->user()->id;
|
||||
|
||||
Log::debug('Inside transaction update');
|
||||
|
||||
$journal = $repository->update($transaction->transactionJournal, $data);
|
||||
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// add include parameter:
|
||||
$include = $request->get('include') ?? '';
|
||||
$manager->parseIncludes($include);
|
||||
|
||||
// needs a lot of extra data to match the journal collector. Or just expand that one.
|
||||
// collect transactions using the journal collector
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setUser(auth()->user());
|
||||
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
|
||||
// filter on specific journals.
|
||||
$collector->setJournals(new Collection([$journal]));
|
||||
|
||||
// add filter to remove transactions:
|
||||
$transactionType = $journal->transactionType->type;
|
||||
if ($transactionType === TransactionType::WITHDRAWAL) {
|
||||
$collector->addFilter(PositiveAmountFilter::class);
|
||||
}
|
||||
if (!($transactionType === TransactionType::WITHDRAWAL)) {
|
||||
$collector->addFilter(NegativeAmountFilter::class);
|
||||
}
|
||||
|
||||
$transactions = $collector->getJournals();
|
||||
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function mapTypes(string $type): array
|
||||
{
|
||||
$types = [
|
||||
'all' => [
|
||||
TransactionType::WITHDRAWAL,
|
||||
TransactionType::DEPOSIT,
|
||||
TransactionType::TRANSFER,
|
||||
TransactionType::OPENING_BALANCE,
|
||||
TransactionType::RECONCILIATION,
|
||||
],
|
||||
'withdrawal' => [
|
||||
TransactionType::WITHDRAWAL,
|
||||
],
|
||||
'withdrawals' => [
|
||||
TransactionType::WITHDRAWAL,
|
||||
],
|
||||
'expense' => [
|
||||
TransactionType::WITHDRAWAL,
|
||||
],
|
||||
'income' => [
|
||||
TransactionType::DEPOSIT,
|
||||
],
|
||||
'deposit' => [
|
||||
TransactionType::DEPOSIT,
|
||||
],
|
||||
'deposits' => [
|
||||
TransactionType::DEPOSIT,
|
||||
],
|
||||
'transfer' => [
|
||||
TransactionType::TRANSFER,
|
||||
],
|
||||
'transfers' => [
|
||||
TransactionType::TRANSFER,
|
||||
],
|
||||
'opening_balance' => [
|
||||
TransactionType::OPENING_BALANCE,
|
||||
],
|
||||
'reconciliation' => [
|
||||
TransactionType::RECONCILIATION,
|
||||
],
|
||||
'reconciliations' => [
|
||||
TransactionType::RECONCILIATION,
|
||||
],
|
||||
'special' => [
|
||||
TransactionType::OPENING_BALANCE,
|
||||
TransactionType::RECONCILIATION,
|
||||
],
|
||||
'specials' => [
|
||||
TransactionType::OPENING_BALANCE,
|
||||
TransactionType::RECONCILIATION,
|
||||
],
|
||||
'default' => [
|
||||
TransactionType::WITHDRAWAL,
|
||||
TransactionType::DEPOSIT,
|
||||
TransactionType::TRANSFER,
|
||||
],
|
||||
];
|
||||
if (isset($types[$type])) {
|
||||
return $types[$type];
|
||||
}
|
||||
|
||||
return $types['default']; // @codeCoverageIgnore
|
||||
|
||||
}
|
||||
}
|
192
app/Api/V1/Controllers/UserController.php
Normal file
192
app/Api/V1/Controllers/UserController.php
Normal file
@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/**
|
||||
* UserController.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\UserRequest;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Transformers\UserTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
use Preferences;
|
||||
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Class UserController
|
||||
*/
|
||||
class UserController extends Controller
|
||||
{
|
||||
|
||||
/** @var UserRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* UserController constructor.
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
/** @var UserRepositoryInterface repository */
|
||||
$this->repository = app(UserRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \FireflyIII\User $user
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function delete(User $user)
|
||||
{
|
||||
if (auth()->user()->hasRole('owner')) {
|
||||
$this->repository->destroy($user);
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
throw new AccessDeniedException(''); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// user preferences
|
||||
$pageSize = intval(Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data);
|
||||
|
||||
// make manager
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// build collection
|
||||
$collection = $this->repository->all();
|
||||
$count = $collection->count();
|
||||
$users = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($users, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.users.index') . $this->buildParams());
|
||||
|
||||
// make resource
|
||||
$resource = new FractalCollection($users, new UserTransformer($this->parameters), 'users');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param User $user
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, User $user)
|
||||
{
|
||||
// make manager
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// add include parameter:
|
||||
$include = $request->get('include') ?? '';
|
||||
$manager->parseIncludes($include);
|
||||
|
||||
// make resource
|
||||
$resource = new Item($user, new UserTransformer($this->parameters), 'users');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(UserRequest $request)
|
||||
{
|
||||
$data = $request->getAll();
|
||||
$user = $this->repository->store($data);
|
||||
|
||||
// make manager
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// add include parameter:
|
||||
$include = $request->get('include') ?? '';
|
||||
$manager->parseIncludes($include);
|
||||
|
||||
// make resource
|
||||
$resource = new Item($user, new UserTransformer($this->parameters), 'users');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserRequest $request
|
||||
* @param User $user
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(UserRequest $request, User $user)
|
||||
{
|
||||
$data = $request->getAll();
|
||||
$user = $this->repository->update($user, $data);
|
||||
|
||||
// make manager
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// add include parameter:
|
||||
$include = $request->get('include') ?? '';
|
||||
$manager->parseIncludes($include);
|
||||
|
||||
// make resource
|
||||
$resource = new Item($user, new UserTransformer($this->parameters), 'users');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
|
||||
}
|
107
app/Api/V1/Requests/AccountRequest.php
Normal file
107
app/Api/V1/Requests/AccountRequest.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* AccountRequest.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
/**
|
||||
* Class AccountRequest
|
||||
*/
|
||||
class AccountRequest extends Request
|
||||
{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow authenticated users
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$data = [
|
||||
'name' => $this->string('name'),
|
||||
'active' => $this->boolean('active'),
|
||||
'accountType' => $this->string('type'),
|
||||
'account_type_id' => null,
|
||||
'currency_id' => $this->integer('currency_id'),
|
||||
'currency_code' => $this->string('currency_code'),
|
||||
'virtualBalance' => $this->string('virtual_balance'),
|
||||
'iban' => $this->string('iban'),
|
||||
'BIC' => $this->string('bic'),
|
||||
'accountNumber' => $this->string('account_number'),
|
||||
'accountRole' => $this->string('account_role'),
|
||||
'openingBalance' => $this->string('opening_balance'),
|
||||
'openingBalanceDate' => $this->date('opening_balance_date'),
|
||||
'ccType' => $this->string('cc_type'),
|
||||
'ccMonthlyPaymentDate' => $this->string('cc_monthly_payment_date'),
|
||||
'notes' => $this->string('notes'),
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$accountRoles = join(',', config('firefly.accountRoles'));
|
||||
$types = join(',', array_keys(config('firefly.subTitlesByIdentifier')));
|
||||
$ccPaymentTypes = join(',', array_keys(config('firefly.ccTypes')));
|
||||
$rules = [
|
||||
'name' => 'required|min:1|uniqueAccountForUser',
|
||||
'opening_balance' => 'numeric|required_with:opening_balance_date|nullable',
|
||||
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
|
||||
'iban' => 'iban|nullable',
|
||||
'bic' => 'bic|nullable',
|
||||
'virtual_balance' => 'numeric|nullable',
|
||||
'currency_id' => 'numeric|exists:transaction_currencies,id|required_without:currency_code',
|
||||
'currency_code' => 'min:3|max:3|exists:transaction_currencies,code|required_without:currency_id',
|
||||
'account_number' => 'between:1,255|nullable|uniqueAccountNumberForUser',
|
||||
'account_role' => 'in:' . $accountRoles . '|required_if:type,asset',
|
||||
'active' => 'required|boolean',
|
||||
'cc_type' => 'in:' . $ccPaymentTypes . '|required_if:account_role,ccAsset',
|
||||
'cc_monthly_payment_date' => 'date' . '|required_if:account_role,ccAsset|required_if:cc_type,monthlyFull',
|
||||
'type' => 'required|in:' . $types,
|
||||
'notes' => 'min:0|max:65536',
|
||||
];
|
||||
switch ($this->method()) {
|
||||
default:
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'PATCH':
|
||||
$account = $this->route()->parameter('account');
|
||||
$rules['name'] .= ':' . $account->id;
|
||||
$rules['account_number'] .= ':' . $account->id;
|
||||
$rules['type'] = 'in:' . $types;
|
||||
break;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
119
app/Api/V1/Requests/BillRequest.php
Normal file
119
app/Api/V1/Requests/BillRequest.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* BillRequest.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class BillRequest
|
||||
*/
|
||||
class BillRequest extends Request
|
||||
{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow authenticated users
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$data = [
|
||||
'name' => $this->string('name'),
|
||||
'match' => $this->string('match'),
|
||||
'amount_min' => $this->string('amount_min'),
|
||||
'amount_max' => $this->string('amount_max'),
|
||||
//'currency_id' => $this->integer('currency_id'),
|
||||
//'currency_code' => $this->string('currency_code'),
|
||||
'date' => $this->date('date'),
|
||||
'repeat_freq' => $this->string('repeat_freq'),
|
||||
'skip' => $this->integer('skip'),
|
||||
'automatch' => $this->boolean('automatch'),
|
||||
'active' => $this->boolean('active'),
|
||||
'notes' => $this->string('notes'),
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required|between:1,255|uniqueObjectForUser:bills,name',
|
||||
'match' => 'required|between:1,255|uniqueObjectForUser:bills,match',
|
||||
'amount_min' => 'required|numeric|more:0',
|
||||
'amount_max' => 'required|numeric|more:0',
|
||||
//'currency_id' => 'numeric|exists:transaction_currencies,id|required_without:currency_code',
|
||||
//'currency_code' => 'min:3|max:3|exists:transaction_currencies,code|required_without:currency_id',
|
||||
'date' => 'required|date',
|
||||
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
|
||||
'skip' => 'required|between:0,31',
|
||||
'automatch' => 'required|boolean',
|
||||
'active' => 'required|boolean',
|
||||
'notes' => 'between:1,65536',
|
||||
];
|
||||
switch ($this->method()) {
|
||||
default:
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'PATCH':
|
||||
$bill = $this->route()->parameter('bill');
|
||||
$rules['name'] .= ',' . $bill->id;
|
||||
$rules['match'] .= ',' . $bill->id;
|
||||
break;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator instance.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(
|
||||
function (Validator $validator) {
|
||||
$data = $validator->getData();
|
||||
$min = floatval($data['amount_min'] ?? 0);
|
||||
$max = floatval($data['amount_max'] ?? 0);
|
||||
if ($min > $max) {
|
||||
$validator->errors()->add('amount_min', trans('validation.amount_min_over_max'));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
32
app/Api/V1/Requests/Request.php
Normal file
32
app/Api/V1/Requests/Request.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* Request.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use FireflyIII\Http\Requests\Request as FireflyIIIRequest;
|
||||
/**
|
||||
* Class Request.
|
||||
*/
|
||||
class Request extends FireflyIIIRequest
|
||||
{
|
||||
|
||||
}
|
500
app/Api/V1/Requests/TransactionRequest.php
Normal file
500
app/Api/V1/Requests/TransactionRequest.php
Normal file
@ -0,0 +1,500 @@
|
||||
<?php
|
||||
/**
|
||||
* TransactionRequest.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Rules\BelongsUser;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
|
||||
/**
|
||||
* Class TransactionRequest
|
||||
*/
|
||||
class TransactionRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow authenticated users
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$data = [
|
||||
// basic fields for journal:
|
||||
'type' => $this->string('type'),
|
||||
'date' => $this->date('date'),
|
||||
'description' => $this->string('description'),
|
||||
'piggy_bank_id' => $this->integer('piggy_bank_id'),
|
||||
'piggy_bank_name' => $this->string('piggy_bank_name'),
|
||||
'bill_id' => $this->integer('bill_id'),
|
||||
'bill_name' => $this->string('bill_name'),
|
||||
'tags' => explode(',', $this->string('tags')),
|
||||
|
||||
// then, custom fields for journal
|
||||
'interest_date' => $this->date('interest_date'),
|
||||
'book_date' => $this->date('book_date'),
|
||||
'process_date' => $this->date('process_date'),
|
||||
'due_date' => $this->date('due_date'),
|
||||
'payment_date' => $this->date('payment_date'),
|
||||
'invoice_date' => $this->date('invoice_date'),
|
||||
'internal_reference' => $this->string('internal_reference'),
|
||||
'notes' => $this->string('notes'),
|
||||
|
||||
// then, transactions (see below).
|
||||
'transactions' => [],
|
||||
|
||||
];
|
||||
foreach ($this->get('transactions') as $index => $transaction) {
|
||||
$array = [
|
||||
'description' => $transaction['description'] ?? null,
|
||||
'amount' => $transaction['amount'],
|
||||
'currency_id' => isset($transaction['currency_id']) ? intval($transaction['currency_id']) : null,
|
||||
'currency_code' => isset($transaction['currency_code']) ? $transaction['currency_code'] : null,
|
||||
'foreign_amount' => $transaction['foreign_amount'] ?? null,
|
||||
'foreign_currency_id' => isset($transaction['foreign_currency_id']) ? intval($transaction['foreign_currency_id']) : null,
|
||||
'foreign_currency_code' => $transaction['foreign_currency_code'] ?? null,
|
||||
'budget_id' => isset($transaction['budget_id']) ? intval($transaction['budget_id']) : null,
|
||||
'budget_name' => $transaction['budget_name'] ?? null,
|
||||
'category_id' => isset($transaction['category_id']) ? intval($transaction['category_id']) : null,
|
||||
'category_name' => $transaction['category_name'] ?? null,
|
||||
'source_id' => isset($transaction['source_id']) ? intval($transaction['source_id']) : null,
|
||||
'source_name' => isset($transaction['source_name']) ? strval($transaction['source_name']) : null,
|
||||
'destination_id' => isset($transaction['destination_id']) ? intval($transaction['destination_id']) : null,
|
||||
'destination_name' => isset($transaction['destination_name']) ? strval($transaction['destination_name']) : null,
|
||||
'reconciled' => $transaction['reconciled'] ?? false,
|
||||
'identifier' => $index,
|
||||
];
|
||||
$data['transactions'][] = $array;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
// basic fields for journal:
|
||||
'type' => 'required|in:withdrawal,deposit,transfer',
|
||||
'date' => 'required|date',
|
||||
'description' => 'between:1,255',
|
||||
'piggy_bank_id' => ['numeric', 'nullable', 'mustExist:piggy_banks,id', new BelongsUser],
|
||||
'piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUser],
|
||||
'bill_id' => ['numeric', 'nullable', 'mustExist:bills,id', new BelongsUser],
|
||||
'bill_name' => ['between:1,255', 'nullable', new BelongsUser],
|
||||
'tags' => 'between:1,255',
|
||||
|
||||
// then, custom fields for journal
|
||||
'interest_date' => 'date|nullable',
|
||||
'book_date' => 'date|nullable',
|
||||
'process_date' => 'date|nullable',
|
||||
'due_date' => 'date|nullable',
|
||||
'payment_date' => 'date|nullable',
|
||||
'invoice_date' => 'date|nullable',
|
||||
'internal_reference' => 'min:1,max:255|nullable',
|
||||
'notes' => 'min:1,max:50000|nullable',
|
||||
|
||||
// transaction rules (in array for splits):
|
||||
'transactions.*.description' => 'nullable|between:1,255',
|
||||
'transactions.*.amount' => 'required|numeric|more:0',
|
||||
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id|required_without:transactions.*.currency_code',
|
||||
'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code|required_without:transactions.*.currency_id',
|
||||
'transactions.*.foreign_amount' => 'numeric|more:0',
|
||||
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'transactions.*.foreign_currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
|
||||
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser],
|
||||
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser],
|
||||
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUser],
|
||||
'transactions.*.category_name' => 'between:1,255|nullable',
|
||||
'transactions.*.reconciled' => 'boolean|nullable',
|
||||
// basic rules will be expanded later.
|
||||
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser],
|
||||
'transactions.*.source_name' => 'between:1,255|nullable',
|
||||
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser],
|
||||
'transactions.*.destination_name' => 'between:1,255|nullable',
|
||||
];
|
||||
|
||||
switch ($this->method()) {
|
||||
default:
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'PATCH':
|
||||
unset($rules['type'], $rules['piggy_bank_id'], $rules['piggy_bank_name']);
|
||||
break;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator instance.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(
|
||||
function (Validator $validator) {
|
||||
$this->atLeastOneTransaction($validator);
|
||||
$this->checkValidDescriptions($validator);
|
||||
$this->equalToJournalDescription($validator);
|
||||
$this->emptySplitDescriptions($validator);
|
||||
$this->foreignCurrencyInformation($validator);
|
||||
$this->validateAccountInformation($validator);
|
||||
$this->validateSplitAccounts($validator);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an error when this asset account is invalid.
|
||||
*
|
||||
* @param Validator $validator
|
||||
* @param int|null $accountId
|
||||
* @param null|string $accountName
|
||||
* @param string $idField
|
||||
* @param string $nameField
|
||||
*/
|
||||
protected function assetAccountExists(Validator $validator, ?int $accountId, ?string $accountName, string $idField, string $nameField): void
|
||||
{
|
||||
|
||||
$accountId = intval($accountId);
|
||||
$accountName = strval($accountName);
|
||||
// both empty? hard exit.
|
||||
if ($accountId < 1 && strlen($accountName) === 0) {
|
||||
$validator->errors()->add($idField, trans('validation.filled', ['attribute' => $idField]));
|
||||
|
||||
return;
|
||||
}
|
||||
// ID belongs to user and is asset account:
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$set = $repository->getAccountsById([$accountId]);
|
||||
if ($set->count() === 1) {
|
||||
/** @var Account $first */
|
||||
$first = $set->first();
|
||||
if ($first->accountType->type !== AccountType::ASSET) {
|
||||
$validator->errors()->add($idField, trans('validation.belongs_user'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// we ignore the account name at this point.
|
||||
return;
|
||||
}
|
||||
|
||||
$account = $repository->findByName($accountName, [AccountType::ASSET]);
|
||||
if (is_null($account)) {
|
||||
$validator->errors()->add($nameField, trans('validation.belongs_user'));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no transactions in the array of data.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function atLeastOneTransaction(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$transactions = $data['transactions'] ?? [];
|
||||
// need at least one transaction
|
||||
if (count($transactions) === 0) {
|
||||
$validator->errors()->add('description', trans('validation.at_least_one_transaction'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the "description" field when the user has submitted no descriptions and no
|
||||
* journal description.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function checkValidDescriptions(Validator $validator)
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$transactions = $data['transactions'] ?? [];
|
||||
$journalDescription = strval($data['description'] ?? '');
|
||||
$validDescriptions = 0;
|
||||
foreach ($transactions as $index => $transaction) {
|
||||
if (strlen(strval($transaction['description'] ?? '')) > 0) {
|
||||
$validDescriptions++;
|
||||
}
|
||||
}
|
||||
|
||||
// no valid descriptions and empty journal description? error.
|
||||
if ($validDescriptions === 0 && strlen($journalDescription) === 0) {
|
||||
$validator->errors()->add('description', trans('validation.filled', ['attribute' => trans('validation.attributes.description')]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when the user submits a split transaction (more than 1 transactions)
|
||||
* but does not give them a description.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function emptySplitDescriptions(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$transactions = $data['transactions'] ?? [];
|
||||
foreach ($transactions as $index => $transaction) {
|
||||
$description = strval($transaction['description'] ?? '');
|
||||
// filled description is mandatory for split transactions.
|
||||
if (count($transactions) > 1 && strlen($description) === 0) {
|
||||
$validator->errors()->add(
|
||||
'transactions.' . $index . '.description',
|
||||
trans('validation.filled', ['attribute' => trans('validation.attributes.transaction_description')])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when any transaction descriptions are equal to the journal description.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function equalToJournalDescription(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$transactions = $data['transactions'] ?? [];
|
||||
$journalDescription = strval($data['description'] ?? '');
|
||||
foreach ($transactions as $index => $transaction) {
|
||||
$description = strval($transaction['description'] ?? '');
|
||||
// description cannot be equal to journal description.
|
||||
if ($description === $journalDescription) {
|
||||
$validator->errors()->add('transactions.' . $index . '.description', trans('validation.equal_description'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the transactions contain foreign amounts, there must also be foreign currency information.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function foreignCurrencyInformation(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$transactions = $data['transactions'] ?? [];
|
||||
foreach ($transactions as $index => $transaction) {
|
||||
// must have currency info.
|
||||
if (isset($transaction['foreign_amount'])
|
||||
&& !(isset($transaction['foreign_currency_id'])
|
||||
|| isset($transaction['foreign_currency_code']))) {
|
||||
$validator->errors()->add(
|
||||
'transactions.' . $index . '.foreign_amount',
|
||||
trans('validation.require_currency_info')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an error when the given opposing account (of type $type) is invalid.
|
||||
* Empty data is allowed, system will default to cash.
|
||||
*
|
||||
* @param Validator $validator
|
||||
* @param string $type
|
||||
* @param int|null $accountId
|
||||
* @param null|string $accountName
|
||||
* @param string $idField
|
||||
*/
|
||||
protected function opposingAccountExists(Validator $validator, string $type, ?int $accountId, ?string $accountName, string $idField): void {
|
||||
$accountId = intval($accountId);
|
||||
$accountName = strval($accountName);
|
||||
// both empty? done!
|
||||
if ($accountId < 1 && strlen($accountName) === 0) {
|
||||
return;
|
||||
}
|
||||
if ($accountId !== 0) {
|
||||
// ID belongs to user and is $type account:
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$set = $repository->getAccountsById([$accountId]);
|
||||
if ($set->count() === 1) {
|
||||
/** @var Account $first */
|
||||
$first = $set->first();
|
||||
if ($first->accountType->type !== $type) {
|
||||
$validator->errors()->add($idField, trans('validation.belongs_user'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// we ignore the account name at this point.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not having an opposing account by this name is NOT a problem.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the given account information. Switches on given transaction type.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
protected function validateAccountInformation(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$transactions = $data['transactions'] ?? [];
|
||||
if (!isset($data['type'])) {
|
||||
// the journal may exist in the request:
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $this->route()->parameter('transaction');
|
||||
if (is_null($transaction)) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
$data['type'] = strtolower($transaction->transactionJournal->transactionType->type);
|
||||
}
|
||||
foreach ($transactions as $index => $transaction) {
|
||||
$sourceId = isset($transaction['source_id']) ? intval($transaction['source_id']) : null;
|
||||
$sourceName = $transaction['source_name'] ?? null;
|
||||
$destinationId = isset($transaction['destination_id']) ? intval($transaction['destination_id']) : null;
|
||||
$destinationName = $transaction['destination_name'] ?? null;
|
||||
|
||||
switch ($data['type']) {
|
||||
case 'withdrawal':
|
||||
$idField = 'transactions.' . $index . '.source_id';
|
||||
$nameField = 'transactions.' . $index . '.source_name';
|
||||
$this->assetAccountExists($validator, $sourceId, $sourceName, $idField, $nameField);
|
||||
|
||||
$idField = 'transactions.' . $index . '.destination_id';
|
||||
$this->opposingAccountExists($validator, AccountType::EXPENSE, $destinationId, $destinationName, $idField);
|
||||
break;
|
||||
case 'deposit':
|
||||
$idField = 'transactions.' . $index . '.source_id';
|
||||
$this->opposingAccountExists($validator, AccountType::REVENUE, $sourceId, $sourceName, $idField);
|
||||
|
||||
$idField = 'transactions.' . $index . '.destination_id';
|
||||
$nameField = 'transactions.' . $index . '.destination_name';
|
||||
$this->assetAccountExists($validator, $destinationId, $destinationName, $idField, $nameField);
|
||||
break;
|
||||
case 'transfer':
|
||||
$idField = 'transactions.' . $index . '.source_id';
|
||||
$nameField = 'transactions.' . $index . '.source_name';
|
||||
$this->assetAccountExists($validator, $sourceId, $sourceName, $idField, $nameField);
|
||||
|
||||
$idField = 'transactions.' . $index . '.destination_id';
|
||||
$nameField = 'transactions.' . $index . '.destination_name';
|
||||
$this->assetAccountExists($validator, $destinationId, $destinationName, $idField, $nameField);
|
||||
break;
|
||||
default:
|
||||
throw new FireflyException(sprintf('The validator cannot handle transaction type "%s" in validateAccountInformation().', $data['type']));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Validator $validator
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
protected function validateSplitAccounts(Validator $validator)
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$count = isset($data['transactions']) ? count($data['transactions']) : 0;
|
||||
if ($count < 2) {
|
||||
return;
|
||||
}
|
||||
// this is pretty much impossible:
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!isset($data['type'])) {
|
||||
// the journal may exist in the request:
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $this->route()->parameter('transaction');
|
||||
if (is_null($transaction)) {
|
||||
return;
|
||||
}
|
||||
$data['type'] = strtolower($transaction->transactionJournal->transactionType->type);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
// collect all source ID's and destination ID's, if present:
|
||||
$sources = [];
|
||||
$destinations = [];
|
||||
|
||||
foreach ($data['transactions'] as $transaction) {
|
||||
$sources[] = isset($transaction['source_id']) ? intval($transaction['source_id']) : 0;
|
||||
$destinations[] = isset($transaction['destination_id']) ? intval($transaction['destination_id']) : 0;
|
||||
}
|
||||
$destinations = array_unique($destinations);
|
||||
$sources = array_unique($sources);
|
||||
// switch on type:
|
||||
switch ($data['type']) {
|
||||
case 'withdrawal':
|
||||
if (count($sources) > 1) {
|
||||
$validator->errors()->add('transactions.0.source_id', trans('validation.all_accounts_equal'));
|
||||
}
|
||||
break;
|
||||
case 'deposit':
|
||||
if (count($destinations) > 1) {
|
||||
$validator->errors()->add('transactions.0.destination_id', trans('validation.all_accounts_equal'));
|
||||
}
|
||||
break;
|
||||
case 'transfer':
|
||||
if (count($sources) > 1 || count($destinations) > 1) {
|
||||
$validator->errors()->add('transactions.0.source_id', trans('validation.all_accounts_equal'));
|
||||
$validator->errors()->add('transactions.0.destination_id', trans('validation.all_accounts_equal'));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new FireflyException(
|
||||
sprintf('The validator cannot handle transaction type "%s" in validateSplitAccounts().', $data['type'])
|
||||
);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
89
app/Api/V1/Requests/UserRequest.php
Normal file
89
app/Api/V1/Requests/UserRequest.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* UserRequest.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use FireflyIII\User;
|
||||
|
||||
|
||||
/**
|
||||
* Class UserRequest
|
||||
*/
|
||||
class UserRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow authenticated users
|
||||
if (!auth()->check()) {
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
if (!$user->hasRole('owner')) {
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$data = [
|
||||
'email' => $this->string('email'),
|
||||
'blocked' => $this->boolean('blocked'),
|
||||
'blocked_code' => $this->string('blocked_code'),
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'email' => 'required|email|unique:users,email,',
|
||||
'blocked' => 'required|boolean',
|
||||
'blocked_code' => 'in:email_changed',
|
||||
];
|
||||
switch ($this->method()) {
|
||||
default:
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'PATCH':
|
||||
$user = $this->route()->parameter('user');
|
||||
$rules['email'] = 'required|email|unique:users,email,' . $user->id;
|
||||
break;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
}
|
@ -85,8 +85,8 @@ class Import extends Command
|
||||
$monolog->pushHandler($handler);
|
||||
|
||||
// actually start job:
|
||||
$type = 'csv' === $job->file_type ? 'file' : $job->file_type;
|
||||
$key = sprintf('import.routine.%s', $type);
|
||||
$type = 'csv' === $job->file_type ? 'file' : $job->file_type;
|
||||
$key = sprintf('import.routine.%s', $type);
|
||||
$className = config($key);
|
||||
if (null === $className || !class_exists($className)) {
|
||||
throw new FireflyException(sprintf('Cannot find import routine class for job of type "%s".', $type)); // @codeCoverageIgnore
|
||||
|
@ -25,8 +25,11 @@ namespace FireflyIII\Exceptions;
|
||||
use ErrorException;
|
||||
use Exception;
|
||||
use FireflyIII\Jobs\MailError;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Request;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Class Handler
|
||||
@ -62,6 +65,36 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
public function render($request, Exception $exception)
|
||||
{
|
||||
if ($exception instanceof ValidationException && $request->expectsJson()) {
|
||||
// ignore it: controller will handle it.
|
||||
return parent::render($request, $exception);
|
||||
}
|
||||
if ($exception instanceof NotFoundHttpException && $request->expectsJson()) {
|
||||
return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404);
|
||||
}
|
||||
|
||||
if ($exception instanceof AuthenticationException && $request->expectsJson()) {
|
||||
return response()->json(['message' => 'Unauthenticated', 'exception' => 'AuthenticationException'], 401);
|
||||
}
|
||||
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
$isDebug = config('app.debug', false);
|
||||
if ($isDebug) {
|
||||
return response()->json(
|
||||
[
|
||||
'message' => $exception->getMessage(),
|
||||
'exception' => get_class($exception),
|
||||
'line' => $exception->getLine(),
|
||||
'file' => $exception->getFile(),
|
||||
'trace' => $exception->getTrace(),
|
||||
], 500
|
||||
);
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Internal Firefly III Exception. See log files.', 'exception' => get_class($exception)], 500);
|
||||
}
|
||||
|
||||
if ($exception instanceof FireflyException || $exception instanceof ErrorException) {
|
||||
$isDebug = env('APP_DEBUG', false);
|
||||
|
||||
|
171
app/Factory/AccountFactory.php
Normal file
171
app/Factory/AccountFactory.php
Normal file
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
* AccountFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Services\Internal\Support\AccountServiceTrait;
|
||||
use FireflyIII\User;
|
||||
|
||||
/**
|
||||
* Factory to create or return accounts.
|
||||
*
|
||||
* Class AccountFactory
|
||||
*/
|
||||
class AccountFactory
|
||||
{
|
||||
use AccountServiceTrait;
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Account
|
||||
*/
|
||||
public function create(array $data): Account
|
||||
{
|
||||
$type = $this->getAccountType($data['account_type_id'], $data['accountType']);
|
||||
$data['iban'] = $this->filterIban($data['iban']);
|
||||
|
||||
|
||||
// account may exist already:
|
||||
$existingAccount = $this->find($data['name'], $type->type);
|
||||
if (null !== $existingAccount) {
|
||||
return $existingAccount;
|
||||
}
|
||||
|
||||
|
||||
// create it:
|
||||
$databaseData
|
||||
= [
|
||||
'user_id' => $this->user->id,
|
||||
'account_type_id' => $type->id,
|
||||
'name' => $data['name'],
|
||||
'virtual_balance' => strlen(strval($data['virtualBalance'])) === 0 ? '0' : $data['virtualBalance'],
|
||||
'active' => true === $data['active'] ? true : false,
|
||||
'iban' => $data['iban'],
|
||||
];
|
||||
|
||||
// remove virtual balance when not an asset account:
|
||||
if ($type->type !== AccountType::ASSET) {
|
||||
$databaseData['virtual_balance'] = '0';
|
||||
}
|
||||
|
||||
$newAccount = Account::create($databaseData);
|
||||
$this->updateMetadata($newAccount, $data);
|
||||
|
||||
if ($this->validIBData($data) && $type->type === AccountType::ASSET) {
|
||||
$this->updateIB($newAccount, $data);
|
||||
}
|
||||
if (!$this->validIBData($data) && $type->type === AccountType::ASSET) {
|
||||
$this->deleteIB($newAccount);
|
||||
}
|
||||
// update note:
|
||||
if (isset($data['notes'])) {
|
||||
$this->updateNote($newAccount, $data['notes']);
|
||||
}
|
||||
|
||||
return $newAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accountName
|
||||
* @param string $accountType
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
public function find(string $accountName, string $accountType): ?Account
|
||||
{
|
||||
$type = AccountType::whereType($accountType)->first();
|
||||
$accounts = $this->user->accounts()->where('account_type_id', $type->id)->get(['accounts.*']);
|
||||
|
||||
/** @var Account $object */
|
||||
foreach ($accounts as $object) {
|
||||
if ($object->name === $accountName) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accountName
|
||||
* @param string $accountType
|
||||
*
|
||||
* @return Account
|
||||
*/
|
||||
public function findOrCreate(string $accountName, string $accountType): Account
|
||||
{
|
||||
$type = AccountType::whereType($accountType)->first();
|
||||
$accounts = $this->user->accounts()->where('account_type_id', $type->id)->get(['accounts.*']);
|
||||
|
||||
/** @var Account $object */
|
||||
foreach ($accounts as $object) {
|
||||
if ($object->name === $accountName) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $accountName,
|
||||
'account_type_id' => $type->id,
|
||||
'accountType' => null,
|
||||
'virtualBalance' => '0',
|
||||
'iban' => null,
|
||||
'active' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $accountTypeId
|
||||
* @param null|string $accountType
|
||||
*
|
||||
* @return AccountType|null
|
||||
*/
|
||||
protected function getAccountType(?int $accountTypeId, ?string $accountType): ?AccountType
|
||||
{
|
||||
$accountTypeId = intval($accountTypeId);
|
||||
if ($accountTypeId > 0) {
|
||||
return AccountType::find($accountTypeId);
|
||||
}
|
||||
$type = config('firefly.accountTypeByIdentifier.' . strval($accountType));
|
||||
|
||||
return AccountType::whereType($type)->first();
|
||||
|
||||
}
|
||||
|
||||
}
|
43
app/Factory/AccountMetaFactory.php
Normal file
43
app/Factory/AccountMetaFactory.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* AccountMetaFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
|
||||
/**
|
||||
* Class AccountMetaFactory
|
||||
*/
|
||||
class AccountMetaFactory
|
||||
{
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return AccountMeta|null
|
||||
*/
|
||||
public function create(array $data): ?AccountMeta
|
||||
{
|
||||
return AccountMeta::create($data);
|
||||
}
|
||||
|
||||
}
|
137
app/Factory/BillFactory.php
Normal file
137
app/Factory/BillFactory.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* BillFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Services\Internal\Support\BillServiceTrait;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class BillFactory
|
||||
*/
|
||||
class BillFactory
|
||||
{
|
||||
use BillServiceTrait;
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Bill|null
|
||||
*/
|
||||
public function create(array $data): ?Bill
|
||||
{
|
||||
$matchArray = explode(',', $data['match']);
|
||||
$matchArray = array_unique($matchArray);
|
||||
$match = join(',', $matchArray);
|
||||
|
||||
/** @var Bill $bill */
|
||||
$bill = Bill::create(
|
||||
[
|
||||
'name' => $data['name'],
|
||||
'match' => $match,
|
||||
'amount_min' => $data['amount_min'],
|
||||
'user_id' => $this->user->id,
|
||||
'amount_max' => $data['amount_max'],
|
||||
'date' => $data['date'],
|
||||
'repeat_freq' => $data['repeat_freq'],
|
||||
'skip' => $data['skip'],
|
||||
'automatch' => $data['automatch'],
|
||||
'active' => $data['active'],
|
||||
]
|
||||
);
|
||||
|
||||
// update note:
|
||||
if (isset($data['notes'])) {
|
||||
$this->updateNote($bill, $data['notes']);
|
||||
}
|
||||
|
||||
return $bill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $billId
|
||||
* @param null|string $billName
|
||||
*
|
||||
* @return Bill|null
|
||||
*/
|
||||
public function find(?int $billId, ?string $billName): ?Bill
|
||||
{
|
||||
$billId = intval($billId);
|
||||
$billName = strval($billName);
|
||||
|
||||
// first find by ID:
|
||||
if ($billId > 0) {
|
||||
/** @var Bill $bill */
|
||||
$bill = $this->user->bills()->find($billId);
|
||||
if (!is_null($bill)) {
|
||||
return $bill;
|
||||
}
|
||||
}
|
||||
|
||||
// then find by name:
|
||||
if (strlen($billName) > 0) {
|
||||
$bill = $this->findByName($billName);
|
||||
if (!is_null($bill)) {
|
||||
return $bill;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return Bill|null
|
||||
*/
|
||||
public function findByName(string $name): ?Bill
|
||||
{
|
||||
/** @var Collection $collection */
|
||||
$collection = $this->user->bills()->get();
|
||||
/** @var Bill $bill */
|
||||
foreach ($collection as $bill) {
|
||||
Log::debug(sprintf('"%s" vs. "%s"', $bill->name, $name));
|
||||
if ($bill->name === $name) {
|
||||
return $bill;
|
||||
}
|
||||
}
|
||||
Log::debug(sprintf('Bill::Find by name returns NULL based on "%s"', $name));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
}
|
100
app/Factory/BudgetFactory.php
Normal file
100
app/Factory/BudgetFactory.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* BudgetFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class BudgetFactory
|
||||
*/
|
||||
class BudgetFactory
|
||||
{
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
|
||||
/**
|
||||
* @param int|null $budgetId
|
||||
* @param null|string $budgetName
|
||||
*
|
||||
* @return Budget|null
|
||||
*/
|
||||
public function find(?int $budgetId, ?string $budgetName): ?Budget
|
||||
{
|
||||
$budgetId = intval($budgetId);
|
||||
$budgetName = strval($budgetName);
|
||||
|
||||
if (strlen($budgetName) === 0 && $budgetId === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// first by ID:
|
||||
if ($budgetId > 0) {
|
||||
/** @var Budget $budget */
|
||||
$budget = $this->user->budgets()->find($budgetId);
|
||||
if (!is_null($budget)) {
|
||||
return $budget;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($budgetName) > 0) {
|
||||
$budget = $this->findByName($budgetName);
|
||||
if (!is_null($budget)) {
|
||||
return $budget;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return Budget|null
|
||||
*/
|
||||
public function findByName(string $name): ?Budget
|
||||
{
|
||||
/** @var Collection $collection */
|
||||
$collection = $this->user->budgets()->get();
|
||||
/** @var Budget $budget */
|
||||
foreach ($collection as $budget) {
|
||||
if ($budget->name === $name) {
|
||||
return $budget;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
}
|
109
app/Factory/CategoryFactory.php
Normal file
109
app/Factory/CategoryFactory.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* CategoryFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class CategoryFactory
|
||||
*/
|
||||
class CategoryFactory
|
||||
{
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return Category|null
|
||||
*/
|
||||
public function findByName(string $name): ?Category
|
||||
{
|
||||
/** @var Collection $collection */
|
||||
$collection = $this->user->categories()->get();
|
||||
/** @var Category $category */
|
||||
foreach ($collection as $category) {
|
||||
if ($category->name === $name) {
|
||||
return $category;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $categoryId
|
||||
* @param null|string $categoryName
|
||||
*
|
||||
* @return Category|null
|
||||
*/
|
||||
public function findOrCreate(?int $categoryId, ?string $categoryName): ?Category
|
||||
{
|
||||
$categoryId = intval($categoryId);
|
||||
$categoryName = strval($categoryName);
|
||||
|
||||
Log::debug(sprintf('Going to find category with ID %d and name "%s"', $categoryId, $categoryName));
|
||||
|
||||
if (strlen($categoryName) === 0 && $categoryId === 0) {
|
||||
return null;
|
||||
}
|
||||
// first by ID:
|
||||
if ($categoryId > 0) {
|
||||
/** @var Category $category */
|
||||
$category = $this->user->categories()->find($categoryId);
|
||||
if (!is_null($category)) {
|
||||
return $category;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($categoryName) > 0) {
|
||||
$category = $this->findByName($categoryName);
|
||||
if (!is_null($category)) {
|
||||
return $category;
|
||||
}
|
||||
|
||||
return Category::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $categoryName,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
}
|
88
app/Factory/PiggyBankEventFactory.php
Normal file
88
app/Factory/PiggyBankEventFactory.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* PiggyBankEventFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Create piggy bank events.
|
||||
*
|
||||
* Class PiggyBankEventFactory
|
||||
*/
|
||||
class PiggyBankEventFactory
|
||||
{
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param PiggyBank|null $piggyBank
|
||||
*
|
||||
* @return PiggyBankEvent|null
|
||||
*/
|
||||
public function create(TransactionJournal $journal, ?PiggyBank $piggyBank): ?PiggyBankEvent
|
||||
{
|
||||
Log::debug(sprintf('Now in PiggyBankEventCreate for a %s', $journal->transactionType->type));
|
||||
if (is_null($piggyBank)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// is a transfer?
|
||||
if (!(TransactionType::TRANSFER === $journal->transactionType->type)) {
|
||||
Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var PiggyBankRepositoryInterface $piggyRepos */
|
||||
$piggyRepos = app(PiggyBankRepositoryInterface::class);
|
||||
$piggyRepos->setUser($journal->user);
|
||||
|
||||
// repetition exists?
|
||||
$repetition = $piggyRepos->getRepetition($piggyBank, $journal->date);
|
||||
if (null === $repetition->id) {
|
||||
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// get the amount
|
||||
$amount = $piggyRepos->getExactAmount($piggyBank, $repetition, $journal);
|
||||
if (0 === bccomp($amount, '0')) {
|
||||
Log::debug('Amount is zero, will not create event.');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// update amount
|
||||
$piggyRepos->addAmountToRepetition($repetition, $amount);
|
||||
$event = $piggyRepos->createEventWithJournal($piggyBank, $amount, $journal);
|
||||
|
||||
Log::debug(sprintf('Created piggy bank event #%d', $event->id));
|
||||
|
||||
return $event;
|
||||
}
|
||||
}
|
100
app/Factory/PiggyBankFactory.php
Normal file
100
app/Factory/PiggyBankFactory.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* PiggyBankFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\User;
|
||||
|
||||
/**
|
||||
* Class PiggyBankFactory
|
||||
*/
|
||||
class PiggyBankFactory
|
||||
{
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @param int|null $piggyBankId
|
||||
* @param null|string $piggyBankName
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
*/
|
||||
public function find(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank
|
||||
{
|
||||
$piggyBankId = intval($piggyBankId);
|
||||
$piggyBankName = strval($piggyBankName);
|
||||
if (strlen($piggyBankName) === 0 && $piggyBankId === 0) {
|
||||
return null;
|
||||
}
|
||||
// first find by ID:
|
||||
if ($piggyBankId > 0) {
|
||||
/** @var PiggyBank $piggyBank */
|
||||
$piggyBank = $this->user->piggyBanks()->find($piggyBankId);
|
||||
if (!is_null($piggyBank)) {
|
||||
return $piggyBank;
|
||||
}
|
||||
}
|
||||
|
||||
// then find by name:
|
||||
if (strlen($piggyBankName) > 0) {
|
||||
/** @var PiggyBank $piggyBank */
|
||||
$piggyBank = $this->findByName($piggyBankName);
|
||||
if (!is_null($piggyBank)) {
|
||||
return $piggyBank;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
*/
|
||||
public function findByName(string $name): ?PiggyBank
|
||||
{
|
||||
$set = $this->user->piggyBanks()->get();
|
||||
/** @var PiggyBank $piggy */
|
||||
foreach ($set as $piggy) {
|
||||
if ($piggy->name === $name) {
|
||||
return $piggy;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
}
|
||||
|
||||
}
|
102
app/Factory/TagFactory.php
Normal file
102
app/Factory/TagFactory.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/**
|
||||
* TagFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class TagFactory
|
||||
*/
|
||||
class TagFactory
|
||||
{
|
||||
/** @var Collection */
|
||||
private $tags;
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Tag|null
|
||||
*/
|
||||
public function create(array $data): ?Tag
|
||||
{
|
||||
return Tag::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'tag' => $data['tag'],
|
||||
'tagMode' => 'nothing',
|
||||
'date' => $data['date'],
|
||||
'description' => $data['description'],
|
||||
'latitude' => $data['latitude'],
|
||||
'longitude ' => $data['longitude'],
|
||||
'zoomLevel' => $data['zoom_level'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tag
|
||||
*
|
||||
* @return Tag|null
|
||||
*/
|
||||
public function findOrCreate(string $tag): ?Tag
|
||||
{
|
||||
if (is_null($this->tags)) {
|
||||
$this->tags = $this->user->tags()->get();
|
||||
}
|
||||
|
||||
/** @var Tag $object */
|
||||
foreach ($this->tags as $object) {
|
||||
if ($object->tag === $tag) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
$newTag = $this->create(
|
||||
[
|
||||
'tag' => $tag,
|
||||
'date' => null,
|
||||
'description' => null,
|
||||
'latitude' => null,
|
||||
'longitude' => null,
|
||||
'zoom_level' => null,
|
||||
]
|
||||
);
|
||||
$this->tags->push($newTag);
|
||||
|
||||
return $newTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
}
|
67
app/Factory/TransactionCurrencyFactory.php
Normal file
67
app/Factory/TransactionCurrencyFactory.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* TransactionCurrencyFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
|
||||
/**
|
||||
* Class TransactionCurrencyFactory
|
||||
*/
|
||||
class TransactionCurrencyFactory
|
||||
{
|
||||
/**
|
||||
* @param int|null $currencyId
|
||||
* @param null|string $currencyCode
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
*/
|
||||
public function find(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
|
||||
{
|
||||
$currencyCode = strval($currencyCode);
|
||||
$currencyId = intval($currencyId);
|
||||
|
||||
if (strlen($currencyCode) === 0 && intval($currencyId) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// first by ID:
|
||||
if ($currencyId > 0) {
|
||||
$currency = TransactionCurrency::find($currencyId);
|
||||
if (!is_null($currency)) {
|
||||
return $currency;
|
||||
}
|
||||
}
|
||||
// then by code:
|
||||
if (strlen($currencyCode) > 0) {
|
||||
$currency = TransactionCurrency::whereCode($currencyCode)->first();
|
||||
if (!is_null($currency)) {
|
||||
return $currency;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
148
app/Factory/TransactionFactory.php
Normal file
148
app/Factory/TransactionFactory.php
Normal file
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/**
|
||||
* TransactionFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Services\Internal\Support\TransactionServiceTrait;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class TransactionFactory
|
||||
*/
|
||||
class TransactionFactory
|
||||
{
|
||||
use TransactionServiceTrait;
|
||||
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Transaction
|
||||
*/
|
||||
public function create(array $data): Transaction
|
||||
{
|
||||
$currencyId = isset($data['currency']) ? $data['currency']->id : $data['currency_id'];
|
||||
|
||||
return Transaction::create(
|
||||
[
|
||||
'reconciled' => $data['reconciled'],
|
||||
'account_id' => $data['account']->id,
|
||||
'transaction_journal_id' => $data['transaction_journal']->id,
|
||||
'description' => $data['description'],
|
||||
'transaction_currency_id' => $currencyId,
|
||||
'amount' => $data['amount'],
|
||||
'foreign_amount' => $data['foreign_amount'],
|
||||
'foreign_currency_id' => null,
|
||||
'identifier' => $data['identifier'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pair of transactions based on the data given in the array.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $data
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function createPair(TransactionJournal $journal, array $data): Collection
|
||||
{
|
||||
// all this data is the same for both transactions:
|
||||
$currency = $this->findCurrency($data['currency_id'], $data['currency_code']);
|
||||
$description = $journal->description === $data['description'] ? null : $data['description'];
|
||||
|
||||
// type of source account depends on journal type:
|
||||
$sourceType = $this->accountType($journal, 'source');
|
||||
$sourceAccount = $this->findAccount($sourceType, $data['source_id'], $data['source_name']);
|
||||
|
||||
// same for destination account:
|
||||
$destinationType = $this->accountType($journal, 'destination');
|
||||
$destinationAccount = $this->findAccount($destinationType, $data['destination_id'], $data['destination_name']);
|
||||
// first make a "negative" (source) transaction based on the data in the array.
|
||||
$source = $this->create(
|
||||
[
|
||||
'description' => $description,
|
||||
'amount' => app('steam')->negative(strval($data['amount'])),
|
||||
'foreign_amount' => null,
|
||||
'currency' => $currency,
|
||||
'account' => $sourceAccount,
|
||||
'transaction_journal' => $journal,
|
||||
'reconciled' => $data['reconciled'],
|
||||
'identifier' => $data['identifier'],
|
||||
]
|
||||
);
|
||||
// then make a "positive" transaction based on the data in the array.
|
||||
$dest = $this->create(
|
||||
[
|
||||
'description' => $description,
|
||||
'amount' => app('steam')->positive(strval($data['amount'])),
|
||||
'foreign_amount' => null,
|
||||
'currency' => $currency,
|
||||
'account' => $destinationAccount,
|
||||
'transaction_journal' => $journal,
|
||||
'reconciled' => $data['reconciled'],
|
||||
'identifier' => $data['identifier'],
|
||||
]
|
||||
);
|
||||
|
||||
// set foreign currency
|
||||
$foreign = $this->findCurrency($data['foreign_currency_id'], $data['foreign_currency_code']);
|
||||
$this->setForeignCurrency($source, $foreign);
|
||||
$this->setForeignCurrency($dest, $foreign);
|
||||
|
||||
// set foreign amount:
|
||||
if (!is_null($data['foreign_amount'])) {
|
||||
$this->setForeignAmount($source, app('steam')->negative(strval($data['foreign_amount'])));
|
||||
$this->setForeignAmount($dest, app('steam')->positive(strval($data['foreign_amount'])));
|
||||
}
|
||||
|
||||
// set budget:
|
||||
$budget = $this->findBudget($data['budget_id'], $data['budget_name']);
|
||||
$this->setBudget($source, $budget);
|
||||
$this->setBudget($dest, $budget);
|
||||
|
||||
// set category
|
||||
$category = $this->findCategory($data['category_id'], $data['category_name']);
|
||||
$this->setCategory($source, $category);
|
||||
$this->setCategory($dest, $category);
|
||||
|
||||
return new Collection([$source, $dest]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
|
||||
}
|
154
app/Factory/TransactionJournalFactory.php
Normal file
154
app/Factory/TransactionJournalFactory.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* TransactionJournalFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Services\Internal\Support\JournalServiceTrait;
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class TransactionJournalFactory
|
||||
*/
|
||||
class TransactionJournalFactory
|
||||
{
|
||||
use JournalServiceTrait;
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Create a new transaction journal and associated transactions.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionJournal
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function create(array $data): TransactionJournal
|
||||
{
|
||||
Log::debug('Start of TransactionJournalFactory::create()');
|
||||
// store basic journal first.
|
||||
$type = $this->findTransactionType($data['type']);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||
$journal = TransactionJournal::create(
|
||||
[
|
||||
'user_id' => $data['user'],
|
||||
'transaction_type_id' => $type->id,
|
||||
'bill_id' => null,
|
||||
'transaction_currency_id' => $defaultCurrency->id,
|
||||
'description' => $data['description'],
|
||||
'date' => $data['date']->format('Y-m-d'),
|
||||
'order' => 0,
|
||||
'tag_count' => 0,
|
||||
'completed' => 0,
|
||||
]
|
||||
);
|
||||
|
||||
// store basic transactions:
|
||||
$factory = app(TransactionFactory::class);
|
||||
$factory->setUser($this->user);
|
||||
|
||||
/** @var array $trData */
|
||||
foreach ($data['transactions'] as $trData) {
|
||||
$factory->createPair($journal, $trData);
|
||||
}
|
||||
$journal->completed = true;
|
||||
$journal->save();
|
||||
|
||||
// link bill:
|
||||
$this->connectBill($journal, $data);
|
||||
|
||||
// link piggy bank (if transfer)
|
||||
$this->connectPiggyBank($journal, $data);
|
||||
|
||||
// link tags:
|
||||
$this->connectTags($journal, $data);
|
||||
|
||||
// store note:
|
||||
$this->storeNote($journal, strval($data['notes']));
|
||||
|
||||
// store date meta fields (if present):
|
||||
$this->storeMeta($journal, $data, 'interest_date');
|
||||
$this->storeMeta($journal, $data, 'book_date');
|
||||
$this->storeMeta($journal, $data, 'process_date');
|
||||
$this->storeMeta($journal, $data, 'due_date');
|
||||
$this->storeMeta($journal, $data, 'payment_date');
|
||||
$this->storeMeta($journal, $data, 'invoice_date');
|
||||
$this->storeMeta($journal, $data, 'internal_reference');
|
||||
Log::debug('End of TransactionJournalFactory::create()');
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user.
|
||||
*
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $data
|
||||
*/
|
||||
protected function connectPiggyBank(TransactionJournal $journal, array $data): void
|
||||
{
|
||||
/** @var PiggyBankFactory $factory */
|
||||
$factory = app(PiggyBankFactory::class);
|
||||
$factory->setUser($this->user);
|
||||
|
||||
$piggyBank = $factory->find($data['piggy_bank_id'], $data['piggy_bank_name']);
|
||||
if (!is_null($piggyBank)) {
|
||||
/** @var PiggyBankEventFactory $factory */
|
||||
$factory = app(PiggyBankEventFactory::class);
|
||||
$factory->create($journal, $piggyBank);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the transaction type. Since this is mandatory, will throw an exception when nothing comes up. Will always
|
||||
* use TransactionType repository.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return TransactionType
|
||||
* @throws FireflyException
|
||||
*/
|
||||
protected function findTransactionType(string $type): TransactionType
|
||||
{
|
||||
$factory = app(TransactionTypeFactory::class);
|
||||
$transactionType = $factory->find($type);
|
||||
if (is_null($transactionType)) {
|
||||
throw new FireflyException(sprintf('Could not find transaction type for "%s"', $type)); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return $transactionType;
|
||||
}
|
||||
|
||||
}
|
72
app/Factory/TransactionJournalMetaFactory.php
Normal file
72
app/Factory/TransactionJournalMetaFactory.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* TransactionJournalMetaFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Models\TransactionJournalMeta;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class TransactionJournalMetaFactory
|
||||
*/
|
||||
class TransactionJournalMetaFactory
|
||||
{
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionJournalMeta|null
|
||||
*/
|
||||
public function updateOrCreate(array $data): ?TransactionJournalMeta
|
||||
{
|
||||
$value = $data['data'];
|
||||
/** @var TransactionJournalMeta $entry */
|
||||
$entry = $data['journal']->transactionJournalMeta()->where('name', $data['name'])->first();
|
||||
if (is_null($value) && !is_null($entry)) {
|
||||
try {
|
||||
$entry->delete();
|
||||
} catch (Exception $e) { // @codeCoverageIgnore
|
||||
Log::error(sprintf('Could not delete transaction journal meta: %s', $e->getMessage())); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($data['data'] instanceof Carbon) {
|
||||
$value = $data['data']->toW3cString();
|
||||
}
|
||||
|
||||
|
||||
if (null === $entry) {
|
||||
$entry = new TransactionJournalMeta();
|
||||
$entry->transactionJournal()->associate($data['journal']);
|
||||
$entry->name = $data['name'];
|
||||
}
|
||||
$entry->data = $value;
|
||||
$entry->save();
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
}
|
44
app/Factory/TransactionTypeFactory.php
Normal file
44
app/Factory/TransactionTypeFactory.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* TransactionTypeFactory.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\TransactionType;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Class TransactionTypeFactory
|
||||
*/
|
||||
class TransactionTypeFactory
|
||||
{
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return TransactionType|null
|
||||
*/
|
||||
public function find(string $type): ?TransactionType
|
||||
{
|
||||
return TransactionType::whereType(ucfirst($type))->first();
|
||||
}
|
||||
|
||||
}
|
@ -61,61 +61,6 @@ class StoredJournalEventHandler
|
||||
$this->ruleGroupRepository = $ruleGroupRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method connects a new transfer to a piggy bank.
|
||||
*
|
||||
* @param StoredTransactionJournal $event
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
public function connectToPiggyBank(StoredTransactionJournal $event): bool
|
||||
{
|
||||
$journal = $event->journal;
|
||||
$piggyBankId = $event->piggyBankId;
|
||||
$piggyBank = $this->repository->find($piggyBankId);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// piggy exists?
|
||||
if (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 (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 (0 === bccomp($amount, '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);
|
||||
|
||||
Log::debug(sprintf('Created piggy bank event #%d', $event->id));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method grabs all the users rules and processes them.
|
||||
*
|
||||
|
@ -51,6 +51,7 @@ class UpdatedJournalEventHandler
|
||||
|
||||
/**
|
||||
* This method will check all the rules when a journal is updated.
|
||||
* TODO move to factory.
|
||||
*
|
||||
* @param UpdatedTransactionJournal $updatedJournalEvent
|
||||
*
|
||||
@ -81,6 +82,7 @@ class UpdatedJournalEventHandler
|
||||
|
||||
/**
|
||||
* This method calls a special bill scanner that will check if the updated journal is part of a bill.
|
||||
* TODO move to factory.
|
||||
*
|
||||
* @param UpdatedTransactionJournal $updatedJournalEvent
|
||||
*
|
||||
|
@ -50,8 +50,9 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||
protected $uploadDisk;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* AttachmentHelper constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -79,6 +79,9 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
/** @var User */
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* MetaPieChart constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->accounts = new Collection;
|
||||
@ -273,11 +276,13 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
$collector->setBudgets($this->budgets);
|
||||
$collector->setCategories($this->categories);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->tags->count() > 0) {
|
||||
$collector->setTags($this->tags);
|
||||
$collector->withCategoryInformation();
|
||||
$collector->withBudgetInformation();
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $collector->getJournals();
|
||||
}
|
||||
@ -294,7 +299,7 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
{
|
||||
if (0 === count($fields) && $this->tags->count() > 0) {
|
||||
// do a special group on tags:
|
||||
return $this->groupByTag($set);
|
||||
return $this->groupByTag($set); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$grouped = [];
|
||||
@ -338,6 +343,8 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return array
|
||||
|
@ -69,6 +69,8 @@ class JournalCollector implements JournalCollectorInterface
|
||||
'transaction_journals.description',
|
||||
'transaction_journals.date',
|
||||
'transaction_journals.encrypted',
|
||||
'transaction_journals.created_at',
|
||||
'transaction_journals.updated_at',
|
||||
'transaction_types.type as transaction_type_type',
|
||||
'transaction_journals.bill_id',
|
||||
'transaction_journals.updated_at',
|
||||
@ -252,6 +254,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
$cache->addProperty($key);
|
||||
if ($cache->has()) {
|
||||
Log::debug(sprintf('Return cache of query with ID "%s".', $key));
|
||||
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
@ -270,10 +273,19 @@ class JournalCollector implements JournalCollectorInterface
|
||||
if (null !== $transaction->bill_name) {
|
||||
$transaction->bill_name = Steam::decrypt(intval($transaction->bill_name_encrypted), $transaction->bill_name);
|
||||
}
|
||||
$transaction->account_name = app('steam')->tryDecrypt($transaction->account_name);
|
||||
$transaction->opposing_account_name = app('steam')->tryDecrypt($transaction->opposing_account_name);
|
||||
$transaction->account_iban = app('steam')->tryDecrypt($transaction->account_iban);
|
||||
$transaction->opposing_account_iban = app('steam')->tryDecrypt($transaction->opposing_account_iban);
|
||||
|
||||
// budget name
|
||||
$transaction->transaction_journal_budget_name = app('steam')->tryDecrypt($transaction->transaction_journal_budget_name);
|
||||
$transaction->transaction_budget_name = app('steam')->tryDecrypt($transaction->transaction_budget_name);
|
||||
// category name:
|
||||
$transaction->transaction_journal_category_name = app('steam')->tryDecrypt($transaction->transaction_journal_category_name);
|
||||
$transaction->transaction_category_name = app('steam')->tryDecrypt($transaction->transaction_category_name);
|
||||
}
|
||||
|
||||
);
|
||||
Log::debug(sprintf('Cached query with ID "%s".', $key));
|
||||
$cache->store($set);
|
||||
@ -342,7 +354,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
*/
|
||||
public function setAfter(Carbon $after): JournalCollectorInterface
|
||||
{
|
||||
$afterStr = $after->format('Y-m-d');
|
||||
$afterStr = $after->format('Y-m-d 00:00:00');
|
||||
$this->query->where('transaction_journals.date', '>=', $afterStr);
|
||||
Log::debug(sprintf('JournalCollector range is now after %s (inclusive)', $afterStr));
|
||||
|
||||
@ -378,7 +390,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
*/
|
||||
public function setBefore(Carbon $before): JournalCollectorInterface
|
||||
{
|
||||
$beforeStr = $before->format('Y-m-d');
|
||||
$beforeStr = $before->format('Y-m-d 00:00:00');
|
||||
$this->query->where('transaction_journals.date', '<=', $beforeStr);
|
||||
Log::debug(sprintf('JournalCollector range is now before %s (inclusive)', $beforeStr));
|
||||
|
||||
@ -485,6 +497,23 @@ class JournalCollector implements JournalCollectorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $journals
|
||||
*
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function setJournals(Collection $journals): JournalCollectorInterface
|
||||
{
|
||||
$ids = $journals->pluck('id')->toArray();
|
||||
$this->query->where(
|
||||
function (EloquentBuilder $q) use ($ids) {
|
||||
$q->whereIn('transaction_journals.id', $ids);
|
||||
}
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
*
|
||||
@ -565,8 +594,8 @@ class JournalCollector implements JournalCollectorInterface
|
||||
public function setRange(Carbon $start, Carbon $end): JournalCollectorInterface
|
||||
{
|
||||
if ($start <= $end) {
|
||||
$startStr = $start->format('Y-m-d');
|
||||
$endStr = $end->format('Y-m-d');
|
||||
$startStr = $start->format('Y-m-d 00:00:00');
|
||||
$endStr = $end->format('Y-m-d 23:59:59');
|
||||
$this->query->where('transaction_journals.date', '>=', $startStr);
|
||||
$this->query->where('transaction_journals.date', '<=', $endStr);
|
||||
Log::debug(sprintf('JournalCollector range is now %s - %s (inclusive)', $startStr, $endStr));
|
||||
|
@ -27,7 +27,6 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
@ -43,6 +42,13 @@ interface JournalCollectorInterface
|
||||
*/
|
||||
public function addFilter(string $filter): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @param Collection $journals
|
||||
*
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function setJournals(Collection $journals): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @param string $amount
|
||||
*
|
||||
|
@ -28,6 +28,7 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
@ -182,6 +183,9 @@ class PopupReport implements PopupReportInterface
|
||||
*/
|
||||
public function byIncome(Account $account, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalRepositoryInterface $repository */
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$repository->setUser($account->user);
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
@ -191,9 +195,10 @@ class PopupReport implements PopupReportInterface
|
||||
|
||||
// filter the set so the destinations outside of $attributes['accounts'] are not included.
|
||||
$journals = $journals->filter(
|
||||
function (Transaction $transaction) use ($report) {
|
||||
function (Transaction $transaction) use ($report, $repository) {
|
||||
// get the destinations:
|
||||
$destinations = $transaction->transactionJournal->destinationAccountList()->pluck('id')->toArray();
|
||||
$journal = $transaction->transactionJournal;
|
||||
$destinations = $repository->getJournalDestinationAccounts($journal)->pluck('id')->toArray();
|
||||
|
||||
// do these intersect with the current list?
|
||||
return !empty(array_intersect($report, $destinations));
|
||||
|
@ -24,9 +24,11 @@ namespace FireflyIII\Http\Controllers\Account;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\TransactionJournalFactory;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\ReconciliationFormRequest;
|
||||
use FireflyIII\Http\Requests\ReconciliationStoreRequest;
|
||||
use FireflyIII\Http\Requests\ReconciliationUpdateRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Transaction;
|
||||
@ -35,8 +37,10 @@ use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Update\TransactionUpdateService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Session;
|
||||
@ -48,6 +52,9 @@ use Session;
|
||||
*/
|
||||
class ReconcileController extends Controller
|
||||
{
|
||||
/** @var JournalRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -60,6 +67,7 @@ class ReconcileController extends Controller
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-credit-card');
|
||||
app('view')->share('title', trans('firefly.accounts'));
|
||||
$this->repository = app(JournalRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
@ -80,10 +88,10 @@ class ReconcileController extends Controller
|
||||
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
|
||||
|
||||
// journal related code
|
||||
$pTransaction = $journal->positiveTransaction();
|
||||
$pTransaction = $this->repository->getFirstPosTransaction($journal);
|
||||
$preFilled = [
|
||||
'date' => $journal->dateAsString(),
|
||||
'category' => $journal->categoryAsString(),
|
||||
'date' => $this->repository->getJournalDate($journal, null),
|
||||
'category' => $this->repository->getJournalCategoryName($journal),
|
||||
'tags' => join(',', $journal->tags->pluck('tag')->toArray()),
|
||||
'amount' => $pTransaction->amount,
|
||||
];
|
||||
@ -126,10 +134,8 @@ class ReconcileController extends Controller
|
||||
$clearedAmount = '0';
|
||||
$route = route('accounts.reconcile.submit', [$account->id, $start->format('Ymd'), $end->format('Ymd')]);
|
||||
// get sum of transaction amounts:
|
||||
/** @var JournalRepositoryInterface $repository */
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$transactions = $repository->getTransactionsById($transactionIds);
|
||||
$cleared = $repository->getTransactionsById($clearedIds);
|
||||
$transactions = $this->repository->getTransactionsById($transactionIds);
|
||||
$cleared = $this->repository->getTransactionsById($clearedIds);
|
||||
$countCleared = 0;
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
@ -182,7 +188,7 @@ class ReconcileController extends Controller
|
||||
/** @var CurrencyRepositoryInterface $currencyRepos */
|
||||
$currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$currencyId = intval($account->getMeta('currency_id'));
|
||||
$currency = $currencyRepos->find($currencyId);
|
||||
$currency = $currencyRepos->findNull($currencyId);
|
||||
if (0 === $currencyId) {
|
||||
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
|
||||
}
|
||||
@ -220,71 +226,105 @@ class ReconcileController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param TransactionJournal $journal
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
|
||||
*/
|
||||
public function show(JournalRepositoryInterface $repository, TransactionJournal $journal)
|
||||
public function show(TransactionJournal $journal)
|
||||
{
|
||||
|
||||
if (TransactionType::RECONCILIATION !== $journal->transactionType->type) {
|
||||
return redirect(route('transactions.show', [$journal->id]));
|
||||
}
|
||||
$subTitle = trans('firefly.reconciliation') . ' "' . $journal->description . '"';
|
||||
|
||||
// get main transaction:
|
||||
$transaction = $repository->getAssetTransaction($journal);
|
||||
$transaction = $this->repository->getAssetTransaction($journal);
|
||||
$account = $transaction->account;
|
||||
|
||||
return view('accounts.reconcile.show', compact('journal', 'subTitle', 'transaction', 'account'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param ReconciliationStoreRequest $request
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function submit(Request $request, Account $account, Carbon $start, Carbon $end)
|
||||
public function submit(ReconciliationStoreRequest $request, JournalRepositoryInterface $repository, Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
/** @var JournalRepositoryInterface $repository */
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$transactions = $repository->getTransactionsById($request->get('transactions') ?? []);
|
||||
Log::debug('In ReconcileController::submit()');
|
||||
$data = $request->getAll();
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$repository->reconcile($transaction); // mark as reconciled.
|
||||
foreach ($data['transactions'] as $transactionId) {
|
||||
$repository->reconcileById(intval($transactionId));
|
||||
}
|
||||
Log::debug('Reconciled all transactions.');
|
||||
|
||||
// create reconciliation transaction (if necessary):
|
||||
if ('create' === $request->get('reconcile')) {
|
||||
if ('create' === $data['reconcile']) {
|
||||
// get "opposing" account.
|
||||
/** @var AccountRepositoryInterface $accountRepos */
|
||||
$accountRepos = app(AccountRepositoryInterface::class);
|
||||
$reconciliation = $accountRepos->getReconciliation($account);
|
||||
$difference = $request->get('difference');
|
||||
|
||||
// store journal between these two.
|
||||
$data = [
|
||||
'what' => 'Reconciliation',
|
||||
'source' => $account,
|
||||
'destination' => $reconciliation,
|
||||
'category' => '',
|
||||
'budget_id' => 0,
|
||||
'amount' => $difference,
|
||||
'currency_id' => $account->getMeta('currency_id'),
|
||||
'description' => trans(
|
||||
'firefly.reconcilliation_transaction_title',
|
||||
['from' => $start->formatLocalized($this->monthAndDayFormat), 'to' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
),
|
||||
'date' => $request->get('end'),
|
||||
'notes' => join(',', $transactions->pluck('id')->toArray()),
|
||||
|
||||
$difference = $data['difference'];
|
||||
$source = $reconciliation;
|
||||
$destination = $account;
|
||||
if (bccomp($difference, '0') === 1) {
|
||||
// amount is positive. Add it to reconciliation?
|
||||
$source = $account;
|
||||
$destination = $reconciliation;
|
||||
|
||||
}
|
||||
|
||||
// data for journal
|
||||
$description = trans(
|
||||
'firefly.reconcilliation_transaction_title',
|
||||
['from' => $start->formatLocalized($this->monthAndDayFormat), 'to' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$journalData = [
|
||||
'type' => 'Reconciliation',
|
||||
'description' => $description,
|
||||
'user' => auth()->user()->id,
|
||||
'date' => $data['end'],
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
'piggy_bank_id' => null,
|
||||
'piggy_bank_name' => null,
|
||||
'tags' => null,
|
||||
'interest_date' => null,
|
||||
'transactions' => [[
|
||||
'currency_id' => intval($account->getMeta('currency_id')),
|
||||
'currency_code' => null,
|
||||
'description' => null,
|
||||
'amount' => app('steam')->positive($difference),
|
||||
'source_id' => $source->id,
|
||||
'source_name' => null,
|
||||
'destination_id' => $destination->id,
|
||||
'destination_name' => null,
|
||||
'reconciled' => true,
|
||||
'identifier' => 0,
|
||||
'foreign_currency_id' => null,
|
||||
'foreign_currency_code' => null,
|
||||
'foreign_amount' => null,
|
||||
'budget_id' => null,
|
||||
'budget_name' => null,
|
||||
'category_id' => null,
|
||||
'category_name' => null,
|
||||
],
|
||||
],
|
||||
'notes' => join(', ', $data['transactions']),
|
||||
];
|
||||
$journal = $repository->store($data);
|
||||
// reconcile this transaction too:
|
||||
$transaction = $journal->transactions()->first();
|
||||
$repository->reconcile($transaction);
|
||||
|
||||
$journal = $repository->store($journalData);
|
||||
}
|
||||
Log::debug('End of routine.');
|
||||
|
||||
Session::flash('success', trans('firefly.reconciliation_stored'));
|
||||
|
||||
@ -313,7 +353,7 @@ class ReconcileController extends Controller
|
||||
/** @var CurrencyRepositoryInterface $currencyRepos */
|
||||
$currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$currencyId = intval($account->getMeta('currency_id'));
|
||||
$currency = $currencyRepos->find($currencyId);
|
||||
$currency = $currencyRepos->findNull($currencyId);
|
||||
if (0 === $currencyId) {
|
||||
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
|
||||
}
|
||||
@ -339,13 +379,12 @@ class ReconcileController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReconciliationFormRequest $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param TransactionJournal $journal
|
||||
* @param ReconciliationUpdateRequest $request
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function update(ReconciliationFormRequest $request, AccountRepositoryInterface $repository, TransactionJournal $journal)
|
||||
public function update(ReconciliationUpdateRequest $request, TransactionJournal $journal)
|
||||
{
|
||||
if (TransactionType::RECONCILIATION !== $journal->transactionType->type) {
|
||||
return redirect(route('transactions.show', [$journal->id]));
|
||||
@ -356,8 +395,53 @@ class ReconcileController extends Controller
|
||||
return redirect(route('accounts.reconcile.edit', [$journal->id]))->withInput();
|
||||
}
|
||||
// update journal using account repository. Keep it consistent.
|
||||
$data = $request->getJournalData();
|
||||
$repository->updateReconciliation($journal, $data);
|
||||
$submitted = $request->getJournalData();
|
||||
|
||||
// amount pos neg influences the accounts:
|
||||
$source = $this->repository->getJournalSourceAccounts($journal)->first();
|
||||
$destination = $this->repository->getJournalDestinationAccounts($journal)->first();
|
||||
if (bccomp($submitted['amount'], '0') === 1) {
|
||||
// amount is positive, switch accounts:
|
||||
list($source, $destination) = [$destination, $source];
|
||||
|
||||
}
|
||||
// expand data with journal data:
|
||||
$data = [
|
||||
'type' => $journal->transactionType->type,
|
||||
'description' => $journal->description,
|
||||
'user' => $journal->user_id,
|
||||
'date' => $journal->date,
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
'piggy_bank_id' => null,
|
||||
'piggy_bank_name' => null,
|
||||
'tags' => $submitted['tags'],
|
||||
'interest_date' => null,
|
||||
'book_date' => null,
|
||||
'transactions' => [[
|
||||
'currency_id' => intval($journal->transaction_currency_id),
|
||||
'currency_code' => null,
|
||||
'description' => null,
|
||||
'amount' => app('steam')->positive($submitted['amount']),
|
||||
'source_id' => $source->id,
|
||||
'source_name' => null,
|
||||
'destination_id' => $destination->id,
|
||||
'destination_name' => null,
|
||||
'reconciled' => true,
|
||||
'identifier' => 0,
|
||||
'foreign_currency_id' => null,
|
||||
'foreign_currency_code' => null,
|
||||
'foreign_amount' => null,
|
||||
'budget_id' => null,
|
||||
'budget_name' => null,
|
||||
'category_id' => null,
|
||||
'category_name' => $submitted['category'],
|
||||
],
|
||||
],
|
||||
'notes' => $this->repository->getNoteText($journal),
|
||||
];
|
||||
|
||||
$this->repository->update($journal, $data);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if (1 === intval($request->get('return_to_edit'))) {
|
||||
|
@ -139,7 +139,7 @@ class AccountController extends Controller
|
||||
$type = $account->accountType->type;
|
||||
$typeName = config('firefly.shortNamesByFullName.' . $type);
|
||||
$name = $account->name;
|
||||
$moveTo = $this->repository->find(intval($request->get('move_account_before_delete')));
|
||||
$moveTo = $this->repository->findNull(intval($request->get('move_account_before_delete')));
|
||||
|
||||
$this->repository->destroy($account, $moveTo);
|
||||
|
||||
@ -162,7 +162,7 @@ class AccountController extends Controller
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function edit(Request $request, Account $account)
|
||||
public function edit(Request $request, Account $account, AccountRepositoryInterface $repository)
|
||||
{
|
||||
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
|
||||
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
|
||||
@ -183,11 +183,9 @@ class AccountController extends Controller
|
||||
// pre fill some useful values.
|
||||
|
||||
// the opening balance is tricky:
|
||||
$openingBalanceAmount = $account->getOpeningBalanceAmount();
|
||||
$openingBalanceAmount = '0' === $account->getOpeningBalanceAmount() ? '' : $openingBalanceAmount;
|
||||
$openingBalanceDate = $account->getOpeningBalanceDate();
|
||||
$openingBalanceDate = 1900 === $openingBalanceDate->year ? null : $openingBalanceDate->format('Y-m-d');
|
||||
$currency = $this->currencyRepos->find(intval($account->getMeta('currency_id')));
|
||||
$openingBalanceAmount = strval($repository->getOpeningBalanceAmount($account));
|
||||
$openingBalanceDate = $repository->getOpeningBalanceDate($account);
|
||||
$currency = $this->currencyRepos->findNull(intval($account->getMeta('currency_id')));
|
||||
|
||||
$preFilled = [
|
||||
'accountNumber' => $account->getMeta('accountNumber'),
|
||||
@ -200,6 +198,7 @@ class AccountController extends Controller
|
||||
'virtualBalance' => $account->virtual_balance,
|
||||
'currency_id' => $currency->id,
|
||||
'notes' => '',
|
||||
'active' => $account->active,
|
||||
];
|
||||
/** @var Note $note */
|
||||
$note = $this->repository->getNote($account);
|
||||
@ -285,68 +284,46 @@ class AccountController extends Controller
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function show(Request $request, Account $account, string $moment = '')
|
||||
public function show(Request $request, Account $account, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
if (AccountType::INITIAL_BALANCE === $account->accountType->type) {
|
||||
return $this->redirectToOriginalAccount($account);
|
||||
}
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
if (null === $start) {
|
||||
$start = session('start');
|
||||
}
|
||||
if (null === $end) {
|
||||
$end = app('navigation')->endOfPeriod($start, $range);
|
||||
}
|
||||
if ($end < $start) {
|
||||
throw new FireflyException('End is after start!'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||
$page = intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('listPageSize', 50)->data);
|
||||
$chartUri = route('chart.account.single', [$account->id]);
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
$currencyId = intval($account->getMeta('currency_id'));
|
||||
$currency = $this->currencyRepos->find($currencyId);
|
||||
$currency = $this->currencyRepos->findNull($currencyId);
|
||||
if (0 === $currencyId) {
|
||||
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// prep for "all" view.
|
||||
if ('all' === $moment) {
|
||||
$subTitle = trans('firefly.all_journals_for_account', ['name' => $account->name]);
|
||||
$chartUri = route('chart.account.all', [$account->id]);
|
||||
$first = $this->journalRepos->first();
|
||||
$start = $first->date ?? new Carbon;
|
||||
$end = new Carbon;
|
||||
}
|
||||
|
||||
// prep for "specific date" view.
|
||||
if (strlen($moment) > 0 && 'all' !== $moment) {
|
||||
$start = new Carbon($moment);
|
||||
$start = app('navigation')->startOfPeriod($start, $range);
|
||||
$end = app('navigation')->endOfPeriod($start, $range);
|
||||
$fStart = $start->formatLocalized($this->monthAndDayFormat);
|
||||
$fEnd = $end->formatLocalized($this->monthAndDayFormat);
|
||||
$subTitle = trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
|
||||
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d')]);
|
||||
$periods = $this->getPeriodOverview($account, $start);
|
||||
}
|
||||
|
||||
// prep for current period view
|
||||
if (0 === strlen($moment)) {
|
||||
$start = clone session('start', app('navigation')->startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', app('navigation')->endOfPeriod(new Carbon, $range));
|
||||
$fStart = $start->formatLocalized($this->monthAndDayFormat);
|
||||
$fEnd = $end->formatLocalized($this->monthAndDayFormat);
|
||||
$subTitle = trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
|
||||
$periods = $this->getPeriodOverview($account, null);
|
||||
}
|
||||
|
||||
// grab journals:
|
||||
$fStart = $start->formatLocalized($this->monthAndDayFormat);
|
||||
$fEnd = $end->formatLocalized($this->monthAndDayFormat);
|
||||
$subTitle = trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
|
||||
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||
$periods = $this->getPeriodOverview($account, $end);
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
|
||||
if (null !== $start) {
|
||||
$collector->setRange($start, $end);
|
||||
}
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('accounts.show', [$account->id, $moment]));
|
||||
$transactions->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
|
||||
|
||||
return view(
|
||||
'accounts.show',
|
||||
compact('account', 'currency', 'moment', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end', 'chartUri')
|
||||
compact('account', 'currency', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end', 'chartUri')
|
||||
);
|
||||
}
|
||||
|
||||
@ -439,6 +416,9 @@ class AccountController extends Controller
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = $this->repository->oldestJournalDate($account);
|
||||
$end = $date ?? new Carbon;
|
||||
if ($end < $start) {
|
||||
list($start, $end) = [$end, $start]; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
@ -449,11 +429,8 @@ class AccountController extends Controller
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
// loop dates
|
||||
foreach ($dates as $date) {
|
||||
|
||||
@ -471,15 +448,15 @@ class AccountController extends Controller
|
||||
->withOpposingAccount();
|
||||
$spent = strval($collector->getJournals()->sum('transaction_amount'));
|
||||
|
||||
$dateStr = $date['end']->format('Y-m-d');
|
||||
$dateName = app('navigation')->periodShow($date['start'], $date['period']);
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'date' => clone $date['end'],]
|
||||
'start' => $date['start']->format('Y-m-d'),
|
||||
'end' => $date['end']->format('Y-m-d'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,7 @@ class ResetPasswordController extends Controller
|
||||
if (true === $singleUserMode && $userCount > 0) {
|
||||
$allowRegistration = false;
|
||||
}
|
||||
|
||||
return view('auth.passwords.reset')->with(
|
||||
['token' => $token, 'email' => $request->email, 'allowRegistration' => $allowRegistration]
|
||||
);
|
||||
|
@ -30,10 +30,14 @@ use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Transformers\BillTransformer;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\DataArraySerializer;
|
||||
use Preferences;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
@ -167,36 +171,26 @@ class BillController extends Controller
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function index(Request $request, BillRepositoryInterface $repository)
|
||||
public function index(BillRepositoryInterface $repository)
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = session('start');
|
||||
/** @var Carbon $end */
|
||||
$start = session('start');
|
||||
$end = session('end');
|
||||
$page = 0 === intval($request->get('page')) ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('listPageSize', 50)->data);
|
||||
$collection = $repository->getBills();
|
||||
$total = $collection->count();
|
||||
$collection = $collection->slice(($page - 1) * $pageSize, $pageSize);
|
||||
|
||||
$collection->each(
|
||||
function (Bill $bill) use ($repository, $start, $end) {
|
||||
// paid in this period?
|
||||
$bill->paidDates = $repository->getPaidDatesInRange($bill, $start, $end);
|
||||
$bill->payDates = $repository->getPayDatesInRange($bill, $start, $end);
|
||||
$lastPaidDate = $this->lastPaidDate($repository->getPaidDatesInRange($bill, $start, $end), $start);
|
||||
if ($bill->paidDates->count() >= $bill->payDates->count()) {
|
||||
// if all bills have been been paid, jump to next period.
|
||||
$lastPaidDate = $end;
|
||||
}
|
||||
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill, $lastPaidDate);
|
||||
$paginator = $repository->getPaginator($pageSize);
|
||||
$parameters = new ParameterBag();
|
||||
$parameters->set('start', $start);
|
||||
$parameters->set('end', $end);
|
||||
$transformer = new BillTransformer($parameters);
|
||||
/** @var Collection $bills */
|
||||
$bills = $paginator->getCollection()->map(
|
||||
function (Bill $bill) use ($transformer) {
|
||||
return $transformer->transform($bill);
|
||||
}
|
||||
);
|
||||
// paginate bills
|
||||
$bills = new LengthAwarePaginator($collection, $total, $pageSize, $page);
|
||||
$bills->setPath(route('bills.index'));
|
||||
|
||||
return view('bills.index', compact('bills'));
|
||||
$paginator->setPath(route('bills.index'));
|
||||
|
||||
return view('bills.index', compact('bills', 'paginator'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -235,15 +229,24 @@ class BillController extends Controller
|
||||
*/
|
||||
public function show(Request $request, BillRepositoryInterface $repository, Bill $bill)
|
||||
{
|
||||
/** @var Carbon $date */
|
||||
$date = session('start');
|
||||
/** @var Carbon $end */
|
||||
$subTitle = $bill->name;
|
||||
$start = session('start');
|
||||
$end = session('end');
|
||||
$year = $date->year;
|
||||
$year = $start->year;
|
||||
$page = intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('listPageSize', 50)->data);
|
||||
$yearAverage = $repository->getYearAverage($bill, $date);
|
||||
$yearAverage = $repository->getYearAverage($bill, $start);
|
||||
$overallAverage = $repository->getOverallAverage($bill);
|
||||
$manager = new Manager();
|
||||
$manager->setSerializer(new DataArraySerializer());
|
||||
$manager->parseIncludes(['attachments']);
|
||||
|
||||
// Make a resource out of the data and
|
||||
$parameters = new ParameterBag();
|
||||
$parameters->set('start', $start);
|
||||
$parameters->set('end', $end);
|
||||
$resource = new Item($bill, new BillTransformer($parameters), 'bill');
|
||||
$object = $manager->createData($resource)->toArray();
|
||||
|
||||
// use collector:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
@ -253,18 +256,8 @@ class BillController extends Controller
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('bills.show', [$bill->id]));
|
||||
|
||||
$bill->paidDates = $repository->getPaidDatesInRange($bill, $date, $end);
|
||||
$bill->payDates = $repository->getPayDatesInRange($bill, $date, $end);
|
||||
$lastPaidDate = $this->lastPaidDate($repository->getPaidDatesInRange($bill, $date, $end), $date);
|
||||
if ($bill->paidDates->count() >= $bill->payDates->count()) {
|
||||
// if all bills have been been paid, jump to next period.
|
||||
$lastPaidDate = $end;
|
||||
}
|
||||
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill, $lastPaidDate);
|
||||
$hideBill = true;
|
||||
$subTitle = $bill->name;
|
||||
|
||||
return view('bills.show', compact('transactions', 'yearAverage', 'overallAverage', 'year', 'hideBill', 'bill', 'subTitle'));
|
||||
return view('bills.show', compact('transactions', 'yearAverage', 'overallAverage', 'year', 'object', 'bill', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -335,28 +328,4 @@ class BillController extends Controller
|
||||
|
||||
return redirect($this->getPreviousUri('bills.edit.uri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latest date in the set, or start when set is empty.
|
||||
*
|
||||
* @param Collection $dates
|
||||
* @param Carbon $default
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
private function lastPaidDate(Collection $dates, Carbon $default): Carbon
|
||||
{
|
||||
if (0 === $dates->count()) {
|
||||
return $default; // @codeCoverageIgnore
|
||||
}
|
||||
$latest = $dates->first();
|
||||
/** @var Carbon $date */
|
||||
foreach ($dates as $date) {
|
||||
if ($date->gte($latest)) {
|
||||
$latest = $date;
|
||||
}
|
||||
}
|
||||
|
||||
return $latest;
|
||||
}
|
||||
}
|
||||
|
@ -82,9 +82,9 @@ class BudgetController extends Controller
|
||||
*/
|
||||
public function amount(Request $request, BudgetRepositoryInterface $repository, Budget $budget)
|
||||
{
|
||||
$amount = strval($request->get('amount'));
|
||||
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
|
||||
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
|
||||
$amount = strval($request->get('amount'));
|
||||
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
|
||||
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
|
||||
$budgetLimit = $this->repository->updateLimitAmount($budget, $start, $end, $amount);
|
||||
if (0 === bccomp($amount, '0')) {
|
||||
$budgetLimit = null;
|
||||
@ -198,13 +198,13 @@ class BudgetController extends Controller
|
||||
$prev->subDay();
|
||||
$prev = app('navigation')->startOfPeriod($prev, $range);
|
||||
$this->repository->cleanupBudgets();
|
||||
$budgets = $this->repository->getActiveBudgets();
|
||||
$total = $budgets->count();
|
||||
$budgets = $budgets->slice(($page - 1) * $pageSize, $pageSize);
|
||||
$allBudgets = $this->repository->getActiveBudgets();
|
||||
$total = $allBudgets->count();
|
||||
$budgets = $allBudgets->slice(($page - 1) * $pageSize, $pageSize);
|
||||
$inactive = $this->repository->getInactiveBudgets();
|
||||
$periodStart = $start->formatLocalized($this->monthAndDayFormat);
|
||||
$periodEnd = $end->formatLocalized($this->monthAndDayFormat);
|
||||
$budgetInformation = $this->repository->collectBudgetInformation($budgets, $start, $end);
|
||||
$budgetInformation = $this->repository->collectBudgetInformation($allBudgets, $start, $end);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$available = $this->repository->getAvailableBudget($defaultCurrency, $start, $end);
|
||||
$spent = array_sum(array_column($budgetInformation, 'spent'));
|
||||
@ -252,7 +252,7 @@ class BudgetController extends Controller
|
||||
'currentMonth',
|
||||
'next',
|
||||
'nextText',
|
||||
'prev',
|
||||
'prev', 'allBudgets',
|
||||
'prevText',
|
||||
'periodStart',
|
||||
'periodEnd',
|
||||
@ -420,11 +420,12 @@ class BudgetController extends Controller
|
||||
$end = Carbon::createFromFormat('Y-m-d', $request->string('end'));
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$amount = $request->get('amount');
|
||||
|
||||
$page = $request->integer('page') === 0 ? 1 : $request->integer('page');
|
||||
$this->repository->cleanupBudgets();
|
||||
$this->repository->setAvailableBudget($defaultCurrency, $start, $end, $amount);
|
||||
Preferences::mark();
|
||||
|
||||
return redirect(route('budgets.index', [$start->format('Y-m-d')]));
|
||||
return redirect(route('budgets.index', [$start->format('Y-m-d')]) . '?page=' . $page);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -503,7 +504,7 @@ class BudgetController extends Controller
|
||||
{
|
||||
$data = $request->getBudgetData();
|
||||
$budget = $this->repository->store($data);
|
||||
|
||||
$this->repository->cleanupBudgets();
|
||||
$request->session()->flash('success', strval(trans('firefly.stored_new_budget', ['name' => $budget->name])));
|
||||
Preferences::mark();
|
||||
|
||||
@ -530,6 +531,7 @@ class BudgetController extends Controller
|
||||
$this->repository->update($budget, $data);
|
||||
|
||||
$request->session()->flash('success', strval(trans('firefly.updated_budget', ['name' => $budget->name])));
|
||||
$this->repository->cleanupBudgets();
|
||||
Preferences::mark();
|
||||
|
||||
if (1 === intval($request->get('return_to_edit'))) {
|
||||
@ -549,13 +551,14 @@ class BudgetController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function updateIncome(Carbon $start, Carbon $end)
|
||||
public function updateIncome(Request $request, Carbon $start, Carbon $end)
|
||||
{
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$available = $this->repository->getAvailableBudget($defaultCurrency, $start, $end);
|
||||
$available = round($available, $defaultCurrency->decimal_places);
|
||||
$page = intval($request->get('page'));
|
||||
|
||||
return view('budgets.income', compact('available', 'start', 'end'));
|
||||
return view('budgets.income', compact('available', 'start', 'end', 'page'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,7 +39,6 @@ use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Steam;
|
||||
|
||||
/** checked
|
||||
* Class AccountController.
|
||||
@ -58,69 +57,6 @@ class AccountController extends Controller
|
||||
$this->generator = app(GeneratorInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function all(Account $account)
|
||||
{
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('chart.account.all');
|
||||
$cache->addProperty($account->id);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$start = $repository->oldestJournalDate($account);
|
||||
$end = new Carbon;
|
||||
|
||||
// depending on diff, do something with range of chart.
|
||||
$step = '1D';
|
||||
$months = $start->diffInMonths($end);
|
||||
if ($months > 3) {
|
||||
$step = '1W';
|
||||
}
|
||||
if ($months > 24) {
|
||||
$step = '1M'; // @codeCoverageIgnore
|
||||
}
|
||||
if ($months > 100) {
|
||||
$step = '1Y'; // @codeCoverageIgnore
|
||||
}
|
||||
$chartData = [];
|
||||
$current = clone $start;
|
||||
switch ($step) {
|
||||
case '1D':
|
||||
$format = (string)trans('config.month_and_day');
|
||||
$range = Steam::balanceInRange($account, $start, $end);
|
||||
$previous = array_values($range)[0];
|
||||
while ($end >= $current) {
|
||||
$theDate = $current->format('Y-m-d');
|
||||
$balance = $range[$theDate] ?? $previous;
|
||||
$label = $current->formatLocalized($format);
|
||||
$chartData[$label] = floatval($balance);
|
||||
$previous = $balance;
|
||||
$current->addDay();
|
||||
}
|
||||
break;
|
||||
case '1W':
|
||||
case '1M': // @codeCoverageIgnore
|
||||
case '1Y': // @codeCoverageIgnore
|
||||
while ($end >= $current) {
|
||||
$balance = floatval(Steam::balance($account, $current));
|
||||
$label = app('navigation')->periodShow($current, $step);
|
||||
$chartData[$label] = $balance;
|
||||
$current = app('navigation')->addPeriod($current, $step, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
$data = $this->generator->singleSet($account->name, $chartData);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the balances for all the user's expense accounts.
|
||||
@ -143,8 +79,8 @@ class AccountController extends Controller
|
||||
$start->subDay();
|
||||
|
||||
$accounts = $repository->getAccountsByType([AccountType::EXPENSE, AccountType::BENEFICIARY]);
|
||||
$startBalances = Steam::balancesByAccounts($accounts, $start);
|
||||
$endBalances = Steam::balancesByAccounts($accounts, $end);
|
||||
$startBalances = app('steam')->balancesByAccounts($accounts, $start);
|
||||
$endBalances = app('steam')->balancesByAccounts($accounts, $end);
|
||||
$chartData = [];
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
@ -366,34 +302,57 @@ class AccountController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function period(Account $account, Carbon $start)
|
||||
public function period(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$end = app('navigation')->endOfPeriod($start, $range);
|
||||
$cache = new CacheProperties();
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('chart.account.period');
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.account.period');
|
||||
$cache->addProperty($account->id);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$format = (string)trans('config.month_and_day');
|
||||
$range = Steam::balanceInRange($account, $start, $end);
|
||||
$current = clone $start;
|
||||
$previous = array_values($range)[0];
|
||||
$chartData = [];
|
||||
|
||||
while ($end >= $current) {
|
||||
$theDate = $current->format('Y-m-d');
|
||||
$balance = $range[$theDate] ?? $previous;
|
||||
$label = $current->formatLocalized($format);
|
||||
$chartData[$label] = $balance;
|
||||
$previous = $balance;
|
||||
$current->addDay();
|
||||
// depending on diff, do something with range of chart.
|
||||
$step = '1D';
|
||||
$months = $start->diffInMonths($end);
|
||||
if ($months > 3) {
|
||||
$step = '1W'; // @codeCoverageIgnore
|
||||
}
|
||||
if ($months > 24) {
|
||||
$step = '1M'; // @codeCoverageIgnore
|
||||
}
|
||||
if ($months > 100) {
|
||||
$step = '1Y'; // @codeCoverageIgnore
|
||||
}
|
||||
$chartData = [];
|
||||
$current = clone $start;
|
||||
switch ($step) {
|
||||
case '1D':
|
||||
$format = (string)trans('config.month_and_day');
|
||||
$range = app('steam')->balanceInRange($account, $start, $end);
|
||||
$previous = array_values($range)[0];
|
||||
while ($end >= $current) {
|
||||
$theDate = $current->format('Y-m-d');
|
||||
$balance = $range[$theDate] ?? $previous;
|
||||
$label = $current->formatLocalized($format);
|
||||
$chartData[$label] = floatval($balance);
|
||||
$previous = $balance;
|
||||
$current->addDay();
|
||||
}
|
||||
break;
|
||||
// @codeCoverageIgnoreStart
|
||||
case '1W':
|
||||
case '1M':
|
||||
case '1Y':
|
||||
while ($end >= $current) {
|
||||
$balance = floatval(app('steam')->balance($account, $current));
|
||||
$label = app('navigation')->periodShow($current, $step);
|
||||
$chartData[$label] = $balance;
|
||||
$current = app('navigation')->addPeriod($current, $step, 1);
|
||||
}
|
||||
break;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$data = $this->generator->singleSet($account->name, $chartData);
|
||||
$cache->store($data);
|
||||
|
||||
@ -436,8 +395,8 @@ class AccountController extends Controller
|
||||
$accounts = $repository->getAccountsByType([AccountType::REVENUE]);
|
||||
|
||||
$start->subDay();
|
||||
$startBalances = Steam::balancesByAccounts($accounts, $start);
|
||||
$endBalances = Steam::balancesByAccounts($accounts, $end);
|
||||
$startBalances = app('steam')->balancesByAccounts($accounts, $start);
|
||||
$endBalances = app('steam')->balancesByAccounts($accounts, $end);
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$id = $account->id;
|
||||
@ -457,49 +416,6 @@ class AccountController extends Controller
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an account's balance for a single month.
|
||||
*
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function single(Account $account)
|
||||
{
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.account.single');
|
||||
$cache->addProperty($account->id);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$format = (string)trans('config.month_and_day');
|
||||
$range = Steam::balanceInRange($account, $start, $end);
|
||||
$current = clone $start;
|
||||
$previous = array_values($range)[0];
|
||||
$chartData = [];
|
||||
|
||||
while ($end >= $current) {
|
||||
$theDate = $current->format('Y-m-d');
|
||||
$balance = $range[$theDate] ?? $previous;
|
||||
$label = $current->formatLocalized($format);
|
||||
$chartData[$label] = $balance;
|
||||
$previous = $balance;
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
$data = $this->generator->singleSet($account->name, $chartData);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
* @param Carbon $start
|
||||
@ -525,14 +441,14 @@ class AccountController extends Controller
|
||||
|
||||
$chartData = [];
|
||||
foreach ($accounts as $account) {
|
||||
$currency = $repository->find(intval($account->getMeta('currency_id')));
|
||||
$currency = $repository->findNull(intval($account->getMeta('currency_id')));
|
||||
$currentSet = [
|
||||
'label' => $account->name,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'entries' => [],
|
||||
];
|
||||
$currentStart = clone $start;
|
||||
$range = Steam::balanceInRange($account, $start, clone $end);
|
||||
$range = app('steam')->balanceInRange($account, $start, clone $end);
|
||||
$previous = array_values($range)[0];
|
||||
while ($currentStart <= $end) {
|
||||
$format = $currentStart->format('Y-m-d');
|
||||
|
@ -83,6 +83,7 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.budget.budget');
|
||||
$cache->addProperty($budget->id);
|
||||
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
@ -149,6 +150,7 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.budget.budget.limit');
|
||||
$cache->addProperty($budgetLimit->id);
|
||||
$cache->addProperty($budget->id);
|
||||
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
|
@ -197,7 +197,7 @@ class ExpenseReportController extends Controller
|
||||
$collection->push($expenseAccount);
|
||||
|
||||
$revenue = $this->accountRepository->findByName($expenseAccount->name, [AccountType::REVENUE]);
|
||||
if (!is_null($revenue->id)) {
|
||||
if (!is_null($revenue)) {
|
||||
$collection->push($revenue);
|
||||
}
|
||||
$combined[$expenseAccount->name] = $collection;
|
||||
|
@ -100,6 +100,7 @@ class IndexController extends Controller
|
||||
$config['initial-config-complete'] = false;
|
||||
$config['has-file-upload'] = false;
|
||||
$config['delimiter'] = "\t" === $config['delimiter'] ? 'tab' : $config['delimiter'];
|
||||
unset($config['stage']);
|
||||
|
||||
$result = json_encode($config, JSON_PRETTY_PRINT);
|
||||
$name = sprintf('"%s"', addcslashes('import-configuration-' . date('Y-m-d') . '.json', '"\\'));
|
||||
|
@ -47,7 +47,7 @@ class JavascriptController extends Controller
|
||||
{
|
||||
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||
$preference = Preferences::get('currencyPreference', config('firefly.default_currency', 'EUR'));
|
||||
$default = $currencyRepository->findByCode($preference->data);
|
||||
$default = $currencyRepository->findByCodeNull($preference->data);
|
||||
|
||||
$data = ['accounts' => []];
|
||||
|
||||
@ -95,13 +95,13 @@ class JavascriptController extends Controller
|
||||
*/
|
||||
public function variables(Request $request, AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepository)
|
||||
{
|
||||
$account = $repository->find(intval($request->get('account')));
|
||||
$account = $repository->findNull(intval($request->get('account')));
|
||||
$currencyId = 0;
|
||||
if (null !== $account) {
|
||||
$currencyId = intval($account->getMeta('currency_id'));
|
||||
}
|
||||
/** @var TransactionCurrency $currency */
|
||||
$currency = $currencyRepository->find($currencyId);
|
||||
$currency = $currencyRepository->findNull($currencyId);
|
||||
if (0 === $currencyId) {
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ class BoxController extends Controller
|
||||
$balance = $balances[$account->id] ?? '0';
|
||||
$currencyId = intval($account->getMeta('currency_id'));
|
||||
if ($currencyId !== 0) {
|
||||
$accountCurrency = $currencyRepos->find($currencyId);
|
||||
$accountCurrency = $currencyRepos->findNull($currencyId);
|
||||
}
|
||||
if (!isset($netWorth[$accountCurrency->id])) {
|
||||
$netWorth[$accountCurrency->id]['currency'] = $accountCurrency;
|
||||
|
@ -45,9 +45,8 @@ class FrontpageController extends Controller
|
||||
$info = [];
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($set as $piggyBank) {
|
||||
$rep = $piggyBank->currentRelevantRep();
|
||||
$amount = strval($rep->currentamount);
|
||||
if (null !== $rep->id && 1 === bccomp($amount, '0')) {
|
||||
$amount = $repository->getCurrentAmount($piggyBank);
|
||||
if (1 === bccomp($amount, '0')) {
|
||||
// percentage!
|
||||
$pct = round(($amount / $piggyBank->targetamount) * 100);
|
||||
|
||||
|
@ -85,14 +85,28 @@ class NewUserController extends Controller
|
||||
$this->createSavingsAccount($request, $repository);
|
||||
|
||||
// also store currency preference from input:
|
||||
$currency = $currencyRepository->find(intval($request->input('amount_currency_id_bank_balance')));
|
||||
$currency = $currencyRepository->findNull(intval($request->input('amount_currency_id_bank_balance')));
|
||||
|
||||
if (null !== $currency->id) {
|
||||
if (null !== $currency) {
|
||||
// store currency preference:
|
||||
Preferences::set('currencyPreference', $currency->code);
|
||||
Preferences::mark();
|
||||
}
|
||||
|
||||
// set default optional fields:
|
||||
$visibleFields = [
|
||||
'interest_date' => true,
|
||||
'book_date' => false,
|
||||
'process_date' => false,
|
||||
'due_date' => false,
|
||||
'payment_date' => false,
|
||||
'invoice_date' => false,
|
||||
'internal_reference' => false,
|
||||
'notes' => true,
|
||||
'attachments' => true,
|
||||
];
|
||||
Preferences::set('transaction_journal_optional_fields', $visibleFields);
|
||||
|
||||
Session::flash('success', strval(trans('firefly.stored_new_accounts_new_user')));
|
||||
Preferences::mark();
|
||||
|
||||
@ -112,6 +126,7 @@ class NewUserController extends Controller
|
||||
'iban' => null,
|
||||
'accountType' => 'asset',
|
||||
'virtualBalance' => 0,
|
||||
'account_type_id' => null,
|
||||
'active' => true,
|
||||
'accountRole' => 'defaultAsset',
|
||||
'openingBalance' => $request->input('bank_balance'),
|
||||
@ -136,6 +151,7 @@ class NewUserController extends Controller
|
||||
'name' => $request->get('bank_name') . ' savings account',
|
||||
'iban' => null,
|
||||
'accountType' => 'asset',
|
||||
'account_type_id' => null,
|
||||
'virtualBalance' => 0,
|
||||
'active' => true,
|
||||
'accountRole' => 'savingAsset',
|
||||
|
@ -67,12 +67,12 @@ class PiggyBankController extends Controller
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function add(PiggyBank $piggyBank)
|
||||
public function add(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
/** @var Carbon $date */
|
||||
$date = session('end', Carbon::now()->endOfMonth());
|
||||
$leftOnAccount = $piggyBank->leftOnAccount($date);
|
||||
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount ?? '0';
|
||||
$savedSoFar = $repository->getCurrentAmount($piggyBank);
|
||||
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
|
||||
$maxAmount = min($leftOnAccount, $leftToSave);
|
||||
|
||||
@ -86,12 +86,12 @@ class PiggyBankController extends Controller
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function addMobile(PiggyBank $piggyBank)
|
||||
public function addMobile(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
/** @var Carbon $date */
|
||||
$date = session('end', Carbon::now()->endOfMonth());
|
||||
$leftOnAccount = $piggyBank->leftOnAccount($date);
|
||||
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount ?? '0';
|
||||
$savedSoFar = $repository->getCurrentAmount($piggyBank);
|
||||
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
|
||||
$maxAmount = min($leftOnAccount, $leftToSave);
|
||||
|
||||
@ -212,7 +212,8 @@ class PiggyBankController extends Controller
|
||||
Log::debug('Looping piggues');
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($collection as $piggyBank) {
|
||||
$piggyBank->savedSoFar = $piggyBank->currentRelevantRep()->currentamount ?? '0';
|
||||
|
||||
$piggyBank->savedSoFar = $piggyRepository->getCurrentAmount($piggyBank);
|
||||
$piggyBank->percentage = 0 !== bccomp('0', $piggyBank->savedSoFar) ? intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100) : 0;
|
||||
$piggyBank->leftToSave = bcsub($piggyBank->targetamount, strval($piggyBank->savedSoFar));
|
||||
$piggyBank->percentage = $piggyBank->percentage > 100 ? 100 : $piggyBank->percentage;
|
||||
|
@ -313,7 +313,7 @@ class ExpenseController extends Controller
|
||||
$collection->push($expenseAccount);
|
||||
|
||||
$revenue = $this->accountRepository->findByName($expenseAccount->name, [AccountType::REVENUE]);
|
||||
if (!is_null($revenue->id)) {
|
||||
if (!is_null($revenue)) {
|
||||
$collection->push($revenue);
|
||||
}
|
||||
$combined[$expenseAccount->name] = $collection;
|
||||
|
@ -31,11 +31,11 @@ use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Update\JournalUpdateService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use View;
|
||||
|
||||
/**
|
||||
@ -43,6 +43,8 @@ use View;
|
||||
*/
|
||||
class BulkController extends Controller
|
||||
{
|
||||
/** @var JournalRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
|
||||
/**
|
||||
@ -54,6 +56,7 @@ class BulkController extends Controller
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(JournalRepositoryInterface::class);
|
||||
app('view')->share('title', trans('firefly.transactions'));
|
||||
app('view')->share('mainTitleIcon', 'fa-repeat');
|
||||
|
||||
@ -77,8 +80,8 @@ class BulkController extends Controller
|
||||
$messages = [];
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$sources = $journal->sourceAccountList();
|
||||
$destinations = $journal->destinationAccountList();
|
||||
$sources = $this->repository->getJournalSourceAccounts($journal);
|
||||
$destinations = $this->repository->getJournalDestinationAccounts($journal);
|
||||
if ($sources->count() > 1) {
|
||||
$messages[] = trans('firefly.cannot_edit_multiple_source', ['description' => $journal->description, 'id' => $journal->id]);
|
||||
continue;
|
||||
@ -88,13 +91,13 @@ class BulkController extends Controller
|
||||
$messages[] = trans('firefly.cannot_edit_multiple_dest', ['description' => $journal->description, 'id' => $journal->id]);
|
||||
continue;
|
||||
}
|
||||
if (TransactionType::OPENING_BALANCE === $journal->transactionType->type) {
|
||||
if (TransactionType::OPENING_BALANCE === $this->repository->getTransactionType($journal)) {
|
||||
$messages[] = trans('firefly.cannot_edit_opening_balance');
|
||||
continue;
|
||||
}
|
||||
|
||||
// cannot edit reconciled transactions / journals:
|
||||
if ($journal->transactions->first()->reconciled) {
|
||||
if ($this->repository->isJournalReconciled($journal)) {
|
||||
$messages[] = trans('firefly.cannot_edit_reconciled', ['description' => $journal->description, 'id' => $journal->id]);
|
||||
continue;
|
||||
}
|
||||
@ -138,11 +141,14 @@ class BulkController extends Controller
|
||||
*/
|
||||
public function update(BulkEditJournalRequest $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
/** @var JournalUpdateService $service */
|
||||
$service = app(JournalUpdateService::class);
|
||||
$journalIds = $request->get('journals');
|
||||
$ignoreCategory = intval($request->get('ignore_category')) === 1;
|
||||
$ignoreBudget = intval($request->get('ignore_budget')) === 1;
|
||||
$ignoreTags = intval($request->get('ignore_tags')) === 1;
|
||||
$count = 0;
|
||||
$count = 0;
|
||||
|
||||
if (is_array($journalIds)) {
|
||||
foreach ($journalIds as $journalId) {
|
||||
$journal = $repository->find(intval($journalId));
|
||||
@ -152,6 +158,7 @@ class BulkController extends Controller
|
||||
// update category if not told to ignore
|
||||
if ($ignoreCategory === false) {
|
||||
Log::debug(sprintf('Set category to %s', $request->string('category')));
|
||||
|
||||
$repository->updateCategory($journal, $request->string('category'));
|
||||
}
|
||||
// update budget if not told to ignore (and is withdrawal)
|
||||
@ -161,7 +168,7 @@ class BulkController extends Controller
|
||||
}
|
||||
if ($ignoreTags === false) {
|
||||
Log::debug(sprintf('Set tags to %s', $request->string('budget_id')));
|
||||
$repository->updateTags($journal, explode(',', $request->string('tags')));
|
||||
$repository->updateTags($journal,['tags' => explode(',', $request->string('tags'))]);
|
||||
}
|
||||
// update tags if not told to ignore (and is withdrawal)
|
||||
}
|
||||
|
@ -43,6 +43,9 @@ class ConvertController extends Controller
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $accounts;
|
||||
|
||||
/** @var JournalRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* ConvertController constructor.
|
||||
*/
|
||||
@ -53,7 +56,8 @@ class ConvertController extends Controller
|
||||
// some useful repositories:
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->accounts = app(AccountRepositoryInterface::class);
|
||||
$this->accounts = app(AccountRepositoryInterface::class);
|
||||
$this->repository = app(JournalRepositoryInterface::class);
|
||||
|
||||
app('view')->share('title', trans('firefly.transactions'));
|
||||
app('view')->share('mainTitleIcon', 'fa-exchange');
|
||||
@ -76,8 +80,7 @@ class ConvertController extends Controller
|
||||
return $this->redirectToAccount($journal);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$positiveAmount = $journal->amountPositive();
|
||||
$positiveAmount = $this->repository->getJournalTotal($journal);
|
||||
$assetAccounts = ExpandedForm::makeSelectList($this->accounts->getActiveAccountsByType([AccountType::DEFAULT, AccountType::ASSET]));
|
||||
$sourceType = $journal->transactionType;
|
||||
$subTitle = trans('firefly.convert_to_' . $destinationType->type, ['description' => $journal->description]);
|
||||
@ -98,8 +101,8 @@ class ConvertController extends Controller
|
||||
}
|
||||
|
||||
// get source and destination account:
|
||||
$sourceAccount = $journal->sourceAccountList()->first();
|
||||
$destinationAccount = $journal->destinationAccountList()->first();
|
||||
$sourceAccount = $this->repository->getJournalSourceAccounts($journal)->first();
|
||||
$destinationAccount = $this->repository->getJournalDestinationAccounts($journal)->first();
|
||||
|
||||
return view(
|
||||
'transactions.convert',
|
||||
@ -183,8 +186,8 @@ class ConvertController extends Controller
|
||||
{
|
||||
/** @var AccountRepositoryInterface $accountRepository */
|
||||
$accountRepository = app(AccountRepositoryInterface::class);
|
||||
$sourceAccount = $journal->sourceAccountList()->first();
|
||||
$destinationAccount = $journal->destinationAccountList()->first();
|
||||
$sourceAccount = $this->repository->getJournalSourceAccounts($journal)->first();
|
||||
$destinationAccount = $this->repository->getJournalDestinationAccounts($journal)->first();
|
||||
$sourceType = $journal->transactionType;
|
||||
$joined = $sourceType->type . '-' . $destinationType->type;
|
||||
switch ($joined) {
|
||||
@ -196,7 +199,7 @@ class ConvertController extends Controller
|
||||
break;
|
||||
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER:
|
||||
// two
|
||||
$destination = $accountRepository->find(intval($data['destination_account_asset']));
|
||||
$destination = $accountRepository->findNull(intval($data['destination_account_asset']));
|
||||
break;
|
||||
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL:
|
||||
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL:
|
||||
@ -239,8 +242,8 @@ class ConvertController extends Controller
|
||||
{
|
||||
/** @var AccountRepositoryInterface $accountRepository */
|
||||
$accountRepository = app(AccountRepositoryInterface::class);
|
||||
$sourceAccount = $journal->sourceAccountList()->first();
|
||||
$destinationAccount = $journal->destinationAccountList()->first();
|
||||
$sourceAccount = $this->repository->getJournalSourceAccounts($journal)->first();
|
||||
$destinationAccount = $this->repository->getJournalDestinationAccounts($journal)->first();
|
||||
$sourceType = $journal->transactionType;
|
||||
$joined = $sourceType->type . '-' . $destinationType->type;
|
||||
switch ($joined) {
|
||||
@ -273,7 +276,7 @@ class ConvertController extends Controller
|
||||
$source = $destinationAccount;
|
||||
break;
|
||||
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER:
|
||||
$source = $accountRepository->find(intval($data['source_account_asset']));
|
||||
$source = $accountRepository->findNull(intval($data['source_account_asset']));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournalLink $link
|
||||
* @param TransactionJournalLink $link
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
@ -93,8 +93,8 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param JournalLinkRequest $request
|
||||
* @param TransactionJournal $journal
|
||||
* @param JournalLinkRequest $request
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
@ -123,7 +123,7 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournalLink $link
|
||||
* @param TransactionJournalLink $link
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
|
@ -25,8 +25,8 @@ namespace FireflyIII\Http\Controllers\Transaction;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\MassDeleteJournalRequest;
|
||||
use FireflyIII\Http\Requests\MassEditJournalRequest;
|
||||
use FireflyIII\Http\Requests\MassEditBulkJournalRequest;
|
||||
use FireflyIII\Http\Requests\MassEditJournalRequest;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
@ -43,6 +43,9 @@ use View;
|
||||
*/
|
||||
class MassController extends Controller
|
||||
{
|
||||
/** @var JournalRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -54,6 +57,7 @@ class MassController extends Controller
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', trans('firefly.transactions'));
|
||||
app('view')->share('mainTitleIcon', 'fa-repeat');
|
||||
$this->repository = app(JournalRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
@ -76,12 +80,11 @@ class MassController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MassDeleteJournalRequest $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param MassDeleteJournalRequest $request
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function destroy(MassDeleteJournalRequest $request, JournalRepositoryInterface $repository)
|
||||
public function destroy(MassDeleteJournalRequest $request)
|
||||
{
|
||||
$ids = $request->get('confirm_mass_delete');
|
||||
$set = new Collection;
|
||||
@ -89,7 +92,7 @@ class MassController extends Controller
|
||||
/** @var int $journalId */
|
||||
foreach ($ids as $journalId) {
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $repository->find(intval($journalId));
|
||||
$journal = $this->repository->find(intval($journalId));
|
||||
if (null !== $journal->id && intval($journalId) === $journal->id) {
|
||||
$set->push($journal);
|
||||
}
|
||||
@ -100,7 +103,7 @@ class MassController extends Controller
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($set as $journal) {
|
||||
$repository->delete($journal);
|
||||
$this->repository->delete($journal);
|
||||
++$count;
|
||||
}
|
||||
|
||||
@ -112,6 +115,8 @@ class MassController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO this code is a mess.
|
||||
*
|
||||
* @param Collection $journals
|
||||
*
|
||||
* @return View
|
||||
@ -134,8 +139,8 @@ class MassController extends Controller
|
||||
$messages = [];
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$sources = $journal->sourceAccountList();
|
||||
$destinations = $journal->destinationAccountList();
|
||||
$sources = $this->repository->getJournalSourceAccounts($journal);
|
||||
$destinations = $this->repository->getJournalDestinationAccounts($journal);
|
||||
if ($sources->count() > 1) {
|
||||
$messages[] = trans('firefly.cannot_edit_multiple_source', ['description' => $journal->description, 'id' => $journal->id]);
|
||||
continue;
|
||||
@ -145,13 +150,13 @@ class MassController extends Controller
|
||||
$messages[] = trans('firefly.cannot_edit_multiple_dest', ['description' => $journal->description, 'id' => $journal->id]);
|
||||
continue;
|
||||
}
|
||||
if (TransactionType::OPENING_BALANCE === $journal->transactionType->type) {
|
||||
if (TransactionType::OPENING_BALANCE === $this->repository->getTransactionType($journal)) {
|
||||
$messages[] = trans('firefly.cannot_edit_opening_balance');
|
||||
continue;
|
||||
}
|
||||
|
||||
// cannot edit reconciled transactions / journals:
|
||||
if ($journal->transactions->first()->reconciled) {
|
||||
if ($this->repository->isJournalReconciled($journal)) {
|
||||
$messages[] = trans('firefly.cannot_edit_reconciled', ['description' => $journal->description, 'id' => $journal->id]);
|
||||
continue;
|
||||
}
|
||||
@ -169,11 +174,11 @@ class MassController extends Controller
|
||||
// collect some useful meta data for the mass edit:
|
||||
$filtered->each(
|
||||
function (TransactionJournal $journal) {
|
||||
$transaction = $journal->positiveTransaction();
|
||||
$transaction = $this->repository->getFirstPosTransaction($journal);
|
||||
$currency = $transaction->transactionCurrency;
|
||||
$journal->amount = floatval($transaction->amount);
|
||||
$sources = $journal->sourceAccountList();
|
||||
$destinations = $journal->destinationAccountList();
|
||||
$sources = $this->repository->getJournalSourceAccounts($journal);
|
||||
$destinations = $this->repository->getJournalDestinationAccounts($journal);
|
||||
$journal->transaction_count = $journal->transactions()->count();
|
||||
$journal->currency_symbol = $currency->symbol;
|
||||
$journal->transaction_type_type = $journal->transactionType->type;
|
||||
@ -202,6 +207,8 @@ class MassController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO this cannot work with new update service.
|
||||
*
|
||||
* @param MassEditJournalRequest $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
*
|
||||
@ -216,11 +223,12 @@ class MassController extends Controller
|
||||
$journal = $repository->find(intval($journalId));
|
||||
if (!is_null($journal)) {
|
||||
// get optional fields:
|
||||
$what = strtolower($journal->transactionTypeStr());
|
||||
$sourceAccountId = $request->get('source_account_id')[$journal->id] ?? 0;
|
||||
$sourceAccountName = $request->get('source_account_name')[$journal->id] ?? '';
|
||||
$destAccountId = $request->get('destination_account_id')[$journal->id] ?? 0;
|
||||
$destAccountName = $request->get('destination_account_name')[$journal->id] ?? '';
|
||||
$what = strtolower($this->repository->getTransactionType($journal));
|
||||
$sourceAccountId = $request->get('source_account_id')[$journal->id] ?? null;
|
||||
$currencyId = $request->get('transaction_currency_id')[$journal->id] ?? 1;
|
||||
$sourceAccountName = $request->get('source_account_name')[$journal->id] ?? null;
|
||||
$destAccountId = $request->get('destination_account_id')[$journal->id] ?? null;
|
||||
$destAccountName = $request->get('destination_account_name')[$journal->id] ?? null;
|
||||
$budgetId = $request->get('budget_id')[$journal->id] ?? 0;
|
||||
$category = $request->get('category')[$journal->id];
|
||||
$tags = $journal->tags->pluck('tag')->toArray();
|
||||
@ -228,29 +236,47 @@ class MassController extends Controller
|
||||
$foreignAmount = isset($request->get('foreign_amount')[$journal->id]) ? round($request->get('foreign_amount')[$journal->id], 12) : null;
|
||||
$foreignCurrencyId = isset($request->get('foreign_currency_id')[$journal->id]) ?
|
||||
intval($request->get('foreign_currency_id')[$journal->id]) : null;
|
||||
|
||||
$notes = $repository->getNoteText($journal);
|
||||
// build data array
|
||||
$data = [
|
||||
'id' => $journal->id,
|
||||
'what' => $what,
|
||||
'description' => $request->get('description')[$journal->id],
|
||||
'source_account_id' => intval($sourceAccountId),
|
||||
'source_account_name' => $sourceAccountName,
|
||||
'destination_account_id' => intval($destAccountId),
|
||||
'destination_account_name' => $destAccountName,
|
||||
'amount' => $foreignAmount,
|
||||
'native_amount' => $amount,
|
||||
'source_amount' => $amount,
|
||||
'date' => new Carbon($request->get('date')[$journal->id]),
|
||||
'interest_date' => $journal->interest_date,
|
||||
'book_date' => $journal->book_date,
|
||||
'process_date' => $journal->process_date,
|
||||
'budget_id' => intval($budgetId),
|
||||
'currency_id' => $foreignCurrencyId,
|
||||
'foreign_amount' => $foreignAmount,
|
||||
'destination_amount' => $foreignAmount,
|
||||
'category' => $category,
|
||||
'tags' => $tags,
|
||||
'id' => $journal->id,
|
||||
'what' => $what,
|
||||
'description' => $request->get('description')[$journal->id],
|
||||
'date' => new Carbon($request->get('date')[$journal->id]),
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
'notes' => $notes,
|
||||
'transactions' => [[
|
||||
|
||||
'category_id' => null,
|
||||
'category_name' => $category,
|
||||
'budget_id' => intval($budgetId),
|
||||
'budget_name' => null,
|
||||
'source_id' => intval($sourceAccountId),
|
||||
'source_name' => $sourceAccountName,
|
||||
'destination_id' => intval($destAccountId),
|
||||
'destination_name' => $destAccountName,
|
||||
'amount' => $amount,
|
||||
'identifier' => 0,
|
||||
'reconciled' => false,
|
||||
'currency_id' => intval($currencyId),
|
||||
'currency_code' => null,
|
||||
'description' => null,
|
||||
'foreign_amount' => null,
|
||||
'foreign_currency_id' => $foreignCurrencyId,
|
||||
'foreign_currency_code' => null,
|
||||
//'native_amount' => $amount,
|
||||
//'source_amount' => $amount,
|
||||
//'foreign_amount' => $foreignAmount,
|
||||
//'destination_amount' => $foreignAmount,
|
||||
//'amount' => $foreignAmount,
|
||||
]],
|
||||
'currency_id' => $foreignCurrencyId,
|
||||
'tags' => $tags,
|
||||
'interest_date' => $journal->interest_date,
|
||||
'book_date' => $journal->book_date,
|
||||
'process_date' => $journal->process_date,
|
||||
|
||||
];
|
||||
// call repository update function.
|
||||
$repository->update($journal, $data);
|
||||
|
@ -104,13 +104,13 @@ class SingleController extends Controller
|
||||
*/
|
||||
public function cloneTransaction(TransactionJournal $journal)
|
||||
{
|
||||
$source = $journal->sourceAccountList()->first();
|
||||
$destination = $journal->destinationAccountList()->first();
|
||||
$budget = $journal->budgets()->first();
|
||||
$budgetId = null === $budget ? 0 : $budget->id;
|
||||
$category = $journal->categories()->first();
|
||||
$categoryName = null === $category ? '' : $category->name;
|
||||
$tags = join(',', $journal->tags()->get()->pluck('tag')->toArray());
|
||||
$source = $this->repository->getJournalSourceAccounts($journal)->first();
|
||||
$destination = $this->repository->getJournalDestinationAccounts($journal)->first();
|
||||
$budgetId = $this->repository->getJournalBudgetId($journal);
|
||||
$categoryName = $this->repository->getJournalCategoryName($journal);
|
||||
|
||||
$tags = join(',', $this->repository->getTags($journal));
|
||||
// todo less direct database access. Use collector?
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $journal->transactions()->first();
|
||||
$amount = app('steam')->positive($transaction->amount);
|
||||
@ -171,6 +171,14 @@ class SingleController extends Controller
|
||||
$subTitle = trans('form.add_new_' . $what);
|
||||
$subTitleIcon = 'fa-plus';
|
||||
$optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
|
||||
$source = intval($request->get('source'));
|
||||
|
||||
if (($what === 'withdrawal' || $what === 'transfer') && $source > 0) {
|
||||
$preFilled['source_account_id'] = $source;
|
||||
}
|
||||
if ($what === 'deposit' && $source > 0) {
|
||||
$preFilled['destination_account_id'] = $source;
|
||||
}
|
||||
|
||||
Session::put('preFilled', $preFilled);
|
||||
|
||||
@ -230,7 +238,7 @@ class SingleController extends Controller
|
||||
$type = $transactionJournal->transactionTypeStr();
|
||||
Session::flash('success', strval(trans('firefly.deleted_' . strtolower($type), ['description' => $transactionJournal->description])));
|
||||
|
||||
$this->repository->delete($transactionJournal);
|
||||
$this->repository->destroy($transactionJournal);
|
||||
|
||||
Preferences::mark();
|
||||
|
||||
@ -242,53 +250,56 @@ class SingleController extends Controller
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function edit(TransactionJournal $journal)
|
||||
public function edit(TransactionJournal $journal, JournalRepositoryInterface $repository)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->isOpeningBalance($journal)) {
|
||||
$transactionType = $repository->getTransactionType($journal);
|
||||
|
||||
// redirect to account:
|
||||
if ($transactionType === TransactionType::OPENING_BALANCE) {
|
||||
return $this->redirectToAccount($journal);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
// redirect to reconcile edit:
|
||||
if ($transactionType === TransactionType::RECONCILIATION) {
|
||||
return redirect(route('accounts.reconcile.edit', [$journal->id]));
|
||||
}
|
||||
|
||||
// redirect to split edit:
|
||||
if ($this->isSplitJournal($journal)) {
|
||||
return redirect(route('transactions.split.edit', [$journal->id]));
|
||||
}
|
||||
|
||||
$what = strtolower($journal->transactionTypeStr());
|
||||
$what = strtolower($transactionType);
|
||||
$assetAccounts = $this->groupedAccountList();
|
||||
$budgetList = ExpandedForm::makeSelectListWithEmpty($this->budgets->getBudgets());
|
||||
|
||||
if (TransactionType::RECONCILIATION === $journal->transactionType->type) {
|
||||
return redirect(route('accounts.reconcile.edit', [$journal->id]));
|
||||
}
|
||||
|
||||
// view related code
|
||||
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
|
||||
|
||||
// journal related code
|
||||
$sourceAccounts = $journal->sourceAccountList();
|
||||
$destinationAccounts = $journal->destinationAccountList();
|
||||
$sourceAccounts = $repository->getJournalSourceAccounts($journal);
|
||||
$destinationAccounts = $repository->getJournalDestinationAccounts($journal);
|
||||
$optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
|
||||
$pTransaction = $journal->positiveTransaction();
|
||||
$pTransaction = $repository->getFirstPosTransaction($journal);
|
||||
$foreignCurrency = null !== $pTransaction->foreignCurrency ? $pTransaction->foreignCurrency : $pTransaction->transactionCurrency;
|
||||
$preFilled = [
|
||||
'date' => $journal->dateAsString(),
|
||||
'interest_date' => $journal->dateAsString('interest_date'),
|
||||
'book_date' => $journal->dateAsString('book_date'),
|
||||
'process_date' => $journal->dateAsString('process_date'),
|
||||
'category' => $journal->categoryAsString(),
|
||||
'budget_id' => $journal->budgetId(),
|
||||
'tags' => join(',', $journal->tags->pluck('tag')->toArray()),
|
||||
'date' => $repository->getJournalDate($journal, null), // $journal->dateAsString()
|
||||
'interest_date' => $repository->getJournalDate($journal, 'interest_date'),
|
||||
'book_date' => $repository->getJournalDate($journal, 'book_date'),
|
||||
'process_date' => $repository->getJournalDate($journal, 'process_date'),
|
||||
'category' => $repository->getJournalCategoryName($journal),
|
||||
'budget_id' => $repository->getJournalBudgetId($journal),
|
||||
'tags' => join(',', $repository->getTags($journal)),
|
||||
'source_account_id' => $sourceAccounts->first()->id,
|
||||
'source_account_name' => $sourceAccounts->first()->edit_name,
|
||||
'destination_account_id' => $destinationAccounts->first()->id,
|
||||
'destination_account_name' => $destinationAccounts->first()->edit_name,
|
||||
|
||||
// new custom fields:
|
||||
'due_date' => $journal->dateAsString('due_date'),
|
||||
'payment_date' => $journal->dateAsString('payment_date'),
|
||||
'invoice_date' => $journal->dateAsString('invoice_date'),
|
||||
'interal_reference' => $journal->getMeta('internal_reference'),
|
||||
'notes' => '',
|
||||
'due_date' => $repository->getJournalDate($journal, 'due_date'),
|
||||
'payment_date' => $repository->getJournalDate($journal, 'payment_date'),
|
||||
'invoice_date' => $repository->getJournalDate($journal, 'invoice_date'),
|
||||
'interal_reference' => $repository->getMetaField($journal, 'internal_reference'),
|
||||
'notes' => $repository->getNoteText($journal),
|
||||
|
||||
// amount fields
|
||||
'amount' => $pTransaction->amount,
|
||||
@ -301,11 +312,6 @@ class SingleController extends Controller
|
||||
'foreign_currency' => $foreignCurrency,
|
||||
'destination_currency' => $foreignCurrency,
|
||||
];
|
||||
/** @var Note $note */
|
||||
$note = $this->repository->getNote($journal);
|
||||
if (null !== $note) {
|
||||
$preFilled['notes'] = $note->text;
|
||||
}
|
||||
|
||||
// amounts for withdrawals and deposits:
|
||||
// amount, native_amount, source_amount, destination_amount
|
||||
@ -340,6 +346,8 @@ class SingleController extends Controller
|
||||
$createAnother = 1 === intval($request->get('create_another'));
|
||||
$data = $request->getJournalData();
|
||||
$journal = $repository->store($data);
|
||||
|
||||
|
||||
if (null === $journal->id) {
|
||||
// error!
|
||||
Log::error('Could not store transaction journal: ', $journal->getErrors()->toArray());
|
||||
@ -416,7 +424,7 @@ class SingleController extends Controller
|
||||
event(new UpdatedTransactionJournal($journal));
|
||||
// update, get events by date and sort DESC
|
||||
|
||||
$type = strtolower($journal->transactionTypeStr());
|
||||
$type = strtolower($this->repository->getTransactionType($journal));
|
||||
Session::flash('success', strval(trans('firefly.updated_' . $type, ['description' => $data['description']])));
|
||||
Preferences::mark();
|
||||
|
||||
|
@ -29,7 +29,6 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\SplitJournalFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
@ -37,7 +36,6 @@ use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalTaskerInterface;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use Steam;
|
||||
@ -97,7 +95,7 @@ class SplitController extends Controller
|
||||
public function edit(Request $request, TransactionJournal $journal)
|
||||
{
|
||||
if ($this->isOpeningBalance($journal)) {
|
||||
return $this->redirectToAccount($journal);
|
||||
return $this->redirectToAccount($journal); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size')));
|
||||
@ -125,20 +123,11 @@ class SplitController extends Controller
|
||||
Session::forget('transactions.edit-split.fromUpdate');
|
||||
|
||||
return view(
|
||||
'transactions.split.edit',
|
||||
compact(
|
||||
'subTitleIcon',
|
||||
'currencies',
|
||||
'optionalFields',
|
||||
'preFilled',
|
||||
'subTitle',
|
||||
'uploadSize',
|
||||
'assetAccounts',
|
||||
'budgets',
|
||||
'journal',
|
||||
'accountArray',
|
||||
'previous'
|
||||
)
|
||||
'transactions.split.edit', compact(
|
||||
'subTitleIcon', 'currencies', 'optionalFields', 'preFilled', 'subTitle', 'uploadSize', 'assetAccounts', 'budgets',
|
||||
'journal', 'accountArray',
|
||||
'previous'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -151,10 +140,11 @@ class SplitController extends Controller
|
||||
public function update(SplitJournalFormRequest $request, TransactionJournal $journal)
|
||||
{
|
||||
if ($this->isOpeningBalance($journal)) {
|
||||
return $this->redirectToAccount($journal);
|
||||
return $this->redirectToAccount($journal); // @codeCoverageIgnore
|
||||
}
|
||||
$data = $this->arrayFromInput($request);
|
||||
$journal = $this->repository->updateSplitJournal($journal, $data);
|
||||
$data = $request->getAll();
|
||||
$journal = $this->repository->update($journal, $data);
|
||||
|
||||
/** @var array $files */
|
||||
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
|
||||
// save attachments:
|
||||
@ -168,8 +158,8 @@ class SplitController extends Controller
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$type = strtolower($journal->transactionTypeStr());
|
||||
Session::flash('success', strval(trans('firefly.updated_' . $type, ['description' => $data['journal_description']])));
|
||||
$type = strtolower($this->repository->getTransactionType($journal));
|
||||
Session::flash('success', strval(trans('firefly.updated_' . $type, ['description' => $data['description']])));
|
||||
Preferences::mark();
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
@ -185,39 +175,6 @@ class SplitController extends Controller
|
||||
return redirect($this->getPreviousUri('transactions.edit-split.uri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SplitJournalFormRequest $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function arrayFromInput(SplitJournalFormRequest $request): array
|
||||
{
|
||||
$tags = null === $request->get('tags') ? '' : $request->get('tags');
|
||||
$array = [
|
||||
'journal_description' => $request->get('journal_description'),
|
||||
'journal_source_account_id' => $request->get('journal_source_account_id'),
|
||||
'journal_source_account_name' => $request->get('journal_source_account_name'),
|
||||
'journal_destination_account_id' => $request->get('journal_destination_account_id'),
|
||||
'what' => $request->get('what'),
|
||||
'date' => $request->get('date'),
|
||||
// all custom fields:
|
||||
'interest_date' => $request->get('interest_date'),
|
||||
'book_date' => $request->get('book_date'),
|
||||
'process_date' => $request->get('process_date'),
|
||||
'due_date' => $request->get('due_date'),
|
||||
'payment_date' => $request->get('payment_date'),
|
||||
'invoice_date' => $request->get('invoice_date'),
|
||||
'internal_reference' => $request->get('internal_reference'),
|
||||
'notes' => $request->get('notes'),
|
||||
'tags' => explode(',', $tags),
|
||||
|
||||
// transactions.
|
||||
'transactions' => $this->getTransactionDataFromRequest($request),
|
||||
];
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SplitJournalFormRequest|Request $request
|
||||
* @param TransactionJournal $journal
|
||||
@ -226,36 +183,29 @@ class SplitController extends Controller
|
||||
*/
|
||||
private function arrayFromJournal(Request $request, TransactionJournal $journal): array
|
||||
{
|
||||
$sourceAccounts = $journal->sourceAccountList();
|
||||
$destinationAccounts = $journal->destinationAccountList();
|
||||
$notes = '';
|
||||
/** @var Note $note */
|
||||
|
||||
$note = $this->repository->getNote($journal);
|
||||
if (null !== $note) {
|
||||
$notes = $note->text;
|
||||
}
|
||||
$array = [
|
||||
$sourceAccounts = $this->repository->getJournalSourceAccounts($journal);
|
||||
$destinationAccounts = $this->repository->getJournalDestinationAccounts($journal);
|
||||
$array = [
|
||||
'journal_description' => $request->old('journal_description', $journal->description),
|
||||
'journal_amount' => $journal->amountPositive(),
|
||||
'journal_amount' => $this->repository->getJournalTotal($journal),
|
||||
'sourceAccounts' => $sourceAccounts,
|
||||
'journal_source_account_id' => $request->old('journal_source_account_id', $sourceAccounts->first()->id),
|
||||
'journal_source_account_name' => $request->old('journal_source_account_name', $sourceAccounts->first()->name),
|
||||
'journal_destination_account_id' => $request->old('journal_destination_account_id', $destinationAccounts->first()->id),
|
||||
'destinationAccounts' => $destinationAccounts,
|
||||
'what' => strtolower($journal->transactionTypeStr()),
|
||||
'date' => $request->old('date', $journal->date->format('Y-m-d')),
|
||||
'what' => strtolower($this->repository->getTransactionType($journal)),
|
||||
'date' => $request->old('date', $this->repository->getJournalDate($journal, null)),
|
||||
'tags' => join(',', $journal->tags->pluck('tag')->toArray()),
|
||||
|
||||
// all custom fields:
|
||||
'interest_date' => $request->old('interest_date', $journal->getMeta('interest_date')),
|
||||
'book_date' => $request->old('book_date', $journal->getMeta('book_date')),
|
||||
'process_date' => $request->old('process_date', $journal->getMeta('process_date')),
|
||||
'due_date' => $request->old('due_date', $journal->getMeta('due_date')),
|
||||
'payment_date' => $request->old('payment_date', $journal->getMeta('payment_date')),
|
||||
'invoice_date' => $request->old('invoice_date', $journal->getMeta('invoice_date')),
|
||||
'internal_reference' => $request->old('internal_reference', $journal->getMeta('internal_reference')),
|
||||
'notes' => $request->old('notes', $notes),
|
||||
'interest_date' => $request->old('interest_date', $this->repository->getMetaField($journal, 'interest_date')),
|
||||
'book_date' => $request->old('book_date', $this->repository->getMetaField($journal, 'book_date')),
|
||||
'process_date' => $request->old('process_date', $this->repository->getMetaField($journal, 'process_date')),
|
||||
'due_date' => $request->old('due_date', $this->repository->getMetaField($journal, 'due_date')),
|
||||
'payment_date' => $request->old('payment_date', $this->repository->getMetaField($journal, 'payment_date')),
|
||||
'invoice_date' => $request->old('invoice_date', $this->repository->getMetaField($journal, 'invoice_date')),
|
||||
'internal_reference' => $request->old('internal_reference', $this->repository->getMetaField($journal, 'internal_reference')),
|
||||
'notes' => $request->old('notes', $this->repository->getNoteText($journal)),
|
||||
|
||||
// transactions.
|
||||
'transactions' => $this->getTransactionDataFromJournal($journal),
|
||||
@ -295,12 +245,14 @@ class SplitController extends Controller
|
||||
'foreign_currency_code' => $transaction['foreign_currency_code'],
|
||||
'foreign_currency_symbol' => $transaction['foreign_currency_symbol'],
|
||||
];
|
||||
|
||||
// set initial category and/or budget:
|
||||
if (1 === count($transactions) && 0 === $index) {
|
||||
$set['budget_id'] = $journal->budgetId();
|
||||
$set['category'] = $journal->categoryAsString();
|
||||
if ($set['budget_id'] === 0) {
|
||||
$set['budget_id'] = $this->repository->getJournalBudgetId($journal);
|
||||
}
|
||||
if (strlen($set['category']) === 0) {
|
||||
$set['category'] = $this->repository->getJournalCategoryName($journal);
|
||||
}
|
||||
|
||||
|
||||
$return[] = $set;
|
||||
}
|
||||
@ -308,35 +260,6 @@ class SplitController extends Controller
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SplitJournalFormRequest|Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTransactionDataFromRequest(SplitJournalFormRequest $request): array
|
||||
{
|
||||
$return = [];
|
||||
$transactions = $request->get('transactions');
|
||||
foreach ($transactions as $transaction) {
|
||||
$return[] = [
|
||||
'description' => $transaction['description'],
|
||||
'source_account_id' => $transaction['source_account_id'] ?? 0,
|
||||
'source_account_name' => $transaction['source_account_name'] ?? '',
|
||||
'destination_account_id' => $transaction['destination_account_id'] ?? 0,
|
||||
'destination_account_name' => $transaction['destination_account_name'] ?? '',
|
||||
'amount' => round($transaction['amount'] ?? 0, 12),
|
||||
'foreign_amount' => !isset($transaction['foreign_amount']) ? null : round($transaction['foreign_amount'] ?? 0, 12),
|
||||
'budget_id' => isset($transaction['budget_id']) ? intval($transaction['budget_id']) : 0,
|
||||
'category' => $transaction['category'] ?? '',
|
||||
'transaction_currency_id' => intval($transaction['transaction_currency_id']),
|
||||
'foreign_currency_id' => $transaction['foreign_currency_id'] ?? null,
|
||||
];
|
||||
}
|
||||
Log::debug(sprintf('Found %d splits in request data.', count($return)));
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $array
|
||||
* @param $old
|
||||
|
@ -44,6 +44,7 @@ use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
||||
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
use Laravel\Passport\Http\Middleware\CreateFreshApiToken;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
@ -84,7 +85,7 @@ class Kernel extends HttpKernel
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
//SubstituteBindings::class,
|
||||
CreateFreshApiToken::class,
|
||||
],
|
||||
|
||||
// MUST NOT be logged in. Does not care about 2FA or confirmation.
|
||||
@ -95,7 +96,6 @@ class Kernel extends HttpKernel
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
//SubstituteBindings::class,
|
||||
Binder::class,
|
||||
RedirectIfAuthenticated::class,
|
||||
],
|
||||
@ -109,7 +109,6 @@ class Kernel extends HttpKernel
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
//SubstituteBindings::class,
|
||||
Binder::class,
|
||||
Authenticate::class,
|
||||
RedirectIfTwoFactorAuthenticated::class,
|
||||
@ -125,7 +124,6 @@ class Kernel extends HttpKernel
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
//SubstituteBindings::class,
|
||||
Binder::class,
|
||||
Authenticate::class,
|
||||
],
|
||||
@ -141,11 +139,11 @@ class Kernel extends HttpKernel
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
//SubstituteBindings::class,
|
||||
Authenticate::class,
|
||||
AuthenticateTwoFactor::class,
|
||||
Range::class,
|
||||
Binder::class,
|
||||
CreateFreshApiToken::class,
|
||||
],
|
||||
// MUST be logged in
|
||||
// MUST have 2fa
|
||||
@ -159,12 +157,12 @@ class Kernel extends HttpKernel
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
//SubstituteBindings::class,
|
||||
Authenticate::class,
|
||||
AuthenticateTwoFactor::class,
|
||||
IsAdmin::class,
|
||||
Range::class,
|
||||
Binder::class,
|
||||
CreateFreshApiToken::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Authenticate.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
@ -18,50 +18,94 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Session;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Contracts\Auth\Factory as Auth;
|
||||
|
||||
/**
|
||||
* Class Authenticate.
|
||||
* Class Authenticate
|
||||
*/
|
||||
class Authenticate
|
||||
{
|
||||
/**
|
||||
* The authentication factory instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Factory
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* Create a new middleware instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Factory $auth
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Auth $auth)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string[] ...$guards
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Illuminate\Auth\AuthenticationException
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, $guard = null)
|
||||
public function handle($request, Closure $next, ...$guards)
|
||||
{
|
||||
if (Auth::guard($guard)->guest()) {
|
||||
if ($request->ajax()) {
|
||||
return response('Unauthorized.', 401);
|
||||
}
|
||||
|
||||
return redirect()->guest('login');
|
||||
}
|
||||
if (1 === intval(auth()->user()->blocked)) {
|
||||
$message = strval(trans('firefly.block_account_logout'));
|
||||
if ('email_changed' === auth()->user()->blocked_code) {
|
||||
$message = strval(trans('firefly.email_changed_logout'));
|
||||
}
|
||||
|
||||
Session::flash('logoutMessage', $message);
|
||||
Auth::guard($guard)->logout();
|
||||
|
||||
return redirect()->guest('login');
|
||||
}
|
||||
$this->authenticate($guards);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user is logged in to any of the given guards.
|
||||
*
|
||||
* @param array $guards
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Auth\AuthenticationException
|
||||
*/
|
||||
protected function authenticate(array $guards)
|
||||
{
|
||||
if (empty($guards)) {
|
||||
// go for default guard:
|
||||
if ($this->auth->check()) {
|
||||
// do an extra check on user object.
|
||||
$user = $this->auth->authenticate();
|
||||
if (1 === intval($user->blocked)) {
|
||||
$message = strval(trans('firefly.block_account_logout'));
|
||||
if ('email_changed' === $user->blocked_code) {
|
||||
$message = strval(trans('firefly.email_changed_logout'));
|
||||
}
|
||||
app('session')->flash('logoutMessage', $message);
|
||||
$this->auth->logout();
|
||||
|
||||
throw new AuthenticationException('Blocked account.', $guards);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->auth->authenticate();
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
foreach ($guards as $guard) {
|
||||
if ($this->auth->guard($guard)->check()) {
|
||||
return $this->auth->shouldUse($guard);
|
||||
}
|
||||
}
|
||||
|
||||
throw new AuthenticationException('Unauthenticated.', $guards);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
@ -23,34 +23,49 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Contracts\Auth\Factory as Auth;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Auth;
|
||||
use Session;
|
||||
|
||||
/**
|
||||
* Class AuthenticateTwoFactor.
|
||||
*/
|
||||
class AuthenticateTwoFactor
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
* The authentication factory instance.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
*
|
||||
* @return mixed
|
||||
* @var \Illuminate\Contracts\Auth\Factory
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, $guard = null)
|
||||
{
|
||||
if (Auth::guard($guard)->guest()) {
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* Create a new middleware instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Factory $auth
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Auth $auth)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $request
|
||||
* @param Closure $next
|
||||
* @param array ...$guards
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|mixed
|
||||
* @throws \Illuminate\Container\EntryNotFoundException
|
||||
*/
|
||||
public function handle($request, Closure $next, ...$guards)
|
||||
{
|
||||
if ($this->auth->guest()) {
|
||||
return redirect()->guest('login');
|
||||
}
|
||||
|
||||
$is2faEnabled = Preferences::get('twoFactorAuthEnabled', false)->data;
|
||||
$has2faSecret = null !== Preferences::get('twoFactorAuthSecret');
|
||||
$is2faEnabled = app('preferences')->get('twoFactorAuthEnabled', false)->data;
|
||||
$has2faSecret = null !== app('preferences')->get('twoFactorAuthSecret');
|
||||
$is2faAuthed = 'true' === $request->cookie('twoFactorAuthenticated');
|
||||
|
||||
if ($is2faEnabled && $has2faSecret && !$is2faAuthed) {
|
||||
@ -61,4 +76,5 @@ class AuthenticateTwoFactor
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Binder.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
@ -24,13 +24,20 @@ namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use FireflyIII\Support\Domain;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Contracts\Auth\Factory as Auth;
|
||||
use Illuminate\Routing\Route;
|
||||
|
||||
/**
|
||||
* Class Binder.
|
||||
* Class HttpBinder
|
||||
*/
|
||||
class Binder
|
||||
{
|
||||
/**
|
||||
* The authentication factory instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Factory
|
||||
*/
|
||||
protected $auth;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@ -38,21 +45,27 @@ class Binder
|
||||
|
||||
/**
|
||||
* Binder constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Factory $auth
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct(Auth $auth)
|
||||
{
|
||||
$this->binders = Domain::getBindables();
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string[] ...$guards
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Illuminate\Auth\AuthenticationException
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
public function handle($request, Closure $next, ...$guards)
|
||||
{
|
||||
foreach ($request->route()->parameters() as $key => $value) {
|
||||
if (isset($this->binders[$key])) {
|
||||
@ -71,7 +84,7 @@ class Binder
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function performBinding($key, $value, $route)
|
||||
private function performBinding(string $key, string $value, Route $route)
|
||||
{
|
||||
$class = $this->binders[$key];
|
||||
|
||||
|
@ -34,26 +34,28 @@ use Session;
|
||||
class IsDemoUser
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request. May not be a limited user (ie. Sandstorm env. or demo user).
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string[] ...$guards
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, $guard = null)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (Auth::guard($guard)->guest()) {
|
||||
// don't care when not logged in, usual stuff applies:
|
||||
/** @var User $user */
|
||||
$user = $request->user();
|
||||
if (is_null($user)) {
|
||||
return $next($request);
|
||||
}
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user->hasRole('demo')) {
|
||||
Session::flash('info', strval(trans('firefly.not_available_demo_user')));
|
||||
|
||||
return redirect($request->session()->previousUrl());
|
||||
redirect($request->session()->previousUrl());
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
@ -38,35 +38,17 @@ use View;
|
||||
*/
|
||||
class Range
|
||||
{
|
||||
/**
|
||||
* The Guard implementation.
|
||||
*
|
||||
* @var Guard
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* Create a new filter instance.
|
||||
*
|
||||
* @param Guard $auth
|
||||
*/
|
||||
public function __construct(Guard $auth)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param Closure $next
|
||||
* @param string|null $guard
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, $guard = null)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!Auth::guard($guard)->guest()) {
|
||||
if ($request->user()) {
|
||||
// set start, end and finish:
|
||||
$this->setRange();
|
||||
|
||||
|
@ -95,8 +95,9 @@ class Sandstorm
|
||||
/** @var User $user */
|
||||
$user = $repository->store(
|
||||
[
|
||||
'blocked' => false,
|
||||
'blocked_code' => null,
|
||||
'email' => $email,
|
||||
'password' => str_random(16),
|
||||
]
|
||||
);
|
||||
Auth::guard($guard)->login($user);
|
||||
|
@ -22,7 +22,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Rules\UniqueIban;
|
||||
|
||||
/**
|
||||
* Class AccountFormRequest.
|
||||
@ -47,6 +48,7 @@ class AccountFormRequest extends Request
|
||||
'name' => $this->string('name'),
|
||||
'active' => $this->boolean('active'),
|
||||
'accountType' => $this->string('what'),
|
||||
'account_type_id' => 0,
|
||||
'currency_id' => $this->integer('currency_id'),
|
||||
'virtualBalance' => $this->string('virtualBalance'),
|
||||
'iban' => $this->string('iban'),
|
||||
@ -66,25 +68,14 @@ class AccountFormRequest extends Request
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$accountRoles = join(',', config('firefly.accountRoles'));
|
||||
$types = join(',', array_keys(config('firefly.subTitlesByIdentifier')));
|
||||
$ccPaymentTypes = join(',', array_keys(config('firefly.ccTypes')));
|
||||
|
||||
$nameRule = 'required|min:1|uniqueAccountForUser';
|
||||
$idRule = '';
|
||||
if (null !== $repository->find(intval($this->get('id')))->id) {
|
||||
$idRule = 'belongsToUser:accounts';
|
||||
$nameRule = 'required|min:1|uniqueAccountForUser:' . intval($this->get('id'));
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $idRule,
|
||||
'name' => $nameRule,
|
||||
$rules = [
|
||||
'name' => 'required|min:1|uniqueAccountForUser',
|
||||
'openingBalance' => 'numeric|required_with:openingBalanceDate|nullable',
|
||||
'openingBalanceDate' => 'date|required_with:openingBalance|nullable',
|
||||
'iban' => 'iban|nullable',
|
||||
'iban' => ['iban', 'nullable', new UniqueIban(null)],
|
||||
'BIC' => 'bic|nullable',
|
||||
'virtualBalance' => 'numeric|nullable',
|
||||
'currency_id' => 'exists:transaction_currencies,id',
|
||||
@ -97,5 +88,16 @@ class AccountFormRequest extends Request
|
||||
'amount_currency_id_virtualBalance' => 'exists:transaction_currencies,id',
|
||||
'what' => 'in:' . $types,
|
||||
];
|
||||
|
||||
/** @var Account $account */
|
||||
$account = $this->route()->parameter('account');
|
||||
if (!is_null($account)) {
|
||||
// add rules:
|
||||
$rules['id'] = 'belongsToUser:accounts';
|
||||
$rules['name'] = 'required|min:1|uniqueAccountForUser:' . intval($this->get('id'));
|
||||
$rules['iban'] = ['iban', 'nullable', new UniqueIban($account)];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
@ -46,38 +46,91 @@ class JournalFormRequest extends Request
|
||||
*/
|
||||
public function getJournalData()
|
||||
{
|
||||
$data = [
|
||||
'what' => $this->get('what'), // type. can be 'deposit', 'withdrawal' or 'transfer'
|
||||
'date' => $this->date('date'),
|
||||
'tags' => explode(',', $this->string('tags')),
|
||||
'currency_id' => $this->integer('amount_currency_id_amount'),
|
||||
$currencyId = $this->integer('amount_currency_id_amount');
|
||||
$data = [
|
||||
'type' => $this->get('what'), // type. can be 'deposit', 'withdrawal' or 'transfer'
|
||||
'date' => $this->date('date'),
|
||||
'tags' => explode(',', $this->string('tags')),
|
||||
'user' => auth()->user()->id,
|
||||
|
||||
// all custom fields:
|
||||
'interest_date' => $this->date('interest_date'),
|
||||
'book_date' => $this->date('book_date'),
|
||||
'process_date' => $this->date('process_date'),
|
||||
'due_date' => $this->date('due_date'),
|
||||
'payment_date' => $this->date('payment_date'),
|
||||
'invoice_date' => $this->date('invoice_date'),
|
||||
'internal_reference' => $this->string('internal_reference'),
|
||||
'notes' => $this->string('notes'),
|
||||
'interest_date' => $this->date('interest_date'),
|
||||
'book_date' => $this->date('book_date'),
|
||||
'process_date' => $this->date('process_date'),
|
||||
'due_date' => $this->date('due_date'),
|
||||
'payment_date' => $this->date('payment_date'),
|
||||
'invoice_date' => $this->date('invoice_date'),
|
||||
'internal_reference' => $this->string('internal_reference'),
|
||||
'notes' => $this->string('notes'),
|
||||
|
||||
// transaction / journal data:
|
||||
'description' => $this->string('description'),
|
||||
'amount' => $this->string('amount'),
|
||||
'budget_id' => $this->integer('budget_id'),
|
||||
'category' => $this->string('category'),
|
||||
'source_account_id' => $this->integer('source_account_id'),
|
||||
'source_account_name' => $this->string('source_account_name'),
|
||||
'destination_account_id' => $this->string('destination_account_id'),
|
||||
'destination_account_name' => $this->string('destination_account_name'),
|
||||
'piggy_bank_id' => $this->integer('piggy_bank_id'),
|
||||
// journal data:
|
||||
'description' => $this->string('description'),
|
||||
'piggy_bank_id' => $this->integer('piggy_bank_id'),
|
||||
'piggy_bank_name' => null,
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
|
||||
// native amount and stuff like that:
|
||||
'native_amount' => $this->string('native_amount'),
|
||||
'source_amount' => $this->string('source_amount'),
|
||||
'destination_amount' => $this->string('destination_amount'),
|
||||
// transaction data:
|
||||
'transactions' => [
|
||||
[
|
||||
'currency_id' => null,
|
||||
'currency_code' => null,
|
||||
'description' => null,
|
||||
'amount' => $this->string('amount'),
|
||||
'budget_id' => $this->integer('budget_id'),
|
||||
'budget_name' => null,
|
||||
'category_id' => null,
|
||||
'category_name' => $this->string('category'),
|
||||
'source_id' => $this->integer('source_account_id'),
|
||||
'source_name' => $this->string('source_account_name'),
|
||||
'destination_id' => $this->integer('destination_account_id'),
|
||||
'destination_name' => $this->string('destination_account_name'),
|
||||
'foreign_currency_id' => null,
|
||||
'foreign_currency_code' => null,
|
||||
'foreign_amount' => null,
|
||||
'reconciled' => false,
|
||||
'identifier' => 0,
|
||||
],
|
||||
],
|
||||
];
|
||||
switch (strtolower($data['type'])) {
|
||||
case 'withdrawal':
|
||||
$sourceCurrency = $this->integer('source_account_currency');
|
||||
$data['transactions'][0]['currency_id'] = $sourceCurrency;
|
||||
$data['transactions'][0]['destination_id'] = null; // clear destination ID (transfer)
|
||||
if ($sourceCurrency !== $currencyId) {
|
||||
// user has selected a foreign currency.
|
||||
$data['transactions'][0]['foreign_currency_id'] = $currencyId;
|
||||
$data['transactions'][0]['foreign_amount'] = $this->string('amount');
|
||||
$data['transactions'][0]['amount'] = $this->string('native_amount');
|
||||
}
|
||||
|
||||
break;
|
||||
case 'deposit':
|
||||
$destinationCurrency = $this->integer('destination_account_currency');
|
||||
$data['transactions'][0]['currency_id'] = $destinationCurrency;
|
||||
$data['transactions'][0]['source_id'] = null; // clear destination ID (transfer)
|
||||
if ($destinationCurrency !== $currencyId) {
|
||||
// user has selected a foreign currency.
|
||||
$data['transactions'][0]['foreign_currency_id'] = $currencyId;
|
||||
$data['transactions'][0]['foreign_amount'] = $this->string('amount');
|
||||
$data['transactions'][0]['amount'] = $this->string('native_amount');
|
||||
}
|
||||
break;
|
||||
case 'transfer':
|
||||
// by default just assume source currency
|
||||
$sourceCurrency = $this->integer('source_account_currency');
|
||||
$destinationCurrency = $this->integer('destination_account_currency');
|
||||
$data['transactions'][0]['currency_id'] = $sourceCurrency;
|
||||
if ($sourceCurrency !== $destinationCurrency) {
|
||||
// user has selected a foreign currency.
|
||||
$data['transactions'][0]['foreign_currency_id'] = $destinationCurrency;
|
||||
$data['transactions'][0]['foreign_amount'] = $this->string('destination_amount');
|
||||
$data['transactions'][0]['amount'] = $this->string('source_amount');
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
@ -154,7 +207,7 @@ class JournalFormRequest extends Request
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new FireflyException('Cannot handle transaction type of type ' . e($what) . ' . ');
|
||||
throw new FireflyException(sprintf('Cannot handle transaction type of type "%s"', $what)); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return $rules;
|
||||
|
@ -44,12 +44,13 @@ class LinkTypeFormRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
// fixed
|
||||
|
||||
/** @var LinkTypeRepositoryInterface $repository */
|
||||
$repository = app(LinkTypeRepositoryInterface::class);
|
||||
$nameRule = 'required|min:1|unique:link_types,name';
|
||||
$idRule = '';
|
||||
if (null !== $repository->find($this->integer('id'))->id) {
|
||||
|
||||
// get parameter link:
|
||||
$link = $this->route()->parameter('linkType');
|
||||
|
||||
if (null !== $link) {
|
||||
$idRule = 'exists:link_types,id';
|
||||
$nameRule = 'required|min:1';
|
||||
}
|
||||
|
81
app/Http/Requests/ReconciliationStoreRequest.php
Normal file
81
app/Http/Requests/ReconciliationStoreRequest.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* ReconciliationStoreRequest.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use FireflyIII\Rules\ValidTransactions;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class ReconciliationStoreRequest
|
||||
*/
|
||||
class ReconciliationStoreRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow logged in users
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$transactions = $this->get('transactions');
|
||||
if (!is_array($transactions)) {
|
||||
$transactions = []; // @codeCoverageIgnore
|
||||
}
|
||||
$data = [
|
||||
'start' => $this->date('start'),
|
||||
'end' => $this->date('end'),
|
||||
'start_balance' => $this->string('startBalance'),
|
||||
'end_balance' => $this->string('endBalance'),
|
||||
'difference' => $this->string('difference'),
|
||||
'transactions' => $transactions,
|
||||
'reconcile' => $this->string('reconcile'),
|
||||
];
|
||||
Log::debug('In ReconciliationStoreRequest::getAll(). Will now return data.');
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'start' => 'required|date',
|
||||
'end' => 'required|date',
|
||||
'startBalance' => 'numeric',
|
||||
'endBalance' => 'numeric',
|
||||
'difference' => 'required|numeric',
|
||||
'transactions' => [new ValidTransactions],
|
||||
'reconcile' => 'required|in:create,nothing',
|
||||
];
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* ReconciliationFormRequest.php
|
||||
* ReconciliationUpdateRequest.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
@ -23,10 +23,9 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Class ReconciliationFormRequest.
|
||||
* Class ReconciliationUpdateRequest.
|
||||
*/
|
||||
class ReconciliationFormRequest extends Request
|
||||
class ReconciliationUpdateRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
@ -57,8 +57,8 @@ class ReportFormRequest extends Request
|
||||
$collection = new Collection;
|
||||
if (is_array($set)) {
|
||||
foreach ($set as $accountId) {
|
||||
$account = $repository->find(intval($accountId));
|
||||
if (null !== $account->id) {
|
||||
$account = $repository->findNull(intval($accountId));
|
||||
if (null !== $account) {
|
||||
$collection->push($account);
|
||||
}
|
||||
}
|
||||
@ -78,8 +78,8 @@ class ReportFormRequest extends Request
|
||||
$collection = new Collection;
|
||||
if (is_array($set)) {
|
||||
foreach ($set as $budgetId) {
|
||||
$budget = $repository->find(intval($budgetId));
|
||||
if (null !== $budget->id) {
|
||||
$budget = $repository->findNull(intval($budgetId));
|
||||
if (null !== $budget) {
|
||||
$collection->push($budget);
|
||||
}
|
||||
}
|
||||
@ -99,8 +99,8 @@ class ReportFormRequest extends Request
|
||||
$collection = new Collection;
|
||||
if (is_array($set)) {
|
||||
foreach ($set as $categoryId) {
|
||||
$category = $repository->find(intval($categoryId));
|
||||
if (null !== $category->id) {
|
||||
$category = $repository->findNull(intval($categoryId));
|
||||
if (null !== $category) {
|
||||
$collection->push($category);
|
||||
}
|
||||
}
|
||||
@ -122,9 +122,12 @@ class ReportFormRequest extends Request
|
||||
if (2 === count($parts)) {
|
||||
try {
|
||||
$date = new Carbon($parts[1]);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Exception $e) {
|
||||
throw new FireflyException(sprintf('"%s" is not a valid date range.', $range));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $date;
|
||||
@ -142,8 +145,8 @@ class ReportFormRequest extends Request
|
||||
$collection = new Collection;
|
||||
if (is_array($set)) {
|
||||
foreach ($set as $accountId) {
|
||||
$account = $repository->find(intval($accountId));
|
||||
if (null !== $account->id) {
|
||||
$account = $repository->findNull(intval($accountId));
|
||||
if (null !== $account) {
|
||||
$collection->push($account);
|
||||
}
|
||||
}
|
||||
@ -165,8 +168,10 @@ class ReportFormRequest extends Request
|
||||
if (2 === count($parts)) {
|
||||
try {
|
||||
$date = new Carbon($parts[0]);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Exception $e) {
|
||||
throw new FireflyException(sprintf('"%s" is not a valid date range.', $range));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,16 @@ class Request extends FormRequest
|
||||
return 1 === intval($this->input($field));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function integer(string $field): int
|
||||
{
|
||||
return intval($this->get($field));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
@ -110,41 +120,4 @@ class Request extends FormRequest
|
||||
{
|
||||
return $this->get($field) ? new Carbon($this->get($field)) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
protected function float(string $field): float
|
||||
{
|
||||
return round($this->input($field), 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param string $type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getArray(string $field, string $type): array
|
||||
{
|
||||
$original = $this->get($field);
|
||||
$return = [];
|
||||
foreach ($original as $index => $value) {
|
||||
$return[$index] = $this->$type($value);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function integer(string $field): int
|
||||
{
|
||||
return intval($this->get($field));
|
||||
}
|
||||
}
|
||||
|
@ -41,23 +41,63 @@ class SplitJournalFormRequest extends Request
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSplitData(): array
|
||||
public function getAll(): array
|
||||
{
|
||||
$data = [
|
||||
'id' => $this->integer('id'),
|
||||
'journal_description' => $this->string('journal_description'),
|
||||
'journal_currency_id' => $this->integer('journal_currency_id'),
|
||||
'journal_source_account_id' => $this->integer('journal_source_account_id'),
|
||||
'journal_source_account_name' => $this->string('journal_source_account_name'),
|
||||
'journal_destination_account_id' => $this->integer('journal_destination_account_id'),
|
||||
'journal_destination_account_name' => $this->string('journal_source_destination_name'),
|
||||
'date' => $this->date('date'),
|
||||
'what' => $this->string('what'),
|
||||
'interest_date' => $this->date('interest_date'),
|
||||
'book_date' => $this->date('book_date'),
|
||||
'process_date' => $this->date('process_date'),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
'description' => $this->string('description'),
|
||||
'type' => $this->string('what'),
|
||||
'date' => $this->date('date'),
|
||||
'tags' => explode(',', $this->string('tags')),
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
'piggy_bank_id' => null,
|
||||
'piggy_bank_name' => null,
|
||||
'notes' => $this->string('notes'),
|
||||
'transactions' => [],
|
||||
];
|
||||
// switch type to get correct source / destination info:
|
||||
$sourceId = null;
|
||||
$sourceName = null;
|
||||
$destinationId = null;
|
||||
$destinationName = null;
|
||||
|
||||
foreach ($this->get('transactions') as $index => $transaction) {
|
||||
switch ($data['type']) {
|
||||
case 'withdrawal':
|
||||
$sourceId = $this->integer('journal_source_account_id');
|
||||
$destinationName = $transaction['destination_account_name'];
|
||||
break;
|
||||
case 'deposit':
|
||||
$sourceName = $transaction['source_account_name'];
|
||||
$destinationId = $this->integer('journal_destination_account_id');
|
||||
break;
|
||||
case 'transfer':
|
||||
$sourceId = $this->integer('journal_source_account_id');
|
||||
$destinationId = $this->integer('journal_destination_account_id');
|
||||
break;
|
||||
}
|
||||
$foreignAmount = $transaction['foreign_amount'] ?? null;
|
||||
$set = [
|
||||
'source_id' => $sourceId,
|
||||
'source_name' => $sourceName,
|
||||
'destination_id' => $destinationId,
|
||||
'destination_name' => $destinationName,
|
||||
'foreign_amount' => $foreignAmount,
|
||||
'foreign_currency_id' => null,
|
||||
'foreign_currency_code' => null,
|
||||
'reconciled' => false,
|
||||
'identifier' => $index,
|
||||
'currency_id' => $this->integer('journal_currency_id'),
|
||||
'currency_code' => null,
|
||||
'description' => $transaction['description'],
|
||||
'amount' => $transaction['amount'],
|
||||
'budget_id' => intval($transaction['budget_id'] ?? 0),
|
||||
'budget_name' => null,
|
||||
'category_id' => null,
|
||||
'category_name' => $transaction['category'],
|
||||
];
|
||||
$data['transactions'][] = $set;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
@ -88,39 +128,4 @@ class SplitJournalFormRequest extends Request
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getTransactionData(): array
|
||||
{
|
||||
$descriptions = $this->getArray('description', 'string');
|
||||
$categories = $this->getArray('category', 'string');
|
||||
$amounts = $this->getArray('amount', 'float');
|
||||
$budgets = $this->getArray('amount', 'integer');
|
||||
$srcAccountIds = $this->getArray('source_account_id', 'integer');
|
||||
$srcAccountNames = $this->getArray('source_account_name', 'string');
|
||||
$dstAccountIds = $this->getArray('destination_account_id', 'integer');
|
||||
$dstAccountNames = $this->getArray('destination_account_name', 'string');
|
||||
$piggyBankIds = $this->getArray('piggy_bank_id', 'integer');
|
||||
|
||||
$return = [];
|
||||
// description is leading because it is one of the mandatory fields.
|
||||
foreach ($descriptions as $index => $description) {
|
||||
$category = $categories[$index] ?? '';
|
||||
$transaction = [
|
||||
'description' => $description,
|
||||
'amount' => Steam::positive($amounts[$index]),
|
||||
'budget_id' => $budgets[$index] ?? 0,
|
||||
'category' => $category,
|
||||
'source_account_id' => $srcAccountIds[$index] ?? $this->get('journal_source_account_id'),
|
||||
'source_account_name' => $srcAccountNames[$index] ?? '',
|
||||
'piggy_bank_id' => $piggyBankIds[$index] ?? 0,
|
||||
'destination_account_id' => $dstAccountIds[$index] ?? $this->get('journal_destination_account_id'),
|
||||
'destination_account_name' => $dstAccountNames[$index] ?? '',
|
||||
];
|
||||
$return[] = $transaction;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
@ -263,6 +263,7 @@ class FileConfigurator implements ConfiguratorInterface
|
||||
* Shorthand method to set the extended status.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param array $extended
|
||||
*/
|
||||
private function setExtendedStatus(array $extended): void
|
||||
|
@ -125,6 +125,7 @@ class CsvProcessor implements FileProcessorInterface
|
||||
* Shorthand method to set the extended status.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param array $array
|
||||
*/
|
||||
public function setExtendedStatus(array $array)
|
||||
|
@ -114,7 +114,7 @@ class ImportBill
|
||||
Log::debug(sprintf('Finding bill with ID #%d', $this->id['value']));
|
||||
/** @var Bill $bill */
|
||||
$bill = $this->repository->find(intval($this->id['value']));
|
||||
if (null !== $bill->id) {
|
||||
if (null !== $bill) {
|
||||
Log::debug(sprintf('Found unmapped bill by ID (#%d): %s', $bill->id, $bill->name));
|
||||
|
||||
return $bill;
|
||||
@ -199,7 +199,7 @@ class ImportBill
|
||||
$search = intval($array['mapped']);
|
||||
$bill = $this->repository->find($search);
|
||||
|
||||
if (null === $bill->id) {
|
||||
if (null === $bill) {
|
||||
Log::error(sprintf('There is no bill with id #%d. Invalid mapping will be ignored!', $search));
|
||||
|
||||
return new Bill;
|
||||
|
@ -67,9 +67,10 @@ class FilePrerequisites implements PrerequisitesInterface
|
||||
*/
|
||||
public function hasPrerequisites(): bool
|
||||
{
|
||||
if($this->user->hasRole('demo')) {
|
||||
if ($this->user->hasRole('demo')) {
|
||||
throw new FireflyException('Apologies, the demo user cannot import files.');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,6 @@ class FileRoutine implements RoutineInterface
|
||||
Log::debug('Back in run()');
|
||||
|
||||
|
||||
|
||||
Log::debug('Updated job...');
|
||||
Log::debug(sprintf('%d journals in $storage->journals', $storage->journals->count()));
|
||||
$this->journals = $storage->journals;
|
||||
@ -177,6 +176,16 @@ class FileRoutine implements RoutineInterface
|
||||
$this->repository->addStepsDone($this->job, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorthand
|
||||
*
|
||||
* @param int $steps
|
||||
*/
|
||||
private function addTotalSteps(int $steps)
|
||||
{
|
||||
$this->repository->addTotalSteps($this->job, $steps);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -194,7 +203,7 @@ class FileRoutine implements RoutineInterface
|
||||
/** @var TagRepositoryInterface $repository */
|
||||
$repository = app(TagRepositoryInterface::class);
|
||||
$repository->setUser($this->job->user);
|
||||
$data = [
|
||||
$data = [
|
||||
'tag' => trans('import.import_with_key', ['key' => $this->job->key]),
|
||||
'date' => new Carbon,
|
||||
'description' => null,
|
||||
@ -203,7 +212,7 @@ class FileRoutine implements RoutineInterface
|
||||
'zoomLevel' => null,
|
||||
'tagMode' => 'nothing',
|
||||
];
|
||||
$tag = $repository->store($data);
|
||||
$tag = $repository->store($data);
|
||||
$this->addStep();
|
||||
$extended = $this->getExtendedStatus();
|
||||
$extended['tag'] = $tag->id;
|
||||
@ -220,6 +229,7 @@ class FileRoutine implements RoutineInterface
|
||||
}
|
||||
Log::info(sprintf('Linked %d journals to tag #%d ("%s")', $this->journals->count(), $tag->id, $tag->tag));
|
||||
$this->addStep();
|
||||
|
||||
return $tag;
|
||||
}
|
||||
|
||||
@ -281,16 +291,6 @@ class FileRoutine implements RoutineInterface
|
||||
$this->repository->setTotalSteps($this->job, $steps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorthand
|
||||
*
|
||||
* @param int $steps
|
||||
*/
|
||||
private function addTotalSteps(int $steps)
|
||||
{
|
||||
$this->repository->addTotalSteps($this->job, $steps);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $objects
|
||||
*
|
||||
|
@ -308,8 +308,8 @@ class ImportStorage
|
||||
return false;
|
||||
}
|
||||
|
||||
$amount = app('steam')->positive($parameters['amount']);
|
||||
$names = [$parameters['asset'], $parameters['opposing']];
|
||||
$amount = app('steam')->positive($parameters['amount']);
|
||||
$names = [$parameters['asset'], $parameters['opposing']];
|
||||
|
||||
sort($names);
|
||||
|
||||
|
@ -241,53 +241,12 @@ class Account extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of the opening balance for this account.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @codeCoverageIgnore
|
||||
* Get all of the notes.
|
||||
*/
|
||||
public function getOpeningBalanceAmount(): string
|
||||
public function notes()
|
||||
{
|
||||
$journal = TransactionJournal::sortCorrectly()
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transactions.account_id', $this->id)
|
||||
->transactionTypes([TransactionType::OPENING_BALANCE])
|
||||
->first(['transaction_journals.*']);
|
||||
if (null === $journal) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
$count = $journal->transactions()->count();
|
||||
if (2 !== $count) {
|
||||
throw new FireflyException(sprintf('Cannot use getFirstTransaction on journal #%d', $journal->id));
|
||||
}
|
||||
$transaction = $journal->transactions()->where('account_id', $this->id)->first();
|
||||
if (null === $transaction) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
return strval($transaction->amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date of the opening balance for this account. If no date, will return 01-01-1900.
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getOpeningBalanceDate(): Carbon
|
||||
{
|
||||
$date = new Carbon('1900-01-01');
|
||||
$journal = TransactionJournal::sortCorrectly()
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transactions.account_id', $this->id)
|
||||
->transactionTypes([TransactionType::OPENING_BALANCE])
|
||||
->first(['transaction_journals.*']);
|
||||
if (null === $journal) {
|
||||
return $date;
|
||||
}
|
||||
|
||||
return $journal->date;
|
||||
return $this->morphMany(Note::class, 'noteable');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -345,15 +304,6 @@ class Account extends Model
|
||||
$this->attributes['iban'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Get all of the notes.
|
||||
*/
|
||||
public function notes()
|
||||
{
|
||||
return $this->morphMany(Note::class, 'noteable');
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
|
@ -43,8 +43,6 @@ class BudgetLimit extends Model
|
||||
'end_date' => 'date',
|
||||
'repeats' => 'boolean',
|
||||
];
|
||||
/** @var array */
|
||||
protected $dates = ['start_date', 'end_date'];
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
|
@ -29,7 +29,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
/**
|
||||
* Class ExportJob.
|
||||
*
|
||||
* @property User $user
|
||||
* @property User $user
|
||||
* @property string $key
|
||||
*/
|
||||
class ExportJob extends Model
|
||||
|
@ -65,7 +65,7 @@ class ImportJob extends Model
|
||||
* @throws NotFoundHttpException
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public static function routeBinder($value): ImportJob
|
||||
public static function routeBinder(string $value): ImportJob
|
||||
{
|
||||
if (auth()->check()) {
|
||||
$key = trim($value);
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
|
||||
/**
|
||||
* Class Note.
|
||||
@ -42,18 +41,7 @@ class Note extends Model
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
/** @var array */
|
||||
protected $fillable = ['title', 'text'];
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return string
|
||||
*/
|
||||
public function getMarkdownAttribute(): string
|
||||
{
|
||||
$converter = new CommonMarkConverter;
|
||||
|
||||
return $converter->convertToHtml($this->text);
|
||||
}
|
||||
protected $fillable = ['title', 'text', 'noteable_id', 'noteable_type'];
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
|
@ -56,7 +56,7 @@ class PiggyBank extends Model
|
||||
/** @var array */
|
||||
protected $dates = ['startdate', 'targetdate'];
|
||||
/** @var array */
|
||||
protected $fillable = ['name', 'account_id', 'order', 'targetamount', 'startdate', 'targetdate'];
|
||||
protected $fillable = ['name', 'account_id', 'order', 'targetamount', 'startdate', 'targetdate', 'active'];
|
||||
/** @var array */
|
||||
protected $hidden = ['targetamount_encrypted', 'encrypted'];
|
||||
|
||||
@ -90,7 +90,7 @@ class PiggyBank extends Model
|
||||
|
||||
/**
|
||||
* Grabs the PiggyBankRepetition that's currently relevant / active.
|
||||
*
|
||||
* @deprecated
|
||||
* @returns PiggyBankRepetition
|
||||
*/
|
||||
public function currentRelevantRep(): PiggyBankRepetition
|
||||
@ -126,6 +126,7 @@ class PiggyBank extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @return string
|
||||
*/
|
||||
public function getSuggestedMonthlyAmount(): string
|
||||
@ -152,7 +153,7 @@ class PiggyBank extends Model
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @deprecated
|
||||
* @return string
|
||||
*/
|
||||
public function leftOnAccount(Carbon $date): string
|
||||
|
@ -26,6 +26,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Class PiggyBankEvent.
|
||||
* @property $piggyBank
|
||||
*/
|
||||
class PiggyBankEvent extends Model
|
||||
{
|
||||
|
@ -103,24 +103,6 @@ class Tag extends Model
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
public static function tagSum(Tag $tag): string
|
||||
{
|
||||
$sum = '0';
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
bcadd($sum, $journal->amount());
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
|
@ -26,6 +26,7 @@ use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
/**
|
||||
@ -90,7 +91,7 @@ class Transaction extends Model
|
||||
*/
|
||||
protected $fillable
|
||||
= ['account_id', 'transaction_journal_id', 'description', 'amount', 'identifier', 'transaction_currency_id', 'foreign_currency_id',
|
||||
'foreign_amount',];
|
||||
'foreign_amount','reconciled'];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@ -130,6 +131,25 @@ class Transaction extends Model
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return Transaction
|
||||
*/
|
||||
public static function routeBinder(string $value): Transaction
|
||||
{
|
||||
if (auth()->check()) {
|
||||
$transactionId = intval($value);
|
||||
$transaction = auth()->user()->transactions()->where('transactions.id', $transactionId)
|
||||
->first(['transactions.*']);
|
||||
if (!is_null($transaction)) {
|
||||
return $transaction;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
|
||||
use SoftDeletes, ValidatingTrait;
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,7 @@ use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Models\TransactionJournalTrait;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
@ -38,6 +39,7 @@ use Watson\Validating\ValidatingTrait;
|
||||
|
||||
/**
|
||||
* Class TransactionJournal.
|
||||
* @property User $user
|
||||
*/
|
||||
class TransactionJournal extends Model
|
||||
{
|
||||
@ -62,8 +64,7 @@ class TransactionJournal extends Model
|
||||
'encrypted' => 'boolean',
|
||||
'completed' => 'boolean',
|
||||
];
|
||||
/** @var array */
|
||||
protected $dates = ['date', 'interest_date', 'book_date', 'process_date'];
|
||||
|
||||
/** @var array */
|
||||
protected $fillable
|
||||
= ['user_id', 'transaction_type_id', 'bill_id', 'interest_date', 'book_date', 'process_date',
|
||||
|
@ -72,7 +72,7 @@ class TransactionType extends Model
|
||||
*
|
||||
* @return Model|null|static
|
||||
*/
|
||||
public static function routeBinder(string $type)
|
||||
public static function routeBinder(string $type): TransactionType
|
||||
{
|
||||
if (!auth()->check()) {
|
||||
throw new NotFoundHttpException();
|
||||
|
@ -24,6 +24,7 @@ namespace FireflyIII\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
@ -44,5 +45,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
Passport::ignoreMigrations();
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
@ -46,5 +47,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||
public function boot()
|
||||
{
|
||||
$this->registerPolicies();
|
||||
Passport::routes();
|
||||
Passport::tokensExpireIn(now()->addDays(14));
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,6 @@ class EventServiceProvider extends ServiceProvider
|
||||
// is a Transaction Journal related event.
|
||||
'FireflyIII\Events\StoredTransactionJournal' => [
|
||||
'FireflyIII\Handlers\Events\StoredJournalEventHandler@scanBills',
|
||||
'FireflyIII\Handlers\Events\StoredJournalEventHandler@connectToPiggyBank',
|
||||
'FireflyIII\Handlers\Events\StoredJournalEventHandler@processRules',
|
||||
],
|
||||
// is a Transaction Journal related event.
|
||||
@ -122,39 +121,6 @@ class EventServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected function registerDeleteEvents()
|
||||
{
|
||||
Account::deleted(
|
||||
function (Account $account) {
|
||||
Log::debug('Now trigger account delete response #' . $account->id);
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($account->transactions()->get() as $transaction) {
|
||||
Log::debug('Now at transaction #' . $transaction->id);
|
||||
$journal = $transaction->transactionJournal()->first();
|
||||
if (null !== $journal) {
|
||||
Log::debug('Call for deletion of journal #' . $journal->id);
|
||||
$journal->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
TransactionJournal::deleted(
|
||||
function (TransactionJournal $journal) {
|
||||
Log::debug(sprintf('Now triggered journal delete response #%d', $journal->id));
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions()->get() as $transaction) {
|
||||
Log::debug(sprintf('Will now delete transaction #%d', $transaction->id));
|
||||
$transaction->delete();
|
||||
}
|
||||
|
||||
// also delete journal_meta entries.
|
||||
|
||||
/** @var TransactionJournalMeta $meta */
|
||||
foreach ($journal->transactionJournalMeta()->get() as $meta) {
|
||||
Log::debug(sprintf('Will now delete meta-entry #%d', $meta->id));
|
||||
$meta->delete();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ use FireflyIII\Helpers\Report\PopupReport;
|
||||
use FireflyIII\Helpers\Report\PopupReportInterface;
|
||||
use FireflyIII\Helpers\Report\ReportHelper;
|
||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
||||
use FireflyIII\Repositories\TransactionType\TransactionTypeRepository;
|
||||
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepository;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Services\Password\PwndVerifier;
|
||||
@ -162,6 +164,7 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
// export:
|
||||
$this->app->bind(ProcessorInterface::class, ExpandedProcessor::class);
|
||||
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
|
||||
$this->app->bind(TransactionTypeRepositoryInterface::class, TransactionTypeRepository::class);
|
||||
$this->app->bind(AttachmentHelperInterface::class, AttachmentHelper::class);
|
||||
|
||||
// more generators:
|
||||
|
@ -38,7 +38,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = 'FireflyIII\Http\Controllers';
|
||||
protected $namespace = '';
|
||||
|
||||
/**
|
||||
* Define your route model bindings, pattern filters, etc.
|
||||
@ -65,8 +65,8 @@ class RouteServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected function mapApiRoutes()
|
||||
{
|
||||
Route::prefix('api')
|
||||
->middleware('api')
|
||||
Route::prefix('api/v1')
|
||||
->middleware('auth:api')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/api.php'));
|
||||
}
|
||||
|
@ -23,37 +23,29 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Account;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\AccountFactory;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
|
||||
use FireflyIII\Services\Internal\Update\AccountUpdateService;
|
||||
use FireflyIII\Services\Internal\Update\JournalUpdateService;
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* Class AccountRepository.
|
||||
*/
|
||||
class AccountRepository implements AccountRepositoryInterface
|
||||
{
|
||||
use FindAccountsTrait;
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
use FindAccountsTrait;
|
||||
/** @var array */
|
||||
private $validFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType', 'accountNumber', 'currency_id', 'BIC'];
|
||||
|
||||
/**
|
||||
* Moved here from account CRUD.
|
||||
*
|
||||
* @param array $types
|
||||
*
|
||||
* @return int
|
||||
@ -69,24 +61,31 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
* Moved here from account CRUD.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Account $moveTo
|
||||
* @param Account|null $moveTo
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function destroy(Account $account, Account $moveTo): bool
|
||||
public function destroy(Account $account, ?Account $moveTo): bool
|
||||
{
|
||||
if (null !== $moveTo->id) {
|
||||
DB::table('transactions')->where('account_id', $account->id)->update(['account_id' => $moveTo->id]);
|
||||
}
|
||||
if (null !== $account) {
|
||||
$account->delete();
|
||||
}
|
||||
/** @var AccountDestroyService $service */
|
||||
$service = app(AccountDestroyService::class);
|
||||
$service->destroy($account, $moveTo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $accountId
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findNull(int $accountId): ?Account
|
||||
{
|
||||
return $this->user->accounts()->find($accountId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return account type by string.
|
||||
*
|
||||
@ -109,6 +108,51 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
return $account->notes()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of the opening balance for this account.
|
||||
*
|
||||
* @param Account $account
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOpeningBalanceAmount(Account $account): ?string
|
||||
{
|
||||
|
||||
$journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transactions.account_id', $account->id)
|
||||
->transactionTypes([TransactionType::OPENING_BALANCE])
|
||||
->first(['transaction_journals.*']);
|
||||
if (null === $journal) {
|
||||
return null;
|
||||
}
|
||||
$transaction = $journal->transactions()->where('account_id', $account->id)->first();
|
||||
if (null === $transaction) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return strval($transaction->amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return date of opening balance as string or null.
|
||||
*
|
||||
* @param Account $account
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getOpeningBalanceDate(Account $account): ?string
|
||||
{
|
||||
$journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transactions.account_id', $account->id)
|
||||
->transactionTypes([TransactionType::OPENING_BALANCE])
|
||||
->first(['transaction_journals.*']);
|
||||
if (null === $journal) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $journal->date->format('Y-m-d');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date of the very last transaction in this account.
|
||||
*
|
||||
@ -184,54 +228,32 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return Account
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function store(array $data): Account
|
||||
{
|
||||
$newAccount = $this->storeAccount($data);
|
||||
$this->updateMetadata($newAccount, $data);
|
||||
/** @var AccountFactory $factory */
|
||||
$factory = app(AccountFactory::class);
|
||||
$factory->setUser($this->user);
|
||||
$account = $factory->create($data);
|
||||
|
||||
if ($this->validOpeningBalanceData($data)) {
|
||||
$this->updateInitialBalance($newAccount, $data);
|
||||
|
||||
return $newAccount;
|
||||
}
|
||||
$this->deleteInitialBalance($newAccount);
|
||||
|
||||
// update note:
|
||||
if (isset($data['notes'])) {
|
||||
$this->updateNote($newAccount, $data['notes']);
|
||||
}
|
||||
|
||||
return $newAccount;
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $data
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @throws Exception
|
||||
* @return Account
|
||||
*/
|
||||
public function update(Account $account, array $data): Account
|
||||
{
|
||||
// update the account:
|
||||
$account->name = $data['name'];
|
||||
$account->active = $data['active'];
|
||||
$account->virtual_balance = trim($data['virtualBalance']) === '' ? '0' : $data['virtualBalance'];
|
||||
$account->iban = $data['iban'];
|
||||
$account->save();
|
||||
|
||||
$this->updateMetadata($account, $data);
|
||||
if ($this->validOpeningBalanceData($data)) {
|
||||
$this->updateInitialBalance($account, $data);
|
||||
}
|
||||
|
||||
// update note:
|
||||
if (isset($data['notes']) && null !== $data['notes']) {
|
||||
$this->updateNote($account, strval($data['notes']));
|
||||
}
|
||||
|
||||
/** @var AccountUpdateService $service */
|
||||
$service = app(AccountUpdateService::class);
|
||||
$account = $service->update($account, $data);
|
||||
|
||||
return $account;
|
||||
}
|
||||
@ -241,465 +263,16 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionJournal
|
||||
* @throws FireflyException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updateReconciliation(TransactionJournal $journal, array $data): TransactionJournal
|
||||
{
|
||||
// update journal
|
||||
// update actual journal:
|
||||
$data['amount'] = strval($data['amount']);
|
||||
|
||||
// unlink all categories, recreate them:
|
||||
$journal->categories()->detach();
|
||||
|
||||
$this->storeCategoryWithJournal($journal, strval($data['category']));
|
||||
|
||||
// update amounts
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions as $transaction) {
|
||||
$transaction->amount = bcmul($data['amount'], '-1');
|
||||
if (AccountType::ASSET === $transaction->account->accountType->type) {
|
||||
$transaction->amount = $data['amount'];
|
||||
}
|
||||
$transaction->save();
|
||||
}
|
||||
|
||||
$journal->save();
|
||||
|
||||
// update tags:
|
||||
if (isset($data['tags']) && is_array($data['tags'])) {
|
||||
$this->updateTags($journal, $data['tags']);
|
||||
}
|
||||
/** @var JournalUpdateService $service */
|
||||
$service = app(JournalUpdateService::class);
|
||||
$journal = $service->update($journal, $data);
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function deleteInitialBalance(Account $account)
|
||||
{
|
||||
$journal = $this->openingBalanceTransaction($account);
|
||||
if (null !== $journal->id) {
|
||||
$journal->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return TransactionJournal|null
|
||||
*/
|
||||
protected function openingBalanceTransaction(Account $account): TransactionJournal
|
||||
{
|
||||
$journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transactions.account_id', $account->id)
|
||||
->transactionTypes([TransactionType::OPENING_BALANCE])
|
||||
->first(['transaction_journals.*']);
|
||||
if (null === $journal) {
|
||||
Log::debug('Could not find a opening balance journal, return empty one.');
|
||||
|
||||
return new TransactionJournal;
|
||||
}
|
||||
Log::debug(sprintf('Found opening balance: journal #%d.', $journal->id));
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Account
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
protected function storeAccount(array $data): Account
|
||||
{
|
||||
$data['accountType'] = $data['accountType'] ?? 'invalid';
|
||||
$type = config('firefly.accountTypeByIdentifier.' . $data['accountType']);
|
||||
$accountType = AccountType::whereType($type)->first();
|
||||
$data['iban'] = $this->filterIban($data['iban']);
|
||||
// verify account type
|
||||
if (null === $accountType) {
|
||||
throw new FireflyException(sprintf('Account type "%s" is invalid. Cannot create account.', $data['accountType']));
|
||||
}
|
||||
|
||||
// account may exist already:
|
||||
$existingAccount = $this->findByName($data['name'], [$type]);
|
||||
if (null !== $existingAccount->id) {
|
||||
Log::warning(sprintf('There already is an account named "%s" of type "%s".', $data['name'], $type));
|
||||
|
||||
return $existingAccount;
|
||||
}
|
||||
|
||||
// create it:
|
||||
$databaseData
|
||||
= [
|
||||
'user_id' => $this->user->id,
|
||||
'account_type_id' => $accountType->id,
|
||||
'name' => $data['name'],
|
||||
'virtual_balance' => strlen(strval($data['virtualBalance'])) === 0 ? '0' : $data['virtualBalance'],
|
||||
'active' => true === $data['active'] ? true : false,
|
||||
'iban' => $data['iban'],
|
||||
];
|
||||
$newAccount = new Account($databaseData);
|
||||
Log::debug('Final account creation dataset', $databaseData);
|
||||
$newAccount->save();
|
||||
// verify its creation:
|
||||
if (null === $newAccount->id) {
|
||||
Log::error(
|
||||
sprintf('Could not create account "%s" (%d error(s))', $data['name'], $newAccount->getErrors()->count()),
|
||||
$newAccount->getErrors()->toArray()
|
||||
);
|
||||
throw new FireflyException(sprintf('Tried to create account named "%s" but failed. The logs have more details.', $data['name']));
|
||||
}
|
||||
Log::debug(sprintf('Created new account #%d named "%s" of type %s.', $newAccount->id, $newAccount->name, $accountType->type));
|
||||
|
||||
return $newAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param string $category
|
||||
*/
|
||||
protected function storeCategoryWithJournal(TransactionJournal $journal, string $category)
|
||||
{
|
||||
if (strlen($category) > 0) {
|
||||
$category = Category::firstOrCreateEncrypted(['name' => $category, 'user_id' => $journal->user_id]);
|
||||
$journal->categories()->save($category);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* At this point strlen of amount > 0.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionJournal
|
||||
*/
|
||||
protected function storeInitialBalance(Account $account, array $data): TransactionJournal
|
||||
{
|
||||
$amount = strval($data['openingBalance']);
|
||||
Log::debug(sprintf('Submitted amount is %s', $amount));
|
||||
|
||||
if (0 === bccomp($amount, '0')) {
|
||||
return new TransactionJournal;
|
||||
}
|
||||
|
||||
$name = $data['name'];
|
||||
$currencyId = $data['currency_id'];
|
||||
$opposing = $this->storeOpposingAccount($name);
|
||||
$transactionType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = TransactionJournal::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'transaction_type_id' => $transactionType->id,
|
||||
'transaction_currency_id' => $currencyId,
|
||||
'description' => strval(trans('firefly.initial_balance_description', ['account' => $account->name])),
|
||||
'completed' => true,
|
||||
'date' => $data['openingBalanceDate'],
|
||||
]
|
||||
);
|
||||
Log::notice(sprintf('Created new opening balance journal: #%d', $journal->id));
|
||||
|
||||
$firstAccount = $account;
|
||||
$secondAccount = $opposing;
|
||||
$firstAmount = $amount;
|
||||
$secondAmount = bcmul($amount, '-1');
|
||||
Log::notice(sprintf('First amount is %s, second amount is %s', $firstAmount, $secondAmount));
|
||||
|
||||
if (bccomp($amount, '0') === -1) {
|
||||
Log::debug(sprintf('%s is a negative number.', $amount));
|
||||
$firstAccount = $opposing;
|
||||
$secondAccount = $account;
|
||||
$firstAmount = bcmul($amount, '-1');
|
||||
$secondAmount = $amount;
|
||||
Log::notice(sprintf('First amount is %s, second amount is %s', $firstAmount, $secondAmount));
|
||||
}
|
||||
|
||||
$one = new Transaction(
|
||||
[
|
||||
'account_id' => $firstAccount->id,
|
||||
'transaction_journal_id' => $journal->id,
|
||||
'amount' => $firstAmount,
|
||||
'transaction_currency_id' => $currencyId,
|
||||
]
|
||||
);
|
||||
$one->save(); // first transaction: from
|
||||
|
||||
$two = new Transaction(
|
||||
[
|
||||
'account_id' => $secondAccount->id,
|
||||
'transaction_journal_id' => $journal->id,
|
||||
'amount' => $secondAmount,
|
||||
'transaction_currency_id' => $currencyId,]
|
||||
);
|
||||
$two->save(); // second transaction: to
|
||||
|
||||
Log::notice(sprintf('Stored two transactions for new account, #%d and #%d', $one->id, $two->id));
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return Account
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
protected function storeOpposingAccount(string $name): Account
|
||||
{
|
||||
$opposingData = [
|
||||
'accountType' => 'initial',
|
||||
'name' => $name . ' initial balance',
|
||||
'active' => false,
|
||||
'iban' => '',
|
||||
'virtualBalance' => '0',
|
||||
];
|
||||
Log::debug('Going to create an opening balance opposing account.');
|
||||
|
||||
return $this->storeAccount($opposingData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function updateInitialBalance(Account $account, array $data): bool
|
||||
{
|
||||
Log::debug(sprintf('updateInitialBalance() for account #%d', $account->id));
|
||||
$openingBalance = $this->openingBalanceTransaction($account);
|
||||
|
||||
// no opening balance journal? create it:
|
||||
if (null === $openingBalance->id) {
|
||||
Log::debug('No opening balance journal yet, create journal.');
|
||||
$this->storeInitialBalance($account, $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
// opening balance data? update it!
|
||||
if (null !== $openingBalance->id) {
|
||||
Log::debug('Opening balance journal found, update journal.');
|
||||
$this->updateOpeningBalanceJournal($account, $openingBalance, $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $data
|
||||
*/
|
||||
protected function updateMetadata(Account $account, array $data)
|
||||
{
|
||||
foreach ($this->validFields as $field) {
|
||||
/** @var AccountMeta $entry */
|
||||
$entry = $account->accountMeta()->where('name', $field)->first();
|
||||
|
||||
// if $data has field and $entry is null, create new one:
|
||||
if (isset($data[$field]) && null === $entry) {
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Created meta-field "%s":"%s" for account #%d ("%s") ',
|
||||
$field,
|
||||
$data[$field],
|
||||
$account->id,
|
||||
$account->name
|
||||
)
|
||||
);
|
||||
AccountMeta::create(
|
||||
[
|
||||
'account_id' => $account->id,
|
||||
'name' => $field,
|
||||
'data' => $data[$field],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// if $data has field and $entry is not null, update $entry:
|
||||
if (isset($data[$field]) && null !== $entry) {
|
||||
$entry->data = $data[$field];
|
||||
$entry->save();
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Updated meta-field "%s":"%s" for account #%d ("%s") ',
|
||||
$field,
|
||||
$data[$field],
|
||||
$account->id,
|
||||
$account->name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param string $note
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function updateNote(Account $account, string $note): bool
|
||||
{
|
||||
if (0 === strlen($note)) {
|
||||
$dbNote = $account->notes()->first();
|
||||
if (null !== $dbNote) {
|
||||
$dbNote->delete();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
$dbNote = $account->notes()->first();
|
||||
if (null === $dbNote) {
|
||||
$dbNote = new Note();
|
||||
$dbNote->noteable()->associate($account);
|
||||
}
|
||||
$dbNote->text = trim($note);
|
||||
$dbNote->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function updateOpeningBalanceJournal(Account $account, TransactionJournal $journal, array $data): bool
|
||||
{
|
||||
$date = $data['openingBalanceDate'];
|
||||
$amount = strval($data['openingBalance']);
|
||||
$negativeAmount = bcmul($amount, '-1');
|
||||
$currencyId = intval($data['currency_id']);
|
||||
|
||||
Log::debug(sprintf('Submitted amount for opening balance to update is "%s"', $amount));
|
||||
|
||||
if (0 === bccomp($amount, '0')) {
|
||||
Log::notice(sprintf('Amount "%s" is zero, delete opening balance.', $amount));
|
||||
$journal->delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// update date:
|
||||
$journal->date = $date;
|
||||
$journal->transaction_currency_id = $currencyId;
|
||||
$journal->save();
|
||||
|
||||
// update transactions:
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions()->get() as $transaction) {
|
||||
if (intval($account->id) === intval($transaction->account_id)) {
|
||||
Log::debug(sprintf('Will (eq) change transaction #%d amount from "%s" to "%s"', $transaction->id, $transaction->amount, $amount));
|
||||
$transaction->amount = $amount;
|
||||
$transaction->transaction_currency_id = $currencyId;
|
||||
$transaction->save();
|
||||
}
|
||||
if (!(intval($account->id) === intval($transaction->account_id))) {
|
||||
Log::debug(sprintf('Will (neq) change transaction #%d amount from "%s" to "%s"', $transaction->id, $transaction->amount, $negativeAmount));
|
||||
$transaction->amount = $negativeAmount;
|
||||
$transaction->transaction_currency_id = $currencyId;
|
||||
$transaction->save();
|
||||
}
|
||||
}
|
||||
Log::debug('Updated opening balance journal.');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function updateTags(TransactionJournal $journal, array $array): bool
|
||||
{
|
||||
// create tag repository
|
||||
/** @var TagRepositoryInterface $tagRepository */
|
||||
$tagRepository = app(TagRepositoryInterface::class);
|
||||
|
||||
// find or create all tags:
|
||||
$tags = [];
|
||||
$ids = [];
|
||||
foreach ($array as $name) {
|
||||
if (strlen(trim($name)) > 0) {
|
||||
$tag = Tag::firstOrCreateEncrypted(['tag' => $name, 'user_id' => $journal->user_id]);
|
||||
$tags[] = $tag;
|
||||
$ids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
|
||||
// delete all tags connected to journal not in this array:
|
||||
if (count($ids) > 0) {
|
||||
DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->whereNotIn('tag_id', $ids)->delete();
|
||||
}
|
||||
// if count is zero, delete them all:
|
||||
if (0 === count($ids)) {
|
||||
DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->delete();
|
||||
}
|
||||
|
||||
// connect each tag to journal (if not yet connected):
|
||||
/** @var Tag $tag */
|
||||
foreach ($tags as $tag) {
|
||||
Log::debug(sprintf('Will try to connect tag #%d to journal #%d.', $tag->id, $journal->id));
|
||||
$tagRepository->connect($journal, $tag);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function validOpeningBalanceData(array $data): bool
|
||||
{
|
||||
$data['openingBalance'] = strval($data['openingBalance'] ?? '');
|
||||
if (isset($data['openingBalance']) && null !== $data['openingBalance'] && strlen($data['openingBalance']) > 0
|
||||
&& isset($data['openingBalanceDate'])) {
|
||||
Log::debug('Array has valid opening balance data.');
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug('Array does not have valid opening balance data.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $iban
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function filterIban(?string $iban)
|
||||
{
|
||||
if (null === $iban) {
|
||||
return null;
|
||||
}
|
||||
$data = ['iban' => $iban];
|
||||
$rules = ['iban' => 'required|iban'];
|
||||
$validator = Validator::make($data, $rules);
|
||||
if ($validator->fails()) {
|
||||
Log::error(sprintf('Detected invalid IBAN ("%s"). Return NULL instead.', $iban));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return $iban;
|
||||
}
|
||||
}
|
||||
|
@ -48,15 +48,16 @@ interface AccountRepositoryInterface
|
||||
* Moved here from account CRUD.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Account $moveTo
|
||||
* @param Account|null $moveTo
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Account $account, Account $moveTo): bool;
|
||||
public function destroy(Account $account, ?Account $moveTo): bool;
|
||||
|
||||
/**
|
||||
* @param int $accountId
|
||||
*
|
||||
* @deprecated
|
||||
* @return Account
|
||||
*/
|
||||
public function find(int $accountId): Account;
|
||||
@ -81,9 +82,16 @@ interface AccountRepositoryInterface
|
||||
* @param string $name
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findByName(string $name, array $types): Account;
|
||||
public function findByName(string $name, array $types): ?Account;
|
||||
|
||||
/**
|
||||
* @param int $accountId
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findNull(int $accountId): ?Account;
|
||||
|
||||
/**
|
||||
* Return account type by string.
|
||||
@ -127,6 +135,25 @@ interface AccountRepositoryInterface
|
||||
*/
|
||||
public function getNote(Account $account): ?Note;
|
||||
|
||||
/**
|
||||
* Returns the amount of the opening balance for this account.
|
||||
*
|
||||
* @param Account $account
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOpeningBalanceAmount(Account $account): ?string;
|
||||
|
||||
|
||||
/**
|
||||
* Return date of opening balance as string or null.
|
||||
*
|
||||
* @param Account $account
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getOpeningBalanceDate(Account $account): ?string;
|
||||
|
||||
/**
|
||||
* Find or create the opposing reconciliation account.
|
||||
*
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Account;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\AccountFactory;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\User;
|
||||
@ -44,6 +45,7 @@ trait FindAccountsTrait
|
||||
*/
|
||||
public function find(int $accountId): Account
|
||||
{
|
||||
/** @var Account $account */
|
||||
$account = $this->user->accounts()->find($accountId);
|
||||
if (null === $account) {
|
||||
return new Account;
|
||||
@ -56,6 +58,7 @@ trait FindAccountsTrait
|
||||
* @param string $number
|
||||
* @param array $types
|
||||
*
|
||||
* @deprecated
|
||||
* @return Account
|
||||
*/
|
||||
public function findByAccountNumber(string $number, array $types): Account
|
||||
@ -83,6 +86,7 @@ trait FindAccountsTrait
|
||||
* @param string $iban
|
||||
* @param array $types
|
||||
*
|
||||
* @deprecated
|
||||
* @return Account
|
||||
*/
|
||||
public function findByIban(string $iban, array $types): Account
|
||||
@ -109,9 +113,9 @@ trait FindAccountsTrait
|
||||
* @param string $name
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findByName(string $name, array $types): Account
|
||||
public function findByName(string $name, array $types): ?Account
|
||||
{
|
||||
$query = $this->user->accounts();
|
||||
|
||||
@ -132,7 +136,7 @@ trait FindAccountsTrait
|
||||
}
|
||||
Log::debug(sprintf('There is no account with name "%s" or types', $name), $types);
|
||||
|
||||
return new Account;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -213,15 +217,15 @@ trait FindAccountsTrait
|
||||
* @return Account
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getCashAccount(): Account
|
||||
{
|
||||
$type = AccountType::where('type', AccountType::CASH)->first();
|
||||
$account = Account::firstOrCreateEncrypted(
|
||||
['user_id' => $this->user->id, 'account_type_id' => $type->id, 'name' => 'Cash account']
|
||||
);
|
||||
$account->active = true;
|
||||
$account->save();
|
||||
$type = AccountType::where('type', AccountType::CASH)->first();
|
||||
/** @var AccountFactory $factory */
|
||||
$factory = app(AccountFactory::class);
|
||||
$factory->setUser($this->user);
|
||||
$account = $factory->findOrCreate('Cash account', $type->type);
|
||||
|
||||
return $account;
|
||||
}
|
||||
@ -232,6 +236,7 @@ trait FindAccountsTrait
|
||||
* @return Account|null
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getReconciliation(Account $account): ?Account
|
||||
{
|
||||
@ -247,23 +252,12 @@ trait FindAccountsTrait
|
||||
return $account;
|
||||
}
|
||||
}
|
||||
// assume nothing was found. create it!
|
||||
$data = [
|
||||
'accountType' => 'reconcile',
|
||||
'name' => $name,
|
||||
'iban' => null,
|
||||
'virtualBalance' => '0',
|
||||
'active' => true,
|
||||
];
|
||||
$account = $this->storeAccount($data);
|
||||
/** @var AccountFactory $factory */
|
||||
$factory = app(AccountFactory::class);
|
||||
$factory->setUser($account->user);
|
||||
$account = $factory->findOrCreate($name, $type->type);
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Account
|
||||
*/
|
||||
abstract protected function storeAccount(array $data): Account;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user