mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-17 17:57:09 +00:00
Merge branch 'release/4.7.5.2'
This commit is contained in:
9
.sandstorm/Vagrantfile
vendored
9
.sandstorm/Vagrantfile
vendored
@@ -9,9 +9,16 @@ VM_NAME = File.basename(File.dirname(File.dirname(__FILE__))) + "_sandstorm_#{Ti
|
||||
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
|
||||
# ugly hack to prevent hashicorp's bitrot. See https://github.com/hashicorp/vagrant/issues/9442
|
||||
# this setting is required for pre-2.0 vagrant, but causes an error as of 2.0.3,
|
||||
# remove entirely when confident nobody uses vagrant 1.x for anything.
|
||||
unless Vagrant::DEFAULT_SERVER_URL.frozen?
|
||||
Vagrant::DEFAULT_SERVER_URL.replace('https://vagrantcloud.com')
|
||||
end
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
# Base on the Sandstorm snapshots of the official Debian 8 (jessie) box.
|
||||
config.vm.box = "sandstorm/debian-jessie64"
|
||||
config.vm.box = "debian/contrib-jessie64"
|
||||
|
||||
if Vagrant.has_plugin?("vagrant-vbguest") then
|
||||
# vagrant-vbguest is a Vagrant plugin that upgrades
|
||||
|
@@ -1,3 +1,17 @@
|
||||
# 4.7.5.2
|
||||
- [Issue 1527](https://github.com/firefly-iii/firefly-iii/issues/1527), fixed views for transactions without a budget.
|
||||
- [Issue 1553](https://github.com/firefly-iii/firefly-iii/issues/1553), report could not handle transactions before the first one in the system.
|
||||
- [Issue 1549](https://github.com/firefly-iii/firefly-iii/issues/1549) update a budget will also update any rules that refer to that budget.
|
||||
- [Issue 1530](https://github.com/firefly-iii/firefly-iii/issues/1530), fix issue with bill chart.
|
||||
- [Issue 1563](https://github.com/firefly-iii/firefly-iii/issues/1563), fix piggy bank suggested amount
|
||||
- [Issue 1571](https://github.com/firefly-iii/firefly-iii/issues/1571), fix OAuth in Sandstorm
|
||||
- [Issue 1568](https://github.com/firefly-iii/firefly-iii/issues/1568), bug in Sandstorm user code.
|
||||
- [Issue 1569](https://github.com/firefly-iii/firefly-iii/issues/1569), optimized Sandstorm build by [ocdtrekkie](https://github.com/ocdtrekkie)
|
||||
- Fixed a bug where transfers would be stored inversely when using the CSV import.
|
||||
- Retired the "Rabobank description"-fix, because it is no longer necessary.
|
||||
- Fixed a bug where users could not delete budget limits in the API.
|
||||
- Piggy bank notes are visible again.
|
||||
|
||||
# 4.7.5.1
|
||||
- [Issue 1531](https://github.com/firefly-iii/firefly-iii/issues/1531), the database routine incorrectly reports empty categories.
|
||||
- [Issue 1532](https://github.com/firefly-iii/firefly-iii/issues/1532), broken dropdown for autosuggest things.
|
||||
|
@@ -9,6 +9,10 @@ CURL_OPTS="--silent --show-error"
|
||||
echo localhost > /etc/hostname
|
||||
hostname localhost
|
||||
|
||||
# Install curl that is needed below.
|
||||
apt-get update
|
||||
apt-get install -y curl
|
||||
|
||||
# The following line copies stderr through stderr to cat without accidentally leaving it in the
|
||||
# output file. Be careful when changing. See: https://github.com/sandstorm-io/vagrant-spk/pull/159
|
||||
curl $CURL_OPTS https://install.sandstorm.io/ 2>&1 > /host-dot-sandstorm/caches/install.sh | cat
|
||||
|
@@ -209,13 +209,6 @@ opt/app/.env.sandstorm
|
||||
opt/app/.gitattributes
|
||||
opt/app/.htaccess
|
||||
opt/app/.sandstorm/.gitattributes
|
||||
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/action_provision
|
||||
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name
|
||||
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/creator_uid
|
||||
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/id
|
||||
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid
|
||||
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/private_key
|
||||
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/synced_folders
|
||||
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/vagrant_cwd
|
||||
opt/app/.sandstorm/Vagrantfile
|
||||
opt/app/.sandstorm/app-graphics/firefly-iii-128.png
|
||||
@@ -242,15 +235,41 @@ 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/AttachmentController.php
|
||||
opt/app/app/Api/V1/Controllers/AvailableBudgetController.php
|
||||
opt/app/app/Api/V1/Controllers/BillController.php
|
||||
opt/app/app/Api/V1/Controllers/BudgetController.php
|
||||
opt/app/app/Api/V1/Controllers/BudgetLimitController.php
|
||||
opt/app/app/Api/V1/Controllers/CategoryController.php
|
||||
opt/app/app/Api/V1/Controllers/ConfigurationController.php
|
||||
opt/app/app/Api/V1/Controllers/Controller.php
|
||||
opt/app/app/Api/V1/Controllers/CurrencyController.php
|
||||
opt/app/app/Api/V1/Controllers/CurrencyExchangeRateController.php
|
||||
opt/app/app/Api/V1/Controllers/JournalLinkController.php
|
||||
opt/app/app/Api/V1/Controllers/LinkTypeController.php
|
||||
opt/app/app/Api/V1/Controllers/PiggyBankController.php
|
||||
opt/app/app/Api/V1/Controllers/PreferenceController.php
|
||||
opt/app/app/Api/V1/Controllers/RecurrenceController.php
|
||||
opt/app/app/Api/V1/Controllers/RuleController.php
|
||||
opt/app/app/Api/V1/Controllers/RuleGroupController.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/AttachmentRequest.php
|
||||
opt/app/app/Api/V1/Requests/AvailableBudgetRequest.php
|
||||
opt/app/app/Api/V1/Requests/BillRequest.php
|
||||
opt/app/app/Api/V1/Requests/BudgetLimitRequest.php
|
||||
opt/app/app/Api/V1/Requests/BudgetRequest.php
|
||||
opt/app/app/Api/V1/Requests/CategoryRequest.php
|
||||
opt/app/app/Api/V1/Requests/CurrencyRequest.php
|
||||
opt/app/app/Api/V1/Requests/JournalLinkRequest.php
|
||||
opt/app/app/Api/V1/Requests/LinkTypeRequest.php
|
||||
opt/app/app/Api/V1/Requests/PiggyBankRequest.php
|
||||
opt/app/app/Api/V1/Requests/PreferenceRequest.php
|
||||
opt/app/app/Api/V1/Requests/RecurrenceRequest.php
|
||||
opt/app/app/Api/V1/Requests/Request.php
|
||||
opt/app/app/Api/V1/Requests/RuleGroupRequest.php
|
||||
opt/app/app/Api/V1/Requests/RuleRequest.php
|
||||
opt/app/app/Api/V1/Requests/TransactionRequest.php
|
||||
opt/app/app/Api/V1/Requests/UserRequest.php
|
||||
opt/app/app/Console/Commands/CreateExport.php
|
||||
@@ -269,6 +288,7 @@ opt/app/app/Events/AdminRequestedTestMessage.php
|
||||
opt/app/app/Events/Event.php
|
||||
opt/app/app/Events/RegisteredUser.php
|
||||
opt/app/app/Events/RequestedNewPassword.php
|
||||
opt/app/app/Events/RequestedReportOnJournals.php
|
||||
opt/app/app/Events/RequestedVersionCheckStatus.php
|
||||
opt/app/app/Events/StoredTransactionJournal.php
|
||||
opt/app/app/Events/UpdatedTransactionJournal.php
|
||||
@@ -289,11 +309,13 @@ 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/AttachmentFactory.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/RecurrenceFactory.php
|
||||
opt/app/app/Factory/TagFactory.php
|
||||
opt/app/app/Factory/TransactionCurrencyFactory.php
|
||||
opt/app/app/Factory/TransactionFactory.php
|
||||
@@ -325,6 +347,7 @@ opt/app/app/Generator/Report/Tag/MultiYearReportGenerator.php
|
||||
opt/app/app/Generator/Report/Tag/YearReportGenerator.php
|
||||
opt/app/app/Handlers/Events/APIEventHandler.php
|
||||
opt/app/app/Handlers/Events/AdminEventHandler.php
|
||||
opt/app/app/Handlers/Events/AutomationHandler.php
|
||||
opt/app/app/Handlers/Events/StoredJournalEventHandler.php
|
||||
opt/app/app/Handlers/Events/UpdatedJournalEventHandler.php
|
||||
opt/app/app/Handlers/Events/UserEventHandler.php
|
||||
@@ -365,8 +388,13 @@ opt/app/app/Helpers/Report/PopupReport.php
|
||||
opt/app/app/Helpers/Report/PopupReportInterface.php
|
||||
opt/app/app/Helpers/Report/ReportHelper.php
|
||||
opt/app/app/Helpers/Report/ReportHelperInterface.php
|
||||
opt/app/app/Helpers/Update/UpdateTrait.php
|
||||
opt/app/app/Http/Controllers/Account/CreateController.php
|
||||
opt/app/app/Http/Controllers/Account/DeleteController.php
|
||||
opt/app/app/Http/Controllers/Account/EditController.php
|
||||
opt/app/app/Http/Controllers/Account/IndexController.php
|
||||
opt/app/app/Http/Controllers/Account/ReconcileController.php
|
||||
opt/app/app/Http/Controllers/AccountController.php
|
||||
opt/app/app/Http/Controllers/Account/ShowController.php
|
||||
opt/app/app/Http/Controllers/Admin/ConfigurationController.php
|
||||
opt/app/app/Http/Controllers/Admin/HomeController.php
|
||||
opt/app/app/Http/Controllers/Admin/LinkController.php
|
||||
@@ -379,7 +407,14 @@ opt/app/app/Http/Controllers/Auth/RegisterController.php
|
||||
opt/app/app/Http/Controllers/Auth/ResetPasswordController.php
|
||||
opt/app/app/Http/Controllers/Auth/TwoFactorController.php
|
||||
opt/app/app/Http/Controllers/BillController.php
|
||||
opt/app/app/Http/Controllers/BudgetController.php
|
||||
opt/app/app/Http/Controllers/Budget/AmountController.php
|
||||
opt/app/app/Http/Controllers/Budget/CreateController.php
|
||||
opt/app/app/Http/Controllers/Budget/DeleteController.php
|
||||
opt/app/app/Http/Controllers/Budget/EditController.php
|
||||
opt/app/app/Http/Controllers/Budget/IndexController.php
|
||||
opt/app/app/Http/Controllers/Budget/ShowController.php
|
||||
opt/app/app/Http/Controllers/Category/NoCategoryController.php
|
||||
opt/app/app/Http/Controllers/Category/ShowController.php
|
||||
opt/app/app/Http/Controllers/CategoryController.php
|
||||
opt/app/app/Http/Controllers/Chart/AccountController.php
|
||||
opt/app/app/Http/Controllers/Chart/BillController.php
|
||||
@@ -407,12 +442,18 @@ opt/app/app/Http/Controllers/Json/BoxController.php
|
||||
opt/app/app/Http/Controllers/Json/ExchangeController.php
|
||||
opt/app/app/Http/Controllers/Json/FrontpageController.php
|
||||
opt/app/app/Http/Controllers/Json/IntroController.php
|
||||
opt/app/app/Http/Controllers/Json/ReconcileController.php
|
||||
opt/app/app/Http/Controllers/Json/RecurrenceController.php
|
||||
opt/app/app/Http/Controllers/JsonController.php
|
||||
opt/app/app/Http/Controllers/NewUserController.php
|
||||
opt/app/app/Http/Controllers/PiggyBankController.php
|
||||
opt/app/app/Http/Controllers/Popup/ReportController.php
|
||||
opt/app/app/Http/Controllers/PreferencesController.php
|
||||
opt/app/app/Http/Controllers/ProfileController.php
|
||||
opt/app/app/Http/Controllers/Recurring/CreateController.php
|
||||
opt/app/app/Http/Controllers/Recurring/DeleteController.php
|
||||
opt/app/app/Http/Controllers/Recurring/EditController.php
|
||||
opt/app/app/Http/Controllers/Recurring/IndexController.php
|
||||
opt/app/app/Http/Controllers/Report/AccountController.php
|
||||
opt/app/app/Http/Controllers/Report/BalanceController.php
|
||||
opt/app/app/Http/Controllers/Report/BudgetController.php
|
||||
@@ -420,7 +461,11 @@ opt/app/app/Http/Controllers/Report/CategoryController.php
|
||||
opt/app/app/Http/Controllers/Report/ExpenseController.php
|
||||
opt/app/app/Http/Controllers/Report/OperationsController.php
|
||||
opt/app/app/Http/Controllers/ReportController.php
|
||||
opt/app/app/Http/Controllers/RuleController.php
|
||||
opt/app/app/Http/Controllers/Rule/CreateController.php
|
||||
opt/app/app/Http/Controllers/Rule/DeleteController.php
|
||||
opt/app/app/Http/Controllers/Rule/EditController.php
|
||||
opt/app/app/Http/Controllers/Rule/IndexController.php
|
||||
opt/app/app/Http/Controllers/Rule/SelectController.php
|
||||
opt/app/app/Http/Controllers/RuleGroupController.php
|
||||
opt/app/app/Http/Controllers/SearchController.php
|
||||
opt/app/app/Http/Controllers/System/InstallController.php
|
||||
@@ -471,6 +516,7 @@ opt/app/app/Http/Requests/PiggyBankFormRequest.php
|
||||
opt/app/app/Http/Requests/ProfileFormRequest.php
|
||||
opt/app/app/Http/Requests/ReconciliationStoreRequest.php
|
||||
opt/app/app/Http/Requests/ReconciliationUpdateRequest.php
|
||||
opt/app/app/Http/Requests/RecurrenceFormRequest.php
|
||||
opt/app/app/Http/Requests/ReportFormRequest.php
|
||||
opt/app/app/Http/Requests/Request.php
|
||||
opt/app/app/Http/Requests/RuleFormRequest.php
|
||||
@@ -482,8 +528,6 @@ opt/app/app/Http/Requests/TestRuleFormRequest.php
|
||||
opt/app/app/Http/Requests/TokenFormRequest.php
|
||||
opt/app/app/Http/Requests/UserFormRequest.php
|
||||
opt/app/app/Http/Requests/UserRegistrationRequest.php
|
||||
opt/app/app/Import/Configuration/BunqConfigurator.php
|
||||
opt/app/app/Import/Configuration/ConfiguratorInterface.php
|
||||
opt/app/app/Import/Converter/Amount.php
|
||||
opt/app/app/Import/Converter/AmountCredit.php
|
||||
opt/app/app/Import/Converter/AmountDebit.php
|
||||
@@ -508,12 +552,6 @@ opt/app/app/Import/Mapper/TransactionCurrencies.php
|
||||
opt/app/app/Import/MapperPreProcess/PreProcessorInterface.php
|
||||
opt/app/app/Import/MapperPreProcess/TagsComma.php
|
||||
opt/app/app/Import/MapperPreProcess/TagsSpace.php
|
||||
opt/app/app/Import/Object/ImportAccount.php
|
||||
opt/app/app/Import/Object/ImportBill.php
|
||||
opt/app/app/Import/Object/ImportBudget.php
|
||||
opt/app/app/Import/Object/ImportCategory.php
|
||||
opt/app/app/Import/Object/ImportCurrency.php
|
||||
opt/app/app/Import/Object/ImportJournal.php
|
||||
opt/app/app/Import/Prerequisites/BunqPrerequisites.php
|
||||
opt/app/app/Import/Prerequisites/FakePrerequisites.php
|
||||
opt/app/app/Import/Prerequisites/FilePrerequisites.php
|
||||
@@ -531,6 +569,7 @@ opt/app/app/Import/Specifics/RabobankDescription.php
|
||||
opt/app/app/Import/Specifics/SnsDescription.php
|
||||
opt/app/app/Import/Specifics/SpecificInterface.php
|
||||
opt/app/app/Import/Storage/ImportArrayStorage.php
|
||||
opt/app/app/Jobs/CreateRecurringTransactions.php
|
||||
opt/app/app/Jobs/ExecuteRuleGroupOnExistingTransactions.php
|
||||
opt/app/app/Jobs/ExecuteRuleOnExistingTransactions.php
|
||||
opt/app/app/Jobs/Job.php
|
||||
@@ -540,6 +579,7 @@ opt/app/app/Mail/AdminTestMail.php
|
||||
opt/app/app/Mail/ConfirmEmailChangeMail.php
|
||||
opt/app/app/Mail/OAuthTokenCreatedMail.php
|
||||
opt/app/app/Mail/RegisteredUser.php
|
||||
opt/app/app/Mail/ReportNewJournalsMail.php
|
||||
opt/app/app/Mail/RequestedNewPassword.php
|
||||
opt/app/app/Mail/UndoEmailChangeMail.php
|
||||
opt/app/app/Models/Account.php
|
||||
@@ -561,6 +601,11 @@ opt/app/app/Models/PiggyBank.php
|
||||
opt/app/app/Models/PiggyBankEvent.php
|
||||
opt/app/app/Models/PiggyBankRepetition.php
|
||||
opt/app/app/Models/Preference.php
|
||||
opt/app/app/Models/Recurrence.php
|
||||
opt/app/app/Models/RecurrenceMeta.php
|
||||
opt/app/app/Models/RecurrenceRepetition.php
|
||||
opt/app/app/Models/RecurrenceTransaction.php
|
||||
opt/app/app/Models/RecurrenceTransactionMeta.php
|
||||
opt/app/app/Models/Role.php
|
||||
opt/app/app/Models/Rule.php
|
||||
opt/app/app/Models/RuleAction.php
|
||||
@@ -588,8 +633,8 @@ opt/app/app/Providers/ExportJobServiceProvider.php
|
||||
opt/app/app/Providers/FireflyServiceProvider.php
|
||||
opt/app/app/Providers/FireflySessionProvider.php
|
||||
opt/app/app/Providers/JournalServiceProvider.php
|
||||
opt/app/app/Providers/LogServiceProvider.php
|
||||
opt/app/app/Providers/PiggyBankServiceProvider.php
|
||||
opt/app/app/Providers/RecurringServiceProvider.php
|
||||
opt/app/app/Providers/RouteServiceProvider.php
|
||||
opt/app/app/Providers/RuleGroupServiceProvider.php
|
||||
opt/app/app/Providers/RuleServiceProvider.php
|
||||
@@ -600,7 +645,6 @@ opt/app/app/Repositories/Account/AccountRepository.php
|
||||
opt/app/app/Repositories/Account/AccountRepositoryInterface.php
|
||||
opt/app/app/Repositories/Account/AccountTasker.php
|
||||
opt/app/app/Repositories/Account/AccountTaskerInterface.php
|
||||
opt/app/app/Repositories/Account/FindAccountsTrait.php
|
||||
opt/app/app/Repositories/Attachment/AttachmentRepository.php
|
||||
opt/app/app/Repositories/Attachment/AttachmentRepositoryInterface.php
|
||||
opt/app/app/Repositories/Bill/BillRepository.php
|
||||
@@ -621,18 +665,22 @@ opt/app/app/Repositories/LinkType/LinkTypeRepository.php
|
||||
opt/app/app/Repositories/LinkType/LinkTypeRepositoryInterface.php
|
||||
opt/app/app/Repositories/PiggyBank/PiggyBankRepository.php
|
||||
opt/app/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php
|
||||
opt/app/app/Repositories/Recurring/RecurringRepository.php
|
||||
opt/app/app/Repositories/Recurring/RecurringRepositoryInterface.php
|
||||
opt/app/app/Repositories/Rule/RuleRepository.php
|
||||
opt/app/app/Repositories/Rule/RuleRepositoryInterface.php
|
||||
opt/app/app/Repositories/RuleGroup/RuleGroupRepository.php
|
||||
opt/app/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php
|
||||
opt/app/app/Repositories/Tag/TagRepository.php
|
||||
opt/app/app/Repositories/Tag/TagRepositoryInterface.php
|
||||
opt/app/app/Repositories/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/IsAssetAccountId.php
|
||||
opt/app/app/Rules/IsValidAttachmentModel.php
|
||||
opt/app/app/Rules/UniqueIban.php
|
||||
opt/app/app/Rules/ValidRecurrenceRepetitionType.php
|
||||
opt/app/app/Rules/ValidRecurrenceRepetitionValue.php
|
||||
opt/app/app/Rules/ValidTransactions.php
|
||||
opt/app/app/Services/Bunq/ApiContext.php
|
||||
opt/app/app/Services/Bunq/MonetaryAccount.php
|
||||
@@ -650,16 +698,20 @@ opt/app/app/Services/Internal/Destroy/BillDestroyService.php
|
||||
opt/app/app/Services/Internal/Destroy/CategoryDestroyService.php
|
||||
opt/app/app/Services/Internal/Destroy/CurrencyDestroyService.php
|
||||
opt/app/app/Services/Internal/Destroy/JournalDestroyService.php
|
||||
opt/app/app/Services/Internal/Destroy/RecurrenceDestroyService.php
|
||||
opt/app/app/Services/Internal/File/EncryptService.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/RecurringTransactionTrait.php
|
||||
opt/app/app/Services/Internal/Support/TransactionServiceTrait.php
|
||||
opt/app/app/Services/Internal/Support/TransactionTypeTrait.php
|
||||
opt/app/app/Services/Internal/Update/AccountUpdateService.php
|
||||
opt/app/app/Services/Internal/Update/BillUpdateService.php
|
||||
opt/app/app/Services/Internal/Update/CategoryUpdateService.php
|
||||
opt/app/app/Services/Internal/Update/CurrencyUpdateService.php
|
||||
opt/app/app/Services/Internal/Update/JournalUpdateService.php
|
||||
opt/app/app/Services/Internal/Update/RecurrenceUpdateService.php
|
||||
opt/app/app/Services/Internal/Update/TransactionUpdateService.php
|
||||
opt/app/app/Services/Password/PwndVerifierV2.php
|
||||
opt/app/app/Services/Password/Verifier.php
|
||||
@@ -705,6 +757,8 @@ opt/app/app/Support/Facades/Navigation.php
|
||||
opt/app/app/Support/Facades/Preferences.php
|
||||
opt/app/app/Support/Facades/Steam.php
|
||||
opt/app/app/Support/FireflyConfig.php
|
||||
opt/app/app/Support/Http/Controllers/DateCalculation.php
|
||||
opt/app/app/Support/Http/Controllers/RuleManagement.php
|
||||
opt/app/app/Support/Import/Information/BunqInformation.php
|
||||
opt/app/app/Support/Import/Information/GetSpectreCustomerTrait.php
|
||||
opt/app/app/Support/Import/Information/GetSpectreTokenTrait.php
|
||||
@@ -759,7 +813,6 @@ opt/app/app/Support/Twig/Journal.php
|
||||
opt/app/app/Support/Twig/Loader/AccountLoader.php
|
||||
opt/app/app/Support/Twig/Loader/TransactionJournalLoader.php
|
||||
opt/app/app/Support/Twig/Loader/TransactionLoader.php
|
||||
opt/app/app/Support/Twig/PiggyBank.php
|
||||
opt/app/app/Support/Twig/Rule.php
|
||||
opt/app/app/Support/Twig/Transaction.php
|
||||
opt/app/app/Support/Twig/Translation.php
|
||||
@@ -823,18 +876,32 @@ 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/AvailableBudgetTransformer.php
|
||||
opt/app/app/Transformers/BillTransformer.php
|
||||
opt/app/app/Transformers/BudgetLimitTransformer.php
|
||||
opt/app/app/Transformers/BudgetTransformer.php
|
||||
opt/app/app/Transformers/CategoryTransformer.php
|
||||
opt/app/app/Transformers/CurrencyExchangeRateTransformer.php
|
||||
opt/app/app/Transformers/CurrencyTransformer.php
|
||||
opt/app/app/Transformers/JournalLinkTransformer.php
|
||||
opt/app/app/Transformers/JournalMetaTransformer.php
|
||||
opt/app/app/Transformers/LinkTypeTransformer.php
|
||||
opt/app/app/Transformers/NoteTransformer.php
|
||||
opt/app/app/Transformers/PiggyBankEventTransformer.php
|
||||
opt/app/app/Transformers/PiggyBankTransformer.php
|
||||
opt/app/app/Transformers/PreferenceTransformer.php
|
||||
opt/app/app/Transformers/RecurrenceTransformer.php
|
||||
opt/app/app/Transformers/RuleActionTransformer.php
|
||||
opt/app/app/Transformers/RuleGroupTransformer.php
|
||||
opt/app/app/Transformers/RuleTransformer.php
|
||||
opt/app/app/Transformers/RuleTriggerTransformer.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/app/Validation/RecurrenceValidation.php
|
||||
opt/app/app/Validation/TransactionValidation.php
|
||||
opt/app/artisan
|
||||
opt/app/bootstrap/app.php
|
||||
opt/app/bootstrap/cache/packages.php
|
||||
@@ -842,7 +909,6 @@ opt/app/bootstrap/cache/services.php
|
||||
opt/app/changelog.md
|
||||
opt/app/composer.json
|
||||
opt/app/composer.lock
|
||||
opt/app/composer.phar
|
||||
opt/app/config/app.php
|
||||
opt/app/config/auth.php
|
||||
opt/app/config/breadcrumbs.php
|
||||
@@ -887,6 +953,7 @@ opt/app/database/migrations/2018_01_01_000005_create_oauth_personal_access_clien
|
||||
opt/app/database/migrations/2018_03_19_141348_changes_for_v472.php
|
||||
opt/app/database/migrations/2018_04_07_210913_changes_for_v473.php
|
||||
opt/app/database/migrations/2018_04_29_174524_changes_for_v474.php
|
||||
opt/app/database/migrations/2018_06_08_200526_changes_for_v475.php
|
||||
opt/app/database/seeds/AccountTypeSeeder.php
|
||||
opt/app/database/seeds/ConfigSeeder.php
|
||||
opt/app/database/seeds/DatabaseSeeder.php
|
||||
@@ -1105,6 +1172,8 @@ opt/app/public/js/ff/piggy-banks/edit.js
|
||||
opt/app/public/js/ff/piggy-banks/index.js
|
||||
opt/app/public/js/ff/piggy-banks/show.js
|
||||
opt/app/public/js/ff/preferences/index.js
|
||||
opt/app/public/js/ff/recurring/create.js
|
||||
opt/app/public/js/ff/recurring/edit.js
|
||||
opt/app/public/js/ff/reports/account/month.js
|
||||
opt/app/public/js/ff/reports/all.js
|
||||
opt/app/public/js/ff/reports/audit/all.js
|
||||
@@ -1153,6 +1222,12 @@ 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/fc/fullcalendar.css
|
||||
opt/app/public/lib/fc/fullcalendar.js
|
||||
opt/app/public/lib/fc/fullcalendar.min.css
|
||||
opt/app/public/lib/fc/fullcalendar.min.js
|
||||
opt/app/public/lib/fc/fullcalendar.print.css
|
||||
opt/app/public/lib/fc/fullcalendar.print.min.css
|
||||
opt/app/public/lib/intro/intro.min.js
|
||||
opt/app/public/lib/intro/introjs-rtl.min.css
|
||||
opt/app/public/lib/intro/introjs.min.css
|
||||
@@ -1419,6 +1494,8 @@ opt/app/resources/views/demo/import/index.twig
|
||||
opt/app/resources/views/demo/index.twig
|
||||
opt/app/resources/views/demo/no-demo-text.twig
|
||||
opt/app/resources/views/demo/piggy-banks/index.twig
|
||||
opt/app/resources/views/demo/recurring/index.twig
|
||||
opt/app/resources/views/demo/recurring/recurring-create.twig
|
||||
opt/app/resources/views/demo/reports/index.twig
|
||||
opt/app/resources/views/demo/transactions/index.twig
|
||||
opt/app/resources/views/emails/access-token-created-html.twig
|
||||
@@ -1441,6 +1518,8 @@ opt/app/resources/views/emails/password-html.twig
|
||||
opt/app/resources/views/emails/password-text.twig
|
||||
opt/app/resources/views/emails/registered-html.twig
|
||||
opt/app/resources/views/emails/registered-text.twig
|
||||
opt/app/resources/views/emails/report-new-journals-html.twig
|
||||
opt/app/resources/views/emails/report-new-journals-text.twig
|
||||
opt/app/resources/views/emails/undo-email-change-html.twig
|
||||
opt/app/resources/views/emails/undo-email-change-text.twig
|
||||
opt/app/resources/views/error.twig
|
||||
@@ -1538,6 +1617,11 @@ opt/app/resources/views/profile/change-password.twig
|
||||
opt/app/resources/views/profile/code.twig
|
||||
opt/app/resources/views/profile/delete-account.twig
|
||||
opt/app/resources/views/profile/index.twig
|
||||
opt/app/resources/views/recurring/create.twig
|
||||
opt/app/resources/views/recurring/delete.twig
|
||||
opt/app/resources/views/recurring/edit.twig
|
||||
opt/app/resources/views/recurring/index.twig
|
||||
opt/app/resources/views/recurring/show.twig
|
||||
opt/app/resources/views/reports/account/report.twig
|
||||
opt/app/resources/views/reports/audit/report.twig
|
||||
opt/app/resources/views/reports/budget/month.twig
|
||||
@@ -2060,30 +2144,6 @@ 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
|
||||
opt/app/vendor/doctrine/annotations/composer.json
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attribute.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attributes.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Required.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/FileCacheReader.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PhpParser.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Reader.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php
|
||||
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php
|
||||
opt/app/vendor/doctrine/annotations/phpstan.neon
|
||||
opt/app/vendor/doctrine/cache/LICENSE
|
||||
opt/app/vendor/doctrine/cache/README.md
|
||||
opt/app/vendor/doctrine/cache/UPGRADE.md
|
||||
@@ -2118,89 +2178,11 @@ opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/VoidCache.php
|
||||
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/WinCacheCache.php
|
||||
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/XcacheCache.php
|
||||
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ZendDataCache.php
|
||||
opt/app/vendor/doctrine/collections/CONTRIBUTING.md
|
||||
opt/app/vendor/doctrine/collections/LICENSE
|
||||
opt/app/vendor/doctrine/collections/README.md
|
||||
opt/app/vendor/doctrine/collections/composer.json
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php
|
||||
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php
|
||||
opt/app/vendor/doctrine/common/LICENSE
|
||||
opt/app/vendor/doctrine/common/README.md
|
||||
opt/app/vendor/doctrine/common/UPGRADE_TO_2_1
|
||||
opt/app/vendor/doctrine/common/UPGRADE_TO_2_2
|
||||
opt/app/vendor/doctrine/common/composer.json
|
||||
opt/app/vendor/doctrine/common/humbug.json.dist
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/CommonException.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Comparable.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/EventArgs.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/EventManager.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/EventSubscriber.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Lexer.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/NotifyPropertyChanged.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/AbstractManagerRegistry.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ConnectionRegistry.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LifecycleEventArgs.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LoadClassMetadataEventArgs.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/ManagerEventArgs.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/OnClearEventArgs.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/PreUpdateEventArgs.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ManagerRegistry.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadata.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadataFactory.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/AnnotationDriver.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/DefaultFileLocator.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileDriver.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileLocator.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriver.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriverChain.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/PHPDriver.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/StaticPHPDriver.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/SymfonyFileLocator.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/MappingException.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ReflectionService.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/StaticReflectionService.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManager.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManagerAware.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManagerDecorator.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectRepository.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/PersistentObject.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Proxy.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/PropertyChangedListener.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Autoloader.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/InvalidArgumentException.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/OutOfBoundsException.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/ProxyException.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/UnexpectedValueException.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Proxy.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyDefinition.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyGenerator.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ClassFinderInterface.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/Psr0FindFile.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ReflectionProviderInterface.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/RuntimePublicReflectionProperty.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionClass.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionMethod.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionProperty.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Util/Inflector.php
|
||||
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Version.php
|
||||
opt/app/vendor/doctrine/common/phpstan.neon
|
||||
opt/app/vendor/doctrine/dbal/.github/ISSUE_TEMPLATE/BC_Break.md
|
||||
opt/app/vendor/doctrine/dbal/.github/ISSUE_TEMPLATE/Bug.md
|
||||
opt/app/vendor/doctrine/dbal/.github/ISSUE_TEMPLATE/Feature_Request.md
|
||||
opt/app/vendor/doctrine/dbal/.github/ISSUE_TEMPLATE/Support_Question.md
|
||||
opt/app/vendor/doctrine/dbal/.github/PULL_REQUEST_TEMPLATE.md
|
||||
opt/app/vendor/doctrine/dbal/LICENSE
|
||||
opt/app/vendor/doctrine/dbal/README.md
|
||||
opt/app/vendor/doctrine/dbal/SECURITY.md
|
||||
@@ -2324,6 +2306,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/KeywordList.ph
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQL57Keywords.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQL80Keywords.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQLKeywords.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL100Keywords.php
|
||||
@@ -2343,6 +2326,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLServerKeywo
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLiteKeywords.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MariaDb1027Platform.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL57Platform.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php
|
||||
@@ -2367,7 +2351,6 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpress
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryException.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/README.markdown
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtilsException.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractAsset.php
|
||||
@@ -2421,6 +2404,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWor
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Dumper.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/TransactionIsolationLevel.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ArrayType.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php
|
||||
@@ -2455,6 +2439,16 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeImmutableType.ph
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php
|
||||
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/VersionAwarePlatformDriver.php
|
||||
opt/app/vendor/doctrine/dbal/phpstan.neon.dist
|
||||
opt/app/vendor/doctrine/event-manager/LICENSE
|
||||
opt/app/vendor/doctrine/event-manager/README.md
|
||||
opt/app/vendor/doctrine/event-manager/composer.json
|
||||
opt/app/vendor/doctrine/event-manager/docs/en/index.rst
|
||||
opt/app/vendor/doctrine/event-manager/docs/en/reference/index.rst
|
||||
opt/app/vendor/doctrine/event-manager/docs/en/sidebar.rst
|
||||
opt/app/vendor/doctrine/event-manager/lib/Doctrine/Common/EventArgs.php
|
||||
opt/app/vendor/doctrine/event-manager/lib/Doctrine/Common/EventManager.php
|
||||
opt/app/vendor/doctrine/event-manager/lib/Doctrine/Common/EventSubscriber.php
|
||||
opt/app/vendor/doctrine/inflector/LICENSE
|
||||
opt/app/vendor/doctrine/inflector/README.md
|
||||
opt/app/vendor/doctrine/inflector/composer.json
|
||||
@@ -2904,6 +2898,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/Refr
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/ResetCommand.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/RollbackCommand.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/StatusCommand.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/TableGuesser.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/SeedCommand.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/SeederMakeCommand.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/stubs/seeder.stub
|
||||
@@ -3176,6 +3171,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/WithoutMiddle
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Validation/ValidatesRequests.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Foundation/stubs/facade.stub
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Hashing/AbstractHasher.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Hashing/ArgonHasher.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Hashing/BcryptHasher.php
|
||||
opt/app/vendor/laravel/framework/src/Illuminate/Hashing/HashManager.php
|
||||
@@ -4432,9 +4428,6 @@ opt/app/vendor/ramsey/uuid/CONTRIBUTING.md
|
||||
opt/app/vendor/ramsey/uuid/LICENSE
|
||||
opt/app/vendor/ramsey/uuid/README.md
|
||||
opt/app/vendor/ramsey/uuid/composer.json
|
||||
opt/app/vendor/ramsey/uuid/docs/Makefile
|
||||
opt/app/vendor/ramsey/uuid/docs/conf.py
|
||||
opt/app/vendor/ramsey/uuid/docs/index.rst
|
||||
opt/app/vendor/ramsey/uuid/src/BinaryUtils.php
|
||||
opt/app/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php
|
||||
opt/app/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php
|
||||
@@ -4532,6 +4525,10 @@ opt/app/vendor/swiftmailer/swiftmailer/doc/messages.rst
|
||||
opt/app/vendor/swiftmailer/swiftmailer/doc/plugins.rst
|
||||
opt/app/vendor/swiftmailer/swiftmailer/doc/sending.rst
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/IdnAddressEncoder.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/Utf8AddressEncoder.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoderException.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Attachment.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php
|
||||
@@ -4594,6 +4591,7 @@ opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.ph
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NullContentEncoder.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php
|
||||
@@ -4670,6 +4668,8 @@ opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/Pl
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/EightBitMimeHandler.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php
|
||||
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php
|
||||
@@ -6327,6 +6327,7 @@ opt/app/vendor/symfony/var-dumper/Resources/bin/var-dump-server
|
||||
opt/app/vendor/symfony/var-dumper/Resources/css/htmlDescriptor.css
|
||||
opt/app/vendor/symfony/var-dumper/Resources/functions/dump.php
|
||||
opt/app/vendor/symfony/var-dumper/Resources/js/htmlDescriptor.js
|
||||
opt/app/vendor/symfony/var-dumper/Server/Connection.php
|
||||
opt/app/vendor/symfony/var-dumper/Server/DumpServer.php
|
||||
opt/app/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php
|
||||
opt/app/vendor/symfony/var-dumper/Tests/Caster/CasterTest.php
|
||||
@@ -6351,6 +6352,7 @@ opt/app/vendor/symfony/var-dumper/Tests/Fixtures/Twig.php
|
||||
opt/app/vendor/symfony/var-dumper/Tests/Fixtures/dumb-var.php
|
||||
opt/app/vendor/symfony/var-dumper/Tests/Fixtures/dump_server.php
|
||||
opt/app/vendor/symfony/var-dumper/Tests/Fixtures/xml_reader.xml
|
||||
opt/app/vendor/symfony/var-dumper/Tests/Server/ConnectionTest.php
|
||||
opt/app/vendor/symfony/var-dumper/Tests/Test/VarDumperTestTraitTest.php
|
||||
opt/app/vendor/symfony/var-dumper/VarDumper.php
|
||||
opt/app/vendor/symfony/var-dumper/composer.json
|
||||
@@ -7259,6 +7261,14 @@ 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
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/functions/create_uploaded_file.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/functions/marshal_headers_from_sapi.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/functions/marshal_method_from_sapi.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/functions/marshal_protocol_version_from_sapi.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/functions/marshal_uri_from_sapi.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/functions/normalize_server.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/functions/normalize_uploaded_files.php
|
||||
opt/app/vendor/zendframework/zend-diactoros/src/functions/parse_cookie_header.php
|
||||
proc/cpuinfo
|
||||
sandstorm-http-bridge
|
||||
sandstorm-http-bridge-config
|
||||
@@ -7433,14 +7443,17 @@ usr/share/zoneinfo/Africa/Libreville
|
||||
usr/share/zoneinfo/Africa/Lome
|
||||
usr/share/zoneinfo/Africa/Luanda
|
||||
usr/share/zoneinfo/Africa/Lubumbashi
|
||||
usr/share/zoneinfo/Africa/Lusaka
|
||||
usr/share/zoneinfo/Africa/Malabo
|
||||
usr/share/zoneinfo/Africa/Maputo
|
||||
usr/share/zoneinfo/Africa/Maseru
|
||||
usr/share/zoneinfo/Africa/Mbabane
|
||||
usr/share/zoneinfo/Africa/Mogadishu
|
||||
usr/share/zoneinfo/Africa/Nairobi
|
||||
usr/share/zoneinfo/Africa/Niamey
|
||||
usr/share/zoneinfo/Africa/Nouakchott
|
||||
usr/share/zoneinfo/Africa/Ouagadougou
|
||||
usr/share/zoneinfo/Africa/Porto-Novo
|
||||
usr/share/zoneinfo/Africa/Sao_Tome
|
||||
usr/share/zoneinfo/Africa/Timbuktu
|
||||
usr/share/zoneinfo/Africa/Tripoli
|
||||
@@ -7459,7 +7472,9 @@ usr/share/zoneinfo/America/Argentina/Mendoza
|
||||
usr/share/zoneinfo/America/Aruba
|
||||
usr/share/zoneinfo/America/Atikokan
|
||||
usr/share/zoneinfo/America/Atka
|
||||
usr/share/zoneinfo/America/Cayman
|
||||
usr/share/zoneinfo/America/Chicago
|
||||
usr/share/zoneinfo/America/Coral_Harbour
|
||||
usr/share/zoneinfo/America/Cordoba
|
||||
usr/share/zoneinfo/America/Curacao
|
||||
usr/share/zoneinfo/America/Denver
|
||||
@@ -7480,6 +7495,7 @@ usr/share/zoneinfo/America/Jamaica
|
||||
usr/share/zoneinfo/America/Kentucky
|
||||
usr/share/zoneinfo/America/Kentucky/Louisville
|
||||
usr/share/zoneinfo/America/Knox_IN
|
||||
usr/share/zoneinfo/America/Kralendijk
|
||||
usr/share/zoneinfo/America/Los_Angeles
|
||||
usr/share/zoneinfo/America/Lower_Princes
|
||||
usr/share/zoneinfo/America/Manaus
|
||||
@@ -7498,6 +7514,7 @@ usr/share/zoneinfo/America/Porto_Acre
|
||||
usr/share/zoneinfo/America/Puerto_Rico
|
||||
usr/share/zoneinfo/America/Regina
|
||||
usr/share/zoneinfo/America/Rio_Branco
|
||||
usr/share/zoneinfo/America/Santa_Isabel
|
||||
usr/share/zoneinfo/America/Santiago
|
||||
usr/share/zoneinfo/America/Sao_Paulo
|
||||
usr/share/zoneinfo/America/Shiprock
|
||||
@@ -7511,6 +7528,7 @@ usr/share/zoneinfo/America/Tijuana
|
||||
usr/share/zoneinfo/America/Toronto
|
||||
usr/share/zoneinfo/America/Tortola
|
||||
usr/share/zoneinfo/America/Vancouver
|
||||
usr/share/zoneinfo/America/Virgin
|
||||
usr/share/zoneinfo/America/Whitehorse
|
||||
usr/share/zoneinfo/America/Winnipeg
|
||||
usr/share/zoneinfo/Antarctica
|
||||
@@ -7521,8 +7539,10 @@ usr/share/zoneinfo/Asia
|
||||
usr/share/zoneinfo/Asia/Aden
|
||||
usr/share/zoneinfo/Asia/Ashgabat
|
||||
usr/share/zoneinfo/Asia/Bangkok
|
||||
usr/share/zoneinfo/Asia/Calcutta
|
||||
usr/share/zoneinfo/Asia/Chongqing
|
||||
usr/share/zoneinfo/Asia/Chungking
|
||||
usr/share/zoneinfo/Asia/Dacca
|
||||
usr/share/zoneinfo/Asia/Dhaka
|
||||
usr/share/zoneinfo/Asia/Dubai
|
||||
usr/share/zoneinfo/Asia/Harbin
|
||||
@@ -7530,24 +7550,31 @@ usr/share/zoneinfo/Asia/Ho_Chi_Minh
|
||||
usr/share/zoneinfo/Asia/Hong_Kong
|
||||
usr/share/zoneinfo/Asia/Istanbul
|
||||
usr/share/zoneinfo/Asia/Jerusalem
|
||||
usr/share/zoneinfo/Asia/Kashgar
|
||||
usr/share/zoneinfo/Asia/Kathmandu
|
||||
usr/share/zoneinfo/Asia/Katmandu
|
||||
usr/share/zoneinfo/Asia/Kolkata
|
||||
usr/share/zoneinfo/Asia/Macao
|
||||
usr/share/zoneinfo/Asia/Macau
|
||||
usr/share/zoneinfo/Asia/Makassar
|
||||
usr/share/zoneinfo/Asia/Nicosia
|
||||
usr/share/zoneinfo/Asia/Phnom_Penh
|
||||
usr/share/zoneinfo/Asia/Qatar
|
||||
usr/share/zoneinfo/Asia/Riyadh
|
||||
usr/share/zoneinfo/Asia/Saigon
|
||||
usr/share/zoneinfo/Asia/Seoul
|
||||
usr/share/zoneinfo/Asia/Shanghai
|
||||
usr/share/zoneinfo/Asia/Singapore
|
||||
usr/share/zoneinfo/Asia/Taipei
|
||||
usr/share/zoneinfo/Asia/Tehran
|
||||
usr/share/zoneinfo/Asia/Tel_Aviv
|
||||
usr/share/zoneinfo/Asia/Thimbu
|
||||
usr/share/zoneinfo/Asia/Thimphu
|
||||
usr/share/zoneinfo/Asia/Tokyo
|
||||
usr/share/zoneinfo/Asia/Ulaanbaatar
|
||||
usr/share/zoneinfo/Asia/Ulan_Bator
|
||||
usr/share/zoneinfo/Asia/Urumqi
|
||||
usr/share/zoneinfo/Asia/Yangon
|
||||
usr/share/zoneinfo/Atlantic
|
||||
usr/share/zoneinfo/Atlantic/Faroe
|
||||
usr/share/zoneinfo/Atlantic/Jan_Mayen
|
||||
@@ -7560,16 +7587,21 @@ usr/share/zoneinfo/Australia/Broken_Hill
|
||||
usr/share/zoneinfo/Australia/Canberra
|
||||
usr/share/zoneinfo/Australia/Darwin
|
||||
usr/share/zoneinfo/Australia/Hobart
|
||||
usr/share/zoneinfo/Australia/LHI
|
||||
usr/share/zoneinfo/Australia/Lord_Howe
|
||||
usr/share/zoneinfo/Australia/Melbourne
|
||||
usr/share/zoneinfo/Australia/NSW
|
||||
usr/share/zoneinfo/Australia/North
|
||||
usr/share/zoneinfo/Australia/Perth
|
||||
usr/share/zoneinfo/Australia/Queensland
|
||||
usr/share/zoneinfo/Australia/Sydney
|
||||
usr/share/zoneinfo/Australia/West
|
||||
usr/share/zoneinfo/Brazil
|
||||
usr/share/zoneinfo/Canada
|
||||
usr/share/zoneinfo/Canada/Atlantic
|
||||
usr/share/zoneinfo/Canada/East-Saskatchewan
|
||||
usr/share/zoneinfo/Canada/Saskatchewan
|
||||
usr/share/zoneinfo/Chile
|
||||
usr/share/zoneinfo/Chile/EasterIsland
|
||||
usr/share/zoneinfo/Etc
|
||||
usr/share/zoneinfo/Etc/GMT
|
||||
usr/share/zoneinfo/Etc/GMT+0
|
||||
@@ -7583,6 +7615,7 @@ usr/share/zoneinfo/Etc/Zulu
|
||||
usr/share/zoneinfo/Europe
|
||||
usr/share/zoneinfo/Europe/Belfast
|
||||
usr/share/zoneinfo/Europe/Belgrade
|
||||
usr/share/zoneinfo/Europe/Bratislava
|
||||
usr/share/zoneinfo/Europe/Busingen
|
||||
usr/share/zoneinfo/Europe/Chisinau
|
||||
usr/share/zoneinfo/Europe/Dublin
|
||||
@@ -7594,25 +7627,37 @@ usr/share/zoneinfo/Europe/Jersey
|
||||
usr/share/zoneinfo/Europe/Lisbon
|
||||
usr/share/zoneinfo/Europe/Ljubljana
|
||||
usr/share/zoneinfo/Europe/London
|
||||
usr/share/zoneinfo/Europe/Mariehamn
|
||||
usr/share/zoneinfo/Europe/Moscow
|
||||
usr/share/zoneinfo/Europe/Nicosia
|
||||
usr/share/zoneinfo/Europe/Oslo
|
||||
usr/share/zoneinfo/Europe/Podgorica
|
||||
usr/share/zoneinfo/Europe/Prague
|
||||
usr/share/zoneinfo/Europe/Rome
|
||||
usr/share/zoneinfo/Europe/San_Marino
|
||||
usr/share/zoneinfo/Europe/Sarajevo
|
||||
usr/share/zoneinfo/Europe/Skopje
|
||||
usr/share/zoneinfo/Europe/Tiraspol
|
||||
usr/share/zoneinfo/Europe/Vaduz
|
||||
usr/share/zoneinfo/Europe/Vatican
|
||||
usr/share/zoneinfo/Europe/Warsaw
|
||||
usr/share/zoneinfo/Europe/Zagreb
|
||||
usr/share/zoneinfo/Europe/Zurich
|
||||
usr/share/zoneinfo/GB
|
||||
usr/share/zoneinfo/GB-Eire
|
||||
usr/share/zoneinfo/GMT
|
||||
usr/share/zoneinfo/GMT+0
|
||||
usr/share/zoneinfo/GMT-0
|
||||
usr/share/zoneinfo/GMT0
|
||||
usr/share/zoneinfo/Greenwich
|
||||
usr/share/zoneinfo/Indian
|
||||
usr/share/zoneinfo/Indian/Antananarivo
|
||||
usr/share/zoneinfo/Indian/Comoro
|
||||
usr/share/zoneinfo/Indian/Mayotte
|
||||
usr/share/zoneinfo/Mexico
|
||||
usr/share/zoneinfo/Mexico/BajaNorte
|
||||
usr/share/zoneinfo/Mexico/BajaSur
|
||||
usr/share/zoneinfo/Mexico/General
|
||||
usr/share/zoneinfo/Pacific
|
||||
usr/share/zoneinfo/Pacific/Auckland
|
||||
usr/share/zoneinfo/Pacific/Chatham
|
||||
@@ -7629,18 +7674,35 @@ usr/share/zoneinfo/Pacific/Pitcairn
|
||||
usr/share/zoneinfo/Pacific/Pohnpei
|
||||
usr/share/zoneinfo/Pacific/Samoa
|
||||
usr/share/zoneinfo/Pacific/Truk
|
||||
usr/share/zoneinfo/Pacific/Yap
|
||||
usr/share/zoneinfo/SystemV
|
||||
usr/share/zoneinfo/SystemV/AST4
|
||||
usr/share/zoneinfo/SystemV/AST4ADT
|
||||
usr/share/zoneinfo/SystemV/CST6
|
||||
usr/share/zoneinfo/SystemV/CST6CDT
|
||||
usr/share/zoneinfo/SystemV/EST5
|
||||
usr/share/zoneinfo/SystemV/EST5EDT
|
||||
usr/share/zoneinfo/SystemV/HST10
|
||||
usr/share/zoneinfo/SystemV/MST7
|
||||
usr/share/zoneinfo/SystemV/MST7MDT
|
||||
usr/share/zoneinfo/SystemV/PST8
|
||||
usr/share/zoneinfo/SystemV/PST8PDT
|
||||
usr/share/zoneinfo/SystemV/YST9
|
||||
usr/share/zoneinfo/SystemV/YST9YDT
|
||||
usr/share/zoneinfo/US
|
||||
usr/share/zoneinfo/US/Alaska
|
||||
usr/share/zoneinfo/US/Aleutian
|
||||
usr/share/zoneinfo/US/Arizona
|
||||
usr/share/zoneinfo/US/Central
|
||||
usr/share/zoneinfo/US/East-Indiana
|
||||
usr/share/zoneinfo/US/Eastern
|
||||
usr/share/zoneinfo/US/Hawaii
|
||||
usr/share/zoneinfo/US/Indiana-Starke
|
||||
usr/share/zoneinfo/US/Michigan
|
||||
usr/share/zoneinfo/US/Mountain
|
||||
usr/share/zoneinfo/US/Pacific
|
||||
usr/share/zoneinfo/US/Pacific-New
|
||||
usr/share/zoneinfo/US/Samoa
|
||||
usr/share/zoneinfo/UTC
|
||||
usr/share/zoneinfo/Universal
|
||||
usr/share/zoneinfo/Zulu
|
||||
|
@@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = (
|
||||
|
||||
manifest = (
|
||||
appTitle = (defaultText = "Firefly III"),
|
||||
appVersion = 14,
|
||||
appMarketingVersion = (defaultText = "4.7.5.1"),
|
||||
appVersion = 15,
|
||||
appMarketingVersion = (defaultText = "4.7.5.2"),
|
||||
|
||||
actions = [
|
||||
# Define your "new document" handlers here.
|
||||
|
@@ -14,10 +14,7 @@ apt-get install -y python-software-properties software-properties-common
|
||||
|
||||
# install all languages
|
||||
sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/g' /etc/locale.gen
|
||||
|
||||
sed -i 's/# es_ES.UTF-8 UTF-8/es_ES.UTF-8 UTF-8/g' /etc/locale.gen
|
||||
sed -i 's/# fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/g' /etc/locale.gen
|
||||
sed -i 's/# id_ID.UTF-8 UTF-8/id_ID.UTF-8 UTF-8/g' /etc/locale.gen
|
||||
sed -i 's/# it_IT.UTF-8 UTF-8/it_IT.UTF-8 UTF-8/g' /etc/locale.gen
|
||||
sed -i 's/# nl_NL.UTF-8 UTF-8/nl_NL.UTF-8 UTF-8/g' /etc/locale.gen
|
||||
sed -i 's/# pl_PL.UTF-8 UTF-8/pl_PL.UTF-8 UTF-8/g' /etc/locale.gen
|
||||
@@ -35,7 +32,7 @@ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E9C74FEEA2098A6E
|
||||
add-apt-repository "deb http://packages.dotdeb.org jessie all"
|
||||
|
||||
# add another repos
|
||||
apt-get install apt-transport-https lsb-release ca-certificates
|
||||
apt-get install -y apt-transport-https lsb-release ca-certificates
|
||||
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
|
||||
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
|
||||
|
||||
|
@@ -59,7 +59,7 @@ RUN (crontab -l ; echo "* * * * * root $FIREFLY_PATH/artisan schedule:run >> /va
|
||||
RUN docker-php-ext-install -j$(nproc) curl gd intl json readline tidy zip bcmath xml mbstring pdo_sqlite pdo_mysql bz2 pdo_pgsql
|
||||
|
||||
# Generate locales supported by Firefly III
|
||||
RUN echo "de_DE.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nes_ES.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8pt_BR.UTF-8 UTF-8ru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\n\n" > /etc/locale.gen && locale-gen
|
||||
RUN echo "en_US.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\n\n" > /etc/locale.gen && locale-gen
|
||||
|
||||
# copy Apache config to correct spot.
|
||||
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
|
||||
|
@@ -232,4 +232,4 @@ class AttachmentController extends Controller
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -187,4 +187,4 @@ class AvailableBudgetController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -185,4 +185,4 @@ class BudgetController extends Controller
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\BudgetLimitRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
@@ -34,13 +34,13 @@ use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use InvalidArgumentException;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* Class BudgetLimitController.
|
||||
@@ -95,34 +95,17 @@ class BudgetLimitController extends Controller
|
||||
{
|
||||
$manager = new Manager;
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$start = null;
|
||||
$end = null;
|
||||
$budgetId = (int)($request->get('budget_id') ?? 0);
|
||||
$budget = $this->repository->findNull($budgetId);
|
||||
$this->parameters->set('budget_id', $budgetId);
|
||||
|
||||
try {
|
||||
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
|
||||
$this->parameters->set('start', $start->format('Y-m-d'));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Log::debug(sprintf('Invalid date: %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
try {
|
||||
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
|
||||
$this->parameters->set('end', $end->format('Y-m-d'));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Log::debug(sprintf('Invalid date: %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
|
||||
$this->parameters->set('budget_id', $budgetId);
|
||||
|
||||
$collection = new Collection;
|
||||
if (null === $budget) {
|
||||
$collection = $this->repository->getAllBudgetLimits($start, $end);
|
||||
$collection = $this->repository->getAllBudgetLimits($this->parameters->get('start'), $this->parameters->get('end'));
|
||||
}
|
||||
if (null !== $budget) {
|
||||
$collection = $this->repository->getBudgetLimits($budget, $start, $end);
|
||||
$collection = $this->repository->getBudgetLimits($budget, $this->parameters->get('start'), $this->parameters->get('end'));
|
||||
}
|
||||
|
||||
$count = $collection->count();
|
||||
@@ -212,4 +195,4 @@ class BudgetLimitController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -185,4 +185,4 @@ class CategoryController extends Controller
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -132,4 +132,4 @@ class ConfigurationController extends Controller
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -108,4 +108,4 @@ class CurrencyExchangeRateController extends Controller
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -214,4 +214,4 @@ class JournalLinkController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -207,4 +207,4 @@ class LinkTypeController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -185,4 +185,4 @@ class PiggyBankController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,6 @@ use League\Fractal\Manager;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -60,7 +59,7 @@ class PreferenceController extends Controller
|
||||
];
|
||||
$preferences = new Collection;
|
||||
foreach ($available as $name) {
|
||||
$pref = Preferences::getForUser($user, $name);
|
||||
$pref = app('preferences')->getForUser($user, $name);
|
||||
if (null !== $pref) {
|
||||
$preferences->push($pref);
|
||||
}
|
||||
@@ -130,7 +129,7 @@ class PreferenceController extends Controller
|
||||
$newValue = 1 === (int)$data['data'];
|
||||
break;
|
||||
}
|
||||
$result = Preferences::set($preference->name, $newValue);
|
||||
$result = app('preferences')->set($preference->name, $newValue);
|
||||
|
||||
// create some objects:
|
||||
$manager = new Manager;
|
||||
@@ -143,4 +142,4 @@ class PreferenceController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -177,4 +177,4 @@ class RecurrenceController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -175,4 +175,4 @@ class RuleController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -176,4 +176,4 @@ class RuleGroupController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -94,4 +94,4 @@ class AttachmentRequest extends Request
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -55,7 +55,6 @@ class AvailableBudgetRequest extends Request
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO must also accept currency code.
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
* @return array
|
||||
@@ -73,4 +72,4 @@ class AvailableBudgetRequest extends Request
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -115,7 +115,7 @@ class BillRequest extends Request
|
||||
$min = (float)($data['amount_min'] ?? 0);
|
||||
$max = (float)($data['amount_max'] ?? 0);
|
||||
if ($min > $max) {
|
||||
$validator->errors()->add('amount_min', trans('validation.amount_min_over_max'));
|
||||
$validator->errors()->add('amount_min', (string)trans('validation.amount_min_over_max'));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@@ -80,4 +80,4 @@ class BudgetLimitRequest extends Request
|
||||
return $rules;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -79,4 +79,4 @@ class BudgetRequest extends Request
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -78,4 +78,4 @@ class CategoryRequest extends Request
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -57,8 +57,6 @@ class JournalLinkRequest extends Request
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO include link-type name as optional parameter.
|
||||
* TODO be consistent and remove notes from this object.
|
||||
*
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
@@ -74,4 +72,4 @@ class JournalLinkRequest extends Request
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -71,7 +71,6 @@ class LinkTypeRequest extends Request
|
||||
'outward' => 'required|unique:link_types,outward|min:1|different:inward',
|
||||
'inward' => 'required|unique:link_types,inward|min:1|different:outward',
|
||||
];
|
||||
// Rule::unique('users')->ignore($user->id),
|
||||
|
||||
|
||||
switch ($this->method()) {
|
||||
@@ -89,4 +88,4 @@ class LinkTypeRequest extends Request
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -93,4 +93,4 @@ class PiggyBankRequest extends Request
|
||||
return $rules;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -66,4 +66,4 @@ class PreferenceRequest extends Request
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -84,8 +84,7 @@ class RecurrenceRequest extends Request
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$today = new Carbon;
|
||||
$today->addDay();
|
||||
$today = Carbon::create()->addDay();
|
||||
|
||||
return [
|
||||
'type' => 'required|in:withdrawal,transfer,deposit',
|
||||
@@ -201,4 +200,4 @@ class RecurrenceRequest extends Request
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -82,4 +82,4 @@ class RuleGroupRequest extends Request
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -141,7 +141,7 @@ class RuleRequest extends Request
|
||||
$repetitions = $data['rule-actions'] ?? [];
|
||||
// need at least one transaction
|
||||
if (0 === \count($repetitions)) {
|
||||
$validator->errors()->add('title', trans('validation.at_least_one_action'));
|
||||
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class RuleRequest extends Request
|
||||
$repetitions = $data['rule-triggers'] ?? [];
|
||||
// need at least one transaction
|
||||
if (0 === \count($repetitions)) {
|
||||
$validator->errors()->add('title', trans('validation.at_least_one_trigger'));
|
||||
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,6 @@ use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Illuminate\Console\Command;
|
||||
use Log;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class CreateImport.
|
||||
@@ -232,7 +231,7 @@ class CreateImport extends Command
|
||||
}
|
||||
}
|
||||
// clear cache for user:
|
||||
Preferences::setForUser($user, 'lastActivity', microtime());
|
||||
app('preferences')->setForUser($user, 'lastActivity', microtime());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -266,8 +265,8 @@ class CreateImport extends Command
|
||||
*/
|
||||
private function validArguments(): bool
|
||||
{
|
||||
$file = $this->argument('file');
|
||||
$configuration = $this->argument('configuration');
|
||||
$file = (string)$this->argument('file');
|
||||
$configuration = (string)$this->argument('configuration');
|
||||
$cwd = getcwd();
|
||||
$validTypes = config('import.options.file.import_formats');
|
||||
$type = strtolower($this->option('type'));
|
||||
|
@@ -63,9 +63,9 @@ class DecryptAttachment extends Command
|
||||
$repository = app(AttachmentRepositoryInterface::class);
|
||||
$attachmentId = (int)$this->argument('id');
|
||||
$attachment = $repository->findWithoutUser($attachmentId);
|
||||
$attachmentName = trim($this->argument('name'));
|
||||
$storagePath = realpath(trim($this->argument('directory')));
|
||||
if (null === $attachment->id) {
|
||||
$attachmentName = trim((string)$this->argument('name'));
|
||||
$storagePath = realpath(trim((string)$this->argument('directory')));
|
||||
if (null === $attachment) {
|
||||
$this->error(sprintf('No attachment with id #%d', $attachmentId));
|
||||
Log::error(sprintf('DecryptAttachment: No attachment with id #%d', $attachmentId));
|
||||
|
||||
|
@@ -59,20 +59,21 @@ class Import extends Command
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle(): int
|
||||
{
|
||||
Log::debug('Start start-import command');
|
||||
$jobKey = $this->argument('key');
|
||||
$jobKey = (string)$this->argument('key');
|
||||
/** @var ImportJob $job */
|
||||
$job = ImportJob::where('key', $jobKey)->first();
|
||||
if (null === $job) {
|
||||
$this->errorLine(sprintf('No job found with key "%s"', $jobKey));
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
if (!$this->isValid($job)) {
|
||||
$this->errorLine('Job is not valid for some reason. Exit.');
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->infoLine(sprintf('Going to import job with key "%s" of type "%s"', $job->key, $job->file_type));
|
||||
@@ -106,6 +107,8 @@ class Import extends Command
|
||||
}
|
||||
|
||||
$this->infoLine(sprintf('The import has finished. %d transactions have been imported.', $count));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -54,7 +54,7 @@ class ScanAttachments extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle(): int
|
||||
{
|
||||
$attachments = Attachment::get();
|
||||
$disk = Storage::disk('upload');
|
||||
@@ -82,5 +82,6 @@ class ScanAttachments extends Command
|
||||
$attachment->save();
|
||||
$this->line(sprintf('Fixed attachment #%d', $attachment->id));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -54,7 +54,6 @@ use Illuminate\Console\Command;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Schema;
|
||||
use UnexpectedValueException;
|
||||
|
||||
@@ -83,7 +82,7 @@ class UpgradeDatabase extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle(): int
|
||||
{
|
||||
$this->setTransactionIdentifier();
|
||||
$this->updateAccountCurrencies();
|
||||
@@ -97,6 +96,8 @@ class UpgradeDatabase extends Command
|
||||
$this->migrateBillsToRules();
|
||||
|
||||
$this->info('Firefly III database is up to date.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,10 +111,10 @@ class UpgradeDatabase extends Command
|
||||
{
|
||||
foreach (User::get() as $user) {
|
||||
/** @var Preference $lang */
|
||||
$lang = Preferences::getForUser($user, 'language', 'en_US');
|
||||
$lang = app('preferences')->getForUser($user, 'language', 'en_US');
|
||||
$groupName = (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data);
|
||||
$ruleGroup = $user->ruleGroups()->where('title', $groupName)->first();
|
||||
$currencyPreference = Preferences::getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR'));
|
||||
$currencyPreference = app('preferences')->getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR'));
|
||||
|
||||
if (null === $currencyPreference) {
|
||||
$this->error('User has no currency preference. Impossible.');
|
||||
@@ -198,7 +199,7 @@ class UpgradeDatabase extends Command
|
||||
[
|
||||
'rule_id' => $rule->id,
|
||||
'trigger_type' => 'amount_more',
|
||||
'trigger_value' => round($bill->amount_min, $currency->decimal_places),
|
||||
'trigger_value' => round((float)$bill->amount_min, $currency->decimal_places),
|
||||
'active' => 1,
|
||||
'stop_processing' => 0,
|
||||
'order' => 4,
|
||||
@@ -210,7 +211,7 @@ class UpgradeDatabase extends Command
|
||||
[
|
||||
'rule_id' => $rule->id,
|
||||
'trigger_type' => 'amount_exactly',
|
||||
'trigger_value' => round($bill->amount_min, $currency->decimal_places),
|
||||
'trigger_value' => round((float)$bill->amount_min, $currency->decimal_places),
|
||||
'active' => 1,
|
||||
'stop_processing' => 0,
|
||||
'order' => 3,
|
||||
@@ -294,7 +295,7 @@ class UpgradeDatabase extends Command
|
||||
function (Account $account) use ($repository) {
|
||||
$repository->setUser($account->user);
|
||||
// get users preference, fall back to system pref.
|
||||
$defaultCurrencyCode = Preferences::getForUser($account->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
|
||||
$defaultCurrencyCode = app('preferences')->getForUser($account->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
|
||||
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
|
||||
$accountCurrency = (int)$repository->getMetaValue($account, 'currency_id');
|
||||
$openingBalance = $account->getOpeningBalance();
|
||||
|
@@ -46,14 +46,15 @@ class UpgradeFireflyInstructions extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle(): int
|
||||
{
|
||||
if ('update' === $this->argument('task')) {
|
||||
if ('update' === (string)$this->argument('task')) {
|
||||
$this->updateInstructions();
|
||||
}
|
||||
if ('install' === $this->argument('task')) {
|
||||
if ('install' === (string)$this->argument('task')) {
|
||||
$this->installInstructions();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -47,7 +47,7 @@ class UseEncryption extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle(): int
|
||||
{
|
||||
if (true === config('firefly.encryption')) {
|
||||
$this->info('Firefly III configuration calls for encrypted data.');
|
||||
@@ -62,6 +62,7 @@ class UseEncryption extends Command
|
||||
$this->handleObjects('Category', 'name', 'encrypted');
|
||||
$this->handleObjects('PiggyBank', 'name', 'encrypted');
|
||||
$this->handleObjects('TransactionJournal', 'description', 'encrypted');
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -25,7 +25,6 @@ namespace FireflyIII\Console\Commands;
|
||||
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Log;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Trait VerifiesAccessToken.
|
||||
@@ -61,7 +60,7 @@ trait VerifiesAccessToken
|
||||
|
||||
return false;
|
||||
}
|
||||
$accessToken = Preferences::getForUser($user, 'access_token', null);
|
||||
$accessToken = app('preferences')->getForUser($user, 'access_token', null);
|
||||
if (null === $accessToken) {
|
||||
Log::error(sprintf('User #%d has no access token, so cannot access command line options.', $userId));
|
||||
|
||||
|
@@ -42,7 +42,6 @@ use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Schema;
|
||||
use stdClass;
|
||||
|
||||
@@ -70,11 +69,11 @@ class VerifyDatabase extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle(): int
|
||||
{
|
||||
// if table does not exist, return false
|
||||
if (!Schema::hasTable('users')) {
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->reportEmptyBudgets();
|
||||
@@ -95,6 +94,8 @@ class VerifyDatabase extends Command
|
||||
$this->fixDoubleAmounts();
|
||||
$this->fixBadMeta();
|
||||
$this->removeBills();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,10 +107,10 @@ class VerifyDatabase extends Command
|
||||
$users = User::get();
|
||||
/** @var User $user */
|
||||
foreach ($users as $user) {
|
||||
$pref = Preferences::getForUser($user, 'access_token', null);
|
||||
$pref = app('preferences')->getForUser($user, 'access_token', null);
|
||||
if (null === $pref) {
|
||||
$token = $user->generateAccessToken();
|
||||
Preferences::setForUser($user, 'access_token', $token);
|
||||
app('preferences')->setForUser($user, 'access_token', $token);
|
||||
$this->line(sprintf('Generated access token for user %s', $user->email));
|
||||
++$count;
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* RequestedReportOnJournals.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
|
@@ -31,7 +31,7 @@ use Exception;
|
||||
use FireflyIII\Jobs\MailError;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Validation\ValidationException as LaravelValidationException;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use Request;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
@@ -54,7 +54,7 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
public function render($request, Exception $exception)
|
||||
{
|
||||
if ($exception instanceof ValidationException && $request->expectsJson()) {
|
||||
if ($exception instanceof LaravelValidationException && $request->expectsJson()) {
|
||||
// ignore it: controller will handle it.
|
||||
return parent::render($request, $exception);
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Export\Collector\AttachmentCollector;
|
||||
use FireflyIII\Export\Collector\UploadCollector;
|
||||
use FireflyIII\Export\Entry\Entry;
|
||||
use FireflyIII\Export\Exporter\ExporterInterface;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
@@ -220,6 +221,7 @@ class ExpandedProcessor implements ProcessorInterface
|
||||
public function exportJournals(): bool
|
||||
{
|
||||
$exporterClass = config('firefly.export_formats.' . $this->exportFormat);
|
||||
/** @var ExporterInterface $exporter */
|
||||
$exporter = app($exporterClass);
|
||||
$exporter->setJob($this->job);
|
||||
$exporter->setEntries($this->exportEntries);
|
||||
|
@@ -189,7 +189,7 @@ class AccountFactory
|
||||
}
|
||||
if (null === $result) {
|
||||
/** @var string $type */
|
||||
$type = (string)config('firefly.accountTypeByIdentifier.' . (string)$accountType);
|
||||
$type = (string)config('firefly.accountTypeByIdentifier.' . $accountType);
|
||||
$result = AccountType::whereType($type)->first();
|
||||
if (null === $result && null !== $accountType) {
|
||||
// try as full name:
|
||||
|
@@ -24,13 +24,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class AccountMetaFactory
|
||||
*/
|
||||
class AccountMetaFactory
|
||||
{
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
@@ -41,4 +45,45 @@ class AccountMetaFactory
|
||||
return AccountMeta::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create update or delete meta data.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
*
|
||||
* @return AccountMeta|null
|
||||
*/
|
||||
public function crud(Account $account, string $field, string $value): ?AccountMeta
|
||||
{
|
||||
/** @var AccountMeta $entry */
|
||||
$entry = $account->accountMeta()->where('name', $field)->first();
|
||||
|
||||
// must not be an empty string:
|
||||
if ('' !== $value) {
|
||||
|
||||
// if $data has field and $entry is null, create new one:
|
||||
if (null === $entry) {
|
||||
Log::debug(sprintf('Created meta-field "%s":"%s" for account #%d ("%s") ', $field, $value, $account->id, $account->name));
|
||||
$this->create(['account_id' => $account->id, 'name' => $field, 'data' => $value]);
|
||||
}
|
||||
|
||||
// if $data has field and $entry is not null, update $entry:
|
||||
if (null !== $entry) {
|
||||
$entry->data = $value;
|
||||
$entry->save();
|
||||
Log::debug(sprintf('Updated meta-field "%s":"%s" for #%d ("%s") ', $field, $value, $account->id, $account->name));
|
||||
}
|
||||
}
|
||||
if ('' === $value && null !== $entry && isset($data[$field])) {
|
||||
try {
|
||||
$entry->delete();
|
||||
} catch (Exception $e) {
|
||||
Log::debug(sprintf('Could not delete entry: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -76,4 +76,4 @@ class AttachmentFactory
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -93,4 +93,4 @@ class RecurrenceFactory
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -43,7 +43,6 @@ class TransactionCurrencyFactory
|
||||
*/
|
||||
public function create(array $data): ?TransactionCurrency
|
||||
{
|
||||
$result = null;
|
||||
try {
|
||||
/** @var TransactionCurrency $currency */
|
||||
$result = TransactionCurrency::create(
|
||||
@@ -55,6 +54,7 @@ class TransactionCurrencyFactory
|
||||
]
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
$result = null;
|
||||
Log::error(sprintf('Could not create new currency: %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
|
@@ -113,6 +113,10 @@ class TransactionFactory
|
||||
$destinationAccount = $this->findAccount($destinationType, $data['destination_id'], $data['destination_name']);
|
||||
|
||||
if (null === $sourceAccount || null === $destinationAccount) {
|
||||
$debugData = $data;
|
||||
$debugData['source_type'] = $sourceType;
|
||||
$debugData['dest_type'] = $destinationType;
|
||||
Log::error('Info about source/dest:', $debugData);
|
||||
throw new FireflyException('Could not determine source or destination account.');
|
||||
}
|
||||
|
||||
|
@@ -104,7 +104,7 @@ class TransactionJournalFactory
|
||||
// store date meta fields (if present):
|
||||
$fields = ['sepa-cc', 'sepa-ct-op', 'sepa-ct-id', 'sepa-db', 'sepa-country', 'sepa-ep', 'sepa-ci', 'interest_date', 'book_date', 'process_date',
|
||||
'due_date', 'recurrence_id', 'payment_date', 'invoice_date', 'internal_reference', 'bunq_payment_id', 'importHash', 'importHashV2',
|
||||
'external_id'];
|
||||
'external_id','sepa-batch-id'];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$this->storeMeta($journal, $data, $field);
|
||||
|
@@ -51,6 +51,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
||||
* Generates the report.
|
||||
*
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function generate(): string
|
||||
|
@@ -29,6 +29,8 @@ use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class Support.
|
||||
* @method Collection getExpenses()
|
||||
* @method Collection getIncome()
|
||||
*/
|
||||
class Support
|
||||
{
|
||||
|
@@ -71,7 +71,6 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
*
|
||||
* @return string
|
||||
* @throws \Throwable
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function generate(): string
|
||||
{
|
||||
|
@@ -74,4 +74,4 @@ class APIEventHandler
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -63,4 +63,4 @@ class AutomationHandler
|
||||
// @codeCoverageIgnoreEnd
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -36,7 +36,6 @@ use FireflyIII\User;
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use Log;
|
||||
use Mail;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class UserEventHandler.
|
||||
@@ -138,7 +137,7 @@ class UserEventHandler
|
||||
$oldEmail = $event->oldEmail;
|
||||
$user = $event->user;
|
||||
$ipAddress = $event->ipAddress;
|
||||
$token = Preferences::getForUser($user, 'email_change_confirm_token', 'invalid');
|
||||
$token = app('preferences')->getForUser($user, 'email_change_confirm_token', 'invalid');
|
||||
$uri = route('profile.confirm-email-change', [$token->data]);
|
||||
try {
|
||||
Mail::to($newEmail)->send(new ConfirmEmailChangeMail($newEmail, $oldEmail, $uri, $ipAddress));
|
||||
@@ -164,7 +163,7 @@ class UserEventHandler
|
||||
$oldEmail = $event->oldEmail;
|
||||
$user = $event->user;
|
||||
$ipAddress = $event->ipAddress;
|
||||
$token = Preferences::getForUser($user, 'email_change_undo_token', 'invalid');
|
||||
$token = app('preferences')->getForUser($user, 'email_change_undo_token', 'invalid');
|
||||
$uri = route('profile.undo-email-change', [$token->data, hash('sha256', $oldEmail)]);
|
||||
try {
|
||||
Mail::to($oldEmail)->send(new UndoEmailChangeMail($newEmail, $oldEmail, $uri, $ipAddress));
|
||||
|
@@ -24,14 +24,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
use FireflyConfig;
|
||||
use FireflyIII\Events\RequestedVersionCheckStatus;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
|
||||
use FireflyIII\Helpers\Update\UpdateTrait;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Services\Github\Object\Release;
|
||||
use FireflyIII\Services\Github\Request\UpdateRequest;
|
||||
|
||||
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
|
||||
@@ -66,7 +66,6 @@ class VersionCheckEventHandler
|
||||
return;
|
||||
}
|
||||
|
||||
$permission = FireflyConfig::get('permission_update_check', -1);
|
||||
$lastCheckTime = FireflyConfig::get('last_update_check', time());
|
||||
$now = time();
|
||||
$diff = $now - $lastCheckTime->data;
|
||||
@@ -80,16 +79,9 @@ class VersionCheckEventHandler
|
||||
// last check time was more than a week ago.
|
||||
Log::debug('Have not checked for a new version in a week!');
|
||||
|
||||
// have actual permission?
|
||||
if ($permission->data === -1) {
|
||||
// never asked before.
|
||||
//session()->flash('info', (string)trans('firefly.check_for_updates_permission', ['link' => route('admin.update-check')]));
|
||||
//return;
|
||||
}
|
||||
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
$versionCheck = $this->versionCheck($latestRelease);
|
||||
$resultString = $this->parseResult($latestRelease, $versionCheck);
|
||||
$resultString = $this->parseResult($versionCheck, $latestRelease);
|
||||
if (0 !== $versionCheck && '' !== $resultString) {
|
||||
// flash info
|
||||
session()->flash('info', $resultString);
|
||||
|
@@ -77,11 +77,12 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
*/
|
||||
public function getAttachmentContent(Attachment $attachment): string
|
||||
{
|
||||
$content = '';
|
||||
|
||||
try {
|
||||
$content = Crypt::decrypt($this->uploadDisk->get(sprintf('at-%d.data', $attachment->id)));
|
||||
} catch (DecryptException|FileNotFoundException $e) {
|
||||
Log::error(sprintf('Could not decrypt data of attachment #%d: %s', $attachment->id, $e->getMessage()));
|
||||
$content = '';
|
||||
}
|
||||
|
||||
return $content;
|
||||
@@ -166,7 +167,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
$attachment->md5 = md5_file($path);
|
||||
$attachment->mime = $mime;
|
||||
$attachment->size = \strlen($content);
|
||||
$attachment->uploaded = 1;
|
||||
$attachment->uploaded = true;
|
||||
$attachment->save();
|
||||
|
||||
return true;
|
||||
@@ -249,7 +250,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
$attachment->filename = $file->getClientOriginalName();
|
||||
$attachment->mime = $file->getMimeType();
|
||||
$attachment->size = $file->getSize();
|
||||
$attachment->uploaded = 0;
|
||||
$attachment->uploaded = false;
|
||||
$attachment->save();
|
||||
Log::debug('Created attachment:', $attachment->toArray());
|
||||
|
||||
@@ -262,7 +263,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
|
||||
// store it:
|
||||
$this->uploadDisk->put($attachment->fileName(), $encrypted);
|
||||
$attachment->uploaded = 1; // update attachment
|
||||
$attachment->uploaded = true; // update attachment
|
||||
$attachment->save();
|
||||
$this->attachments->push($attachment);
|
||||
|
||||
|
@@ -359,7 +359,7 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
$repository->setUser($this->user);
|
||||
foreach ($array as $objectId => $amount) {
|
||||
if (!isset($names[$objectId])) {
|
||||
$object = $repository->find((int)$objectId);
|
||||
$object = $repository->findNull((int)$objectId);
|
||||
$names[$objectId] = $object->name ?? $object->tag;
|
||||
}
|
||||
$amount = app('steam')->positive($amount);
|
||||
|
@@ -51,7 +51,6 @@ use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* TODO rename references to journals to transactions
|
||||
* Maybe this is a good idea after all...
|
||||
*
|
||||
* Class JournalCollector
|
||||
|
@@ -82,7 +82,6 @@ interface JournalCollectorInterface
|
||||
|
||||
/**
|
||||
* Get all journals.
|
||||
* TODO rename me.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
|
@@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Helpers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class FiscalHelper.
|
||||
@@ -38,7 +37,7 @@ class FiscalHelper implements FiscalHelperInterface
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->useCustomFiscalYear = Preferences::get('customFiscalYear', false)->data;
|
||||
$this->useCustomFiscalYear = app('preferences')->get('customFiscalYear', false)->data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,7 +71,7 @@ class FiscalHelper implements FiscalHelperInterface
|
||||
// get start mm-dd. Then create a start date in the year passed.
|
||||
$startDate = clone $date;
|
||||
if (true === $this->useCustomFiscalYear) {
|
||||
$prefStartStr = Preferences::get('fiscalYearStart', '01-01')->data;
|
||||
$prefStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data;
|
||||
[$mth, $day] = explode('-', $prefStartStr);
|
||||
$startDate->month((int)$mth)->day((int)$day);
|
||||
|
||||
|
@@ -76,7 +76,8 @@ class Help implements HelpInterface
|
||||
$statusCode = $res->getStatusCode();
|
||||
$content = trim($res->getBody()->getContents());
|
||||
} catch (GuzzleException|Exception $e) {
|
||||
Log::error($e);
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Status code is %d', $statusCode));
|
||||
|
@@ -32,7 +32,6 @@ use Log;
|
||||
/**
|
||||
* Trait UpdateTrait
|
||||
*
|
||||
* @package FireflyIII\Helpers\Update
|
||||
*/
|
||||
trait UpdateTrait
|
||||
{
|
||||
@@ -67,12 +66,12 @@ trait UpdateTrait
|
||||
/**
|
||||
* Parses the version check result in a human readable sentence.
|
||||
*
|
||||
* @param Release|null $release
|
||||
* @param int $versionCheck
|
||||
* @param Release|null $release
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function parseResult(Release $release = null, int $versionCheck): string
|
||||
public function parseResult(int $versionCheck, Release $release = null): string
|
||||
{
|
||||
$current = (string)config('firefly.version');
|
||||
$return = '';
|
||||
@@ -128,4 +127,4 @@ trait UpdateTrait
|
||||
|
||||
return $check;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
128
app/Http/Controllers/Account/CreateController.php
Normal file
128
app/Http/Controllers/Account/CreateController.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
/**
|
||||
* CreateController.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\Controllers\Account;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\AccountFormRequest;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class CreateController
|
||||
*/
|
||||
class CreateController extends Controller
|
||||
{
|
||||
/** @var AccountRepositoryInterface The account repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* CreateController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// translations:
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-credit-card');
|
||||
app('view')->share('title', (string)trans('firefly.accounts'));
|
||||
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new account.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string|null $what
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function create(Request $request, string $what = null)
|
||||
{
|
||||
$what = $what ?? 'asset';
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = (string)trans('firefly.make_new_' . $what . '_account');
|
||||
$roles = [];
|
||||
foreach (config('firefly.accountRoles') as $role) {
|
||||
$roles[$role] = (string)trans('firefly.account_role_' . $role);
|
||||
}
|
||||
|
||||
// pre fill some data
|
||||
$request->session()->flash('preFilled', ['currency_id' => $defaultCurrency->id]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (true !== session('accounts.create.fromStore')) {
|
||||
$this->rememberPreviousUri('accounts.create.uri');
|
||||
}
|
||||
$request->session()->forget('accounts.create.fromStore');
|
||||
|
||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'roles'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store the new account.
|
||||
*
|
||||
* @param AccountFormRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function store(AccountFormRequest $request)
|
||||
{
|
||||
$data = $request->getAccountData();
|
||||
$account = $this->repository->store($data);
|
||||
$request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
// update preferences if necessary:
|
||||
$frontPage = app('preferences')->get('frontPageAccounts', [])->data;
|
||||
if (AccountType::ASSET === $account->accountType->type && \count($frontPage) > 0) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$frontPage[] = $account->id;
|
||||
app('preferences')->set('frontPageAccounts', $frontPage);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
// redirect to previous URL.
|
||||
$redirect = redirect($this->getPreviousUri('accounts.create.uri'));
|
||||
if (1 === (int)$request->get('create_another')) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
$request->session()->put('accounts.create.fromStore', true);
|
||||
|
||||
$redirect = redirect(route('accounts.create', [$request->input('what')]))->withInput();
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
}
|
103
app/Http/Controllers/Account/DeleteController.php
Normal file
103
app/Http/Controllers/Account/DeleteController.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* DeleteController.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\Controllers\Account;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class DeleteController
|
||||
*/
|
||||
class DeleteController extends Controller
|
||||
{
|
||||
/** @var AccountRepositoryInterface The account repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* DeleteController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// translations:
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-credit-card');
|
||||
app('view')->share('title', (string)trans('firefly.accounts'));
|
||||
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete account screen.
|
||||
*
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function delete(Account $account)
|
||||
{
|
||||
$typeName = config('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
$subTitle = (string)trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
|
||||
$accountList = app('expandedform')->makeSelectListWithEmpty($this->repository->getAccountsByType([$account->accountType->type]));
|
||||
unset($accountList[$account->id]);
|
||||
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('accounts.delete.uri');
|
||||
|
||||
return view('accounts.delete', compact('account', 'subTitle', 'accountList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the account.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function destroy(Request $request, Account $account)
|
||||
{
|
||||
$type = $account->accountType->type;
|
||||
$typeName = config('firefly.shortNamesByFullName.' . $type);
|
||||
$name = $account->name;
|
||||
$moveTo = $this->repository->findNull((int)$request->get('move_account_before_delete'));
|
||||
|
||||
$this->repository->destroy($account, $moveTo);
|
||||
|
||||
$request->session()->flash('success', (string)trans('firefly.' . $typeName . '_deleted', ['name' => $name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect($this->getPreviousUri('accounts.delete.uri'));
|
||||
}
|
||||
|
||||
}
|
151
app/Http/Controllers/Account/EditController.php
Normal file
151
app/Http/Controllers/Account/EditController.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
/**
|
||||
* EditController.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\Controllers\Account;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\AccountFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class EditController
|
||||
*/
|
||||
class EditController extends Controller
|
||||
{
|
||||
/** @var CurrencyRepositoryInterface The currency repository */
|
||||
private $currencyRepos;
|
||||
/** @var AccountRepositoryInterface The account repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* EditController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// translations:
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-credit-card');
|
||||
app('view')->share('title', (string)trans('firefly.accounts'));
|
||||
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit account overview.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
public function edit(Request $request, Account $account, AccountRepositoryInterface $repository)
|
||||
{
|
||||
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
|
||||
$subTitle = (string)trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$roles = [];
|
||||
foreach (config('firefly.accountRoles') as $role) {
|
||||
$roles[$role] = (string)trans('firefly.account_role_' . $role);
|
||||
}
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('accounts.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('accounts.edit.uri');
|
||||
}
|
||||
$request->session()->forget('accounts.edit.fromUpdate');
|
||||
|
||||
$openingBalanceAmount = (string)$repository->getOpeningBalanceAmount($account);
|
||||
$openingBalanceDate = $repository->getOpeningBalanceDate($account);
|
||||
$default = app('amount')->getDefaultCurrency();
|
||||
$currency = $this->currencyRepos->findNull((int)$repository->getMetaValue($account, 'currency_id'));
|
||||
if (null === $currency) {
|
||||
$currency = $default;
|
||||
}
|
||||
|
||||
// code to handle active-checkboxes
|
||||
$hasOldInput = null !== $request->old('_token');
|
||||
$preFilled = [
|
||||
'accountNumber' => $repository->getMetaValue($account, 'accountNumber'),
|
||||
'accountRole' => $repository->getMetaValue($account, 'accountRole'),
|
||||
'ccType' => $repository->getMetaValue($account, 'ccType'),
|
||||
'ccMonthlyPaymentDate' => $repository->getMetaValue($account, 'ccMonthlyPaymentDate'),
|
||||
'BIC' => $repository->getMetaValue($account, 'BIC'),
|
||||
'openingBalanceDate' => $openingBalanceDate,
|
||||
'openingBalance' => $openingBalanceAmount,
|
||||
'virtualBalance' => $account->virtual_balance,
|
||||
'currency_id' => $currency->id,
|
||||
'notes' => $this->repository->getNoteText($account),
|
||||
'active' => $hasOldInput ? (bool)$request->old('active') : $account->active,
|
||||
];
|
||||
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
|
||||
return view('accounts.edit', compact('account', 'currency', 'subTitle', 'subTitleIcon', 'what', 'roles', 'preFilled'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the account.
|
||||
*
|
||||
* @param AccountFormRequest $request
|
||||
* @param Account $account
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function update(AccountFormRequest $request, Account $account)
|
||||
{
|
||||
$data = $request->getAccountData();
|
||||
$this->repository->update($account, $data);
|
||||
|
||||
$request->session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
$redirect = redirect($this->getPreviousUri('accounts.edit.uri'));
|
||||
if (1 === (int)$request->get('return_to_edit')) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
$request->session()->put('accounts.edit.fromUpdate', true);
|
||||
|
||||
$redirect = redirect(route('accounts.edit', [$account->id]))->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
}
|
129
app/Http/Controllers/Account/IndexController.php
Normal file
129
app/Http/Controllers/Account/IndexController.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* IndexController.php
|
||||
* Copyright (c) 2017 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/>.
|
||||
*/
|
||||
/** @noinspection CallableParameterUseCaseInTypeContextInspection */
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Account;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class IndexController
|
||||
*/
|
||||
class IndexController extends Controller
|
||||
{
|
||||
/** @var AccountRepositoryInterface The account repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* IndexController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// translations:
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-credit-card');
|
||||
app('view')->share('title', (string)trans('firefly.accounts'));
|
||||
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show list of accounts.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $what
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request, string $what)
|
||||
{
|
||||
$what = $what ?? 'asset';
|
||||
$subTitle = (string)trans('firefly.' . $what . '_accounts');
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$types = config('firefly.accountTypesByIdentifier.' . $what);
|
||||
$collection = $this->repository->getAccountsByType($types);
|
||||
$total = $collection->count();
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$accounts = $collection->slice(($page - 1) * $pageSize, $pageSize);
|
||||
unset($collection);
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$start->subDay();
|
||||
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
$startBalances = app('steam')->balancesByAccounts($accounts, $start);
|
||||
$endBalances = app('steam')->balancesByAccounts($accounts, $end);
|
||||
$activities = app('steam')->getLastActivities($ids);
|
||||
|
||||
$accounts->each(
|
||||
function (Account $account) use ($activities, $startBalances, $endBalances) {
|
||||
$account->lastActivityDate = $this->isInArray($activities, $account->id);
|
||||
$account->startBalance = $this->isInArray($startBalances, $account->id);
|
||||
$account->endBalance = $this->isInArray($endBalances, $account->id);
|
||||
$account->difference = bcsub($account->endBalance, $account->startBalance);
|
||||
}
|
||||
);
|
||||
|
||||
// make paginator:
|
||||
$accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
|
||||
$accounts->setPath(route('accounts.index', [$what]));
|
||||
|
||||
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'page', 'accounts'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the ID in a given array. Return '0' of not there (amount).
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $entryId
|
||||
*
|
||||
* @return null|mixed
|
||||
*/
|
||||
protected function isInArray(array $array, int $entryId)
|
||||
{
|
||||
$result = '0';
|
||||
if (isset($array[$entryId])) {
|
||||
$result = $array[$entryId];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -36,9 +36,7 @@ use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Update\CurrencyUpdateService;
|
||||
use Log;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class ReconcileController.
|
||||
@@ -47,15 +45,15 @@ use Preferences;
|
||||
*/
|
||||
class ReconcileController extends Controller
|
||||
{
|
||||
/** @var CurrencyUpdateService */
|
||||
/** @var AccountRepositoryInterface The account repository */
|
||||
private $accountRepos;
|
||||
/** @var AccountRepositoryInterface */
|
||||
/** @var CurrencyRepositoryInterface The currency repository */
|
||||
private $currencyRepos;
|
||||
/** @var JournalRepositoryInterface */
|
||||
/** @var JournalRepositoryInterface Journals and transactions overview */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
* ReconcileController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -65,7 +63,7 @@ class ReconcileController extends Controller
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-credit-card');
|
||||
app('view')->share('title', trans('firefly.accounts'));
|
||||
app('view')->share('title', (string)trans('firefly.accounts'));
|
||||
$this->repository = app(JournalRepositoryInterface::class);
|
||||
$this->accountRepos = app(AccountRepositoryInterface::class);
|
||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
@@ -76,6 +74,8 @@ class ReconcileController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a reconciliation.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
@@ -86,7 +86,7 @@ class ReconcileController extends Controller
|
||||
return redirect(route('transactions.edit', [$journal->id]));
|
||||
}
|
||||
// view related code
|
||||
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
|
||||
$subTitle = (string)trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
|
||||
|
||||
// journal related code
|
||||
$pTransaction = $this->repository->getFirstPosTransaction($journal);
|
||||
@@ -112,6 +112,8 @@ class ReconcileController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconciliation overview.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon|null $start
|
||||
* @param Carbon|null $end
|
||||
@@ -127,7 +129,7 @@ class ReconcileController extends Controller
|
||||
return $this->redirectToOriginalAccount($account);
|
||||
}
|
||||
if (AccountType::ASSET !== $account->accountType->type) {
|
||||
session()->flash('error', trans('firefly.must_be_asset_account'));
|
||||
session()->flash('error', (string)trans('firefly.must_be_asset_account'));
|
||||
|
||||
return redirect(route('accounts.index', [config('firefly.shortNamesByFullName.' . $account->accountType->type)]));
|
||||
}
|
||||
@@ -138,14 +140,17 @@ class ReconcileController extends Controller
|
||||
}
|
||||
|
||||
// no start or end:
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
|
||||
// get start and end
|
||||
if (null === $start && null === $end) {
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', app('navigation')->startOfPeriod(new Carbon, $range));
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', app('navigation')->endOfPeriod(new Carbon, $range));
|
||||
}
|
||||
if (null === $end) {
|
||||
/** @var Carbon $end */
|
||||
$end = app('navigation')->endOfPeriod($start, $range);
|
||||
}
|
||||
|
||||
@@ -154,7 +159,7 @@ class ReconcileController extends Controller
|
||||
$startBalance = round(app('steam')->balance($account, $startDate), $currency->decimal_places);
|
||||
$endBalance = round(app('steam')->balance($account, $end), $currency->decimal_places);
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||
$subTitle = trans('firefly.reconcile_account', ['account' => $account->name]);
|
||||
$subTitle = (string)trans('firefly.reconcile_account', ['account' => $account->name]);
|
||||
|
||||
// various links
|
||||
$transactionsUri = route('accounts.reconcile.transactions', [$account->id, '%start%', '%end%']);
|
||||
@@ -170,6 +175,8 @@ class ReconcileController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a single reconciliation.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
|
||||
@@ -195,6 +202,8 @@ class ReconcileController extends Controller
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Submit a new reconciliation.
|
||||
*
|
||||
* @param ReconciliationStoreRequest $request
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
@@ -273,17 +282,22 @@ class ReconcileController extends Controller
|
||||
}
|
||||
Log::debug('End of routine.');
|
||||
app('preferences')->mark();
|
||||
session()->flash('success', trans('firefly.reconciliation_stored'));
|
||||
session()->flash('success', (string)trans('firefly.reconciliation_stored'));
|
||||
|
||||
return redirect(route('accounts.show', [$account->id]));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update a reconciliation.
|
||||
*
|
||||
* @param ReconciliationUpdateRequest $request
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
public function update(ReconciliationUpdateRequest $request, TransactionJournal $journal)
|
||||
{
|
||||
@@ -291,7 +305,7 @@ class ReconcileController extends Controller
|
||||
return redirect(route('transactions.show', [$journal->id]));
|
||||
}
|
||||
if (0 === bccomp('0', $request->get('amount'))) {
|
||||
session()->flash('error', trans('firefly.amount_cannot_be_zero'));
|
||||
session()->flash('error', (string)trans('firefly.amount_cannot_be_zero'));
|
||||
|
||||
return redirect(route('accounts.reconcile.edit', [$journal->id]))->withInput();
|
||||
}
|
||||
@@ -358,6 +372,8 @@ class ReconcileController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect user to the original asset account.
|
||||
*
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
|
273
app/Http/Controllers/Account/ShowController.php
Normal file
273
app/Http/Controllers/Account/ShowController.php
Normal file
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
/**
|
||||
* ShowController.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\Controllers\Account;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class ShowController
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
*/
|
||||
class ShowController extends Controller
|
||||
{
|
||||
/** @var CurrencyRepositoryInterface The currency repository */
|
||||
private $currencyRepos;
|
||||
/** @var AccountRepositoryInterface The account repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* ShowController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// translations:
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-credit-card');
|
||||
app('view')->share('title', (string)trans('firefly.accounts'));
|
||||
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Show an account.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
* @param Carbon|null $start
|
||||
* @param Carbon|null $end
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
*
|
||||
* @throws FireflyException
|
||||
*
|
||||
*/
|
||||
public function show(Request $request, Account $account, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
if (AccountType::INITIAL_BALANCE === $account->accountType->type) {
|
||||
return $this->redirectToOriginalAccount($account);
|
||||
}
|
||||
/** @var Carbon $start */
|
||||
$start = $start ?? session('start');
|
||||
/** @var Carbon $end */
|
||||
$end = $end ?? session('end');
|
||||
if ($end < $start) {
|
||||
throw new FireflyException('End is after start!'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$what = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type)); // used for menu
|
||||
$today = new Carbon;
|
||||
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$currencyId = (int)$this->repository->getMetaValue($account, 'currency_id');
|
||||
$currency = $this->currencyRepos->findNull($currencyId);
|
||||
if (0 === $currencyId) {
|
||||
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
|
||||
}
|
||||
$fStart = $start->formatLocalized($this->monthAndDayFormat);
|
||||
$fEnd = $end->formatLocalized($this->monthAndDayFormat);
|
||||
$subTitle = (string)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);
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
|
||||
$collector->setRange($start, $end);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
|
||||
$showAll = false;
|
||||
|
||||
return view(
|
||||
'accounts.show',
|
||||
compact('account', 'showAll', 'what', 'currency', 'today', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end', 'chartUri')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an account.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
*
|
||||
* @throws FireflyException
|
||||
*
|
||||
*/
|
||||
public function showAll(Request $request, Account $account)
|
||||
{
|
||||
if (AccountType::INITIAL_BALANCE === $account->accountType->type) {
|
||||
return $this->redirectToOriginalAccount($account); // @codeCoverageIgnore
|
||||
}
|
||||
$end = new Carbon;
|
||||
$today = new Carbon;
|
||||
$start = $this->repository->oldestJournalDate($account);
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$currencyId = (int)$this->repository->getMetaValue($account, 'currency_id');
|
||||
$currency = $this->currencyRepos->findNull($currencyId);
|
||||
if (0 === $currencyId) {
|
||||
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
|
||||
}
|
||||
$subTitle = (string)trans('firefly.all_journals_for_account', ['name' => $account->name]);
|
||||
$periods = new Collection;
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('accounts.show.all', [$account->id]));
|
||||
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||
$showAll = true;
|
||||
|
||||
return view(
|
||||
'accounts.show',
|
||||
compact('account', 'showAll', 'currency', 'today', 'chartUri', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* This method returns "period entries", so nov-2015, dec-2015, etc etc (this depends on the users session range)
|
||||
* and for each period, the amount of money spent and earned. This is a complex operation which is cached for
|
||||
* performance reasons.
|
||||
*
|
||||
* @param Account $account the account involved
|
||||
*
|
||||
* @param Carbon|null $date
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
private function getPeriodOverview(Account $account, ?Carbon $date): Collection
|
||||
{
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$start = $this->repository->oldestJournalDate($account);
|
||||
$end = $date ?? new Carbon;
|
||||
if ($end < $start) {
|
||||
[$start, $end] = [$end, $start]; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('account-show-period-entries');
|
||||
$cache->addProperty($account->id);
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$entries = new Collection;
|
||||
// loop dates
|
||||
foreach ($dates as $currentDate) {
|
||||
|
||||
// try a collector for income:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::DEPOSIT])
|
||||
->withOpposingAccount();
|
||||
$earned = (string)$collector->getJournals()->sum('transaction_amount');
|
||||
|
||||
// try a collector for expenses:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::WITHDRAWAL])
|
||||
->withOpposingAccount();
|
||||
$spent = (string)$collector->getJournals()->sum('transaction_amount');
|
||||
|
||||
$dateName = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$entries->push(
|
||||
[
|
||||
'name' => $dateName,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'start' => $currentDate['start']->format('Y-m-d'),
|
||||
'end' => $currentDate['end']->format('Y-m-d'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the original account.
|
||||
*
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function redirectToOriginalAccount(Account $account)
|
||||
{
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $account->transactions()->first();
|
||||
if (null === $transaction) {
|
||||
throw new FireflyException('Expected a transaction. This account has none. BEEP, error.');
|
||||
}
|
||||
|
||||
$journal = $transaction->transactionJournal;
|
||||
/** @var Transaction $opposingTransaction */
|
||||
$opposingTransaction = $journal->transactions()->where('transactions.id', '!=', $transaction->id)->first();
|
||||
|
||||
if (null === $opposingTransaction) {
|
||||
throw new FireflyException('Expected an opposing transaction. This account has none. BEEP, error.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return redirect(route('accounts.show', [$opposingTransaction->account_id]));
|
||||
}
|
||||
}
|
@@ -1,521 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* AccountController.php
|
||||
* Copyright (c) 2017 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/>.
|
||||
*/
|
||||
/** @noinspection CallableParameterUseCaseInTypeContextInspection */
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use ExpandedForm;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Requests\AccountFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class AccountController.
|
||||
*
|
||||
*/
|
||||
class AccountController extends Controller
|
||||
{
|
||||
/** @var CurrencyRepositoryInterface */
|
||||
private $currencyRepos;
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// translations:
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-credit-card');
|
||||
app('view')->share('title', trans('firefly.accounts'));
|
||||
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param string|null $what
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function create(Request $request, string $what = null)
|
||||
{
|
||||
$what = $what ?? 'asset';
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
||||
$roles = [];
|
||||
foreach (config('firefly.accountRoles') as $role) {
|
||||
$roles[$role] = (string)trans('firefly.account_role_' . $role);
|
||||
}
|
||||
|
||||
// pre fill some data
|
||||
$request->session()->flash('preFilled', ['currency_id' => $defaultCurrency->id]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (true !== session('accounts.create.fromStore')) {
|
||||
$this->rememberPreviousUri('accounts.create.uri');
|
||||
}
|
||||
$request->session()->forget('accounts.create.fromStore');
|
||||
|
||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'roles'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function delete(Account $account)
|
||||
{
|
||||
$typeName = config('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
$subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
|
||||
$accountList = ExpandedForm::makeSelectListWithEmpty($this->repository->getAccountsByType([$account->accountType->type]));
|
||||
unset($accountList[$account->id]);
|
||||
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('accounts.delete.uri');
|
||||
|
||||
return view('accounts.delete', compact('account', 'subTitle', 'accountList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function destroy(Request $request, Account $account)
|
||||
{
|
||||
$type = $account->accountType->type;
|
||||
$typeName = config('firefly.shortNamesByFullName.' . $type);
|
||||
$name = $account->name;
|
||||
$moveTo = $this->repository->findNull((int)$request->get('move_account_before_delete'));
|
||||
|
||||
$this->repository->destroy($account, $moveTo);
|
||||
|
||||
$request->session()->flash('success', (string)trans('firefly.' . $typeName . '_deleted', ['name' => $name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect($this->getPreviousUri('accounts.delete.uri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
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]);
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$roles = [];
|
||||
foreach (config('firefly.accountRoles') as $role) {
|
||||
$roles[$role] = (string)trans('firefly.account_role_' . $role);
|
||||
}
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('accounts.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('accounts.edit.uri');
|
||||
}
|
||||
$request->session()->forget('accounts.edit.fromUpdate');
|
||||
|
||||
// pre fill some useful values.
|
||||
|
||||
// the opening balance is tricky:
|
||||
$openingBalanceAmount = (string)$repository->getOpeningBalanceAmount($account);
|
||||
$openingBalanceDate = $repository->getOpeningBalanceDate($account);
|
||||
$default = app('amount')->getDefaultCurrency();
|
||||
$currency = $this->currencyRepos->findNull((int)$repository->getMetaValue($account, 'currency_id'));
|
||||
if (null === $currency) {
|
||||
$currency = $default;
|
||||
}
|
||||
|
||||
// code to handle active-checkboxes
|
||||
$hasOldInput = null !== $request->old('_token');
|
||||
$preFilled = [
|
||||
'accountNumber' => $repository->getMetaValue($account, 'accountNumber'),
|
||||
'accountRole' => $repository->getMetaValue($account, 'accountRole'),
|
||||
'ccType' => $repository->getMetaValue($account, 'ccType'),
|
||||
'ccMonthlyPaymentDate' => $repository->getMetaValue($account, 'ccMonthlyPaymentDate'),
|
||||
'BIC' => $repository->getMetaValue($account, 'BIC'),
|
||||
'openingBalanceDate' => $openingBalanceDate,
|
||||
'openingBalance' => $openingBalanceAmount,
|
||||
'virtualBalance' => $account->virtual_balance,
|
||||
'currency_id' => $currency->id,
|
||||
'notes' => '',
|
||||
'active' => $hasOldInput ? (bool)$request->old('active') : $account->active,
|
||||
];
|
||||
/** @var Note $note */
|
||||
$note = $this->repository->getNote($account);
|
||||
if (null !== $note) {
|
||||
$preFilled['notes'] = $note->text;
|
||||
}
|
||||
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
|
||||
return view('accounts.edit', compact('account', 'currency', 'subTitle', 'subTitleIcon', 'what', 'roles', 'preFilled'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param string $what
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request, string $what)
|
||||
{
|
||||
$what = $what ?? 'asset';
|
||||
$subTitle = trans('firefly.' . $what . '_accounts');
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$types = config('firefly.accountTypesByIdentifier.' . $what);
|
||||
$collection = $this->repository->getAccountsByType($types);
|
||||
$total = $collection->count();
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$accounts = $collection->slice(($page - 1) * $pageSize, $pageSize);
|
||||
unset($collection);
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$start->subDay();
|
||||
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
$startBalances = app('steam')->balancesByAccounts($accounts, $start);
|
||||
$endBalances = app('steam')->balancesByAccounts($accounts, $end);
|
||||
$activities = app('steam')->getLastActivities($ids);
|
||||
|
||||
$accounts->each(
|
||||
function (Account $account) use ($activities, $startBalances, $endBalances) {
|
||||
$account->lastActivityDate = $this->isInArray($activities, $account->id);
|
||||
$account->startBalance = $this->isInArray($startBalances, $account->id);
|
||||
$account->endBalance = $this->isInArray($endBalances, $account->id);
|
||||
$account->difference = bcsub($account->endBalance, $account->startBalance);
|
||||
}
|
||||
);
|
||||
|
||||
// make paginator:
|
||||
$accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
|
||||
$accounts->setPath(route('accounts.index', [$what]));
|
||||
|
||||
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'page', 'accounts'));
|
||||
}
|
||||
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Show an account.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
* @param Carbon|null $start
|
||||
* @param Carbon|null $end
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
*
|
||||
* @throws FireflyException
|
||||
*
|
||||
*/
|
||||
public function show(Request $request, Account $account, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
if (AccountType::INITIAL_BALANCE === $account->accountType->type) {
|
||||
return $this->redirectToOriginalAccount($account);
|
||||
}
|
||||
if (null === $start) {
|
||||
$start = session('start');
|
||||
}
|
||||
if (null === $end) {
|
||||
$end = session('end');
|
||||
}
|
||||
if ($end < $start) {
|
||||
throw new FireflyException('End is after start!'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
|
||||
$what = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type)); // used for menu
|
||||
$today = new Carbon;
|
||||
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$currencyId = (int)$this->repository->getMetaValue($account, 'currency_id');
|
||||
$currency = $this->currencyRepos->findNull($currencyId);
|
||||
if (0 === $currencyId) {
|
||||
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
|
||||
}
|
||||
$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);
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
|
||||
$collector->setRange($start, $end);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
|
||||
$showAll = false;
|
||||
|
||||
return view(
|
||||
'accounts.show',
|
||||
compact('account', 'showAll', 'what', 'currency', 'today', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end', 'chartUri')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show an account.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
*
|
||||
* @throws FireflyException
|
||||
*
|
||||
*/
|
||||
public function showAll(Request $request, Account $account)
|
||||
{
|
||||
if (AccountType::INITIAL_BALANCE === $account->accountType->type) {
|
||||
return $this->redirectToOriginalAccount($account); // @codeCoverageIgnore
|
||||
}
|
||||
$end = new Carbon;
|
||||
$today = new Carbon;
|
||||
$start = $this->repository->oldestJournalDate($account);
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$currencyId = (int)$this->repository->getMetaValue($account, 'currency_id');
|
||||
$currency = $this->currencyRepos->findNull($currencyId);
|
||||
if (0 === $currencyId) {
|
||||
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
|
||||
}
|
||||
$subTitle = trans('firefly.all_journals_for_account', ['name' => $account->name]);
|
||||
$periods = new Collection;
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('accounts.show.all', [$account->id]));
|
||||
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||
$showAll = true;
|
||||
|
||||
return view(
|
||||
'accounts.show',
|
||||
compact('account', 'showAll', 'currency', 'today', 'chartUri', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountFormRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function store(AccountFormRequest $request)
|
||||
{
|
||||
$data = $request->getAccountData();
|
||||
$account = $this->repository->store($data);
|
||||
$request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
// update preferences if necessary:
|
||||
$frontPage = Preferences::get('frontPageAccounts', [])->data;
|
||||
if (AccountType::ASSET === $account->accountType->type && \count($frontPage) > 0) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$frontPage[] = $account->id;
|
||||
Preferences::set('frontPageAccounts', $frontPage);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
// redirect to previous URL.
|
||||
$redirect = redirect($this->getPreviousUri('accounts.create.uri'));
|
||||
if (1 === (int)$request->get('create_another')) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
$request->session()->put('accounts.create.fromStore', true);
|
||||
|
||||
$redirect = redirect(route('accounts.create', [$request->input('what')]))->withInput();
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountFormRequest $request
|
||||
* @param Account $account
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function update(AccountFormRequest $request, Account $account)
|
||||
{
|
||||
$data = $request->getAccountData();
|
||||
$this->repository->update($account, $data);
|
||||
|
||||
$request->session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
$redirect = redirect($this->getPreviousUri('accounts.edit.uri'));
|
||||
if (1 === (int)$request->get('return_to_edit')) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
$request->session()->put('accounts.edit.fromUpdate', true);
|
||||
|
||||
$redirect = redirect(route('accounts.edit', [$account->id]))->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @param int $entryId
|
||||
*
|
||||
* @return null|mixed
|
||||
*/
|
||||
protected function isInArray(array $array, int $entryId)
|
||||
{
|
||||
$result = '0';
|
||||
if (isset($array[$entryId])) {
|
||||
$result = $array[$entryId];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method returns "period entries", so nov-2015, dec-2015, etc etc (this depends on the users session range)
|
||||
* and for each period, the amount of money spent and earned. This is a complex operation which is cached for
|
||||
* performance reasons.
|
||||
*
|
||||
* @param Account $account the account involved
|
||||
*
|
||||
* @param Carbon|null $date
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
*/
|
||||
private function getPeriodOverview(Account $account, ?Carbon $date): Collection
|
||||
{
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = $this->repository->oldestJournalDate($account);
|
||||
$end = $date ?? new Carbon;
|
||||
if ($end < $start) {
|
||||
[$start, $end] = [$end, $start]; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('account-show-period-entries');
|
||||
$cache->addProperty($account->id);
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$entries = new Collection;
|
||||
// loop dates
|
||||
foreach ($dates as $currentDate) {
|
||||
|
||||
// try a collector for income:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::DEPOSIT])
|
||||
->withOpposingAccount();
|
||||
$earned = (string)$collector->getJournals()->sum('transaction_amount');
|
||||
|
||||
// try a collector for expenses:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::WITHDRAWAL])
|
||||
->withOpposingAccount();
|
||||
$spent = (string)$collector->getJournals()->sum('transaction_amount');
|
||||
|
||||
$dateName = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$entries->push(
|
||||
[
|
||||
'name' => $dateName,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'start' => $currentDate['start']->format('Y-m-d'),
|
||||
'end' => $currentDate['end']->format('Y-m-d'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function redirectToOriginalAccount(Account $account)
|
||||
{
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $account->transactions()->first();
|
||||
if (null === $transaction) {
|
||||
throw new FireflyException('Expected a transaction. This account has none. BEEP, error.');
|
||||
}
|
||||
|
||||
$journal = $transaction->transactionJournal;
|
||||
/** @var Transaction $opposingTransaction */
|
||||
$opposingTransaction = $journal->transactions()->where('transactions.id', '!=', $transaction->id)->first();
|
||||
|
||||
if (null === $opposingTransaction) {
|
||||
throw new FireflyException('Expected an opposing transaction. This account has none. BEEP, error.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return redirect(route('accounts.show', [$opposingTransaction->account_id]));
|
||||
}
|
||||
}
|
@@ -55,6 +55,8 @@ class ConfigurationController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show configuration index.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
@@ -75,6 +77,8 @@ class ConfigurationController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Store new configuration values.
|
||||
*
|
||||
* @param ConfigurationRequest $request
|
||||
*
|
||||
* @return RedirectResponse
|
||||
|
@@ -46,6 +46,8 @@ class HomeController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Index of the admin.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
@@ -58,6 +60,8 @@ class HomeController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a test message to the admin.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
|
@@ -36,7 +36,7 @@ use View;
|
||||
class LinkController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
* LinkController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -54,11 +54,12 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new link form.
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$subTitle = trans('firefly.create_new_link_type');
|
||||
$subTitle = (string)trans('firefly.create_new_link_type');
|
||||
$subTitleIcon = 'fa-link';
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
@@ -70,6 +71,8 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a link form.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param LinkTypeRepositoryInterface $repository
|
||||
* @param LinkType $linkType
|
||||
@@ -84,11 +87,11 @@ class LinkController extends Controller
|
||||
return redirect(route('admin.links.index'));
|
||||
}
|
||||
|
||||
$subTitle = trans('firefly.delete_link_type', ['name' => $linkType->name]);
|
||||
$subTitle = (string)trans('firefly.delete_link_type', ['name' => $linkType->name]);
|
||||
$otherTypes = $repository->get();
|
||||
$count = $repository->countJournals($linkType);
|
||||
$moveTo = [];
|
||||
$moveTo[0] = trans('firefly.do_not_save_connection');
|
||||
$moveTo[0] = (string)trans('firefly.do_not_save_connection');
|
||||
/** @var LinkType $otherType */
|
||||
foreach ($otherTypes as $otherType) {
|
||||
if ($otherType->id !== $linkType->id) {
|
||||
@@ -102,6 +105,8 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually destroy the link.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param LinkTypeRepositoryInterface $repository
|
||||
* @param LinkType $linkType
|
||||
@@ -121,6 +126,8 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a link form.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param LinkType $linkType
|
||||
*
|
||||
@@ -133,7 +140,7 @@ class LinkController extends Controller
|
||||
|
||||
return redirect(route('admin.links.index'));
|
||||
}
|
||||
$subTitle = trans('firefly.edit_link_type', ['name' => $linkType->name]);
|
||||
$subTitle = (string)trans('firefly.edit_link_type', ['name' => $linkType->name]);
|
||||
$subTitleIcon = 'fa-link';
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
@@ -146,13 +153,15 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show index of all links.
|
||||
*
|
||||
* @param LinkTypeRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index(LinkTypeRepositoryInterface $repository)
|
||||
{
|
||||
$subTitle = trans('firefly.journal_link_configuration');
|
||||
$subTitle = (string)trans('firefly.journal_link_configuration');
|
||||
$subTitleIcon = 'fa-link';
|
||||
$linkTypes = $repository->get();
|
||||
$linkTypes->each(
|
||||
@@ -165,13 +174,15 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a single link.
|
||||
*
|
||||
* @param LinkType $linkType
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function show(LinkType $linkType)
|
||||
{
|
||||
$subTitle = trans('firefly.overview_for_link', ['name' => $linkType->name]);
|
||||
$subTitle = (string)trans('firefly.overview_for_link', ['name' => $linkType->name]);
|
||||
$subTitleIcon = 'fa-link';
|
||||
$links = $linkType->transactionJournalLinks()->get();
|
||||
|
||||
@@ -179,6 +190,8 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the new link.
|
||||
*
|
||||
* @param LinkTypeFormRequest $request
|
||||
* @param LinkTypeRepositoryInterface $repository
|
||||
*
|
||||
@@ -206,6 +219,8 @@ class LinkController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing link.
|
||||
*
|
||||
* @param LinkTypeFormRequest $request
|
||||
* @param LinkTypeRepositoryInterface $repository
|
||||
* @param LinkType $linkType
|
||||
|
@@ -56,26 +56,30 @@ class UpdateController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show page with update options.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws \Psr\Container\NotFoundExceptionInterface
|
||||
* @throws \Psr\Container\ContainerExceptionInterface
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$subTitle = trans('firefly.update_check_title');
|
||||
$subTitle = (string)trans('firefly.update_check_title');
|
||||
$subTitleIcon = 'fa-star';
|
||||
$permission = app('fireflyconfig')->get('permission_update_check', -1);
|
||||
$selected = $permission->data;
|
||||
$options = [
|
||||
-1 => trans('firefly.updates_ask_me_later'),
|
||||
0 => trans('firefly.updates_do_not_check'),
|
||||
1 => trans('firefly.updates_enable_check'),
|
||||
-1 => (string)trans('firefly.updates_ask_me_later'),
|
||||
0 => (string)trans('firefly.updates_do_not_check'),
|
||||
1 => (string)trans('firefly.updates_enable_check'),
|
||||
];
|
||||
|
||||
return view('admin.update.index', compact('subTitle', 'subTitleIcon', 'selected', 'options'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Post new settings.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
@@ -97,7 +101,7 @@ class UpdateController extends Controller
|
||||
{
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
$versionCheck = $this->versionCheck($latestRelease);
|
||||
$resultString = $this->parseResult($latestRelease, $versionCheck);
|
||||
$resultString = $this->parseResult($versionCheck, $latestRelease);
|
||||
|
||||
if (0 !== $versionCheck && '' !== $resultString) {
|
||||
// flash info
|
||||
|
@@ -29,7 +29,6 @@ use FireflyIII\Http\Requests\UserFormRequest;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class UserController.
|
||||
@@ -37,7 +36,7 @@ use Preferences;
|
||||
class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
* UserController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -56,18 +55,22 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a user.
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function delete(User $user)
|
||||
{
|
||||
$subTitle = trans('firefly.delete_user', ['email' => $user->email]);
|
||||
$subTitle = (string)trans('firefly.delete_user', ['email' => $user->email]);
|
||||
|
||||
return view('admin.users.delete', compact('user', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a user.
|
||||
*
|
||||
* @param User $user
|
||||
* @param UserRepositoryInterface $repository
|
||||
*
|
||||
@@ -82,6 +85,8 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit user form.
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
@@ -107,6 +112,8 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show index of user manager.
|
||||
*
|
||||
* @param UserRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
@@ -121,7 +128,7 @@ class UserController extends Controller
|
||||
$users->each(
|
||||
function (User $user) use ($repository) {
|
||||
$list = ['twoFactorAuthEnabled', 'twoFactorAuthSecret'];
|
||||
$preferences = Preferences::getArrayForUser($user, $list);
|
||||
$preferences = app('preferences')->getArrayForUser($user, $list);
|
||||
$user->isAdmin = $repository->hasRole($user, 'owner');
|
||||
$is2faEnabled = 1 === $preferences['twoFactorAuthEnabled'];
|
||||
$has2faSecret = null !== $preferences['twoFactorAuthSecret'];
|
||||
@@ -134,6 +141,8 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show single user.
|
||||
*
|
||||
* @param UserRepositoryInterface $repository
|
||||
* @param User $user
|
||||
*
|
||||
@@ -155,6 +164,8 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Update single user.
|
||||
*
|
||||
* @param UserFormRequest $request
|
||||
* @param User $user
|
||||
* @param UserRepositoryInterface $repository
|
||||
|
@@ -36,11 +36,11 @@ use Illuminate\Http\Response as LaravelResponse;
|
||||
*/
|
||||
class AttachmentController extends Controller
|
||||
{
|
||||
/** @var AttachmentRepositoryInterface */
|
||||
/** @var AttachmentRepositoryInterface Attachment repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
* AttachmentController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -50,7 +50,7 @@ class AttachmentController extends Controller
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-paperclip');
|
||||
app('view')->share('title', trans('firefly.attachments'));
|
||||
app('view')->share('title', (string)trans('firefly.attachments'));
|
||||
$this->repository = app(AttachmentRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
@@ -59,13 +59,15 @@ class AttachmentController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Form to delete an attachment.
|
||||
*
|
||||
* @param Attachment $attachment
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function delete(Attachment $attachment)
|
||||
{
|
||||
$subTitle = trans('firefly.delete_attachment', ['name' => $attachment->filename]);
|
||||
$subTitle = (string)trans('firefly.delete_attachment', ['name' => $attachment->filename]);
|
||||
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('attachments.delete.uri');
|
||||
@@ -74,6 +76,8 @@ class AttachmentController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy attachment.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Attachment $attachment
|
||||
*
|
||||
@@ -92,6 +96,8 @@ class AttachmentController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Download attachment to PC.
|
||||
*
|
||||
* @param Attachment $attachment
|
||||
*
|
||||
* @return mixed
|
||||
@@ -123,6 +129,8 @@ class AttachmentController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit an attachment.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Attachment $attachment
|
||||
*
|
||||
@@ -131,21 +139,24 @@ class AttachmentController extends Controller
|
||||
public function edit(Request $request, Attachment $attachment)
|
||||
{
|
||||
$subTitleIcon = 'fa-pencil';
|
||||
$subTitle = trans('firefly.edit_attachment', ['name' => $attachment->filename]);
|
||||
$subTitle = (string)trans('firefly.edit_attachment', ['name' => $attachment->filename]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('attachments.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('attachments.edit.uri');
|
||||
}
|
||||
$request->session()->forget('attachments.edit.fromUpdate');
|
||||
|
||||
$preFilled['notes'] = $this->repository->getNoteText($attachment);
|
||||
$preFilled = [
|
||||
'notes' => $this->repository->getNoteText($attachment),
|
||||
];
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
|
||||
return view('attachments.edit', compact('attachment', 'subTitleIcon', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Index of all attachments.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
@@ -164,6 +175,8 @@ class AttachmentController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Update attachment.
|
||||
*
|
||||
* @param AttachmentFormRequest $request
|
||||
* @param Attachment $attachment
|
||||
*
|
||||
@@ -191,6 +204,8 @@ class AttachmentController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* View attachment in browser.
|
||||
*
|
||||
* @param Attachment $attachment
|
||||
*
|
||||
* @return LaravelResponse
|
||||
|
@@ -36,17 +36,6 @@ use Illuminate\Support\Facades\Password;
|
||||
*/
|
||||
class ForgotPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset emails and
|
||||
| includes a trait which assists in sending these notifications from
|
||||
| your application to your users. Feel free to explore this trait.
|
||||
|
|
||||
*/
|
||||
|
||||
use SendsPasswordResetEmails;
|
||||
|
||||
/**
|
||||
@@ -75,7 +64,7 @@ class ForgotPasswordController extends Controller
|
||||
$user = User::where('email', $request->get('email'))->first();
|
||||
|
||||
if (null !== $user && $repository->hasRole($user, 'demo')) {
|
||||
return back()->withErrors(['email' => trans('firefly.cannot_reset_demo_user')]);
|
||||
return back()->withErrors(['email' => (string)trans('firefly.cannot_reset_demo_user')]);
|
||||
}
|
||||
|
||||
// We will send the password reset link to this user. Once we have attempted
|
||||
@@ -93,6 +82,8 @@ class ForgotPasswordController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show form for email recovery.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
|
@@ -32,12 +32,13 @@ use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Class LoginController
|
||||
*
|
||||
* This controller handles authenticating users for the application and
|
||||
* redirecting them to your home screen. The controller uses a trait
|
||||
* to conveniently provide its functionality to your applications.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class LoginController extends Controller
|
||||
{
|
||||
@@ -60,6 +61,8 @@ class LoginController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Log in a user.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response|void
|
||||
|
@@ -33,12 +33,13 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Class RegisterController
|
||||
*
|
||||
* This controller handles the registration of new users as well as their
|
||||
* validation and creation. By default this controller uses a trait to
|
||||
* provide this functionality without requiring any additional code.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
@@ -87,8 +88,9 @@ class RegisterController extends Controller
|
||||
|
||||
session()->flash('success', (string)trans('firefly.registered'));
|
||||
|
||||
return $this->registered($request, $user)
|
||||
?: redirect($this->redirectPath());
|
||||
$this->registered($request, $user);
|
||||
|
||||
return redirect($this->redirectPath());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -30,12 +30,13 @@ use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Class ResetPasswordController
|
||||
*
|
||||
* This controller is responsible for handling password reset requests
|
||||
* and uses a simple trait to include this behavior. You're free to
|
||||
* explore this trait and override any methods you wish to tweak.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
|
@@ -29,7 +29,6 @@ use FireflyIII\User;
|
||||
use Illuminate\Cookie\CookieJar;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class TwoFactorController.
|
||||
@@ -37,24 +36,26 @@ use Preferences;
|
||||
class TwoFactorController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show 2FA screen.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
|
||||
*
|
||||
* @throws FireflyException
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
// to make sure the validator in the next step gets the secret, we push it in session
|
||||
$secretPreference = Preferences::get('twoFactorAuthSecret', null);
|
||||
$secretPreference = app('preferences')->get('twoFactorAuthSecret', null);
|
||||
$secret = null === $secretPreference ? null : $secretPreference->data;
|
||||
$title = (string)trans('firefly.two_factor_title');
|
||||
|
||||
// make sure the user has two factor configured:
|
||||
$has2FA = Preferences::get('twoFactorAuthEnabled', false)->data;
|
||||
$has2FA = app('preferences')->get('twoFactorAuthEnabled', false)->data;
|
||||
if (null === $has2FA || false === $has2FA) {
|
||||
return redirect(route('index'));
|
||||
}
|
||||
@@ -68,6 +69,8 @@ class TwoFactorController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* What to do if 2FA lost?
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function lostTwoFactor()
|
||||
@@ -87,6 +90,8 @@ class TwoFactorController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit 2FA code.
|
||||
*
|
||||
* @param TokenFormRequest $request
|
||||
* @param CookieJar $cookieJar
|
||||
*
|
||||
|
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Requests\BillFormRequest;
|
||||
@@ -36,25 +37,25 @@ 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;
|
||||
|
||||
/**
|
||||
* Class BillController.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
*/
|
||||
class BillController extends Controller
|
||||
{
|
||||
/** @var AttachmentHelperInterface Helper for attachments. */
|
||||
private $attachments;
|
||||
/** @var BillRepositoryInterface */
|
||||
/** @var BillRepositoryInterface Bill repository */
|
||||
private $billRepository;
|
||||
/** @var RuleGroupRepositoryInterface */
|
||||
/** @var RuleGroupRepositoryInterface Rule group repository */
|
||||
private $ruleGroupRepos;
|
||||
|
||||
/**
|
||||
*
|
||||
* BillController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -63,11 +64,11 @@ class BillController extends Controller
|
||||
$maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize'));
|
||||
$maxPostSize = app('steam')->phpBytes(ini_get('post_max_size'));
|
||||
$uploadSize = min($maxFileSize, $maxPostSize);
|
||||
View::share('uploadSize', $uploadSize);
|
||||
app('view')->share('uploadSize', $uploadSize);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', trans('firefly.bills'));
|
||||
app('view')->share('title', (string)trans('firefly.bills'));
|
||||
app('view')->share('mainTitleIcon', 'fa-calendar-o');
|
||||
$this->attachments = app(AttachmentHelperInterface::class);
|
||||
$this->billRepository = app(BillRepositoryInterface::class);
|
||||
@@ -79,6 +80,8 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new bill.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
@@ -91,7 +94,7 @@ class BillController extends Controller
|
||||
foreach ($billPeriods as $current) {
|
||||
$periods[$current] = strtolower((string)trans('firefly.repeat_freq_' . $current));
|
||||
}
|
||||
$subTitle = trans('firefly.create_new_bill');
|
||||
$subTitle = (string)trans('firefly.create_new_bill');
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
@@ -104,6 +107,8 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bill.
|
||||
*
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
@@ -112,12 +117,14 @@ class BillController extends Controller
|
||||
{
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('bills.delete.uri');
|
||||
$subTitle = trans('firefly.delete_bill', ['name' => $bill->name]);
|
||||
$subTitle = (string)trans('firefly.delete_bill', ['name' => $bill->name]);
|
||||
|
||||
return view('bills.delete', compact('bill', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
@@ -135,6 +142,8 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
@@ -147,10 +156,10 @@ class BillController extends Controller
|
||||
$billPeriods = config('firefly.bill_periods');
|
||||
|
||||
foreach ($billPeriods as $current) {
|
||||
$periods[$current] = trans('firefly.' . $current);
|
||||
$periods[$current] = (string)trans('firefly.' . $current);
|
||||
}
|
||||
|
||||
$subTitle = trans('firefly.edit_bill', ['name' => $bill->name]);
|
||||
$subTitle = (string)trans('firefly.edit_bill', ['name' => $bill->name]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('bills.edit.fromUpdate')) {
|
||||
@@ -158,8 +167,8 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
$bill->amount_min = round($bill->amount_min, $currency->decimal_places);
|
||||
$bill->amount_max = round($bill->amount_max, $currency->decimal_places);
|
||||
$bill->amount_min = round((float)$bill->amount_min, $currency->decimal_places);
|
||||
$bill->amount_max = round((float)$bill->amount_max, $currency->decimal_places);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
|
||||
// code to handle active-checkboxes
|
||||
@@ -178,13 +187,15 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all bills.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$start = session('start');
|
||||
$end = session('end');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$paginator = $this->billRepository->getPaginator($pageSize);
|
||||
$parameters = new ParameterBag();
|
||||
$parameters->set('start', $start);
|
||||
@@ -218,6 +229,8 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Rescan bills for transactions.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
@@ -253,6 +266,8 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
@@ -263,11 +278,13 @@ class BillController extends Controller
|
||||
// add info about rules:
|
||||
$rules = $this->billRepository->getRulesForBill($bill);
|
||||
$subTitle = $bill->name;
|
||||
/** @var Carbon $start */
|
||||
$start = session('start');
|
||||
/** @var Carbon $end */
|
||||
$end = session('end');
|
||||
$year = $start->year;
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$yearAverage = $this->billRepository->getYearAverage($bill, $start);
|
||||
$overallAverage = $this->billRepository->getOverallAverage($bill);
|
||||
$manager = new Manager();
|
||||
@@ -295,9 +312,14 @@ class BillController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Store a new bill.
|
||||
*
|
||||
* @param BillFormRequest $request
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
public function store(BillFormRequest $request): RedirectResponse
|
||||
{
|
||||
@@ -316,7 +338,6 @@ class BillController extends Controller
|
||||
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
|
||||
$this->attachments->saveAttachmentsForModel($bill, $files);
|
||||
|
||||
// flash messages
|
||||
if (\count($this->attachments->getMessages()->get('attachments')) > 0) {
|
||||
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
|
||||
}
|
||||
@@ -348,6 +369,8 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a bill.
|
||||
*
|
||||
* @param BillFormRequest $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
|
213
app/Http/Controllers/Budget/AmountController.php
Normal file
213
app/Http/Controllers/Budget/AmountController.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
/**
|
||||
* AmountController.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\Controllers\Budget;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\BudgetIncomeRequest;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class AmountController
|
||||
*/
|
||||
class AmountController extends Controller
|
||||
{
|
||||
use DateCalculation;
|
||||
/** @var BudgetRepositoryInterface The budget repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* AmountController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
app('view')->share('hideBudgets', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.budgets'));
|
||||
app('view')->share('mainTitleIcon', 'fa-tasks');
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the amount for a single budget in a specific period. Shows a waring when its a lot.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
public function amount(Request $request, BudgetRepositoryInterface $repository, Budget $budget): JsonResponse
|
||||
{
|
||||
$amount = (string)$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);
|
||||
$spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end);
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
$left = app('amount')->formatAnything($currency, bcadd($amount, $spent), true);
|
||||
$largeDiff = false;
|
||||
$warnText = '';
|
||||
$leftPerDay = null;
|
||||
$periodLength = $start->diffInDays($end);
|
||||
$dayDifference = $this->getDayDifference($start, $end);
|
||||
|
||||
// If the user budgets ANY amount per day for this budget (anything but zero) Firefly III calculates how much he could spend per day.
|
||||
if (1 === bccomp(bcadd($amount, $spent), '0')) {
|
||||
$leftPerDay = app('amount')->formatAnything($currency, bcdiv(bcadd($amount, $spent), (string)$dayDifference), true);
|
||||
}
|
||||
|
||||
// Get the average amount of money the user budgets for this budget. And calculate the same for the current amount.
|
||||
// If the difference is very large, give the user a notification.
|
||||
$average = $this->repository->budgetedPerDay($budget);
|
||||
$current = bcdiv($amount, (string)$periodLength);
|
||||
if (bccomp(bcmul('1.1', $average), $current) === -1) {
|
||||
$largeDiff = true;
|
||||
$warnText = (string)trans(
|
||||
'firefly.over_budget_warn',
|
||||
[
|
||||
'amount' => app('amount')->formatAnything($currency, $average, false),
|
||||
'over_amount' => app('amount')->formatAnything($currency, $current, false),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
app('preferences')->mark();
|
||||
|
||||
return response()->json(
|
||||
['left' => $left, 'name' => $budget->name, 'limit' => $budgetLimit ? $budgetLimit->id : 0, 'amount' => $amount, 'current' => $current,
|
||||
'average' => $average, 'large_diff' => $largeDiff, 'left_per_day' => $leftPerDay, 'warn_text' => $warnText,]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows some basic info about the income and the suggested budget.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function infoIncome(Carbon $start, Carbon $end)
|
||||
{
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
/** @var Carbon $searchBegin */
|
||||
$searchBegin = app('navigation')->subtractPeriod($start, $range, 3);
|
||||
$searchEnd = app('navigation')->addPeriod($end, $range, 3);
|
||||
$daysInPeriod = $start->diffInDays($end);
|
||||
$daysInSearchPeriod = $searchBegin->diffInDays($searchEnd);
|
||||
$average = $this->repository->getAverageAvailable($start, $end);
|
||||
$available = bcmul($average, (string)$daysInPeriod);
|
||||
|
||||
// amount earned in this period:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($searchBegin, $searchEnd)->setTypes([TransactionType::DEPOSIT])->withOpposingAccount();
|
||||
$earned = (string)$collector->getJournals()->sum('transaction_amount');
|
||||
// Total amount earned divided by the number of days in the whole search period is the average amount earned per day.
|
||||
// This is multiplied by the number of days in the current period, showing you the average.
|
||||
$earnedAverage = bcmul(bcdiv($earned, (string)$daysInSearchPeriod), (string)$daysInPeriod);
|
||||
|
||||
// amount spent in period
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($searchBegin, $searchEnd)->setTypes([TransactionType::WITHDRAWAL])->withOpposingAccount();
|
||||
$spent = (string)$collector->getJournals()->sum('transaction_amount');
|
||||
$spentAverage = app('steam')->positive(bcmul(bcdiv($spent, (string)$daysInSearchPeriod), (string)$daysInPeriod));
|
||||
|
||||
// the default suggestion is the money the user has spent, on average, over this period.
|
||||
$suggested = $spentAverage;
|
||||
|
||||
// if the user makes less per period, suggest that amount instead.
|
||||
if (1 === bccomp($spentAverage, $earnedAverage)) {
|
||||
$suggested = $earnedAverage;
|
||||
}
|
||||
|
||||
$result = ['available' => $available, 'earned' => $earnedAverage, 'spent' => $spentAverage, 'suggested' => $suggested,];
|
||||
|
||||
return view('budgets.info', compact('result', 'searchBegin', 'searchEnd', 'start', 'end'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store an available budget for the current period.
|
||||
*
|
||||
* @param BudgetIncomeRequest $request
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function postUpdateIncome(BudgetIncomeRequest $request): RedirectResponse
|
||||
{
|
||||
$start = Carbon::createFromFormat('Y-m-d', $request->string('start'));
|
||||
$end = Carbon::createFromFormat('Y-m-d', $request->string('end'));
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$amount = $request->get('amount');
|
||||
$page = 0 === $request->integer('page') ? 1 : $request->integer('page');
|
||||
$this->repository->cleanupBudgets();
|
||||
$this->repository->setAvailableBudget($defaultCurrency, $start, $end, $amount);
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect(route('budgets.index', [$start->format('Y-m-d')]) . '?page=' . $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the form to update available budget.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
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 = (int)$request->get('page');
|
||||
|
||||
return view('budgets.income', compact('available', 'start', 'end', 'page'));
|
||||
}
|
||||
}
|
109
app/Http/Controllers/Budget/CreateController.php
Normal file
109
app/Http/Controllers/Budget/CreateController.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* CreateController.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\Controllers\Budget;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\BudgetFormRequest;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class CreateController
|
||||
*/
|
||||
class CreateController extends Controller
|
||||
{
|
||||
/** @var BudgetRepositoryInterface The budget repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* CreateController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
app('view')->share('hideBudgets', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.budgets'));
|
||||
app('view')->share('mainTitleIcon', 'fa-tasks');
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Form to create a budget.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function create(Request $request)
|
||||
{
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (true !== session('budgets.create.fromStore')) {
|
||||
$this->rememberPreviousUri('budgets.create.uri');
|
||||
}
|
||||
$request->session()->forget('budgets.create.fromStore');
|
||||
$subTitle = (string)trans('firefly.create_new_budget');
|
||||
|
||||
return view('budgets.create', compact('subTitle'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores a budget.
|
||||
*
|
||||
* @param BudgetFormRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(BudgetFormRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getBudgetData();
|
||||
$budget = $this->repository->store($data);
|
||||
$this->repository->cleanupBudgets();
|
||||
$request->session()->flash('success', (string)trans('firefly.stored_new_budget', ['name' => $budget->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
$redirect = redirect($this->getPreviousUri('budgets.create.uri'));
|
||||
|
||||
if (1 === (int)$request->get('create_another')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('budgets.create.fromStore', true);
|
||||
|
||||
$redirect = redirect(route('budgets.create'))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
}
|
97
app/Http/Controllers/Budget/DeleteController.php
Normal file
97
app/Http/Controllers/Budget/DeleteController.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* DeleteController.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\Controllers\Budget;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class DeleteController
|
||||
*/
|
||||
class DeleteController extends Controller
|
||||
{
|
||||
/** @var BudgetRepositoryInterface The budget repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* DeleteController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
app('view')->share('hideBudgets', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.budgets'));
|
||||
app('view')->share('mainTitleIcon', 'fa-tasks');
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes a budget.
|
||||
*
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function delete(Budget $budget)
|
||||
{
|
||||
$subTitle = (string)trans('firefly.delete_budget', ['name' => $budget->name]);
|
||||
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('budgets.delete.uri');
|
||||
|
||||
return view('budgets.delete', compact('budget', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a budget.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function destroy(Request $request, Budget $budget)
|
||||
{
|
||||
$name = $budget->name;
|
||||
$this->repository->destroy($budget);
|
||||
$request->session()->flash('success', (string)trans('firefly.deleted_budget', ['name' => $name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect($this->getPreviousUri('budgets.delete.uri'));
|
||||
}
|
||||
|
||||
}
|
120
app/Http/Controllers/Budget/EditController.php
Normal file
120
app/Http/Controllers/Budget/EditController.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* EditController.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\Controllers\Budget;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\BudgetFormRequest;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class EditController
|
||||
*/
|
||||
class EditController extends Controller
|
||||
{
|
||||
/** @var BudgetRepositoryInterface The budget repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* EditController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
app('view')->share('hideBudgets', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.budgets'));
|
||||
app('view')->share('mainTitleIcon', 'fa-tasks');
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Budget edit form.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function edit(Request $request, Budget $budget)
|
||||
{
|
||||
$subTitle = (string)trans('firefly.edit_budget', ['name' => $budget->name]);
|
||||
|
||||
// code to handle active-checkboxes
|
||||
$hasOldInput = null !== $request->old('_token');
|
||||
$preFilled = [
|
||||
'active' => $hasOldInput ? (bool)$request->old('active') : $budget->active,
|
||||
];
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('budgets.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('budgets.edit.uri');
|
||||
}
|
||||
$request->session()->forget('budgets.edit.fromUpdate');
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
|
||||
return view('budgets.edit', compact('budget', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Budget update routine.
|
||||
*
|
||||
* @param BudgetFormRequest $request
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(BudgetFormRequest $request, Budget $budget): RedirectResponse
|
||||
{
|
||||
$data = $request->getBudgetData();
|
||||
$this->repository->update($budget, $data);
|
||||
|
||||
$request->session()->flash('success', (string)trans('firefly.updated_budget', ['name' => $budget->name]));
|
||||
$this->repository->cleanupBudgets();
|
||||
app('preferences')->mark();
|
||||
|
||||
$redirect = redirect($this->getPreviousUri('budgets.edit.uri'));
|
||||
|
||||
if (1 === (int)$request->get('return_to_edit')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('budgets.edit.fromUpdate', true);
|
||||
|
||||
$redirect = redirect(route('budgets.edit', [$budget->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
}
|
146
app/Http/Controllers/Budget/IndexController.php
Normal file
146
app/Http/Controllers/Budget/IndexController.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* IndexController.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\Controllers\Budget;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class IndexController
|
||||
*/
|
||||
class IndexController extends Controller
|
||||
{
|
||||
|
||||
use DateCalculation;
|
||||
/** @var BudgetRepositoryInterface The budget repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* IndexController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
app('view')->share('hideBudgets', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.budgets'));
|
||||
app('view')->share('mainTitleIcon', 'fa-tasks');
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show all budgets.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string|null $moment
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
public function index(Request $request, string $moment = null)
|
||||
{
|
||||
/** @var string $range */
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
/** @var Carbon $start */
|
||||
$start = session('start', new Carbon);
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', new Carbon);
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$moment = $moment ?? '';
|
||||
|
||||
// make date if the data is given.
|
||||
if ('' !== (string)$moment) {
|
||||
try {
|
||||
$start = new Carbon($moment);
|
||||
/** @var Carbon $end */
|
||||
$end = app('navigation')->endOfPeriod($start, $range);
|
||||
} catch (Exception $e) {
|
||||
// start and end are already defined.
|
||||
Log::debug(sprintf('start and end are already defined: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// if today is between start and end, use the diff in days between end and today (days left)
|
||||
// otherwise, use diff between start and end.
|
||||
$dayDifference = $this->getDayDifference($start, $end);
|
||||
|
||||
$next = clone $end;
|
||||
$next->addDay();
|
||||
$prev = clone $start;
|
||||
$prev->subDay();
|
||||
$prev = app('navigation')->startOfPeriod($prev, $range);
|
||||
$this->repository->cleanupBudgets();
|
||||
$daysPassed = $this->getDaysPassedInPeriod($start, $end);
|
||||
$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($allBudgets, $start, $end);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$available = $this->repository->getAvailableBudget($defaultCurrency, $start, $end);
|
||||
$spent = array_sum(array_column($budgetInformation, 'spent'));
|
||||
$budgeted = array_sum(array_column($budgetInformation, 'budgeted'));
|
||||
$previousLoop = $this->getPreviousPeriods($start, $range);
|
||||
$nextLoop = $this->getNextPeriods($end, $range);
|
||||
|
||||
// paginate budgets
|
||||
$budgets = new LengthAwarePaginator($budgets, $total, $pageSize, $page);
|
||||
$budgets->setPath(route('budgets.index'));
|
||||
// display info
|
||||
$currentMonth = app('navigation')->periodShow($start, $range);
|
||||
$nextText = app('navigation')->periodShow($next, $range);
|
||||
$prevText = app('navigation')->periodShow($prev, $range);
|
||||
|
||||
return view(
|
||||
'budgets.index', compact(
|
||||
'available', 'currentMonth', 'next', 'nextText', 'prev', 'allBudgets', 'prevText', 'periodStart', 'periodEnd', 'dayDifference',
|
||||
'page',
|
||||
'budgetInformation', 'daysPassed',
|
||||
'inactive', 'budgets', 'spent', 'budgeted', 'previousLoop', 'nextLoop', 'start', 'end'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
293
app/Http/Controllers/Budget/ShowController.php
Normal file
293
app/Http/Controllers/Budget/ShowController.php
Normal file
@@ -0,0 +1,293 @@
|
||||
<?php
|
||||
/**
|
||||
* ShowController.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\Controllers\Budget;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class ShowController
|
||||
*/
|
||||
class ShowController extends Controller
|
||||
{
|
||||
|
||||
/** @var BudgetRepositoryInterface The budget repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* ShowController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
app('view')->share('hideBudgets', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.budgets'));
|
||||
app('view')->share('mainTitleIcon', 'fa-tasks');
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show transactions without a budget.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Carbon|null $start
|
||||
* @param Carbon|null $end
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function noBudget(Request $request, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = $start ?? session('start');
|
||||
/** @var Carbon $end */
|
||||
$end = $end ?? session('end');
|
||||
$subTitle = trans(
|
||||
'firefly.without_budget_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getPeriodOverview();
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setLimit($pageSize)->setPage($page)
|
||||
->withoutBudget()->withOpposingAccount();
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('budgets.no-budget'));
|
||||
|
||||
return view('budgets.no-budget', compact('transactions', 'subTitle', 'periods', 'start', 'end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows ALL transactions without a budget.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
|
||||
*/
|
||||
public function noBudgetAll(Request $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
$subTitle = (string)trans('firefly.all_journals_without_budget');
|
||||
$first = $repository->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$end = new Carbon;
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$moment = 'all';
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setLimit($pageSize)->setPage($page)
|
||||
->withoutBudget()->withOpposingAccount();
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('budgets.no-budget'));
|
||||
|
||||
return view('budgets.no-budget', compact('transactions', 'subTitle', 'moment', 'start', 'end'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show a single budget.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function show(Request $request, Budget $budget)
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = session('first', Carbon::create()->startOfYear());
|
||||
$end = new Carbon;
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$limits = $this->getLimits($budget, $start, $end);
|
||||
$repetition = null;
|
||||
|
||||
// collector:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setBudget($budget)->setLimit($pageSize)->setPage($page)->withBudgetInformation();
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('budgets.show', [$budget->id]));
|
||||
|
||||
$subTitle = (string)trans('firefly.all_journals_for_budget', ['name' => $budget->name]);
|
||||
|
||||
return view('budgets.show', compact('limits', 'budget', 'repetition', 'transactions', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a single budget by a budget limit.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Budget $budget
|
||||
* @param BudgetLimit $budgetLimit
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function showByBudgetLimit(Request $request, Budget $budget, BudgetLimit $budgetLimit)
|
||||
{
|
||||
if ($budgetLimit->budget->id !== $budget->id) {
|
||||
throw new FireflyException('This budget limit is not part of this budget.');
|
||||
}
|
||||
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$subTitle = trans(
|
||||
'firefly.budget_in_period',
|
||||
[
|
||||
'name' => $budget->name,
|
||||
'start' => $budgetLimit->start_date->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $budgetLimit->end_date->formatLocalized($this->monthAndDayFormat),
|
||||
]
|
||||
);
|
||||
|
||||
// collector:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($budgetLimit->start_date, $budgetLimit->end_date)
|
||||
->setBudget($budget)->setLimit($pageSize)->setPage($page)->withBudgetInformation();
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('budgets.show', [$budget->id, $budgetLimit->id]));
|
||||
/** @var Carbon $start */
|
||||
$start = session('first', Carbon::create()->startOfYear());
|
||||
$end = new Carbon;
|
||||
$limits = $this->getLimits($budget, $start, $end);
|
||||
|
||||
return view('budgets.show', compact('limits', 'budget', 'budgetLimit', 'transactions', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all budget limits for a budget.
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function getLimits(Budget $budget, Carbon $start, Carbon $end): Collection
|
||||
{
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($budget->id);
|
||||
$cache->addProperty('get-limits');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$set = $this->repository->getBudgetLimits($budget, $start, $end);
|
||||
$limits = new Collection();
|
||||
|
||||
/** @var BudgetLimit $entry */
|
||||
foreach ($set as $entry) {
|
||||
$entry->spent = $this->repository->spentInPeriod(new Collection([$budget]), new Collection(), $entry->start_date, $entry->end_date);
|
||||
$limits->push($entry);
|
||||
}
|
||||
$cache->store($limits);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets period overview used for budgets.
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
private function getPeriodOverview(): Collection
|
||||
{
|
||||
/** @var JournalRepositoryInterface $repository */
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$first = $repository->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$start = app('navigation')->startOfPeriod($start, $range);
|
||||
$end = app('navigation')->endOfX(new Carbon, $range, null);
|
||||
$entries = new Collection;
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('no-budget-period-entries');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
foreach ($dates as $date) {
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutBudget()->withOpposingAccount()->setTypes(
|
||||
[TransactionType::WITHDRAWAL]
|
||||
);
|
||||
$set = $collector->getJournals();
|
||||
$sum = (string)($set->sum('transaction_amount') ?? '0');
|
||||
$journals = $set->count();
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$dateStr = $date['end']->format('Y-m-d');
|
||||
$dateName = app('navigation')->periodShow($date['end'], $date['period']);
|
||||
$entries->push(
|
||||
['string' => $dateStr, 'name' => $dateName, 'count' => $journals, 'sum' => $sum, 'date' => clone $date['end'],
|
||||
'start' => $date['start'],
|
||||
'end' => $date['end'],
|
||||
|
||||
]
|
||||
);
|
||||
}
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
}
|
@@ -1,714 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* BudgetController.php
|
||||
* Copyright (c) 2017 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\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Requests\BudgetFormRequest;
|
||||
use FireflyIII\Http\Requests\BudgetIncomeRequest;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class BudgetController.
|
||||
*
|
||||
*/
|
||||
class BudgetController extends Controller
|
||||
{
|
||||
/** @var BudgetRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
View::share('hideBudgets', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', trans('firefly.budgets'));
|
||||
app('view')->share('mainTitleIcon', 'fa-tasks');
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function amount(Request $request, BudgetRepositoryInterface $repository, Budget $budget): JsonResponse
|
||||
{
|
||||
$amount = (string)$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);
|
||||
$largeDiff = false;
|
||||
$warnText = '';
|
||||
$days = 0;
|
||||
$daysInMonth = 0;
|
||||
if (0 === bccomp($amount, '0')) {
|
||||
$budgetLimit = null;
|
||||
}
|
||||
|
||||
// if today is between start and end, use the diff in days between end and today (days left)
|
||||
// otherwise, use diff between start and end.
|
||||
$today = new Carbon;
|
||||
Log::debug(sprintf('Start is %s, end is %s, today is %s', $start->format('Y-m-d'), $end->format('Y-m-d'), $today->format('Y-m-d')));
|
||||
if ($today->gte($start) && $today->lte($end)) {
|
||||
$days = $end->diffInDays($today);
|
||||
$daysInMonth = $start->diffInDays($today);
|
||||
}
|
||||
if ($today->lte($start) || $today->gte($end)) {
|
||||
$days = $start->diffInDays($end);
|
||||
$daysInMonth = $start->diffInDays($end);
|
||||
}
|
||||
$days = 0 === $days ? 1 : $days;
|
||||
$daysInMonth = 0 === $daysInMonth ? 1 : $daysInMonth;
|
||||
|
||||
// calculate left in budget:
|
||||
$spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end);
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
$left = app('amount')->formatAnything($currency, bcadd($amount, $spent), true);
|
||||
$leftPerDay = 'none';
|
||||
|
||||
// is user has money left, calculate.
|
||||
if (1 === bccomp(bcadd($amount, $spent), '0')) {
|
||||
$leftPerDay = app('amount')->formatAnything($currency, bcdiv(bcadd($amount, $spent), (string)$days), true);
|
||||
}
|
||||
|
||||
|
||||
// over or under budgeting, compared to previous budgets?
|
||||
$average = $this->repository->budgetedPerDay($budget);
|
||||
// current average per day:
|
||||
$diff = $start->diffInDays($end);
|
||||
$current = $amount;
|
||||
if ($diff > 0) {
|
||||
$current = bcdiv($amount, (string)$diff);
|
||||
}
|
||||
if (bccomp(bcmul('1.1', $average), $current) === -1) {
|
||||
$largeDiff = true;
|
||||
$warnText = (string)trans(
|
||||
'firefly.over_budget_warn',
|
||||
[
|
||||
'amount' => app('amount')->formatAnything($currency, $average, false),
|
||||
'over_amount' => app('amount')->formatAnything($currency, $current, false),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
app('preferences')->mark();
|
||||
|
||||
return response()->json(
|
||||
[
|
||||
'left' => $left,
|
||||
'name' => $budget->name,
|
||||
'limit' => $budgetLimit ? $budgetLimit->id : 0,
|
||||
'amount' => $amount,
|
||||
'current' => $current,
|
||||
'average' => $average,
|
||||
'large_diff' => $largeDiff,
|
||||
'left_per_day' => $leftPerDay,
|
||||
'warn_text' => $warnText,
|
||||
'daysInMonth' => $daysInMonth,
|
||||
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function create(Request $request)
|
||||
{
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (true !== session('budgets.create.fromStore')) {
|
||||
$this->rememberPreviousUri('budgets.create.uri');
|
||||
}
|
||||
$request->session()->forget('budgets.create.fromStore');
|
||||
$subTitle = (string)trans('firefly.create_new_budget');
|
||||
|
||||
return view('budgets.create', compact('subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function delete(Budget $budget)
|
||||
{
|
||||
$subTitle = trans('firefly.delete_budget', ['name' => $budget->name]);
|
||||
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('budgets.delete.uri');
|
||||
|
||||
return view('budgets.delete', compact('budget', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function destroy(Request $request, Budget $budget)
|
||||
{
|
||||
$name = $budget->name;
|
||||
$this->repository->destroy($budget);
|
||||
$request->session()->flash('success', (string)trans('firefly.deleted_budget', ['name' => $name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect($this->getPreviousUri('budgets.delete.uri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function edit(Request $request, Budget $budget)
|
||||
{
|
||||
$subTitle = trans('firefly.edit_budget', ['name' => $budget->name]);
|
||||
|
||||
// code to handle active-checkboxes
|
||||
$hasOldInput = null !== $request->old('_token');
|
||||
$preFilled = [
|
||||
'active' => $hasOldInput ? (bool)$request->old('active') : $budget->active,
|
||||
];
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('budgets.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('budgets.edit.uri');
|
||||
}
|
||||
$request->session()->forget('budgets.edit.fromUpdate');
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
|
||||
return view('budgets.edit', compact('budget', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param string|null $moment
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request, string $moment = null)
|
||||
{
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = session('start', new Carbon);
|
||||
$end = session('end', new Carbon);
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$days = 0;
|
||||
$daysInMonth = 0;
|
||||
|
||||
// make date if present:
|
||||
if (null !== $moment || '' !== (string)$moment) {
|
||||
try {
|
||||
$start = new Carbon($moment);
|
||||
$end = app('navigation')->endOfPeriod($start, $range);
|
||||
} catch (Exception $e) {
|
||||
// start and end are already defined.
|
||||
Log::debug(sprintf('start and end are already defined: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// if today is between start and end, use the diff in days between end and today (days left)
|
||||
// otherwise, use diff between start and end.
|
||||
$today = new Carbon;
|
||||
if ($today->gte($start) && $today->lte($end)) {
|
||||
$days = $end->diffInDays($today);
|
||||
$daysInMonth = $start->diffInDays($today);
|
||||
}
|
||||
if ($today->lte($start) || $today->gte($end)) {
|
||||
$days = $start->diffInDays($end);
|
||||
$daysInMonth = $start->diffInDays($end);
|
||||
}
|
||||
$days = 0 === $days ? 1 : $days;
|
||||
$daysInMonth = 0 === $daysInMonth ? 1 : $daysInMonth;
|
||||
|
||||
|
||||
$next = clone $end;
|
||||
$next->addDay();
|
||||
$prev = clone $start;
|
||||
$prev->subDay();
|
||||
$prev = app('navigation')->startOfPeriod($prev, $range);
|
||||
$this->repository->cleanupBudgets();
|
||||
$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($allBudgets, $start, $end);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$available = $this->repository->getAvailableBudget($defaultCurrency, $start, $end);
|
||||
$spent = array_sum(array_column($budgetInformation, 'spent'));
|
||||
$budgeted = array_sum(array_column($budgetInformation, 'budgeted'));
|
||||
|
||||
// paginate budgets
|
||||
$budgets = new LengthAwarePaginator($budgets, $total, $pageSize, $page);
|
||||
$budgets->setPath(route('budgets.index'));
|
||||
|
||||
// select thing for last 12 periods:
|
||||
$previousLoop = [];
|
||||
/** @var Carbon $previousDate */
|
||||
$previousDate = clone $start;
|
||||
$count = 0;
|
||||
while ($count < 12) {
|
||||
$previousDate->subDay();
|
||||
$previousDate = app('navigation')->startOfPeriod($previousDate, $range);
|
||||
$format = $previousDate->format('Y-m-d');
|
||||
$previousLoop[$format] = app('navigation')->periodShow($previousDate, $range);
|
||||
++$count;
|
||||
}
|
||||
|
||||
// select thing for next 12 periods:
|
||||
$nextLoop = [];
|
||||
/** @var Carbon $nextDate */
|
||||
$nextDate = clone $end;
|
||||
$nextDate->addDay();
|
||||
$count = 0;
|
||||
|
||||
while ($count < 12) {
|
||||
$format = $nextDate->format('Y-m-d');
|
||||
$nextLoop[$format] = app('navigation')->periodShow($nextDate, $range);
|
||||
$nextDate = app('navigation')->endOfPeriod($nextDate, $range);
|
||||
++$count;
|
||||
$nextDate->addDay();
|
||||
}
|
||||
|
||||
// display info
|
||||
$currentMonth = app('navigation')->periodShow($start, $range);
|
||||
$nextText = app('navigation')->periodShow($next, $range);
|
||||
$prevText = app('navigation')->periodShow($prev, $range);
|
||||
|
||||
return view(
|
||||
'budgets.index', compact(
|
||||
'available', 'currentMonth', 'next', 'nextText', 'prev', 'allBudgets', 'prevText', 'periodStart', 'periodEnd', 'days', 'page',
|
||||
'budgetInformation', 'daysInMonth',
|
||||
'inactive', 'budgets', 'spent', 'budgeted', 'previousLoop', 'nextLoop', 'start', 'end'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function infoIncome(Carbon $start, Carbon $end)
|
||||
{
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('info-income');
|
||||
|
||||
Log::debug(sprintf('infoIncome start is %s', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('infoIncome end is %s', $end->format('Y-m-d')));
|
||||
|
||||
if ($cache->has()) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$result = $cache->get();
|
||||
|
||||
return view('budgets.info', compact('result'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$result = [
|
||||
'available' => '0',
|
||||
'earned' => '0',
|
||||
'suggested' => '0',
|
||||
];
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
/** @var Carbon $begin */
|
||||
$begin = app('navigation')->subtractPeriod($start, $range, 3);
|
||||
|
||||
Log::debug(sprintf('Range is %s', $range));
|
||||
Log::debug(sprintf('infoIncome begin is %s', $begin->format('Y-m-d')));
|
||||
|
||||
// get average amount available.
|
||||
$total = '0';
|
||||
$count = 0;
|
||||
$currentStart = clone $begin;
|
||||
while ($currentStart < $start) {
|
||||
|
||||
Log::debug(sprintf('Loop: currentStart is %s', $currentStart->format('Y-m-d')));
|
||||
$currentEnd = app('navigation')->endOfPeriod($currentStart, $range);
|
||||
$total = bcadd($total, $this->repository->getAvailableBudget($currency, $currentStart, $currentEnd));
|
||||
$currentStart = app('navigation')->addPeriod($currentStart, $range, 0);
|
||||
++$count;
|
||||
}
|
||||
Log::debug('Loop end');
|
||||
|
||||
if (0 === $count) {
|
||||
$count = 1;
|
||||
}
|
||||
$result['available'] = bcdiv($total, (string)$count);
|
||||
|
||||
// amount earned in this period:
|
||||
$subDay = clone $end;
|
||||
$subDay->subDay();
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($begin, $subDay)->setTypes([TransactionType::DEPOSIT])->withOpposingAccount();
|
||||
$result['earned'] = bcdiv((string)$collector->getJournals()->sum('transaction_amount'), (string)$count);
|
||||
|
||||
// amount spent in period
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($begin, $subDay)->setTypes([TransactionType::WITHDRAWAL])->withOpposingAccount();
|
||||
$result['spent'] = bcdiv((string)$collector->getJournals()->sum('transaction_amount'), (string)$count);
|
||||
// suggestion starts with the amount spent
|
||||
$result['suggested'] = bcmul($result['spent'], '-1');
|
||||
$result['suggested'] = 1 === bccomp($result['suggested'], $result['earned']) ? $result['earned'] : $result['suggested'];
|
||||
// unless it's more than you earned. So min() of suggested/earned
|
||||
|
||||
$cache->store($result);
|
||||
|
||||
return view('budgets.info', compact('result', 'begin', 'currentEnd'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param string|null $moment
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function noBudget(Request $request, JournalRepositoryInterface $repository, string $moment = null)
|
||||
{
|
||||
// default values:
|
||||
$moment = $moment ?? '';
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
|
||||
// prep for "all" view.
|
||||
if ('all' === $moment) {
|
||||
$subTitle = trans('firefly.all_journals_without_budget');
|
||||
$first = $repository->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$end = new Carbon;
|
||||
}
|
||||
|
||||
// prep for "specific date" view.
|
||||
if ('all' !== $moment && \strlen($moment) > 0) {
|
||||
$start = new Carbon($moment);
|
||||
/** @var Carbon $end */
|
||||
$end = app('navigation')->endOfPeriod($start, $range);
|
||||
$subTitle = trans(
|
||||
'firefly.without_budget_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getPeriodOverview();
|
||||
}
|
||||
|
||||
// prep for current period
|
||||
if ('' === $moment) {
|
||||
$start = clone session('start', app('navigation')->startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', app('navigation')->endOfPeriod(new Carbon, $range));
|
||||
$periods = $this->getPeriodOverview();
|
||||
$subTitle = trans(
|
||||
'firefly.without_budget_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setLimit($pageSize)->setPage($page)
|
||||
->withoutBudget()->withOpposingAccount();
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('budgets.no-budget'));
|
||||
|
||||
return view('budgets.no-budget', compact('transactions', 'subTitle', 'moment', 'periods', 'start', 'end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetIncomeRequest $request
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function postUpdateIncome(BudgetIncomeRequest $request): RedirectResponse
|
||||
{
|
||||
$start = Carbon::createFromFormat('Y-m-d', $request->string('start'));
|
||||
$end = Carbon::createFromFormat('Y-m-d', $request->string('end'));
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$amount = $request->get('amount');
|
||||
$page = 0 === $request->integer('page') ? 1 : $request->integer('page');
|
||||
$this->repository->cleanupBudgets();
|
||||
$this->repository->setAvailableBudget($defaultCurrency, $start, $end, $amount);
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect(route('budgets.index', [$start->format('Y-m-d')]) . '?page=' . $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function show(Request $request, Budget $budget)
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = session('first', Carbon::create()->startOfYear());
|
||||
$end = new Carbon;
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$limits = $this->getLimits($budget, $start, $end);
|
||||
$repetition = null;
|
||||
|
||||
// collector:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setBudget($budget)->setLimit($pageSize)->setPage($page)->withBudgetInformation();
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('budgets.show', [$budget->id]));
|
||||
|
||||
$subTitle = trans('firefly.all_journals_for_budget', ['name' => $budget->name]);
|
||||
|
||||
return view('budgets.show', compact('limits', 'budget', 'repetition', 'transactions', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Budget $budget
|
||||
* @param BudgetLimit $budgetLimit
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function showByBudgetLimit(Request $request, Budget $budget, BudgetLimit $budgetLimit)
|
||||
{
|
||||
if ($budgetLimit->budget->id !== $budget->id) {
|
||||
throw new FireflyException('This budget limit is not part of this budget.');
|
||||
}
|
||||
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$subTitle = trans(
|
||||
'firefly.budget_in_period',
|
||||
[
|
||||
'name' => $budget->name,
|
||||
'start' => $budgetLimit->start_date->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $budgetLimit->end_date->formatLocalized($this->monthAndDayFormat),
|
||||
]
|
||||
);
|
||||
|
||||
// collector:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($budgetLimit->start_date, $budgetLimit->end_date)
|
||||
->setBudget($budget)->setLimit($pageSize)->setPage($page)->withBudgetInformation();
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('budgets.show', [$budget->id, $budgetLimit->id]));
|
||||
$start = session('first', Carbon::create()->startOfYear());
|
||||
$end = new Carbon;
|
||||
$limits = $this->getLimits($budget, $start, $end);
|
||||
|
||||
return view('budgets.show', compact('limits', 'budget', 'budgetLimit', 'transactions', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetFormRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(BudgetFormRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getBudgetData();
|
||||
$budget = $this->repository->store($data);
|
||||
$this->repository->cleanupBudgets();
|
||||
$request->session()->flash('success', (string)trans('firefly.stored_new_budget', ['name' => $budget->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
$redirect = redirect($this->getPreviousUri('budgets.create.uri'));
|
||||
|
||||
if (1 === (int)$request->get('create_another')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('budgets.create.fromStore', true);
|
||||
|
||||
$redirect = redirect(route('budgets.create'))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param BudgetFormRequest $request
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(BudgetFormRequest $request, Budget $budget): RedirectResponse
|
||||
{
|
||||
$data = $request->getBudgetData();
|
||||
$this->repository->update($budget, $data);
|
||||
|
||||
$request->session()->flash('success', (string)trans('firefly.updated_budget', ['name' => $budget->name]));
|
||||
$this->repository->cleanupBudgets();
|
||||
app('preferences')->mark();
|
||||
|
||||
$redirect = redirect($this->getPreviousUri('budgets.edit.uri'));
|
||||
|
||||
if (1 === (int)$request->get('return_to_edit')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('budgets.edit.fromUpdate', true);
|
||||
|
||||
$redirect = redirect(route('budgets.edit', [$budget->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
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 = (int)$request->get('page');
|
||||
|
||||
return view('budgets.income', compact('available', 'start', 'end', 'page'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function getLimits(Budget $budget, Carbon $start, Carbon $end): Collection
|
||||
{
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($budget->id);
|
||||
$cache->addProperty('get-limits');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$set = $this->repository->getBudgetLimits($budget, $start, $end);
|
||||
$limits = new Collection();
|
||||
|
||||
/** @var BudgetLimit $entry */
|
||||
foreach ($set as $entry) {
|
||||
$entry->spent = $this->repository->spentInPeriod(new Collection([$budget]), new Collection(), $entry->start_date, $entry->end_date);
|
||||
$limits->push($entry);
|
||||
}
|
||||
$cache->store($limits);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getPeriodOverview(): Collection
|
||||
{
|
||||
/** @var JournalRepositoryInterface $repository */
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$first = $repository->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = app('navigation')->startOfPeriod($start, $range);
|
||||
$end = app('navigation')->endOfX(new Carbon, $range, null);
|
||||
$entries = new Collection;
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('no-budget-period-entries');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
foreach ($dates as $date) {
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutBudget()->withOpposingAccount()->setTypes(
|
||||
[TransactionType::WITHDRAWAL]
|
||||
);
|
||||
$set = $collector->getJournals();
|
||||
$sum = (string)($set->sum('transaction_amount') ?? '0');
|
||||
$journals = $set->count();
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$dateStr = $date['end']->format('Y-m-d');
|
||||
$dateName = app('navigation')->periodShow($date['end'], $date['period']);
|
||||
$entries->push(['string' => $dateStr, 'name' => $dateName, 'count' => $journals, 'sum' => $sum, 'date' => clone $date['end']]);
|
||||
}
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
}
|
230
app/Http/Controllers/Category/NoCategoryController.php
Normal file
230
app/Http/Controllers/Category/NoCategoryController.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
/**
|
||||
* NoCategoryController.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\Controllers\Category;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class NoCategoryController
|
||||
*/
|
||||
class NoCategoryController extends Controller
|
||||
{
|
||||
|
||||
/** @var JournalRepositoryInterface Journals and transactions overview */
|
||||
private $journalRepos;
|
||||
|
||||
/**
|
||||
* CategoryController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.categories'));
|
||||
app('view')->share('mainTitleIcon', 'fa-bar-chart');
|
||||
$this->journalRepos = app(JournalRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show transactions without a category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Carbon|null $start
|
||||
* @param Carbon|null $end
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function show(Request $request, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
Log::debug('Start of noCategory()');
|
||||
/** @var Carbon $start */
|
||||
$start = $start ?? session('start');
|
||||
/** @var Carbon $end */
|
||||
$end = $end ?? session('end');
|
||||
$moment = '';
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$subTitle = trans(
|
||||
'firefly.without_category_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getNoCategoryPeriodOverview($start);
|
||||
|
||||
Log::debug(sprintf('Start for noCategory() is %s', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('End for noCategory() is %s', $end->format('Y-m-d')));
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutCategory()->withOpposingAccount()
|
||||
->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('categories.no-category'));
|
||||
|
||||
return view('categories.no-category', compact('transactions', 'subTitle', 'moment', 'periods', 'start', 'end'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show all transactions without a category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string|null $moment
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function showAll(Request $request, string $moment = null)
|
||||
{
|
||||
// default values:
|
||||
$moment = $moment ?? '';
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
Log::debug('Start of noCategory()');
|
||||
$subTitle = (string)trans('firefly.all_journals_without_category');
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$end = new Carbon;
|
||||
Log::debug(sprintf('Start for noCategory() is %s', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('End for noCategory() is %s', $end->format('Y-m-d')));
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutCategory()->withOpposingAccount()
|
||||
->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('categories.no-category'));
|
||||
|
||||
return view('categories.no-category', compact('transactions', 'subTitle', 'moment', 'periods', 'start', 'end'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show period overview for no category view.
|
||||
*
|
||||
* @param Carbon $theDate
|
||||
*
|
||||
* @return Collection
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
private function getNoCategoryPeriodOverview(Carbon $theDate): Collection
|
||||
{
|
||||
Log::debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d')));
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$end = $theDate ?? new Carbon;
|
||||
|
||||
Log::debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d')));
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('no-category-period-entries');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
foreach ($dates as $date) {
|
||||
|
||||
// count journals without category in this period:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutCategory()
|
||||
->withOpposingAccount()->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$count = $collector->getJournals()->count();
|
||||
|
||||
// amount transferred
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutCategory()
|
||||
->withOpposingAccount()->setTypes([TransactionType::TRANSFER]);
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transferred = app('steam')->positive((string)$collector->getJournals()->sum('transaction_amount'));
|
||||
|
||||
// amount spent
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutCategory()->withOpposingAccount()->setTypes(
|
||||
[TransactionType::WITHDRAWAL]
|
||||
);
|
||||
$spent = $collector->getJournals()->sum('transaction_amount');
|
||||
|
||||
// amount earned
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutCategory()->withOpposingAccount()->setTypes(
|
||||
[TransactionType::DEPOSIT]
|
||||
);
|
||||
$earned = $collector->getJournals()->sum('transaction_amount');
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$dateStr = $date['end']->format('Y-m-d');
|
||||
$dateName = app('navigation')->periodShow($date['end'], $date['period']);
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'count' => $count,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'transferred' => $transferred,
|
||||
'start' => clone $date['start'],
|
||||
'end' => clone $date['end'],
|
||||
]
|
||||
);
|
||||
}
|
||||
Log::debug('End of loops');
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
}
|
226
app/Http/Controllers/Category/ShowController.php
Normal file
226
app/Http/Controllers/Category/ShowController.php
Normal file
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/**
|
||||
* ShowController.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\Controllers\Category;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class ShowController
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
*/
|
||||
class ShowController extends Controller
|
||||
{
|
||||
|
||||
/** @var AccountRepositoryInterface The account repository */
|
||||
private $accountRepos;
|
||||
/** @var JournalRepositoryInterface Journals and transactions overview */
|
||||
private $journalRepos;
|
||||
/** @var CategoryRepositoryInterface The category repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* CategoryController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.categories'));
|
||||
app('view')->share('mainTitleIcon', 'fa-bar-chart');
|
||||
$this->journalRepos = app(JournalRepositoryInterface::class);
|
||||
$this->repository = app(CategoryRepositoryInterface::class);
|
||||
$this->accountRepos = app(AccountRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Show a single category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Category $category
|
||||
* @param Carbon|null $start
|
||||
* @param Carbon|null $end
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function show(Request $request, Category $category, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
Log::debug('Now in show()');
|
||||
/** @var Carbon $start */
|
||||
$start = $start ?? session('start', Carbon::create()->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = $end ?? session('end', Carbon::create()->startOfMonth());
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$moment = '';
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$periods = $this->getPeriodOverview($category, $start);
|
||||
$path = route('categories.show', [$category->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_category',
|
||||
['name' => $category->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat),]
|
||||
);
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
|
||||
->setCategory($category)->withBudgetInformation()->withCategoryInformation();
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath($path);
|
||||
|
||||
Log::debug('End of show()');
|
||||
|
||||
return view('categories.show', compact('category', 'transactions', 'moment', 'periods', 'subTitle', 'subTitleIcon', 'start', 'end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all transactions within a category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Category $category
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function showAll(Request $request, Category $category)
|
||||
{
|
||||
// default values:
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
$moment = 'all';
|
||||
|
||||
$subTitle = (string)trans('firefly.all_journals_for_category', ['name' => $category->name]);
|
||||
$first = $this->repository->firstUseDate($category);
|
||||
/** @var Carbon $start */
|
||||
$start = $first ?? new Carbon;
|
||||
$end = new Carbon;
|
||||
$path = route('categories.show-all', [$category->id]);
|
||||
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
|
||||
->setCategory($category)->withBudgetInformation()->withCategoryInformation();
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath($path);
|
||||
|
||||
return view('categories.show', compact('category', 'moment', 'transactions', 'periods', 'subTitle', 'subTitleIcon', 'start', 'end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a period overview for category.
|
||||
*
|
||||
* @param Category $category
|
||||
*
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
private function getPeriodOverview(Category $category, Carbon $date): Collection
|
||||
{
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$end = $date ?? new Carbon;
|
||||
$accounts = $this->accountRepos->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||
|
||||
// properties for entries with their amounts.
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($range);
|
||||
$cache->addProperty('categories.entries');
|
||||
$cache->addProperty($category->id);
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
foreach ($dates as $currentDate) {
|
||||
$spent = $this->repository->spentInPeriod(new Collection([$category]), $accounts, $currentDate['start'], $currentDate['end']);
|
||||
$earned = $this->repository->earnedInPeriod(new Collection([$category]), $accounts, $currentDate['start'], $currentDate['end']);
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$dateStr = $currentDate['end']->format('Y-m-d');
|
||||
$dateName = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||
|
||||
// amount transferred
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($currentDate['start'], $currentDate['end'])->setCategory($category)
|
||||
->withOpposingAccount()->setTypes([TransactionType::TRANSFER]);
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transferred = app('steam')->positive((string)$collector->getJournals()->sum('transaction_amount'));
|
||||
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'sum' => bcadd($earned, $spent),
|
||||
'transferred' => $transferred,
|
||||
'start' => clone $currentDate['start'],
|
||||
'end' => clone $currentDate['end'],
|
||||
]
|
||||
);
|
||||
}
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
}
|
@@ -22,33 +22,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
use FireflyIII\Http\Requests\CategoryFormRequest;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class CategoryController.
|
||||
*/
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $accountRepos;
|
||||
/** @var JournalRepositoryInterface */
|
||||
private $journalRepos;
|
||||
/** @var CategoryRepositoryInterface */
|
||||
/** @var CategoryRepositoryInterface The category repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
@@ -60,11 +46,9 @@ class CategoryController extends Controller
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', trans('firefly.categories'));
|
||||
app('view')->share('title', (string)trans('firefly.categories'));
|
||||
app('view')->share('mainTitleIcon', 'fa-bar-chart');
|
||||
$this->journalRepos = app(JournalRepositoryInterface::class);
|
||||
$this->repository = app(CategoryRepositoryInterface::class);
|
||||
$this->accountRepos = app(AccountRepositoryInterface::class);
|
||||
$this->repository = app(CategoryRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
@@ -72,6 +56,8 @@ class CategoryController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Create category.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
@@ -82,19 +68,21 @@ class CategoryController extends Controller
|
||||
$this->rememberPreviousUri('categories.create.uri');
|
||||
}
|
||||
$request->session()->forget('categories.create.fromStore');
|
||||
$subTitle = trans('firefly.create_new_category');
|
||||
$subTitle = (string)trans('firefly.create_new_category');
|
||||
|
||||
return view('categories.create', compact('subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a category.
|
||||
*
|
||||
* @param Category $category
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function delete(Category $category)
|
||||
{
|
||||
$subTitle = trans('firefly.delete_category', ['name' => $category->name]);
|
||||
$subTitle = (string)trans('firefly.delete_category', ['name' => $category->name]);
|
||||
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('categories.delete.uri');
|
||||
@@ -103,6 +91,8 @@ class CategoryController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Category $category
|
||||
*
|
||||
@@ -120,6 +110,8 @@ class CategoryController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Category $category
|
||||
*
|
||||
@@ -127,7 +119,7 @@ class CategoryController extends Controller
|
||||
*/
|
||||
public function edit(Request $request, Category $category)
|
||||
{
|
||||
$subTitle = trans('firefly.edit_category', ['name' => $category->name]);
|
||||
$subTitle = (string)trans('firefly.edit_category', ['name' => $category->name]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('categories.edit.fromUpdate')) {
|
||||
@@ -139,6 +131,8 @@ class CategoryController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all categories.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
@@ -146,7 +140,7 @@ class CategoryController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$collection = $this->repository->getCategories();
|
||||
$total = $collection->count();
|
||||
$collection = $collection->slice(($page - 1) * $pageSize, $pageSize);
|
||||
@@ -164,141 +158,10 @@ class CategoryController extends Controller
|
||||
return view('categories.index', compact('categories'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param string|null $moment
|
||||
* Store new category.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function noCategory(Request $request, string $moment = null)
|
||||
{
|
||||
// default values:
|
||||
$moment = $moment ?? '';
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
Log::debug('Start of noCategory()');
|
||||
// prep for "all" view.
|
||||
if ('all' === $moment) {
|
||||
$subTitle = trans('firefly.all_journals_without_category');
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$end = new Carbon;
|
||||
Log::debug('Moment is all()');
|
||||
}
|
||||
|
||||
// prep for "specific date" view.
|
||||
if ('all' !== $moment && \strlen($moment) > 0) {
|
||||
/** @var Carbon $start */
|
||||
$start = app('navigation')->startOfPeriod(new Carbon($moment), $range);
|
||||
/** @var Carbon $end */
|
||||
$end = app('navigation')->endOfPeriod($start, $range);
|
||||
$subTitle = trans(
|
||||
'firefly.without_category_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getNoCategoryPeriodOverview($start);
|
||||
|
||||
}
|
||||
|
||||
// prep for current period
|
||||
if ('' === $moment) {
|
||||
$start = clone session('start', app('navigation')->startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', app('navigation')->endOfPeriod(new Carbon, $range));
|
||||
$periods = $this->getNoCategoryPeriodOverview($start);
|
||||
$subTitle = trans(
|
||||
'firefly.without_category_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
Log::debug(sprintf('Start for noCategory() is %s', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('End for noCategory() is %s', $end->format('Y-m-d')));
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutCategory()->withOpposingAccount()
|
||||
->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath(route('categories.no-category'));
|
||||
|
||||
return view('categories.no-category', compact('transactions', 'subTitle', 'moment', 'periods', 'start', 'end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Category $category
|
||||
* @param string|null $moment
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function show(Request $request, Category $category, string $moment = null)
|
||||
{
|
||||
// default values:
|
||||
$moment = $moment ?? '';
|
||||
$subTitle = $category->name;
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
$path = route('categories.show', [$category->id]);
|
||||
|
||||
// prep for "all" view.
|
||||
if ('all' === $moment) {
|
||||
$subTitle = trans('firefly.all_journals_for_category', ['name' => $category->name]);
|
||||
$first = $this->repository->firstUseDate($category);
|
||||
/** @var Carbon $start */
|
||||
$start = $first ?? new Carbon;
|
||||
$end = new Carbon;
|
||||
$path = route('categories.show', [$category->id, 'all']);
|
||||
}
|
||||
|
||||
// prep for "specific date" view.
|
||||
if ('all' !== $moment && \strlen($moment) > 0) {
|
||||
$start = app('navigation')->startOfPeriod(new Carbon($moment), $range);
|
||||
/** @var Carbon $end */
|
||||
$end = app('navigation')->endOfPeriod($start, $range);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_category',
|
||||
['name' => $category->name,
|
||||
'start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat),]
|
||||
);
|
||||
$periods = $this->getPeriodOverview($category, $start);
|
||||
$path = route('categories.show', [$category->id, $moment]);
|
||||
}
|
||||
|
||||
// prep for current period
|
||||
if ('' === $moment) {
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', app('navigation')->startOfPeriod(new Carbon, $range));
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', app('navigation')->endOfPeriod(new Carbon, $range));
|
||||
$periods = $this->getPeriodOverview($category, $start);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_category',
|
||||
['name' => $category->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat),]
|
||||
);
|
||||
}
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
|
||||
->setCategory($category)->withBudgetInformation()->withCategoryInformation();
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transactions = $collector->getPaginatedJournals();
|
||||
$transactions->setPath($path);
|
||||
|
||||
return view('categories.show', compact('category', 'moment', 'transactions', 'periods', 'subTitle', 'subTitleIcon', 'start', 'end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CategoryFormRequest $request
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
*
|
||||
@@ -326,6 +189,8 @@ class CategoryController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Update category.
|
||||
*
|
||||
* @param CategoryFormRequest $request
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
* @param Category $category
|
||||
@@ -354,149 +219,4 @@ class CategoryController extends Controller
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Carbon $theDate
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function getNoCategoryPeriodOverview(Carbon $theDate): Collection
|
||||
{
|
||||
Log::debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d')));
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$end = $theDate ?? new Carbon;
|
||||
|
||||
Log::debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d')));
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('no-category-period-entries');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
foreach ($dates as $date) {
|
||||
|
||||
// count journals without category in this period:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutCategory()
|
||||
->withOpposingAccount()->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$count = $collector->getJournals()->count();
|
||||
|
||||
// amount transferred
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutCategory()
|
||||
->withOpposingAccount()->setTypes([TransactionType::TRANSFER]);
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transferred = app('steam')->positive((string)$collector->getJournals()->sum('transaction_amount'));
|
||||
|
||||
// amount spent
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutCategory()->withOpposingAccount()->setTypes(
|
||||
[TransactionType::WITHDRAWAL]
|
||||
);
|
||||
$spent = $collector->getJournals()->sum('transaction_amount');
|
||||
|
||||
// amount earned
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->withoutCategory()->withOpposingAccount()->setTypes(
|
||||
[TransactionType::DEPOSIT]
|
||||
);
|
||||
$earned = $collector->getJournals()->sum('transaction_amount');
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$dateStr = $date['end']->format('Y-m-d');
|
||||
$dateName = app('navigation')->periodShow($date['end'], $date['period']);
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'count' => $count,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'transferred' => $transferred,
|
||||
'date' => clone $date['end'],
|
||||
]
|
||||
);
|
||||
}
|
||||
Log::debug('End of loops');
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function getPeriodOverview(Category $category, Carbon $date): Collection
|
||||
{
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$start = null === $first ? new Carbon : $first->date;
|
||||
$end = $date ?? new Carbon;
|
||||
$accounts = $this->accountRepos->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||
|
||||
// properties for entries with their amounts.
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($range);
|
||||
$cache->addProperty('categories.entries');
|
||||
$cache->addProperty($category->id);
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
foreach ($dates as $currentDate) {
|
||||
$spent = $this->repository->spentInPeriod(new Collection([$category]), $accounts, $currentDate['start'], $currentDate['end']);
|
||||
$earned = $this->repository->earnedInPeriod(new Collection([$category]), $accounts, $currentDate['start'], $currentDate['end']);
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$dateStr = $currentDate['end']->format('Y-m-d');
|
||||
$dateName = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||
|
||||
// amount transferred
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($currentDate['start'], $currentDate['end'])->setCategory($category)
|
||||
->withOpposingAccount()->setTypes([TransactionType::TRANSFER]);
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
$transferred = app('steam')->positive((string)$collector->getJournals()->sum('transaction_amount'));
|
||||
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'sum' => bcadd($earned, $spent),
|
||||
'transferred' => $transferred,
|
||||
'date' => clone $currentDate['end'],
|
||||
]
|
||||
);
|
||||
}
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
}
|
||||
|
@@ -36,21 +36,27 @@ use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Preferences;
|
||||
|
||||
/** checked
|
||||
/**
|
||||
* Class AccountController.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
*/
|
||||
class AccountController extends Controller
|
||||
{
|
||||
/** @var GeneratorInterface */
|
||||
use DateCalculation;
|
||||
|
||||
/** @var GeneratorInterface Chart generation methods. */
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
*
|
||||
* AccountController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -68,7 +74,9 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function expenseAccounts(AccountRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
@@ -103,6 +111,8 @@ class AccountController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Expenses per budget, as shown on account overview.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
@@ -146,6 +156,8 @@ class AccountController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Expenses per budget for all time, as shown on account overview.
|
||||
*
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
@@ -161,6 +173,8 @@ class AccountController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Expenses per category for one single account.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
@@ -204,6 +218,8 @@ class AccountController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Expenses grouped by category for account.
|
||||
*
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
@@ -231,7 +247,7 @@ class AccountController extends Controller
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$defaultSet = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])->pluck('id')->toArray();
|
||||
Log::debug('Default set is ', $defaultSet);
|
||||
$frontPage = Preferences::get('frontPageAccounts', $defaultSet);
|
||||
$frontPage = app('preferences')->get('frontPageAccounts', $defaultSet);
|
||||
|
||||
|
||||
Log::debug('Frontpage preference set is ', $frontPage->data);
|
||||
@@ -247,6 +263,8 @@ class AccountController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows all income per account for each category.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
@@ -290,6 +308,8 @@ class AccountController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the income grouped by category for an account, in all time.
|
||||
*
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
@@ -305,12 +325,16 @@ class AccountController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows overview of account during a single period.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
*
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
public function period(Account $account, Carbon $start, Carbon $end): JsonResponse
|
||||
{
|
||||
@@ -322,18 +346,8 @@ class AccountController extends Controller
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
$step = $this->calculateStep($start, $end);
|
||||
$chartData = [];
|
||||
$current = clone $start;
|
||||
switch ($step) {
|
||||
@@ -429,11 +443,16 @@ class AccountController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows an overview of the account balances for a set of accounts.
|
||||
*
|
||||
* @param Collection $accounts
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
private function accountBalanceChart(Collection $accounts, Carbon $start, Carbon $end): array
|
||||
{
|
||||
@@ -450,10 +469,14 @@ class AccountController extends Controller
|
||||
|
||||
/** @var CurrencyRepositoryInterface $repository */
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$default = app('amount')->getDefaultCurrency();
|
||||
$chartData = [];
|
||||
/** @var AccountRepositoryInterface $accountRepos */
|
||||
$accountRepos = app(AccountRepositoryInterface::class);
|
||||
|
||||
$default = app('amount')->getDefaultCurrency();
|
||||
$chartData = [];
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$currency = $repository->findNull((int)$account->getMeta('currency_id'));
|
||||
$currency = $repository->findNull((int)$accountRepos->getMetaValue($account, 'currency_id'));
|
||||
if (null === $currency) {
|
||||
$currency = $default;
|
||||
}
|
||||
@@ -483,6 +506,8 @@ class AccountController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the budget names from a set of budget ID's.
|
||||
*
|
||||
* @param array $budgetIds
|
||||
*
|
||||
* @return array
|
||||
@@ -499,13 +524,13 @@ class AccountController extends Controller
|
||||
$return[$budgetId] = $grouped[$budgetId][0]['name'];
|
||||
}
|
||||
}
|
||||
$return[0] = trans('firefly.no_budget');
|
||||
$return[0] = (string)trans('firefly.no_budget');
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Small helper function for some of the charts.
|
||||
* Get the category names from a set of category ID's. Small helper function for some of the charts.
|
||||
*
|
||||
* @param array $categoryIds
|
||||
*
|
||||
@@ -523,7 +548,7 @@ class AccountController extends Controller
|
||||
$return[$categoryId] = $grouped[$categoryId][0]['name'];
|
||||
}
|
||||
}
|
||||
$return[0] = trans('firefly.noCategory');
|
||||
$return[0] = (string)trans('firefly.noCategory');
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
@@ -38,11 +38,11 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
class BillController extends Controller
|
||||
{
|
||||
/** @var GeneratorInterface */
|
||||
/** @var GeneratorInterface Chart generation methods. */
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
* checked.
|
||||
* BillController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -85,6 +85,8 @@ class BillController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows overview for a single bill.
|
||||
*
|
||||
* @param JournalCollectorInterface $collector
|
||||
* @param Bill $bill
|
||||
*
|
||||
@@ -99,16 +101,16 @@ class BillController extends Controller
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$results = $collector->setAllAssetAccounts()->setBills(new Collection([$bill]))->getJournals();
|
||||
$results = $results->sortBy(
|
||||
$results = $collector->setAllAssetAccounts()->setBills(new Collection([$bill]))->getJournals();
|
||||
$results = $results->sortBy(
|
||||
function (Transaction $transaction) {
|
||||
return $transaction->date->format('U');
|
||||
}
|
||||
);
|
||||
$chartData = [
|
||||
['type' => 'bar', 'label' => trans('firefly.min-amount'), 'entries' => []],
|
||||
['type' => 'bar', 'label' => trans('firefly.max-amount'), 'entries' => []],
|
||||
['type' => 'line', 'label' => trans('firefly.journal-amount'), 'entries' => []],
|
||||
['type' => 'bar', 'label' => (string)trans('firefly.min-amount'), 'entries' => []],
|
||||
['type' => 'bar', 'label' => (string)trans('firefly.max-amount'), 'entries' => []],
|
||||
['type' => 'line', 'label' => (string)trans('firefly.journal-amount'), 'entries' => []],
|
||||
];
|
||||
|
||||
/** @var Transaction $entry */
|
||||
@@ -116,7 +118,13 @@ class BillController extends Controller
|
||||
$date = $entry->date->formatLocalized((string)trans('config.month_and_day'));
|
||||
$chartData[0]['entries'][$date] = $bill->amount_min; // minimum amount of bill
|
||||
$chartData[1]['entries'][$date] = $bill->amount_max; // maximum amount of bill
|
||||
$chartData[2]['entries'][$date] = bcmul($entry->transaction_amount, '-1'); // amount of journal
|
||||
|
||||
// append amount because there are more than one per moment:
|
||||
if (!isset($chartData[2]['entries'][$date])) {
|
||||
$chartData[2]['entries'][$date] = '0';
|
||||
}
|
||||
$amount = bcmul($entry->transaction_amount, '-1');
|
||||
$chartData[2]['entries'][$date] = bcadd($chartData[2]['entries'][$date], $amount); // amount of journal
|
||||
}
|
||||
|
||||
$data = $this->generator->multiSet($chartData);
|
||||
|
@@ -36,19 +36,24 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class BudgetController.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
*
|
||||
*/
|
||||
class BudgetController extends Controller
|
||||
{
|
||||
/** @var GeneratorInterface */
|
||||
use DateCalculation;
|
||||
/** @var GeneratorInterface Chart generation methods. */
|
||||
protected $generator;
|
||||
|
||||
/** @var BudgetRepositoryInterface */
|
||||
/** @var BudgetRepositoryInterface The budget repository */
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
@@ -70,13 +75,17 @@ class BudgetController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows overview of a single budget.
|
||||
*
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function budget(Budget $budget): JsonResponse
|
||||
{
|
||||
$start = $this->repository->firstUseDate($budget);
|
||||
/** @var Carbon $start */
|
||||
$start = $this->repository->firstUseDate($budget) ?? session('start', new Carbon);
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', new Carbon);
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
@@ -88,23 +97,11 @@ class BudgetController extends Controller
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// 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';
|
||||
}
|
||||
if ($months > 60) {
|
||||
$step = '1Y'; // @codeCoverageIgnore
|
||||
}
|
||||
$step = $this->calculateStep($start, $end); // depending on diff, do something with range of chart.
|
||||
$budgetCollection = new Collection([$budget]);
|
||||
$chartData = [];
|
||||
$current = clone $start;
|
||||
$current = app('navigation')->startOfPeriod($current, $step);
|
||||
|
||||
while ($end >= $current) {
|
||||
/** @var Carbon $currentEnd */
|
||||
$currentEnd = app('navigation')->endOfPeriod($current, $step);
|
||||
@@ -129,7 +126,6 @@ class BudgetController extends Controller
|
||||
/**
|
||||
* Shows the amount left in a specific budget limit.
|
||||
*
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param BudgetLimit $budgetLimit
|
||||
*
|
||||
@@ -175,10 +171,14 @@ class BudgetController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows how much is spent per asset account.
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param BudgetLimit|null $budgetLimit
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*/
|
||||
public function expenseAsset(Budget $budget, ?BudgetLimit $budgetLimit): JsonResponse
|
||||
{
|
||||
@@ -221,10 +221,14 @@ class BudgetController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows how much is spent per category.
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param BudgetLimit|null $budgetLimit
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*/
|
||||
public function expenseCategory(Budget $budget, ?BudgetLimit $budgetLimit): JsonResponse
|
||||
{
|
||||
@@ -260,7 +264,6 @@ class BudgetController extends Controller
|
||||
foreach ($result as $categoryId => $amount) {
|
||||
$chartData[$names[$categoryId]] = $amount;
|
||||
}
|
||||
|
||||
$data = $this->generator->pieChart($chartData);
|
||||
$cache->store($data);
|
||||
|
||||
@@ -269,10 +272,14 @@ class BudgetController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows how much is spent per expense account.
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param BudgetLimit|null $budgetLimit
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*/
|
||||
public function expenseExpense(Budget $budget, ?BudgetLimit $budgetLimit): JsonResponse
|
||||
{
|
||||
@@ -319,6 +326,9 @@ class BudgetController extends Controller
|
||||
* Shows a budget list with spent/left/overspent.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
public function frontpage(): \Symfony\Component\HttpFoundation\Response
|
||||
{
|
||||
@@ -368,6 +378,7 @@ class BudgetController extends Controller
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Shows a budget overview chart (spent and budgeted).
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
@@ -413,6 +424,8 @@ class BudgetController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows a chart for transactions without a budget.
|
||||
*
|
||||
* @param Collection $accounts
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
@@ -449,6 +462,8 @@ class BudgetController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the account names belonging to a bunch of account ID's.
|
||||
*
|
||||
* @param array $accountIds
|
||||
*
|
||||
* @return array
|
||||
@@ -471,6 +486,8 @@ class BudgetController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of money budgeted in a period.
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
@@ -499,7 +516,7 @@ class BudgetController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Small helper function for some of the charts.
|
||||
* Small helper function for some of the charts. Extracts category names from a bunch of ID's.
|
||||
*
|
||||
* @param array $categoryIds
|
||||
*
|
||||
@@ -517,13 +534,14 @@ class BudgetController extends Controller
|
||||
$return[$categoryId] = $grouped[$categoryId][0]['name'];
|
||||
}
|
||||
}
|
||||
$return[0] = trans('firefly.noCategory');
|
||||
$return[0] = (string)trans('firefly.noCategory');
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Get the expenses for a budget in a date range.
|
||||
*
|
||||
* @param Collection $limits
|
||||
* @param Budget $budget
|
||||
@@ -531,6 +549,8 @@ class BudgetController extends Controller
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*/
|
||||
private function getExpensesForBudget(Collection $limits, Budget $budget, Carbon $start, Carbon $end): array
|
||||
{
|
||||
@@ -571,6 +591,9 @@ class BudgetController extends Controller
|
||||
* @param Collection $limits
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*
|
||||
*/
|
||||
private function spentInPeriodMulti(Budget $budget, Collection $limits): array
|
||||
{
|
||||
@@ -591,18 +614,12 @@ class BudgetController extends Controller
|
||||
]
|
||||
);
|
||||
}
|
||||
/*
|
||||
* amount: amount of budget limit
|
||||
* left: amount of budget limit min spent, or 0 when < 0.
|
||||
* spent: spent, or amount of budget limit when > amount
|
||||
*/
|
||||
$amount = $budgetLimit->amount;
|
||||
$leftInLimit = bcsub($amount, $expenses);
|
||||
$hasOverspent = bccomp($leftInLimit, '0') === -1;
|
||||
|
||||
$left = $hasOverspent ? '0' : bcsub($amount, $expenses);
|
||||
$spent = $hasOverspent ? $amount : $expenses;
|
||||
$overspent = $hasOverspent ? app('steam')->positive($leftInLimit) : '0';
|
||||
$left = $hasOverspent ? '0' : bcsub($amount, $expenses);
|
||||
$spent = $hasOverspent ? $amount : $expenses;
|
||||
$overspent = $hasOverspent ? app('steam')->positive($leftInLimit) : '0';
|
||||
|
||||
$return[$name] = [
|
||||
'left' => $left,
|
||||
|
@@ -43,16 +43,18 @@ use Illuminate\Support\Collection;
|
||||
* Separate controller because many helper functions are shared.
|
||||
*
|
||||
* Class BudgetReportController
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
*/
|
||||
class BudgetReportController extends Controller
|
||||
{
|
||||
/** @var BudgetRepositoryInterface */
|
||||
/** @var BudgetRepositoryInterface The budget repository */
|
||||
private $budgetRepository;
|
||||
/** @var GeneratorInterface */
|
||||
/** @var GeneratorInterface Chart generation methods. */
|
||||
private $generator;
|
||||
|
||||
/**
|
||||
*
|
||||
* BudgetReportController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -69,6 +71,8 @@ class BudgetReportController extends Controller
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Chart that groups expenses by the account.
|
||||
*
|
||||
* @param Collection $accounts
|
||||
* @param Collection $budgets
|
||||
* @param Carbon $start
|
||||
@@ -76,6 +80,8 @@ class BudgetReportController extends Controller
|
||||
* @param string $others
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
|
||||
*/
|
||||
public function accountExpense(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end, string $others): JsonResponse
|
||||
{
|
||||
@@ -94,6 +100,8 @@ class BudgetReportController extends Controller
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Chart that groups the expenses by budget.
|
||||
*
|
||||
* @param Collection $accounts
|
||||
* @param Collection $budgets
|
||||
* @param Carbon $start
|
||||
@@ -101,6 +109,8 @@ class BudgetReportController extends Controller
|
||||
* @param string $others
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
|
||||
*/
|
||||
public function budgetExpense(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end, string $others): JsonResponse
|
||||
{
|
||||
@@ -119,12 +129,17 @@ class BudgetReportController extends Controller
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Main overview of a budget in the budget report.
|
||||
*
|
||||
* @param Collection $accounts
|
||||
* @param Collection $budgets
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
public function mainChart(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end): JsonResponse
|
||||
{
|
||||
@@ -233,6 +248,8 @@ class BudgetReportController extends Controller
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Helper function that collects expenses for the given budgets.
|
||||
*
|
||||
* @param Collection $accounts
|
||||
* @param Collection $budgets
|
||||
* @param Carbon $start
|
||||
@@ -255,6 +272,8 @@ class BudgetReportController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that groups expenses.
|
||||
*
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return array
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user