From 9595267ee7f4b36dd95f421e06a94408081d8109 Mon Sep 17 00:00:00 2001
From: WuYongJie <549727955@qq.com>
Date: Mon, 20 Jul 2026 18:20:25 +0800
Subject: [PATCH] =?UTF-8?q?chore:=20=E5=AF=BC=E5=85=A5=20Akaunting=20?=
=?UTF-8?q?=E5=88=9D=E5=A7=8B=E6=BA=90=E7=A0=81=E4=B8=8E=E5=9B=A2=E9=98=9F?=
=?UTF-8?q?=E5=8D=8F=E4=BD=9C=E8=A7=84=E5=88=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.dockerignore | 16 +
.editorconfig | 18 +
.gitattributes | 26 +
.github/FUNDING.yml | 1 +
.github/ISSUE_TEMPLATE.md | 21 +
.github/ISSUE_TEMPLATE/bug.yml | 63 +
.github/ISSUE_TEMPLATE/config.yml | 11 +
.github/workflows/tests.yml | 51 +
.gitignore | 98 +
.htaccess | 49 +
AGENTS.md | 72 +
LICENSE.txt | 78 +
LocalValetDriver.php | 23 +
README.md | 62 +
SECURITY.md | 19 +
app/Abstracts/BulkAction.php | 328 +
app/Abstracts/Commands/Module.php | 86 +
app/Abstracts/Event.php | 12 +
app/Abstracts/Export.php | 301 +
app/Abstracts/Factory.php | 76 +
app/Abstracts/Http/ApiController.php | 186 +
app/Abstracts/Http/Controller.php | 272 +
app/Abstracts/Http/FormRequest.php | 20 +
app/Abstracts/Http/PaymentController.php | 209 +
app/Abstracts/Http/Response.php | 55 +
app/Abstracts/Http/SettingController.php | 174 +
app/Abstracts/Import.php | 276 +
app/Abstracts/ImportMultipleSheets.php | 31 +
app/Abstracts/Job.php | 136 +
app/Abstracts/JobShouldQueue.php | 161 +
app/Abstracts/Listeners/Report.php | 363 +
app/Abstracts/Listeners/Update.php | 36 +
app/Abstracts/Model.php | 269 +
app/Abstracts/Notification.php | 179 +
app/Abstracts/Observer.php | 10 +
app/Abstracts/Report.php | 741 +
app/Abstracts/View/Component.php | 13 +
.../View/Components/Contacts/Form.php | 568 +
.../View/Components/Contacts/Index.php | 497 +
.../View/Components/Contacts/Show.php | 319 +
.../View/Components/Documents/Form.php | 1395 +
.../View/Components/Documents/Index.php | 907 +
.../View/Components/Documents/Show.php | 1434 +
.../View/Components/Documents/Template.php | 767 +
app/Abstracts/View/Components/Form.php | 362 +
.../View/Components/Transactions/Index.php | 760 +
.../View/Components/Transactions/Show.php | 1142 +
.../View/Components/Transactions/Template.php | 660 +
.../View/Components/Transfers/Show.php | 50 +
.../View/Components/Transfers/Template.php | 50 +
app/Abstracts/Widget.php | 143 +
app/Builders/Category.php | 74 +
app/BulkActions/Auth/Users.php | 123 +
app/BulkActions/Banking/Accounts.php | 100 +
app/BulkActions/Banking/Reconciliations.php | 96 +
app/BulkActions/Banking/Transactions.php | 122 +
app/BulkActions/Banking/Transfers.php | 57 +
app/BulkActions/Common/Companies.php | 122 +
app/BulkActions/Common/Dashboards.php | 67 +
app/BulkActions/Common/Items.php | 100 +
app/BulkActions/Purchases/Bills.php | 156 +
app/BulkActions/Purchases/Vendors.php | 97 +
app/BulkActions/Sales/Customers.php | 97 +
app/BulkActions/Sales/Invoices.php | 172 +
app/BulkActions/Settings/Categories.php | 117 +
app/BulkActions/Settings/Currencies.php | 108 +
app/BulkActions/Settings/Taxes.php | 109 +
app/Classifiers/BulkAction.php | 29 +
app/Classifiers/Event.php | 29 +
app/Classifiers/Export.php | 29 +
app/Classifiers/Import.php | 29 +
app/Classifiers/Job.php | 29 +
app/Classifiers/Observer.php | 29 +
app/Classifiers/Report.php | 29 +
app/Classifiers/Scope.php | 29 +
app/Classifiers/Widget.php | 29 +
app/Console/Commands/BillReminder.php | 99 +
app/Console/Commands/CompanySeed.php | 50 +
app/Console/Commands/DownloadModule.php | 130 +
app/Console/Commands/FinishUpdate.php | 68 +
app/Console/Commands/Install.php | 201 +
app/Console/Commands/InstallRefresh.php | 57 +
app/Console/Commands/InvoiceReminder.php | 99 +
app/Console/Commands/RecurringCheck.php | 284 +
app/Console/Commands/SampleData.php | 37 +
app/Console/Commands/StorageTempClear.php | 42 +
app/Console/Commands/UninstallModule.php | 54 +
app/Console/Commands/Update.php | 199 +
app/Console/Commands/UpdateAll.php | 74 +
app/Console/Commands/UpdateDb.php | 43 +
app/Console/Commands/UserSeed.php | 34 +
app/Console/Kernel.php | 60 +
app/Console/Stubs/Modules/assets/js/app.stub | 0
.../Stubs/Modules/assets/sass/app.stub | 0
app/Console/Stubs/Modules/command.stub | 32 +
app/Console/Stubs/Modules/component.stub | 28 +
app/Console/Stubs/Modules/composer.stub | 17 +
app/Console/Stubs/Modules/controller-api.stub | 61 +
.../Stubs/Modules/controller-plain.stub | 9 +
app/Console/Stubs/Modules/controller.stub | 86 +
app/Console/Stubs/Modules/event.stub | 28 +
app/Console/Stubs/Modules/factory.stub | 28 +
app/Console/Stubs/Modules/job-queued.stub | 34 +
app/Console/Stubs/Modules/job.stub | 28 +
app/Console/Stubs/Modules/json.stub | 17 +
app/Console/Stubs/Modules/lang/general.stub | 8 +
app/Console/Stubs/Modules/listener-duck.stub | 30 +
.../Stubs/Modules/listener-queued-duck.stub | 32 +
.../Stubs/Modules/listener-queued.stub | 23 +
app/Console/Stubs/Modules/listener.stub | 19 +
.../Stubs/Modules/listeners/install.stub | 47 +
app/Console/Stubs/Modules/mail.stub | 33 +
app/Console/Stubs/Modules/middleware.stub | 21 +
app/Console/Stubs/Modules/migration/add.stub | 32 +
.../Stubs/Modules/migration/create.stub | 32 +
.../Stubs/Modules/migration/delete.stub | 32 +
app/Console/Stubs/Modules/migration/drop.stub | 32 +
.../Stubs/Modules/migration/plain.stub | 28 +
app/Console/Stubs/Modules/model.stub | 23 +
app/Console/Stubs/Modules/notification.stub | 61 +
app/Console/Stubs/Modules/package.stub | 17 +
app/Console/Stubs/Modules/policy.plain.stub | 20 +
app/Console/Stubs/Modules/provider.stub | 28 +
.../Stubs/Modules/providers/event.stub | 30 +
app/Console/Stubs/Modules/request.stub | 20 +
.../Stubs/Modules/resource-collection.stub | 19 +
app/Console/Stubs/Modules/resource.stub | 19 +
app/Console/Stubs/Modules/routes/admin.stub | 13 +
app/Console/Stubs/Modules/routes/portal.stub | 14 +
app/Console/Stubs/Modules/rule.stub | 40 +
.../Stubs/Modules/scaffold/config.stub | 7 +
.../Stubs/Modules/scaffold/provider.stub | 103 +
app/Console/Stubs/Modules/seeder.stub | 23 +
app/Console/Stubs/Modules/unit-test.stub | 19 +
app/Console/Stubs/Modules/views/index.stub | 9 +
app/Console/Stubs/Modules/webpack.stub | 20 +
app/Events/Auth/Attempting.php | 28 +
app/Events/Auth/Authenticated.php | 28 +
app/Events/Auth/Failed.php | 28 +
app/Events/Auth/LandingPageShowing.php | 20 +
app/Events/Auth/RoleCreated.php | 24 +
app/Events/Auth/RoleCreating.php | 22 +
app/Events/Auth/RoleDeleted.php | 20 +
app/Events/Auth/RoleDeleting.php | 20 +
app/Events/Auth/RoleUpdated.php | 24 +
app/Events/Auth/RoleUpdating.php | 24 +
app/Events/Auth/UserCreated.php | 24 +
app/Events/Auth/UserCreating.php | 22 +
app/Events/Auth/UserDeleted.php | 20 +
app/Events/Auth/UserDeleting.php | 20 +
app/Events/Auth/UserUpdated.php | 24 +
app/Events/Auth/UserUpdating.php | 24 +
app/Events/Banking/AccountCreated.php | 21 +
app/Events/Banking/AccountCreating.php | 20 +
app/Events/Banking/AccountDeleted.php | 20 +
app/Events/Banking/AccountDeleting.php | 20 +
app/Events/Banking/AccountUpdated.php | 25 +
app/Events/Banking/AccountUpdating.php | 25 +
.../Banking/DocumentTransactionCreated.php | 26 +
.../Banking/DocumentTransactionCreating.php | 25 +
.../Banking/DocumentTransactionUpdated.php | 30 +
.../Banking/DocumentTransactionUpdating.php | 30 +
app/Events/Banking/TransactionCreated.php | 21 +
app/Events/Banking/TransactionCreating.php | 20 +
app/Events/Banking/TransactionDeleted.php | 20 +
app/Events/Banking/TransactionDeleting.php | 20 +
app/Events/Banking/TransactionPrinting.php | 22 +
app/Events/Banking/TransactionRecurring.php | 20 +
app/Events/Banking/TransactionSending.php | 20 +
app/Events/Banking/TransactionSent.php | 20 +
app/Events/Banking/TransactionSplitted.php | 23 +
app/Events/Banking/TransactionSplitting.php | 23 +
app/Events/Banking/TransactionUpdated.php | 25 +
app/Events/Banking/TransactionUpdating.php | 25 +
app/Events/Banking/TransferCreated.php | 21 +
app/Events/Banking/TransferCreating.php | 20 +
app/Events/Banking/TransferDeleted.php | 20 +
app/Events/Banking/TransferDeleting.php | 20 +
app/Events/Banking/TransferPrinting.php | 22 +
app/Events/Banking/TransferUpdated.php | 25 +
app/Events/Banking/TransferUpdating.php | 25 +
app/Events/Common/BulkActionsAdding.php | 20 +
app/Events/Common/CompanyCreated.php | 23 +
app/Events/Common/CompanyCreating.php | 20 +
app/Events/Common/CompanyDeleted.php | 24 +
app/Events/Common/CompanyDeleting.php | 24 +
.../Common/CompanyForgettingCurrent.php | 20 +
app/Events/Common/CompanyForgotCurrent.php | 20 +
app/Events/Common/CompanyMadeCurrent.php | 20 +
app/Events/Common/CompanyMakingCurrent.php | 20 +
app/Events/Common/CompanySwitched.php | 24 +
app/Events/Common/CompanyUpdated.php | 24 +
app/Events/Common/CompanyUpdating.php | 24 +
app/Events/Common/ContactCreated.php | 21 +
app/Events/Common/ContactCreating.php | 20 +
app/Events/Common/ContactDeleted.php | 20 +
app/Events/Common/ContactDeleting.php | 20 +
app/Events/Common/ContactUpdated.php | 25 +
app/Events/Common/ContactUpdating.php | 25 +
app/Events/Common/DatesFormating.php | 23 +
app/Events/Common/GlobalSearched.php | 20 +
app/Events/Common/ImportViewCreated.php | 21 +
app/Events/Common/ImportViewCreating.php | 21 +
app/Events/Common/ItemCreated.php | 25 +
app/Events/Common/ItemCreating.php | 20 +
app/Events/Common/ItemDeleted.php | 20 +
app/Events/Common/ItemDeleting.php | 20 +
app/Events/Common/ItemUpdated.php | 25 +
app/Events/Common/ItemUpdating.php | 25 +
app/Events/Common/RelationshipCounting.php | 20 +
app/Events/Common/RelationshipDeleting.php | 20 +
app/Events/Common/SearchStringApplied.php | 20 +
app/Events/Common/SearchStringApplying.php | 20 +
app/Events/Document/DocumentCancelled.php | 22 +
app/Events/Document/DocumentCreated.php | 24 +
app/Events/Document/DocumentCreating.php | 22 +
app/Events/Document/DocumentDeleted.php | 20 +
app/Events/Document/DocumentDeleting.php | 20 +
app/Events/Document/DocumentDuplicating.php | 20 +
app/Events/Document/DocumentMarkedSent.php | 20 +
app/Events/Document/DocumentPrinting.php | 22 +
app/Events/Document/DocumentReceived.php | 22 +
app/Events/Document/DocumentRecurring.php | 21 +
app/Events/Document/DocumentReminded.php | 24 +
.../Document/DocumentResourceShowing.php | 34 +
app/Events/Document/DocumentRestored.php | 22 +
app/Events/Document/DocumentSending.php | 20 +
app/Events/Document/DocumentSent.php | 20 +
app/Events/Document/DocumentTemplates.php | 26 +
app/Events/Document/DocumentUpdated.php | 24 +
app/Events/Document/DocumentUpdating.php | 24 +
app/Events/Document/DocumentViewed.php | 20 +
app/Events/Document/PaidAmountCalculated.php | 20 +
app/Events/Document/PaymentReceived.php | 31 +
app/Events/Document/TransactionsCounted.php | 20 +
app/Events/Email/InvalidEmailDetected.php | 50 +
app/Events/Email/TooManyEmailsSent.php | 15 +
app/Events/Export/HeadingsPreparing.php | 20 +
app/Events/Export/RowsPreparing.php | 24 +
app/Events/Import/RowPreparing.php | 24 +
app/Events/Install/UpdateCacheCleared.php | 20 +
app/Events/Install/UpdateCopied.php | 28 +
app/Events/Install/UpdateDownloaded.php | 28 +
app/Events/Install/UpdateFailed.php | 35 +
app/Events/Install/UpdateFinished.php | 28 +
app/Events/Install/UpdateUnzipped.php | 28 +
app/Events/Menu/AdminCreated.php | 20 +
app/Events/Menu/AdminCreating.php | 20 +
app/Events/Menu/ItemAuthorizing.php | 20 +
app/Events/Menu/NewwCreated.php | 20 +
app/Events/Menu/NewwCreating.php | 20 +
app/Events/Menu/NotificationsCreated.php | 20 +
app/Events/Menu/NotificationsCreating.php | 20 +
app/Events/Menu/PortalCreated.php | 20 +
app/Events/Menu/PortalCreating.php | 20 +
app/Events/Menu/ProfileCreated.php | 20 +
app/Events/Menu/ProfileCreating.php | 20 +
app/Events/Menu/SettingsCreated.php | 20 +
app/Events/Menu/SettingsCreating.php | 20 +
app/Events/Menu/SettingsFinished.php | 20 +
app/Events/Module/Copied.php | 24 +
app/Events/Module/Disabled.php | 24 +
app/Events/Module/Disabling.php | 24 +
app/Events/Module/Enabled.php | 24 +
app/Events/Module/Installed.php | 28 +
app/Events/Module/Installing.php | 24 +
app/Events/Module/PaymentMethodShowing.php | 20 +
app/Events/Module/Uninstalled.php | 24 +
app/Events/Module/Uninstalling.php | 24 +
app/Events/Report/ClassesCreated.php | 20 +
app/Events/Report/DataLoaded.php | 20 +
app/Events/Report/DataLoading.php | 20 +
app/Events/Report/FilterApplying.php | 28 +
app/Events/Report/FilterShowing.php | 20 +
app/Events/Report/GroupApplying.php | 28 +
app/Events/Report/GroupShowing.php | 20 +
app/Events/Report/RowsShowing.php | 20 +
app/Events/Report/SkipClass.php | 20 +
app/Events/Report/SkipRowsShowing.php | 20 +
app/Events/Report/TotalCalculated.php | 40 +
app/Events/Report/TotalCalculating.php | 40 +
app/Events/Setting/CategoryCreated.php | 24 +
app/Events/Setting/CategoryCreating.php | 22 +
app/Events/Setting/CategoryDeleted.php | 20 +
app/Events/Setting/CategoryDeleting.php | 20 +
app/Events/Setting/CategoryUpdated.php | 24 +
app/Events/Setting/CategoryUpdating.php | 24 +
app/Events/Setting/CurrencyCreated.php | 24 +
app/Events/Setting/CurrencyCreating.php | 20 +
app/Events/Setting/CurrencyDeleted.php | 20 +
app/Events/Setting/CurrencyDeleting.php | 20 +
app/Events/Setting/CurrencyUpdated.php | 24 +
app/Events/Setting/CurrencyUpdating.php | 24 +
app/Events/Setting/SettingUpdated.php | 20 +
app/Events/Setting/SettingUpdating.php | 20 +
app/Events/Setting/TaxCreated.php | 24 +
app/Events/Setting/TaxCreating.php | 20 +
app/Events/Setting/TaxDeleted.php | 20 +
app/Events/Setting/TaxDeleting.php | 20 +
app/Events/Setting/TaxUpdated.php | 24 +
app/Events/Setting/TaxUpdating.php | 24 +
app/Events/Widget/ClassesCreated.php | 20 +
app/Exceptions/Common/LastDashboard.php | 10 +
app/Exceptions/Common/NotUserDashboard.php | 10 +
app/Exceptions/Common/TooManyEmailsSent.php | 14 +
app/Exceptions/Handler.php | 401 +
app/Exceptions/Http/Resource.php | 59 +
.../Settings/LastCategoryDelete.php | 22 +
app/Exceptions/Trackers/Bugsnag.php | 25 +
app/Exceptions/Trackers/Sentry.php | 66 +
app/Exports/Banking/RecurringTransactions.php | 28 +
app/Exports/Banking/Sheets/Recurring.php | 37 +
.../Banking/Sheets/RecurringTransactions.php | 54 +
app/Exports/Banking/Transactions.php | 77 +
app/Exports/Banking/Transfers.php | 66 +
app/Exports/Common/Items.php | 28 +
app/Exports/Common/Reports.php | 34 +
app/Exports/Common/Sheets/ItemTaxes.php | 40 +
app/Exports/Common/Sheets/Items.php | 37 +
app/Exports/Purchases/Bills/Bills.php | 36 +
.../Purchases/Bills/Sheets/BillHistories.php | 38 +
.../Purchases/Bills/Sheets/BillItemTaxes.php | 42 +
.../Purchases/Bills/Sheets/BillItems.php | 47 +
.../Purchases/Bills/Sheets/BillTotals.php | 39 +
.../Bills/Sheets/BillTransactions.php | 60 +
app/Exports/Purchases/Bills/Sheets/Bills.php | 73 +
.../RecurringBills/RecurringBills.php | 36 +
.../RecurringBills/Sheets/Recurring.php | 37 +
.../Sheets/RecurringBillHistories.php | 38 +
.../Sheets/RecurringBillItemTaxes.php | 42 +
.../Sheets/RecurringBillItems.php | 47 +
.../Sheets/RecurringBillTotals.php | 39 +
.../RecurringBills/Sheets/RecurringBills.php | 72 +
app/Exports/Purchases/Vendors.php | 48 +
app/Exports/Sales/Customers.php | 51 +
app/Exports/Sales/Invoices/Invoices.php | 36 +
.../Invoices/Sheets/InvoiceHistories.php | 38 +
.../Invoices/Sheets/InvoiceItemTaxes.php | 42 +
.../Sales/Invoices/Sheets/InvoiceItems.php | 47 +
.../Sales/Invoices/Sheets/InvoiceTotals.php | 40 +
.../Invoices/Sheets/InvoiceTransactions.php | 60 +
.../Sales/Invoices/Sheets/Invoices.php | 74 +
.../RecurringInvoices/RecurringInvoices.php | 36 +
.../RecurringInvoices/Sheets/Recurring.php | 37 +
.../Sheets/RecurringInvoiceHistories.php | 38 +
.../Sheets/RecurringInvoiceItemTaxes.php | 42 +
.../Sheets/RecurringInvoiceItems.php | 47 +
.../Sheets/RecurringInvoiceTotals.php | 39 +
.../Sheets/RecurringInvoices.php | 73 +
app/Exports/Settings/Categories.php | 37 +
app/Exports/Settings/Taxes.php | 27 +
app/Http/Controllers/Api/Auth/Users.php | 134 +
app/Http/Controllers/Api/Banking/Accounts.php | 126 +
.../Api/Banking/Reconciliations.php | 81 +
.../Controllers/Api/Banking/Transactions.php | 93 +
.../Controllers/Api/Banking/Transfers.php | 111 +
app/Http/Controllers/Api/Common/Companies.php | 148 +
app/Http/Controllers/Api/Common/Contacts.php | 126 +
.../Controllers/Api/Common/Dashboards.php | 154 +
app/Http/Controllers/Api/Common/Items.php | 113 +
app/Http/Controllers/Api/Common/Ping.php | 30 +
app/Http/Controllers/Api/Common/Reports.php | 81 +
.../Controllers/Api/Common/Translations.php | 91 +
.../Api/Document/DocumentTransactions.php | 109 +
.../Controllers/Api/Document/Documents.php | 119 +
.../Controllers/Api/Settings/Categories.php | 115 +
.../Controllers/Api/Settings/Currencies.php | 126 +
.../Controllers/Api/Settings/Settings.php | 105 +
app/Http/Controllers/Api/Settings/Taxes.php | 115 +
app/Http/Controllers/Auth/Forgot.php | 102 +
app/Http/Controllers/Auth/Login.php | 150 +
app/Http/Controllers/Auth/Register.php | 88 +
app/Http/Controllers/Auth/Reset.php | 146 +
app/Http/Controllers/Auth/Users.php | 448 +
app/Http/Controllers/Banking/Accounts.php | 307 +
app/Http/Controllers/Banking/FundAccounts.php | 182 +
.../Controllers/Banking/Reconciliations.php | 256 +
.../Banking/RecurringTransactions.php | 271 +
app/Http/Controllers/Banking/Transactions.php | 462 +
app/Http/Controllers/Banking/Transfers.php | 252 +
app/Http/Controllers/Business/Pages.php | 99 +
app/Http/Controllers/Common/BulkActions.php | 167 +
app/Http/Controllers/Common/Companies.php | 264 +
app/Http/Controllers/Common/Contacts.php | 33 +
app/Http/Controllers/Common/Dashboards.php | 261 +
app/Http/Controllers/Common/Import.php | 27 +
app/Http/Controllers/Common/Items.php | 324 +
app/Http/Controllers/Common/Plans.php | 23 +
app/Http/Controllers/Common/Reports.php | 316 +
app/Http/Controllers/Common/Uploads.php | 317 +
app/Http/Controllers/Common/Widgets.php | 200 +
app/Http/Controllers/Install/Database.php | 62 +
app/Http/Controllers/Install/Language.php | 59 +
app/Http/Controllers/Install/Requirements.php | 36 +
app/Http/Controllers/Install/Settings.php | 49 +
app/Http/Controllers/Install/Updates.php | 323 +
app/Http/Controllers/Modals/Accounts.php | 62 +
app/Http/Controllers/Modals/Categories.php | 89 +
app/Http/Controllers/Modals/Companies.php | 38 +
app/Http/Controllers/Modals/Currencies.php | 86 +
app/Http/Controllers/Modals/Customers.php | 113 +
.../Modals/DocumentItemColumns.php | 138 +
.../Modals/DocumentTransactions.php | 332 +
app/Http/Controllers/Modals/InvoiceEmails.php | 84 +
app/Http/Controllers/Modals/InvoiceShare.php | 81 +
.../Controllers/Modals/InvoiceTemplates.php | 67 +
app/Http/Controllers/Modals/Items.php | 76 +
app/Http/Controllers/Modals/Taxes.php | 82 +
.../Controllers/Modals/TransactionEmails.php | 101 +
.../Controllers/Modals/TransactionShare.php | 80 +
.../Controllers/Modals/TransferTemplates.php | 67 +
app/Http/Controllers/Modals/Vendors.php | 113 +
app/Http/Controllers/Modules/ApiKey.php | 46 +
app/Http/Controllers/Modules/Home.php | 28 +
app/Http/Controllers/Modules/Item.php | 401 +
app/Http/Controllers/Modules/My.php | 24 +
app/Http/Controllers/Modules/Tiles.php | 242 +
app/Http/Controllers/Portal/Dashboard.php | 101 +
app/Http/Controllers/Portal/Invoices.php | 203 +
app/Http/Controllers/Portal/Payments.php | 132 +
app/Http/Controllers/Portal/Profile.php | 107 +
app/Http/Controllers/Purchases/Bills.php | 353 +
.../Controllers/Purchases/RecurringBills.php | 235 +
app/Http/Controllers/Purchases/Vendors.php | 269 +
app/Http/Controllers/Sales/Customers.php | 269 +
app/Http/Controllers/Sales/Invoices.php | 378 +
.../Controllers/Sales/RecurringInvoices.php | 235 +
app/Http/Controllers/Settings/Categories.php | 311 +
app/Http/Controllers/Settings/Company.php | 13 +
app/Http/Controllers/Settings/Currencies.php | 248 +
app/Http/Controllers/Settings/Defaults.php | 57 +
app/Http/Controllers/Settings/Email.php | 23 +
.../Controllers/Settings/EmailTemplates.php | 84 +
app/Http/Controllers/Settings/Invoice.php | 38 +
.../Controllers/Settings/Localisation.php | 58 +
app/Http/Controllers/Settings/Modules.php | 82 +
app/Http/Controllers/Settings/Navigation.php | 77 +
app/Http/Controllers/Settings/Schedule.php | 13 +
app/Http/Controllers/Settings/Taxes.php | 249 +
.../Controllers/SystemSettings/Databases.php | 195 +
.../Controllers/SystemSettings/Sidebar.php | 102 +
app/Http/Controllers/SystemSettings/Users.php | 182 +
app/Http/Controllers/Wizard/Companies.php | 130 +
app/Http/Controllers/Wizard/Currencies.php | 131 +
app/Http/Controllers/Wizard/Finish.php | 58 +
app/Http/Kernel.php | 217 +
app/Http/Livewire/Common/Search.php | 273 +
app/Http/Livewire/Menu/Favorite.php | 99 +
app/Http/Livewire/Menu/Favorites.php | 101 +
app/Http/Livewire/Menu/Neww.php | 83 +
app/Http/Livewire/Menu/Notifications.php | 163 +
app/Http/Livewire/Menu/Profile.php | 32 +
app/Http/Livewire/Menu/Settings.php | 55 +
app/Http/Livewire/Notification/Browser.php | 49 +
app/Http/Livewire/Report/Pin.php | 99 +
app/Http/Livewire/Report/Pins.php | 69 +
app/Http/Livewire/Tab/Pin.php | 96 +
.../Middleware/AddWWWAuthenticateHeader.php | 118 +
app/Http/Middleware/AddXHeader.php | 32 +
app/Http/Middleware/AdminMenu.php | 35 +
app/Http/Middleware/Authenticate.php | 48 +
.../AuthenticateOnceWithBasicAuth.php | 20 +
.../AuthenticateOnceWithDynamicApi.php | 88 +
.../Middleware/AuthenticateOnceWithOAuth.php | 107 +
app/Http/Middleware/CanInstall.php | 26 +
app/Http/Middleware/CheckForReadOnlyMode.php | 68 +
app/Http/Middleware/DateFormat.php | 57 +
app/Http/Middleware/DisableQuic.php | 24 +
app/Http/Middleware/Dropzone.php | 77 +
app/Http/Middleware/EncryptCookies.php | 17 +
app/Http/Middleware/EnforceLocalOnly.php | 35 +
app/Http/Middleware/IdentifyCompany.php | 67 +
app/Http/Middleware/LogoutIfUserDisabled.php | 28 +
app/Http/Middleware/Money.php | 121 +
app/Http/Middleware/PortalMenu.php | 35 +
.../Middleware/RedirectIfAuthenticated.php | 32 +
.../RedirectIfHitModuleSubscription.php | 40 +
.../Middleware/RedirectIfHitPlanLimits.php | 50 +
app/Http/Middleware/RedirectIfNoApiKey.php | 28 +
.../Middleware/RedirectIfNotInstalled.php | 31 +
.../RedirectIfWizardNotCompleted.php | 31 +
app/Http/Middleware/TrimStrings.php | 18 +
app/Http/Middleware/TrustHosts.php | 22 +
app/Http/Middleware/TrustProxies.php | 23 +
app/Http/Middleware/ValidateSignature.php | 86 +
app/Http/Middleware/VerifyCsrfToken.php | 24 +
app/Http/Requests/Auth/Forgot.php | 30 +
app/Http/Requests/Auth/Login.php | 31 +
app/Http/Requests/Auth/Register.php | 31 +
app/Http/Requests/Auth/Reset.php | 32 +
app/Http/Requests/Auth/User.php | 96 +
app/Http/Requests/Banking/Account.php | 32 +
app/Http/Requests/Banking/FundAccount.php | 25 +
app/Http/Requests/Banking/Reconciliation.php | 23 +
.../Banking/ReconciliationCalculate.php | 22 +
app/Http/Requests/Banking/Transaction.php | 101 +
.../Requests/Banking/TransactionConnect.php | 22 +
app/Http/Requests/Banking/Transfer.php | 24 +
app/Http/Requests/Common/BulkAction.php | 21 +
app/Http/Requests/Common/Company.php | 46 +
app/Http/Requests/Common/Contact.php | 89 +
app/Http/Requests/Common/ContactPerson.php | 24 +
app/Http/Requests/Common/CustomMail.php | 23 +
app/Http/Requests/Common/Dashboard.php | 22 +
app/Http/Requests/Common/Import.php | 20 +
app/Http/Requests/Common/Item.php | 84 +
app/Http/Requests/Common/ItemTax.php | 21 +
app/Http/Requests/Common/Notification.php | 21 +
app/Http/Requests/Common/Report.php | 22 +
app/Http/Requests/Common/ReportShow.php | 51 +
app/Http/Requests/Common/TotalItem.php | 32 +
app/Http/Requests/Common/Widget.php | 31 +
app/Http/Requests/Document/Document.php | 172 +
.../Requests/Document/DocumentAddItem.php | 21 +
.../Requests/Document/DocumentHistory.php | 23 +
app/Http/Requests/Document/DocumentItem.php | 41 +
.../Requests/Document/DocumentItemTax.php | 25 +
app/Http/Requests/Document/DocumentTotal.php | 24 +
app/Http/Requests/Install/Database.php | 22 +
app/Http/Requests/Install/Setting.php | 23 +
app/Http/Requests/Module/Install.php | 35 +
app/Http/Requests/Module/Module.php | 35 +
app/Http/Requests/Portal/InvoiceConfirm.php | 20 +
app/Http/Requests/Portal/InvoicePayment.php | 20 +
app/Http/Requests/Portal/InvoiceShow.php | 39 +
app/Http/Requests/Portal/PaymentShow.php | 39 +
app/Http/Requests/Portal/Profile.php | 70 +
app/Http/Requests/Setting/Category.php | 30 +
app/Http/Requests/Setting/Currency.php | 37 +
app/Http/Requests/Setting/EmailTemplate.php | 21 +
app/Http/Requests/Setting/Module.php | 34 +
app/Http/Requests/Setting/Setting.php | 75 +
app/Http/Requests/Setting/Tax.php | 40 +
app/Http/Requests/Wizard/Company.php | 67 +
app/Http/Resources/Auth/Owner.php | 31 +
app/Http/Resources/Auth/Role.php | 28 +
app/Http/Resources/Auth/User.php | 36 +
app/Http/Resources/Banking/Account.php | 39 +
app/Http/Resources/Banking/Reconciliation.php | 35 +
app/Http/Resources/Banking/Transaction.php | 54 +
app/Http/Resources/Banking/TransactionTax.php | 34 +
app/Http/Resources/Banking/Transfer.php | 38 +
app/Http/Resources/Common/Company.php | 33 +
app/Http/Resources/Common/Contact.php | 40 +
app/Http/Resources/Common/ContactPerson.php | 32 +
app/Http/Resources/Common/Dashboard.php | 36 +
app/Http/Resources/Common/Item.php | 41 +
app/Http/Resources/Common/ItemTax.php | 31 +
app/Http/Resources/Common/Report.php | 54 +
app/Http/Resources/Common/Widget.php | 33 +
app/Http/Resources/Document/Document.php | 77 +
.../Resources/Document/DocumentHistory.php | 32 +
app/Http/Resources/Document/DocumentItem.php | 38 +
.../Resources/Document/DocumentItemTax.php | 36 +
app/Http/Resources/Document/DocumentTotal.php | 34 +
app/Http/Resources/Setting/Category.php | 34 +
app/Http/Resources/Setting/Currency.php | 36 +
app/Http/Resources/Setting/Setting.php | 24 +
app/Http/Resources/Setting/Tax.php | 30 +
app/Http/Responses/Common/Items.php | 10 +
app/Http/ViewComposers/ContactType.php | 30 +
app/Http/ViewComposers/DocumentRecurring.php | 40 +
app/Http/ViewComposers/DocumentType.php | 31 +
app/Http/ViewComposers/PlanLimits.php | 77 +
.../ViewComposers/ReadOnlyNotification.php | 23 +
app/Imports/Banking/RecurringTransactions.php | 18 +
app/Imports/Banking/Sheets/Recurring.php | 37 +
.../Banking/Sheets/RecurringTransactions.php | 52 +
app/Imports/Banking/Transactions.php | 61 +
app/Imports/Banking/Transfers.php | 170 +
app/Imports/Common/Items.php | 18 +
app/Imports/Common/Sheets/ItemTaxes.php | 43 +
app/Imports/Common/Sheets/Items.php | 43 +
app/Imports/Purchases/Bills/Bills.php | 26 +
.../Purchases/Bills/Sheets/BillHistories.php | 59 +
.../Purchases/Bills/Sheets/BillItemTaxes.php | 86 +
.../Purchases/Bills/Sheets/BillItems.php | 73 +
.../Purchases/Bills/Sheets/BillTotals.php | 58 +
.../Bills/Sheets/BillTransactions.php | 57 +
app/Imports/Purchases/Bills/Sheets/Bills.php | 70 +
.../RecurringBills/RecurringBills.php | 26 +
.../RecurringBills/Sheets/Recurring.php | 40 +
.../Sheets/RecurringBillHistories.php | 62 +
.../Sheets/RecurringBillItemTaxes.php | 84 +
.../Sheets/RecurringBillItems.php | 76 +
.../Sheets/RecurringBillTotals.php | 62 +
.../RecurringBills/Sheets/RecurringBills.php | 87 +
app/Imports/Purchases/Vendors.php | 44 +
app/Imports/Sales/Customers.php | 49 +
app/Imports/Sales/Invoices/Invoices.php | 26 +
.../Invoices/Sheets/InvoiceHistories.php | 59 +
.../Invoices/Sheets/InvoiceItemTaxes.php | 86 +
.../Sales/Invoices/Sheets/InvoiceItems.php | 73 +
.../Sales/Invoices/Sheets/InvoiceTotals.php | 58 +
.../Invoices/Sheets/InvoiceTransactions.php | 58 +
.../Sales/Invoices/Sheets/Invoices.php | 70 +
.../RecurringInvoices/RecurringInvoices.php | 26 +
.../RecurringInvoices/Sheets/Recurring.php | 40 +
.../Sheets/RecurringInvoiceHistories.php | 62 +
.../Sheets/RecurringInvoiceItemTaxes.php | 86 +
.../Sheets/RecurringInvoiceItems.php | 76 +
.../Sheets/RecurringInvoiceTotals.php | 62 +
.../Sheets/RecurringInvoices.php | 87 +
app/Imports/Settings/Categories.php | 60 +
app/Imports/Settings/Taxes.php | 53 +
app/Interfaces/Export/WithParentSheet.php | 8 +
app/Interfaces/Job/HasOwner.php | 8 +
app/Interfaces/Job/HasSource.php | 8 +
app/Interfaces/Job/ShouldCreate.php | 8 +
app/Interfaces/Job/ShouldDelete.php | 8 +
app/Interfaces/Job/ShouldUpdate.php | 8 +
.../Listener/ShouldUpdateAllCompanies.php | 8 +
app/Interfaces/Utility/DocumentNumber.php | 12 +
app/Interfaces/Utility/TransactionNumber.php | 12 +
app/Jobs/Auth/CreateInvitation.php | 55 +
app/Jobs/Auth/CreatePermission.php | 19 +
app/Jobs/Auth/CreateRole.php | 31 +
app/Jobs/Auth/CreateUser.php | 117 +
app/Jobs/Auth/DeleteInvitation.php | 18 +
app/Jobs/Auth/DeletePermission.php | 18 +
app/Jobs/Auth/DeleteRole.php | 26 +
app/Jobs/Auth/DeleteUser.php | 43 +
app/Jobs/Auth/NotifyUser.php | 36 +
app/Jobs/Auth/UpdatePermission.php | 19 +
app/Jobs/Auth/UpdateRole.php | 35 +
app/Jobs/Auth/UpdateUser.php | 137 +
app/Jobs/Banking/CreateAccount.php | 33 +
.../CreateBankingDocumentTransaction.php | 131 +
app/Jobs/Banking/CreateReconciliation.php | 49 +
app/Jobs/Banking/CreateTransaction.php | 53 +
app/Jobs/Banking/CreateTransactionTaxes.php | 156 +
app/Jobs/Banking/CreateTransfer.php | 134 +
app/Jobs/Banking/DeleteAccount.php | 54 +
app/Jobs/Banking/DeleteReconciliation.php | 26 +
app/Jobs/Banking/DeleteTransaction.php | 44 +
app/Jobs/Banking/DeleteTransfer.php | 26 +
app/Jobs/Banking/DuplicateTransaction.php | 30 +
.../MatchBankingDocumentTransaction.php | 94 +
app/Jobs/Banking/SendTransaction.php | 27 +
.../Banking/SendTransactionAsCustomMail.php | 66 +
app/Jobs/Banking/SplitTransaction.php | 85 +
app/Jobs/Banking/UpdateAccount.php | 68 +
.../UpdateBankingDocumentTransaction.php | 127 +
app/Jobs/Banking/UpdateReconciliation.php | 41 +
app/Jobs/Banking/UpdateTransaction.php | 77 +
app/Jobs/Banking/UpdateTransfer.php | 131 +
app/Jobs/Common/CreateCompany.php | 170 +
app/Jobs/Common/CreateContact.php | 67 +
app/Jobs/Common/CreateContactPerson.php | 21 +
app/Jobs/Common/CreateContactPersons.php | 59 +
app/Jobs/Common/CreateDashboard.php | 145 +
app/Jobs/Common/CreateItem.php | 47 +
app/Jobs/Common/CreateItemTaxes.php | 57 +
app/Jobs/Common/CreateMediableForDownload.php | 116 +
app/Jobs/Common/CreateMediableForExport.php | 101 +
app/Jobs/Common/CreateReport.php | 30 +
app/Jobs/Common/CreateWidget.php | 21 +
app/Jobs/Common/CreateZipForDownload.php | 110 +
app/Jobs/Common/DeleteCompany.php | 98 +
app/Jobs/Common/DeleteContact.php | 63 +
app/Jobs/Common/DeleteContactPerson.php | 18 +
app/Jobs/Common/DeleteDashboard.php | 51 +
app/Jobs/Common/DeleteItem.php | 50 +
app/Jobs/Common/DeleteReport.php | 71 +
app/Jobs/Common/DeleteWidget.php | 18 +
app/Jobs/Common/DuplicateContact.php | 27 +
app/Jobs/Common/UpdateCompany.php | 157 +
app/Jobs/Common/UpdateContact.php | 127 +
app/Jobs/Common/UpdateContactPerson.php | 19 +
app/Jobs/Common/UpdateDashboard.php | 64 +
app/Jobs/Common/UpdateItem.php | 52 +
app/Jobs/Common/UpdateReport.php | 26 +
app/Jobs/Common/UpdateWidget.php | 19 +
app/Jobs/Document/CancelDocument.php | 50 +
app/Jobs/Document/CreateDocument.php | 69 +
app/Jobs/Document/CreateDocumentHistory.php | 67 +
app/Jobs/Document/CreateDocumentItem.php | 203 +
.../Document/CreateDocumentItemsAndTotals.php | 290 +
app/Jobs/Document/DeleteDocument.php | 51 +
app/Jobs/Document/DownloadDocument.php | 68 +
app/Jobs/Document/DuplicateDocument.php | 37 +
app/Jobs/Document/RestoreDocument.php | 28 +
app/Jobs/Document/SendDocument.php | 28 +
.../Document/SendDocumentAsCustomMail.php | 67 +
app/Jobs/Document/UpdateDocument.php | 113 +
app/Jobs/Install/CopyFiles.php | 102 +
app/Jobs/Install/DisableModule.php | 66 +
app/Jobs/Install/DownloadFile.php | 81 +
app/Jobs/Install/DownloadModule.php | 41 +
app/Jobs/Install/EnableModule.php | 64 +
app/Jobs/Install/FinishUpdate.php | 135 +
app/Jobs/Install/InstallModule.php | 66 +
app/Jobs/Install/UninstallModule.php | 66 +
app/Jobs/Install/UnzipFile.php | 79 +
app/Jobs/Setting/CreateCategory.php | 41 +
app/Jobs/Setting/CreateCurrency.php | 38 +
app/Jobs/Setting/CreateEmailTemplate.php | 21 +
app/Jobs/Setting/CreateTax.php | 27 +
app/Jobs/Setting/DeleteCategory.php | 113 +
app/Jobs/Setting/DeleteCurrency.php | 57 +
app/Jobs/Setting/DeleteEmailTemplate.php | 18 +
app/Jobs/Setting/DeleteTax.php | 49 +
app/Jobs/Setting/UpdateCategory.php | 61 +
app/Jobs/Setting/UpdateCurrency.php | 79 +
app/Jobs/Setting/UpdateEmailTemplate.php | 19 +
app/Jobs/Setting/UpdateTax.php | 60 +
app/Listeners/Auth/AddLandingPages.php | 93 +
app/Listeners/Auth/Login.php | 23 +
app/Listeners/Auth/Logout.php | 19 +
.../Banking/IncreaseNextTransactionNumber.php | 25 +
app/Listeners/Common/ClearPlansCache.php | 26 +
app/Listeners/Common/PreparingResponse.php | 34 +
.../Common/SkipScheduleInReadOnlyMode.php | 30 +
.../Document/CreateDocumentCreatedHistory.php | 25 +
.../Document/CreateDocumentTransaction.php | 67 +
.../Document/IncreaseNextDocumentNumber.php | 23 +
.../Document/MarkDocumentCancelled.php | 42 +
.../Document/MarkDocumentReceived.php | 50 +
app/Listeners/Document/MarkDocumentSent.php | 46 +
app/Listeners/Document/MarkDocumentViewed.php | 50 +
app/Listeners/Document/RestoreDocument.php | 36 +
.../SendDocumentPaymentNotification.php | 43 +
.../SendDocumentRecurringNotification.php | 58 +
.../SendDocumentReminderNotification.php | 37 +
.../Document/SendDocumentViewNotification.php | 51 +
.../Document/SettingFieldCreated.php | 83 +
.../Document/SettingFieldUpdated.php | 83 +
.../Email/DisablePersonDueToInvalidEmail.php | 50 +
.../Email/ReportTooManyEmailsSent.php | 14 +
.../Email/SendInvalidEmailNotification.php | 65 +
.../Email/TellFirewallTooManyEmailsSent.php | 40 +
app/Listeners/Menu/ShowInAdmin.php | 65 +
app/Listeners/Menu/ShowInNeww.php | 57 +
app/Listeners/Menu/ShowInNotifications.php | 108 +
app/Listeners/Menu/ShowInPortal.php | 36 +
app/Listeners/Menu/ShowInProfile.php | 39 +
app/Listeners/Menu/ShowInSettings.php | 79 +
app/Listeners/Module/ClearCache.php | 45 +
app/Listeners/Module/FinishInstallation.php | 27 +
app/Listeners/Module/FinishUninstallation.php | 146 +
app/Listeners/Module/InstallExtraModules.php | 63 +
app/Listeners/Module/UpdateExtraModules.php | 68 +
app/Listeners/Report/AddAccounts.php | 93 +
app/Listeners/Report/AddBasis.php | 39 +
app/Listeners/Report/AddContacts.php | 77 +
app/Listeners/Report/AddCustomers.php | 117 +
app/Listeners/Report/AddDate.php | 54 +
app/Listeners/Report/AddDiscount.php | 52 +
app/Listeners/Report/AddExpenseCategories.php | 81 +
app/Listeners/Report/AddGroup.php | 39 +
app/Listeners/Report/AddIncomeCategories.php | 81 +
.../Report/AddIncomeExpenseCategories.php | 122 +
app/Listeners/Report/AddPeriod.php | 40 +
app/Listeners/Report/AddRowsToTax.php | 33 +
app/Listeners/Report/AddSearchString.php | 70 +
app/Listeners/Report/AddVendors.php | 117 +
.../DeleteCategoryDeletedSubCategories.php | 31 +
.../Update/CreateModuleUpdatedHistory.php | 42 +
.../Update/SendNotificationOnFailure.php | 51 +
app/Listeners/Update/V30/Version300.php | 656 +
app/Listeners/Update/V30/Version3013.php | 34 +
app/Listeners/Update/V30/Version3014.php | 71 +
app/Listeners/Update/V30/Version3015.php | 43 +
app/Listeners/Update/V30/Version3016.php | 43 +
app/Listeners/Update/V30/Version3017.php | 43 +
app/Listeners/Update/V30/Version303.php | 107 +
app/Listeners/Update/V30/Version304.php | 111 +
app/Listeners/Update/V30/Version305.php | 95 +
app/Listeners/Update/V30/Version307.php | 43 +
app/Listeners/Update/V30/Version309.php | 63 +
app/Listeners/Update/V31/Version310.php | 43 +
app/Listeners/Update/V31/Version3112.php | 43 +
app/Listeners/Update/V31/Version3115.php | 43 +
app/Listeners/Update/V31/Version3119.php | 58 +
app/Listeners/Update/V31/Version315.php | 93 +
app/Listeners/Update/V31/Version317.php | 78 +
app/Listeners/Update/V31/Version318.php | 91 +
app/Listeners/Update/V32/Version320.php | 61 +
app/Models/Auth/Permission.php | 81 +
app/Models/Auth/Role.php | 103 +
app/Models/Auth/User.php | 420 +
app/Models/Auth/UserCompany.php | 36 +
app/Models/Auth/UserDashboard.php | 41 +
app/Models/Auth/UserInvitation.php | 40 +
app/Models/Auth/UserRole.php | 36 +
app/Models/Banking/Account.php | 223 +
app/Models/Banking/FundAccount.php | 43 +
app/Models/Banking/Reconciliation.php | 89 +
app/Models/Banking/Transaction.php | 784 +
app/Models/Banking/TransactionTax.php | 123 +
app/Models/Banking/Transfer.php | 306 +
app/Models/Common/Company.php | 707 +
app/Models/Common/Contact.php | 423 +
app/Models/Common/ContactPerson.php | 70 +
app/Models/Common/Dashboard.php | 162 +
app/Models/Common/Item.php | 237 +
app/Models/Common/ItemTax.php | 30 +
app/Models/Common/Media.php | 33 +
app/Models/Common/Notification.php | 20 +
app/Models/Common/Recurring.php | 187 +
app/Models/Common/Report.php | 99 +
app/Models/Common/Widget.php | 138 +
app/Models/Document/Document.php | 794 +
app/Models/Document/DocumentHistory.php | 57 +
app/Models/Document/DocumentItem.php | 157 +
app/Models/Document/DocumentItemTax.php | 73 +
app/Models/Document/DocumentTotal.php | 100 +
app/Models/Module/Module.php | 29 +
app/Models/Module/ModuleHistory.php | 22 +
app/Models/Setting/Category.php | 452 +
app/Models/Setting/Currency.php | 239 +
app/Models/Setting/EmailTemplate.php | 114 +
app/Models/Setting/Setting.php | 37 +
app/Models/Setting/Tax.php | 182 +
app/Models/Settings/DatabaseConnection.php | 30 +
app/Notifications/Auth/Invitation.php | 53 +
app/Notifications/Auth/Reset.php | 61 +
app/Notifications/Banking/Transaction.php | 159 +
.../Common/DownloadCompleted.php | 81 +
app/Notifications/Common/DownloadFailed.php | 77 +
app/Notifications/Common/ExportCompleted.php | 81 +
app/Notifications/Common/ExportFailed.php | 77 +
app/Notifications/Common/ImportCompleted.php | 77 +
app/Notifications/Common/ImportFailed.php | 83 +
app/Notifications/Email/InvalidEmail.php | 80 +
app/Notifications/Install/UpdateFailed.php | 125 +
app/Notifications/Portal/PaymentReceived.php | 152 +
app/Notifications/Purchase/Bill.php | 113 +
app/Notifications/Sale/Invoice.php | 166 +
app/Observers/Transaction.php | 80 +
app/Providers/App.php | 55 +
app/Providers/Auth.php | 27 +
app/Providers/Binding.php | 22 +
app/Providers/Blade.php | 55 +
app/Providers/Broadcast.php | 20 +
app/Providers/Event.php | 158 +
app/Providers/Macro.php | 157 +
app/Providers/Observer.php | 29 +
app/Providers/Queue.php | 129 +
app/Providers/Route.php | 330 +
app/Providers/Validation.php | 158 +
app/Providers/ViewComposer.php | 55 +
app/Relations/HasMany/Category.php | 25 +
app/Reports/DiscountSummary.php | 131 +
app/Reports/ExpenseSummary.php | 67 +
app/Reports/IncomeExpenseSummary.php | 101 +
app/Reports/IncomeSummary.php | 67 +
app/Reports/ProfitLoss.php | 316 +
app/Reports/TaxSummary.php | 227 +
app/Scopes/Category.php | 26 +
app/Scopes/Company.php | 51 +
app/Scopes/Contact.php | 28 +
app/Scopes/Document.php | 25 +
app/Scopes/Transaction.php | 27 +
app/Traits/Categories.php | 342 +
app/Traits/Charts.php | 235 +
app/Traits/Cloud.php | 47 +
app/Traits/Companies.php | 208 +
app/Traits/Contacts.php | 103 +
app/Traits/Currencies.php | 85 +
app/Traits/Database.php | 13 +
app/Traits/DateTime.php | 373 +
app/Traits/Documents.php | 316 +
app/Traits/Emails.php | 51 +
app/Traits/HasApiTokens.php | 83 +
app/Traits/Import.php | 583 +
app/Traits/Jobs.php | 83 +
app/Traits/Media.php | 63 +
app/Traits/Modules.php | 659 +
app/Traits/Omnipay.php | 210 +
app/Traits/Owners.php | 18 +
app/Traits/Permissions.php | 514 +
app/Traits/Plans.php | 104 +
app/Traits/Recurring.php | 233 +
app/Traits/Relationships.php | 70 +
app/Traits/Scopes.php | 114 +
app/Traits/SearchString.php | 196 +
app/Traits/Settings.php | 30 +
app/Traits/SiteApi.php | 86 +
app/Traits/Sources.php | 72 +
app/Traits/Tailwind.php | 113 +
app/Traits/Tenants.php | 30 +
app/Traits/Trackers.php | 43 +
app/Traits/Transactions.php | 262 +
app/Traits/Translations.php | 41 +
app/Traits/Updates.php | 83 +
app/Traits/Uploads.php | 216 +
app/Traits/Users.php | 138 +
app/Traits/ViewComponents.php | 746 +
app/Utilities/BusinessNavigation.php | 39 +
app/Utilities/Console.php | 56 +
app/Utilities/Date.php | 140 +
app/Utilities/DocumentNumber.php | 39 +
app/Utilities/Export.php | 57 +
app/Utilities/FundAccountSpreadsheet.php | 297 +
app/Utilities/Import.php | 104 +
app/Utilities/Info.php | 104 +
app/Utilities/Installer.php | 324 +
app/Utilities/ModuleActivator.php | 179 +
app/Utilities/Modules.php | 92 +
app/Utilities/Overrider.php | 140 +
app/Utilities/QueueCollection.php | 10 +
app/Utilities/Recurring.php | 51 +
app/Utilities/Reports.php | 164 +
app/Utilities/SidebarPermissions.php | 88 +
app/Utilities/Str.php | 57 +
app/Utilities/SystemAccess.php | 73 +
app/Utilities/TransactionNumber.php | 62 +
app/Utilities/Versions.php | 248 +
app/Utilities/Widgets.php | 222 +
app/Utilities/helpers.php | 483 +
app/View/Components/Alert.php | 142 +
app/View/Components/Alert/Border.php | 18 +
app/View/Components/Alert/Danger.php | 18 +
app/View/Components/Alert/Info.php | 18 +
app/View/Components/Alert/Success.php | 18 +
app/View/Components/Alert/Warning.php | 18 +
app/View/Components/Button.php | 72 +
app/View/Components/Button/Hover.php | 36 +
app/View/Components/Contacts/Form/Address.php | 18 +
app/View/Components/Contacts/Form/Billing.php | 18 +
app/View/Components/Contacts/Form/Buttons.php | 18 +
app/View/Components/Contacts/Form/Content.php | 18 +
app/View/Components/Contacts/Form/General.php | 18 +
app/View/Components/Contacts/Form/Persons.php | 18 +
.../Components/Contacts/Index/Buttons.php | 18 +
.../Components/Contacts/Index/Content.php | 18 +
.../Components/Contacts/Index/MoreButtons.php | 18 +
app/View/Components/Contacts/Script.php | 75 +
app/View/Components/Contacts/Show/Buttons.php | 18 +
app/View/Components/Contacts/Show/Content.php | 121 +
.../Components/Contacts/Show/MoreButtons.php | 18 +
app/View/Components/Date.php | 68 +
app/View/Components/DeleteButton.php | 288 +
app/View/Components/DeleteLink.php | 301 +
.../Components/Documents/Form/Advanced.php | 18 +
.../Components/Documents/Form/Buttons.php | 18 +
.../Components/Documents/Form/Company.php | 22 +
.../Components/Documents/Form/Contact.php | 230 +
.../Components/Documents/Form/Content.php | 24 +
app/View/Components/Documents/Form/Footer.php | 18 +
.../Components/Documents/Form/ItemButton.php | 105 +
.../Components/Documents/Form/ItemColumns.php | 31 +
app/View/Components/Documents/Form/Items.php | 21 +
.../Components/Documents/Form/LineItem.php | 18 +
app/View/Components/Documents/Form/Main.php | 18 +
.../Components/Documents/Form/Metadata.php | 18 +
app/View/Components/Documents/Form/Note.php | 18 +
.../Components/Documents/Form/Recurring.php | 18 +
.../Documents/Form/RecurringMetadata.php | 18 +
app/View/Components/Documents/Form/Totals.php | 18 +
.../Components/Documents/Index/BulkAction.php | 18 +
.../Components/Documents/Index/Buttons.php | 18 +
.../Components/Documents/Index/Content.php | 18 +
.../Components/Documents/Index/Document.php | 18 +
.../Documents/Index/Information.php | 63 +
.../Documents/Index/MoreButtons.php | 18 +
.../Documents/Index/RecurringTemplates.php | 18 +
app/View/Components/Documents/Script.php | 88 +
.../Components/Documents/Show/Attachment.php | 39 +
.../Components/Documents/Show/Buttons.php | 18 +
.../Components/Documents/Show/Children.php | 28 +
.../Components/Documents/Show/Content.php | 18 +
app/View/Components/Documents/Show/Create.php | 35 +
.../Components/Documents/Show/GetPaid.php | 32 +
.../Components/Documents/Show/MakePayment.php | 32 +
.../Components/Documents/Show/Message.php | 44 +
.../Components/Documents/Show/MoreButtons.php | 18 +
.../Components/Documents/Show/Receive.php | 41 +
.../Components/Documents/Show/Restore.php | 39 +
.../Components/Documents/Show/Schedule.php | 36 +
app/View/Components/Documents/Show/Send.php | 45 +
.../Components/Documents/Show/Template.php | 18 +
.../Components/Documents/Template/Classic.php | 18 +
.../Documents/Template/Ddefault.php | 18 +
.../Documents/Template/LineItem.php | 18 +
.../Components/Documents/Template/Modern.php | 18 +
app/View/Components/Dropdown.php | 34 +
app/View/Components/Dropdown/Button.php | 18 +
app/View/Components/Dropdown/Link.php | 33 +
app/View/Components/EmptyPage.php | 370 +
app/View/Components/Form.php | 132 +
app/View/Components/Form/Accordion.php | 46 +
app/View/Components/Form/Buttons.php | 139 +
app/View/Components/Form/Group/Account.php | 73 +
app/View/Components/Form/Group/Attachment.php | 80 +
app/View/Components/Form/Group/Category.php | 184 +
app/View/Components/Form/Group/Checkbox.php | 27 +
app/View/Components/Form/Group/Color.php | 20 +
app/View/Components/Form/Group/Contact.php | 83 +
app/View/Components/Form/Group/Country.php | 28 +
app/View/Components/Form/Group/Currency.php | 60 +
app/View/Components/Form/Group/Customer.php | 10 +
app/View/Components/Form/Group/Date.php | 20 +
app/View/Components/Form/Group/DateTime.php | 20 +
app/View/Components/Form/Group/Editor.php | 20 +
app/View/Components/Form/Group/Email.php | 20 +
app/View/Components/Form/Group/File.php | 38 +
app/View/Components/Form/Group/Import.php | 38 +
.../Components/Form/Group/InvoiceText.php | 20 +
app/View/Components/Form/Group/Locale.php | 26 +
app/View/Components/Form/Group/Money.php | 20 +
app/View/Components/Form/Group/Number.php | 20 +
.../Components/Form/Group/NumberDigit.php | 53 +
app/View/Components/Form/Group/Password.php | 20 +
.../Components/Form/Group/PaymentMethod.php | 33 +
.../Components/Form/Group/PaymentTerm.php | 42 +
app/View/Components/Form/Group/Radio.php | 30 +
app/View/Components/Form/Group/Recurring.php | 225 +
app/View/Components/Form/Group/Select.php | 20 +
app/View/Components/Form/Group/Sswitch.php | 20 +
app/View/Components/Form/Group/Tax.php | 73 +
app/View/Components/Form/Group/Text.php | 20 +
app/View/Components/Form/Group/Textarea.php | 22 +
app/View/Components/Form/Group/Time.php | 20 +
app/View/Components/Form/Group/Toggle.php | 20 +
app/View/Components/Form/Group/Vendor.php | 10 +
app/View/Components/Form/Input/Checkbox.php | 20 +
app/View/Components/Form/Input/Color.php | 20 +
app/View/Components/Form/Input/Editor.php | 20 +
app/View/Components/Form/Input/Email.php | 20 +
app/View/Components/Form/Input/Ffile.php | 30 +
app/View/Components/Form/Input/Hidden.php | 20 +
app/View/Components/Form/Input/Import.php | 30 +
app/View/Components/Form/Input/Input.php | 20 +
app/View/Components/Form/Input/Money.php | 20 +
app/View/Components/Form/Input/Number.php | 20 +
app/View/Components/Form/Input/Password.php | 20 +
app/View/Components/Form/Input/Radio.php | 20 +
app/View/Components/Form/Input/Select.php | 20 +
app/View/Components/Form/Input/Text.php | 20 +
app/View/Components/Form/Input/Textarea.php | 20 +
app/View/Components/Form/Section.php | 38 +
app/View/Components/Icon.php | 86 +
app/View/Components/Index/Balance.php | 71 +
app/View/Components/Index/Bulkaction.php | 108 +
app/View/Components/Index/Category.php | 120 +
app/View/Components/Index/Country.php | 46 +
app/View/Components/Index/Currency.php | 45 +
app/View/Components/Index/Ddefault.php | 63 +
app/View/Components/Index/Disable.php | 80 +
app/View/Components/Index/Search.php | 121 +
app/View/Components/Index/Status.php | 56 +
app/View/Components/Index/Summary.php | 31 +
app/View/Components/Layouts/Admin.php | 18 +
app/View/Components/Layouts/Admin/Head.php | 18 +
app/View/Components/Layouts/Admin/Menu.php | 51 +
.../Layouts/Admin/Notifications.php | 57 +
app/View/Components/Layouts/Modules.php | 23 +
app/View/Components/Layouts/Modules/Bar.php | 60 +
.../Components/Layouts/Modules/Releases.php | 26 +
.../Components/Layouts/Modules/Reviews.php | 26 +
app/View/Components/Layouts/Portal/Menu.php | 34 +
app/View/Components/Layouts/Wizard.php | 18 +
.../Components/Layouts/Wizard/Scripts.php | 160 +
app/View/Components/Link.php | 66 +
app/View/Components/Link/Hover.php | 36 +
app/View/Components/Media/Ffile.php | 36 +
app/View/Components/Menu/Favorite.php | 41 +
app/View/Components/Modules/Banners.php | 12 +
app/View/Components/Modules/Free.php | 12 +
app/View/Components/Modules/Installed.php | 12 +
app/View/Components/Modules/Item.php | 31 +
app/View/Components/Modules/Items.php | 257 +
app/View/Components/Modules/Nnew.php | 12 +
app/View/Components/Modules/NoApps.php | 12 +
app/View/Components/Modules/Paid.php | 12 +
app/View/Components/Modules/PreSale.php | 12 +
app/View/Components/Modules/Purchased.php | 12 +
app/View/Components/Pagination.php | 53 +
app/View/Components/PaymentMethod.php | 81 +
app/View/Components/Script.php | 72 +
app/View/Components/Script/Declaration.php | 65 +
.../Components/Script/Exceptions/Trackers.php | 144 +
app/View/Components/SearchString.php | 292 +
app/View/Components/Show/Accordion.php | 46 +
app/View/Components/Show/NoRecords.php | 144 +
app/View/Components/Show/Right.php | 21 +
app/View/Components/Show/Status.php | 56 +
app/View/Components/Suggestions.php | 81 +
app/View/Components/Table/Actions.php | 114 +
app/View/Components/Table/Tbody.php | 18 +
app/View/Components/Table/Td.php | 80 +
app/View/Components/Table/Th.php | 75 +
app/View/Components/Table/Thead.php | 18 +
app/View/Components/Table/Tr.php | 61 +
app/View/Components/Tips.php | 104 +
app/View/Components/Title.php | 46 +
app/View/Components/Tooltip.php | 163 +
.../Transactions/Index/BulkAction.php | 18 +
.../Components/Transactions/Index/Buttons.php | 18 +
.../Components/Transactions/Index/Content.php | 18 +
.../Transactions/Index/MoreButtons.php | 18 +
.../Transactions/Index/RecurringTemplates.php | 18 +
.../Transactions/Index/Transaction.php | 18 +
app/View/Components/Transactions/Script.php | 56 +
.../Transactions/Show/Attachment.php | 18 +
.../Components/Transactions/Show/Buttons.php | 18 +
.../Components/Transactions/Show/Children.php | 18 +
.../Components/Transactions/Show/Connect.php | 18 +
.../Components/Transactions/Show/Content.php | 18 +
.../Components/Transactions/Show/Create.php | 18 +
.../Transactions/Show/MoreButtons.php | 18 +
.../Components/Transactions/Show/Schedule.php | 18 +
.../Components/Transactions/Show/Template.php | 18 +
.../Components/Transactions/Show/Transfer.php | 18 +
.../Transactions/Template/Ddefault.php | 18 +
app/View/Components/Transfers/Script.php | 55 +
.../Components/Transfers/Show/Attachment.php | 18 +
.../Components/Transfers/Show/Buttons.php | 18 +
.../Components/Transfers/Show/Content.php | 18 +
app/View/Components/Transfers/Show/Create.php | 18 +
.../Components/Transfers/Show/MoreButtons.php | 18 +
.../Components/Transfers/Show/Template.php | 18 +
.../Transfers/Show/Transactions.php | 18 +
.../Transfers/Template/Ddefault.php | 18 +
.../Components/Transfers/Template/Second.php | 18 +
.../Components/Transfers/Template/Third.php | 18 +
app/View/Components/UpdateAlert.php | 73 +
app/View/Components/Widgets/Contact.php | 52 +
.../Components/Widgets/InvoiceHistory.php | 50 +
app/View/Components/Widgets/LastPayment.php | 50 +
.../Components/Widgets/LatestInvoices.php | 50 +
.../Components/Widgets/OutstandingBalance.php | 32 +
.../Components/Widgets/PaymentHistory.php | 50 +
app/View/Presenters/Menu.php | 280 +
app/Widgets/AccountBalance.php | 46 +
app/Widgets/BankFeeds.php | 24 +
app/Widgets/CashFlow.php | 217 +
app/Widgets/Currencies.php | 27 +
app/Widgets/ExpensesByCategory.php | 44 +
app/Widgets/Payables.php | 86 +
app/Widgets/ProfitLoss.php | 196 +
app/Widgets/Receivables.php | 86 +
artisan | 29 +
bootstrap/app.php | 55 +
bootstrap/autoload.php | 20 +
bootstrap/cache/.gitignore | 2 +
compose.jiangling.yml | 22 +
composer.json | 223 +
composer.lock | 15900 +++++
config/apexcharts.php | 80 +
config/api.php | 159 +
config/app.php | 225 +
config/auth.php | 126 +
config/broadcasting.php | 70 +
config/bugsnag.php | 364 +
config/business_navigation.php | 277 +
config/cache.php | 110 +
config/charts.php | 15 +
config/cors.php | 34 +
config/database.php | 219 +
config/debugbar.php | 278 +
config/dompdf.php | 284 +
config/excel.php | 355 +
config/filesystems.php | 136 +
config/firewall.php | 466 +
config/hashing.php | 52 +
config/ide-helper.php | 246 +
config/image.php | 20 +
config/imagecache.php | 71 +
config/import.php | 36 +
config/language.php | 231 +
config/laratrust.php | 360 +
config/laravel-model-caching.php | 13 +
config/livewire.php | 159 +
config/logging.php | 161 +
config/mail.php | 133 +
config/mediable.php | 236 +
config/menu.php | 16 +
config/module.php | 200 +
config/money.php | 1843 +
config/queue.php | 94 +
config/read-only.php | 50 +
config/sanctum.php | 67 +
config/search-string.php | 592 +
config/sentry.php | 112 +
config/services.php | 37 +
config/session.php | 198 +
config/setting.php | 223 +
config/sortable.php | 79 +
config/stats.php | 96 +
config/trustedproxy.php | 7 +
config/type.php | 619 +
config/update.php | 24 +
config/version.php | 25 +
config/view.php | 36 +
database/.gitignore | 1 +
database/factories/Account.php | 76 +
database/factories/Category.php | 125 +
database/factories/Company.php | 56 +
database/factories/Contact.php | 95 +
database/factories/Currency.php | 77 +
database/factories/Dashboard.php | 79 +
database/factories/Document.php | 370 +
database/factories/Item.php | 62 +
database/factories/Reconciliation.php | 64 +
database/factories/Tax.php | 119 +
database/factories/Transaction.php | 147 +
database/factories/Transfer.php | 41 +
database/factories/User.php | 76 +
database/factories/Widget.php | 36 +
.../migrations/2017_09_14_000000_core_v1.php | 535 +
.../migrations/2019_11_16_000000_core_v2.php | 460 +
.../2022_05_10_000000_core_v300.php | 105 +
.../2022_06_28_000000_core_v304.php | 30 +
.../2022_07_21_000000_core_v305.php | 34 +
.../2022_08_29_000000_core_v3015.php | 53 +
.../2022_08_29_000000_core_v307.php | 42 +
.../2023_06_22_000000_core_v3016.php | 64 +
.../2023_08_14_000000_core_v3017.php | 34 +
.../2023_10_03_000000_core_v310.php | 62 +
.../2024_09_26_000000_core_v3112.php | 34 +
.../2024_12_29_000000_core_v3115.php | 34 +
.../2026_02_17_000000_core_v3122.php | 56 +
...7_18_000000_create_fund_accounts_table.php | 36 +
...0_000000_create_system_settings_tables.php | 123 +
database/seeds/Accounts.php | 44 +
database/seeds/Categories.php | 104 +
database/seeds/Company.php | 24 +
database/seeds/Currencies.php | 53 +
database/seeds/Dashboards.php | 49 +
database/seeds/DatabaseSeeder.php | 16 +
database/seeds/EmailTemplates.php | 107 +
database/seeds/Modules.php | 41 +
database/seeds/Permissions.php | 174 +
database/seeds/Reports.php | 76 +
database/seeds/SampleData.php | 67 +
database/seeds/Settings.php | 51 +
database/seeds/TestCompany.php | 135 +
database/seeds/User.php | 18 +
deploy/Dockerfile | 52 +
deploy/apache-vhost.conf | 16 +
deploy/entrypoint.sh | 29 +
deploy/host-nginx.conf | 19 +
deploy/php.ini | 10 +
docs/ecommerce-finance-development.md | 320 +
docs/team-collaboration.md | 77 +
index.php | 38 +
manifest.json | 125 +
modules/.gitkeep | 0
nginx.example.com.conf | 54 +
.../Translation/MessageSelector.php | 412 +
.../View/Concerns/ManagesStacks.php | 201 +
.../laravel-module/Commands/DeleteCommand.php | 22 +
.../Commands/DisableCommand.php | 59 +
.../laravel-module/Commands/EnableCommand.php | 59 +
.../Commands/InstallCommand.php | 59 +
.../HandleRequests/HandleRequests.php | 107 +
.../maatwebsite/excel/Fakes/ExcelFake.php | 358 +
overrides/maatwebsite/excel/Fakes/fake_file | 0
overrides/maatwebsite/excel/QueuedWriter.php | 215 +
.../symfony/process/PhpExecutableFinder.php | 177 +
package-lock.json | 21322 ++++++
package.json | 105 +
phpunit.xml | 34 +
presets.js | 537 +
public/.htaccess | 21 +
public/akaunting-js/generalAction.js | 514 +
public/akaunting-js/hotkeys.js | 62 +
public/akaunting-js/popper.js | 6 +
public/akaunting-js/swiper-bundle.min.js | 14 +
public/css/app.css | 5 +
public/css/custom_loading.css | 99 +
public/css/element.css | 15726 +++++
public/css/fonts/NotoSansArabic.ttf | Bin 0 -> 844676 bytes
public/css/fonts/element-icons.ttf | Bin 0 -> 55956 bytes
public/css/fonts/element-icons.woff | Bin 0 -> 28200 bytes
public/css/fonts/firefly_sung_normal.ttf | Bin 0 -> 15443432 bytes
.../MaterialIconsOutlined-Regular.eot | Bin 0 -> 357942 bytes
.../MaterialIconsOutlined-Regular.otf | Bin 0 -> 314916 bytes
.../MaterialIconsOutlined-Regular.ttf | Bin 0 -> 357668 bytes
.../MaterialIconsOutlined-Regular.woff | Bin 0 -> 172364 bytes
.../MaterialIconsOutlined-Regular.woff2 | Bin 0 -> 130748 bytes
.../Regular/MaterialIcons-Regular.eot | Bin 0 -> 327556 bytes
.../Regular/MaterialIcons-Regular.otf | Bin 0 -> 702804 bytes
.../Regular/MaterialIcons-Regular.ttf | Bin 0 -> 327360 bytes
.../Regular/MaterialIcons-Regular.woff | Bin 0 -> 166412 bytes
.../Regular/MaterialIcons-Regular.woff2 | Bin 0 -> 118032 bytes
.../Rounded/MaterialIconsRound-Regular.eot | Bin 0 -> 424658 bytes
.../Rounded/MaterialIconsRound-Regular.otf | Bin 0 -> 373784 bytes
.../Rounded/MaterialIconsRound-Regular.ttf | Bin 0 -> 424396 bytes
.../Rounded/MaterialIconsRound-Regular.woff | Bin 0 -> 196788 bytes
.../Rounded/MaterialIconsRound-Regular.woff2 | Bin 0 -> 146364 bytes
.../Sharp/MaterialIconsSharp-Regular.eot | Bin 0 -> 304070 bytes
.../Sharp/MaterialIconsSharp-Regular.otf | Bin 0 -> 266260 bytes
.../Sharp/MaterialIconsSharp-Regular.ttf | Bin 0 -> 303808 bytes
.../Sharp/MaterialIconsSharp-Regular.woff | Bin 0 -> 149932 bytes
.../Sharp/MaterialIconsSharp-Regular.woff2 | Bin 0 -> 114500 bytes
public/css/fonts/material-icons/style.css | 141 +
public/css/print.css | 1137 +
public/css/third_party/dropzone_custom.css | 138 +
public/css/third_party/swiper-bundle.min.css | 1 +
public/css/third_party/vue-html-editor.css | 945 +
.../third_party/vue-html-editor_custom.css | 288 +
public/files/import/bills.xlsx | Bin 0 -> 15282 bytes
public/files/import/categories.xlsx | Bin 0 -> 9666 bytes
public/files/import/customers.xlsx | Bin 0 -> 9475 bytes
public/files/import/invoices.xlsx | Bin 0 -> 15402 bytes
public/files/import/items.xlsx | Bin 0 -> 10532 bytes
public/files/import/recurring-bills.xlsx | Bin 0 -> 14619 bytes
public/files/import/recurring-invoices.xlsx | Bin 0 -> 14169 bytes
.../files/import/recurring-transactions.xlsx | Bin 0 -> 10231 bytes
public/files/import/taxes.xlsx | Bin 0 -> 9598 bytes
public/files/import/transactions.xlsx | Bin 0 -> 10206 bytes
public/files/import/transfers.xlsx | Bin 0 -> 10356 bytes
public/files/import/vendors.xlsx | Bin 0 -> 9611 bytes
public/fonts/MaterialIcons-Regular.eot | Bin 0 -> 356347 bytes
public/fonts/MaterialIcons-Regular.ttf | Bin 0 -> 327360 bytes
public/fonts/MaterialIcons-Regular.woff | Bin 0 -> 166412 bytes
public/fonts/MaterialIcons-Regular.woff2 | Bin 0 -> 356348 bytes
public/img/akaunting-loading.gif | Bin 0 -> 104457 bytes
public/img/akaunting-logo-gold.png | Bin 0 -> 7763 bytes
public/img/akaunting-logo-green.svg | 1 +
public/img/akaunting-logo-horizontal.svg | 61 +
public/img/akaunting-logo-purple.svg | 6 +
public/img/akaunting-logo-white.svg | 1 +
public/img/akaunting-logo-wild-blue.png | Bin 0 -> 3929 bytes
public/img/auth/bullet_active.png | Bin 0 -> 200 bytes
public/img/auth/bullet_inactive.png | Bin 0 -> 212 bytes
public/img/auth/chart.png | Bin 0 -> 165877 bytes
public/img/auth/client.png | Bin 0 -> 71910 bytes
public/img/auth/folder.png | Bin 0 -> 125125 bytes
public/img/auth/layout.png | Bin 0 -> 160811 bytes
public/img/auth/login-bg.png | Bin 0 -> 198921 bytes
public/img/auth/logo.png | Bin 0 -> 1546 bytes
public/img/auth/small-logo.png | Bin 0 -> 1629 bytes
public/img/company.png | Bin 0 -> 13098 bytes
public/img/credit_card/amex.png | Bin 0 -> 3232 bytes
public/img/credit_card/chip.png | Bin 0 -> 8992 bytes
public/img/credit_card/dinersclub.png | Bin 0 -> 2292 bytes
public/img/credit_card/discover.png | Bin 0 -> 3372 bytes
public/img/credit_card/jcb.png | Bin 0 -> 3587 bytes
public/img/credit_card/mastercard.png | Bin 0 -> 5693 bytes
public/img/credit_card/troy.png | Bin 0 -> 2618 bytes
public/img/credit_card/unionpay.png | Bin 0 -> 6697 bytes
public/img/credit_card/visa.png | Bin 0 -> 3580 bytes
public/img/dashboard.png | Bin 0 -> 258828 bytes
public/img/empty_pages/bills.png | Bin 0 -> 110926 bytes
public/img/empty_pages/companies.png | Bin 0 -> 101712 bytes
public/img/empty_pages/contacs.png | Bin 0 -> 115862 bytes
public/img/empty_pages/customers.png | Bin 0 -> 68929 bytes
public/img/empty_pages/default.png | Bin 0 -> 86016 bytes
public/img/empty_pages/invoices.png | Bin 0 -> 62276 bytes
public/img/empty_pages/items.png | Bin 0 -> 93852 bytes
public/img/empty_pages/no-apps.png | Bin 0 -> 383332 bytes
public/img/empty_pages/payments.png | Bin 0 -> 77376 bytes
public/img/empty_pages/reconciliations.png | Bin 0 -> 88797 bytes
.../img/empty_pages/recurring_templates.png | Bin 0 -> 115169 bytes
public/img/empty_pages/revenues.png | Bin 0 -> 76728 bytes
public/img/empty_pages/subscriptions.png | Bin 0 -> 75953 bytes
public/img/empty_pages/taxes.png | Bin 0 -> 76693 bytes
public/img/empty_pages/tickets.png | Bin 0 -> 72006 bytes
public/img/empty_pages/transactions.png | Bin 0 -> 103418 bytes
public/img/empty_pages/transfers.png | Bin 0 -> 90627 bytes
public/img/empty_pages/users.png | Bin 0 -> 1083035 bytes
public/img/empty_pages/vendors.png | Bin 0 -> 59446 bytes
public/img/errors/403.png | Bin 0 -> 175499 bytes
public/img/errors/404.png | Bin 0 -> 142162 bytes
public/img/errors/500.png | Bin 0 -> 169358 bytes
public/img/favicon.ico | Bin 0 -> 99678 bytes
public/img/icons/.gitkeep | 0
public/img/import.png | Bin 0 -> 158858 bytes
public/img/invoice_templates/classic.png | Bin 0 -> 37157 bytes
public/img/invoice_templates/default.png | Bin 0 -> 36208 bytes
public/img/invoice_templates/modern.png | Bin 0 -> 38307 bytes
.../img/no_records/accounts_transactions.png | Bin 0 -> 19970 bytes
public/img/no_records/accounts_transfers.png | Bin 0 -> 16268 bytes
public/img/no_records/customers_invoices.png | Bin 0 -> 37289 bytes
.../img/no_records/customers_transactions.png | Bin 0 -> 22302 bytes
public/img/no_records/vendors_bills.png | Bin 0 -> 17408 bytes
.../img/no_records/vendors_transactions.png | Bin 0 -> 27421 bytes
public/img/pwa/icon-192x192-maskable.png | Bin 0 -> 5254 bytes
public/img/pwa/icon-192x192.png | Bin 0 -> 7919 bytes
public/img/pwa/icon-512x512-maskable.png | Bin 0 -> 13504 bytes
public/img/pwa/icon-512x512.png | Bin 0 -> 21439 bytes
public/img/pwa/screenshot-dashboard.png | Bin 0 -> 374201 bytes
public/img/pwa/screenshot-invoice.png | Bin 0 -> 479388 bytes
public/img/pwa/splash-1242x2208.png | Bin 0 -> 15478 bytes
public/img/pwa/splash-1242x2688.png | Bin 0 -> 16284 bytes
public/img/pwa/splash-1536x2048.png | Bin 0 -> 16123 bytes
public/img/pwa/splash-1668x2224.png | Bin 0 -> 16983 bytes
public/img/pwa/splash-1668x2388.png | Bin 0 -> 17311 bytes
public/img/pwa/splash-2048x2732.png | Bin 0 -> 19157 bytes
public/img/pwa/splash-640x1136.png | Bin 0 -> 8499 bytes
public/img/pwa/splash-750x1334.png | Bin 0 -> 10198 bytes
public/img/pwa/splash-828x1792.png | Bin 0 -> 11775 bytes
public/img/tailwind_icons/not-equal.svg | 5 +
public/img/transfer_templates/default.png | Bin 0 -> 24272 bytes
public/img/transfer_templates/second.png | Bin 0 -> 23845 bytes
public/img/transfer_templates/third.png | Bin 0 -> 22133 bytes
public/img/user.svg | 1 +
public/img/wizard-modules.png | Bin 0 -> 78154 bytes
public/img/wizard-rocket.gif | Bin 0 -> 1181401 bytes
public/index.php | 76 +
public/money.json | 58961 ++++++++++++++++
public/shortcuts-config.json | 30 +
resources/assets/css/creditcard/style.scss | 685 +
resources/assets/js/Install.vue | 8 +
resources/assets/js/Wizard.vue | 48 +
resources/assets/js/bootstrap.js | 69 +
.../assets/js/components/AkauntingColor.vue | 289 +
.../js/components/AkauntingCompanyEdit.vue | 244 +
.../AkauntingConnectTransactions.vue | 542 +
.../js/components/AkauntingContactCard.vue | 689 +
.../js/components/AkauntingCountdown.vue | 141 +
.../AkauntingCurrencyConversion.vue | 117 +
.../assets/js/components/AkauntingDate.vue | 221 +
.../js/components/AkauntingDocumentButton.vue | 321 +
.../AkauntingDropzoneFileUpload.vue | 292 +
.../components/AkauntingEditItemColumns.vue | 172 +
.../js/components/AkauntingHtmlEditor.vue | 112 +
.../assets/js/components/AkauntingImport.vue | 254 +
.../js/components/AkauntingItemButton.vue | 669 +
.../assets/js/components/AkauntingModal.vue | 180 +
.../js/components/AkauntingModalAddNew.vue | 381 +
.../assets/js/components/AkauntingMoney.vue | 250 +
.../js/components/AkauntingRadioGroup.vue | 87 +
.../js/components/AkauntingRecurring.vue | 394 +
.../assets/js/components/AkauntingSearch.vue | 1363 +
.../assets/js/components/AkauntingSelect.vue | 1358 +
.../js/components/AkauntingSelectRemote.vue | 1689 +
.../assets/js/components/AkauntingSlider.vue | 125 +
.../assets/js/components/AkauntingSwitch.vue | 77 +
.../assets/js/components/AkauntingWidget.vue | 282 +
resources/assets/js/components/Badge.vue | 51 +
resources/assets/js/components/BaseAlert.vue | 74 +
resources/assets/js/components/BaseButton.vue | 71 +
resources/assets/js/components/Cards/Card.vue | 70 +
.../assets/js/components/Cards/StatsCard.vue | 48 +
.../assets/js/components/CreditCard/Card.vue | 269 +
.../js/components/CreditCard/CardForm.vue | 719 +
.../assets/js/components/Inputs/BaseInput.vue | 189 +
resources/assets/js/components/Modal.vue | 125 +
.../NotificationPlugin/Notification.vue | 259 +
.../NotificationPlugin/Notifications.vue | 63 +
.../js/components/NotificationPlugin/index.js | 81 +
.../js/components/SearchString/FilterMain.vue | 301 +
.../components/SearchString/FilteredList.vue | 125 +
.../js/components/SearchString/Filters.vue | 389 +
.../components/SearchString/SearchString.vue | 802 +
.../assets/js/directives/click-ouside.js | 15 +
.../assets/js/exceptions/trackers/bugsnag.js | 1 +
.../assets/js/exceptions/trackers/sentry.js | 43 +
resources/assets/js/install.js | 89 +
resources/assets/js/mixins/global.js | 1651 +
resources/assets/js/mixins/wizardAction.js | 210 +
resources/assets/js/plugins/bulk-action.js | 252 +
resources/assets/js/plugins/currency.js | 114 +
.../assets/js/plugins/dashboard-plugin.js | 35 +
resources/assets/js/plugins/error.js | 38 +
resources/assets/js/plugins/form.js | 509 +
resources/assets/js/plugins/functions.js | 43 +
.../assets/js/plugins/globalComponents.js | 29 +
.../assets/js/plugins/globalDirectives.js | 13 +
resources/assets/js/plugins/money.js | 138 +
.../assets/js/plugins/nprogress-axios.js | 28 +
resources/assets/js/polyfills.js | 96 +
resources/assets/js/views/auth/common.js | 142 +
resources/assets/js/views/auth/users.js | 76 +
resources/assets/js/views/banking/accounts.js | 34 +
.../js/views/banking/reconciliations.js | 129 +
.../assets/js/views/banking/transactions.js | 165 +
.../assets/js/views/banking/transfers.js | 156 +
resources/assets/js/views/common/companies.js | 87 +
resources/assets/js/views/common/contacts.js | 166 +
.../assets/js/views/common/dashboards.js | 227 +
resources/assets/js/views/common/documents.js | 1087 +
resources/assets/js/views/common/imports.js | 31 +
resources/assets/js/views/common/items.js | 134 +
resources/assets/js/views/common/reports.js | 93 +
.../assets/js/views/install/Database.vue | 192 +
.../assets/js/views/install/Language.vue | 79 +
.../assets/js/views/install/Requirements.vue | 50 +
.../assets/js/views/install/Settings.vue | 179 +
resources/assets/js/views/install/Steps.vue | 48 +
resources/assets/js/views/install/update.js | 152 +
resources/assets/js/views/modules/apps.js | 334 +
resources/assets/js/views/portal/apps.js | 288 +
.../assets/js/views/settings/categories.js | 60 +
.../assets/js/views/settings/currencies.js | 88 +
.../assets/js/views/settings/settings.js | 181 +
resources/assets/js/views/settings/taxes.js | 40 +
resources/assets/js/views/wizard/Company.vue | 385 +
.../assets/js/views/wizard/Currencies.vue | 421 +
resources/assets/js/views/wizard/Finish.vue | 175 +
resources/assets/js/views/wizard/Steps.vue | 89 +
resources/assets/js/wizard.js | 65 +
resources/assets/sass/app.css | 873 +
resources/lang/ar-SA/accounts.php | 31 +
resources/lang/ar-SA/auth.php | 93 +
resources/lang/ar-SA/bills.php | 63 +
resources/lang/ar-SA/bulk_actions.php | 27 +
resources/lang/ar-SA/categories.php | 11 +
resources/lang/ar-SA/companies.php | 22 +
resources/lang/ar-SA/countries.php | 256 +
resources/lang/ar-SA/currencies.php | 27 +
resources/lang/ar-SA/customers.php | 31 +
resources/lang/ar-SA/dashboards.php | 15 +
resources/lang/ar-SA/demo.php | 31 +
resources/lang/ar-SA/documents.php | 104 +
resources/lang/ar-SA/email_templates.php | 65 +
resources/lang/ar-SA/errors.php | 25 +
resources/lang/ar-SA/footer.php | 13 +
resources/lang/ar-SA/general.php | 353 +
resources/lang/ar-SA/header.php | 33 +
resources/lang/ar-SA/import.php | 18 +
resources/lang/ar-SA/install.php | 51 +
resources/lang/ar-SA/invoices.php | 82 +
resources/lang/ar-SA/items.php | 16 +
resources/lang/ar-SA/maintenance.php | 11 +
resources/lang/ar-SA/messages.php | 53 +
resources/lang/ar-SA/modules.php | 133 +
resources/lang/ar-SA/notifications.php | 250 +
resources/lang/ar-SA/pagination.php | 9 +
resources/lang/ar-SA/passwords.php | 22 +
resources/lang/ar-SA/portal.php | 53 +
resources/lang/ar-SA/reconciliations.php | 22 +
resources/lang/ar-SA/recurring.php | 43 +
resources/lang/ar-SA/reports.php | 45 +
resources/lang/ar-SA/search_string.php | 21 +
resources/lang/ar-SA/settings.php | 209 +
resources/lang/ar-SA/taxes.php | 20 +
resources/lang/ar-SA/transactions.php | 58 +
resources/lang/ar-SA/transfers.php | 34 +
resources/lang/ar-SA/updates.php | 15 +
resources/lang/ar-SA/validation.php | 146 +
resources/lang/ar-SA/vendors.php | 16 +
resources/lang/ar-SA/widgets.php | 34 +
resources/lang/az-AZ/accounts.php | 14 +
resources/lang/az-AZ/auth.php | 41 +
resources/lang/az-AZ/bills.php | 57 +
resources/lang/az-AZ/bulk_actions.php | 23 +
resources/lang/az-AZ/companies.php | 14 +
resources/lang/az-AZ/countries.php | 253 +
resources/lang/az-AZ/currencies.php | 19 +
resources/lang/az-AZ/customers.php | 12 +
resources/lang/az-AZ/dashboards.php | 11 +
resources/lang/az-AZ/demo.php | 31 +
resources/lang/az-AZ/documents.php | 54 +
resources/lang/az-AZ/email_templates.php | 50 +
resources/lang/az-AZ/errors.php | 23 +
resources/lang/az-AZ/footer.php | 10 +
resources/lang/az-AZ/general.php | 231 +
resources/lang/az-AZ/header.php | 16 +
resources/lang/az-AZ/import.php | 9 +
resources/lang/az-AZ/install.php | 46 +
resources/lang/az-AZ/invoices.php | 60 +
resources/lang/az-AZ/items.php | 9 +
resources/lang/az-AZ/maintenance.php | 9 +
resources/lang/az-AZ/messages.php | 37 +
resources/lang/az-AZ/modules.php | 83 +
resources/lang/az-AZ/notifications.php | 10 +
resources/lang/az-AZ/pagination.php | 9 +
resources/lang/az-AZ/passwords.php | 22 +
resources/lang/az-AZ/payments.php | 10 +
resources/lang/az-AZ/reconciliations.php | 18 +
resources/lang/az-AZ/recurring.php | 20 +
resources/lang/az-AZ/reports.php | 28 +
resources/lang/az-AZ/search_string.php | 20 +
resources/lang/az-AZ/settings.php | 144 +
resources/lang/az-AZ/taxes.php | 12 +
resources/lang/az-AZ/transfers.php | 12 +
resources/lang/az-AZ/updates.php | 15 +
resources/lang/az-AZ/validation.php | 123 +
resources/lang/az-AZ/widgets.php | 24 +
resources/lang/bg-BG/accounts.php | 31 +
resources/lang/bg-BG/auth.php | 93 +
resources/lang/bg-BG/bills.php | 63 +
resources/lang/bg-BG/bulk_actions.php | 27 +
resources/lang/bg-BG/categories.php | 11 +
resources/lang/bg-BG/companies.php | 22 +
resources/lang/bg-BG/countries.php | 256 +
resources/lang/bg-BG/currencies.php | 27 +
resources/lang/bg-BG/customers.php | 31 +
resources/lang/bg-BG/dashboards.php | 15 +
resources/lang/bg-BG/demo.php | 31 +
resources/lang/bg-BG/documents.php | 105 +
resources/lang/bg-BG/email_templates.php | 64 +
resources/lang/bg-BG/errors.php | 25 +
resources/lang/bg-BG/footer.php | 13 +
resources/lang/bg-BG/general.php | 355 +
resources/lang/bg-BG/header.php | 34 +
resources/lang/bg-BG/import.php | 18 +
resources/lang/bg-BG/install.php | 51 +
resources/lang/bg-BG/invoices.php | 83 +
resources/lang/bg-BG/items.php | 17 +
resources/lang/bg-BG/maintenance.php | 11 +
resources/lang/bg-BG/messages.php | 51 +
resources/lang/bg-BG/modules.php | 137 +
resources/lang/bg-BG/notifications.php | 250 +
resources/lang/bg-BG/pagination.php | 9 +
resources/lang/bg-BG/passwords.php | 22 +
resources/lang/bg-BG/portal.php | 53 +
resources/lang/bg-BG/reconciliations.php | 22 +
resources/lang/bg-BG/recurring.php | 44 +
resources/lang/bg-BG/reports.php | 39 +
resources/lang/bg-BG/search_string.php | 21 +
resources/lang/bg-BG/settings.php | 210 +
resources/lang/bg-BG/taxes.php | 20 +
resources/lang/bg-BG/transactions.php | 51 +
resources/lang/bg-BG/transfers.php | 35 +
resources/lang/bg-BG/updates.php | 15 +
resources/lang/bg-BG/validation.php | 177 +
resources/lang/bg-BG/vendors.php | 16 +
resources/lang/bg-BG/widgets.php | 34 +
resources/lang/bn-BD/accounts.php | 18 +
resources/lang/bn-BD/auth.php | 43 +
resources/lang/bn-BD/bills.php | 56 +
resources/lang/bn-BD/bulk_actions.php | 21 +
resources/lang/bn-BD/companies.php | 14 +
resources/lang/bn-BD/countries.php | 253 +
resources/lang/bn-BD/currencies.php | 18 +
resources/lang/bn-BD/customers.php | 12 +
resources/lang/bn-BD/dashboards.php | 11 +
resources/lang/bn-BD/demo.php | 31 +
resources/lang/bn-BD/email_templates.php | 50 +
resources/lang/bn-BD/errors.php | 23 +
resources/lang/bn-BD/footer.php | 10 +
resources/lang/bn-BD/general.php | 209 +
resources/lang/bn-BD/header.php | 16 +
resources/lang/bn-BD/import.php | 9 +
resources/lang/bn-BD/install.php | 46 +
resources/lang/bn-BD/invoices.php | 60 +
resources/lang/bn-BD/items.php | 8 +
resources/lang/bn-BD/maintenance.php | 11 +
resources/lang/bn-BD/messages.php | 37 +
resources/lang/bn-BD/modules.php | 83 +
resources/lang/bn-BD/notifications.php | 10 +
resources/lang/bn-BD/pagination.php | 9 +
resources/lang/bn-BD/passwords.php | 23 +
resources/lang/bn-BD/reconciliations.php | 16 +
resources/lang/bn-BD/recurring.php | 20 +
resources/lang/bn-BD/reports.php | 27 +
resources/lang/bn-BD/settings.php | 129 +
resources/lang/bn-BD/taxes.php | 12 +
resources/lang/bn-BD/transfers.php | 12 +
resources/lang/bn-BD/updates.php | 15 +
resources/lang/bn-BD/validation.php | 124 +
resources/lang/bn-BD/widgets.php | 23 +
resources/lang/bs-BA/accounts.php | 31 +
resources/lang/bs-BA/auth.php | 92 +
resources/lang/bs-BA/bills.php | 63 +
resources/lang/bs-BA/bulk_actions.php | 26 +
resources/lang/bs-BA/categories.php | 11 +
resources/lang/bs-BA/companies.php | 22 +
resources/lang/bs-BA/countries.php | 256 +
resources/lang/bs-BA/currencies.php | 27 +
resources/lang/bs-BA/customers.php | 30 +
resources/lang/bs-BA/dashboards.php | 15 +
resources/lang/bs-BA/demo.php | 31 +
resources/lang/bs-BA/documents.php | 86 +
resources/lang/bs-BA/email_templates.php | 65 +
resources/lang/bs-BA/errors.php | 23 +
resources/lang/bs-BA/footer.php | 13 +
resources/lang/bs-BA/general.php | 311 +
resources/lang/bs-BA/header.php | 33 +
resources/lang/bs-BA/import.php | 10 +
resources/lang/bs-BA/install.php | 50 +
resources/lang/bs-BA/invoices.php | 85 +
resources/lang/bs-BA/items.php | 17 +
resources/lang/bs-BA/maintenance.php | 11 +
resources/lang/bs-BA/messages.php | 46 +
resources/lang/bs-BA/modules.php | 126 +
resources/lang/bs-BA/notifications.php | 181 +
resources/lang/bs-BA/pagination.php | 9 +
resources/lang/bs-BA/passwords.php | 22 +
resources/lang/bs-BA/payments.php | 10 +
resources/lang/bs-BA/portal.php | 52 +
resources/lang/bs-BA/reconciliations.php | 22 +
resources/lang/bs-BA/recurring.php | 41 +
resources/lang/bs-BA/reports.php | 43 +
resources/lang/bs-BA/revenues.php | 10 +
resources/lang/bs-BA/search_string.php | 21 +
resources/lang/bs-BA/settings.php | 203 +
resources/lang/bs-BA/taxes.php | 20 +
resources/lang/bs-BA/transactions.php | 45 +
resources/lang/bs-BA/transfers.php | 30 +
resources/lang/bs-BA/updates.php | 15 +
resources/lang/bs-BA/validation.php | 159 +
resources/lang/bs-BA/vendors.php | 16 +
resources/lang/bs-BA/widgets.php | 34 +
resources/lang/ca-ES/accounts.php | 31 +
resources/lang/ca-ES/auth.php | 93 +
resources/lang/ca-ES/bills.php | 63 +
resources/lang/ca-ES/bulk_actions.php | 27 +
resources/lang/ca-ES/categories.php | 11 +
resources/lang/ca-ES/companies.php | 22 +
resources/lang/ca-ES/countries.php | 256 +
resources/lang/ca-ES/currencies.php | 27 +
resources/lang/ca-ES/customers.php | 31 +
resources/lang/ca-ES/dashboards.php | 15 +
resources/lang/ca-ES/demo.php | 31 +
resources/lang/ca-ES/documents.php | 103 +
resources/lang/ca-ES/email_templates.php | 64 +
resources/lang/ca-ES/errors.php | 25 +
resources/lang/ca-ES/footer.php | 13 +
resources/lang/ca-ES/general.php | 350 +
resources/lang/ca-ES/header.php | 33 +
resources/lang/ca-ES/import.php | 18 +
resources/lang/ca-ES/install.php | 51 +
resources/lang/ca-ES/invoices.php | 83 +
resources/lang/ca-ES/items.php | 17 +
resources/lang/ca-ES/maintenance.php | 11 +
resources/lang/ca-ES/messages.php | 52 +
resources/lang/ca-ES/modules.php | 136 +
resources/lang/ca-ES/notifications.php | 251 +
resources/lang/ca-ES/pagination.php | 9 +
resources/lang/ca-ES/passwords.php | 22 +
resources/lang/ca-ES/payments.php | 10 +
resources/lang/ca-ES/portal.php | 53 +
resources/lang/ca-ES/reconciliations.php | 22 +
resources/lang/ca-ES/recurring.php | 43 +
resources/lang/ca-ES/reports.php | 40 +
resources/lang/ca-ES/revenues.php | 10 +
resources/lang/ca-ES/search_string.php | 21 +
resources/lang/ca-ES/settings.php | 209 +
resources/lang/ca-ES/taxes.php | 20 +
resources/lang/ca-ES/transactions.php | 58 +
resources/lang/ca-ES/transfers.php | 34 +
resources/lang/ca-ES/updates.php | 15 +
resources/lang/ca-ES/validation.php | 177 +
resources/lang/ca-ES/vendors.php | 16 +
resources/lang/ca-ES/widgets.php | 34 +
resources/lang/cs-CZ/accounts.php | 31 +
resources/lang/cs-CZ/auth.php | 93 +
resources/lang/cs-CZ/bills.php | 63 +
resources/lang/cs-CZ/bulk_actions.php | 26 +
resources/lang/cs-CZ/categories.php | 11 +
resources/lang/cs-CZ/companies.php | 22 +
resources/lang/cs-CZ/countries.php | 256 +
resources/lang/cs-CZ/currencies.php | 27 +
resources/lang/cs-CZ/customers.php | 31 +
resources/lang/cs-CZ/dashboard.php | 23 +
resources/lang/cs-CZ/dashboards.php | 15 +
resources/lang/cs-CZ/demo.php | 31 +
resources/lang/cs-CZ/documents.php | 103 +
resources/lang/cs-CZ/email_templates.php | 64 +
resources/lang/cs-CZ/errors.php | 25 +
resources/lang/cs-CZ/footer.php | 13 +
resources/lang/cs-CZ/general.php | 339 +
resources/lang/cs-CZ/header.php | 33 +
resources/lang/cs-CZ/import.php | 13 +
resources/lang/cs-CZ/install.php | 51 +
resources/lang/cs-CZ/invoices.php | 83 +
resources/lang/cs-CZ/items.php | 17 +
resources/lang/cs-CZ/maintenance.php | 11 +
resources/lang/cs-CZ/messages.php | 50 +
resources/lang/cs-CZ/modules.php | 136 +
resources/lang/cs-CZ/notifications.php | 218 +
resources/lang/cs-CZ/pagination.php | 9 +
resources/lang/cs-CZ/passwords.php | 22 +
resources/lang/cs-CZ/portal.php | 53 +
resources/lang/cs-CZ/reconciliations.php | 22 +
resources/lang/cs-CZ/recurring.php | 43 +
resources/lang/cs-CZ/reports.php | 39 +
resources/lang/cs-CZ/search_string.php | 21 +
resources/lang/cs-CZ/settings.php | 203 +
resources/lang/cs-CZ/taxes.php | 20 +
resources/lang/cs-CZ/transactions.php | 50 +
resources/lang/cs-CZ/transfers.php | 34 +
resources/lang/cs-CZ/updates.php | 15 +
resources/lang/cs-CZ/validation.php | 175 +
resources/lang/cs-CZ/vendors.php | 16 +
resources/lang/cs-CZ/widgets.php | 34 +
resources/lang/da-DK/accounts.php | 31 +
resources/lang/da-DK/auth.php | 93 +
resources/lang/da-DK/bills.php | 63 +
resources/lang/da-DK/bulk_actions.php | 26 +
resources/lang/da-DK/categories.php | 11 +
resources/lang/da-DK/companies.php | 22 +
resources/lang/da-DK/countries.php | 256 +
resources/lang/da-DK/currencies.php | 27 +
resources/lang/da-DK/customers.php | 30 +
resources/lang/da-DK/dashboards.php | 15 +
resources/lang/da-DK/demo.php | 31 +
resources/lang/da-DK/documents.php | 93 +
resources/lang/da-DK/email_templates.php | 67 +
resources/lang/da-DK/errors.php | 25 +
resources/lang/da-DK/footer.php | 13 +
resources/lang/da-DK/general.php | 317 +
resources/lang/da-DK/header.php | 33 +
resources/lang/da-DK/import.php | 14 +
resources/lang/da-DK/install.php | 51 +
resources/lang/da-DK/invoices.php | 82 +
resources/lang/da-DK/items.php | 17 +
resources/lang/da-DK/maintenance.php | 11 +
resources/lang/da-DK/messages.php | 48 +
resources/lang/da-DK/modules.php | 136 +
resources/lang/da-DK/notifications.php | 219 +
resources/lang/da-DK/pagination.php | 9 +
resources/lang/da-DK/passwords.php | 22 +
resources/lang/da-DK/payments.php | 10 +
resources/lang/da-DK/portal.php | 53 +
resources/lang/da-DK/reconciliations.php | 22 +
resources/lang/da-DK/recurring.php | 43 +
resources/lang/da-DK/reports.php | 43 +
resources/lang/da-DK/revenues.php | 10 +
resources/lang/da-DK/search_string.php | 21 +
resources/lang/da-DK/settings.php | 151 +
resources/lang/da-DK/taxes.php | 12 +
resources/lang/da-DK/transfers.php | 15 +
resources/lang/da-DK/updates.php | 15 +
resources/lang/da-DK/validation.php | 165 +
resources/lang/da-DK/widgets.php | 24 +
resources/lang/de-DE/accounts.php | 31 +
resources/lang/de-DE/auth.php | 93 +
resources/lang/de-DE/bills.php | 63 +
resources/lang/de-DE/bulk_actions.php | 27 +
resources/lang/de-DE/categories.php | 11 +
resources/lang/de-DE/companies.php | 22 +
resources/lang/de-DE/countries.php | 256 +
resources/lang/de-DE/currencies.php | 27 +
resources/lang/de-DE/customers.php | 31 +
resources/lang/de-DE/dashboards.php | 15 +
resources/lang/de-DE/demo.php | 31 +
resources/lang/de-DE/documents.php | 104 +
resources/lang/de-DE/email_templates.php | 64 +
resources/lang/de-DE/errors.php | 25 +
resources/lang/de-DE/footer.php | 13 +
resources/lang/de-DE/general.php | 353 +
resources/lang/de-DE/header.php | 33 +
resources/lang/de-DE/import.php | 18 +
resources/lang/de-DE/install.php | 51 +
resources/lang/de-DE/invoices.php | 83 +
resources/lang/de-DE/items.php | 17 +
resources/lang/de-DE/maintenance.php | 11 +
resources/lang/de-DE/messages.php | 53 +
resources/lang/de-DE/modules.php | 133 +
resources/lang/de-DE/notifications.php | 250 +
resources/lang/de-DE/pagination.php | 9 +
resources/lang/de-DE/passwords.php | 22 +
resources/lang/de-DE/portal.php | 53 +
resources/lang/de-DE/reconciliations.php | 22 +
resources/lang/de-DE/recurring.php | 43 +
resources/lang/de-DE/reports.php | 45 +
resources/lang/de-DE/search_string.php | 21 +
resources/lang/de-DE/settings.php | 209 +
resources/lang/de-DE/taxes.php | 20 +
resources/lang/de-DE/transactions.php | 58 +
resources/lang/de-DE/transfers.php | 34 +
resources/lang/de-DE/updates.php | 15 +
resources/lang/de-DE/validation.php | 179 +
resources/lang/de-DE/vendors.php | 16 +
resources/lang/de-DE/widgets.php | 34 +
resources/lang/el-GR/accounts.php | 31 +
resources/lang/el-GR/auth.php | 93 +
resources/lang/el-GR/bills.php | 63 +
resources/lang/el-GR/bulk_actions.php | 27 +
resources/lang/el-GR/categories.php | 11 +
resources/lang/el-GR/companies.php | 22 +
resources/lang/el-GR/countries.php | 256 +
resources/lang/el-GR/currencies.php | 27 +
resources/lang/el-GR/customers.php | 31 +
resources/lang/el-GR/dashboards.php | 15 +
resources/lang/el-GR/demo.php | 31 +
resources/lang/el-GR/documents.php | 104 +
resources/lang/el-GR/email_templates.php | 64 +
resources/lang/el-GR/errors.php | 25 +
resources/lang/el-GR/footer.php | 13 +
resources/lang/el-GR/general.php | 353 +
resources/lang/el-GR/header.php | 33 +
resources/lang/el-GR/import.php | 18 +
resources/lang/el-GR/install.php | 51 +
resources/lang/el-GR/invoices.php | 83 +
resources/lang/el-GR/items.php | 17 +
resources/lang/el-GR/maintenance.php | 11 +
resources/lang/el-GR/messages.php | 52 +
resources/lang/el-GR/modules.php | 136 +
resources/lang/el-GR/notifications.php | 250 +
resources/lang/el-GR/pagination.php | 9 +
resources/lang/el-GR/passwords.php | 22 +
resources/lang/el-GR/portal.php | 53 +
resources/lang/el-GR/reconciliations.php | 22 +
resources/lang/el-GR/recurring.php | 43 +
resources/lang/el-GR/reports.php | 44 +
resources/lang/el-GR/search_string.php | 21 +
resources/lang/el-GR/settings.php | 209 +
resources/lang/el-GR/taxes.php | 20 +
resources/lang/el-GR/transactions.php | 58 +
resources/lang/el-GR/transfers.php | 34 +
resources/lang/el-GR/updates.php | 15 +
resources/lang/el-GR/validation.php | 179 +
resources/lang/el-GR/vendors.php | 16 +
resources/lang/el-GR/widgets.php | 34 +
resources/lang/en-AU/accounts.php | 31 +
resources/lang/en-AU/auth.php | 93 +
resources/lang/en-AU/bills.php | 63 +
resources/lang/en-AU/bulk_actions.php | 27 +
resources/lang/en-AU/categories.php | 11 +
resources/lang/en-AU/companies.php | 22 +
resources/lang/en-AU/countries.php | 256 +
resources/lang/en-AU/currencies.php | 27 +
resources/lang/en-AU/customers.php | 31 +
resources/lang/en-AU/dashboards.php | 15 +
resources/lang/en-AU/demo.php | 31 +
resources/lang/en-AU/documents.php | 104 +
resources/lang/en-AU/email_templates.php | 64 +
resources/lang/en-AU/errors.php | 25 +
resources/lang/en-AU/footer.php | 13 +
resources/lang/en-AU/general.php | 353 +
resources/lang/en-AU/header.php | 33 +
resources/lang/en-AU/import.php | 18 +
resources/lang/en-AU/install.php | 51 +
resources/lang/en-AU/invoices.php | 83 +
resources/lang/en-AU/items.php | 17 +
resources/lang/en-AU/maintenance.php | 11 +
resources/lang/en-AU/messages.php | 53 +
resources/lang/en-AU/modules.php | 133 +
resources/lang/en-AU/notifications.php | 250 +
resources/lang/en-AU/pagination.php | 9 +
resources/lang/en-AU/passwords.php | 22 +
resources/lang/en-AU/portal.php | 53 +
resources/lang/en-AU/reconciliations.php | 22 +
resources/lang/en-AU/recurring.php | 43 +
resources/lang/en-AU/reports.php | 45 +
resources/lang/en-AU/search_string.php | 21 +
resources/lang/en-AU/settings.php | 209 +
resources/lang/en-AU/taxes.php | 20 +
resources/lang/en-AU/transactions.php | 58 +
resources/lang/en-AU/transfers.php | 34 +
resources/lang/en-AU/updates.php | 15 +
resources/lang/en-AU/validation.php | 179 +
resources/lang/en-AU/vendors.php | 16 +
resources/lang/en-AU/widgets.php | 34 +
resources/lang/en-GB/accounts.php | 31 +
resources/lang/en-GB/auth.php | 93 +
resources/lang/en-GB/bills.php | 63 +
resources/lang/en-GB/bulk_actions.php | 27 +
resources/lang/en-GB/categories.php | 11 +
resources/lang/en-GB/companies.php | 22 +
resources/lang/en-GB/countries.php | 256 +
resources/lang/en-GB/currencies.php | 27 +
resources/lang/en-GB/customers.php | 31 +
resources/lang/en-GB/dashboards.php | 15 +
resources/lang/en-GB/demo.php | 31 +
resources/lang/en-GB/documents.php | 104 +
resources/lang/en-GB/email_templates.php | 64 +
resources/lang/en-GB/errors.php | 25 +
resources/lang/en-GB/footer.php | 13 +
resources/lang/en-GB/general.php | 353 +
resources/lang/en-GB/header.php | 33 +
resources/lang/en-GB/import.php | 18 +
resources/lang/en-GB/install.php | 51 +
resources/lang/en-GB/invoices.php | 83 +
resources/lang/en-GB/items.php | 17 +
resources/lang/en-GB/maintenance.php | 11 +
resources/lang/en-GB/messages.php | 53 +
resources/lang/en-GB/modules.php | 133 +
resources/lang/en-GB/notifications.php | 250 +
resources/lang/en-GB/pagination.php | 9 +
resources/lang/en-GB/passwords.php | 22 +
resources/lang/en-GB/portal.php | 53 +
resources/lang/en-GB/reconciliations.php | 22 +
resources/lang/en-GB/recurring.php | 43 +
resources/lang/en-GB/reports.php | 45 +
resources/lang/en-GB/search_string.php | 21 +
resources/lang/en-GB/settings.php | 209 +
resources/lang/en-GB/taxes.php | 20 +
resources/lang/en-GB/transactions.php | 58 +
resources/lang/en-GB/transfers.php | 34 +
resources/lang/en-GB/updates.php | 15 +
resources/lang/en-GB/validation.php | 179 +
resources/lang/en-GB/vendors.php | 16 +
resources/lang/en-GB/widgets.php | 34 +
resources/lang/en-US/accounts.php | 31 +
resources/lang/en-US/auth.php | 93 +
resources/lang/en-US/bills.php | 63 +
resources/lang/en-US/bulk_actions.php | 27 +
resources/lang/en-US/categories.php | 11 +
resources/lang/en-US/companies.php | 22 +
resources/lang/en-US/countries.php | 256 +
resources/lang/en-US/currencies.php | 27 +
resources/lang/en-US/customers.php | 31 +
resources/lang/en-US/dashboards.php | 15 +
resources/lang/en-US/demo.php | 31 +
resources/lang/en-US/documents.php | 104 +
resources/lang/en-US/email_templates.php | 64 +
resources/lang/en-US/errors.php | 25 +
resources/lang/en-US/footer.php | 13 +
resources/lang/en-US/general.php | 353 +
resources/lang/en-US/header.php | 33 +
resources/lang/en-US/import.php | 18 +
resources/lang/en-US/install.php | 51 +
resources/lang/en-US/invoices.php | 83 +
resources/lang/en-US/items.php | 17 +
resources/lang/en-US/maintenance.php | 11 +
resources/lang/en-US/messages.php | 53 +
resources/lang/en-US/modules.php | 136 +
resources/lang/en-US/notifications.php | 250 +
resources/lang/en-US/pagination.php | 9 +
resources/lang/en-US/passwords.php | 22 +
resources/lang/en-US/portal.php | 53 +
resources/lang/en-US/reconciliations.php | 22 +
resources/lang/en-US/recurring.php | 43 +
resources/lang/en-US/reports.php | 45 +
resources/lang/en-US/search_string.php | 21 +
resources/lang/en-US/settings.php | 209 +
resources/lang/en-US/taxes.php | 20 +
resources/lang/en-US/transactions.php | 58 +
resources/lang/en-US/transfers.php | 34 +
resources/lang/en-US/updates.php | 15 +
resources/lang/en-US/validation.php | 179 +
resources/lang/en-US/vendors.php | 16 +
resources/lang/en-US/widgets.php | 34 +
resources/lang/es-AR/accounts.php | 31 +
resources/lang/es-AR/auth.php | 41 +
resources/lang/es-AR/bills.php | 63 +
resources/lang/es-AR/bulk_actions.php | 26 +
resources/lang/es-AR/categories.php | 11 +
resources/lang/es-AR/companies.php | 22 +
resources/lang/es-AR/countries.php | 256 +
resources/lang/es-AR/currencies.php | 27 +
resources/lang/es-AR/customers.php | 30 +
resources/lang/es-AR/dashboards.php | 15 +
resources/lang/es-AR/demo.php | 31 +
resources/lang/es-AR/documents.php | 12 +
resources/lang/es-AR/email_templates.php | 64 +
resources/lang/es-AR/errors.php | 25 +
resources/lang/es-AR/footer.php | 13 +
resources/lang/es-AR/general.php | 206 +
resources/lang/es-AR/header.php | 16 +
resources/lang/es-AR/import.php | 9 +
resources/lang/es-AR/install.php | 46 +
resources/lang/es-AR/invoices.php | 85 +
resources/lang/es-AR/items.php | 17 +
resources/lang/es-AR/maintenance.php | 9 +
resources/lang/es-AR/messages.php | 37 +
resources/lang/es-AR/modules.php | 83 +
resources/lang/es-AR/notifications.php | 10 +
resources/lang/es-AR/pagination.php | 9 +
resources/lang/es-AR/passwords.php | 23 +
resources/lang/es-AR/reconciliations.php | 18 +
resources/lang/es-AR/recurring.php | 41 +
resources/lang/es-AR/reports.php | 43 +
resources/lang/es-AR/search_string.php | 21 +
resources/lang/es-AR/settings.php | 144 +
resources/lang/es-AR/taxes.php | 12 +
resources/lang/es-AR/transfers.php | 12 +
resources/lang/es-AR/updates.php | 15 +
resources/lang/es-AR/validation.php | 123 +
resources/lang/es-AR/widgets.php | 23 +
resources/lang/es-CO/accounts.php | 31 +
resources/lang/es-CO/auth.php | 93 +
resources/lang/es-CO/bills.php | 63 +
resources/lang/es-CO/bulk_actions.php | 26 +
resources/lang/es-CO/categories.php | 11 +
resources/lang/es-CO/companies.php | 22 +
resources/lang/es-CO/countries.php | 256 +
resources/lang/es-CO/currencies.php | 27 +
resources/lang/es-CO/customers.php | 30 +
resources/lang/es-CO/dashboards.php | 15 +
resources/lang/es-CO/demo.php | 31 +
resources/lang/es-CO/documents.php | 86 +
resources/lang/es-CO/errors.php | 25 +
resources/lang/es-CO/footer.php | 13 +
resources/lang/es-CO/pagination.php | 9 +
resources/lang/es-CO/passwords.php | 24 +
resources/lang/es-CO/search_string.php | 21 +
resources/lang/es-CO/taxes.php | 20 +
resources/lang/es-CO/vendors.php | 16 +
resources/lang/es-CO/widgets.php | 34 +
resources/lang/es-ES/accounts.php | 31 +
resources/lang/es-ES/auth.php | 93 +
resources/lang/es-ES/bills.php | 63 +
resources/lang/es-ES/bulk_actions.php | 27 +
resources/lang/es-ES/categories.php | 11 +
resources/lang/es-ES/companies.php | 22 +
resources/lang/es-ES/countries.php | 256 +
resources/lang/es-ES/currencies.php | 27 +
resources/lang/es-ES/customers.php | 31 +
resources/lang/es-ES/dashboards.php | 15 +
resources/lang/es-ES/demo.php | 31 +
resources/lang/es-ES/documents.php | 104 +
resources/lang/es-ES/email_templates.php | 64 +
resources/lang/es-ES/errors.php | 24 +
resources/lang/es-ES/footer.php | 13 +
resources/lang/es-ES/general.php | 354 +
resources/lang/es-ES/header.php | 33 +
resources/lang/es-ES/import.php | 18 +
resources/lang/es-ES/install.php | 51 +
resources/lang/es-ES/invoices.php | 83 +
resources/lang/es-ES/items.php | 17 +
resources/lang/es-ES/maintenance.php | 11 +
resources/lang/es-ES/messages.php | 53 +
resources/lang/es-ES/modules.php | 133 +
resources/lang/es-ES/notifications.php | 250 +
resources/lang/es-ES/pagination.php | 9 +
resources/lang/es-ES/passwords.php | 22 +
resources/lang/es-ES/portal.php | 53 +
resources/lang/es-ES/reconciliations.php | 22 +
resources/lang/es-ES/recurring.php | 43 +
resources/lang/es-ES/reports.php | 45 +
resources/lang/es-ES/search_string.php | 21 +
resources/lang/es-ES/settings.php | 209 +
resources/lang/es-ES/taxes.php | 20 +
resources/lang/es-ES/transactions.php | 58 +
resources/lang/es-ES/transfers.php | 33 +
resources/lang/es-ES/updates.php | 15 +
resources/lang/es-ES/validation.php | 152 +
resources/lang/es-ES/vendors.php | 16 +
resources/lang/es-ES/widgets.php | 34 +
resources/lang/es-MX/accounts.php | 31 +
resources/lang/es-MX/auth.php | 93 +
resources/lang/es-MX/bills.php | 63 +
resources/lang/es-MX/bulk_actions.php | 27 +
resources/lang/es-MX/categories.php | 11 +
resources/lang/es-MX/companies.php | 22 +
resources/lang/es-MX/countries.php | 256 +
resources/lang/es-MX/currencies.php | 27 +
resources/lang/es-MX/customers.php | 31 +
resources/lang/es-MX/dashboards.php | 15 +
resources/lang/es-MX/demo.php | 31 +
resources/lang/es-MX/documents.php | 104 +
resources/lang/es-MX/email_templates.php | 64 +
resources/lang/es-MX/errors.php | 24 +
resources/lang/es-MX/footer.php | 13 +
resources/lang/es-MX/general.php | 353 +
resources/lang/es-MX/header.php | 33 +
resources/lang/es-MX/import.php | 18 +
resources/lang/es-MX/install.php | 51 +
resources/lang/es-MX/invoices.php | 83 +
resources/lang/es-MX/items.php | 17 +
resources/lang/es-MX/maintenance.php | 11 +
resources/lang/es-MX/messages.php | 53 +
resources/lang/es-MX/modules.php | 133 +
resources/lang/es-MX/notifications.php | 250 +
resources/lang/es-MX/pagination.php | 9 +
resources/lang/es-MX/passwords.php | 22 +
resources/lang/es-MX/portal.php | 53 +
resources/lang/es-MX/reconciliations.php | 22 +
resources/lang/es-MX/recurring.php | 43 +
resources/lang/es-MX/reports.php | 45 +
resources/lang/es-MX/search_string.php | 21 +
resources/lang/es-MX/settings.php | 209 +
resources/lang/es-MX/taxes.php | 20 +
resources/lang/es-MX/transactions.php | 58 +
resources/lang/es-MX/transfers.php | 33 +
resources/lang/es-MX/updates.php | 15 +
resources/lang/es-MX/validation.php | 152 +
resources/lang/es-MX/vendors.php | 16 +
resources/lang/es-MX/widgets.php | 34 +
resources/lang/et-EE/accounts.php | 14 +
resources/lang/et-EE/auth.php | 41 +
resources/lang/et-EE/bills.php | 56 +
resources/lang/et-EE/bulk_actions.php | 23 +
resources/lang/et-EE/companies.php | 14 +
resources/lang/et-EE/countries.php | 253 +
resources/lang/et-EE/currencies.php | 19 +
resources/lang/et-EE/customers.php | 12 +
resources/lang/et-EE/dashboards.php | 11 +
resources/lang/et-EE/demo.php | 31 +
resources/lang/et-EE/documents.php | 54 +
resources/lang/et-EE/email_templates.php | 50 +
resources/lang/et-EE/errors.php | 23 +
resources/lang/et-EE/footer.php | 10 +
resources/lang/et-EE/general.php | 232 +
resources/lang/et-EE/header.php | 16 +
resources/lang/et-EE/import.php | 11 +
resources/lang/et-EE/install.php | 50 +
resources/lang/et-EE/invoices.php | 60 +
resources/lang/et-EE/items.php | 9 +
resources/lang/et-EE/maintenance.php | 9 +
resources/lang/et-EE/messages.php | 39 +
resources/lang/et-EE/modules.php | 83 +
resources/lang/et-EE/notifications.php | 54 +
resources/lang/et-EE/pagination.php | 9 +
resources/lang/et-EE/passwords.php | 23 +
resources/lang/et-EE/reconciliations.php | 18 +
resources/lang/et-EE/recurring.php | 20 +
resources/lang/et-EE/reports.php | 28 +
resources/lang/et-EE/search_string.php | 20 +
resources/lang/et-EE/settings.php | 144 +
resources/lang/et-EE/taxes.php | 12 +
resources/lang/et-EE/transfers.php | 14 +
resources/lang/et-EE/updates.php | 15 +
resources/lang/et-EE/validation.php | 123 +
resources/lang/et-EE/widgets.php | 24 +
resources/lang/fa-IR/accounts.php | 31 +
resources/lang/fa-IR/auth.php | 41 +
resources/lang/fa-IR/bills.php | 57 +
resources/lang/fa-IR/bulk_actions.php | 23 +
resources/lang/fa-IR/categories.php | 11 +
resources/lang/fa-IR/companies.php | 14 +
resources/lang/fa-IR/countries.php | 256 +
resources/lang/fa-IR/currencies.php | 19 +
resources/lang/fa-IR/customers.php | 12 +
resources/lang/fa-IR/dashboards.php | 11 +
resources/lang/fa-IR/demo.php | 31 +
resources/lang/fa-IR/email_templates.php | 52 +
resources/lang/fa-IR/errors.php | 23 +
resources/lang/fa-IR/footer.php | 10 +
resources/lang/fa-IR/general.php | 228 +
resources/lang/fa-IR/header.php | 16 +
resources/lang/fa-IR/import.php | 9 +
resources/lang/fa-IR/install.php | 50 +
resources/lang/fa-IR/invoices.php | 61 +
resources/lang/fa-IR/items.php | 9 +
resources/lang/fa-IR/maintenance.php | 11 +
resources/lang/fa-IR/messages.php | 37 +
resources/lang/fa-IR/modules.php | 83 +
resources/lang/fa-IR/notifications.php | 10 +
resources/lang/fa-IR/pagination.php | 9 +
resources/lang/fa-IR/passwords.php | 22 +
resources/lang/fa-IR/payments.php | 10 +
resources/lang/fa-IR/reconciliations.php | 18 +
resources/lang/fa-IR/recurring.php | 20 +
resources/lang/fa-IR/reports.php | 28 +
resources/lang/fa-IR/revenues.php | 10 +
resources/lang/fa-IR/settings.php | 138 +
resources/lang/fa-IR/taxes.php | 12 +
resources/lang/fa-IR/transfers.php | 12 +
resources/lang/fa-IR/updates.php | 15 +
resources/lang/fa-IR/validation.php | 123 +
resources/lang/fa-IR/widgets.php | 24 +
resources/lang/fi-FI/accounts.php | 31 +
resources/lang/fi-FI/auth.php | 95 +
resources/lang/fi-FI/bills.php | 56 +
resources/lang/fi-FI/bulk_actions.php | 26 +
resources/lang/fi-FI/categories.php | 11 +
resources/lang/fi-FI/companies.php | 14 +
resources/lang/fi-FI/countries.php | 253 +
resources/lang/fi-FI/currencies.php | 19 +
resources/lang/fi-FI/customers.php | 12 +
resources/lang/fi-FI/dashboards.php | 11 +
resources/lang/fi-FI/demo.php | 31 +
resources/lang/fi-FI/documents.php | 54 +
resources/lang/fi-FI/email_templates.php | 50 +
resources/lang/fi-FI/errors.php | 23 +
resources/lang/fi-FI/footer.php | 10 +
resources/lang/fi-FI/general.php | 231 +
resources/lang/fi-FI/header.php | 16 +
resources/lang/fi-FI/import.php | 9 +
resources/lang/fi-FI/install.php | 46 +
resources/lang/fi-FI/invoices.php | 60 +
resources/lang/fi-FI/items.php | 8 +
resources/lang/fi-FI/maintenance.php | 9 +
resources/lang/fi-FI/messages.php | 37 +
resources/lang/fi-FI/modules.php | 83 +
resources/lang/fi-FI/notifications.php | 10 +
resources/lang/fi-FI/pagination.php | 9 +
resources/lang/fi-FI/passwords.php | 22 +
resources/lang/fi-FI/reconciliations.php | 18 +
resources/lang/fi-FI/recurring.php | 20 +
resources/lang/fi-FI/reports.php | 28 +
resources/lang/fi-FI/search_string.php | 21 +
resources/lang/fi-FI/settings.php | 138 +
resources/lang/fi-FI/taxes.php | 12 +
resources/lang/fi-FI/transfers.php | 12 +
resources/lang/fi-FI/updates.php | 15 +
resources/lang/fi-FI/validation.php | 123 +
resources/lang/fi-FI/widgets.php | 23 +
resources/lang/fr-FR/accounts.php | 31 +
resources/lang/fr-FR/auth.php | 93 +
resources/lang/fr-FR/bills.php | 63 +
resources/lang/fr-FR/bulk_actions.php | 27 +
resources/lang/fr-FR/categories.php | 11 +
resources/lang/fr-FR/companies.php | 22 +
resources/lang/fr-FR/countries.php | 256 +
resources/lang/fr-FR/currencies.php | 27 +
resources/lang/fr-FR/customers.php | 31 +
resources/lang/fr-FR/dashboards.php | 15 +
resources/lang/fr-FR/demo.php | 31 +
resources/lang/fr-FR/documents.php | 104 +
resources/lang/fr-FR/email_templates.php | 64 +
resources/lang/fr-FR/errors.php | 25 +
resources/lang/fr-FR/footer.php | 13 +
resources/lang/fr-FR/general.php | 354 +
resources/lang/fr-FR/header.php | 33 +
resources/lang/fr-FR/import.php | 18 +
resources/lang/fr-FR/install.php | 51 +
resources/lang/fr-FR/invoices.php | 83 +
resources/lang/fr-FR/items.php | 17 +
resources/lang/fr-FR/maintenance.php | 11 +
resources/lang/fr-FR/messages.php | 53 +
resources/lang/fr-FR/modules.php | 133 +
resources/lang/fr-FR/notifications.php | 250 +
resources/lang/fr-FR/pagination.php | 9 +
resources/lang/fr-FR/passwords.php | 22 +
resources/lang/fr-FR/portal.php | 53 +
resources/lang/fr-FR/reconciliations.php | 22 +
resources/lang/fr-FR/recurring.php | 43 +
resources/lang/fr-FR/reports.php | 45 +
resources/lang/fr-FR/search_string.php | 21 +
resources/lang/fr-FR/settings.php | 209 +
resources/lang/fr-FR/taxes.php | 20 +
resources/lang/fr-FR/transactions.php | 58 +
resources/lang/fr-FR/transfers.php | 34 +
resources/lang/fr-FR/updates.php | 15 +
resources/lang/fr-FR/validation.php | 179 +
resources/lang/fr-FR/vendors.php | 16 +
resources/lang/fr-FR/widgets.php | 34 +
resources/lang/he-IL/accounts.php | 14 +
resources/lang/he-IL/auth.php | 39 +
resources/lang/he-IL/bills.php | 63 +
resources/lang/he-IL/categories.php | 11 +
resources/lang/he-IL/companies.php | 22 +
resources/lang/he-IL/countries.php | 256 +
resources/lang/he-IL/currencies.php | 18 +
resources/lang/he-IL/customers.php | 16 +
resources/lang/he-IL/dashboard.php | 24 +
resources/lang/he-IL/dashboards.php | 15 +
resources/lang/he-IL/demo.php | 31 +
resources/lang/he-IL/errors.php | 23 +
resources/lang/he-IL/footer.php | 10 +
resources/lang/he-IL/general.php | 148 +
resources/lang/he-IL/header.php | 16 +
resources/lang/he-IL/import.php | 9 +
resources/lang/he-IL/install.php | 44 +
resources/lang/he-IL/invoices.php | 68 +
resources/lang/he-IL/items.php | 8 +
resources/lang/he-IL/messages.php | 29 +
resources/lang/he-IL/modules.php | 80 +
resources/lang/he-IL/notifications.php | 10 +
resources/lang/he-IL/pagination.php | 9 +
resources/lang/he-IL/passwords.php | 22 +
resources/lang/he-IL/reconciliations.php | 14 +
resources/lang/he-IL/recurring.php | 20 +
resources/lang/he-IL/reports.php | 27 +
resources/lang/he-IL/settings.php | 102 +
resources/lang/he-IL/taxes.php | 20 +
resources/lang/he-IL/transfers.php | 12 +
resources/lang/he-IL/updates.php | 15 +
resources/lang/he-IL/validation.php | 121 +
resources/lang/hi-IN/accounts.php | 31 +
resources/lang/hi-IN/auth.php | 93 +
resources/lang/hi-IN/bills.php | 63 +
resources/lang/hi-IN/bulk_actions.php | 27 +
resources/lang/hi-IN/categories.php | 11 +
resources/lang/hi-IN/companies.php | 22 +
resources/lang/hi-IN/countries.php | 256 +
resources/lang/hi-IN/currencies.php | 27 +
resources/lang/hi-IN/customers.php | 31 +
resources/lang/hi-IN/dashboards.php | 15 +
resources/lang/hi-IN/demo.php | 31 +
resources/lang/hi-IN/documents.php | 104 +
resources/lang/hi-IN/email_templates.php | 64 +
resources/lang/hi-IN/errors.php | 25 +
resources/lang/hi-IN/footer.php | 13 +
resources/lang/hi-IN/general.php | 353 +
resources/lang/hi-IN/header.php | 33 +
resources/lang/hi-IN/import.php | 18 +
resources/lang/hi-IN/install.php | 51 +
resources/lang/hi-IN/invoices.php | 83 +
resources/lang/hi-IN/items.php | 17 +
resources/lang/hi-IN/maintenance.php | 11 +
resources/lang/hi-IN/messages.php | 53 +
resources/lang/hi-IN/modules.php | 136 +
resources/lang/hi-IN/notifications.php | 250 +
resources/lang/hi-IN/pagination.php | 9 +
resources/lang/hi-IN/passwords.php | 22 +
resources/lang/hi-IN/portal.php | 53 +
resources/lang/hi-IN/reconciliations.php | 22 +
resources/lang/hi-IN/recurring.php | 43 +
resources/lang/hi-IN/reports.php | 46 +
resources/lang/hi-IN/search_string.php | 21 +
resources/lang/hi-IN/settings.php | 210 +
resources/lang/hi-IN/taxes.php | 20 +
resources/lang/hi-IN/transactions.php | 58 +
resources/lang/hi-IN/transfers.php | 34 +
resources/lang/hi-IN/updates.php | 15 +
resources/lang/hi-IN/validation.php | 179 +
resources/lang/hi-IN/vendors.php | 16 +
resources/lang/hi-IN/widgets.php | 34 +
resources/lang/hr-HR/accounts.php | 14 +
resources/lang/hr-HR/auth.php | 41 +
resources/lang/hr-HR/bills.php | 69 +
resources/lang/hr-HR/bulk_actions.php | 21 +
resources/lang/hr-HR/companies.php | 14 +
resources/lang/hr-HR/countries.php | 253 +
resources/lang/hr-HR/currencies.php | 18 +
resources/lang/hr-HR/customers.php | 12 +
resources/lang/hr-HR/dashboards.php | 11 +
resources/lang/hr-HR/demo.php | 31 +
resources/lang/hr-HR/email_templates.php | 51 +
resources/lang/hr-HR/errors.php | 23 +
resources/lang/hr-HR/footer.php | 10 +
resources/lang/hr-HR/general.php | 206 +
resources/lang/hr-HR/header.php | 16 +
resources/lang/hr-HR/import.php | 9 +
resources/lang/hr-HR/install.php | 45 +
resources/lang/hr-HR/invoices.php | 77 +
resources/lang/hr-HR/items.php | 8 +
resources/lang/hr-HR/maintenance.php | 9 +
resources/lang/hr-HR/messages.php | 37 +
resources/lang/hr-HR/modules.php | 83 +
resources/lang/hr-HR/notifications.php | 10 +
resources/lang/hr-HR/pagination.php | 9 +
resources/lang/hr-HR/passwords.php | 23 +
resources/lang/hr-HR/reconciliations.php | 16 +
resources/lang/hr-HR/recurring.php | 20 +
resources/lang/hr-HR/reports.php | 27 +
resources/lang/hr-HR/settings.php | 129 +
resources/lang/hr-HR/taxes.php | 11 +
resources/lang/hr-HR/transfers.php | 12 +
resources/lang/hr-HR/updates.php | 15 +
resources/lang/hr-HR/validation.php | 123 +
resources/lang/hr-HR/widgets.php | 23 +
resources/lang/hu-HU/accounts.php | 14 +
resources/lang/hu-HU/auth.php | 42 +
resources/lang/hu-HU/bills.php | 59 +
resources/lang/hu-HU/bulk_actions.php | 36 +
resources/lang/hu-HU/companies.php | 14 +
resources/lang/hu-HU/countries.php | 253 +
resources/lang/hu-HU/currencies.php | 18 +
resources/lang/hu-HU/customers.php | 13 +
resources/lang/hu-HU/dashboards.php | 13 +
resources/lang/hu-HU/demo.php | 32 +
resources/lang/hu-HU/email_templates.php | 61 +
resources/lang/hu-HU/errors.php | 23 +
resources/lang/hu-HU/footer.php | 10 +
resources/lang/hu-HU/header.php | 16 +
resources/lang/hu-HU/import.php | 9 +
resources/lang/hu-HU/install.php | 51 +
resources/lang/hu-HU/invoices.php | 65 +
resources/lang/hu-HU/items.php | 17 +
resources/lang/hu-HU/maintenance.php | 10 +
resources/lang/hu-HU/messages.php | 42 +
resources/lang/hu-HU/modules.php | 93 +
resources/lang/hu-HU/notifications.php | 10 +
resources/lang/hu-HU/pagination.php | 9 +
resources/lang/hu-HU/passwords.php | 22 +
resources/lang/hu-HU/reconciliations.php | 18 +
resources/lang/hu-HU/recurring.php | 20 +
resources/lang/hu-HU/reports.php | 27 +
resources/lang/hu-HU/taxes.php | 12 +
resources/lang/hu-HU/transfers.php | 12 +
resources/lang/hu-HU/updates.php | 15 +
resources/lang/hu-HU/validation.php | 123 +
resources/lang/hu-HU/vendors.php | 16 +
resources/lang/hu-HU/widgets.php | 23 +
resources/lang/id-ID/accounts.php | 31 +
resources/lang/id-ID/auth.php | 93 +
resources/lang/id-ID/bills.php | 63 +
resources/lang/id-ID/bulk_actions.php | 27 +
resources/lang/id-ID/categories.php | 11 +
resources/lang/id-ID/companies.php | 22 +
resources/lang/id-ID/countries.php | 256 +
resources/lang/id-ID/currencies.php | 27 +
resources/lang/id-ID/customers.php | 31 +
resources/lang/id-ID/dashboards.php | 15 +
resources/lang/id-ID/demo.php | 31 +
resources/lang/id-ID/documents.php | 104 +
resources/lang/id-ID/email_templates.php | 64 +
resources/lang/id-ID/errors.php | 25 +
resources/lang/id-ID/footer.php | 13 +
resources/lang/id-ID/general.php | 353 +
resources/lang/id-ID/header.php | 33 +
resources/lang/id-ID/import.php | 18 +
resources/lang/id-ID/install.php | 51 +
resources/lang/id-ID/invoices.php | 83 +
resources/lang/id-ID/items.php | 17 +
resources/lang/id-ID/maintenance.php | 11 +
resources/lang/id-ID/messages.php | 53 +
resources/lang/id-ID/modules.php | 133 +
resources/lang/id-ID/notifications.php | 249 +
resources/lang/id-ID/pagination.php | 9 +
resources/lang/id-ID/passwords.php | 22 +
resources/lang/id-ID/portal.php | 53 +
resources/lang/id-ID/reconciliations.php | 22 +
resources/lang/id-ID/recurring.php | 43 +
resources/lang/id-ID/reports.php | 51 +
resources/lang/id-ID/search_string.php | 21 +
resources/lang/id-ID/settings.php | 209 +
resources/lang/id-ID/taxes.php | 20 +
resources/lang/id-ID/transactions.php | 58 +
resources/lang/id-ID/transfers.php | 34 +
resources/lang/id-ID/updates.php | 15 +
resources/lang/id-ID/validation.php | 179 +
resources/lang/id-ID/vendors.php | 16 +
resources/lang/id-ID/widgets.php | 34 +
resources/lang/is-IS/accounts.php | 14 +
resources/lang/is-IS/auth.php | 41 +
resources/lang/is-IS/bills.php | 56 +
resources/lang/is-IS/bulk_actions.php | 21 +
resources/lang/is-IS/companies.php | 14 +
resources/lang/is-IS/countries.php | 253 +
resources/lang/is-IS/currencies.php | 18 +
resources/lang/is-IS/customers.php | 12 +
resources/lang/is-IS/dashboards.php | 11 +
resources/lang/is-IS/demo.php | 34 +
resources/lang/is-IS/email_templates.php | 50 +
resources/lang/is-IS/errors.php | 23 +
resources/lang/is-IS/footer.php | 10 +
resources/lang/is-IS/general.php | 206 +
resources/lang/is-IS/header.php | 16 +
resources/lang/is-IS/import.php | 9 +
resources/lang/is-IS/install.php | 45 +
resources/lang/is-IS/invoices.php | 77 +
resources/lang/is-IS/items.php | 8 +
resources/lang/is-IS/maintenance.php | 11 +
resources/lang/is-IS/messages.php | 37 +
resources/lang/is-IS/modules.php | 83 +
resources/lang/is-IS/notifications.php | 10 +
resources/lang/is-IS/pagination.php | 10 +
resources/lang/is-IS/passwords.php | 23 +
resources/lang/is-IS/reconciliations.php | 16 +
resources/lang/is-IS/recurring.php | 20 +
resources/lang/is-IS/reports.php | 27 +
resources/lang/is-IS/settings.php | 129 +
resources/lang/is-IS/taxes.php | 11 +
resources/lang/is-IS/transfers.php | 12 +
resources/lang/is-IS/updates.php | 15 +
resources/lang/is-IS/validation.php | 123 +
resources/lang/is-IS/widgets.php | 23 +
resources/lang/it-IT/accounts.php | 31 +
resources/lang/it-IT/auth.php | 93 +
resources/lang/it-IT/bills.php | 63 +
resources/lang/it-IT/bulk_actions.php | 27 +
resources/lang/it-IT/categories.php | 11 +
resources/lang/it-IT/companies.php | 22 +
resources/lang/it-IT/countries.php | 256 +
resources/lang/it-IT/currencies.php | 27 +
resources/lang/it-IT/customers.php | 31 +
resources/lang/it-IT/dashboards.php | 15 +
resources/lang/it-IT/demo.php | 31 +
resources/lang/it-IT/documents.php | 104 +
resources/lang/it-IT/email_templates.php | 64 +
resources/lang/it-IT/errors.php | 25 +
resources/lang/it-IT/footer.php | 13 +
resources/lang/it-IT/general.php | 353 +
resources/lang/it-IT/header.php | 33 +
resources/lang/it-IT/import.php | 18 +
resources/lang/it-IT/install.php | 51 +
resources/lang/it-IT/invoices.php | 83 +
resources/lang/it-IT/items.php | 17 +
resources/lang/it-IT/maintenance.php | 11 +
resources/lang/it-IT/messages.php | 53 +
resources/lang/it-IT/modules.php | 134 +
resources/lang/it-IT/notifications.php | 250 +
resources/lang/it-IT/pagination.php | 9 +
resources/lang/it-IT/passwords.php | 22 +
resources/lang/it-IT/portal.php | 53 +
resources/lang/it-IT/reconciliations.php | 22 +
resources/lang/it-IT/recurring.php | 43 +
resources/lang/it-IT/reports.php | 45 +
resources/lang/it-IT/search_string.php | 21 +
resources/lang/it-IT/settings.php | 209 +
resources/lang/it-IT/taxes.php | 20 +
resources/lang/it-IT/transactions.php | 58 +
resources/lang/it-IT/transfers.php | 34 +
resources/lang/it-IT/updates.php | 15 +
resources/lang/it-IT/validation.php | 179 +
resources/lang/it-IT/vendors.php | 16 +
resources/lang/it-IT/widgets.php | 34 +
resources/lang/ja-JP/accounts.php | 14 +
resources/lang/ja-JP/auth.php | 41 +
resources/lang/ja-JP/bills.php | 56 +
resources/lang/ja-JP/bulk_actions.php | 22 +
resources/lang/ja-JP/companies.php | 14 +
resources/lang/ja-JP/countries.php | 253 +
resources/lang/ja-JP/currencies.php | 18 +
resources/lang/ja-JP/customers.php | 12 +
resources/lang/ja-JP/dashboards.php | 11 +
resources/lang/ja-JP/demo.php | 31 +
resources/lang/ja-JP/email_templates.php | 50 +
resources/lang/ja-JP/errors.php | 23 +
resources/lang/ja-JP/footer.php | 10 +
resources/lang/ja-JP/general.php | 206 +
resources/lang/ja-JP/header.php | 16 +
resources/lang/ja-JP/import.php | 9 +
resources/lang/ja-JP/install.php | 45 +
resources/lang/ja-JP/invoices.php | 60 +
resources/lang/ja-JP/items.php | 8 +
resources/lang/ja-JP/maintenance.php | 9 +
resources/lang/ja-JP/messages.php | 37 +
resources/lang/ja-JP/modules.php | 83 +
resources/lang/ja-JP/notifications.php | 10 +
resources/lang/ja-JP/pagination.php | 9 +
resources/lang/ja-JP/passwords.php | 23 +
resources/lang/ja-JP/reconciliations.php | 16 +
resources/lang/ja-JP/recurring.php | 20 +
resources/lang/ja-JP/reports.php | 27 +
resources/lang/ja-JP/settings.php | 129 +
resources/lang/ja-JP/taxes.php | 11 +
resources/lang/ja-JP/transfers.php | 12 +
resources/lang/ja-JP/updates.php | 15 +
resources/lang/ja-JP/validation.php | 123 +
resources/lang/ja-JP/widgets.php | 23 +
resources/lang/ka-GE/accounts.php | 14 +
resources/lang/ka-GE/auth.php | 41 +
resources/lang/ka-GE/bills.php | 61 +
resources/lang/ka-GE/companies.php | 14 +
resources/lang/ka-GE/countries.php | 253 +
resources/lang/ka-GE/currencies.php | 18 +
resources/lang/ka-GE/customers.php | 12 +
resources/lang/ka-GE/dashboard.php | 24 +
resources/lang/ka-GE/demo.php | 31 +
resources/lang/ka-GE/email_templates.php | 50 +
resources/lang/ka-GE/errors.php | 21 +
resources/lang/ka-GE/footer.php | 10 +
resources/lang/ka-GE/general.php | 147 +
resources/lang/ka-GE/header.php | 16 +
resources/lang/ka-GE/import.php | 9 +
resources/lang/ka-GE/install.php | 44 +
resources/lang/ka-GE/invoices.php | 72 +
resources/lang/ka-GE/items.php | 8 +
resources/lang/ka-GE/maintenance.php | 9 +
resources/lang/ka-GE/messages.php | 32 +
resources/lang/ka-GE/modules.php | 85 +
resources/lang/ka-GE/notifications.php | 10 +
resources/lang/ka-GE/pagination.php | 9 +
resources/lang/ka-GE/passwords.php | 22 +
resources/lang/ka-GE/reconciliations.php | 16 +
resources/lang/ka-GE/recurring.php | 20 +
resources/lang/ka-GE/reports.php | 27 +
resources/lang/ka-GE/settings.php | 103 +
resources/lang/ka-GE/taxes.php | 11 +
resources/lang/ka-GE/transfers.php | 12 +
resources/lang/ka-GE/updates.php | 15 +
resources/lang/ka-GE/validation.php | 123 +
resources/lang/ko-KR/accounts.php | 14 +
resources/lang/ko-KR/auth.php | 39 +
resources/lang/ko-KR/bills.php | 61 +
resources/lang/ko-KR/companies.php | 13 +
resources/lang/ko-KR/countries.php | 253 +
resources/lang/ko-KR/currencies.php | 18 +
resources/lang/ko-KR/customers.php | 16 +
resources/lang/ko-KR/dashboard.php | 24 +
resources/lang/ko-KR/demo.php | 16 +
resources/lang/ko-KR/footer.php | 10 +
resources/lang/ko-KR/general.php | 148 +
resources/lang/ko-KR/header.php | 16 +
resources/lang/ko-KR/import.php | 9 +
resources/lang/ko-KR/install.php | 44 +
resources/lang/ko-KR/invoices.php | 71 +
resources/lang/ko-KR/items.php | 8 +
resources/lang/ko-KR/messages.php | 32 +
resources/lang/ko-KR/modules.php | 83 +
resources/lang/ko-KR/notifications.php | 10 +
resources/lang/ko-KR/pagination.php | 9 +
resources/lang/ko-KR/passwords.php | 22 +
resources/lang/ko-KR/reconciliations.php | 16 +
resources/lang/ko-KR/recurring.php | 20 +
resources/lang/ko-KR/reports.php | 27 +
resources/lang/ko-KR/settings.php | 103 +
resources/lang/ko-KR/taxes.php | 11 +
resources/lang/ko-KR/transfers.php | 12 +
resources/lang/ko-KR/updates.php | 15 +
resources/lang/ko-KR/validation.php | 121 +
resources/lang/lt-LT/accounts.php | 14 +
resources/lang/lt-LT/auth.php | 41 +
resources/lang/lt-LT/bills.php | 56 +
resources/lang/lt-LT/bulk_actions.php | 21 +
resources/lang/lt-LT/companies.php | 14 +
resources/lang/lt-LT/countries.php | 253 +
resources/lang/lt-LT/currencies.php | 18 +
resources/lang/lt-LT/customers.php | 12 +
resources/lang/lt-LT/dashboards.php | 11 +
resources/lang/lt-LT/demo.php | 31 +
resources/lang/lt-LT/email_templates.php | 50 +
resources/lang/lt-LT/errors.php | 23 +
resources/lang/lt-LT/footer.php | 10 +
resources/lang/lt-LT/general.php | 206 +
resources/lang/lt-LT/header.php | 16 +
resources/lang/lt-LT/import.php | 9 +
resources/lang/lt-LT/install.php | 45 +
resources/lang/lt-LT/invoices.php | 85 +
resources/lang/lt-LT/items.php | 8 +
resources/lang/lt-LT/maintenance.php | 9 +
resources/lang/lt-LT/messages.php | 37 +
resources/lang/lt-LT/modules.php | 83 +
resources/lang/lt-LT/notifications.php | 10 +
resources/lang/lt-LT/pagination.php | 9 +
resources/lang/lt-LT/passwords.php | 23 +
resources/lang/lt-LT/reconciliations.php | 16 +
resources/lang/lt-LT/recurring.php | 20 +
resources/lang/lt-LT/reports.php | 27 +
resources/lang/lt-LT/settings.php | 129 +
resources/lang/lt-LT/taxes.php | 11 +
resources/lang/lt-LT/transfers.php | 12 +
resources/lang/lt-LT/updates.php | 15 +
resources/lang/lt-LT/validation.php | 123 +
resources/lang/lt-LT/widgets.php | 23 +
resources/lang/lv-LV/accounts.php | 31 +
resources/lang/lv-LV/auth.php | 93 +
resources/lang/lv-LV/bills.php | 63 +
resources/lang/lv-LV/bulk_actions.php | 26 +
resources/lang/lv-LV/categories.php | 11 +
resources/lang/lv-LV/companies.php | 22 +
resources/lang/lv-LV/countries.php | 256 +
resources/lang/lv-LV/currencies.php | 27 +
resources/lang/lv-LV/customers.php | 30 +
resources/lang/lv-LV/dashboards.php | 15 +
resources/lang/lv-LV/demo.php | 31 +
resources/lang/lv-LV/documents.php | 92 +
resources/lang/lv-LV/email_templates.php | 65 +
resources/lang/lv-LV/errors.php | 25 +
resources/lang/lv-LV/footer.php | 13 +
resources/lang/lv-LV/general.php | 312 +
resources/lang/lv-LV/header.php | 33 +
resources/lang/lv-LV/import.php | 10 +
resources/lang/lv-LV/install.php | 51 +
resources/lang/lv-LV/invoices.php | 85 +
resources/lang/lv-LV/items.php | 17 +
resources/lang/lv-LV/maintenance.php | 11 +
resources/lang/lv-LV/messages.php | 48 +
resources/lang/lv-LV/modules.php | 136 +
resources/lang/lv-LV/notifications.php | 200 +
resources/lang/lv-LV/pagination.php | 9 +
resources/lang/lv-LV/passwords.php | 22 +
resources/lang/lv-LV/portal.php | 53 +
resources/lang/lv-LV/reconciliations.php | 22 +
resources/lang/lv-LV/recurring.php | 42 +
resources/lang/lv-LV/reports.php | 43 +
resources/lang/lv-LV/search_string.php | 21 +
resources/lang/lv-LV/settings.php | 203 +
resources/lang/lv-LV/taxes.php | 20 +
resources/lang/lv-LV/transactions.php | 47 +
resources/lang/lv-LV/transfers.php | 34 +
resources/lang/lv-LV/updates.php | 15 +
resources/lang/lv-LV/validation.php | 174 +
resources/lang/lv-LV/vendors.php | 16 +
resources/lang/lv-LV/widgets.php | 34 +
resources/lang/mk-MK/accounts.php | 31 +
resources/lang/mk-MK/auth.php | 93 +
resources/lang/mk-MK/bills.php | 63 +
resources/lang/mk-MK/categories.php | 11 +
resources/lang/mk-MK/companies.php | 22 +
resources/lang/mk-MK/countries.php | 253 +
resources/lang/mk-MK/currencies.php | 27 +
resources/lang/mk-MK/customers.php | 30 +
resources/lang/mk-MK/dashboard.php | 24 +
resources/lang/mk-MK/dashboards.php | 15 +
resources/lang/mk-MK/demo.php | 31 +
resources/lang/mk-MK/documents.php | 86 +
resources/lang/mk-MK/email_templates.php | 64 +
resources/lang/mk-MK/errors.php | 25 +
resources/lang/mk-MK/footer.php | 13 +
resources/lang/mk-MK/general.php | 312 +
resources/lang/mk-MK/header.php | 33 +
resources/lang/mk-MK/import.php | 10 +
resources/lang/mk-MK/install.php | 44 +
resources/lang/mk-MK/invoices.php | 85 +
resources/lang/mk-MK/items.php | 17 +
resources/lang/mk-MK/maintenance.php | 11 +
resources/lang/mk-MK/messages.php | 49 +
resources/lang/mk-MK/modules.php | 82 +
resources/lang/mk-MK/notifications.php | 27 +
resources/lang/mk-MK/pagination.php | 9 +
resources/lang/mk-MK/passwords.php | 22 +
resources/lang/mk-MK/payments.php | 10 +
resources/lang/mk-MK/portal.php | 53 +
resources/lang/mk-MK/reconciliations.php | 22 +
resources/lang/mk-MK/recurring.php | 41 +
resources/lang/mk-MK/reports.php | 43 +
resources/lang/mk-MK/revenues.php | 10 +
resources/lang/mk-MK/search_string.php | 21 +
resources/lang/mk-MK/settings.php | 203 +
resources/lang/mk-MK/taxes.php | 20 +
resources/lang/mk-MK/transactions.php | 47 +
resources/lang/mk-MK/transfers.php | 34 +
resources/lang/mk-MK/updates.php | 15 +
resources/lang/mk-MK/validation.php | 174 +
resources/lang/mk-MK/vendors.php | 16 +
resources/lang/mk-MK/widgets.php | 34 +
resources/lang/ms-MY/accounts.php | 31 +
resources/lang/ms-MY/auth.php | 93 +
resources/lang/ms-MY/bills.php | 63 +
resources/lang/ms-MY/bulk_actions.php | 27 +
resources/lang/ms-MY/categories.php | 11 +
resources/lang/ms-MY/companies.php | 22 +
resources/lang/ms-MY/countries.php | 256 +
resources/lang/ms-MY/currencies.php | 27 +
resources/lang/ms-MY/customers.php | 31 +
resources/lang/ms-MY/dashboards.php | 15 +
resources/lang/ms-MY/demo.php | 31 +
resources/lang/ms-MY/documents.php | 104 +
resources/lang/ms-MY/email_templates.php | 64 +
resources/lang/ms-MY/errors.php | 25 +
resources/lang/ms-MY/footer.php | 13 +
resources/lang/ms-MY/general.php | 353 +
resources/lang/ms-MY/header.php | 33 +
resources/lang/ms-MY/import.php | 18 +
resources/lang/ms-MY/install.php | 51 +
resources/lang/ms-MY/invoices.php | 83 +
resources/lang/ms-MY/items.php | 17 +
resources/lang/ms-MY/maintenance.php | 11 +
resources/lang/ms-MY/messages.php | 53 +
resources/lang/ms-MY/modules.php | 133 +
resources/lang/ms-MY/notifications.php | 250 +
resources/lang/ms-MY/pagination.php | 9 +
resources/lang/ms-MY/passwords.php | 22 +
resources/lang/ms-MY/portal.php | 53 +
resources/lang/ms-MY/reconciliations.php | 22 +
resources/lang/ms-MY/recurring.php | 43 +
resources/lang/ms-MY/reports.php | 45 +
resources/lang/ms-MY/search_string.php | 21 +
resources/lang/ms-MY/settings.php | 209 +
resources/lang/ms-MY/taxes.php | 20 +
resources/lang/ms-MY/transactions.php | 58 +
resources/lang/ms-MY/transfers.php | 34 +
resources/lang/ms-MY/updates.php | 15 +
resources/lang/ms-MY/validation.php | 179 +
resources/lang/ms-MY/vendors.php | 16 +
resources/lang/ms-MY/widgets.php | 34 +
resources/lang/nb-NO/accounts.php | 31 +
resources/lang/nb-NO/auth.php | 41 +
resources/lang/nb-NO/bills.php | 63 +
resources/lang/nb-NO/bulk_actions.php | 26 +
resources/lang/nb-NO/categories.php | 11 +
resources/lang/nb-NO/companies.php | 22 +
resources/lang/nb-NO/countries.php | 256 +
resources/lang/nb-NO/currencies.php | 27 +
resources/lang/nb-NO/customers.php | 30 +
resources/lang/nb-NO/dashboards.php | 15 +
resources/lang/nb-NO/demo.php | 31 +
resources/lang/nb-NO/documents.php | 86 +
resources/lang/nb-NO/email_templates.php | 59 +
resources/lang/nb-NO/errors.php | 23 +
resources/lang/nb-NO/footer.php | 13 +
resources/lang/nb-NO/general.php | 239 +
resources/lang/nb-NO/header.php | 28 +
resources/lang/nb-NO/import.php | 10 +
resources/lang/nb-NO/install.php | 46 +
resources/lang/nb-NO/invoices.php | 61 +
resources/lang/nb-NO/items.php | 17 +
resources/lang/nb-NO/maintenance.php | 11 +
resources/lang/nb-NO/messages.php | 41 +
resources/lang/nb-NO/modules.php | 83 +
resources/lang/nb-NO/notifications.php | 188 +
resources/lang/nb-NO/pagination.php | 9 +
resources/lang/nb-NO/passwords.php | 22 +
resources/lang/nb-NO/payments.php | 10 +
resources/lang/nb-NO/portal.php | 52 +
resources/lang/nb-NO/reconciliations.php | 22 +
resources/lang/nb-NO/recurring.php | 20 +
resources/lang/nb-NO/reports.php | 28 +
resources/lang/nb-NO/revenues.php | 10 +
resources/lang/nb-NO/search_string.php | 21 +
resources/lang/nb-NO/settings.php | 203 +
resources/lang/nb-NO/taxes.php | 12 +
resources/lang/nb-NO/transactions.php | 47 +
resources/lang/nb-NO/transfers.php | 15 +
resources/lang/nb-NO/updates.php | 15 +
resources/lang/nb-NO/validation.php | 159 +
resources/lang/nb-NO/vendors.php | 16 +
resources/lang/nb-NO/widgets.php | 34 +
resources/lang/ne-NP/accounts.php | 14 +
resources/lang/ne-NP/auth.php | 41 +
resources/lang/ne-NP/bills.php | 57 +
resources/lang/ne-NP/bulk_actions.php | 23 +
resources/lang/ne-NP/companies.php | 14 +
resources/lang/ne-NP/countries.php | 253 +
resources/lang/ne-NP/currencies.php | 19 +
resources/lang/ne-NP/customers.php | 12 +
resources/lang/ne-NP/dashboards.php | 11 +
resources/lang/ne-NP/demo.php | 31 +
resources/lang/ne-NP/documents.php | 12 +
resources/lang/ne-NP/email_templates.php | 50 +
resources/lang/ne-NP/errors.php | 23 +
resources/lang/ne-NP/footer.php | 10 +
resources/lang/ne-NP/general.php | 239 +
resources/lang/ne-NP/header.php | 28 +
resources/lang/ne-NP/import.php | 10 +
resources/lang/ne-NP/install.php | 46 +
resources/lang/ne-NP/invoices.php | 61 +
resources/lang/ne-NP/items.php | 9 +
resources/lang/ne-NP/maintenance.php | 9 +
resources/lang/ne-NP/messages.php | 41 +
resources/lang/ne-NP/modules.php | 83 +
resources/lang/ne-NP/notifications.php | 79 +
resources/lang/ne-NP/pagination.php | 9 +
resources/lang/ne-NP/passwords.php | 22 +
resources/lang/ne-NP/reconciliations.php | 18 +
resources/lang/ne-NP/recurring.php | 20 +
resources/lang/ne-NP/reports.php | 28 +
resources/lang/ne-NP/search_string.php | 15 +
resources/lang/ne-NP/settings.php | 144 +
resources/lang/ne-NP/taxes.php | 12 +
resources/lang/ne-NP/transfers.php | 15 +
resources/lang/ne-NP/updates.php | 15 +
resources/lang/ne-NP/validation.php | 123 +
resources/lang/ne-NP/widgets.php | 24 +
resources/lang/nl-NL/accounts.php | 31 +
resources/lang/nl-NL/auth.php | 93 +
resources/lang/nl-NL/bills.php | 63 +
resources/lang/nl-NL/bulk_actions.php | 27 +
resources/lang/nl-NL/categories.php | 11 +
resources/lang/nl-NL/companies.php | 22 +
resources/lang/nl-NL/countries.php | 256 +
resources/lang/nl-NL/currencies.php | 27 +
resources/lang/nl-NL/customers.php | 31 +
resources/lang/nl-NL/dashboards.php | 15 +
resources/lang/nl-NL/demo.php | 31 +
resources/lang/nl-NL/documents.php | 104 +
resources/lang/nl-NL/email_templates.php | 64 +
resources/lang/nl-NL/errors.php | 25 +
resources/lang/nl-NL/footer.php | 13 +
resources/lang/nl-NL/general.php | 353 +
resources/lang/nl-NL/header.php | 33 +
resources/lang/nl-NL/import.php | 18 +
resources/lang/nl-NL/install.php | 51 +
resources/lang/nl-NL/invoices.php | 83 +
resources/lang/nl-NL/items.php | 17 +
resources/lang/nl-NL/maintenance.php | 11 +
resources/lang/nl-NL/messages.php | 53 +
resources/lang/nl-NL/modules.php | 136 +
resources/lang/nl-NL/notifications.php | 250 +
resources/lang/nl-NL/pagination.php | 9 +
resources/lang/nl-NL/passwords.php | 22 +
resources/lang/nl-NL/portal.php | 53 +
resources/lang/nl-NL/reconciliations.php | 22 +
resources/lang/nl-NL/recurring.php | 43 +
resources/lang/nl-NL/reports.php | 45 +
resources/lang/nl-NL/search_string.php | 21 +
resources/lang/nl-NL/settings.php | 209 +
resources/lang/nl-NL/taxes.php | 20 +
resources/lang/nl-NL/transactions.php | 58 +
resources/lang/nl-NL/transfers.php | 34 +
resources/lang/nl-NL/updates.php | 15 +
resources/lang/nl-NL/validation.php | 179 +
resources/lang/nl-NL/vendors.php | 16 +
resources/lang/nl-NL/widgets.php | 34 +
resources/lang/pl-PL/accounts.php | 31 +
resources/lang/pl-PL/auth.php | 93 +
resources/lang/pl-PL/bills.php | 63 +
resources/lang/pl-PL/bulk_actions.php | 27 +
resources/lang/pl-PL/categories.php | 11 +
resources/lang/pl-PL/companies.php | 22 +
resources/lang/pl-PL/countries.php | 256 +
resources/lang/pl-PL/currencies.php | 27 +
resources/lang/pl-PL/customers.php | 31 +
resources/lang/pl-PL/dashboards.php | 15 +
resources/lang/pl-PL/demo.php | 31 +
resources/lang/pl-PL/documents.php | 104 +
resources/lang/pl-PL/email_templates.php | 64 +
resources/lang/pl-PL/errors.php | 25 +
resources/lang/pl-PL/footer.php | 13 +
resources/lang/pl-PL/general.php | 353 +
resources/lang/pl-PL/header.php | 33 +
resources/lang/pl-PL/import.php | 18 +
resources/lang/pl-PL/install.php | 51 +
resources/lang/pl-PL/invoices.php | 83 +
resources/lang/pl-PL/items.php | 17 +
resources/lang/pl-PL/maintenance.php | 11 +
resources/lang/pl-PL/messages.php | 53 +
resources/lang/pl-PL/modules.php | 129 +
resources/lang/pl-PL/notifications.php | 155 +
resources/lang/pl-PL/pagination.php | 9 +
resources/lang/pl-PL/passwords.php | 22 +
resources/lang/pl-PL/portal.php | 53 +
resources/lang/pl-PL/reconciliations.php | 22 +
resources/lang/pl-PL/recurring.php | 43 +
resources/lang/pl-PL/reports.php | 45 +
resources/lang/pl-PL/search_string.php | 21 +
resources/lang/pl-PL/settings.php | 209 +
resources/lang/pl-PL/taxes.php | 20 +
resources/lang/pl-PL/transactions.php | 58 +
resources/lang/pl-PL/transfers.php | 34 +
resources/lang/pl-PL/updates.php | 15 +
resources/lang/pl-PL/validation.php | 146 +
resources/lang/pl-PL/vendors.php | 16 +
resources/lang/pl-PL/widgets.php | 34 +
resources/lang/pt-BR/accounts.php | 31 +
resources/lang/pt-BR/auth.php | 93 +
resources/lang/pt-BR/bills.php | 63 +
resources/lang/pt-BR/bulk_actions.php | 27 +
resources/lang/pt-BR/categories.php | 11 +
resources/lang/pt-BR/companies.php | 22 +
resources/lang/pt-BR/countries.php | 256 +
resources/lang/pt-BR/currencies.php | 27 +
resources/lang/pt-BR/customers.php | 31 +
resources/lang/pt-BR/dashboards.php | 15 +
resources/lang/pt-BR/demo.php | 31 +
resources/lang/pt-BR/documents.php | 104 +
resources/lang/pt-BR/email_templates.php | 64 +
resources/lang/pt-BR/errors.php | 25 +
resources/lang/pt-BR/footer.php | 13 +
resources/lang/pt-BR/general.php | 353 +
resources/lang/pt-BR/header.php | 33 +
resources/lang/pt-BR/import.php | 18 +
resources/lang/pt-BR/install.php | 51 +
resources/lang/pt-BR/invoices.php | 82 +
resources/lang/pt-BR/items.php | 17 +
resources/lang/pt-BR/maintenance.php | 11 +
resources/lang/pt-BR/messages.php | 53 +
resources/lang/pt-BR/modules.php | 133 +
resources/lang/pt-BR/notifications.php | 247 +
resources/lang/pt-BR/pagination.php | 9 +
resources/lang/pt-BR/passwords.php | 22 +
resources/lang/pt-BR/portal.php | 53 +
resources/lang/pt-BR/reconciliations.php | 22 +
resources/lang/pt-BR/recurring.php | 43 +
resources/lang/pt-BR/reports.php | 45 +
resources/lang/pt-BR/search_string.php | 21 +
resources/lang/pt-BR/settings.php | 209 +
resources/lang/pt-BR/taxes.php | 20 +
resources/lang/pt-BR/transactions.php | 58 +
resources/lang/pt-BR/transfers.php | 34 +
resources/lang/pt-BR/updates.php | 15 +
resources/lang/pt-BR/validation.php | 179 +
resources/lang/pt-BR/vendors.php | 16 +
resources/lang/pt-BR/widgets.php | 34 +
resources/lang/pt-PT/accounts.php | 14 +
resources/lang/pt-PT/auth.php | 41 +
resources/lang/pt-PT/bills.php | 69 +
resources/lang/pt-PT/bulk_actions.php | 21 +
resources/lang/pt-PT/companies.php | 14 +
resources/lang/pt-PT/countries.php | 253 +
resources/lang/pt-PT/currencies.php | 18 +
resources/lang/pt-PT/customers.php | 12 +
resources/lang/pt-PT/dashboards.php | 11 +
resources/lang/pt-PT/demo.php | 31 +
resources/lang/pt-PT/email_templates.php | 50 +
resources/lang/pt-PT/errors.php | 23 +
resources/lang/pt-PT/footer.php | 10 +
resources/lang/pt-PT/general.php | 206 +
resources/lang/pt-PT/header.php | 16 +
resources/lang/pt-PT/import.php | 9 +
resources/lang/pt-PT/install.php | 46 +
resources/lang/pt-PT/invoices.php | 77 +
resources/lang/pt-PT/items.php | 8 +
resources/lang/pt-PT/maintenance.php | 9 +
resources/lang/pt-PT/messages.php | 37 +
resources/lang/pt-PT/modules.php | 83 +
resources/lang/pt-PT/notifications.php | 10 +
resources/lang/pt-PT/pagination.php | 9 +
resources/lang/pt-PT/passwords.php | 23 +
resources/lang/pt-PT/reconciliations.php | 17 +
resources/lang/pt-PT/recurring.php | 20 +
resources/lang/pt-PT/reports.php | 27 +
resources/lang/pt-PT/settings.php | 129 +
resources/lang/pt-PT/taxes.php | 12 +
resources/lang/pt-PT/transfers.php | 12 +
resources/lang/pt-PT/updates.php | 15 +
resources/lang/pt-PT/validation.php | 123 +
resources/lang/pt-PT/widgets.php | 23 +
resources/lang/ro-RO/accounts.php | 31 +
resources/lang/ro-RO/auth.php | 93 +
resources/lang/ro-RO/bills.php | 64 +
resources/lang/ro-RO/bulk_actions.php | 23 +
resources/lang/ro-RO/categories.php | 11 +
resources/lang/ro-RO/companies.php | 22 +
resources/lang/ro-RO/countries.php | 256 +
resources/lang/ro-RO/currencies.php | 27 +
resources/lang/ro-RO/customers.php | 30 +
resources/lang/ro-RO/dashboard.php | 24 +
resources/lang/ro-RO/dashboards.php | 15 +
resources/lang/ro-RO/demo.php | 31 +
resources/lang/ro-RO/documents.php | 56 +
resources/lang/ro-RO/email_templates.php | 64 +
resources/lang/ro-RO/errors.php | 25 +
resources/lang/ro-RO/footer.php | 13 +
resources/lang/ro-RO/general.php | 311 +
resources/lang/ro-RO/header.php | 16 +
resources/lang/ro-RO/import.php | 9 +
resources/lang/ro-RO/install.php | 51 +
resources/lang/ro-RO/invoices.php | 86 +
resources/lang/ro-RO/items.php | 17 +
resources/lang/ro-RO/maintenance.php | 11 +
resources/lang/ro-RO/messages.php | 47 +
resources/lang/ro-RO/modules.php | 83 +
resources/lang/ro-RO/notifications.php | 54 +
resources/lang/ro-RO/pagination.php | 9 +
resources/lang/ro-RO/passwords.php | 22 +
resources/lang/ro-RO/portal.php | 52 +
resources/lang/ro-RO/reconciliations.php | 22 +
resources/lang/ro-RO/recurring.php | 42 +
resources/lang/ro-RO/reports.php | 43 +
resources/lang/ro-RO/search_string.php | 21 +
resources/lang/ro-RO/settings.php | 203 +
resources/lang/ro-RO/taxes.php | 20 +
resources/lang/ro-RO/transfers.php | 34 +
resources/lang/ro-RO/updates.php | 15 +
resources/lang/ro-RO/validation.php | 123 +
resources/lang/ro-RO/vendors.php | 16 +
resources/lang/ro-RO/widgets.php | 34 +
resources/lang/ru-RU/accounts.php | 31 +
resources/lang/ru-RU/auth.php | 93 +
resources/lang/ru-RU/bills.php | 63 +
resources/lang/ru-RU/bulk_actions.php | 27 +
resources/lang/ru-RU/categories.php | 11 +
resources/lang/ru-RU/companies.php | 22 +
resources/lang/ru-RU/countries.php | 254 +
resources/lang/ru-RU/currencies.php | 27 +
resources/lang/ru-RU/customers.php | 31 +
resources/lang/ru-RU/dashboards.php | 15 +
resources/lang/ru-RU/demo.php | 31 +
resources/lang/ru-RU/documents.php | 104 +
resources/lang/ru-RU/email_templates.php | 65 +
resources/lang/ru-RU/errors.php | 25 +
resources/lang/ru-RU/footer.php | 13 +
resources/lang/ru-RU/general.php | 353 +
resources/lang/ru-RU/header.php | 33 +
resources/lang/ru-RU/import.php | 18 +
resources/lang/ru-RU/install.php | 51 +
resources/lang/ru-RU/invoices.php | 83 +
resources/lang/ru-RU/items.php | 17 +
resources/lang/ru-RU/maintenance.php | 11 +
resources/lang/ru-RU/messages.php | 53 +
resources/lang/ru-RU/modules.php | 133 +
resources/lang/ru-RU/notifications.php | 250 +
resources/lang/ru-RU/pagination.php | 9 +
resources/lang/ru-RU/passwords.php | 22 +
resources/lang/ru-RU/portal.php | 53 +
resources/lang/ru-RU/reconciliations.php | 22 +
resources/lang/ru-RU/recurring.php | 43 +
resources/lang/ru-RU/reports.php | 45 +
resources/lang/ru-RU/search_string.php | 21 +
resources/lang/ru-RU/settings.php | 209 +
resources/lang/ru-RU/taxes.php | 20 +
resources/lang/ru-RU/transactions.php | 58 +
resources/lang/ru-RU/transfers.php | 34 +
resources/lang/ru-RU/updates.php | 15 +
resources/lang/ru-RU/validation.php | 179 +
resources/lang/ru-RU/vendors.php | 16 +
resources/lang/ru-RU/widgets.php | 34 +
resources/lang/si-LK/passwords.php | 22 +
resources/lang/sk-SK/accounts.php | 31 +
resources/lang/sk-SK/auth.php | 93 +
resources/lang/sk-SK/bills.php | 58 +
resources/lang/sk-SK/bulk_actions.php | 26 +
resources/lang/sk-SK/categories.php | 11 +
resources/lang/sk-SK/companies.php | 22 +
resources/lang/sk-SK/countries.php | 256 +
resources/lang/sk-SK/currencies.php | 27 +
resources/lang/sk-SK/customers.php | 30 +
resources/lang/sk-SK/dashboard.php | 24 +
resources/lang/sk-SK/dashboards.php | 15 +
resources/lang/sk-SK/demo.php | 16 +
resources/lang/sk-SK/errors.php | 25 +
resources/lang/sk-SK/footer.php | 10 +
resources/lang/sk-SK/general.php | 148 +
resources/lang/sk-SK/header.php | 16 +
resources/lang/sk-SK/import.php | 10 +
resources/lang/sk-SK/install.php | 44 +
resources/lang/sk-SK/invoices.php | 68 +
resources/lang/sk-SK/items.php | 8 +
resources/lang/sk-SK/messages.php | 29 +
resources/lang/sk-SK/modules.php | 80 +
resources/lang/sk-SK/notifications.php | 10 +
resources/lang/sk-SK/pagination.php | 9 +
resources/lang/sk-SK/passwords.php | 22 +
resources/lang/sk-SK/reconciliations.php | 14 +
resources/lang/sk-SK/recurring.php | 20 +
resources/lang/sk-SK/reports.php | 27 +
resources/lang/sk-SK/search_string.php | 20 +
resources/lang/sk-SK/settings.php | 102 +
resources/lang/sk-SK/taxes.php | 8 +
resources/lang/sk-SK/transfers.php | 12 +
resources/lang/sk-SK/updates.php | 15 +
resources/lang/sk-SK/validation.php | 121 +
resources/lang/sl-SI/accounts.php | 32 +
resources/lang/sl-SI/auth.php | 97 +
resources/lang/sl-SI/bills.php | 63 +
resources/lang/sl-SI/bulk_actions.php | 28 +
resources/lang/sl-SI/categories.php | 11 +
resources/lang/sl-SI/companies.php | 22 +
resources/lang/sl-SI/countries.php | 256 +
resources/lang/sl-SI/currencies.php | 27 +
resources/lang/sl-SI/customers.php | 39 +
resources/lang/sl-SI/dashboards.php | 17 +
resources/lang/sl-SI/demo.php | 34 +
resources/lang/sl-SI/documents.php | 103 +
resources/lang/sl-SI/email_templates.php | 66 +
resources/lang/sl-SI/errors.php | 26 +
resources/lang/sl-SI/footer.php | 13 +
resources/lang/sl-SI/general.php | 340 +
resources/lang/sl-SI/header.php | 33 +
resources/lang/sl-SI/import.php | 13 +
resources/lang/sl-SI/install.php | 51 +
resources/lang/sl-SI/invoices.php | 83 +
resources/lang/sl-SI/items.php | 17 +
resources/lang/sl-SI/maintenance.php | 11 +
resources/lang/sl-SI/messages.php | 50 +
resources/lang/sl-SI/modules.php | 136 +
resources/lang/sl-SI/notifications.php | 218 +
resources/lang/sl-SI/pagination.php | 9 +
resources/lang/sl-SI/passwords.php | 22 +
resources/lang/sl-SI/payments.php | 10 +
resources/lang/sl-SI/portal.php | 53 +
resources/lang/sl-SI/reconciliations.php | 22 +
resources/lang/sl-SI/recurring.php | 43 +
resources/lang/sl-SI/reports.php | 40 +
resources/lang/sl-SI/revenues.php | 10 +
resources/lang/sl-SI/search_string.php | 21 +
resources/lang/sl-SI/settings.php | 212 +
resources/lang/sl-SI/taxes.php | 20 +
resources/lang/sl-SI/transactions.php | 53 +
resources/lang/sl-SI/transfers.php | 34 +
resources/lang/sl-SI/updates.php | 15 +
resources/lang/sl-SI/validation.php | 174 +
resources/lang/sl-SI/vendors.php | 16 +
resources/lang/sl-SI/widgets.php | 34 +
resources/lang/sq-AL/accounts.php | 14 +
resources/lang/sq-AL/auth.php | 41 +
resources/lang/sq-AL/bills.php | 56 +
resources/lang/sq-AL/bulk_actions.php | 23 +
resources/lang/sq-AL/companies.php | 14 +
resources/lang/sq-AL/countries.php | 253 +
resources/lang/sq-AL/currencies.php | 19 +
resources/lang/sq-AL/customers.php | 12 +
resources/lang/sq-AL/dashboards.php | 11 +
resources/lang/sq-AL/demo.php | 31 +
resources/lang/sq-AL/documents.php | 54 +
resources/lang/sq-AL/email_templates.php | 50 +
resources/lang/sq-AL/errors.php | 23 +
resources/lang/sq-AL/footer.php | 10 +
resources/lang/sq-AL/general.php | 232 +
resources/lang/sq-AL/header.php | 16 +
resources/lang/sq-AL/import.php | 9 +
resources/lang/sq-AL/install.php | 46 +
resources/lang/sq-AL/invoices.php | 60 +
resources/lang/sq-AL/items.php | 9 +
resources/lang/sq-AL/maintenance.php | 9 +
resources/lang/sq-AL/messages.php | 39 +
resources/lang/sq-AL/modules.php | 83 +
resources/lang/sq-AL/notifications.php | 54 +
resources/lang/sq-AL/pagination.php | 9 +
resources/lang/sq-AL/passwords.php | 23 +
resources/lang/sq-AL/reconciliations.php | 18 +
resources/lang/sq-AL/recurring.php | 20 +
resources/lang/sq-AL/reports.php | 28 +
resources/lang/sq-AL/search_string.php | 20 +
resources/lang/sq-AL/settings.php | 144 +
resources/lang/sq-AL/taxes.php | 12 +
resources/lang/sq-AL/transfers.php | 14 +
resources/lang/sq-AL/updates.php | 15 +
resources/lang/sq-AL/validation.php | 123 +
resources/lang/sq-AL/widgets.php | 24 +
resources/lang/sr-CS/accounts.php | 14 +
resources/lang/sr-CS/auth.php | 41 +
resources/lang/sr-CS/bills.php | 56 +
resources/lang/sr-CS/bulk_actions.php | 23 +
resources/lang/sr-CS/companies.php | 14 +
resources/lang/sr-CS/countries.php | 253 +
resources/lang/sr-CS/currencies.php | 19 +
resources/lang/sr-CS/customers.php | 12 +
resources/lang/sr-CS/dashboards.php | 11 +
resources/lang/sr-CS/demo.php | 31 +
resources/lang/sr-CS/documents.php | 12 +
resources/lang/sr-CS/errors.php | 23 +
resources/lang/sr-CS/footer.php | 10 +
resources/lang/sr-CS/import.php | 9 +
resources/lang/sr-CS/items.php | 8 +
resources/lang/sr-CS/pagination.php | 9 +
resources/lang/sr-CS/passwords.php | 23 +
resources/lang/sr-CS/search_string.php | 15 +
resources/lang/sr-CS/taxes.php | 12 +
resources/lang/sr-CS/transfers.php | 12 +
resources/lang/sr-CS/updates.php | 15 +
resources/lang/sr-CS/widgets.php | 23 +
resources/lang/sr-RS/accounts.php | 14 +
resources/lang/sr-RS/auth.php | 39 +
resources/lang/sr-RS/bills.php | 58 +
resources/lang/sr-RS/companies.php | 13 +
resources/lang/sr-RS/countries.php | 253 +
resources/lang/sr-RS/currencies.php | 18 +
resources/lang/sr-RS/customers.php | 16 +
resources/lang/sr-RS/dashboard.php | 24 +
resources/lang/sr-RS/demo.php | 16 +
resources/lang/sr-RS/footer.php | 10 +
resources/lang/sr-RS/general.php | 146 +
resources/lang/sr-RS/header.php | 16 +
resources/lang/sr-RS/import.php | 9 +
resources/lang/sr-RS/install.php | 44 +
resources/lang/sr-RS/invoices.php | 68 +
resources/lang/sr-RS/items.php | 18 +
resources/lang/sr-RS/messages.php | 32 +
resources/lang/sr-RS/modules.php | 83 +
resources/lang/sr-RS/notifications.php | 10 +
resources/lang/sr-RS/pagination.php | 9 +
resources/lang/sr-RS/passwords.php | 22 +
resources/lang/sr-RS/reconciliations.php | 16 +
resources/lang/sr-RS/recurring.php | 20 +
resources/lang/sr-RS/reports.php | 27 +
resources/lang/sr-RS/settings.php | 102 +
resources/lang/sr-RS/taxes.php | 11 +
resources/lang/sr-RS/transfers.php | 12 +
resources/lang/sr-RS/updates.php | 15 +
resources/lang/sr-RS/validation.php | 121 +
resources/lang/sr-SP/accounts.php | 14 +
resources/lang/sr-SP/auth.php | 41 +
resources/lang/sr-SP/bills.php | 56 +
resources/lang/sr-SP/countries.php | 253 +
resources/lang/sr-SP/currencies.php | 18 +
resources/lang/sr-SP/footer.php | 10 +
resources/lang/sr-SP/header.php | 16 +
resources/lang/sr-SP/import.php | 9 +
resources/lang/sr-SP/items.php | 8 +
resources/lang/sr-SP/notifications.php | 10 +
resources/lang/sr-SP/recurring.php | 20 +
resources/lang/sr-SP/transfers.php | 12 +
resources/lang/sr-SP/updates.php | 15 +
resources/lang/sv-SE/accounts.php | 31 +
resources/lang/sv-SE/auth.php | 93 +
resources/lang/sv-SE/bills.php | 63 +
resources/lang/sv-SE/bulk_actions.php | 26 +
resources/lang/sv-SE/categories.php | 11 +
resources/lang/sv-SE/companies.php | 22 +
resources/lang/sv-SE/countries.php | 256 +
resources/lang/sv-SE/currencies.php | 27 +
resources/lang/sv-SE/customers.php | 30 +
resources/lang/sv-SE/dashboards.php | 15 +
resources/lang/sv-SE/demo.php | 31 +
resources/lang/sv-SE/documents.php | 86 +
resources/lang/sv-SE/email_templates.php | 64 +
resources/lang/sv-SE/errors.php | 25 +
resources/lang/sv-SE/footer.php | 13 +
resources/lang/sv-SE/general.php | 312 +
resources/lang/sv-SE/header.php | 33 +
resources/lang/sv-SE/import.php | 10 +
resources/lang/sv-SE/install.php | 51 +
resources/lang/sv-SE/invoices.php | 85 +
resources/lang/sv-SE/items.php | 17 +
resources/lang/sv-SE/maintenance.php | 11 +
resources/lang/sv-SE/messages.php | 47 +
resources/lang/sv-SE/modules.php | 135 +
resources/lang/sv-SE/notifications.php | 188 +
resources/lang/sv-SE/pagination.php | 9 +
resources/lang/sv-SE/passwords.php | 22 +
resources/lang/sv-SE/payments.php | 10 +
resources/lang/sv-SE/portal.php | 53 +
resources/lang/sv-SE/reconciliations.php | 22 +
resources/lang/sv-SE/recurring.php | 41 +
resources/lang/sv-SE/reports.php | 43 +
resources/lang/sv-SE/revenues.php | 10 +
resources/lang/sv-SE/search_string.php | 21 +
resources/lang/sv-SE/settings.php | 204 +
resources/lang/sv-SE/taxes.php | 20 +
resources/lang/sv-SE/transactions.php | 47 +
resources/lang/sv-SE/transfers.php | 34 +
resources/lang/sv-SE/updates.php | 15 +
resources/lang/sv-SE/validation.php | 174 +
resources/lang/sv-SE/vendors.php | 16 +
resources/lang/sv-SE/widgets.php | 34 +
resources/lang/sw-KE/passwords.php | 22 +
resources/lang/ta-IN/accounts.php | 14 +
resources/lang/ta-IN/auth.php | 41 +
resources/lang/ta-IN/countries.php | 253 +
resources/lang/th-TH/accounts.php | 14 +
resources/lang/th-TH/auth.php | 41 +
resources/lang/th-TH/bills.php | 61 +
resources/lang/th-TH/companies.php | 14 +
resources/lang/th-TH/countries.php | 253 +
resources/lang/th-TH/currencies.php | 19 +
resources/lang/th-TH/customers.php | 12 +
resources/lang/th-TH/dashboard.php | 24 +
resources/lang/th-TH/dashboards.php | 11 +
resources/lang/th-TH/demo.php | 31 +
resources/lang/th-TH/errors.php | 23 +
resources/lang/th-TH/footer.php | 10 +
resources/lang/th-TH/general.php | 147 +
resources/lang/th-TH/header.php | 16 +
resources/lang/th-TH/import.php | 9 +
resources/lang/th-TH/install.php | 44 +
resources/lang/th-TH/invoices.php | 71 +
resources/lang/th-TH/items.php | 8 +
resources/lang/th-TH/maintenance.php | 9 +
resources/lang/th-TH/messages.php | 32 +
resources/lang/th-TH/modules.php | 83 +
resources/lang/th-TH/notifications.php | 10 +
resources/lang/th-TH/pagination.php | 9 +
resources/lang/th-TH/passwords.php | 23 +
resources/lang/th-TH/reconciliations.php | 16 +
resources/lang/th-TH/recurring.php | 20 +
resources/lang/th-TH/reports.php | 27 +
resources/lang/th-TH/settings.php | 103 +
resources/lang/th-TH/taxes.php | 12 +
resources/lang/th-TH/transfers.php | 12 +
resources/lang/th-TH/updates.php | 15 +
resources/lang/th-TH/validation.php | 123 +
resources/lang/tr-TR/accounts.php | 31 +
resources/lang/tr-TR/auth.php | 93 +
resources/lang/tr-TR/bills.php | 63 +
resources/lang/tr-TR/bulk_actions.php | 27 +
resources/lang/tr-TR/categories.php | 11 +
resources/lang/tr-TR/companies.php | 22 +
resources/lang/tr-TR/countries.php | 256 +
resources/lang/tr-TR/currencies.php | 27 +
resources/lang/tr-TR/customers.php | 31 +
resources/lang/tr-TR/dashboards.php | 15 +
resources/lang/tr-TR/demo.php | 31 +
resources/lang/tr-TR/documents.php | 104 +
resources/lang/tr-TR/email_templates.php | 64 +
resources/lang/tr-TR/errors.php | 25 +
resources/lang/tr-TR/footer.php | 13 +
resources/lang/tr-TR/general.php | 353 +
resources/lang/tr-TR/header.php | 33 +
resources/lang/tr-TR/import.php | 18 +
resources/lang/tr-TR/install.php | 51 +
resources/lang/tr-TR/invoices.php | 83 +
resources/lang/tr-TR/items.php | 17 +
resources/lang/tr-TR/maintenance.php | 11 +
resources/lang/tr-TR/messages.php | 53 +
resources/lang/tr-TR/modules.php | 134 +
resources/lang/tr-TR/notifications.php | 250 +
resources/lang/tr-TR/pagination.php | 9 +
resources/lang/tr-TR/passwords.php | 22 +
resources/lang/tr-TR/portal.php | 53 +
resources/lang/tr-TR/reconciliations.php | 22 +
resources/lang/tr-TR/recurring.php | 43 +
resources/lang/tr-TR/reports.php | 45 +
resources/lang/tr-TR/search_string.php | 21 +
resources/lang/tr-TR/settings.php | 209 +
resources/lang/tr-TR/taxes.php | 20 +
resources/lang/tr-TR/transactions.php | 58 +
resources/lang/tr-TR/transfers.php | 34 +
resources/lang/tr-TR/updates.php | 15 +
resources/lang/tr-TR/validation.php | 179 +
resources/lang/tr-TR/vendors.php | 16 +
resources/lang/tr-TR/widgets.php | 34 +
resources/lang/uk-UA/accounts.php | 14 +
resources/lang/uk-UA/auth.php | 41 +
resources/lang/uk-UA/bills.php | 63 +
resources/lang/uk-UA/bulk_actions.php | 19 +
resources/lang/uk-UA/companies.php | 14 +
resources/lang/uk-UA/countries.php | 253 +
resources/lang/uk-UA/currencies.php | 18 +
resources/lang/uk-UA/customers.php | 12 +
resources/lang/uk-UA/dashboards.php | 11 +
resources/lang/uk-UA/demo.php | 31 +
resources/lang/uk-UA/email_templates.php | 50 +
resources/lang/uk-UA/errors.php | 23 +
resources/lang/uk-UA/footer.php | 10 +
resources/lang/uk-UA/general.php | 206 +
resources/lang/uk-UA/header.php | 16 +
resources/lang/uk-UA/import.php | 9 +
resources/lang/uk-UA/install.php | 44 +
resources/lang/uk-UA/invoices.php | 72 +
resources/lang/uk-UA/items.php | 8 +
resources/lang/uk-UA/maintenance.php | 9 +
resources/lang/uk-UA/messages.php | 35 +
resources/lang/uk-UA/modules.php | 83 +
resources/lang/uk-UA/notifications.php | 10 +
resources/lang/uk-UA/pagination.php | 9 +
resources/lang/uk-UA/passwords.php | 22 +
resources/lang/uk-UA/reconciliations.php | 16 +
resources/lang/uk-UA/recurring.php | 21 +
resources/lang/uk-UA/reports.php | 27 +
resources/lang/uk-UA/settings.php | 123 +
resources/lang/uk-UA/taxes.php | 11 +
resources/lang/uk-UA/transfers.php | 12 +
resources/lang/uk-UA/updates.php | 15 +
resources/lang/uk-UA/validation.php | 122 +
resources/lang/uk-UA/widgets.php | 23 +
resources/lang/ur-PK/accounts.php | 31 +
resources/lang/ur-PK/auth.php | 39 +
resources/lang/ur-PK/bills.php | 61 +
resources/lang/ur-PK/companies.php | 13 +
resources/lang/ur-PK/countries.php | 253 +
resources/lang/ur-PK/currencies.php | 18 +
resources/lang/ur-PK/customers.php | 16 +
resources/lang/ur-PK/dashboard.php | 24 +
resources/lang/ur-PK/demo.php | 13 +
resources/lang/ur-PK/errors.php | 24 +
resources/lang/ur-PK/footer.php | 10 +
resources/lang/ur-PK/general.php | 148 +
resources/lang/ur-PK/header.php | 16 +
resources/lang/ur-PK/import.php | 9 +
resources/lang/ur-PK/install.php | 44 +
resources/lang/ur-PK/invoices.php | 72 +
resources/lang/ur-PK/items.php | 8 +
resources/lang/ur-PK/messages.php | 32 +
resources/lang/ur-PK/modules.php | 85 +
resources/lang/ur-PK/notifications.php | 10 +
resources/lang/ur-PK/pagination.php | 9 +
resources/lang/ur-PK/passwords.php | 22 +
resources/lang/ur-PK/reconciliations.php | 16 +
resources/lang/ur-PK/recurring.php | 20 +
resources/lang/ur-PK/reports.php | 27 +
resources/lang/ur-PK/settings.php | 103 +
resources/lang/ur-PK/taxes.php | 11 +
resources/lang/ur-PK/transfers.php | 12 +
resources/lang/ur-PK/updates.php | 15 +
resources/lang/ur-PK/validation.php | 121 +
resources/lang/uz-UZ/accounts.php | 14 +
resources/lang/uz-UZ/auth.php | 41 +
resources/lang/uz-UZ/bills.php | 61 +
resources/lang/uz-UZ/bulk_actions.php | 19 +
resources/lang/uz-UZ/companies.php | 14 +
resources/lang/uz-UZ/countries.php | 253 +
resources/lang/uz-UZ/currencies.php | 18 +
resources/lang/uz-UZ/customers.php | 12 +
resources/lang/uz-UZ/dashboard.php | 23 +
resources/lang/uz-UZ/dashboards.php | 11 +
resources/lang/uz-UZ/demo.php | 31 +
resources/lang/uz-UZ/email_templates.php | 50 +
resources/lang/uz-UZ/errors.php | 23 +
resources/lang/uz-UZ/footer.php | 10 +
resources/lang/uz-UZ/general.php | 181 +
resources/lang/uz-UZ/header.php | 16 +
resources/lang/uz-UZ/import.php | 9 +
resources/lang/uz-UZ/install.php | 44 +
resources/lang/uz-UZ/invoices.php | 69 +
resources/lang/uz-UZ/items.php | 8 +
resources/lang/uz-UZ/maintenance.php | 9 +
resources/lang/uz-UZ/messages.php | 34 +
resources/lang/uz-UZ/modules.php | 83 +
resources/lang/uz-UZ/notifications.php | 10 +
resources/lang/uz-UZ/pagination.php | 9 +
resources/lang/uz-UZ/passwords.php | 22 +
resources/lang/uz-UZ/reconciliations.php | 16 +
resources/lang/uz-UZ/recurring.php | 20 +
resources/lang/uz-UZ/reports.php | 27 +
resources/lang/uz-UZ/settings.php | 119 +
resources/lang/uz-UZ/taxes.php | 11 +
resources/lang/uz-UZ/transfers.php | 12 +
resources/lang/uz-UZ/updates.php | 15 +
resources/lang/uz-UZ/validation.php | 122 +
resources/lang/uz-UZ/widgets.php | 23 +
resources/lang/vi-VN/accounts.php | 31 +
resources/lang/vi-VN/auth.php | 39 +
resources/lang/vi-VN/bills.php | 58 +
resources/lang/vi-VN/companies.php | 13 +
resources/lang/vi-VN/countries.php | 253 +
resources/lang/vi-VN/currencies.php | 18 +
resources/lang/vi-VN/customers.php | 16 +
resources/lang/vi-VN/dashboard.php | 24 +
resources/lang/vi-VN/demo.php | 16 +
resources/lang/vi-VN/footer.php | 10 +
resources/lang/vi-VN/general.php | 148 +
resources/lang/vi-VN/header.php | 16 +
resources/lang/vi-VN/import.php | 10 +
resources/lang/vi-VN/install.php | 44 +
resources/lang/vi-VN/invoices.php | 68 +
resources/lang/vi-VN/items.php | 8 +
resources/lang/vi-VN/messages.php | 29 +
resources/lang/vi-VN/modules.php | 80 +
resources/lang/vi-VN/notifications.php | 10 +
resources/lang/vi-VN/pagination.php | 9 +
resources/lang/vi-VN/passwords.php | 22 +
resources/lang/vi-VN/reconciliations.php | 14 +
resources/lang/vi-VN/recurring.php | 21 +
resources/lang/vi-VN/reports.php | 27 +
resources/lang/vi-VN/settings.php | 102 +
resources/lang/vi-VN/taxes.php | 8 +
resources/lang/vi-VN/transfers.php | 12 +
resources/lang/vi-VN/updates.php | 15 +
resources/lang/vi-VN/validation.php | 121 +
resources/lang/zh-CN/accounts.php | 31 +
resources/lang/zh-CN/auth.php | 93 +
resources/lang/zh-CN/bills.php | 63 +
resources/lang/zh-CN/bulk_actions.php | 27 +
resources/lang/zh-CN/categories.php | 11 +
resources/lang/zh-CN/companies.php | 22 +
resources/lang/zh-CN/countries.php | 256 +
resources/lang/zh-CN/currencies.php | 27 +
resources/lang/zh-CN/customers.php | 31 +
resources/lang/zh-CN/dashboards.php | 15 +
resources/lang/zh-CN/demo.php | 31 +
resources/lang/zh-CN/documents.php | 104 +
resources/lang/zh-CN/email_templates.php | 64 +
resources/lang/zh-CN/errors.php | 25 +
resources/lang/zh-CN/footer.php | 13 +
resources/lang/zh-CN/fund_accounts.php | 35 +
resources/lang/zh-CN/general.php | 353 +
resources/lang/zh-CN/header.php | 33 +
resources/lang/zh-CN/import.php | 18 +
resources/lang/zh-CN/install.php | 51 +
resources/lang/zh-CN/invoices.php | 83 +
resources/lang/zh-CN/items.php | 17 +
resources/lang/zh-CN/maintenance.php | 11 +
resources/lang/zh-CN/messages.php | 53 +
resources/lang/zh-CN/modules.php | 133 +
resources/lang/zh-CN/notifications.php | 250 +
resources/lang/zh-CN/pagination.php | 9 +
resources/lang/zh-CN/passwords.php | 21 +
resources/lang/zh-CN/portal.php | 53 +
resources/lang/zh-CN/reconciliations.php | 22 +
resources/lang/zh-CN/recurring.php | 43 +
resources/lang/zh-CN/reports.php | 45 +
resources/lang/zh-CN/search_string.php | 21 +
resources/lang/zh-CN/settings.php | 209 +
resources/lang/zh-CN/taxes.php | 19 +
resources/lang/zh-CN/transactions.php | 58 +
resources/lang/zh-CN/transfers.php | 34 +
resources/lang/zh-CN/updates.php | 15 +
resources/lang/zh-CN/validation.php | 179 +
resources/lang/zh-CN/vendors.php | 16 +
resources/lang/zh-CN/widgets.php | 34 +
resources/lang/zh-TW/accounts.php | 14 +
resources/lang/zh-TW/auth.php | 41 +
resources/lang/zh-TW/bills.php | 56 +
resources/lang/zh-TW/bulk_actions.php | 23 +
resources/lang/zh-TW/companies.php | 14 +
resources/lang/zh-TW/countries.php | 253 +
resources/lang/zh-TW/currencies.php | 19 +
resources/lang/zh-TW/customers.php | 12 +
resources/lang/zh-TW/dashboards.php | 11 +
resources/lang/zh-TW/demo.php | 31 +
resources/lang/zh-TW/email_templates.php | 50 +
resources/lang/zh-TW/errors.php | 23 +
resources/lang/zh-TW/footer.php | 10 +
resources/lang/zh-TW/general.php | 231 +
resources/lang/zh-TW/header.php | 16 +
resources/lang/zh-TW/import.php | 9 +
resources/lang/zh-TW/install.php | 46 +
resources/lang/zh-TW/invoices.php | 60 +
resources/lang/zh-TW/items.php | 9 +
resources/lang/zh-TW/maintenance.php | 9 +
resources/lang/zh-TW/messages.php | 37 +
resources/lang/zh-TW/modules.php | 83 +
resources/lang/zh-TW/notifications.php | 27 +
resources/lang/zh-TW/pagination.php | 9 +
resources/lang/zh-TW/passwords.php | 23 +
resources/lang/zh-TW/reconciliations.php | 18 +
resources/lang/zh-TW/recurring.php | 20 +
resources/lang/zh-TW/reports.php | 27 +
resources/lang/zh-TW/settings.php | 144 +
resources/lang/zh-TW/taxes.php | 12 +
resources/lang/zh-TW/transfers.php | 12 +
resources/lang/zh-TW/updates.php | 15 +
resources/lang/zh-TW/validation.php | 123 +
resources/lang/zh-TW/widgets.php | 24 +
resources/views/auth/forgot/create.blade.php | 53 +
resources/views/auth/login/create.blade.php | 81 +
.../views/auth/register/create.blade.php | 64 +
resources/views/auth/reset/create.blade.php | 71 +
resources/views/auth/users/create.blade.php | 77 +
resources/views/auth/users/edit.blade.php | 91 +
resources/views/auth/users/index.blade.php | 110 +
resources/views/auth/users/show.blade.php | 273 +
.../views/banking/accounts/create.blade.php | 77 +
.../views/banking/accounts/edit.blade.php | 75 +
.../views/banking/accounts/index.blade.php | 116 +
.../views/banking/accounts/show.blade.php | 472 +
.../banking/fund_accounts/form.blade.php | 69 +
.../banking/fund_accounts/index.blade.php | 174 +
.../fund_accounts/store-index.blade.php | 14 +
.../banking/reconciliations/create.blade.php | 315 +
.../banking/reconciliations/edit.blade.php | 265 +
.../banking/reconciliations/index.blade.php | 123 +
.../recurring_transactions/create.blade.php | 124 +
.../recurring_transactions/edit.blade.php | 129 +
.../recurring_transactions/index.blade.php | 32 +
.../recurring_transactions/show.blade.php | 38 +
.../banking/transactions/create.blade.php | 89 +
.../views/banking/transactions/edit.blade.php | 112 +
.../banking/transactions/import.blade.php | 151 +
.../banking/transactions/index.blade.php | 30 +
.../transactions/print_default.blade.php | 9 +
.../views/banking/transactions/show.blade.php | 23 +
.../views/banking/transfers/create.blade.php | 82 +
.../views/banking/transfers/edit.blade.php | 94 +
.../views/banking/transfers/index.blade.php | 166 +
.../banking/transfers/print_default.blade.php | 9 +
.../banking/transfers/print_second.blade.php | 9 +
.../banking/transfers/print_third.blade.php | 9 +
.../views/banking/transfers/show.blade.php | 58 +
.../bulk-actions/auth/users/edit.blade.php | 43 +
.../banking/accounts/edit.blade.php | 41 +
.../banking/transactions/edit.blade.php | 7 +
.../common/companies/edit.blade.php | 16 +
.../bulk-actions/common/items/edit.blade.php | 30 +
.../purchases/bills/edit.blade.php | 1 +
.../purchases/vendors/edit.blade.php | 14 +
.../sales/customers/edit.blade.php | 14 +
.../sales/invoices/edit.blade.php | 1 +
.../settings/categories/edit.blade.php | 11 +
.../settings/currencies/edit.blade.php | 33 +
.../settings/taxes/edit.blade.php | 11 +
resources/views/business/pages/show.blade.php | 102 +
.../views/common/companies/create.blade.php | 41 +
.../views/common/companies/edit.blade.php | 43 +
.../views/common/companies/index.blade.php | 148 +
.../views/common/dashboards/create.blade.php | 31 +
.../views/common/dashboards/edit.blade.php | 35 +
.../views/common/dashboards/index.blade.php | 74 +
.../views/common/dashboards/show.blade.php | 173 +
.../views/common/import/create.blade.php | 77 +
resources/views/common/items/create.blade.php | 65 +
resources/views/common/items/edit.blade.php | 63 +
resources/views/common/items/index.blade.php | 150 +
.../views/common/reports/create.blade.php | 43 +
resources/views/common/reports/edit.blade.php | 158 +
.../views/common/reports/index.blade.php | 94 +
.../views/components/alert/border.blade.php | 15 +
.../views/components/alert/call.blade.php | 8 +
.../views/components/alert/danger.blade.php | 15 +
.../views/components/alert/index.blade.php | 116 +
.../views/components/alert/info.blade.php | 15 +
.../views/components/alert/success.blade.php | 15 +
.../views/components/alert/warning.blade.php | 15 +
.../views/components/button/hover.blade.php | 9 +
.../views/components/button/index.blade.php | 3 +
.../views/components/button/loading.blade.php | 21 +
.../contacts/form/address.blade.php | 30 +
.../contacts/form/billing.blade.php | 22 +
.../contacts/form/buttons.blade.php | 5 +
.../contacts/form/content.blade.php | 32 +
.../contacts/form/general.blade.php | 73 +
.../contacts/form/persons.blade.php | 88 +
.../contacts/index/buttons.blade.php | 15 +
.../contacts/index/content.blade.php | 268 +
.../contacts/index/more-buttons.blade.php | 27 +
.../components/contacts/script.blade.php | 15 +
.../contacts/show/buttons.blade.php | 44 +
.../contacts/show/content.blade.php | 410 +
.../contacts/show/more-buttons.blade.php | 33 +
resources/views/components/date.blade.php | 1 +
.../views/components/delete-button.blade.php | 45 +
.../views/components/delete-link.blade.php | 27 +
.../documents/form/advanced.blade.php | 63 +
.../documents/form/buttons.blade.php | 22 +
.../documents/form/company.blade.php | 66 +
.../documents/form/contact.blade.php | 33 +
.../documents/form/content.blade.php | 32 +
.../documents/form/item-button.blade.php | 21 +
.../documents/form/item-columns.blade.php | 18 +
.../components/documents/form/items.blade.php | 145 +
.../documents/form/line-item.blade.php | 497 +
.../components/documents/form/main.blade.php | 15 +
.../documents/form/metadata.blade.php | 90 +
.../components/documents/form/note.blade.php | 13 +
.../documents/form/recurring.blade.php | 24 +
.../form/recurring_metadata.blade.php | 94 +
.../documents/form/totals.blade.php | 247 +
.../documents/index/bulk-action.blade.php | 32 +
.../documents/index/buttons.blade.php | 15 +
.../documents/index/content.blade.php | 159 +
.../documents/index/document.blade.php | 180 +
.../documents/index/information.blade.php | 120 +
.../documents/index/more-buttons.blade.php | 27 +
.../index/recurring_templates.blade.php | 238 +
.../components/documents/script.blade.php | 28 +
.../documents/show/attachment.blade.php | 38 +
.../documents/show/buttons.blade.php | 23 +
.../documents/show/children.blade.php | 31 +
.../documents/show/content.blade.php | 129 +
.../documents/show/create.blade.php | 38 +
.../documents/show/get-paid.blade.php | 162 +
.../documents/show/make-payment.blade.php | 141 +
.../documents/show/message.blade.php | 17 +
.../documents/show/more-buttons.blade.php | 147 +
.../documents/show/receive.blade.php | 40 +
.../documents/show/restore.blade.php | 28 +
.../documents/show/schedule.blade.php | 36 +
.../components/documents/show/send.blade.php | 96 +
.../documents/show/template.blade.php | 142 +
.../documents/template/classic.blade.php | 421 +
.../documents/template/default.blade.php | 392 +
.../documents/template/line-item.blade.php | 80 +
.../documents/template/modern.blade.php | 388 +
.../components/dropdown/button.blade.php | 5 +
.../components/dropdown/divider.blade.php | 3 +
.../views/components/dropdown/index.blade.php | 27 +
.../views/components/dropdown/link.blade.php | 5 +
.../views/components/email/body.blade.php | 1 +
.../views/components/email/footer.blade.php | 33 +
.../views/components/empty-data.blade.php | 1 +
.../views/components/empty-page.blade.php | 83 +
.../components/form/accordion/head.blade.php | 11 +
.../components/form/accordion/index.blade.php | 26 +
.../views/components/form/buttons.blade.php | 25 +
.../views/components/form/container.blade.php | 19 +
.../views/components/form/error.blade.php | 4 +
.../components/form/group/account.blade.php | 60 +
.../form/group/attachment.blade.php | 10 +
.../components/form/group/category.blade.php | 142 +
.../components/form/group/checkbox.blade.php | 73 +
.../components/form/group/color.blade.php | 79 +
.../components/form/group/contact.blade.php | 221 +
.../components/form/group/country.blade.php | 10 +
.../components/form/group/currency.blade.php | 39 +
.../components/form/group/customer.blade.php | 19 +
.../components/form/group/date.blade.php | 109 +
.../components/form/group/date_time.blade.php | 95 +
.../components/form/group/editor.blade.php | 47 +
.../components/form/group/email.blade.php | 59 +
.../components/form/group/file.blade.php | 59 +
.../components/form/group/import.blade.php | 59 +
.../form/group/invoice_text.blade.php | 180 +
.../components/form/group/locale.blade.php | 11 +
.../components/form/group/money.blade.php | 88 +
.../components/form/group/number.blade.php | 58 +
.../form/group/number_digit.blade.php | 13 +
.../components/form/group/password.blade.php | 58 +
.../form/group/payment_method.blade.php | 12 +
.../form/group/payment_term.blade.php | 185 +
.../components/form/group/radio.blade.php | 60 +
.../components/form/group/recurring.blade.php | 86 +
.../components/form/group/select.blade.php | 220 +
.../components/form/group/switch.blade.php | 26 +
.../views/components/form/group/tax.blade.php | 251 +
.../components/form/group/text.blade.php | 65 +
.../components/form/group/textarea.blade.php | 61 +
.../components/form/group/time.blade.php | 93 +
.../components/form/group/toggle.blade.php | 48 +
.../components/form/group/vendor.blade.php | 19 +
.../views/components/form/icon.blade.php | 5 +
.../views/components/form/index.blade.php | 26 +
.../components/form/input/checkbox.blade.php | 25 +
.../components/form/input/color.blade.php | 77 +
.../components/form/input/editor.blade.php | 25 +
.../components/form/input/email.blade.php | 19 +
.../components/form/input/file.blade.php | 83 +
.../components/form/input/hidden.blade.php | 16 +
.../components/form/input/import.blade.php | 80 +
.../components/form/input/input.blade.php | 18 +
.../components/form/input/money.blade.php | 82 +
.../components/form/input/number.blade.php | 19 +
.../components/form/input/password.blade.php | 34 +
.../components/form/input/radio.blade.php | 28 +
.../components/form/input/select.blade.php | 180 +
.../components/form/input/text.blade.php | 17 +
.../components/form/input/textarea.blade.php | 26 +
.../views/components/form/label.blade.php | 7 +
.../components/form/section/head.blade.php | 11 +
.../components/form/section/index.blade.php | 22 +
resources/views/components/icon.blade.php | 20 +
.../views/components/index/balance.blade.php | 3 +
.../components/index/bulkaction/all.blade.php | 13 +
.../index/bulkaction/index.blade.php | 96 +
.../index/bulkaction/modal.blade.php | 13 +
.../index/bulkaction/single.blade.php | 21 +
.../views/components/index/category.blade.php | 11 +
.../components/index/container.blade.php | 5 +
.../views/components/index/country.blade.php | 1 +
.../views/components/index/currency.blade.php | 1 +
.../views/components/index/default.blade.php | 7 +
.../views/components/index/disable.blade.php | 7 +
.../views/components/index/search.blade.php | 25 +
.../views/components/index/status.blade.php | 8 +
.../views/components/index/summary.blade.php | 247 +
.../views/components/layouts/admin.blade.php | 99 +
.../layouts/admin/content.blade.php | 15 +
.../components/layouts/admin/footer.blade.php | 16 +
.../components/layouts/admin/head.blade.php | 66 +
.../components/layouts/admin/header.blade.php | 45 +
.../components/layouts/admin/menu.blade.php | 262 +
.../layouts/admin/notifications.blade.php | 3 +
.../layouts/admin/scripts.blade.php | 313 +
.../views/components/layouts/auth.blade.php | 35 +
.../components/layouts/auth/content.blade.php | 7 +
.../components/layouts/auth/footer.blade.php | 12 +
.../components/layouts/auth/head.blade.php | 61 +
.../components/layouts/auth/scripts.blade.php | 15 +
.../components/layouts/auth/slider.blade.php | 51 +
.../views/components/layouts/error.blade.php | 32 +
.../layouts/error/content.blade.php | 15 +
.../components/layouts/error/head.blade.php | 57 +
.../layouts/error/scripts.blade.php | 11 +
.../components/layouts/install.blade.php | 52 +
.../layouts/install/content.blade.php | 50 +
.../components/layouts/install/head.blade.php | 57 +
.../layouts/install/scripts.blade.php | 13 +
.../components/layouts/maintenance.blade.php | 6 +
.../layouts/maintenance/body.blade.php | 15 +
.../layouts/maintenance/head.blade.php | 32 +
.../components/layouts/modules.blade.php | 83 +
.../components/layouts/modules/bar.blade.php | 137 +
.../components/layouts/modules/head.blade.php | 85 +
.../components/layouts/modules/item.blade.php | 63 +
.../layouts/modules/my_apps_item.blade.php | 59 +
.../layouts/modules/releases.blade.php | 9 +
.../layouts/modules/reviews.blade.php | 41 +
.../layouts/modules/show/buttons.blade.php | 184 +
.../layouts/modules/show/changelog.blade.php | 5 +
.../modules/show/description.blade.php | 7 +
.../modules/show/documentation.blade.php | 7 +
.../layouts/modules/show/features.blade.php | 29 +
.../modules/show/information.blade.php | 44 +
.../modules/show/installation.blade.php | 5 +
.../layouts/modules/show/price.blade.php | 69 +
.../layouts/modules/show/releases.blade.php | 35 +
.../layouts/modules/show/reviews.blade.php | 35 +
.../modules/show/screenshots.blade.php | 5 +
.../layouts/modules/show/toggle.blade.php | 31 +
.../views/components/layouts/portal.blade.php | 89 +
.../layouts/portal/content.blade.php | 15 +
.../layouts/portal/finish/buttons.blade.php | 19 +
.../layouts/portal/finish/content.blade.php | 10 +
.../layouts/portal/footer.blade.php | 15 +
.../components/layouts/portal/head.blade.php | 65 +
.../layouts/portal/header.blade.php | 39 +
.../components/layouts/portal/menu.blade.php | 191 +
.../layouts/portal/scripts.blade.php | 271 +
.../components/layouts/preview.blade.php | 98 +
.../layouts/preview/content.blade.php | 15 +
.../layouts/preview/footer.blade.php | 18 +
.../components/layouts/preview/head.blade.php | 65 +
.../layouts/preview/header.blade.php | 39 +
.../layouts/preview/scripts.blade.php | 13 +
.../views/components/layouts/print.blade.php | 20 +
.../layouts/print/content.blade.php | 3 +
.../components/layouts/print/head.blade.php | 71 +
.../layouts/print/scripts.blade.php | 27 +
.../components/layouts/pwa/head.blade.php | 36 +
.../views/components/layouts/signed.blade.php | 78 +
.../layouts/signed/content.blade.php | 15 +
.../layouts/signed/footer.blade.php | 18 +
.../components/layouts/signed/head.blade.php | 65 +
.../layouts/signed/header.blade.php | 39 +
.../layouts/signed/scripts.blade.php | 13 +
.../views/components/layouts/wizard.blade.php | 24 +
.../layouts/wizard/background.blade.php | 2 +
.../layouts/wizard/content.blade.php | 11 +
.../components/layouts/wizard/head.blade.php | 60 +
.../layouts/wizard/scripts.blade.php | 29 +
.../views/components/link/hover.blade.php | 9 +
.../views/components/link/index.blade.php | 3 +
.../views/components/link/loading.blade.php | 11 +
.../components/loading/absolute.blade.php | 18 +
.../components/loading/content.blade.php | 18 +
.../views/components/loading/menu.blade.php | 89 +
.../views/components/media/file.blade.php | 43 +
.../views/components/menu/favorite.blade.php | 6 +
.../components/modules/banners.blade.php | 33 +
.../views/components/modules/free.blade.php | 7 +
.../components/modules/installed.blade.php | 6 +
.../views/components/modules/item.blade.php | 101 +
.../views/components/modules/items.blade.php | 52 +
.../views/components/modules/nnew.blade.php | 7 +
.../components/modules/no_apps.blade.php | 44 +
.../views/components/modules/paid.blade.php | 7 +
.../components/modules/pre_sale.blade.php | 7 +
.../components/modules/purchased.blade.php | 6 +
.../components/modules/raw_items.blade.php | 3 +
resources/views/components/nl2br.blade.php | 1 +
.../views/components/pagination.blade.php | 43 +
.../views/components/payment_method.blade.php | 5 +
.../payment_method/hosted.blade.php | 19 +
.../payment_method/redirect.blade.php | 17 +
.../views/components/read-only.blade.php | 3 +
.../views/components/reports/detail.blade.php | 7 +
.../reports/detail/content/footer.blade.php | 0
.../reports/detail/content/header.blade.php | 0
.../components/reports/detail/table.blade.php | 7 +
.../reports/detail/table/body.blade.php | 13 +
.../reports/detail/table/footer.blade.php | 11 +
.../reports/detail/table/header.blade.php | 14 +
.../reports/detail/table/row.blade.php | 90 +
.../views/components/reports/fields.blade.php | 103 +
.../views/components/reports/filter.blade.php | 117 +
.../views/components/reports/print.blade.php | 13 +
.../views/components/reports/show.blade.php | 77 +
.../components/reports/summary.blade.php | 17 +
.../reports/summary/chart.blade.php | 43 +
.../reports/summary/content/footer.blade.php | 0
.../reports/summary/content/header.blade.php | 0
.../reports/summary/table.blade.php | 7 +
.../reports/summary/table/body.blade.php | 29 +
.../reports/summary/table/footer.blade.php | 0
.../reports/summary/table/header.blade.php | 0
.../reports/summary/table/row.blade.php | 110 +
resources/views/components/script.blade.php | 3 +
.../components/script/declaration.blade.php | 5 +
.../script/exceptions/trackers.blade.php | 16 +
.../views/components/search-string.blade.php | 29 +
.../components/show/accordion/head.blade.php | 13 +
.../components/show/accordion/index.blade.php | 26 +
.../views/components/show/container.blade.php | 9 +
.../components/show/content/index.blade.php | 3 +
.../components/show/content/left.blade.php | 3 +
.../components/show/content/right.blade.php | 7 +
.../components/show/no-records.blade.php | 31 +
.../views/components/show/status.blade.php | 8 +
.../components/show/summary/index.blade.php | 3 +
.../components/show/summary/left.blade.php | 11 +
.../components/show/summary/right.blade.php | 243 +
.../views/components/suggestions.blade.php | 11 +
.../components/table/actions-mobile.blade.php | 153 +
.../views/components/table/actions.blade.php | 142 +
.../views/components/table/index.blade.php | 7 +
.../views/components/table/tbody.blade.php | 3 +
resources/views/components/table/td.blade.php | 44 +
resources/views/components/table/th.blade.php | 43 +
.../views/components/table/thead.blade.php | 3 +
resources/views/components/table/tr.blade.php | 3 +
.../views/components/tabs/index.blade.php | 26 +
.../views/components/tabs/nav-link.blade.php | 19 +
.../views/components/tabs/nav-pin.blade.php | 21 +
resources/views/components/tabs/nav.blade.php | 18 +
resources/views/components/tabs/tab.blade.php | 10 +
.../views/components/tips/fixed.blade.php | 38 +
.../views/components/tips/relative.blade.php | 37 +
resources/views/components/title.blade.php | 11 +
resources/views/components/tooltip.blade.php | 38 +
.../transactions/index/bulk-action.blade.php | 47 +
.../transactions/index/buttons.blade.php | 27 +
.../transactions/index/content.blade.php | 190 +
.../transactions/index/more-buttons.blade.php | 27 +
.../index/recurring_templates.blade.php | 225 +
.../transactions/index/transaction.blade.php | 213 +
.../components/transactions/script.blade.php | 1 +
.../transactions/show/attachment.blade.php | 16 +
.../transactions/show/buttons.blade.php | 23 +
.../transactions/show/children.blade.php | 22 +
.../transactions/show/connect.blade.php | 22 +
.../transactions/show/content.blade.php | 162 +
.../transactions/show/create.blade.php | 27 +
.../transactions/show/more-buttons.blade.php | 147 +
.../transactions/show/schedule.blade.php | 33 +
.../transactions/show/template.blade.php | 75 +
.../transactions/show/transfer.blade.php | 41 +
.../transactions/template/default.blade.php | 417 +
.../components/transfers/script.blade.php | 1 +
.../transfers/show/attachment.blade.php | 16 +
.../transfers/show/buttons.blade.php | 9 +
.../transfers/show/content.blade.php | 17 +
.../transfers/show/create.blade.php | 18 +
.../transfers/show/more-buttons.blade.php | 67 +
.../transfers/show/template.blade.php | 10 +
.../transfers/show/transactions.blade.php | 24 +
.../transfers/template/default.blade.php | 273 +
.../transfers/template/second.blade.php | 268 +
.../transfers/template/third.blade.php | 282 +
.../views/components/update-alert.blade.php | 5 +
.../components/widgets/contact.blade.php | 51 +
.../views/components/widgets/header.blade.php | 64 +
.../widgets/invoice_history.blade.php | 23 +
.../components/widgets/last_payment.blade.php | 19 +
.../widgets/latest_invoices.blade.php | 23 +
.../widgets/outstanding_balance.blade.php | 25 +
.../widgets/payment_history.blade.php | 34 +
resources/views/errors/403.blade.php | 36 +
resources/views/errors/404.blade.php | 36 +
resources/views/errors/500.blade.php | 36 +
.../views/install/database/create.blade.php | 17 +
.../views/install/language/create.blade.php | 15 +
.../views/install/requirements/show.blade.php | 13 +
.../views/install/settings/create.blade.php | 17 +
.../views/install/updates/edit.blade.php | 35 +
.../views/install/updates/index.blade.php | 142 +
.../views/livewire/common/search.blade.php | 46 +
.../views/livewire/menu/favorite.blade.php | 13 +
.../views/livewire/menu/favorites.blade.php | 20 +
resources/views/livewire/menu/neww.blade.php | 25 +
.../livewire/menu/notifications.blade.php | 83 +
.../views/livewire/menu/profile.blade.php | 9 +
.../views/livewire/menu/settings.blade.php | 31 +
.../notification/browser/firefox.blade.php | 55 +
.../notification/browser/index.blade.php | 2 +
resources/views/livewire/report/pin.blade.php | 26 +
.../views/livewire/report/pins.blade.php | 32 +
resources/views/livewire/tab/pin.blade.php | 35 +
.../views/modals/accounts/create.blade.php | 32 +
.../views/modals/categories/create.blade.php | 26 +
.../views/modals/companies/edit.blade.php | 17 +
.../views/modals/currencies/create.blade.php | 13 +
.../views/modals/customers/create.blade.php | 71 +
.../views/modals/customers/edit.blade.php | 71 +
.../modals/documents/item_columns.blade.php | 43 +
.../views/modals/documents/payment.blade.php | 143 +
.../views/modals/invoices/email.blade.php | 128 +
.../views/modals/invoices/share.blade.php | 35 +
resources/views/modals/items/create.blade.php | 17 +
.../settings/transfer_template.blade.php | 42 +
resources/views/modals/taxes/create.blade.php | 11 +
.../modals/transactions/connect.blade.php | 27 +
.../views/modals/transactions/email.blade.php | 128 +
.../views/modals/transactions/share.blade.php | 36 +
.../views/modals/vendors/create.blade.php | 70 +
resources/views/modals/vendors/edit.blade.php | 70 +
.../views/modules/api_key/create.blade.php | 21 +
resources/views/modules/home/index.blade.php | 29 +
.../modules/item/documentation.blade.php | 35 +
.../views/modules/item/pre_sale.blade.php | 174 +
resources/views/modules/item/show.blade.php | 276 +
resources/views/modules/my/index.blade.php | 35 +
resources/views/modules/tiles/index.blade.php | 21 +
.../views/portal/dashboard/index.blade.php | 33 +
.../views/portal/invoices/finish.blade.php | 31 +
.../views/portal/invoices/index.blade.php | 174 +
.../views/portal/invoices/preview.blade.php | 153 +
.../views/portal/invoices/show.blade.php | 145 +
.../views/portal/invoices/signed.blade.php | 161 +
.../views/portal/payments/index.blade.php | 82 +
.../views/portal/payments/preview.blade.php | 71 +
.../views/portal/payments/show.blade.php | 68 +
.../views/portal/payments/signed.blade.php | 79 +
resources/views/portal/profile/edit.blade.php | 75 +
.../views/purchases/bills/create.blade.php | 25 +
.../views/purchases/bills/edit.blade.php | 19 +
.../views/purchases/bills/index.blade.php | 25 +
.../views/purchases/bills/print.blade.php | 14 +
.../views/purchases/bills/show.blade.php | 45 +
.../recurring_bills/create.blade.php | 25 +
.../purchases/recurring_bills/edit.blade.php | 20 +
.../purchases/recurring_bills/index.blade.php | 31 +
.../purchases/recurring_bills/show.blade.php | 40 +
.../views/purchases/vendors/create.blade.php | 17 +
.../views/purchases/vendors/edit.blade.php | 11 +
.../views/purchases/vendors/index.blade.php | 23 +
.../views/purchases/vendors/show.blade.php | 31 +
.../profit_loss/content/footer.blade.php | 30 +
.../profit_loss/content/header.blade.php | 19 +
.../reports/profit_loss/detail.blade.php | 38 +
.../profit_loss/table/footer.blade.php | 26 +
.../profit_loss/table/header.blade.php | 7 +
.../reports/profit_loss/table/row.blade.php | 120 +
.../tax_summary/content/footer.blade.php | 0
.../tax_summary/content/header.blade.php | 19 +
.../tax_summary/table/footer.blade.php | 19 +
.../tax_summary/table/header.blade.php | 7 +
.../views/sales/customers/create.blade.php | 17 +
.../views/sales/customers/edit.blade.php | 11 +
.../views/sales/customers/index.blade.php | 23 +
.../views/sales/customers/show.blade.php | 31 +
.../views/sales/invoices/create.blade.php | 17 +
resources/views/sales/invoices/edit.blade.php | 11 +
.../views/sales/invoices/index.blade.php | 25 +
.../sales/invoices/print_classic.blade.php | 12 +
.../sales/invoices/print_default.blade.php | 12 +
.../sales/invoices/print_modern.blade.php | 12 +
resources/views/sales/invoices/show.blade.php | 27 +
.../sales/recurring_invoices/create.blade.php | 17 +
.../sales/recurring_invoices/edit.blade.php | 11 +
.../sales/recurring_invoices/index.blade.php | 31 +
.../sales/recurring_invoices/show.blade.php | 40 +
.../settings/categories/create.blade.php | 52 +
.../views/settings/categories/edit.blade.php | 60 +
.../views/settings/categories/index.blade.php | 165 +
.../categories/sub_category.blade.php | 126 +
.../views/settings/company/edit.blade.php | 61 +
.../settings/currencies/create.blade.php | 51 +
.../views/settings/currencies/edit.blade.php | 49 +
.../views/settings/currencies/index.blade.php | 100 +
.../views/settings/default/edit.blade.php | 82 +
.../settings/email-templates/edit.blade.php | 92 +
resources/views/settings/email/edit.blade.php | 43 +
.../views/settings/invoice/edit.blade.php | 162 +
.../settings/localisation/edit.blade.php | 59 +
.../views/settings/modules/edit.blade.php | 138 +
.../views/settings/navigation/edit.blade.php | 61 +
.../views/settings/schedule/edit.blade.php | 62 +
.../views/settings/taxes/create.blade.php | 39 +
resources/views/settings/taxes/edit.blade.php | 37 +
.../views/settings/taxes/index.blade.php | 110 +
.../system_settings/databases/form.blade.php | 72 +
.../system_settings/databases/index.blade.php | 85 +
.../partials/navigation.blade.php | 20 +
.../system_settings/sidebar/edit.blade.php | 107 +
.../system_settings/users/form.blade.php | 60 +
.../system_settings/users/index.blade.php | 82 +
.../views/widgets/account_balance.blade.php | 15 +
resources/views/widgets/bank_feeds.blade.php | 23 +
resources/views/widgets/bar_chart.blade.php | 13 +
resources/views/widgets/cash_flow.blade.php | 53 +
resources/views/widgets/currencies.blade.php | 15 +
resources/views/widgets/donut_chart.blade.php | 13 +
resources/views/widgets/line_chart.blade.php | 13 +
.../widgets/receivables_payables.blade.php | 57 +
.../views/wizard/companies/edit.blade.php | 7 +
.../views/wizard/currencies/index.blade.php | 7 +
resources/views/wizard/finish/index.blade.php | 7 +
routes/admin.php | 316 +
routes/api.php | 84 +
routes/channels.php | 18 +
routes/common.php | 34 +
routes/console.php | 19 +
routes/guest.php | 29 +
routes/install.php | 22 +
routes/portal.php | 27 +
routes/preview.php | 23 +
routes/signed.php | 21 +
routes/web.php | 16 +
routes/wizard.php | 21 +
safelist.txt | 116 +
serviceworker.js | 45 +
storage/app/.gitignore | 5 +
storage/app/public/.gitignore | 2 +
storage/app/temp/.gitignore | 2 +
storage/app/uploads/.gitignore | 2 +
storage/debugbar/.gitignore | 2 +
storage/fonts/.gitignore | 2 +
storage/framework/.gitignore | 8 +
storage/framework/testing/.gitignore | 2 +
tailwind.config.js | 23 +
tests/CreatesApplication.php | 22 +
tests/Feature/Auth/UsersTest.php | 244 +
tests/Feature/Banking/AccountsTest.php | 142 +
.../Banking/DocumentTransactionsTest.php | 168 +
tests/Feature/Banking/ReconciliationsTest.php | 82 +
.../Feature/Banking/SplitTransactionTest.php | 122 +
.../Feature/Banking/TransactionTaxesTest.php | 97 +
tests/Feature/Banking/TransactionsTest.php | 295 +
tests/Feature/Banking/TransfersTest.php | 175 +
tests/Feature/Commands/BillReminderTest.php | 48 +
.../Feature/Commands/InvoiceReminderTest.php | 48 +
tests/Feature/Commands/RecurringCheckTest.php | 160 +
tests/Feature/Common/CompaniesTest.php | 126 +
tests/Feature/Common/DashboardsTest.php | 171 +
tests/Feature/Common/ItemsTest.php | 163 +
tests/Feature/Common/ReportsTest.php | 65 +
tests/Feature/Common/SourcesTest.php | 46 +
tests/Feature/Document/CancelDocumentTest.php | 88 +
tests/Feature/Email/TooManyEmailsSentTest.php | 51 +
tests/Feature/FeatureTestCase.php | 63 +
tests/Feature/PaymentTestCase.php | 159 +
.../Performance/N1QueryOptimizationTest.php | 178 +
.../Feature/Performance/VendorN1QueryTest.php | 255 +
tests/Feature/Purchases/BillsTest.php | 310 +
tests/Feature/Purchases/VendorsTest.php | 188 +
tests/Feature/Sales/CustomersTest.php | 220 +
tests/Feature/Sales/InvoicesTest.php | 370 +
tests/Feature/Settings/CategoriesTest.php | 93 +
tests/Feature/Settings/CurrenciesTest.php | 95 +
tests/Feature/Settings/NavigationTest.php | 34 +
tests/Feature/Settings/TaxesTest.php | 89 +
tests/Feature/Wizard/CompaniesTest.php | 42 +
tests/Feature/Wizard/CurrenciesTest.php | 86 +
tests/TestCase.php | 19 +
tests/Unit/ExampleTest.php | 18 +
.../Imports/Banking/TransfersImportTest.php | 26 +
tests/Unit/UpdatesTest.php | 53 +
.../Utilities/CalculationToQuantityTest.php | 21 +
.../Unit/Utilities/DateImportParsingTest.php | 25 +
web.config | 23 +
webpack.mix.js | 82 +
4202 files changed, 395334 insertions(+)
create mode 100644 .dockerignore
create mode 100644 .editorconfig
create mode 100644 .gitattributes
create mode 100644 .github/FUNDING.yml
create mode 100644 .github/ISSUE_TEMPLATE.md
create mode 100644 .github/ISSUE_TEMPLATE/bug.yml
create mode 100644 .github/ISSUE_TEMPLATE/config.yml
create mode 100644 .github/workflows/tests.yml
create mode 100644 .gitignore
create mode 100644 .htaccess
create mode 100644 AGENTS.md
create mode 100644 LICENSE.txt
create mode 100644 LocalValetDriver.php
create mode 100644 README.md
create mode 100644 SECURITY.md
create mode 100644 app/Abstracts/BulkAction.php
create mode 100644 app/Abstracts/Commands/Module.php
create mode 100644 app/Abstracts/Event.php
create mode 100644 app/Abstracts/Export.php
create mode 100644 app/Abstracts/Factory.php
create mode 100644 app/Abstracts/Http/ApiController.php
create mode 100644 app/Abstracts/Http/Controller.php
create mode 100644 app/Abstracts/Http/FormRequest.php
create mode 100644 app/Abstracts/Http/PaymentController.php
create mode 100644 app/Abstracts/Http/Response.php
create mode 100644 app/Abstracts/Http/SettingController.php
create mode 100644 app/Abstracts/Import.php
create mode 100644 app/Abstracts/ImportMultipleSheets.php
create mode 100644 app/Abstracts/Job.php
create mode 100644 app/Abstracts/JobShouldQueue.php
create mode 100644 app/Abstracts/Listeners/Report.php
create mode 100644 app/Abstracts/Listeners/Update.php
create mode 100644 app/Abstracts/Model.php
create mode 100644 app/Abstracts/Notification.php
create mode 100644 app/Abstracts/Observer.php
create mode 100644 app/Abstracts/Report.php
create mode 100644 app/Abstracts/View/Component.php
create mode 100644 app/Abstracts/View/Components/Contacts/Form.php
create mode 100644 app/Abstracts/View/Components/Contacts/Index.php
create mode 100644 app/Abstracts/View/Components/Contacts/Show.php
create mode 100644 app/Abstracts/View/Components/Documents/Form.php
create mode 100644 app/Abstracts/View/Components/Documents/Index.php
create mode 100644 app/Abstracts/View/Components/Documents/Show.php
create mode 100644 app/Abstracts/View/Components/Documents/Template.php
create mode 100644 app/Abstracts/View/Components/Form.php
create mode 100644 app/Abstracts/View/Components/Transactions/Index.php
create mode 100644 app/Abstracts/View/Components/Transactions/Show.php
create mode 100644 app/Abstracts/View/Components/Transactions/Template.php
create mode 100644 app/Abstracts/View/Components/Transfers/Show.php
create mode 100644 app/Abstracts/View/Components/Transfers/Template.php
create mode 100644 app/Abstracts/Widget.php
create mode 100644 app/Builders/Category.php
create mode 100644 app/BulkActions/Auth/Users.php
create mode 100644 app/BulkActions/Banking/Accounts.php
create mode 100644 app/BulkActions/Banking/Reconciliations.php
create mode 100644 app/BulkActions/Banking/Transactions.php
create mode 100644 app/BulkActions/Banking/Transfers.php
create mode 100644 app/BulkActions/Common/Companies.php
create mode 100644 app/BulkActions/Common/Dashboards.php
create mode 100644 app/BulkActions/Common/Items.php
create mode 100644 app/BulkActions/Purchases/Bills.php
create mode 100644 app/BulkActions/Purchases/Vendors.php
create mode 100644 app/BulkActions/Sales/Customers.php
create mode 100644 app/BulkActions/Sales/Invoices.php
create mode 100644 app/BulkActions/Settings/Categories.php
create mode 100644 app/BulkActions/Settings/Currencies.php
create mode 100644 app/BulkActions/Settings/Taxes.php
create mode 100644 app/Classifiers/BulkAction.php
create mode 100644 app/Classifiers/Event.php
create mode 100644 app/Classifiers/Export.php
create mode 100644 app/Classifiers/Import.php
create mode 100644 app/Classifiers/Job.php
create mode 100644 app/Classifiers/Observer.php
create mode 100644 app/Classifiers/Report.php
create mode 100644 app/Classifiers/Scope.php
create mode 100644 app/Classifiers/Widget.php
create mode 100644 app/Console/Commands/BillReminder.php
create mode 100644 app/Console/Commands/CompanySeed.php
create mode 100644 app/Console/Commands/DownloadModule.php
create mode 100644 app/Console/Commands/FinishUpdate.php
create mode 100644 app/Console/Commands/Install.php
create mode 100644 app/Console/Commands/InstallRefresh.php
create mode 100644 app/Console/Commands/InvoiceReminder.php
create mode 100644 app/Console/Commands/RecurringCheck.php
create mode 100644 app/Console/Commands/SampleData.php
create mode 100644 app/Console/Commands/StorageTempClear.php
create mode 100644 app/Console/Commands/UninstallModule.php
create mode 100644 app/Console/Commands/Update.php
create mode 100644 app/Console/Commands/UpdateAll.php
create mode 100644 app/Console/Commands/UpdateDb.php
create mode 100644 app/Console/Commands/UserSeed.php
create mode 100644 app/Console/Kernel.php
create mode 100644 app/Console/Stubs/Modules/assets/js/app.stub
create mode 100644 app/Console/Stubs/Modules/assets/sass/app.stub
create mode 100644 app/Console/Stubs/Modules/command.stub
create mode 100644 app/Console/Stubs/Modules/component.stub
create mode 100644 app/Console/Stubs/Modules/composer.stub
create mode 100644 app/Console/Stubs/Modules/controller-api.stub
create mode 100644 app/Console/Stubs/Modules/controller-plain.stub
create mode 100644 app/Console/Stubs/Modules/controller.stub
create mode 100644 app/Console/Stubs/Modules/event.stub
create mode 100644 app/Console/Stubs/Modules/factory.stub
create mode 100644 app/Console/Stubs/Modules/job-queued.stub
create mode 100644 app/Console/Stubs/Modules/job.stub
create mode 100644 app/Console/Stubs/Modules/json.stub
create mode 100644 app/Console/Stubs/Modules/lang/general.stub
create mode 100644 app/Console/Stubs/Modules/listener-duck.stub
create mode 100644 app/Console/Stubs/Modules/listener-queued-duck.stub
create mode 100644 app/Console/Stubs/Modules/listener-queued.stub
create mode 100644 app/Console/Stubs/Modules/listener.stub
create mode 100644 app/Console/Stubs/Modules/listeners/install.stub
create mode 100644 app/Console/Stubs/Modules/mail.stub
create mode 100644 app/Console/Stubs/Modules/middleware.stub
create mode 100644 app/Console/Stubs/Modules/migration/add.stub
create mode 100644 app/Console/Stubs/Modules/migration/create.stub
create mode 100644 app/Console/Stubs/Modules/migration/delete.stub
create mode 100644 app/Console/Stubs/Modules/migration/drop.stub
create mode 100644 app/Console/Stubs/Modules/migration/plain.stub
create mode 100644 app/Console/Stubs/Modules/model.stub
create mode 100644 app/Console/Stubs/Modules/notification.stub
create mode 100644 app/Console/Stubs/Modules/package.stub
create mode 100644 app/Console/Stubs/Modules/policy.plain.stub
create mode 100644 app/Console/Stubs/Modules/provider.stub
create mode 100644 app/Console/Stubs/Modules/providers/event.stub
create mode 100644 app/Console/Stubs/Modules/request.stub
create mode 100644 app/Console/Stubs/Modules/resource-collection.stub
create mode 100644 app/Console/Stubs/Modules/resource.stub
create mode 100644 app/Console/Stubs/Modules/routes/admin.stub
create mode 100644 app/Console/Stubs/Modules/routes/portal.stub
create mode 100644 app/Console/Stubs/Modules/rule.stub
create mode 100644 app/Console/Stubs/Modules/scaffold/config.stub
create mode 100644 app/Console/Stubs/Modules/scaffold/provider.stub
create mode 100644 app/Console/Stubs/Modules/seeder.stub
create mode 100644 app/Console/Stubs/Modules/unit-test.stub
create mode 100644 app/Console/Stubs/Modules/views/index.stub
create mode 100644 app/Console/Stubs/Modules/webpack.stub
create mode 100644 app/Events/Auth/Attempting.php
create mode 100644 app/Events/Auth/Authenticated.php
create mode 100644 app/Events/Auth/Failed.php
create mode 100644 app/Events/Auth/LandingPageShowing.php
create mode 100644 app/Events/Auth/RoleCreated.php
create mode 100644 app/Events/Auth/RoleCreating.php
create mode 100644 app/Events/Auth/RoleDeleted.php
create mode 100644 app/Events/Auth/RoleDeleting.php
create mode 100644 app/Events/Auth/RoleUpdated.php
create mode 100644 app/Events/Auth/RoleUpdating.php
create mode 100644 app/Events/Auth/UserCreated.php
create mode 100644 app/Events/Auth/UserCreating.php
create mode 100644 app/Events/Auth/UserDeleted.php
create mode 100644 app/Events/Auth/UserDeleting.php
create mode 100644 app/Events/Auth/UserUpdated.php
create mode 100644 app/Events/Auth/UserUpdating.php
create mode 100644 app/Events/Banking/AccountCreated.php
create mode 100644 app/Events/Banking/AccountCreating.php
create mode 100644 app/Events/Banking/AccountDeleted.php
create mode 100644 app/Events/Banking/AccountDeleting.php
create mode 100644 app/Events/Banking/AccountUpdated.php
create mode 100644 app/Events/Banking/AccountUpdating.php
create mode 100644 app/Events/Banking/DocumentTransactionCreated.php
create mode 100644 app/Events/Banking/DocumentTransactionCreating.php
create mode 100644 app/Events/Banking/DocumentTransactionUpdated.php
create mode 100644 app/Events/Banking/DocumentTransactionUpdating.php
create mode 100644 app/Events/Banking/TransactionCreated.php
create mode 100644 app/Events/Banking/TransactionCreating.php
create mode 100644 app/Events/Banking/TransactionDeleted.php
create mode 100644 app/Events/Banking/TransactionDeleting.php
create mode 100644 app/Events/Banking/TransactionPrinting.php
create mode 100644 app/Events/Banking/TransactionRecurring.php
create mode 100644 app/Events/Banking/TransactionSending.php
create mode 100644 app/Events/Banking/TransactionSent.php
create mode 100644 app/Events/Banking/TransactionSplitted.php
create mode 100644 app/Events/Banking/TransactionSplitting.php
create mode 100644 app/Events/Banking/TransactionUpdated.php
create mode 100644 app/Events/Banking/TransactionUpdating.php
create mode 100644 app/Events/Banking/TransferCreated.php
create mode 100644 app/Events/Banking/TransferCreating.php
create mode 100644 app/Events/Banking/TransferDeleted.php
create mode 100644 app/Events/Banking/TransferDeleting.php
create mode 100644 app/Events/Banking/TransferPrinting.php
create mode 100644 app/Events/Banking/TransferUpdated.php
create mode 100644 app/Events/Banking/TransferUpdating.php
create mode 100644 app/Events/Common/BulkActionsAdding.php
create mode 100644 app/Events/Common/CompanyCreated.php
create mode 100644 app/Events/Common/CompanyCreating.php
create mode 100644 app/Events/Common/CompanyDeleted.php
create mode 100644 app/Events/Common/CompanyDeleting.php
create mode 100644 app/Events/Common/CompanyForgettingCurrent.php
create mode 100644 app/Events/Common/CompanyForgotCurrent.php
create mode 100644 app/Events/Common/CompanyMadeCurrent.php
create mode 100644 app/Events/Common/CompanyMakingCurrent.php
create mode 100644 app/Events/Common/CompanySwitched.php
create mode 100644 app/Events/Common/CompanyUpdated.php
create mode 100644 app/Events/Common/CompanyUpdating.php
create mode 100644 app/Events/Common/ContactCreated.php
create mode 100644 app/Events/Common/ContactCreating.php
create mode 100644 app/Events/Common/ContactDeleted.php
create mode 100644 app/Events/Common/ContactDeleting.php
create mode 100644 app/Events/Common/ContactUpdated.php
create mode 100644 app/Events/Common/ContactUpdating.php
create mode 100644 app/Events/Common/DatesFormating.php
create mode 100644 app/Events/Common/GlobalSearched.php
create mode 100644 app/Events/Common/ImportViewCreated.php
create mode 100644 app/Events/Common/ImportViewCreating.php
create mode 100644 app/Events/Common/ItemCreated.php
create mode 100644 app/Events/Common/ItemCreating.php
create mode 100644 app/Events/Common/ItemDeleted.php
create mode 100644 app/Events/Common/ItemDeleting.php
create mode 100644 app/Events/Common/ItemUpdated.php
create mode 100644 app/Events/Common/ItemUpdating.php
create mode 100644 app/Events/Common/RelationshipCounting.php
create mode 100644 app/Events/Common/RelationshipDeleting.php
create mode 100644 app/Events/Common/SearchStringApplied.php
create mode 100644 app/Events/Common/SearchStringApplying.php
create mode 100644 app/Events/Document/DocumentCancelled.php
create mode 100644 app/Events/Document/DocumentCreated.php
create mode 100644 app/Events/Document/DocumentCreating.php
create mode 100644 app/Events/Document/DocumentDeleted.php
create mode 100644 app/Events/Document/DocumentDeleting.php
create mode 100644 app/Events/Document/DocumentDuplicating.php
create mode 100644 app/Events/Document/DocumentMarkedSent.php
create mode 100644 app/Events/Document/DocumentPrinting.php
create mode 100644 app/Events/Document/DocumentReceived.php
create mode 100644 app/Events/Document/DocumentRecurring.php
create mode 100644 app/Events/Document/DocumentReminded.php
create mode 100644 app/Events/Document/DocumentResourceShowing.php
create mode 100644 app/Events/Document/DocumentRestored.php
create mode 100644 app/Events/Document/DocumentSending.php
create mode 100644 app/Events/Document/DocumentSent.php
create mode 100644 app/Events/Document/DocumentTemplates.php
create mode 100644 app/Events/Document/DocumentUpdated.php
create mode 100644 app/Events/Document/DocumentUpdating.php
create mode 100644 app/Events/Document/DocumentViewed.php
create mode 100644 app/Events/Document/PaidAmountCalculated.php
create mode 100644 app/Events/Document/PaymentReceived.php
create mode 100644 app/Events/Document/TransactionsCounted.php
create mode 100644 app/Events/Email/InvalidEmailDetected.php
create mode 100644 app/Events/Email/TooManyEmailsSent.php
create mode 100644 app/Events/Export/HeadingsPreparing.php
create mode 100644 app/Events/Export/RowsPreparing.php
create mode 100644 app/Events/Import/RowPreparing.php
create mode 100644 app/Events/Install/UpdateCacheCleared.php
create mode 100644 app/Events/Install/UpdateCopied.php
create mode 100644 app/Events/Install/UpdateDownloaded.php
create mode 100644 app/Events/Install/UpdateFailed.php
create mode 100644 app/Events/Install/UpdateFinished.php
create mode 100644 app/Events/Install/UpdateUnzipped.php
create mode 100644 app/Events/Menu/AdminCreated.php
create mode 100644 app/Events/Menu/AdminCreating.php
create mode 100644 app/Events/Menu/ItemAuthorizing.php
create mode 100644 app/Events/Menu/NewwCreated.php
create mode 100644 app/Events/Menu/NewwCreating.php
create mode 100644 app/Events/Menu/NotificationsCreated.php
create mode 100644 app/Events/Menu/NotificationsCreating.php
create mode 100644 app/Events/Menu/PortalCreated.php
create mode 100644 app/Events/Menu/PortalCreating.php
create mode 100644 app/Events/Menu/ProfileCreated.php
create mode 100644 app/Events/Menu/ProfileCreating.php
create mode 100644 app/Events/Menu/SettingsCreated.php
create mode 100644 app/Events/Menu/SettingsCreating.php
create mode 100644 app/Events/Menu/SettingsFinished.php
create mode 100644 app/Events/Module/Copied.php
create mode 100644 app/Events/Module/Disabled.php
create mode 100644 app/Events/Module/Disabling.php
create mode 100644 app/Events/Module/Enabled.php
create mode 100644 app/Events/Module/Installed.php
create mode 100644 app/Events/Module/Installing.php
create mode 100644 app/Events/Module/PaymentMethodShowing.php
create mode 100644 app/Events/Module/Uninstalled.php
create mode 100644 app/Events/Module/Uninstalling.php
create mode 100644 app/Events/Report/ClassesCreated.php
create mode 100644 app/Events/Report/DataLoaded.php
create mode 100644 app/Events/Report/DataLoading.php
create mode 100644 app/Events/Report/FilterApplying.php
create mode 100644 app/Events/Report/FilterShowing.php
create mode 100644 app/Events/Report/GroupApplying.php
create mode 100644 app/Events/Report/GroupShowing.php
create mode 100644 app/Events/Report/RowsShowing.php
create mode 100644 app/Events/Report/SkipClass.php
create mode 100644 app/Events/Report/SkipRowsShowing.php
create mode 100644 app/Events/Report/TotalCalculated.php
create mode 100644 app/Events/Report/TotalCalculating.php
create mode 100644 app/Events/Setting/CategoryCreated.php
create mode 100644 app/Events/Setting/CategoryCreating.php
create mode 100644 app/Events/Setting/CategoryDeleted.php
create mode 100644 app/Events/Setting/CategoryDeleting.php
create mode 100644 app/Events/Setting/CategoryUpdated.php
create mode 100644 app/Events/Setting/CategoryUpdating.php
create mode 100644 app/Events/Setting/CurrencyCreated.php
create mode 100644 app/Events/Setting/CurrencyCreating.php
create mode 100644 app/Events/Setting/CurrencyDeleted.php
create mode 100644 app/Events/Setting/CurrencyDeleting.php
create mode 100644 app/Events/Setting/CurrencyUpdated.php
create mode 100644 app/Events/Setting/CurrencyUpdating.php
create mode 100644 app/Events/Setting/SettingUpdated.php
create mode 100644 app/Events/Setting/SettingUpdating.php
create mode 100644 app/Events/Setting/TaxCreated.php
create mode 100644 app/Events/Setting/TaxCreating.php
create mode 100644 app/Events/Setting/TaxDeleted.php
create mode 100644 app/Events/Setting/TaxDeleting.php
create mode 100644 app/Events/Setting/TaxUpdated.php
create mode 100644 app/Events/Setting/TaxUpdating.php
create mode 100644 app/Events/Widget/ClassesCreated.php
create mode 100644 app/Exceptions/Common/LastDashboard.php
create mode 100644 app/Exceptions/Common/NotUserDashboard.php
create mode 100644 app/Exceptions/Common/TooManyEmailsSent.php
create mode 100644 app/Exceptions/Handler.php
create mode 100644 app/Exceptions/Http/Resource.php
create mode 100644 app/Exceptions/Settings/LastCategoryDelete.php
create mode 100644 app/Exceptions/Trackers/Bugsnag.php
create mode 100644 app/Exceptions/Trackers/Sentry.php
create mode 100644 app/Exports/Banking/RecurringTransactions.php
create mode 100644 app/Exports/Banking/Sheets/Recurring.php
create mode 100644 app/Exports/Banking/Sheets/RecurringTransactions.php
create mode 100644 app/Exports/Banking/Transactions.php
create mode 100644 app/Exports/Banking/Transfers.php
create mode 100644 app/Exports/Common/Items.php
create mode 100644 app/Exports/Common/Reports.php
create mode 100644 app/Exports/Common/Sheets/ItemTaxes.php
create mode 100644 app/Exports/Common/Sheets/Items.php
create mode 100644 app/Exports/Purchases/Bills/Bills.php
create mode 100644 app/Exports/Purchases/Bills/Sheets/BillHistories.php
create mode 100644 app/Exports/Purchases/Bills/Sheets/BillItemTaxes.php
create mode 100644 app/Exports/Purchases/Bills/Sheets/BillItems.php
create mode 100644 app/Exports/Purchases/Bills/Sheets/BillTotals.php
create mode 100644 app/Exports/Purchases/Bills/Sheets/BillTransactions.php
create mode 100644 app/Exports/Purchases/Bills/Sheets/Bills.php
create mode 100644 app/Exports/Purchases/RecurringBills/RecurringBills.php
create mode 100644 app/Exports/Purchases/RecurringBills/Sheets/Recurring.php
create mode 100644 app/Exports/Purchases/RecurringBills/Sheets/RecurringBillHistories.php
create mode 100644 app/Exports/Purchases/RecurringBills/Sheets/RecurringBillItemTaxes.php
create mode 100644 app/Exports/Purchases/RecurringBills/Sheets/RecurringBillItems.php
create mode 100644 app/Exports/Purchases/RecurringBills/Sheets/RecurringBillTotals.php
create mode 100644 app/Exports/Purchases/RecurringBills/Sheets/RecurringBills.php
create mode 100644 app/Exports/Purchases/Vendors.php
create mode 100644 app/Exports/Sales/Customers.php
create mode 100644 app/Exports/Sales/Invoices/Invoices.php
create mode 100644 app/Exports/Sales/Invoices/Sheets/InvoiceHistories.php
create mode 100644 app/Exports/Sales/Invoices/Sheets/InvoiceItemTaxes.php
create mode 100644 app/Exports/Sales/Invoices/Sheets/InvoiceItems.php
create mode 100644 app/Exports/Sales/Invoices/Sheets/InvoiceTotals.php
create mode 100644 app/Exports/Sales/Invoices/Sheets/InvoiceTransactions.php
create mode 100644 app/Exports/Sales/Invoices/Sheets/Invoices.php
create mode 100644 app/Exports/Sales/RecurringInvoices/RecurringInvoices.php
create mode 100644 app/Exports/Sales/RecurringInvoices/Sheets/Recurring.php
create mode 100644 app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceHistories.php
create mode 100644 app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItemTaxes.php
create mode 100644 app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItems.php
create mode 100644 app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceTotals.php
create mode 100644 app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoices.php
create mode 100644 app/Exports/Settings/Categories.php
create mode 100644 app/Exports/Settings/Taxes.php
create mode 100644 app/Http/Controllers/Api/Auth/Users.php
create mode 100644 app/Http/Controllers/Api/Banking/Accounts.php
create mode 100644 app/Http/Controllers/Api/Banking/Reconciliations.php
create mode 100644 app/Http/Controllers/Api/Banking/Transactions.php
create mode 100644 app/Http/Controllers/Api/Banking/Transfers.php
create mode 100644 app/Http/Controllers/Api/Common/Companies.php
create mode 100644 app/Http/Controllers/Api/Common/Contacts.php
create mode 100644 app/Http/Controllers/Api/Common/Dashboards.php
create mode 100644 app/Http/Controllers/Api/Common/Items.php
create mode 100644 app/Http/Controllers/Api/Common/Ping.php
create mode 100644 app/Http/Controllers/Api/Common/Reports.php
create mode 100644 app/Http/Controllers/Api/Common/Translations.php
create mode 100644 app/Http/Controllers/Api/Document/DocumentTransactions.php
create mode 100644 app/Http/Controllers/Api/Document/Documents.php
create mode 100644 app/Http/Controllers/Api/Settings/Categories.php
create mode 100644 app/Http/Controllers/Api/Settings/Currencies.php
create mode 100644 app/Http/Controllers/Api/Settings/Settings.php
create mode 100644 app/Http/Controllers/Api/Settings/Taxes.php
create mode 100644 app/Http/Controllers/Auth/Forgot.php
create mode 100644 app/Http/Controllers/Auth/Login.php
create mode 100644 app/Http/Controllers/Auth/Register.php
create mode 100644 app/Http/Controllers/Auth/Reset.php
create mode 100644 app/Http/Controllers/Auth/Users.php
create mode 100644 app/Http/Controllers/Banking/Accounts.php
create mode 100644 app/Http/Controllers/Banking/FundAccounts.php
create mode 100644 app/Http/Controllers/Banking/Reconciliations.php
create mode 100644 app/Http/Controllers/Banking/RecurringTransactions.php
create mode 100644 app/Http/Controllers/Banking/Transactions.php
create mode 100644 app/Http/Controllers/Banking/Transfers.php
create mode 100644 app/Http/Controllers/Business/Pages.php
create mode 100644 app/Http/Controllers/Common/BulkActions.php
create mode 100644 app/Http/Controllers/Common/Companies.php
create mode 100644 app/Http/Controllers/Common/Contacts.php
create mode 100644 app/Http/Controllers/Common/Dashboards.php
create mode 100644 app/Http/Controllers/Common/Import.php
create mode 100644 app/Http/Controllers/Common/Items.php
create mode 100644 app/Http/Controllers/Common/Plans.php
create mode 100644 app/Http/Controllers/Common/Reports.php
create mode 100644 app/Http/Controllers/Common/Uploads.php
create mode 100644 app/Http/Controllers/Common/Widgets.php
create mode 100644 app/Http/Controllers/Install/Database.php
create mode 100644 app/Http/Controllers/Install/Language.php
create mode 100644 app/Http/Controllers/Install/Requirements.php
create mode 100644 app/Http/Controllers/Install/Settings.php
create mode 100644 app/Http/Controllers/Install/Updates.php
create mode 100644 app/Http/Controllers/Modals/Accounts.php
create mode 100644 app/Http/Controllers/Modals/Categories.php
create mode 100644 app/Http/Controllers/Modals/Companies.php
create mode 100644 app/Http/Controllers/Modals/Currencies.php
create mode 100644 app/Http/Controllers/Modals/Customers.php
create mode 100644 app/Http/Controllers/Modals/DocumentItemColumns.php
create mode 100644 app/Http/Controllers/Modals/DocumentTransactions.php
create mode 100644 app/Http/Controllers/Modals/InvoiceEmails.php
create mode 100644 app/Http/Controllers/Modals/InvoiceShare.php
create mode 100644 app/Http/Controllers/Modals/InvoiceTemplates.php
create mode 100644 app/Http/Controllers/Modals/Items.php
create mode 100644 app/Http/Controllers/Modals/Taxes.php
create mode 100644 app/Http/Controllers/Modals/TransactionEmails.php
create mode 100644 app/Http/Controllers/Modals/TransactionShare.php
create mode 100644 app/Http/Controllers/Modals/TransferTemplates.php
create mode 100644 app/Http/Controllers/Modals/Vendors.php
create mode 100644 app/Http/Controllers/Modules/ApiKey.php
create mode 100644 app/Http/Controllers/Modules/Home.php
create mode 100644 app/Http/Controllers/Modules/Item.php
create mode 100644 app/Http/Controllers/Modules/My.php
create mode 100644 app/Http/Controllers/Modules/Tiles.php
create mode 100644 app/Http/Controllers/Portal/Dashboard.php
create mode 100644 app/Http/Controllers/Portal/Invoices.php
create mode 100644 app/Http/Controllers/Portal/Payments.php
create mode 100644 app/Http/Controllers/Portal/Profile.php
create mode 100644 app/Http/Controllers/Purchases/Bills.php
create mode 100644 app/Http/Controllers/Purchases/RecurringBills.php
create mode 100644 app/Http/Controllers/Purchases/Vendors.php
create mode 100644 app/Http/Controllers/Sales/Customers.php
create mode 100644 app/Http/Controllers/Sales/Invoices.php
create mode 100644 app/Http/Controllers/Sales/RecurringInvoices.php
create mode 100644 app/Http/Controllers/Settings/Categories.php
create mode 100644 app/Http/Controllers/Settings/Company.php
create mode 100644 app/Http/Controllers/Settings/Currencies.php
create mode 100644 app/Http/Controllers/Settings/Defaults.php
create mode 100644 app/Http/Controllers/Settings/Email.php
create mode 100644 app/Http/Controllers/Settings/EmailTemplates.php
create mode 100644 app/Http/Controllers/Settings/Invoice.php
create mode 100644 app/Http/Controllers/Settings/Localisation.php
create mode 100644 app/Http/Controllers/Settings/Modules.php
create mode 100644 app/Http/Controllers/Settings/Navigation.php
create mode 100644 app/Http/Controllers/Settings/Schedule.php
create mode 100644 app/Http/Controllers/Settings/Taxes.php
create mode 100644 app/Http/Controllers/SystemSettings/Databases.php
create mode 100644 app/Http/Controllers/SystemSettings/Sidebar.php
create mode 100644 app/Http/Controllers/SystemSettings/Users.php
create mode 100644 app/Http/Controllers/Wizard/Companies.php
create mode 100644 app/Http/Controllers/Wizard/Currencies.php
create mode 100644 app/Http/Controllers/Wizard/Finish.php
create mode 100644 app/Http/Kernel.php
create mode 100644 app/Http/Livewire/Common/Search.php
create mode 100644 app/Http/Livewire/Menu/Favorite.php
create mode 100644 app/Http/Livewire/Menu/Favorites.php
create mode 100644 app/Http/Livewire/Menu/Neww.php
create mode 100644 app/Http/Livewire/Menu/Notifications.php
create mode 100644 app/Http/Livewire/Menu/Profile.php
create mode 100644 app/Http/Livewire/Menu/Settings.php
create mode 100644 app/Http/Livewire/Notification/Browser.php
create mode 100644 app/Http/Livewire/Report/Pin.php
create mode 100644 app/Http/Livewire/Report/Pins.php
create mode 100644 app/Http/Livewire/Tab/Pin.php
create mode 100644 app/Http/Middleware/AddWWWAuthenticateHeader.php
create mode 100644 app/Http/Middleware/AddXHeader.php
create mode 100644 app/Http/Middleware/AdminMenu.php
create mode 100644 app/Http/Middleware/Authenticate.php
create mode 100644 app/Http/Middleware/AuthenticateOnceWithBasicAuth.php
create mode 100644 app/Http/Middleware/AuthenticateOnceWithDynamicApi.php
create mode 100644 app/Http/Middleware/AuthenticateOnceWithOAuth.php
create mode 100644 app/Http/Middleware/CanInstall.php
create mode 100644 app/Http/Middleware/CheckForReadOnlyMode.php
create mode 100644 app/Http/Middleware/DateFormat.php
create mode 100644 app/Http/Middleware/DisableQuic.php
create mode 100644 app/Http/Middleware/Dropzone.php
create mode 100644 app/Http/Middleware/EncryptCookies.php
create mode 100644 app/Http/Middleware/EnforceLocalOnly.php
create mode 100644 app/Http/Middleware/IdentifyCompany.php
create mode 100644 app/Http/Middleware/LogoutIfUserDisabled.php
create mode 100644 app/Http/Middleware/Money.php
create mode 100644 app/Http/Middleware/PortalMenu.php
create mode 100644 app/Http/Middleware/RedirectIfAuthenticated.php
create mode 100644 app/Http/Middleware/RedirectIfHitModuleSubscription.php
create mode 100644 app/Http/Middleware/RedirectIfHitPlanLimits.php
create mode 100644 app/Http/Middleware/RedirectIfNoApiKey.php
create mode 100644 app/Http/Middleware/RedirectIfNotInstalled.php
create mode 100644 app/Http/Middleware/RedirectIfWizardNotCompleted.php
create mode 100644 app/Http/Middleware/TrimStrings.php
create mode 100644 app/Http/Middleware/TrustHosts.php
create mode 100644 app/Http/Middleware/TrustProxies.php
create mode 100644 app/Http/Middleware/ValidateSignature.php
create mode 100644 app/Http/Middleware/VerifyCsrfToken.php
create mode 100644 app/Http/Requests/Auth/Forgot.php
create mode 100644 app/Http/Requests/Auth/Login.php
create mode 100644 app/Http/Requests/Auth/Register.php
create mode 100644 app/Http/Requests/Auth/Reset.php
create mode 100644 app/Http/Requests/Auth/User.php
create mode 100644 app/Http/Requests/Banking/Account.php
create mode 100644 app/Http/Requests/Banking/FundAccount.php
create mode 100644 app/Http/Requests/Banking/Reconciliation.php
create mode 100644 app/Http/Requests/Banking/ReconciliationCalculate.php
create mode 100644 app/Http/Requests/Banking/Transaction.php
create mode 100644 app/Http/Requests/Banking/TransactionConnect.php
create mode 100644 app/Http/Requests/Banking/Transfer.php
create mode 100644 app/Http/Requests/Common/BulkAction.php
create mode 100644 app/Http/Requests/Common/Company.php
create mode 100644 app/Http/Requests/Common/Contact.php
create mode 100644 app/Http/Requests/Common/ContactPerson.php
create mode 100644 app/Http/Requests/Common/CustomMail.php
create mode 100644 app/Http/Requests/Common/Dashboard.php
create mode 100644 app/Http/Requests/Common/Import.php
create mode 100644 app/Http/Requests/Common/Item.php
create mode 100644 app/Http/Requests/Common/ItemTax.php
create mode 100644 app/Http/Requests/Common/Notification.php
create mode 100644 app/Http/Requests/Common/Report.php
create mode 100644 app/Http/Requests/Common/ReportShow.php
create mode 100644 app/Http/Requests/Common/TotalItem.php
create mode 100644 app/Http/Requests/Common/Widget.php
create mode 100644 app/Http/Requests/Document/Document.php
create mode 100644 app/Http/Requests/Document/DocumentAddItem.php
create mode 100644 app/Http/Requests/Document/DocumentHistory.php
create mode 100644 app/Http/Requests/Document/DocumentItem.php
create mode 100644 app/Http/Requests/Document/DocumentItemTax.php
create mode 100644 app/Http/Requests/Document/DocumentTotal.php
create mode 100644 app/Http/Requests/Install/Database.php
create mode 100644 app/Http/Requests/Install/Setting.php
create mode 100644 app/Http/Requests/Module/Install.php
create mode 100644 app/Http/Requests/Module/Module.php
create mode 100644 app/Http/Requests/Portal/InvoiceConfirm.php
create mode 100644 app/Http/Requests/Portal/InvoicePayment.php
create mode 100644 app/Http/Requests/Portal/InvoiceShow.php
create mode 100644 app/Http/Requests/Portal/PaymentShow.php
create mode 100644 app/Http/Requests/Portal/Profile.php
create mode 100644 app/Http/Requests/Setting/Category.php
create mode 100644 app/Http/Requests/Setting/Currency.php
create mode 100644 app/Http/Requests/Setting/EmailTemplate.php
create mode 100644 app/Http/Requests/Setting/Module.php
create mode 100644 app/Http/Requests/Setting/Setting.php
create mode 100644 app/Http/Requests/Setting/Tax.php
create mode 100644 app/Http/Requests/Wizard/Company.php
create mode 100644 app/Http/Resources/Auth/Owner.php
create mode 100644 app/Http/Resources/Auth/Role.php
create mode 100644 app/Http/Resources/Auth/User.php
create mode 100644 app/Http/Resources/Banking/Account.php
create mode 100644 app/Http/Resources/Banking/Reconciliation.php
create mode 100644 app/Http/Resources/Banking/Transaction.php
create mode 100644 app/Http/Resources/Banking/TransactionTax.php
create mode 100644 app/Http/Resources/Banking/Transfer.php
create mode 100644 app/Http/Resources/Common/Company.php
create mode 100644 app/Http/Resources/Common/Contact.php
create mode 100644 app/Http/Resources/Common/ContactPerson.php
create mode 100644 app/Http/Resources/Common/Dashboard.php
create mode 100644 app/Http/Resources/Common/Item.php
create mode 100644 app/Http/Resources/Common/ItemTax.php
create mode 100644 app/Http/Resources/Common/Report.php
create mode 100644 app/Http/Resources/Common/Widget.php
create mode 100644 app/Http/Resources/Document/Document.php
create mode 100644 app/Http/Resources/Document/DocumentHistory.php
create mode 100644 app/Http/Resources/Document/DocumentItem.php
create mode 100644 app/Http/Resources/Document/DocumentItemTax.php
create mode 100644 app/Http/Resources/Document/DocumentTotal.php
create mode 100644 app/Http/Resources/Setting/Category.php
create mode 100644 app/Http/Resources/Setting/Currency.php
create mode 100644 app/Http/Resources/Setting/Setting.php
create mode 100644 app/Http/Resources/Setting/Tax.php
create mode 100644 app/Http/Responses/Common/Items.php
create mode 100644 app/Http/ViewComposers/ContactType.php
create mode 100644 app/Http/ViewComposers/DocumentRecurring.php
create mode 100644 app/Http/ViewComposers/DocumentType.php
create mode 100644 app/Http/ViewComposers/PlanLimits.php
create mode 100644 app/Http/ViewComposers/ReadOnlyNotification.php
create mode 100644 app/Imports/Banking/RecurringTransactions.php
create mode 100644 app/Imports/Banking/Sheets/Recurring.php
create mode 100644 app/Imports/Banking/Sheets/RecurringTransactions.php
create mode 100644 app/Imports/Banking/Transactions.php
create mode 100644 app/Imports/Banking/Transfers.php
create mode 100644 app/Imports/Common/Items.php
create mode 100644 app/Imports/Common/Sheets/ItemTaxes.php
create mode 100644 app/Imports/Common/Sheets/Items.php
create mode 100644 app/Imports/Purchases/Bills/Bills.php
create mode 100644 app/Imports/Purchases/Bills/Sheets/BillHistories.php
create mode 100644 app/Imports/Purchases/Bills/Sheets/BillItemTaxes.php
create mode 100644 app/Imports/Purchases/Bills/Sheets/BillItems.php
create mode 100644 app/Imports/Purchases/Bills/Sheets/BillTotals.php
create mode 100644 app/Imports/Purchases/Bills/Sheets/BillTransactions.php
create mode 100644 app/Imports/Purchases/Bills/Sheets/Bills.php
create mode 100644 app/Imports/Purchases/RecurringBills/RecurringBills.php
create mode 100644 app/Imports/Purchases/RecurringBills/Sheets/Recurring.php
create mode 100644 app/Imports/Purchases/RecurringBills/Sheets/RecurringBillHistories.php
create mode 100644 app/Imports/Purchases/RecurringBills/Sheets/RecurringBillItemTaxes.php
create mode 100644 app/Imports/Purchases/RecurringBills/Sheets/RecurringBillItems.php
create mode 100644 app/Imports/Purchases/RecurringBills/Sheets/RecurringBillTotals.php
create mode 100644 app/Imports/Purchases/RecurringBills/Sheets/RecurringBills.php
create mode 100644 app/Imports/Purchases/Vendors.php
create mode 100644 app/Imports/Sales/Customers.php
create mode 100644 app/Imports/Sales/Invoices/Invoices.php
create mode 100644 app/Imports/Sales/Invoices/Sheets/InvoiceHistories.php
create mode 100644 app/Imports/Sales/Invoices/Sheets/InvoiceItemTaxes.php
create mode 100644 app/Imports/Sales/Invoices/Sheets/InvoiceItems.php
create mode 100644 app/Imports/Sales/Invoices/Sheets/InvoiceTotals.php
create mode 100644 app/Imports/Sales/Invoices/Sheets/InvoiceTransactions.php
create mode 100644 app/Imports/Sales/Invoices/Sheets/Invoices.php
create mode 100644 app/Imports/Sales/RecurringInvoices/RecurringInvoices.php
create mode 100644 app/Imports/Sales/RecurringInvoices/Sheets/Recurring.php
create mode 100644 app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceHistories.php
create mode 100644 app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItemTaxes.php
create mode 100644 app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItems.php
create mode 100644 app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceTotals.php
create mode 100644 app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoices.php
create mode 100644 app/Imports/Settings/Categories.php
create mode 100644 app/Imports/Settings/Taxes.php
create mode 100644 app/Interfaces/Export/WithParentSheet.php
create mode 100644 app/Interfaces/Job/HasOwner.php
create mode 100644 app/Interfaces/Job/HasSource.php
create mode 100644 app/Interfaces/Job/ShouldCreate.php
create mode 100644 app/Interfaces/Job/ShouldDelete.php
create mode 100644 app/Interfaces/Job/ShouldUpdate.php
create mode 100644 app/Interfaces/Listener/ShouldUpdateAllCompanies.php
create mode 100644 app/Interfaces/Utility/DocumentNumber.php
create mode 100644 app/Interfaces/Utility/TransactionNumber.php
create mode 100644 app/Jobs/Auth/CreateInvitation.php
create mode 100644 app/Jobs/Auth/CreatePermission.php
create mode 100644 app/Jobs/Auth/CreateRole.php
create mode 100644 app/Jobs/Auth/CreateUser.php
create mode 100644 app/Jobs/Auth/DeleteInvitation.php
create mode 100644 app/Jobs/Auth/DeletePermission.php
create mode 100644 app/Jobs/Auth/DeleteRole.php
create mode 100644 app/Jobs/Auth/DeleteUser.php
create mode 100644 app/Jobs/Auth/NotifyUser.php
create mode 100644 app/Jobs/Auth/UpdatePermission.php
create mode 100644 app/Jobs/Auth/UpdateRole.php
create mode 100644 app/Jobs/Auth/UpdateUser.php
create mode 100644 app/Jobs/Banking/CreateAccount.php
create mode 100644 app/Jobs/Banking/CreateBankingDocumentTransaction.php
create mode 100644 app/Jobs/Banking/CreateReconciliation.php
create mode 100644 app/Jobs/Banking/CreateTransaction.php
create mode 100644 app/Jobs/Banking/CreateTransactionTaxes.php
create mode 100644 app/Jobs/Banking/CreateTransfer.php
create mode 100644 app/Jobs/Banking/DeleteAccount.php
create mode 100644 app/Jobs/Banking/DeleteReconciliation.php
create mode 100644 app/Jobs/Banking/DeleteTransaction.php
create mode 100644 app/Jobs/Banking/DeleteTransfer.php
create mode 100644 app/Jobs/Banking/DuplicateTransaction.php
create mode 100644 app/Jobs/Banking/MatchBankingDocumentTransaction.php
create mode 100644 app/Jobs/Banking/SendTransaction.php
create mode 100644 app/Jobs/Banking/SendTransactionAsCustomMail.php
create mode 100644 app/Jobs/Banking/SplitTransaction.php
create mode 100644 app/Jobs/Banking/UpdateAccount.php
create mode 100644 app/Jobs/Banking/UpdateBankingDocumentTransaction.php
create mode 100644 app/Jobs/Banking/UpdateReconciliation.php
create mode 100644 app/Jobs/Banking/UpdateTransaction.php
create mode 100644 app/Jobs/Banking/UpdateTransfer.php
create mode 100644 app/Jobs/Common/CreateCompany.php
create mode 100644 app/Jobs/Common/CreateContact.php
create mode 100644 app/Jobs/Common/CreateContactPerson.php
create mode 100644 app/Jobs/Common/CreateContactPersons.php
create mode 100644 app/Jobs/Common/CreateDashboard.php
create mode 100644 app/Jobs/Common/CreateItem.php
create mode 100644 app/Jobs/Common/CreateItemTaxes.php
create mode 100644 app/Jobs/Common/CreateMediableForDownload.php
create mode 100644 app/Jobs/Common/CreateMediableForExport.php
create mode 100644 app/Jobs/Common/CreateReport.php
create mode 100644 app/Jobs/Common/CreateWidget.php
create mode 100644 app/Jobs/Common/CreateZipForDownload.php
create mode 100644 app/Jobs/Common/DeleteCompany.php
create mode 100644 app/Jobs/Common/DeleteContact.php
create mode 100644 app/Jobs/Common/DeleteContactPerson.php
create mode 100644 app/Jobs/Common/DeleteDashboard.php
create mode 100644 app/Jobs/Common/DeleteItem.php
create mode 100644 app/Jobs/Common/DeleteReport.php
create mode 100644 app/Jobs/Common/DeleteWidget.php
create mode 100644 app/Jobs/Common/DuplicateContact.php
create mode 100644 app/Jobs/Common/UpdateCompany.php
create mode 100644 app/Jobs/Common/UpdateContact.php
create mode 100644 app/Jobs/Common/UpdateContactPerson.php
create mode 100644 app/Jobs/Common/UpdateDashboard.php
create mode 100644 app/Jobs/Common/UpdateItem.php
create mode 100644 app/Jobs/Common/UpdateReport.php
create mode 100644 app/Jobs/Common/UpdateWidget.php
create mode 100644 app/Jobs/Document/CancelDocument.php
create mode 100644 app/Jobs/Document/CreateDocument.php
create mode 100644 app/Jobs/Document/CreateDocumentHistory.php
create mode 100644 app/Jobs/Document/CreateDocumentItem.php
create mode 100644 app/Jobs/Document/CreateDocumentItemsAndTotals.php
create mode 100644 app/Jobs/Document/DeleteDocument.php
create mode 100644 app/Jobs/Document/DownloadDocument.php
create mode 100644 app/Jobs/Document/DuplicateDocument.php
create mode 100644 app/Jobs/Document/RestoreDocument.php
create mode 100644 app/Jobs/Document/SendDocument.php
create mode 100644 app/Jobs/Document/SendDocumentAsCustomMail.php
create mode 100644 app/Jobs/Document/UpdateDocument.php
create mode 100644 app/Jobs/Install/CopyFiles.php
create mode 100644 app/Jobs/Install/DisableModule.php
create mode 100644 app/Jobs/Install/DownloadFile.php
create mode 100644 app/Jobs/Install/DownloadModule.php
create mode 100644 app/Jobs/Install/EnableModule.php
create mode 100644 app/Jobs/Install/FinishUpdate.php
create mode 100644 app/Jobs/Install/InstallModule.php
create mode 100644 app/Jobs/Install/UninstallModule.php
create mode 100644 app/Jobs/Install/UnzipFile.php
create mode 100644 app/Jobs/Setting/CreateCategory.php
create mode 100644 app/Jobs/Setting/CreateCurrency.php
create mode 100644 app/Jobs/Setting/CreateEmailTemplate.php
create mode 100644 app/Jobs/Setting/CreateTax.php
create mode 100644 app/Jobs/Setting/DeleteCategory.php
create mode 100644 app/Jobs/Setting/DeleteCurrency.php
create mode 100644 app/Jobs/Setting/DeleteEmailTemplate.php
create mode 100644 app/Jobs/Setting/DeleteTax.php
create mode 100644 app/Jobs/Setting/UpdateCategory.php
create mode 100644 app/Jobs/Setting/UpdateCurrency.php
create mode 100644 app/Jobs/Setting/UpdateEmailTemplate.php
create mode 100644 app/Jobs/Setting/UpdateTax.php
create mode 100644 app/Listeners/Auth/AddLandingPages.php
create mode 100644 app/Listeners/Auth/Login.php
create mode 100644 app/Listeners/Auth/Logout.php
create mode 100644 app/Listeners/Banking/IncreaseNextTransactionNumber.php
create mode 100644 app/Listeners/Common/ClearPlansCache.php
create mode 100644 app/Listeners/Common/PreparingResponse.php
create mode 100644 app/Listeners/Common/SkipScheduleInReadOnlyMode.php
create mode 100644 app/Listeners/Document/CreateDocumentCreatedHistory.php
create mode 100644 app/Listeners/Document/CreateDocumentTransaction.php
create mode 100644 app/Listeners/Document/IncreaseNextDocumentNumber.php
create mode 100644 app/Listeners/Document/MarkDocumentCancelled.php
create mode 100644 app/Listeners/Document/MarkDocumentReceived.php
create mode 100644 app/Listeners/Document/MarkDocumentSent.php
create mode 100644 app/Listeners/Document/MarkDocumentViewed.php
create mode 100644 app/Listeners/Document/RestoreDocument.php
create mode 100644 app/Listeners/Document/SendDocumentPaymentNotification.php
create mode 100644 app/Listeners/Document/SendDocumentRecurringNotification.php
create mode 100644 app/Listeners/Document/SendDocumentReminderNotification.php
create mode 100644 app/Listeners/Document/SendDocumentViewNotification.php
create mode 100644 app/Listeners/Document/SettingFieldCreated.php
create mode 100644 app/Listeners/Document/SettingFieldUpdated.php
create mode 100644 app/Listeners/Email/DisablePersonDueToInvalidEmail.php
create mode 100644 app/Listeners/Email/ReportTooManyEmailsSent.php
create mode 100644 app/Listeners/Email/SendInvalidEmailNotification.php
create mode 100644 app/Listeners/Email/TellFirewallTooManyEmailsSent.php
create mode 100644 app/Listeners/Menu/ShowInAdmin.php
create mode 100644 app/Listeners/Menu/ShowInNeww.php
create mode 100644 app/Listeners/Menu/ShowInNotifications.php
create mode 100644 app/Listeners/Menu/ShowInPortal.php
create mode 100644 app/Listeners/Menu/ShowInProfile.php
create mode 100644 app/Listeners/Menu/ShowInSettings.php
create mode 100644 app/Listeners/Module/ClearCache.php
create mode 100644 app/Listeners/Module/FinishInstallation.php
create mode 100644 app/Listeners/Module/FinishUninstallation.php
create mode 100644 app/Listeners/Module/InstallExtraModules.php
create mode 100644 app/Listeners/Module/UpdateExtraModules.php
create mode 100644 app/Listeners/Report/AddAccounts.php
create mode 100644 app/Listeners/Report/AddBasis.php
create mode 100644 app/Listeners/Report/AddContacts.php
create mode 100644 app/Listeners/Report/AddCustomers.php
create mode 100644 app/Listeners/Report/AddDate.php
create mode 100644 app/Listeners/Report/AddDiscount.php
create mode 100644 app/Listeners/Report/AddExpenseCategories.php
create mode 100644 app/Listeners/Report/AddGroup.php
create mode 100644 app/Listeners/Report/AddIncomeCategories.php
create mode 100644 app/Listeners/Report/AddIncomeExpenseCategories.php
create mode 100644 app/Listeners/Report/AddPeriod.php
create mode 100644 app/Listeners/Report/AddRowsToTax.php
create mode 100644 app/Listeners/Report/AddSearchString.php
create mode 100644 app/Listeners/Report/AddVendors.php
create mode 100644 app/Listeners/Setting/DeleteCategoryDeletedSubCategories.php
create mode 100644 app/Listeners/Update/CreateModuleUpdatedHistory.php
create mode 100644 app/Listeners/Update/SendNotificationOnFailure.php
create mode 100644 app/Listeners/Update/V30/Version300.php
create mode 100644 app/Listeners/Update/V30/Version3013.php
create mode 100644 app/Listeners/Update/V30/Version3014.php
create mode 100644 app/Listeners/Update/V30/Version3015.php
create mode 100644 app/Listeners/Update/V30/Version3016.php
create mode 100644 app/Listeners/Update/V30/Version3017.php
create mode 100644 app/Listeners/Update/V30/Version303.php
create mode 100644 app/Listeners/Update/V30/Version304.php
create mode 100644 app/Listeners/Update/V30/Version305.php
create mode 100644 app/Listeners/Update/V30/Version307.php
create mode 100644 app/Listeners/Update/V30/Version309.php
create mode 100644 app/Listeners/Update/V31/Version310.php
create mode 100644 app/Listeners/Update/V31/Version3112.php
create mode 100644 app/Listeners/Update/V31/Version3115.php
create mode 100644 app/Listeners/Update/V31/Version3119.php
create mode 100644 app/Listeners/Update/V31/Version315.php
create mode 100644 app/Listeners/Update/V31/Version317.php
create mode 100644 app/Listeners/Update/V31/Version318.php
create mode 100644 app/Listeners/Update/V32/Version320.php
create mode 100644 app/Models/Auth/Permission.php
create mode 100644 app/Models/Auth/Role.php
create mode 100644 app/Models/Auth/User.php
create mode 100644 app/Models/Auth/UserCompany.php
create mode 100644 app/Models/Auth/UserDashboard.php
create mode 100644 app/Models/Auth/UserInvitation.php
create mode 100644 app/Models/Auth/UserRole.php
create mode 100644 app/Models/Banking/Account.php
create mode 100644 app/Models/Banking/FundAccount.php
create mode 100644 app/Models/Banking/Reconciliation.php
create mode 100644 app/Models/Banking/Transaction.php
create mode 100644 app/Models/Banking/TransactionTax.php
create mode 100644 app/Models/Banking/Transfer.php
create mode 100644 app/Models/Common/Company.php
create mode 100644 app/Models/Common/Contact.php
create mode 100644 app/Models/Common/ContactPerson.php
create mode 100644 app/Models/Common/Dashboard.php
create mode 100644 app/Models/Common/Item.php
create mode 100644 app/Models/Common/ItemTax.php
create mode 100644 app/Models/Common/Media.php
create mode 100644 app/Models/Common/Notification.php
create mode 100644 app/Models/Common/Recurring.php
create mode 100644 app/Models/Common/Report.php
create mode 100644 app/Models/Common/Widget.php
create mode 100644 app/Models/Document/Document.php
create mode 100644 app/Models/Document/DocumentHistory.php
create mode 100644 app/Models/Document/DocumentItem.php
create mode 100644 app/Models/Document/DocumentItemTax.php
create mode 100644 app/Models/Document/DocumentTotal.php
create mode 100644 app/Models/Module/Module.php
create mode 100644 app/Models/Module/ModuleHistory.php
create mode 100644 app/Models/Setting/Category.php
create mode 100644 app/Models/Setting/Currency.php
create mode 100644 app/Models/Setting/EmailTemplate.php
create mode 100644 app/Models/Setting/Setting.php
create mode 100644 app/Models/Setting/Tax.php
create mode 100644 app/Models/Settings/DatabaseConnection.php
create mode 100644 app/Notifications/Auth/Invitation.php
create mode 100644 app/Notifications/Auth/Reset.php
create mode 100644 app/Notifications/Banking/Transaction.php
create mode 100644 app/Notifications/Common/DownloadCompleted.php
create mode 100644 app/Notifications/Common/DownloadFailed.php
create mode 100644 app/Notifications/Common/ExportCompleted.php
create mode 100644 app/Notifications/Common/ExportFailed.php
create mode 100644 app/Notifications/Common/ImportCompleted.php
create mode 100644 app/Notifications/Common/ImportFailed.php
create mode 100644 app/Notifications/Email/InvalidEmail.php
create mode 100644 app/Notifications/Install/UpdateFailed.php
create mode 100644 app/Notifications/Portal/PaymentReceived.php
create mode 100644 app/Notifications/Purchase/Bill.php
create mode 100644 app/Notifications/Sale/Invoice.php
create mode 100644 app/Observers/Transaction.php
create mode 100644 app/Providers/App.php
create mode 100644 app/Providers/Auth.php
create mode 100644 app/Providers/Binding.php
create mode 100644 app/Providers/Blade.php
create mode 100644 app/Providers/Broadcast.php
create mode 100644 app/Providers/Event.php
create mode 100644 app/Providers/Macro.php
create mode 100644 app/Providers/Observer.php
create mode 100644 app/Providers/Queue.php
create mode 100644 app/Providers/Route.php
create mode 100644 app/Providers/Validation.php
create mode 100644 app/Providers/ViewComposer.php
create mode 100644 app/Relations/HasMany/Category.php
create mode 100644 app/Reports/DiscountSummary.php
create mode 100644 app/Reports/ExpenseSummary.php
create mode 100644 app/Reports/IncomeExpenseSummary.php
create mode 100644 app/Reports/IncomeSummary.php
create mode 100644 app/Reports/ProfitLoss.php
create mode 100644 app/Reports/TaxSummary.php
create mode 100644 app/Scopes/Category.php
create mode 100644 app/Scopes/Company.php
create mode 100644 app/Scopes/Contact.php
create mode 100644 app/Scopes/Document.php
create mode 100644 app/Scopes/Transaction.php
create mode 100644 app/Traits/Categories.php
create mode 100644 app/Traits/Charts.php
create mode 100644 app/Traits/Cloud.php
create mode 100644 app/Traits/Companies.php
create mode 100644 app/Traits/Contacts.php
create mode 100644 app/Traits/Currencies.php
create mode 100644 app/Traits/Database.php
create mode 100644 app/Traits/DateTime.php
create mode 100644 app/Traits/Documents.php
create mode 100644 app/Traits/Emails.php
create mode 100644 app/Traits/HasApiTokens.php
create mode 100644 app/Traits/Import.php
create mode 100644 app/Traits/Jobs.php
create mode 100644 app/Traits/Media.php
create mode 100644 app/Traits/Modules.php
create mode 100644 app/Traits/Omnipay.php
create mode 100644 app/Traits/Owners.php
create mode 100644 app/Traits/Permissions.php
create mode 100644 app/Traits/Plans.php
create mode 100644 app/Traits/Recurring.php
create mode 100644 app/Traits/Relationships.php
create mode 100644 app/Traits/Scopes.php
create mode 100644 app/Traits/SearchString.php
create mode 100644 app/Traits/Settings.php
create mode 100644 app/Traits/SiteApi.php
create mode 100644 app/Traits/Sources.php
create mode 100644 app/Traits/Tailwind.php
create mode 100644 app/Traits/Tenants.php
create mode 100644 app/Traits/Trackers.php
create mode 100644 app/Traits/Transactions.php
create mode 100644 app/Traits/Translations.php
create mode 100644 app/Traits/Updates.php
create mode 100644 app/Traits/Uploads.php
create mode 100644 app/Traits/Users.php
create mode 100644 app/Traits/ViewComponents.php
create mode 100644 app/Utilities/BusinessNavigation.php
create mode 100644 app/Utilities/Console.php
create mode 100644 app/Utilities/Date.php
create mode 100644 app/Utilities/DocumentNumber.php
create mode 100644 app/Utilities/Export.php
create mode 100644 app/Utilities/FundAccountSpreadsheet.php
create mode 100644 app/Utilities/Import.php
create mode 100644 app/Utilities/Info.php
create mode 100644 app/Utilities/Installer.php
create mode 100644 app/Utilities/ModuleActivator.php
create mode 100644 app/Utilities/Modules.php
create mode 100644 app/Utilities/Overrider.php
create mode 100644 app/Utilities/QueueCollection.php
create mode 100644 app/Utilities/Recurring.php
create mode 100644 app/Utilities/Reports.php
create mode 100644 app/Utilities/SidebarPermissions.php
create mode 100644 app/Utilities/Str.php
create mode 100644 app/Utilities/SystemAccess.php
create mode 100644 app/Utilities/TransactionNumber.php
create mode 100644 app/Utilities/Versions.php
create mode 100644 app/Utilities/Widgets.php
create mode 100644 app/Utilities/helpers.php
create mode 100644 app/View/Components/Alert.php
create mode 100644 app/View/Components/Alert/Border.php
create mode 100644 app/View/Components/Alert/Danger.php
create mode 100644 app/View/Components/Alert/Info.php
create mode 100644 app/View/Components/Alert/Success.php
create mode 100644 app/View/Components/Alert/Warning.php
create mode 100644 app/View/Components/Button.php
create mode 100644 app/View/Components/Button/Hover.php
create mode 100644 app/View/Components/Contacts/Form/Address.php
create mode 100644 app/View/Components/Contacts/Form/Billing.php
create mode 100644 app/View/Components/Contacts/Form/Buttons.php
create mode 100644 app/View/Components/Contacts/Form/Content.php
create mode 100644 app/View/Components/Contacts/Form/General.php
create mode 100644 app/View/Components/Contacts/Form/Persons.php
create mode 100644 app/View/Components/Contacts/Index/Buttons.php
create mode 100644 app/View/Components/Contacts/Index/Content.php
create mode 100644 app/View/Components/Contacts/Index/MoreButtons.php
create mode 100644 app/View/Components/Contacts/Script.php
create mode 100644 app/View/Components/Contacts/Show/Buttons.php
create mode 100644 app/View/Components/Contacts/Show/Content.php
create mode 100644 app/View/Components/Contacts/Show/MoreButtons.php
create mode 100644 app/View/Components/Date.php
create mode 100644 app/View/Components/DeleteButton.php
create mode 100644 app/View/Components/DeleteLink.php
create mode 100644 app/View/Components/Documents/Form/Advanced.php
create mode 100644 app/View/Components/Documents/Form/Buttons.php
create mode 100644 app/View/Components/Documents/Form/Company.php
create mode 100644 app/View/Components/Documents/Form/Contact.php
create mode 100644 app/View/Components/Documents/Form/Content.php
create mode 100644 app/View/Components/Documents/Form/Footer.php
create mode 100644 app/View/Components/Documents/Form/ItemButton.php
create mode 100644 app/View/Components/Documents/Form/ItemColumns.php
create mode 100644 app/View/Components/Documents/Form/Items.php
create mode 100644 app/View/Components/Documents/Form/LineItem.php
create mode 100644 app/View/Components/Documents/Form/Main.php
create mode 100644 app/View/Components/Documents/Form/Metadata.php
create mode 100644 app/View/Components/Documents/Form/Note.php
create mode 100644 app/View/Components/Documents/Form/Recurring.php
create mode 100644 app/View/Components/Documents/Form/RecurringMetadata.php
create mode 100644 app/View/Components/Documents/Form/Totals.php
create mode 100644 app/View/Components/Documents/Index/BulkAction.php
create mode 100644 app/View/Components/Documents/Index/Buttons.php
create mode 100644 app/View/Components/Documents/Index/Content.php
create mode 100644 app/View/Components/Documents/Index/Document.php
create mode 100644 app/View/Components/Documents/Index/Information.php
create mode 100644 app/View/Components/Documents/Index/MoreButtons.php
create mode 100644 app/View/Components/Documents/Index/RecurringTemplates.php
create mode 100644 app/View/Components/Documents/Script.php
create mode 100644 app/View/Components/Documents/Show/Attachment.php
create mode 100644 app/View/Components/Documents/Show/Buttons.php
create mode 100644 app/View/Components/Documents/Show/Children.php
create mode 100644 app/View/Components/Documents/Show/Content.php
create mode 100644 app/View/Components/Documents/Show/Create.php
create mode 100644 app/View/Components/Documents/Show/GetPaid.php
create mode 100644 app/View/Components/Documents/Show/MakePayment.php
create mode 100644 app/View/Components/Documents/Show/Message.php
create mode 100644 app/View/Components/Documents/Show/MoreButtons.php
create mode 100644 app/View/Components/Documents/Show/Receive.php
create mode 100644 app/View/Components/Documents/Show/Restore.php
create mode 100644 app/View/Components/Documents/Show/Schedule.php
create mode 100644 app/View/Components/Documents/Show/Send.php
create mode 100644 app/View/Components/Documents/Show/Template.php
create mode 100644 app/View/Components/Documents/Template/Classic.php
create mode 100644 app/View/Components/Documents/Template/Ddefault.php
create mode 100644 app/View/Components/Documents/Template/LineItem.php
create mode 100644 app/View/Components/Documents/Template/Modern.php
create mode 100644 app/View/Components/Dropdown.php
create mode 100644 app/View/Components/Dropdown/Button.php
create mode 100644 app/View/Components/Dropdown/Link.php
create mode 100644 app/View/Components/EmptyPage.php
create mode 100644 app/View/Components/Form.php
create mode 100644 app/View/Components/Form/Accordion.php
create mode 100644 app/View/Components/Form/Buttons.php
create mode 100644 app/View/Components/Form/Group/Account.php
create mode 100644 app/View/Components/Form/Group/Attachment.php
create mode 100644 app/View/Components/Form/Group/Category.php
create mode 100644 app/View/Components/Form/Group/Checkbox.php
create mode 100644 app/View/Components/Form/Group/Color.php
create mode 100644 app/View/Components/Form/Group/Contact.php
create mode 100644 app/View/Components/Form/Group/Country.php
create mode 100644 app/View/Components/Form/Group/Currency.php
create mode 100644 app/View/Components/Form/Group/Customer.php
create mode 100644 app/View/Components/Form/Group/Date.php
create mode 100644 app/View/Components/Form/Group/DateTime.php
create mode 100644 app/View/Components/Form/Group/Editor.php
create mode 100644 app/View/Components/Form/Group/Email.php
create mode 100644 app/View/Components/Form/Group/File.php
create mode 100644 app/View/Components/Form/Group/Import.php
create mode 100644 app/View/Components/Form/Group/InvoiceText.php
create mode 100644 app/View/Components/Form/Group/Locale.php
create mode 100644 app/View/Components/Form/Group/Money.php
create mode 100644 app/View/Components/Form/Group/Number.php
create mode 100644 app/View/Components/Form/Group/NumberDigit.php
create mode 100644 app/View/Components/Form/Group/Password.php
create mode 100644 app/View/Components/Form/Group/PaymentMethod.php
create mode 100644 app/View/Components/Form/Group/PaymentTerm.php
create mode 100644 app/View/Components/Form/Group/Radio.php
create mode 100644 app/View/Components/Form/Group/Recurring.php
create mode 100644 app/View/Components/Form/Group/Select.php
create mode 100644 app/View/Components/Form/Group/Sswitch.php
create mode 100644 app/View/Components/Form/Group/Tax.php
create mode 100644 app/View/Components/Form/Group/Text.php
create mode 100644 app/View/Components/Form/Group/Textarea.php
create mode 100644 app/View/Components/Form/Group/Time.php
create mode 100644 app/View/Components/Form/Group/Toggle.php
create mode 100644 app/View/Components/Form/Group/Vendor.php
create mode 100644 app/View/Components/Form/Input/Checkbox.php
create mode 100644 app/View/Components/Form/Input/Color.php
create mode 100644 app/View/Components/Form/Input/Editor.php
create mode 100644 app/View/Components/Form/Input/Email.php
create mode 100644 app/View/Components/Form/Input/Ffile.php
create mode 100644 app/View/Components/Form/Input/Hidden.php
create mode 100644 app/View/Components/Form/Input/Import.php
create mode 100644 app/View/Components/Form/Input/Input.php
create mode 100644 app/View/Components/Form/Input/Money.php
create mode 100644 app/View/Components/Form/Input/Number.php
create mode 100644 app/View/Components/Form/Input/Password.php
create mode 100644 app/View/Components/Form/Input/Radio.php
create mode 100644 app/View/Components/Form/Input/Select.php
create mode 100644 app/View/Components/Form/Input/Text.php
create mode 100644 app/View/Components/Form/Input/Textarea.php
create mode 100644 app/View/Components/Form/Section.php
create mode 100644 app/View/Components/Icon.php
create mode 100644 app/View/Components/Index/Balance.php
create mode 100644 app/View/Components/Index/Bulkaction.php
create mode 100644 app/View/Components/Index/Category.php
create mode 100644 app/View/Components/Index/Country.php
create mode 100644 app/View/Components/Index/Currency.php
create mode 100644 app/View/Components/Index/Ddefault.php
create mode 100644 app/View/Components/Index/Disable.php
create mode 100644 app/View/Components/Index/Search.php
create mode 100644 app/View/Components/Index/Status.php
create mode 100644 app/View/Components/Index/Summary.php
create mode 100644 app/View/Components/Layouts/Admin.php
create mode 100644 app/View/Components/Layouts/Admin/Head.php
create mode 100644 app/View/Components/Layouts/Admin/Menu.php
create mode 100644 app/View/Components/Layouts/Admin/Notifications.php
create mode 100644 app/View/Components/Layouts/Modules.php
create mode 100644 app/View/Components/Layouts/Modules/Bar.php
create mode 100644 app/View/Components/Layouts/Modules/Releases.php
create mode 100644 app/View/Components/Layouts/Modules/Reviews.php
create mode 100644 app/View/Components/Layouts/Portal/Menu.php
create mode 100644 app/View/Components/Layouts/Wizard.php
create mode 100644 app/View/Components/Layouts/Wizard/Scripts.php
create mode 100644 app/View/Components/Link.php
create mode 100644 app/View/Components/Link/Hover.php
create mode 100644 app/View/Components/Media/Ffile.php
create mode 100644 app/View/Components/Menu/Favorite.php
create mode 100644 app/View/Components/Modules/Banners.php
create mode 100644 app/View/Components/Modules/Free.php
create mode 100644 app/View/Components/Modules/Installed.php
create mode 100644 app/View/Components/Modules/Item.php
create mode 100644 app/View/Components/Modules/Items.php
create mode 100644 app/View/Components/Modules/Nnew.php
create mode 100644 app/View/Components/Modules/NoApps.php
create mode 100644 app/View/Components/Modules/Paid.php
create mode 100644 app/View/Components/Modules/PreSale.php
create mode 100644 app/View/Components/Modules/Purchased.php
create mode 100644 app/View/Components/Pagination.php
create mode 100644 app/View/Components/PaymentMethod.php
create mode 100644 app/View/Components/Script.php
create mode 100644 app/View/Components/Script/Declaration.php
create mode 100644 app/View/Components/Script/Exceptions/Trackers.php
create mode 100644 app/View/Components/SearchString.php
create mode 100644 app/View/Components/Show/Accordion.php
create mode 100644 app/View/Components/Show/NoRecords.php
create mode 100644 app/View/Components/Show/Right.php
create mode 100644 app/View/Components/Show/Status.php
create mode 100644 app/View/Components/Suggestions.php
create mode 100644 app/View/Components/Table/Actions.php
create mode 100644 app/View/Components/Table/Tbody.php
create mode 100644 app/View/Components/Table/Td.php
create mode 100644 app/View/Components/Table/Th.php
create mode 100644 app/View/Components/Table/Thead.php
create mode 100644 app/View/Components/Table/Tr.php
create mode 100644 app/View/Components/Tips.php
create mode 100644 app/View/Components/Title.php
create mode 100644 app/View/Components/Tooltip.php
create mode 100644 app/View/Components/Transactions/Index/BulkAction.php
create mode 100644 app/View/Components/Transactions/Index/Buttons.php
create mode 100644 app/View/Components/Transactions/Index/Content.php
create mode 100644 app/View/Components/Transactions/Index/MoreButtons.php
create mode 100644 app/View/Components/Transactions/Index/RecurringTemplates.php
create mode 100644 app/View/Components/Transactions/Index/Transaction.php
create mode 100644 app/View/Components/Transactions/Script.php
create mode 100644 app/View/Components/Transactions/Show/Attachment.php
create mode 100644 app/View/Components/Transactions/Show/Buttons.php
create mode 100644 app/View/Components/Transactions/Show/Children.php
create mode 100644 app/View/Components/Transactions/Show/Connect.php
create mode 100644 app/View/Components/Transactions/Show/Content.php
create mode 100644 app/View/Components/Transactions/Show/Create.php
create mode 100644 app/View/Components/Transactions/Show/MoreButtons.php
create mode 100644 app/View/Components/Transactions/Show/Schedule.php
create mode 100644 app/View/Components/Transactions/Show/Template.php
create mode 100644 app/View/Components/Transactions/Show/Transfer.php
create mode 100644 app/View/Components/Transactions/Template/Ddefault.php
create mode 100644 app/View/Components/Transfers/Script.php
create mode 100644 app/View/Components/Transfers/Show/Attachment.php
create mode 100644 app/View/Components/Transfers/Show/Buttons.php
create mode 100644 app/View/Components/Transfers/Show/Content.php
create mode 100644 app/View/Components/Transfers/Show/Create.php
create mode 100644 app/View/Components/Transfers/Show/MoreButtons.php
create mode 100644 app/View/Components/Transfers/Show/Template.php
create mode 100644 app/View/Components/Transfers/Show/Transactions.php
create mode 100644 app/View/Components/Transfers/Template/Ddefault.php
create mode 100644 app/View/Components/Transfers/Template/Second.php
create mode 100644 app/View/Components/Transfers/Template/Third.php
create mode 100644 app/View/Components/UpdateAlert.php
create mode 100644 app/View/Components/Widgets/Contact.php
create mode 100644 app/View/Components/Widgets/InvoiceHistory.php
create mode 100644 app/View/Components/Widgets/LastPayment.php
create mode 100644 app/View/Components/Widgets/LatestInvoices.php
create mode 100644 app/View/Components/Widgets/OutstandingBalance.php
create mode 100644 app/View/Components/Widgets/PaymentHistory.php
create mode 100644 app/View/Presenters/Menu.php
create mode 100644 app/Widgets/AccountBalance.php
create mode 100644 app/Widgets/BankFeeds.php
create mode 100644 app/Widgets/CashFlow.php
create mode 100644 app/Widgets/Currencies.php
create mode 100644 app/Widgets/ExpensesByCategory.php
create mode 100644 app/Widgets/Payables.php
create mode 100644 app/Widgets/ProfitLoss.php
create mode 100644 app/Widgets/Receivables.php
create mode 100644 artisan
create mode 100644 bootstrap/app.php
create mode 100644 bootstrap/autoload.php
create mode 100644 bootstrap/cache/.gitignore
create mode 100644 compose.jiangling.yml
create mode 100644 composer.json
create mode 100644 composer.lock
create mode 100644 config/apexcharts.php
create mode 100644 config/api.php
create mode 100644 config/app.php
create mode 100644 config/auth.php
create mode 100644 config/broadcasting.php
create mode 100644 config/bugsnag.php
create mode 100644 config/business_navigation.php
create mode 100644 config/cache.php
create mode 100644 config/charts.php
create mode 100644 config/cors.php
create mode 100644 config/database.php
create mode 100644 config/debugbar.php
create mode 100644 config/dompdf.php
create mode 100644 config/excel.php
create mode 100644 config/filesystems.php
create mode 100644 config/firewall.php
create mode 100644 config/hashing.php
create mode 100644 config/ide-helper.php
create mode 100644 config/image.php
create mode 100644 config/imagecache.php
create mode 100644 config/import.php
create mode 100644 config/language.php
create mode 100644 config/laratrust.php
create mode 100644 config/laravel-model-caching.php
create mode 100644 config/livewire.php
create mode 100644 config/logging.php
create mode 100644 config/mail.php
create mode 100644 config/mediable.php
create mode 100644 config/menu.php
create mode 100644 config/module.php
create mode 100644 config/money.php
create mode 100644 config/queue.php
create mode 100644 config/read-only.php
create mode 100644 config/sanctum.php
create mode 100644 config/search-string.php
create mode 100644 config/sentry.php
create mode 100644 config/services.php
create mode 100644 config/session.php
create mode 100644 config/setting.php
create mode 100644 config/sortable.php
create mode 100644 config/stats.php
create mode 100644 config/trustedproxy.php
create mode 100644 config/type.php
create mode 100644 config/update.php
create mode 100644 config/version.php
create mode 100644 config/view.php
create mode 100644 database/.gitignore
create mode 100644 database/factories/Account.php
create mode 100644 database/factories/Category.php
create mode 100644 database/factories/Company.php
create mode 100644 database/factories/Contact.php
create mode 100644 database/factories/Currency.php
create mode 100644 database/factories/Dashboard.php
create mode 100644 database/factories/Document.php
create mode 100644 database/factories/Item.php
create mode 100644 database/factories/Reconciliation.php
create mode 100644 database/factories/Tax.php
create mode 100644 database/factories/Transaction.php
create mode 100644 database/factories/Transfer.php
create mode 100644 database/factories/User.php
create mode 100644 database/factories/Widget.php
create mode 100644 database/migrations/2017_09_14_000000_core_v1.php
create mode 100644 database/migrations/2019_11_16_000000_core_v2.php
create mode 100644 database/migrations/2022_05_10_000000_core_v300.php
create mode 100644 database/migrations/2022_06_28_000000_core_v304.php
create mode 100644 database/migrations/2022_07_21_000000_core_v305.php
create mode 100644 database/migrations/2022_08_29_000000_core_v3015.php
create mode 100644 database/migrations/2022_08_29_000000_core_v307.php
create mode 100644 database/migrations/2023_06_22_000000_core_v3016.php
create mode 100644 database/migrations/2023_08_14_000000_core_v3017.php
create mode 100644 database/migrations/2023_10_03_000000_core_v310.php
create mode 100644 database/migrations/2024_09_26_000000_core_v3112.php
create mode 100644 database/migrations/2024_12_29_000000_core_v3115.php
create mode 100644 database/migrations/2026_02_17_000000_core_v3122.php
create mode 100644 database/migrations/2026_07_18_000000_create_fund_accounts_table.php
create mode 100644 database/migrations/2026_07_20_000000_create_system_settings_tables.php
create mode 100644 database/seeds/Accounts.php
create mode 100644 database/seeds/Categories.php
create mode 100644 database/seeds/Company.php
create mode 100644 database/seeds/Currencies.php
create mode 100644 database/seeds/Dashboards.php
create mode 100644 database/seeds/DatabaseSeeder.php
create mode 100644 database/seeds/EmailTemplates.php
create mode 100644 database/seeds/Modules.php
create mode 100644 database/seeds/Permissions.php
create mode 100644 database/seeds/Reports.php
create mode 100644 database/seeds/SampleData.php
create mode 100644 database/seeds/Settings.php
create mode 100644 database/seeds/TestCompany.php
create mode 100644 database/seeds/User.php
create mode 100644 deploy/Dockerfile
create mode 100644 deploy/apache-vhost.conf
create mode 100644 deploy/entrypoint.sh
create mode 100644 deploy/host-nginx.conf
create mode 100644 deploy/php.ini
create mode 100644 docs/ecommerce-finance-development.md
create mode 100644 docs/team-collaboration.md
create mode 100644 index.php
create mode 100644 manifest.json
create mode 100644 modules/.gitkeep
create mode 100644 nginx.example.com.conf
create mode 100644 overrides/Illuminate/Translation/MessageSelector.php
create mode 100644 overrides/Illuminate/View/Concerns/ManagesStacks.php
create mode 100644 overrides/akaunting/laravel-module/Commands/DeleteCommand.php
create mode 100644 overrides/akaunting/laravel-module/Commands/DisableCommand.php
create mode 100644 overrides/akaunting/laravel-module/Commands/EnableCommand.php
create mode 100644 overrides/akaunting/laravel-module/Commands/InstallCommand.php
create mode 100644 overrides/livewire/livewire/Mechanisms/HandleRequests/HandleRequests.php
create mode 100644 overrides/maatwebsite/excel/Fakes/ExcelFake.php
create mode 100644 overrides/maatwebsite/excel/Fakes/fake_file
create mode 100644 overrides/maatwebsite/excel/QueuedWriter.php
create mode 100644 overrides/symfony/process/PhpExecutableFinder.php
create mode 100644 package-lock.json
create mode 100644 package.json
create mode 100644 phpunit.xml
create mode 100644 presets.js
create mode 100644 public/.htaccess
create mode 100644 public/akaunting-js/generalAction.js
create mode 100644 public/akaunting-js/hotkeys.js
create mode 100644 public/akaunting-js/popper.js
create mode 100644 public/akaunting-js/swiper-bundle.min.js
create mode 100644 public/css/app.css
create mode 100644 public/css/custom_loading.css
create mode 100644 public/css/element.css
create mode 100644 public/css/fonts/NotoSansArabic.ttf
create mode 100644 public/css/fonts/element-icons.ttf
create mode 100644 public/css/fonts/element-icons.woff
create mode 100644 public/css/fonts/firefly_sung_normal.ttf
create mode 100644 public/css/fonts/material-icons/Outlined/MaterialIconsOutlined-Regular.eot
create mode 100644 public/css/fonts/material-icons/Outlined/MaterialIconsOutlined-Regular.otf
create mode 100644 public/css/fonts/material-icons/Outlined/MaterialIconsOutlined-Regular.ttf
create mode 100644 public/css/fonts/material-icons/Outlined/MaterialIconsOutlined-Regular.woff
create mode 100644 public/css/fonts/material-icons/Outlined/MaterialIconsOutlined-Regular.woff2
create mode 100644 public/css/fonts/material-icons/Regular/MaterialIcons-Regular.eot
create mode 100644 public/css/fonts/material-icons/Regular/MaterialIcons-Regular.otf
create mode 100644 public/css/fonts/material-icons/Regular/MaterialIcons-Regular.ttf
create mode 100644 public/css/fonts/material-icons/Regular/MaterialIcons-Regular.woff
create mode 100644 public/css/fonts/material-icons/Regular/MaterialIcons-Regular.woff2
create mode 100644 public/css/fonts/material-icons/Rounded/MaterialIconsRound-Regular.eot
create mode 100644 public/css/fonts/material-icons/Rounded/MaterialIconsRound-Regular.otf
create mode 100644 public/css/fonts/material-icons/Rounded/MaterialIconsRound-Regular.ttf
create mode 100644 public/css/fonts/material-icons/Rounded/MaterialIconsRound-Regular.woff
create mode 100644 public/css/fonts/material-icons/Rounded/MaterialIconsRound-Regular.woff2
create mode 100644 public/css/fonts/material-icons/Sharp/MaterialIconsSharp-Regular.eot
create mode 100644 public/css/fonts/material-icons/Sharp/MaterialIconsSharp-Regular.otf
create mode 100644 public/css/fonts/material-icons/Sharp/MaterialIconsSharp-Regular.ttf
create mode 100644 public/css/fonts/material-icons/Sharp/MaterialIconsSharp-Regular.woff
create mode 100644 public/css/fonts/material-icons/Sharp/MaterialIconsSharp-Regular.woff2
create mode 100644 public/css/fonts/material-icons/style.css
create mode 100644 public/css/print.css
create mode 100644 public/css/third_party/dropzone_custom.css
create mode 100644 public/css/third_party/swiper-bundle.min.css
create mode 100644 public/css/third_party/vue-html-editor.css
create mode 100644 public/css/third_party/vue-html-editor_custom.css
create mode 100644 public/files/import/bills.xlsx
create mode 100644 public/files/import/categories.xlsx
create mode 100644 public/files/import/customers.xlsx
create mode 100644 public/files/import/invoices.xlsx
create mode 100644 public/files/import/items.xlsx
create mode 100644 public/files/import/recurring-bills.xlsx
create mode 100644 public/files/import/recurring-invoices.xlsx
create mode 100644 public/files/import/recurring-transactions.xlsx
create mode 100644 public/files/import/taxes.xlsx
create mode 100644 public/files/import/transactions.xlsx
create mode 100644 public/files/import/transfers.xlsx
create mode 100644 public/files/import/vendors.xlsx
create mode 100644 public/fonts/MaterialIcons-Regular.eot
create mode 100644 public/fonts/MaterialIcons-Regular.ttf
create mode 100644 public/fonts/MaterialIcons-Regular.woff
create mode 100644 public/fonts/MaterialIcons-Regular.woff2
create mode 100644 public/img/akaunting-loading.gif
create mode 100644 public/img/akaunting-logo-gold.png
create mode 100644 public/img/akaunting-logo-green.svg
create mode 100644 public/img/akaunting-logo-horizontal.svg
create mode 100644 public/img/akaunting-logo-purple.svg
create mode 100644 public/img/akaunting-logo-white.svg
create mode 100644 public/img/akaunting-logo-wild-blue.png
create mode 100644 public/img/auth/bullet_active.png
create mode 100644 public/img/auth/bullet_inactive.png
create mode 100644 public/img/auth/chart.png
create mode 100644 public/img/auth/client.png
create mode 100644 public/img/auth/folder.png
create mode 100644 public/img/auth/layout.png
create mode 100644 public/img/auth/login-bg.png
create mode 100644 public/img/auth/logo.png
create mode 100644 public/img/auth/small-logo.png
create mode 100644 public/img/company.png
create mode 100644 public/img/credit_card/amex.png
create mode 100644 public/img/credit_card/chip.png
create mode 100644 public/img/credit_card/dinersclub.png
create mode 100644 public/img/credit_card/discover.png
create mode 100644 public/img/credit_card/jcb.png
create mode 100644 public/img/credit_card/mastercard.png
create mode 100644 public/img/credit_card/troy.png
create mode 100644 public/img/credit_card/unionpay.png
create mode 100644 public/img/credit_card/visa.png
create mode 100644 public/img/dashboard.png
create mode 100644 public/img/empty_pages/bills.png
create mode 100644 public/img/empty_pages/companies.png
create mode 100644 public/img/empty_pages/contacs.png
create mode 100644 public/img/empty_pages/customers.png
create mode 100644 public/img/empty_pages/default.png
create mode 100644 public/img/empty_pages/invoices.png
create mode 100644 public/img/empty_pages/items.png
create mode 100644 public/img/empty_pages/no-apps.png
create mode 100644 public/img/empty_pages/payments.png
create mode 100644 public/img/empty_pages/reconciliations.png
create mode 100644 public/img/empty_pages/recurring_templates.png
create mode 100644 public/img/empty_pages/revenues.png
create mode 100644 public/img/empty_pages/subscriptions.png
create mode 100644 public/img/empty_pages/taxes.png
create mode 100644 public/img/empty_pages/tickets.png
create mode 100644 public/img/empty_pages/transactions.png
create mode 100644 public/img/empty_pages/transfers.png
create mode 100644 public/img/empty_pages/users.png
create mode 100644 public/img/empty_pages/vendors.png
create mode 100644 public/img/errors/403.png
create mode 100644 public/img/errors/404.png
create mode 100644 public/img/errors/500.png
create mode 100644 public/img/favicon.ico
create mode 100644 public/img/icons/.gitkeep
create mode 100644 public/img/import.png
create mode 100644 public/img/invoice_templates/classic.png
create mode 100644 public/img/invoice_templates/default.png
create mode 100644 public/img/invoice_templates/modern.png
create mode 100644 public/img/no_records/accounts_transactions.png
create mode 100644 public/img/no_records/accounts_transfers.png
create mode 100644 public/img/no_records/customers_invoices.png
create mode 100644 public/img/no_records/customers_transactions.png
create mode 100644 public/img/no_records/vendors_bills.png
create mode 100644 public/img/no_records/vendors_transactions.png
create mode 100644 public/img/pwa/icon-192x192-maskable.png
create mode 100644 public/img/pwa/icon-192x192.png
create mode 100644 public/img/pwa/icon-512x512-maskable.png
create mode 100644 public/img/pwa/icon-512x512.png
create mode 100644 public/img/pwa/screenshot-dashboard.png
create mode 100644 public/img/pwa/screenshot-invoice.png
create mode 100644 public/img/pwa/splash-1242x2208.png
create mode 100644 public/img/pwa/splash-1242x2688.png
create mode 100644 public/img/pwa/splash-1536x2048.png
create mode 100644 public/img/pwa/splash-1668x2224.png
create mode 100644 public/img/pwa/splash-1668x2388.png
create mode 100644 public/img/pwa/splash-2048x2732.png
create mode 100644 public/img/pwa/splash-640x1136.png
create mode 100644 public/img/pwa/splash-750x1334.png
create mode 100644 public/img/pwa/splash-828x1792.png
create mode 100644 public/img/tailwind_icons/not-equal.svg
create mode 100644 public/img/transfer_templates/default.png
create mode 100644 public/img/transfer_templates/second.png
create mode 100644 public/img/transfer_templates/third.png
create mode 100644 public/img/user.svg
create mode 100644 public/img/wizard-modules.png
create mode 100644 public/img/wizard-rocket.gif
create mode 100644 public/index.php
create mode 100644 public/money.json
create mode 100644 public/shortcuts-config.json
create mode 100644 resources/assets/css/creditcard/style.scss
create mode 100644 resources/assets/js/Install.vue
create mode 100644 resources/assets/js/Wizard.vue
create mode 100644 resources/assets/js/bootstrap.js
create mode 100644 resources/assets/js/components/AkauntingColor.vue
create mode 100644 resources/assets/js/components/AkauntingCompanyEdit.vue
create mode 100644 resources/assets/js/components/AkauntingConnectTransactions.vue
create mode 100644 resources/assets/js/components/AkauntingContactCard.vue
create mode 100644 resources/assets/js/components/AkauntingCountdown.vue
create mode 100644 resources/assets/js/components/AkauntingCurrencyConversion.vue
create mode 100644 resources/assets/js/components/AkauntingDate.vue
create mode 100644 resources/assets/js/components/AkauntingDocumentButton.vue
create mode 100644 resources/assets/js/components/AkauntingDropzoneFileUpload.vue
create mode 100644 resources/assets/js/components/AkauntingEditItemColumns.vue
create mode 100644 resources/assets/js/components/AkauntingHtmlEditor.vue
create mode 100644 resources/assets/js/components/AkauntingImport.vue
create mode 100644 resources/assets/js/components/AkauntingItemButton.vue
create mode 100644 resources/assets/js/components/AkauntingModal.vue
create mode 100644 resources/assets/js/components/AkauntingModalAddNew.vue
create mode 100644 resources/assets/js/components/AkauntingMoney.vue
create mode 100644 resources/assets/js/components/AkauntingRadioGroup.vue
create mode 100644 resources/assets/js/components/AkauntingRecurring.vue
create mode 100644 resources/assets/js/components/AkauntingSearch.vue
create mode 100644 resources/assets/js/components/AkauntingSelect.vue
create mode 100644 resources/assets/js/components/AkauntingSelectRemote.vue
create mode 100644 resources/assets/js/components/AkauntingSlider.vue
create mode 100644 resources/assets/js/components/AkauntingSwitch.vue
create mode 100644 resources/assets/js/components/AkauntingWidget.vue
create mode 100644 resources/assets/js/components/Badge.vue
create mode 100644 resources/assets/js/components/BaseAlert.vue
create mode 100644 resources/assets/js/components/BaseButton.vue
create mode 100644 resources/assets/js/components/Cards/Card.vue
create mode 100644 resources/assets/js/components/Cards/StatsCard.vue
create mode 100644 resources/assets/js/components/CreditCard/Card.vue
create mode 100644 resources/assets/js/components/CreditCard/CardForm.vue
create mode 100644 resources/assets/js/components/Inputs/BaseInput.vue
create mode 100644 resources/assets/js/components/Modal.vue
create mode 100644 resources/assets/js/components/NotificationPlugin/Notification.vue
create mode 100644 resources/assets/js/components/NotificationPlugin/Notifications.vue
create mode 100644 resources/assets/js/components/NotificationPlugin/index.js
create mode 100644 resources/assets/js/components/SearchString/FilterMain.vue
create mode 100644 resources/assets/js/components/SearchString/FilteredList.vue
create mode 100644 resources/assets/js/components/SearchString/Filters.vue
create mode 100644 resources/assets/js/components/SearchString/SearchString.vue
create mode 100644 resources/assets/js/directives/click-ouside.js
create mode 100644 resources/assets/js/exceptions/trackers/bugsnag.js
create mode 100644 resources/assets/js/exceptions/trackers/sentry.js
create mode 100644 resources/assets/js/install.js
create mode 100644 resources/assets/js/mixins/global.js
create mode 100644 resources/assets/js/mixins/wizardAction.js
create mode 100644 resources/assets/js/plugins/bulk-action.js
create mode 100644 resources/assets/js/plugins/currency.js
create mode 100644 resources/assets/js/plugins/dashboard-plugin.js
create mode 100644 resources/assets/js/plugins/error.js
create mode 100644 resources/assets/js/plugins/form.js
create mode 100644 resources/assets/js/plugins/functions.js
create mode 100644 resources/assets/js/plugins/globalComponents.js
create mode 100644 resources/assets/js/plugins/globalDirectives.js
create mode 100644 resources/assets/js/plugins/money.js
create mode 100644 resources/assets/js/plugins/nprogress-axios.js
create mode 100644 resources/assets/js/polyfills.js
create mode 100644 resources/assets/js/views/auth/common.js
create mode 100644 resources/assets/js/views/auth/users.js
create mode 100644 resources/assets/js/views/banking/accounts.js
create mode 100644 resources/assets/js/views/banking/reconciliations.js
create mode 100644 resources/assets/js/views/banking/transactions.js
create mode 100644 resources/assets/js/views/banking/transfers.js
create mode 100644 resources/assets/js/views/common/companies.js
create mode 100644 resources/assets/js/views/common/contacts.js
create mode 100644 resources/assets/js/views/common/dashboards.js
create mode 100644 resources/assets/js/views/common/documents.js
create mode 100644 resources/assets/js/views/common/imports.js
create mode 100644 resources/assets/js/views/common/items.js
create mode 100644 resources/assets/js/views/common/reports.js
create mode 100644 resources/assets/js/views/install/Database.vue
create mode 100644 resources/assets/js/views/install/Language.vue
create mode 100644 resources/assets/js/views/install/Requirements.vue
create mode 100644 resources/assets/js/views/install/Settings.vue
create mode 100644 resources/assets/js/views/install/Steps.vue
create mode 100644 resources/assets/js/views/install/update.js
create mode 100644 resources/assets/js/views/modules/apps.js
create mode 100644 resources/assets/js/views/portal/apps.js
create mode 100644 resources/assets/js/views/settings/categories.js
create mode 100644 resources/assets/js/views/settings/currencies.js
create mode 100644 resources/assets/js/views/settings/settings.js
create mode 100644 resources/assets/js/views/settings/taxes.js
create mode 100644 resources/assets/js/views/wizard/Company.vue
create mode 100644 resources/assets/js/views/wizard/Currencies.vue
create mode 100644 resources/assets/js/views/wizard/Finish.vue
create mode 100644 resources/assets/js/views/wizard/Steps.vue
create mode 100644 resources/assets/js/wizard.js
create mode 100644 resources/assets/sass/app.css
create mode 100644 resources/lang/ar-SA/accounts.php
create mode 100644 resources/lang/ar-SA/auth.php
create mode 100644 resources/lang/ar-SA/bills.php
create mode 100644 resources/lang/ar-SA/bulk_actions.php
create mode 100644 resources/lang/ar-SA/categories.php
create mode 100644 resources/lang/ar-SA/companies.php
create mode 100644 resources/lang/ar-SA/countries.php
create mode 100644 resources/lang/ar-SA/currencies.php
create mode 100644 resources/lang/ar-SA/customers.php
create mode 100644 resources/lang/ar-SA/dashboards.php
create mode 100644 resources/lang/ar-SA/demo.php
create mode 100644 resources/lang/ar-SA/documents.php
create mode 100644 resources/lang/ar-SA/email_templates.php
create mode 100644 resources/lang/ar-SA/errors.php
create mode 100644 resources/lang/ar-SA/footer.php
create mode 100644 resources/lang/ar-SA/general.php
create mode 100644 resources/lang/ar-SA/header.php
create mode 100644 resources/lang/ar-SA/import.php
create mode 100644 resources/lang/ar-SA/install.php
create mode 100644 resources/lang/ar-SA/invoices.php
create mode 100644 resources/lang/ar-SA/items.php
create mode 100644 resources/lang/ar-SA/maintenance.php
create mode 100644 resources/lang/ar-SA/messages.php
create mode 100644 resources/lang/ar-SA/modules.php
create mode 100644 resources/lang/ar-SA/notifications.php
create mode 100644 resources/lang/ar-SA/pagination.php
create mode 100644 resources/lang/ar-SA/passwords.php
create mode 100644 resources/lang/ar-SA/portal.php
create mode 100644 resources/lang/ar-SA/reconciliations.php
create mode 100644 resources/lang/ar-SA/recurring.php
create mode 100644 resources/lang/ar-SA/reports.php
create mode 100644 resources/lang/ar-SA/search_string.php
create mode 100644 resources/lang/ar-SA/settings.php
create mode 100644 resources/lang/ar-SA/taxes.php
create mode 100644 resources/lang/ar-SA/transactions.php
create mode 100644 resources/lang/ar-SA/transfers.php
create mode 100644 resources/lang/ar-SA/updates.php
create mode 100644 resources/lang/ar-SA/validation.php
create mode 100644 resources/lang/ar-SA/vendors.php
create mode 100644 resources/lang/ar-SA/widgets.php
create mode 100644 resources/lang/az-AZ/accounts.php
create mode 100644 resources/lang/az-AZ/auth.php
create mode 100644 resources/lang/az-AZ/bills.php
create mode 100644 resources/lang/az-AZ/bulk_actions.php
create mode 100644 resources/lang/az-AZ/companies.php
create mode 100644 resources/lang/az-AZ/countries.php
create mode 100644 resources/lang/az-AZ/currencies.php
create mode 100644 resources/lang/az-AZ/customers.php
create mode 100644 resources/lang/az-AZ/dashboards.php
create mode 100644 resources/lang/az-AZ/demo.php
create mode 100644 resources/lang/az-AZ/documents.php
create mode 100644 resources/lang/az-AZ/email_templates.php
create mode 100644 resources/lang/az-AZ/errors.php
create mode 100644 resources/lang/az-AZ/footer.php
create mode 100644 resources/lang/az-AZ/general.php
create mode 100644 resources/lang/az-AZ/header.php
create mode 100644 resources/lang/az-AZ/import.php
create mode 100644 resources/lang/az-AZ/install.php
create mode 100644 resources/lang/az-AZ/invoices.php
create mode 100644 resources/lang/az-AZ/items.php
create mode 100644 resources/lang/az-AZ/maintenance.php
create mode 100644 resources/lang/az-AZ/messages.php
create mode 100644 resources/lang/az-AZ/modules.php
create mode 100644 resources/lang/az-AZ/notifications.php
create mode 100644 resources/lang/az-AZ/pagination.php
create mode 100644 resources/lang/az-AZ/passwords.php
create mode 100644 resources/lang/az-AZ/payments.php
create mode 100644 resources/lang/az-AZ/reconciliations.php
create mode 100644 resources/lang/az-AZ/recurring.php
create mode 100644 resources/lang/az-AZ/reports.php
create mode 100644 resources/lang/az-AZ/search_string.php
create mode 100644 resources/lang/az-AZ/settings.php
create mode 100644 resources/lang/az-AZ/taxes.php
create mode 100644 resources/lang/az-AZ/transfers.php
create mode 100644 resources/lang/az-AZ/updates.php
create mode 100644 resources/lang/az-AZ/validation.php
create mode 100644 resources/lang/az-AZ/widgets.php
create mode 100644 resources/lang/bg-BG/accounts.php
create mode 100644 resources/lang/bg-BG/auth.php
create mode 100644 resources/lang/bg-BG/bills.php
create mode 100644 resources/lang/bg-BG/bulk_actions.php
create mode 100644 resources/lang/bg-BG/categories.php
create mode 100644 resources/lang/bg-BG/companies.php
create mode 100644 resources/lang/bg-BG/countries.php
create mode 100644 resources/lang/bg-BG/currencies.php
create mode 100644 resources/lang/bg-BG/customers.php
create mode 100644 resources/lang/bg-BG/dashboards.php
create mode 100644 resources/lang/bg-BG/demo.php
create mode 100644 resources/lang/bg-BG/documents.php
create mode 100644 resources/lang/bg-BG/email_templates.php
create mode 100644 resources/lang/bg-BG/errors.php
create mode 100644 resources/lang/bg-BG/footer.php
create mode 100644 resources/lang/bg-BG/general.php
create mode 100644 resources/lang/bg-BG/header.php
create mode 100644 resources/lang/bg-BG/import.php
create mode 100644 resources/lang/bg-BG/install.php
create mode 100644 resources/lang/bg-BG/invoices.php
create mode 100644 resources/lang/bg-BG/items.php
create mode 100644 resources/lang/bg-BG/maintenance.php
create mode 100644 resources/lang/bg-BG/messages.php
create mode 100644 resources/lang/bg-BG/modules.php
create mode 100644 resources/lang/bg-BG/notifications.php
create mode 100644 resources/lang/bg-BG/pagination.php
create mode 100644 resources/lang/bg-BG/passwords.php
create mode 100644 resources/lang/bg-BG/portal.php
create mode 100644 resources/lang/bg-BG/reconciliations.php
create mode 100644 resources/lang/bg-BG/recurring.php
create mode 100644 resources/lang/bg-BG/reports.php
create mode 100644 resources/lang/bg-BG/search_string.php
create mode 100644 resources/lang/bg-BG/settings.php
create mode 100644 resources/lang/bg-BG/taxes.php
create mode 100644 resources/lang/bg-BG/transactions.php
create mode 100644 resources/lang/bg-BG/transfers.php
create mode 100644 resources/lang/bg-BG/updates.php
create mode 100644 resources/lang/bg-BG/validation.php
create mode 100644 resources/lang/bg-BG/vendors.php
create mode 100644 resources/lang/bg-BG/widgets.php
create mode 100644 resources/lang/bn-BD/accounts.php
create mode 100644 resources/lang/bn-BD/auth.php
create mode 100644 resources/lang/bn-BD/bills.php
create mode 100644 resources/lang/bn-BD/bulk_actions.php
create mode 100644 resources/lang/bn-BD/companies.php
create mode 100644 resources/lang/bn-BD/countries.php
create mode 100644 resources/lang/bn-BD/currencies.php
create mode 100644 resources/lang/bn-BD/customers.php
create mode 100644 resources/lang/bn-BD/dashboards.php
create mode 100644 resources/lang/bn-BD/demo.php
create mode 100644 resources/lang/bn-BD/email_templates.php
create mode 100644 resources/lang/bn-BD/errors.php
create mode 100644 resources/lang/bn-BD/footer.php
create mode 100644 resources/lang/bn-BD/general.php
create mode 100644 resources/lang/bn-BD/header.php
create mode 100644 resources/lang/bn-BD/import.php
create mode 100644 resources/lang/bn-BD/install.php
create mode 100644 resources/lang/bn-BD/invoices.php
create mode 100644 resources/lang/bn-BD/items.php
create mode 100644 resources/lang/bn-BD/maintenance.php
create mode 100644 resources/lang/bn-BD/messages.php
create mode 100644 resources/lang/bn-BD/modules.php
create mode 100644 resources/lang/bn-BD/notifications.php
create mode 100644 resources/lang/bn-BD/pagination.php
create mode 100644 resources/lang/bn-BD/passwords.php
create mode 100644 resources/lang/bn-BD/reconciliations.php
create mode 100644 resources/lang/bn-BD/recurring.php
create mode 100644 resources/lang/bn-BD/reports.php
create mode 100644 resources/lang/bn-BD/settings.php
create mode 100644 resources/lang/bn-BD/taxes.php
create mode 100644 resources/lang/bn-BD/transfers.php
create mode 100644 resources/lang/bn-BD/updates.php
create mode 100644 resources/lang/bn-BD/validation.php
create mode 100644 resources/lang/bn-BD/widgets.php
create mode 100644 resources/lang/bs-BA/accounts.php
create mode 100644 resources/lang/bs-BA/auth.php
create mode 100644 resources/lang/bs-BA/bills.php
create mode 100644 resources/lang/bs-BA/bulk_actions.php
create mode 100644 resources/lang/bs-BA/categories.php
create mode 100644 resources/lang/bs-BA/companies.php
create mode 100644 resources/lang/bs-BA/countries.php
create mode 100644 resources/lang/bs-BA/currencies.php
create mode 100644 resources/lang/bs-BA/customers.php
create mode 100644 resources/lang/bs-BA/dashboards.php
create mode 100644 resources/lang/bs-BA/demo.php
create mode 100644 resources/lang/bs-BA/documents.php
create mode 100644 resources/lang/bs-BA/email_templates.php
create mode 100644 resources/lang/bs-BA/errors.php
create mode 100644 resources/lang/bs-BA/footer.php
create mode 100644 resources/lang/bs-BA/general.php
create mode 100644 resources/lang/bs-BA/header.php
create mode 100644 resources/lang/bs-BA/import.php
create mode 100644 resources/lang/bs-BA/install.php
create mode 100644 resources/lang/bs-BA/invoices.php
create mode 100644 resources/lang/bs-BA/items.php
create mode 100644 resources/lang/bs-BA/maintenance.php
create mode 100644 resources/lang/bs-BA/messages.php
create mode 100644 resources/lang/bs-BA/modules.php
create mode 100644 resources/lang/bs-BA/notifications.php
create mode 100644 resources/lang/bs-BA/pagination.php
create mode 100644 resources/lang/bs-BA/passwords.php
create mode 100644 resources/lang/bs-BA/payments.php
create mode 100644 resources/lang/bs-BA/portal.php
create mode 100644 resources/lang/bs-BA/reconciliations.php
create mode 100644 resources/lang/bs-BA/recurring.php
create mode 100644 resources/lang/bs-BA/reports.php
create mode 100644 resources/lang/bs-BA/revenues.php
create mode 100644 resources/lang/bs-BA/search_string.php
create mode 100644 resources/lang/bs-BA/settings.php
create mode 100644 resources/lang/bs-BA/taxes.php
create mode 100644 resources/lang/bs-BA/transactions.php
create mode 100644 resources/lang/bs-BA/transfers.php
create mode 100644 resources/lang/bs-BA/updates.php
create mode 100644 resources/lang/bs-BA/validation.php
create mode 100644 resources/lang/bs-BA/vendors.php
create mode 100644 resources/lang/bs-BA/widgets.php
create mode 100644 resources/lang/ca-ES/accounts.php
create mode 100644 resources/lang/ca-ES/auth.php
create mode 100644 resources/lang/ca-ES/bills.php
create mode 100644 resources/lang/ca-ES/bulk_actions.php
create mode 100644 resources/lang/ca-ES/categories.php
create mode 100644 resources/lang/ca-ES/companies.php
create mode 100644 resources/lang/ca-ES/countries.php
create mode 100644 resources/lang/ca-ES/currencies.php
create mode 100644 resources/lang/ca-ES/customers.php
create mode 100644 resources/lang/ca-ES/dashboards.php
create mode 100644 resources/lang/ca-ES/demo.php
create mode 100644 resources/lang/ca-ES/documents.php
create mode 100644 resources/lang/ca-ES/email_templates.php
create mode 100644 resources/lang/ca-ES/errors.php
create mode 100644 resources/lang/ca-ES/footer.php
create mode 100644 resources/lang/ca-ES/general.php
create mode 100644 resources/lang/ca-ES/header.php
create mode 100644 resources/lang/ca-ES/import.php
create mode 100644 resources/lang/ca-ES/install.php
create mode 100644 resources/lang/ca-ES/invoices.php
create mode 100644 resources/lang/ca-ES/items.php
create mode 100644 resources/lang/ca-ES/maintenance.php
create mode 100644 resources/lang/ca-ES/messages.php
create mode 100644 resources/lang/ca-ES/modules.php
create mode 100644 resources/lang/ca-ES/notifications.php
create mode 100644 resources/lang/ca-ES/pagination.php
create mode 100644 resources/lang/ca-ES/passwords.php
create mode 100644 resources/lang/ca-ES/payments.php
create mode 100644 resources/lang/ca-ES/portal.php
create mode 100644 resources/lang/ca-ES/reconciliations.php
create mode 100644 resources/lang/ca-ES/recurring.php
create mode 100644 resources/lang/ca-ES/reports.php
create mode 100644 resources/lang/ca-ES/revenues.php
create mode 100644 resources/lang/ca-ES/search_string.php
create mode 100644 resources/lang/ca-ES/settings.php
create mode 100644 resources/lang/ca-ES/taxes.php
create mode 100644 resources/lang/ca-ES/transactions.php
create mode 100644 resources/lang/ca-ES/transfers.php
create mode 100644 resources/lang/ca-ES/updates.php
create mode 100644 resources/lang/ca-ES/validation.php
create mode 100644 resources/lang/ca-ES/vendors.php
create mode 100644 resources/lang/ca-ES/widgets.php
create mode 100644 resources/lang/cs-CZ/accounts.php
create mode 100644 resources/lang/cs-CZ/auth.php
create mode 100644 resources/lang/cs-CZ/bills.php
create mode 100644 resources/lang/cs-CZ/bulk_actions.php
create mode 100644 resources/lang/cs-CZ/categories.php
create mode 100644 resources/lang/cs-CZ/companies.php
create mode 100644 resources/lang/cs-CZ/countries.php
create mode 100644 resources/lang/cs-CZ/currencies.php
create mode 100644 resources/lang/cs-CZ/customers.php
create mode 100644 resources/lang/cs-CZ/dashboard.php
create mode 100644 resources/lang/cs-CZ/dashboards.php
create mode 100644 resources/lang/cs-CZ/demo.php
create mode 100644 resources/lang/cs-CZ/documents.php
create mode 100644 resources/lang/cs-CZ/email_templates.php
create mode 100644 resources/lang/cs-CZ/errors.php
create mode 100644 resources/lang/cs-CZ/footer.php
create mode 100644 resources/lang/cs-CZ/general.php
create mode 100644 resources/lang/cs-CZ/header.php
create mode 100644 resources/lang/cs-CZ/import.php
create mode 100644 resources/lang/cs-CZ/install.php
create mode 100644 resources/lang/cs-CZ/invoices.php
create mode 100644 resources/lang/cs-CZ/items.php
create mode 100644 resources/lang/cs-CZ/maintenance.php
create mode 100644 resources/lang/cs-CZ/messages.php
create mode 100644 resources/lang/cs-CZ/modules.php
create mode 100644 resources/lang/cs-CZ/notifications.php
create mode 100644 resources/lang/cs-CZ/pagination.php
create mode 100644 resources/lang/cs-CZ/passwords.php
create mode 100644 resources/lang/cs-CZ/portal.php
create mode 100644 resources/lang/cs-CZ/reconciliations.php
create mode 100644 resources/lang/cs-CZ/recurring.php
create mode 100644 resources/lang/cs-CZ/reports.php
create mode 100644 resources/lang/cs-CZ/search_string.php
create mode 100644 resources/lang/cs-CZ/settings.php
create mode 100644 resources/lang/cs-CZ/taxes.php
create mode 100644 resources/lang/cs-CZ/transactions.php
create mode 100644 resources/lang/cs-CZ/transfers.php
create mode 100644 resources/lang/cs-CZ/updates.php
create mode 100644 resources/lang/cs-CZ/validation.php
create mode 100644 resources/lang/cs-CZ/vendors.php
create mode 100644 resources/lang/cs-CZ/widgets.php
create mode 100644 resources/lang/da-DK/accounts.php
create mode 100644 resources/lang/da-DK/auth.php
create mode 100644 resources/lang/da-DK/bills.php
create mode 100644 resources/lang/da-DK/bulk_actions.php
create mode 100644 resources/lang/da-DK/categories.php
create mode 100644 resources/lang/da-DK/companies.php
create mode 100644 resources/lang/da-DK/countries.php
create mode 100644 resources/lang/da-DK/currencies.php
create mode 100644 resources/lang/da-DK/customers.php
create mode 100644 resources/lang/da-DK/dashboards.php
create mode 100644 resources/lang/da-DK/demo.php
create mode 100644 resources/lang/da-DK/documents.php
create mode 100644 resources/lang/da-DK/email_templates.php
create mode 100644 resources/lang/da-DK/errors.php
create mode 100644 resources/lang/da-DK/footer.php
create mode 100644 resources/lang/da-DK/general.php
create mode 100644 resources/lang/da-DK/header.php
create mode 100644 resources/lang/da-DK/import.php
create mode 100644 resources/lang/da-DK/install.php
create mode 100644 resources/lang/da-DK/invoices.php
create mode 100644 resources/lang/da-DK/items.php
create mode 100644 resources/lang/da-DK/maintenance.php
create mode 100644 resources/lang/da-DK/messages.php
create mode 100644 resources/lang/da-DK/modules.php
create mode 100644 resources/lang/da-DK/notifications.php
create mode 100644 resources/lang/da-DK/pagination.php
create mode 100644 resources/lang/da-DK/passwords.php
create mode 100644 resources/lang/da-DK/payments.php
create mode 100644 resources/lang/da-DK/portal.php
create mode 100644 resources/lang/da-DK/reconciliations.php
create mode 100644 resources/lang/da-DK/recurring.php
create mode 100644 resources/lang/da-DK/reports.php
create mode 100644 resources/lang/da-DK/revenues.php
create mode 100644 resources/lang/da-DK/search_string.php
create mode 100644 resources/lang/da-DK/settings.php
create mode 100644 resources/lang/da-DK/taxes.php
create mode 100644 resources/lang/da-DK/transfers.php
create mode 100644 resources/lang/da-DK/updates.php
create mode 100644 resources/lang/da-DK/validation.php
create mode 100644 resources/lang/da-DK/widgets.php
create mode 100644 resources/lang/de-DE/accounts.php
create mode 100644 resources/lang/de-DE/auth.php
create mode 100644 resources/lang/de-DE/bills.php
create mode 100644 resources/lang/de-DE/bulk_actions.php
create mode 100644 resources/lang/de-DE/categories.php
create mode 100644 resources/lang/de-DE/companies.php
create mode 100644 resources/lang/de-DE/countries.php
create mode 100644 resources/lang/de-DE/currencies.php
create mode 100644 resources/lang/de-DE/customers.php
create mode 100644 resources/lang/de-DE/dashboards.php
create mode 100644 resources/lang/de-DE/demo.php
create mode 100644 resources/lang/de-DE/documents.php
create mode 100644 resources/lang/de-DE/email_templates.php
create mode 100644 resources/lang/de-DE/errors.php
create mode 100644 resources/lang/de-DE/footer.php
create mode 100644 resources/lang/de-DE/general.php
create mode 100644 resources/lang/de-DE/header.php
create mode 100644 resources/lang/de-DE/import.php
create mode 100644 resources/lang/de-DE/install.php
create mode 100644 resources/lang/de-DE/invoices.php
create mode 100644 resources/lang/de-DE/items.php
create mode 100644 resources/lang/de-DE/maintenance.php
create mode 100644 resources/lang/de-DE/messages.php
create mode 100644 resources/lang/de-DE/modules.php
create mode 100644 resources/lang/de-DE/notifications.php
create mode 100644 resources/lang/de-DE/pagination.php
create mode 100644 resources/lang/de-DE/passwords.php
create mode 100644 resources/lang/de-DE/portal.php
create mode 100644 resources/lang/de-DE/reconciliations.php
create mode 100644 resources/lang/de-DE/recurring.php
create mode 100644 resources/lang/de-DE/reports.php
create mode 100644 resources/lang/de-DE/search_string.php
create mode 100644 resources/lang/de-DE/settings.php
create mode 100644 resources/lang/de-DE/taxes.php
create mode 100644 resources/lang/de-DE/transactions.php
create mode 100644 resources/lang/de-DE/transfers.php
create mode 100644 resources/lang/de-DE/updates.php
create mode 100644 resources/lang/de-DE/validation.php
create mode 100644 resources/lang/de-DE/vendors.php
create mode 100644 resources/lang/de-DE/widgets.php
create mode 100644 resources/lang/el-GR/accounts.php
create mode 100644 resources/lang/el-GR/auth.php
create mode 100644 resources/lang/el-GR/bills.php
create mode 100644 resources/lang/el-GR/bulk_actions.php
create mode 100644 resources/lang/el-GR/categories.php
create mode 100644 resources/lang/el-GR/companies.php
create mode 100644 resources/lang/el-GR/countries.php
create mode 100644 resources/lang/el-GR/currencies.php
create mode 100644 resources/lang/el-GR/customers.php
create mode 100644 resources/lang/el-GR/dashboards.php
create mode 100644 resources/lang/el-GR/demo.php
create mode 100644 resources/lang/el-GR/documents.php
create mode 100644 resources/lang/el-GR/email_templates.php
create mode 100644 resources/lang/el-GR/errors.php
create mode 100644 resources/lang/el-GR/footer.php
create mode 100644 resources/lang/el-GR/general.php
create mode 100644 resources/lang/el-GR/header.php
create mode 100644 resources/lang/el-GR/import.php
create mode 100644 resources/lang/el-GR/install.php
create mode 100644 resources/lang/el-GR/invoices.php
create mode 100644 resources/lang/el-GR/items.php
create mode 100644 resources/lang/el-GR/maintenance.php
create mode 100644 resources/lang/el-GR/messages.php
create mode 100644 resources/lang/el-GR/modules.php
create mode 100644 resources/lang/el-GR/notifications.php
create mode 100644 resources/lang/el-GR/pagination.php
create mode 100644 resources/lang/el-GR/passwords.php
create mode 100644 resources/lang/el-GR/portal.php
create mode 100644 resources/lang/el-GR/reconciliations.php
create mode 100644 resources/lang/el-GR/recurring.php
create mode 100644 resources/lang/el-GR/reports.php
create mode 100644 resources/lang/el-GR/search_string.php
create mode 100644 resources/lang/el-GR/settings.php
create mode 100644 resources/lang/el-GR/taxes.php
create mode 100644 resources/lang/el-GR/transactions.php
create mode 100644 resources/lang/el-GR/transfers.php
create mode 100644 resources/lang/el-GR/updates.php
create mode 100644 resources/lang/el-GR/validation.php
create mode 100644 resources/lang/el-GR/vendors.php
create mode 100644 resources/lang/el-GR/widgets.php
create mode 100644 resources/lang/en-AU/accounts.php
create mode 100644 resources/lang/en-AU/auth.php
create mode 100644 resources/lang/en-AU/bills.php
create mode 100644 resources/lang/en-AU/bulk_actions.php
create mode 100644 resources/lang/en-AU/categories.php
create mode 100644 resources/lang/en-AU/companies.php
create mode 100644 resources/lang/en-AU/countries.php
create mode 100644 resources/lang/en-AU/currencies.php
create mode 100644 resources/lang/en-AU/customers.php
create mode 100644 resources/lang/en-AU/dashboards.php
create mode 100644 resources/lang/en-AU/demo.php
create mode 100644 resources/lang/en-AU/documents.php
create mode 100644 resources/lang/en-AU/email_templates.php
create mode 100644 resources/lang/en-AU/errors.php
create mode 100644 resources/lang/en-AU/footer.php
create mode 100644 resources/lang/en-AU/general.php
create mode 100644 resources/lang/en-AU/header.php
create mode 100644 resources/lang/en-AU/import.php
create mode 100644 resources/lang/en-AU/install.php
create mode 100644 resources/lang/en-AU/invoices.php
create mode 100644 resources/lang/en-AU/items.php
create mode 100644 resources/lang/en-AU/maintenance.php
create mode 100644 resources/lang/en-AU/messages.php
create mode 100644 resources/lang/en-AU/modules.php
create mode 100644 resources/lang/en-AU/notifications.php
create mode 100644 resources/lang/en-AU/pagination.php
create mode 100644 resources/lang/en-AU/passwords.php
create mode 100644 resources/lang/en-AU/portal.php
create mode 100644 resources/lang/en-AU/reconciliations.php
create mode 100644 resources/lang/en-AU/recurring.php
create mode 100644 resources/lang/en-AU/reports.php
create mode 100644 resources/lang/en-AU/search_string.php
create mode 100644 resources/lang/en-AU/settings.php
create mode 100644 resources/lang/en-AU/taxes.php
create mode 100644 resources/lang/en-AU/transactions.php
create mode 100644 resources/lang/en-AU/transfers.php
create mode 100644 resources/lang/en-AU/updates.php
create mode 100644 resources/lang/en-AU/validation.php
create mode 100644 resources/lang/en-AU/vendors.php
create mode 100644 resources/lang/en-AU/widgets.php
create mode 100644 resources/lang/en-GB/accounts.php
create mode 100644 resources/lang/en-GB/auth.php
create mode 100644 resources/lang/en-GB/bills.php
create mode 100644 resources/lang/en-GB/bulk_actions.php
create mode 100644 resources/lang/en-GB/categories.php
create mode 100644 resources/lang/en-GB/companies.php
create mode 100644 resources/lang/en-GB/countries.php
create mode 100644 resources/lang/en-GB/currencies.php
create mode 100644 resources/lang/en-GB/customers.php
create mode 100644 resources/lang/en-GB/dashboards.php
create mode 100644 resources/lang/en-GB/demo.php
create mode 100644 resources/lang/en-GB/documents.php
create mode 100644 resources/lang/en-GB/email_templates.php
create mode 100644 resources/lang/en-GB/errors.php
create mode 100644 resources/lang/en-GB/footer.php
create mode 100644 resources/lang/en-GB/general.php
create mode 100644 resources/lang/en-GB/header.php
create mode 100644 resources/lang/en-GB/import.php
create mode 100644 resources/lang/en-GB/install.php
create mode 100644 resources/lang/en-GB/invoices.php
create mode 100644 resources/lang/en-GB/items.php
create mode 100644 resources/lang/en-GB/maintenance.php
create mode 100644 resources/lang/en-GB/messages.php
create mode 100644 resources/lang/en-GB/modules.php
create mode 100644 resources/lang/en-GB/notifications.php
create mode 100644 resources/lang/en-GB/pagination.php
create mode 100644 resources/lang/en-GB/passwords.php
create mode 100644 resources/lang/en-GB/portal.php
create mode 100644 resources/lang/en-GB/reconciliations.php
create mode 100644 resources/lang/en-GB/recurring.php
create mode 100644 resources/lang/en-GB/reports.php
create mode 100644 resources/lang/en-GB/search_string.php
create mode 100644 resources/lang/en-GB/settings.php
create mode 100644 resources/lang/en-GB/taxes.php
create mode 100644 resources/lang/en-GB/transactions.php
create mode 100644 resources/lang/en-GB/transfers.php
create mode 100644 resources/lang/en-GB/updates.php
create mode 100644 resources/lang/en-GB/validation.php
create mode 100644 resources/lang/en-GB/vendors.php
create mode 100644 resources/lang/en-GB/widgets.php
create mode 100644 resources/lang/en-US/accounts.php
create mode 100644 resources/lang/en-US/auth.php
create mode 100644 resources/lang/en-US/bills.php
create mode 100644 resources/lang/en-US/bulk_actions.php
create mode 100644 resources/lang/en-US/categories.php
create mode 100644 resources/lang/en-US/companies.php
create mode 100644 resources/lang/en-US/countries.php
create mode 100644 resources/lang/en-US/currencies.php
create mode 100644 resources/lang/en-US/customers.php
create mode 100644 resources/lang/en-US/dashboards.php
create mode 100644 resources/lang/en-US/demo.php
create mode 100644 resources/lang/en-US/documents.php
create mode 100644 resources/lang/en-US/email_templates.php
create mode 100644 resources/lang/en-US/errors.php
create mode 100644 resources/lang/en-US/footer.php
create mode 100644 resources/lang/en-US/general.php
create mode 100644 resources/lang/en-US/header.php
create mode 100644 resources/lang/en-US/import.php
create mode 100644 resources/lang/en-US/install.php
create mode 100644 resources/lang/en-US/invoices.php
create mode 100644 resources/lang/en-US/items.php
create mode 100644 resources/lang/en-US/maintenance.php
create mode 100644 resources/lang/en-US/messages.php
create mode 100644 resources/lang/en-US/modules.php
create mode 100644 resources/lang/en-US/notifications.php
create mode 100644 resources/lang/en-US/pagination.php
create mode 100644 resources/lang/en-US/passwords.php
create mode 100644 resources/lang/en-US/portal.php
create mode 100644 resources/lang/en-US/reconciliations.php
create mode 100644 resources/lang/en-US/recurring.php
create mode 100644 resources/lang/en-US/reports.php
create mode 100644 resources/lang/en-US/search_string.php
create mode 100644 resources/lang/en-US/settings.php
create mode 100644 resources/lang/en-US/taxes.php
create mode 100644 resources/lang/en-US/transactions.php
create mode 100644 resources/lang/en-US/transfers.php
create mode 100644 resources/lang/en-US/updates.php
create mode 100644 resources/lang/en-US/validation.php
create mode 100644 resources/lang/en-US/vendors.php
create mode 100644 resources/lang/en-US/widgets.php
create mode 100644 resources/lang/es-AR/accounts.php
create mode 100644 resources/lang/es-AR/auth.php
create mode 100644 resources/lang/es-AR/bills.php
create mode 100644 resources/lang/es-AR/bulk_actions.php
create mode 100644 resources/lang/es-AR/categories.php
create mode 100644 resources/lang/es-AR/companies.php
create mode 100644 resources/lang/es-AR/countries.php
create mode 100644 resources/lang/es-AR/currencies.php
create mode 100644 resources/lang/es-AR/customers.php
create mode 100644 resources/lang/es-AR/dashboards.php
create mode 100644 resources/lang/es-AR/demo.php
create mode 100644 resources/lang/es-AR/documents.php
create mode 100644 resources/lang/es-AR/email_templates.php
create mode 100644 resources/lang/es-AR/errors.php
create mode 100644 resources/lang/es-AR/footer.php
create mode 100644 resources/lang/es-AR/general.php
create mode 100644 resources/lang/es-AR/header.php
create mode 100644 resources/lang/es-AR/import.php
create mode 100644 resources/lang/es-AR/install.php
create mode 100644 resources/lang/es-AR/invoices.php
create mode 100644 resources/lang/es-AR/items.php
create mode 100644 resources/lang/es-AR/maintenance.php
create mode 100644 resources/lang/es-AR/messages.php
create mode 100644 resources/lang/es-AR/modules.php
create mode 100644 resources/lang/es-AR/notifications.php
create mode 100644 resources/lang/es-AR/pagination.php
create mode 100644 resources/lang/es-AR/passwords.php
create mode 100644 resources/lang/es-AR/reconciliations.php
create mode 100644 resources/lang/es-AR/recurring.php
create mode 100644 resources/lang/es-AR/reports.php
create mode 100644 resources/lang/es-AR/search_string.php
create mode 100644 resources/lang/es-AR/settings.php
create mode 100644 resources/lang/es-AR/taxes.php
create mode 100644 resources/lang/es-AR/transfers.php
create mode 100644 resources/lang/es-AR/updates.php
create mode 100644 resources/lang/es-AR/validation.php
create mode 100644 resources/lang/es-AR/widgets.php
create mode 100644 resources/lang/es-CO/accounts.php
create mode 100644 resources/lang/es-CO/auth.php
create mode 100644 resources/lang/es-CO/bills.php
create mode 100644 resources/lang/es-CO/bulk_actions.php
create mode 100644 resources/lang/es-CO/categories.php
create mode 100644 resources/lang/es-CO/companies.php
create mode 100644 resources/lang/es-CO/countries.php
create mode 100644 resources/lang/es-CO/currencies.php
create mode 100644 resources/lang/es-CO/customers.php
create mode 100644 resources/lang/es-CO/dashboards.php
create mode 100644 resources/lang/es-CO/demo.php
create mode 100644 resources/lang/es-CO/documents.php
create mode 100644 resources/lang/es-CO/errors.php
create mode 100644 resources/lang/es-CO/footer.php
create mode 100644 resources/lang/es-CO/pagination.php
create mode 100644 resources/lang/es-CO/passwords.php
create mode 100644 resources/lang/es-CO/search_string.php
create mode 100644 resources/lang/es-CO/taxes.php
create mode 100644 resources/lang/es-CO/vendors.php
create mode 100644 resources/lang/es-CO/widgets.php
create mode 100644 resources/lang/es-ES/accounts.php
create mode 100644 resources/lang/es-ES/auth.php
create mode 100644 resources/lang/es-ES/bills.php
create mode 100644 resources/lang/es-ES/bulk_actions.php
create mode 100644 resources/lang/es-ES/categories.php
create mode 100644 resources/lang/es-ES/companies.php
create mode 100644 resources/lang/es-ES/countries.php
create mode 100644 resources/lang/es-ES/currencies.php
create mode 100644 resources/lang/es-ES/customers.php
create mode 100644 resources/lang/es-ES/dashboards.php
create mode 100644 resources/lang/es-ES/demo.php
create mode 100644 resources/lang/es-ES/documents.php
create mode 100644 resources/lang/es-ES/email_templates.php
create mode 100644 resources/lang/es-ES/errors.php
create mode 100644 resources/lang/es-ES/footer.php
create mode 100644 resources/lang/es-ES/general.php
create mode 100644 resources/lang/es-ES/header.php
create mode 100644 resources/lang/es-ES/import.php
create mode 100644 resources/lang/es-ES/install.php
create mode 100644 resources/lang/es-ES/invoices.php
create mode 100644 resources/lang/es-ES/items.php
create mode 100644 resources/lang/es-ES/maintenance.php
create mode 100644 resources/lang/es-ES/messages.php
create mode 100644 resources/lang/es-ES/modules.php
create mode 100644 resources/lang/es-ES/notifications.php
create mode 100644 resources/lang/es-ES/pagination.php
create mode 100644 resources/lang/es-ES/passwords.php
create mode 100644 resources/lang/es-ES/portal.php
create mode 100644 resources/lang/es-ES/reconciliations.php
create mode 100644 resources/lang/es-ES/recurring.php
create mode 100644 resources/lang/es-ES/reports.php
create mode 100644 resources/lang/es-ES/search_string.php
create mode 100644 resources/lang/es-ES/settings.php
create mode 100644 resources/lang/es-ES/taxes.php
create mode 100644 resources/lang/es-ES/transactions.php
create mode 100644 resources/lang/es-ES/transfers.php
create mode 100644 resources/lang/es-ES/updates.php
create mode 100644 resources/lang/es-ES/validation.php
create mode 100644 resources/lang/es-ES/vendors.php
create mode 100644 resources/lang/es-ES/widgets.php
create mode 100644 resources/lang/es-MX/accounts.php
create mode 100644 resources/lang/es-MX/auth.php
create mode 100644 resources/lang/es-MX/bills.php
create mode 100644 resources/lang/es-MX/bulk_actions.php
create mode 100644 resources/lang/es-MX/categories.php
create mode 100644 resources/lang/es-MX/companies.php
create mode 100644 resources/lang/es-MX/countries.php
create mode 100644 resources/lang/es-MX/currencies.php
create mode 100644 resources/lang/es-MX/customers.php
create mode 100644 resources/lang/es-MX/dashboards.php
create mode 100644 resources/lang/es-MX/demo.php
create mode 100644 resources/lang/es-MX/documents.php
create mode 100644 resources/lang/es-MX/email_templates.php
create mode 100644 resources/lang/es-MX/errors.php
create mode 100644 resources/lang/es-MX/footer.php
create mode 100644 resources/lang/es-MX/general.php
create mode 100644 resources/lang/es-MX/header.php
create mode 100644 resources/lang/es-MX/import.php
create mode 100644 resources/lang/es-MX/install.php
create mode 100644 resources/lang/es-MX/invoices.php
create mode 100644 resources/lang/es-MX/items.php
create mode 100644 resources/lang/es-MX/maintenance.php
create mode 100644 resources/lang/es-MX/messages.php
create mode 100644 resources/lang/es-MX/modules.php
create mode 100644 resources/lang/es-MX/notifications.php
create mode 100644 resources/lang/es-MX/pagination.php
create mode 100644 resources/lang/es-MX/passwords.php
create mode 100644 resources/lang/es-MX/portal.php
create mode 100644 resources/lang/es-MX/reconciliations.php
create mode 100644 resources/lang/es-MX/recurring.php
create mode 100644 resources/lang/es-MX/reports.php
create mode 100644 resources/lang/es-MX/search_string.php
create mode 100644 resources/lang/es-MX/settings.php
create mode 100644 resources/lang/es-MX/taxes.php
create mode 100644 resources/lang/es-MX/transactions.php
create mode 100644 resources/lang/es-MX/transfers.php
create mode 100644 resources/lang/es-MX/updates.php
create mode 100644 resources/lang/es-MX/validation.php
create mode 100644 resources/lang/es-MX/vendors.php
create mode 100644 resources/lang/es-MX/widgets.php
create mode 100644 resources/lang/et-EE/accounts.php
create mode 100644 resources/lang/et-EE/auth.php
create mode 100644 resources/lang/et-EE/bills.php
create mode 100644 resources/lang/et-EE/bulk_actions.php
create mode 100644 resources/lang/et-EE/companies.php
create mode 100644 resources/lang/et-EE/countries.php
create mode 100644 resources/lang/et-EE/currencies.php
create mode 100644 resources/lang/et-EE/customers.php
create mode 100644 resources/lang/et-EE/dashboards.php
create mode 100644 resources/lang/et-EE/demo.php
create mode 100644 resources/lang/et-EE/documents.php
create mode 100644 resources/lang/et-EE/email_templates.php
create mode 100644 resources/lang/et-EE/errors.php
create mode 100644 resources/lang/et-EE/footer.php
create mode 100644 resources/lang/et-EE/general.php
create mode 100644 resources/lang/et-EE/header.php
create mode 100644 resources/lang/et-EE/import.php
create mode 100644 resources/lang/et-EE/install.php
create mode 100644 resources/lang/et-EE/invoices.php
create mode 100644 resources/lang/et-EE/items.php
create mode 100644 resources/lang/et-EE/maintenance.php
create mode 100644 resources/lang/et-EE/messages.php
create mode 100644 resources/lang/et-EE/modules.php
create mode 100644 resources/lang/et-EE/notifications.php
create mode 100644 resources/lang/et-EE/pagination.php
create mode 100644 resources/lang/et-EE/passwords.php
create mode 100644 resources/lang/et-EE/reconciliations.php
create mode 100644 resources/lang/et-EE/recurring.php
create mode 100644 resources/lang/et-EE/reports.php
create mode 100644 resources/lang/et-EE/search_string.php
create mode 100644 resources/lang/et-EE/settings.php
create mode 100644 resources/lang/et-EE/taxes.php
create mode 100644 resources/lang/et-EE/transfers.php
create mode 100644 resources/lang/et-EE/updates.php
create mode 100644 resources/lang/et-EE/validation.php
create mode 100644 resources/lang/et-EE/widgets.php
create mode 100644 resources/lang/fa-IR/accounts.php
create mode 100644 resources/lang/fa-IR/auth.php
create mode 100644 resources/lang/fa-IR/bills.php
create mode 100644 resources/lang/fa-IR/bulk_actions.php
create mode 100644 resources/lang/fa-IR/categories.php
create mode 100644 resources/lang/fa-IR/companies.php
create mode 100644 resources/lang/fa-IR/countries.php
create mode 100644 resources/lang/fa-IR/currencies.php
create mode 100644 resources/lang/fa-IR/customers.php
create mode 100644 resources/lang/fa-IR/dashboards.php
create mode 100644 resources/lang/fa-IR/demo.php
create mode 100644 resources/lang/fa-IR/email_templates.php
create mode 100644 resources/lang/fa-IR/errors.php
create mode 100644 resources/lang/fa-IR/footer.php
create mode 100644 resources/lang/fa-IR/general.php
create mode 100644 resources/lang/fa-IR/header.php
create mode 100644 resources/lang/fa-IR/import.php
create mode 100644 resources/lang/fa-IR/install.php
create mode 100644 resources/lang/fa-IR/invoices.php
create mode 100644 resources/lang/fa-IR/items.php
create mode 100644 resources/lang/fa-IR/maintenance.php
create mode 100644 resources/lang/fa-IR/messages.php
create mode 100644 resources/lang/fa-IR/modules.php
create mode 100644 resources/lang/fa-IR/notifications.php
create mode 100644 resources/lang/fa-IR/pagination.php
create mode 100644 resources/lang/fa-IR/passwords.php
create mode 100644 resources/lang/fa-IR/payments.php
create mode 100644 resources/lang/fa-IR/reconciliations.php
create mode 100644 resources/lang/fa-IR/recurring.php
create mode 100644 resources/lang/fa-IR/reports.php
create mode 100644 resources/lang/fa-IR/revenues.php
create mode 100644 resources/lang/fa-IR/settings.php
create mode 100644 resources/lang/fa-IR/taxes.php
create mode 100644 resources/lang/fa-IR/transfers.php
create mode 100644 resources/lang/fa-IR/updates.php
create mode 100644 resources/lang/fa-IR/validation.php
create mode 100644 resources/lang/fa-IR/widgets.php
create mode 100644 resources/lang/fi-FI/accounts.php
create mode 100644 resources/lang/fi-FI/auth.php
create mode 100644 resources/lang/fi-FI/bills.php
create mode 100644 resources/lang/fi-FI/bulk_actions.php
create mode 100644 resources/lang/fi-FI/categories.php
create mode 100644 resources/lang/fi-FI/companies.php
create mode 100644 resources/lang/fi-FI/countries.php
create mode 100644 resources/lang/fi-FI/currencies.php
create mode 100644 resources/lang/fi-FI/customers.php
create mode 100644 resources/lang/fi-FI/dashboards.php
create mode 100644 resources/lang/fi-FI/demo.php
create mode 100644 resources/lang/fi-FI/documents.php
create mode 100644 resources/lang/fi-FI/email_templates.php
create mode 100644 resources/lang/fi-FI/errors.php
create mode 100644 resources/lang/fi-FI/footer.php
create mode 100644 resources/lang/fi-FI/general.php
create mode 100644 resources/lang/fi-FI/header.php
create mode 100644 resources/lang/fi-FI/import.php
create mode 100644 resources/lang/fi-FI/install.php
create mode 100644 resources/lang/fi-FI/invoices.php
create mode 100644 resources/lang/fi-FI/items.php
create mode 100644 resources/lang/fi-FI/maintenance.php
create mode 100644 resources/lang/fi-FI/messages.php
create mode 100644 resources/lang/fi-FI/modules.php
create mode 100644 resources/lang/fi-FI/notifications.php
create mode 100644 resources/lang/fi-FI/pagination.php
create mode 100644 resources/lang/fi-FI/passwords.php
create mode 100644 resources/lang/fi-FI/reconciliations.php
create mode 100644 resources/lang/fi-FI/recurring.php
create mode 100644 resources/lang/fi-FI/reports.php
create mode 100644 resources/lang/fi-FI/search_string.php
create mode 100644 resources/lang/fi-FI/settings.php
create mode 100644 resources/lang/fi-FI/taxes.php
create mode 100644 resources/lang/fi-FI/transfers.php
create mode 100644 resources/lang/fi-FI/updates.php
create mode 100644 resources/lang/fi-FI/validation.php
create mode 100644 resources/lang/fi-FI/widgets.php
create mode 100644 resources/lang/fr-FR/accounts.php
create mode 100644 resources/lang/fr-FR/auth.php
create mode 100644 resources/lang/fr-FR/bills.php
create mode 100644 resources/lang/fr-FR/bulk_actions.php
create mode 100644 resources/lang/fr-FR/categories.php
create mode 100644 resources/lang/fr-FR/companies.php
create mode 100644 resources/lang/fr-FR/countries.php
create mode 100644 resources/lang/fr-FR/currencies.php
create mode 100644 resources/lang/fr-FR/customers.php
create mode 100644 resources/lang/fr-FR/dashboards.php
create mode 100644 resources/lang/fr-FR/demo.php
create mode 100644 resources/lang/fr-FR/documents.php
create mode 100644 resources/lang/fr-FR/email_templates.php
create mode 100644 resources/lang/fr-FR/errors.php
create mode 100644 resources/lang/fr-FR/footer.php
create mode 100644 resources/lang/fr-FR/general.php
create mode 100644 resources/lang/fr-FR/header.php
create mode 100644 resources/lang/fr-FR/import.php
create mode 100644 resources/lang/fr-FR/install.php
create mode 100644 resources/lang/fr-FR/invoices.php
create mode 100644 resources/lang/fr-FR/items.php
create mode 100644 resources/lang/fr-FR/maintenance.php
create mode 100644 resources/lang/fr-FR/messages.php
create mode 100644 resources/lang/fr-FR/modules.php
create mode 100644 resources/lang/fr-FR/notifications.php
create mode 100644 resources/lang/fr-FR/pagination.php
create mode 100644 resources/lang/fr-FR/passwords.php
create mode 100644 resources/lang/fr-FR/portal.php
create mode 100644 resources/lang/fr-FR/reconciliations.php
create mode 100644 resources/lang/fr-FR/recurring.php
create mode 100644 resources/lang/fr-FR/reports.php
create mode 100644 resources/lang/fr-FR/search_string.php
create mode 100644 resources/lang/fr-FR/settings.php
create mode 100644 resources/lang/fr-FR/taxes.php
create mode 100644 resources/lang/fr-FR/transactions.php
create mode 100644 resources/lang/fr-FR/transfers.php
create mode 100644 resources/lang/fr-FR/updates.php
create mode 100644 resources/lang/fr-FR/validation.php
create mode 100644 resources/lang/fr-FR/vendors.php
create mode 100644 resources/lang/fr-FR/widgets.php
create mode 100644 resources/lang/he-IL/accounts.php
create mode 100644 resources/lang/he-IL/auth.php
create mode 100644 resources/lang/he-IL/bills.php
create mode 100644 resources/lang/he-IL/categories.php
create mode 100644 resources/lang/he-IL/companies.php
create mode 100644 resources/lang/he-IL/countries.php
create mode 100644 resources/lang/he-IL/currencies.php
create mode 100644 resources/lang/he-IL/customers.php
create mode 100644 resources/lang/he-IL/dashboard.php
create mode 100644 resources/lang/he-IL/dashboards.php
create mode 100644 resources/lang/he-IL/demo.php
create mode 100644 resources/lang/he-IL/errors.php
create mode 100644 resources/lang/he-IL/footer.php
create mode 100644 resources/lang/he-IL/general.php
create mode 100644 resources/lang/he-IL/header.php
create mode 100644 resources/lang/he-IL/import.php
create mode 100644 resources/lang/he-IL/install.php
create mode 100644 resources/lang/he-IL/invoices.php
create mode 100644 resources/lang/he-IL/items.php
create mode 100644 resources/lang/he-IL/messages.php
create mode 100644 resources/lang/he-IL/modules.php
create mode 100644 resources/lang/he-IL/notifications.php
create mode 100644 resources/lang/he-IL/pagination.php
create mode 100644 resources/lang/he-IL/passwords.php
create mode 100644 resources/lang/he-IL/reconciliations.php
create mode 100644 resources/lang/he-IL/recurring.php
create mode 100644 resources/lang/he-IL/reports.php
create mode 100644 resources/lang/he-IL/settings.php
create mode 100644 resources/lang/he-IL/taxes.php
create mode 100644 resources/lang/he-IL/transfers.php
create mode 100644 resources/lang/he-IL/updates.php
create mode 100644 resources/lang/he-IL/validation.php
create mode 100644 resources/lang/hi-IN/accounts.php
create mode 100644 resources/lang/hi-IN/auth.php
create mode 100644 resources/lang/hi-IN/bills.php
create mode 100644 resources/lang/hi-IN/bulk_actions.php
create mode 100644 resources/lang/hi-IN/categories.php
create mode 100644 resources/lang/hi-IN/companies.php
create mode 100644 resources/lang/hi-IN/countries.php
create mode 100644 resources/lang/hi-IN/currencies.php
create mode 100644 resources/lang/hi-IN/customers.php
create mode 100644 resources/lang/hi-IN/dashboards.php
create mode 100644 resources/lang/hi-IN/demo.php
create mode 100644 resources/lang/hi-IN/documents.php
create mode 100644 resources/lang/hi-IN/email_templates.php
create mode 100644 resources/lang/hi-IN/errors.php
create mode 100644 resources/lang/hi-IN/footer.php
create mode 100644 resources/lang/hi-IN/general.php
create mode 100644 resources/lang/hi-IN/header.php
create mode 100644 resources/lang/hi-IN/import.php
create mode 100644 resources/lang/hi-IN/install.php
create mode 100644 resources/lang/hi-IN/invoices.php
create mode 100644 resources/lang/hi-IN/items.php
create mode 100644 resources/lang/hi-IN/maintenance.php
create mode 100644 resources/lang/hi-IN/messages.php
create mode 100644 resources/lang/hi-IN/modules.php
create mode 100644 resources/lang/hi-IN/notifications.php
create mode 100644 resources/lang/hi-IN/pagination.php
create mode 100644 resources/lang/hi-IN/passwords.php
create mode 100644 resources/lang/hi-IN/portal.php
create mode 100644 resources/lang/hi-IN/reconciliations.php
create mode 100644 resources/lang/hi-IN/recurring.php
create mode 100644 resources/lang/hi-IN/reports.php
create mode 100644 resources/lang/hi-IN/search_string.php
create mode 100644 resources/lang/hi-IN/settings.php
create mode 100644 resources/lang/hi-IN/taxes.php
create mode 100644 resources/lang/hi-IN/transactions.php
create mode 100644 resources/lang/hi-IN/transfers.php
create mode 100644 resources/lang/hi-IN/updates.php
create mode 100644 resources/lang/hi-IN/validation.php
create mode 100644 resources/lang/hi-IN/vendors.php
create mode 100644 resources/lang/hi-IN/widgets.php
create mode 100644 resources/lang/hr-HR/accounts.php
create mode 100644 resources/lang/hr-HR/auth.php
create mode 100644 resources/lang/hr-HR/bills.php
create mode 100644 resources/lang/hr-HR/bulk_actions.php
create mode 100644 resources/lang/hr-HR/companies.php
create mode 100644 resources/lang/hr-HR/countries.php
create mode 100644 resources/lang/hr-HR/currencies.php
create mode 100644 resources/lang/hr-HR/customers.php
create mode 100644 resources/lang/hr-HR/dashboards.php
create mode 100644 resources/lang/hr-HR/demo.php
create mode 100644 resources/lang/hr-HR/email_templates.php
create mode 100644 resources/lang/hr-HR/errors.php
create mode 100644 resources/lang/hr-HR/footer.php
create mode 100644 resources/lang/hr-HR/general.php
create mode 100644 resources/lang/hr-HR/header.php
create mode 100644 resources/lang/hr-HR/import.php
create mode 100644 resources/lang/hr-HR/install.php
create mode 100644 resources/lang/hr-HR/invoices.php
create mode 100644 resources/lang/hr-HR/items.php
create mode 100644 resources/lang/hr-HR/maintenance.php
create mode 100644 resources/lang/hr-HR/messages.php
create mode 100644 resources/lang/hr-HR/modules.php
create mode 100644 resources/lang/hr-HR/notifications.php
create mode 100644 resources/lang/hr-HR/pagination.php
create mode 100644 resources/lang/hr-HR/passwords.php
create mode 100644 resources/lang/hr-HR/reconciliations.php
create mode 100644 resources/lang/hr-HR/recurring.php
create mode 100644 resources/lang/hr-HR/reports.php
create mode 100644 resources/lang/hr-HR/settings.php
create mode 100644 resources/lang/hr-HR/taxes.php
create mode 100644 resources/lang/hr-HR/transfers.php
create mode 100644 resources/lang/hr-HR/updates.php
create mode 100644 resources/lang/hr-HR/validation.php
create mode 100644 resources/lang/hr-HR/widgets.php
create mode 100644 resources/lang/hu-HU/accounts.php
create mode 100644 resources/lang/hu-HU/auth.php
create mode 100644 resources/lang/hu-HU/bills.php
create mode 100644 resources/lang/hu-HU/bulk_actions.php
create mode 100644 resources/lang/hu-HU/companies.php
create mode 100644 resources/lang/hu-HU/countries.php
create mode 100644 resources/lang/hu-HU/currencies.php
create mode 100644 resources/lang/hu-HU/customers.php
create mode 100644 resources/lang/hu-HU/dashboards.php
create mode 100644 resources/lang/hu-HU/demo.php
create mode 100644 resources/lang/hu-HU/email_templates.php
create mode 100644 resources/lang/hu-HU/errors.php
create mode 100644 resources/lang/hu-HU/footer.php
create mode 100644 resources/lang/hu-HU/header.php
create mode 100644 resources/lang/hu-HU/import.php
create mode 100644 resources/lang/hu-HU/install.php
create mode 100644 resources/lang/hu-HU/invoices.php
create mode 100644 resources/lang/hu-HU/items.php
create mode 100644 resources/lang/hu-HU/maintenance.php
create mode 100644 resources/lang/hu-HU/messages.php
create mode 100644 resources/lang/hu-HU/modules.php
create mode 100644 resources/lang/hu-HU/notifications.php
create mode 100644 resources/lang/hu-HU/pagination.php
create mode 100644 resources/lang/hu-HU/passwords.php
create mode 100644 resources/lang/hu-HU/reconciliations.php
create mode 100644 resources/lang/hu-HU/recurring.php
create mode 100644 resources/lang/hu-HU/reports.php
create mode 100644 resources/lang/hu-HU/taxes.php
create mode 100644 resources/lang/hu-HU/transfers.php
create mode 100644 resources/lang/hu-HU/updates.php
create mode 100644 resources/lang/hu-HU/validation.php
create mode 100644 resources/lang/hu-HU/vendors.php
create mode 100644 resources/lang/hu-HU/widgets.php
create mode 100644 resources/lang/id-ID/accounts.php
create mode 100644 resources/lang/id-ID/auth.php
create mode 100644 resources/lang/id-ID/bills.php
create mode 100644 resources/lang/id-ID/bulk_actions.php
create mode 100644 resources/lang/id-ID/categories.php
create mode 100644 resources/lang/id-ID/companies.php
create mode 100644 resources/lang/id-ID/countries.php
create mode 100644 resources/lang/id-ID/currencies.php
create mode 100644 resources/lang/id-ID/customers.php
create mode 100644 resources/lang/id-ID/dashboards.php
create mode 100644 resources/lang/id-ID/demo.php
create mode 100644 resources/lang/id-ID/documents.php
create mode 100644 resources/lang/id-ID/email_templates.php
create mode 100644 resources/lang/id-ID/errors.php
create mode 100644 resources/lang/id-ID/footer.php
create mode 100644 resources/lang/id-ID/general.php
create mode 100644 resources/lang/id-ID/header.php
create mode 100644 resources/lang/id-ID/import.php
create mode 100644 resources/lang/id-ID/install.php
create mode 100644 resources/lang/id-ID/invoices.php
create mode 100644 resources/lang/id-ID/items.php
create mode 100644 resources/lang/id-ID/maintenance.php
create mode 100644 resources/lang/id-ID/messages.php
create mode 100644 resources/lang/id-ID/modules.php
create mode 100644 resources/lang/id-ID/notifications.php
create mode 100644 resources/lang/id-ID/pagination.php
create mode 100644 resources/lang/id-ID/passwords.php
create mode 100644 resources/lang/id-ID/portal.php
create mode 100644 resources/lang/id-ID/reconciliations.php
create mode 100644 resources/lang/id-ID/recurring.php
create mode 100644 resources/lang/id-ID/reports.php
create mode 100644 resources/lang/id-ID/search_string.php
create mode 100644 resources/lang/id-ID/settings.php
create mode 100644 resources/lang/id-ID/taxes.php
create mode 100644 resources/lang/id-ID/transactions.php
create mode 100644 resources/lang/id-ID/transfers.php
create mode 100644 resources/lang/id-ID/updates.php
create mode 100644 resources/lang/id-ID/validation.php
create mode 100644 resources/lang/id-ID/vendors.php
create mode 100644 resources/lang/id-ID/widgets.php
create mode 100644 resources/lang/is-IS/accounts.php
create mode 100644 resources/lang/is-IS/auth.php
create mode 100644 resources/lang/is-IS/bills.php
create mode 100644 resources/lang/is-IS/bulk_actions.php
create mode 100644 resources/lang/is-IS/companies.php
create mode 100644 resources/lang/is-IS/countries.php
create mode 100644 resources/lang/is-IS/currencies.php
create mode 100644 resources/lang/is-IS/customers.php
create mode 100644 resources/lang/is-IS/dashboards.php
create mode 100644 resources/lang/is-IS/demo.php
create mode 100644 resources/lang/is-IS/email_templates.php
create mode 100644 resources/lang/is-IS/errors.php
create mode 100644 resources/lang/is-IS/footer.php
create mode 100644 resources/lang/is-IS/general.php
create mode 100644 resources/lang/is-IS/header.php
create mode 100644 resources/lang/is-IS/import.php
create mode 100644 resources/lang/is-IS/install.php
create mode 100644 resources/lang/is-IS/invoices.php
create mode 100644 resources/lang/is-IS/items.php
create mode 100644 resources/lang/is-IS/maintenance.php
create mode 100644 resources/lang/is-IS/messages.php
create mode 100644 resources/lang/is-IS/modules.php
create mode 100644 resources/lang/is-IS/notifications.php
create mode 100644 resources/lang/is-IS/pagination.php
create mode 100644 resources/lang/is-IS/passwords.php
create mode 100644 resources/lang/is-IS/reconciliations.php
create mode 100644 resources/lang/is-IS/recurring.php
create mode 100644 resources/lang/is-IS/reports.php
create mode 100644 resources/lang/is-IS/settings.php
create mode 100644 resources/lang/is-IS/taxes.php
create mode 100644 resources/lang/is-IS/transfers.php
create mode 100644 resources/lang/is-IS/updates.php
create mode 100644 resources/lang/is-IS/validation.php
create mode 100644 resources/lang/is-IS/widgets.php
create mode 100644 resources/lang/it-IT/accounts.php
create mode 100644 resources/lang/it-IT/auth.php
create mode 100644 resources/lang/it-IT/bills.php
create mode 100644 resources/lang/it-IT/bulk_actions.php
create mode 100644 resources/lang/it-IT/categories.php
create mode 100644 resources/lang/it-IT/companies.php
create mode 100644 resources/lang/it-IT/countries.php
create mode 100644 resources/lang/it-IT/currencies.php
create mode 100644 resources/lang/it-IT/customers.php
create mode 100644 resources/lang/it-IT/dashboards.php
create mode 100644 resources/lang/it-IT/demo.php
create mode 100644 resources/lang/it-IT/documents.php
create mode 100644 resources/lang/it-IT/email_templates.php
create mode 100644 resources/lang/it-IT/errors.php
create mode 100644 resources/lang/it-IT/footer.php
create mode 100644 resources/lang/it-IT/general.php
create mode 100644 resources/lang/it-IT/header.php
create mode 100644 resources/lang/it-IT/import.php
create mode 100644 resources/lang/it-IT/install.php
create mode 100644 resources/lang/it-IT/invoices.php
create mode 100644 resources/lang/it-IT/items.php
create mode 100644 resources/lang/it-IT/maintenance.php
create mode 100644 resources/lang/it-IT/messages.php
create mode 100644 resources/lang/it-IT/modules.php
create mode 100644 resources/lang/it-IT/notifications.php
create mode 100644 resources/lang/it-IT/pagination.php
create mode 100644 resources/lang/it-IT/passwords.php
create mode 100644 resources/lang/it-IT/portal.php
create mode 100644 resources/lang/it-IT/reconciliations.php
create mode 100644 resources/lang/it-IT/recurring.php
create mode 100644 resources/lang/it-IT/reports.php
create mode 100644 resources/lang/it-IT/search_string.php
create mode 100644 resources/lang/it-IT/settings.php
create mode 100644 resources/lang/it-IT/taxes.php
create mode 100644 resources/lang/it-IT/transactions.php
create mode 100644 resources/lang/it-IT/transfers.php
create mode 100644 resources/lang/it-IT/updates.php
create mode 100644 resources/lang/it-IT/validation.php
create mode 100644 resources/lang/it-IT/vendors.php
create mode 100644 resources/lang/it-IT/widgets.php
create mode 100644 resources/lang/ja-JP/accounts.php
create mode 100644 resources/lang/ja-JP/auth.php
create mode 100644 resources/lang/ja-JP/bills.php
create mode 100644 resources/lang/ja-JP/bulk_actions.php
create mode 100644 resources/lang/ja-JP/companies.php
create mode 100644 resources/lang/ja-JP/countries.php
create mode 100644 resources/lang/ja-JP/currencies.php
create mode 100644 resources/lang/ja-JP/customers.php
create mode 100644 resources/lang/ja-JP/dashboards.php
create mode 100644 resources/lang/ja-JP/demo.php
create mode 100644 resources/lang/ja-JP/email_templates.php
create mode 100644 resources/lang/ja-JP/errors.php
create mode 100644 resources/lang/ja-JP/footer.php
create mode 100644 resources/lang/ja-JP/general.php
create mode 100644 resources/lang/ja-JP/header.php
create mode 100644 resources/lang/ja-JP/import.php
create mode 100644 resources/lang/ja-JP/install.php
create mode 100644 resources/lang/ja-JP/invoices.php
create mode 100644 resources/lang/ja-JP/items.php
create mode 100644 resources/lang/ja-JP/maintenance.php
create mode 100644 resources/lang/ja-JP/messages.php
create mode 100644 resources/lang/ja-JP/modules.php
create mode 100644 resources/lang/ja-JP/notifications.php
create mode 100644 resources/lang/ja-JP/pagination.php
create mode 100644 resources/lang/ja-JP/passwords.php
create mode 100644 resources/lang/ja-JP/reconciliations.php
create mode 100644 resources/lang/ja-JP/recurring.php
create mode 100644 resources/lang/ja-JP/reports.php
create mode 100644 resources/lang/ja-JP/settings.php
create mode 100644 resources/lang/ja-JP/taxes.php
create mode 100644 resources/lang/ja-JP/transfers.php
create mode 100644 resources/lang/ja-JP/updates.php
create mode 100644 resources/lang/ja-JP/validation.php
create mode 100644 resources/lang/ja-JP/widgets.php
create mode 100644 resources/lang/ka-GE/accounts.php
create mode 100644 resources/lang/ka-GE/auth.php
create mode 100644 resources/lang/ka-GE/bills.php
create mode 100644 resources/lang/ka-GE/companies.php
create mode 100644 resources/lang/ka-GE/countries.php
create mode 100644 resources/lang/ka-GE/currencies.php
create mode 100644 resources/lang/ka-GE/customers.php
create mode 100644 resources/lang/ka-GE/dashboard.php
create mode 100644 resources/lang/ka-GE/demo.php
create mode 100644 resources/lang/ka-GE/email_templates.php
create mode 100644 resources/lang/ka-GE/errors.php
create mode 100644 resources/lang/ka-GE/footer.php
create mode 100644 resources/lang/ka-GE/general.php
create mode 100644 resources/lang/ka-GE/header.php
create mode 100644 resources/lang/ka-GE/import.php
create mode 100644 resources/lang/ka-GE/install.php
create mode 100644 resources/lang/ka-GE/invoices.php
create mode 100644 resources/lang/ka-GE/items.php
create mode 100644 resources/lang/ka-GE/maintenance.php
create mode 100644 resources/lang/ka-GE/messages.php
create mode 100644 resources/lang/ka-GE/modules.php
create mode 100644 resources/lang/ka-GE/notifications.php
create mode 100644 resources/lang/ka-GE/pagination.php
create mode 100644 resources/lang/ka-GE/passwords.php
create mode 100644 resources/lang/ka-GE/reconciliations.php
create mode 100644 resources/lang/ka-GE/recurring.php
create mode 100644 resources/lang/ka-GE/reports.php
create mode 100644 resources/lang/ka-GE/settings.php
create mode 100644 resources/lang/ka-GE/taxes.php
create mode 100644 resources/lang/ka-GE/transfers.php
create mode 100644 resources/lang/ka-GE/updates.php
create mode 100644 resources/lang/ka-GE/validation.php
create mode 100644 resources/lang/ko-KR/accounts.php
create mode 100644 resources/lang/ko-KR/auth.php
create mode 100644 resources/lang/ko-KR/bills.php
create mode 100644 resources/lang/ko-KR/companies.php
create mode 100644 resources/lang/ko-KR/countries.php
create mode 100644 resources/lang/ko-KR/currencies.php
create mode 100644 resources/lang/ko-KR/customers.php
create mode 100644 resources/lang/ko-KR/dashboard.php
create mode 100644 resources/lang/ko-KR/demo.php
create mode 100644 resources/lang/ko-KR/footer.php
create mode 100644 resources/lang/ko-KR/general.php
create mode 100644 resources/lang/ko-KR/header.php
create mode 100644 resources/lang/ko-KR/import.php
create mode 100644 resources/lang/ko-KR/install.php
create mode 100644 resources/lang/ko-KR/invoices.php
create mode 100644 resources/lang/ko-KR/items.php
create mode 100644 resources/lang/ko-KR/messages.php
create mode 100644 resources/lang/ko-KR/modules.php
create mode 100644 resources/lang/ko-KR/notifications.php
create mode 100644 resources/lang/ko-KR/pagination.php
create mode 100644 resources/lang/ko-KR/passwords.php
create mode 100644 resources/lang/ko-KR/reconciliations.php
create mode 100644 resources/lang/ko-KR/recurring.php
create mode 100644 resources/lang/ko-KR/reports.php
create mode 100644 resources/lang/ko-KR/settings.php
create mode 100644 resources/lang/ko-KR/taxes.php
create mode 100644 resources/lang/ko-KR/transfers.php
create mode 100644 resources/lang/ko-KR/updates.php
create mode 100644 resources/lang/ko-KR/validation.php
create mode 100644 resources/lang/lt-LT/accounts.php
create mode 100644 resources/lang/lt-LT/auth.php
create mode 100644 resources/lang/lt-LT/bills.php
create mode 100644 resources/lang/lt-LT/bulk_actions.php
create mode 100644 resources/lang/lt-LT/companies.php
create mode 100644 resources/lang/lt-LT/countries.php
create mode 100644 resources/lang/lt-LT/currencies.php
create mode 100644 resources/lang/lt-LT/customers.php
create mode 100644 resources/lang/lt-LT/dashboards.php
create mode 100644 resources/lang/lt-LT/demo.php
create mode 100644 resources/lang/lt-LT/email_templates.php
create mode 100644 resources/lang/lt-LT/errors.php
create mode 100644 resources/lang/lt-LT/footer.php
create mode 100644 resources/lang/lt-LT/general.php
create mode 100644 resources/lang/lt-LT/header.php
create mode 100644 resources/lang/lt-LT/import.php
create mode 100644 resources/lang/lt-LT/install.php
create mode 100644 resources/lang/lt-LT/invoices.php
create mode 100644 resources/lang/lt-LT/items.php
create mode 100644 resources/lang/lt-LT/maintenance.php
create mode 100644 resources/lang/lt-LT/messages.php
create mode 100644 resources/lang/lt-LT/modules.php
create mode 100644 resources/lang/lt-LT/notifications.php
create mode 100644 resources/lang/lt-LT/pagination.php
create mode 100644 resources/lang/lt-LT/passwords.php
create mode 100644 resources/lang/lt-LT/reconciliations.php
create mode 100644 resources/lang/lt-LT/recurring.php
create mode 100644 resources/lang/lt-LT/reports.php
create mode 100644 resources/lang/lt-LT/settings.php
create mode 100644 resources/lang/lt-LT/taxes.php
create mode 100644 resources/lang/lt-LT/transfers.php
create mode 100644 resources/lang/lt-LT/updates.php
create mode 100644 resources/lang/lt-LT/validation.php
create mode 100644 resources/lang/lt-LT/widgets.php
create mode 100644 resources/lang/lv-LV/accounts.php
create mode 100644 resources/lang/lv-LV/auth.php
create mode 100644 resources/lang/lv-LV/bills.php
create mode 100644 resources/lang/lv-LV/bulk_actions.php
create mode 100644 resources/lang/lv-LV/categories.php
create mode 100644 resources/lang/lv-LV/companies.php
create mode 100644 resources/lang/lv-LV/countries.php
create mode 100644 resources/lang/lv-LV/currencies.php
create mode 100644 resources/lang/lv-LV/customers.php
create mode 100644 resources/lang/lv-LV/dashboards.php
create mode 100644 resources/lang/lv-LV/demo.php
create mode 100644 resources/lang/lv-LV/documents.php
create mode 100644 resources/lang/lv-LV/email_templates.php
create mode 100644 resources/lang/lv-LV/errors.php
create mode 100644 resources/lang/lv-LV/footer.php
create mode 100644 resources/lang/lv-LV/general.php
create mode 100644 resources/lang/lv-LV/header.php
create mode 100644 resources/lang/lv-LV/import.php
create mode 100644 resources/lang/lv-LV/install.php
create mode 100644 resources/lang/lv-LV/invoices.php
create mode 100644 resources/lang/lv-LV/items.php
create mode 100644 resources/lang/lv-LV/maintenance.php
create mode 100644 resources/lang/lv-LV/messages.php
create mode 100644 resources/lang/lv-LV/modules.php
create mode 100644 resources/lang/lv-LV/notifications.php
create mode 100644 resources/lang/lv-LV/pagination.php
create mode 100644 resources/lang/lv-LV/passwords.php
create mode 100644 resources/lang/lv-LV/portal.php
create mode 100644 resources/lang/lv-LV/reconciliations.php
create mode 100644 resources/lang/lv-LV/recurring.php
create mode 100644 resources/lang/lv-LV/reports.php
create mode 100644 resources/lang/lv-LV/search_string.php
create mode 100644 resources/lang/lv-LV/settings.php
create mode 100644 resources/lang/lv-LV/taxes.php
create mode 100644 resources/lang/lv-LV/transactions.php
create mode 100644 resources/lang/lv-LV/transfers.php
create mode 100644 resources/lang/lv-LV/updates.php
create mode 100644 resources/lang/lv-LV/validation.php
create mode 100644 resources/lang/lv-LV/vendors.php
create mode 100644 resources/lang/lv-LV/widgets.php
create mode 100644 resources/lang/mk-MK/accounts.php
create mode 100644 resources/lang/mk-MK/auth.php
create mode 100644 resources/lang/mk-MK/bills.php
create mode 100644 resources/lang/mk-MK/categories.php
create mode 100644 resources/lang/mk-MK/companies.php
create mode 100644 resources/lang/mk-MK/countries.php
create mode 100644 resources/lang/mk-MK/currencies.php
create mode 100644 resources/lang/mk-MK/customers.php
create mode 100644 resources/lang/mk-MK/dashboard.php
create mode 100644 resources/lang/mk-MK/dashboards.php
create mode 100644 resources/lang/mk-MK/demo.php
create mode 100644 resources/lang/mk-MK/documents.php
create mode 100644 resources/lang/mk-MK/email_templates.php
create mode 100644 resources/lang/mk-MK/errors.php
create mode 100644 resources/lang/mk-MK/footer.php
create mode 100644 resources/lang/mk-MK/general.php
create mode 100644 resources/lang/mk-MK/header.php
create mode 100644 resources/lang/mk-MK/import.php
create mode 100644 resources/lang/mk-MK/install.php
create mode 100644 resources/lang/mk-MK/invoices.php
create mode 100644 resources/lang/mk-MK/items.php
create mode 100644 resources/lang/mk-MK/maintenance.php
create mode 100644 resources/lang/mk-MK/messages.php
create mode 100644 resources/lang/mk-MK/modules.php
create mode 100644 resources/lang/mk-MK/notifications.php
create mode 100644 resources/lang/mk-MK/pagination.php
create mode 100644 resources/lang/mk-MK/passwords.php
create mode 100644 resources/lang/mk-MK/payments.php
create mode 100644 resources/lang/mk-MK/portal.php
create mode 100644 resources/lang/mk-MK/reconciliations.php
create mode 100644 resources/lang/mk-MK/recurring.php
create mode 100644 resources/lang/mk-MK/reports.php
create mode 100644 resources/lang/mk-MK/revenues.php
create mode 100644 resources/lang/mk-MK/search_string.php
create mode 100644 resources/lang/mk-MK/settings.php
create mode 100644 resources/lang/mk-MK/taxes.php
create mode 100644 resources/lang/mk-MK/transactions.php
create mode 100644 resources/lang/mk-MK/transfers.php
create mode 100644 resources/lang/mk-MK/updates.php
create mode 100644 resources/lang/mk-MK/validation.php
create mode 100644 resources/lang/mk-MK/vendors.php
create mode 100644 resources/lang/mk-MK/widgets.php
create mode 100644 resources/lang/ms-MY/accounts.php
create mode 100644 resources/lang/ms-MY/auth.php
create mode 100644 resources/lang/ms-MY/bills.php
create mode 100644 resources/lang/ms-MY/bulk_actions.php
create mode 100644 resources/lang/ms-MY/categories.php
create mode 100644 resources/lang/ms-MY/companies.php
create mode 100644 resources/lang/ms-MY/countries.php
create mode 100644 resources/lang/ms-MY/currencies.php
create mode 100644 resources/lang/ms-MY/customers.php
create mode 100644 resources/lang/ms-MY/dashboards.php
create mode 100644 resources/lang/ms-MY/demo.php
create mode 100644 resources/lang/ms-MY/documents.php
create mode 100644 resources/lang/ms-MY/email_templates.php
create mode 100644 resources/lang/ms-MY/errors.php
create mode 100644 resources/lang/ms-MY/footer.php
create mode 100644 resources/lang/ms-MY/general.php
create mode 100644 resources/lang/ms-MY/header.php
create mode 100644 resources/lang/ms-MY/import.php
create mode 100644 resources/lang/ms-MY/install.php
create mode 100644 resources/lang/ms-MY/invoices.php
create mode 100644 resources/lang/ms-MY/items.php
create mode 100644 resources/lang/ms-MY/maintenance.php
create mode 100644 resources/lang/ms-MY/messages.php
create mode 100644 resources/lang/ms-MY/modules.php
create mode 100644 resources/lang/ms-MY/notifications.php
create mode 100644 resources/lang/ms-MY/pagination.php
create mode 100644 resources/lang/ms-MY/passwords.php
create mode 100644 resources/lang/ms-MY/portal.php
create mode 100644 resources/lang/ms-MY/reconciliations.php
create mode 100644 resources/lang/ms-MY/recurring.php
create mode 100644 resources/lang/ms-MY/reports.php
create mode 100644 resources/lang/ms-MY/search_string.php
create mode 100644 resources/lang/ms-MY/settings.php
create mode 100644 resources/lang/ms-MY/taxes.php
create mode 100644 resources/lang/ms-MY/transactions.php
create mode 100644 resources/lang/ms-MY/transfers.php
create mode 100644 resources/lang/ms-MY/updates.php
create mode 100644 resources/lang/ms-MY/validation.php
create mode 100644 resources/lang/ms-MY/vendors.php
create mode 100644 resources/lang/ms-MY/widgets.php
create mode 100644 resources/lang/nb-NO/accounts.php
create mode 100644 resources/lang/nb-NO/auth.php
create mode 100644 resources/lang/nb-NO/bills.php
create mode 100644 resources/lang/nb-NO/bulk_actions.php
create mode 100644 resources/lang/nb-NO/categories.php
create mode 100644 resources/lang/nb-NO/companies.php
create mode 100644 resources/lang/nb-NO/countries.php
create mode 100644 resources/lang/nb-NO/currencies.php
create mode 100644 resources/lang/nb-NO/customers.php
create mode 100644 resources/lang/nb-NO/dashboards.php
create mode 100644 resources/lang/nb-NO/demo.php
create mode 100644 resources/lang/nb-NO/documents.php
create mode 100644 resources/lang/nb-NO/email_templates.php
create mode 100644 resources/lang/nb-NO/errors.php
create mode 100644 resources/lang/nb-NO/footer.php
create mode 100644 resources/lang/nb-NO/general.php
create mode 100644 resources/lang/nb-NO/header.php
create mode 100644 resources/lang/nb-NO/import.php
create mode 100644 resources/lang/nb-NO/install.php
create mode 100644 resources/lang/nb-NO/invoices.php
create mode 100644 resources/lang/nb-NO/items.php
create mode 100644 resources/lang/nb-NO/maintenance.php
create mode 100644 resources/lang/nb-NO/messages.php
create mode 100644 resources/lang/nb-NO/modules.php
create mode 100644 resources/lang/nb-NO/notifications.php
create mode 100644 resources/lang/nb-NO/pagination.php
create mode 100644 resources/lang/nb-NO/passwords.php
create mode 100644 resources/lang/nb-NO/payments.php
create mode 100644 resources/lang/nb-NO/portal.php
create mode 100644 resources/lang/nb-NO/reconciliations.php
create mode 100644 resources/lang/nb-NO/recurring.php
create mode 100644 resources/lang/nb-NO/reports.php
create mode 100644 resources/lang/nb-NO/revenues.php
create mode 100644 resources/lang/nb-NO/search_string.php
create mode 100644 resources/lang/nb-NO/settings.php
create mode 100644 resources/lang/nb-NO/taxes.php
create mode 100644 resources/lang/nb-NO/transactions.php
create mode 100644 resources/lang/nb-NO/transfers.php
create mode 100644 resources/lang/nb-NO/updates.php
create mode 100644 resources/lang/nb-NO/validation.php
create mode 100644 resources/lang/nb-NO/vendors.php
create mode 100644 resources/lang/nb-NO/widgets.php
create mode 100644 resources/lang/ne-NP/accounts.php
create mode 100644 resources/lang/ne-NP/auth.php
create mode 100644 resources/lang/ne-NP/bills.php
create mode 100644 resources/lang/ne-NP/bulk_actions.php
create mode 100644 resources/lang/ne-NP/companies.php
create mode 100644 resources/lang/ne-NP/countries.php
create mode 100644 resources/lang/ne-NP/currencies.php
create mode 100644 resources/lang/ne-NP/customers.php
create mode 100644 resources/lang/ne-NP/dashboards.php
create mode 100644 resources/lang/ne-NP/demo.php
create mode 100644 resources/lang/ne-NP/documents.php
create mode 100644 resources/lang/ne-NP/email_templates.php
create mode 100644 resources/lang/ne-NP/errors.php
create mode 100644 resources/lang/ne-NP/footer.php
create mode 100644 resources/lang/ne-NP/general.php
create mode 100644 resources/lang/ne-NP/header.php
create mode 100644 resources/lang/ne-NP/import.php
create mode 100644 resources/lang/ne-NP/install.php
create mode 100644 resources/lang/ne-NP/invoices.php
create mode 100644 resources/lang/ne-NP/items.php
create mode 100644 resources/lang/ne-NP/maintenance.php
create mode 100644 resources/lang/ne-NP/messages.php
create mode 100644 resources/lang/ne-NP/modules.php
create mode 100644 resources/lang/ne-NP/notifications.php
create mode 100644 resources/lang/ne-NP/pagination.php
create mode 100644 resources/lang/ne-NP/passwords.php
create mode 100644 resources/lang/ne-NP/reconciliations.php
create mode 100644 resources/lang/ne-NP/recurring.php
create mode 100644 resources/lang/ne-NP/reports.php
create mode 100644 resources/lang/ne-NP/search_string.php
create mode 100644 resources/lang/ne-NP/settings.php
create mode 100644 resources/lang/ne-NP/taxes.php
create mode 100644 resources/lang/ne-NP/transfers.php
create mode 100644 resources/lang/ne-NP/updates.php
create mode 100644 resources/lang/ne-NP/validation.php
create mode 100644 resources/lang/ne-NP/widgets.php
create mode 100644 resources/lang/nl-NL/accounts.php
create mode 100644 resources/lang/nl-NL/auth.php
create mode 100644 resources/lang/nl-NL/bills.php
create mode 100644 resources/lang/nl-NL/bulk_actions.php
create mode 100644 resources/lang/nl-NL/categories.php
create mode 100644 resources/lang/nl-NL/companies.php
create mode 100644 resources/lang/nl-NL/countries.php
create mode 100644 resources/lang/nl-NL/currencies.php
create mode 100644 resources/lang/nl-NL/customers.php
create mode 100644 resources/lang/nl-NL/dashboards.php
create mode 100644 resources/lang/nl-NL/demo.php
create mode 100644 resources/lang/nl-NL/documents.php
create mode 100644 resources/lang/nl-NL/email_templates.php
create mode 100644 resources/lang/nl-NL/errors.php
create mode 100644 resources/lang/nl-NL/footer.php
create mode 100644 resources/lang/nl-NL/general.php
create mode 100644 resources/lang/nl-NL/header.php
create mode 100644 resources/lang/nl-NL/import.php
create mode 100644 resources/lang/nl-NL/install.php
create mode 100644 resources/lang/nl-NL/invoices.php
create mode 100644 resources/lang/nl-NL/items.php
create mode 100644 resources/lang/nl-NL/maintenance.php
create mode 100644 resources/lang/nl-NL/messages.php
create mode 100644 resources/lang/nl-NL/modules.php
create mode 100644 resources/lang/nl-NL/notifications.php
create mode 100644 resources/lang/nl-NL/pagination.php
create mode 100644 resources/lang/nl-NL/passwords.php
create mode 100644 resources/lang/nl-NL/portal.php
create mode 100644 resources/lang/nl-NL/reconciliations.php
create mode 100644 resources/lang/nl-NL/recurring.php
create mode 100644 resources/lang/nl-NL/reports.php
create mode 100644 resources/lang/nl-NL/search_string.php
create mode 100644 resources/lang/nl-NL/settings.php
create mode 100644 resources/lang/nl-NL/taxes.php
create mode 100644 resources/lang/nl-NL/transactions.php
create mode 100644 resources/lang/nl-NL/transfers.php
create mode 100644 resources/lang/nl-NL/updates.php
create mode 100644 resources/lang/nl-NL/validation.php
create mode 100644 resources/lang/nl-NL/vendors.php
create mode 100644 resources/lang/nl-NL/widgets.php
create mode 100644 resources/lang/pl-PL/accounts.php
create mode 100644 resources/lang/pl-PL/auth.php
create mode 100644 resources/lang/pl-PL/bills.php
create mode 100644 resources/lang/pl-PL/bulk_actions.php
create mode 100644 resources/lang/pl-PL/categories.php
create mode 100644 resources/lang/pl-PL/companies.php
create mode 100644 resources/lang/pl-PL/countries.php
create mode 100644 resources/lang/pl-PL/currencies.php
create mode 100644 resources/lang/pl-PL/customers.php
create mode 100644 resources/lang/pl-PL/dashboards.php
create mode 100644 resources/lang/pl-PL/demo.php
create mode 100644 resources/lang/pl-PL/documents.php
create mode 100644 resources/lang/pl-PL/email_templates.php
create mode 100644 resources/lang/pl-PL/errors.php
create mode 100644 resources/lang/pl-PL/footer.php
create mode 100644 resources/lang/pl-PL/general.php
create mode 100644 resources/lang/pl-PL/header.php
create mode 100644 resources/lang/pl-PL/import.php
create mode 100644 resources/lang/pl-PL/install.php
create mode 100644 resources/lang/pl-PL/invoices.php
create mode 100644 resources/lang/pl-PL/items.php
create mode 100644 resources/lang/pl-PL/maintenance.php
create mode 100644 resources/lang/pl-PL/messages.php
create mode 100644 resources/lang/pl-PL/modules.php
create mode 100644 resources/lang/pl-PL/notifications.php
create mode 100644 resources/lang/pl-PL/pagination.php
create mode 100644 resources/lang/pl-PL/passwords.php
create mode 100644 resources/lang/pl-PL/portal.php
create mode 100644 resources/lang/pl-PL/reconciliations.php
create mode 100644 resources/lang/pl-PL/recurring.php
create mode 100644 resources/lang/pl-PL/reports.php
create mode 100644 resources/lang/pl-PL/search_string.php
create mode 100644 resources/lang/pl-PL/settings.php
create mode 100644 resources/lang/pl-PL/taxes.php
create mode 100644 resources/lang/pl-PL/transactions.php
create mode 100644 resources/lang/pl-PL/transfers.php
create mode 100644 resources/lang/pl-PL/updates.php
create mode 100644 resources/lang/pl-PL/validation.php
create mode 100644 resources/lang/pl-PL/vendors.php
create mode 100644 resources/lang/pl-PL/widgets.php
create mode 100644 resources/lang/pt-BR/accounts.php
create mode 100644 resources/lang/pt-BR/auth.php
create mode 100644 resources/lang/pt-BR/bills.php
create mode 100644 resources/lang/pt-BR/bulk_actions.php
create mode 100644 resources/lang/pt-BR/categories.php
create mode 100644 resources/lang/pt-BR/companies.php
create mode 100644 resources/lang/pt-BR/countries.php
create mode 100644 resources/lang/pt-BR/currencies.php
create mode 100644 resources/lang/pt-BR/customers.php
create mode 100644 resources/lang/pt-BR/dashboards.php
create mode 100644 resources/lang/pt-BR/demo.php
create mode 100644 resources/lang/pt-BR/documents.php
create mode 100644 resources/lang/pt-BR/email_templates.php
create mode 100644 resources/lang/pt-BR/errors.php
create mode 100644 resources/lang/pt-BR/footer.php
create mode 100644 resources/lang/pt-BR/general.php
create mode 100644 resources/lang/pt-BR/header.php
create mode 100644 resources/lang/pt-BR/import.php
create mode 100644 resources/lang/pt-BR/install.php
create mode 100644 resources/lang/pt-BR/invoices.php
create mode 100644 resources/lang/pt-BR/items.php
create mode 100644 resources/lang/pt-BR/maintenance.php
create mode 100644 resources/lang/pt-BR/messages.php
create mode 100644 resources/lang/pt-BR/modules.php
create mode 100644 resources/lang/pt-BR/notifications.php
create mode 100644 resources/lang/pt-BR/pagination.php
create mode 100644 resources/lang/pt-BR/passwords.php
create mode 100644 resources/lang/pt-BR/portal.php
create mode 100644 resources/lang/pt-BR/reconciliations.php
create mode 100644 resources/lang/pt-BR/recurring.php
create mode 100644 resources/lang/pt-BR/reports.php
create mode 100644 resources/lang/pt-BR/search_string.php
create mode 100644 resources/lang/pt-BR/settings.php
create mode 100644 resources/lang/pt-BR/taxes.php
create mode 100644 resources/lang/pt-BR/transactions.php
create mode 100644 resources/lang/pt-BR/transfers.php
create mode 100644 resources/lang/pt-BR/updates.php
create mode 100644 resources/lang/pt-BR/validation.php
create mode 100644 resources/lang/pt-BR/vendors.php
create mode 100644 resources/lang/pt-BR/widgets.php
create mode 100644 resources/lang/pt-PT/accounts.php
create mode 100644 resources/lang/pt-PT/auth.php
create mode 100644 resources/lang/pt-PT/bills.php
create mode 100644 resources/lang/pt-PT/bulk_actions.php
create mode 100644 resources/lang/pt-PT/companies.php
create mode 100644 resources/lang/pt-PT/countries.php
create mode 100644 resources/lang/pt-PT/currencies.php
create mode 100644 resources/lang/pt-PT/customers.php
create mode 100644 resources/lang/pt-PT/dashboards.php
create mode 100644 resources/lang/pt-PT/demo.php
create mode 100644 resources/lang/pt-PT/email_templates.php
create mode 100644 resources/lang/pt-PT/errors.php
create mode 100644 resources/lang/pt-PT/footer.php
create mode 100644 resources/lang/pt-PT/general.php
create mode 100644 resources/lang/pt-PT/header.php
create mode 100644 resources/lang/pt-PT/import.php
create mode 100644 resources/lang/pt-PT/install.php
create mode 100644 resources/lang/pt-PT/invoices.php
create mode 100644 resources/lang/pt-PT/items.php
create mode 100644 resources/lang/pt-PT/maintenance.php
create mode 100644 resources/lang/pt-PT/messages.php
create mode 100644 resources/lang/pt-PT/modules.php
create mode 100644 resources/lang/pt-PT/notifications.php
create mode 100644 resources/lang/pt-PT/pagination.php
create mode 100644 resources/lang/pt-PT/passwords.php
create mode 100644 resources/lang/pt-PT/reconciliations.php
create mode 100644 resources/lang/pt-PT/recurring.php
create mode 100644 resources/lang/pt-PT/reports.php
create mode 100644 resources/lang/pt-PT/settings.php
create mode 100644 resources/lang/pt-PT/taxes.php
create mode 100644 resources/lang/pt-PT/transfers.php
create mode 100644 resources/lang/pt-PT/updates.php
create mode 100644 resources/lang/pt-PT/validation.php
create mode 100644 resources/lang/pt-PT/widgets.php
create mode 100644 resources/lang/ro-RO/accounts.php
create mode 100644 resources/lang/ro-RO/auth.php
create mode 100644 resources/lang/ro-RO/bills.php
create mode 100644 resources/lang/ro-RO/bulk_actions.php
create mode 100644 resources/lang/ro-RO/categories.php
create mode 100644 resources/lang/ro-RO/companies.php
create mode 100644 resources/lang/ro-RO/countries.php
create mode 100644 resources/lang/ro-RO/currencies.php
create mode 100644 resources/lang/ro-RO/customers.php
create mode 100644 resources/lang/ro-RO/dashboard.php
create mode 100644 resources/lang/ro-RO/dashboards.php
create mode 100644 resources/lang/ro-RO/demo.php
create mode 100644 resources/lang/ro-RO/documents.php
create mode 100644 resources/lang/ro-RO/email_templates.php
create mode 100644 resources/lang/ro-RO/errors.php
create mode 100644 resources/lang/ro-RO/footer.php
create mode 100644 resources/lang/ro-RO/general.php
create mode 100644 resources/lang/ro-RO/header.php
create mode 100644 resources/lang/ro-RO/import.php
create mode 100644 resources/lang/ro-RO/install.php
create mode 100644 resources/lang/ro-RO/invoices.php
create mode 100644 resources/lang/ro-RO/items.php
create mode 100644 resources/lang/ro-RO/maintenance.php
create mode 100644 resources/lang/ro-RO/messages.php
create mode 100644 resources/lang/ro-RO/modules.php
create mode 100644 resources/lang/ro-RO/notifications.php
create mode 100644 resources/lang/ro-RO/pagination.php
create mode 100644 resources/lang/ro-RO/passwords.php
create mode 100644 resources/lang/ro-RO/portal.php
create mode 100644 resources/lang/ro-RO/reconciliations.php
create mode 100644 resources/lang/ro-RO/recurring.php
create mode 100644 resources/lang/ro-RO/reports.php
create mode 100644 resources/lang/ro-RO/search_string.php
create mode 100644 resources/lang/ro-RO/settings.php
create mode 100644 resources/lang/ro-RO/taxes.php
create mode 100644 resources/lang/ro-RO/transfers.php
create mode 100644 resources/lang/ro-RO/updates.php
create mode 100644 resources/lang/ro-RO/validation.php
create mode 100644 resources/lang/ro-RO/vendors.php
create mode 100644 resources/lang/ro-RO/widgets.php
create mode 100644 resources/lang/ru-RU/accounts.php
create mode 100644 resources/lang/ru-RU/auth.php
create mode 100644 resources/lang/ru-RU/bills.php
create mode 100644 resources/lang/ru-RU/bulk_actions.php
create mode 100644 resources/lang/ru-RU/categories.php
create mode 100644 resources/lang/ru-RU/companies.php
create mode 100644 resources/lang/ru-RU/countries.php
create mode 100644 resources/lang/ru-RU/currencies.php
create mode 100644 resources/lang/ru-RU/customers.php
create mode 100644 resources/lang/ru-RU/dashboards.php
create mode 100644 resources/lang/ru-RU/demo.php
create mode 100644 resources/lang/ru-RU/documents.php
create mode 100644 resources/lang/ru-RU/email_templates.php
create mode 100644 resources/lang/ru-RU/errors.php
create mode 100644 resources/lang/ru-RU/footer.php
create mode 100644 resources/lang/ru-RU/general.php
create mode 100644 resources/lang/ru-RU/header.php
create mode 100644 resources/lang/ru-RU/import.php
create mode 100644 resources/lang/ru-RU/install.php
create mode 100644 resources/lang/ru-RU/invoices.php
create mode 100644 resources/lang/ru-RU/items.php
create mode 100644 resources/lang/ru-RU/maintenance.php
create mode 100644 resources/lang/ru-RU/messages.php
create mode 100644 resources/lang/ru-RU/modules.php
create mode 100644 resources/lang/ru-RU/notifications.php
create mode 100644 resources/lang/ru-RU/pagination.php
create mode 100644 resources/lang/ru-RU/passwords.php
create mode 100644 resources/lang/ru-RU/portal.php
create mode 100644 resources/lang/ru-RU/reconciliations.php
create mode 100644 resources/lang/ru-RU/recurring.php
create mode 100644 resources/lang/ru-RU/reports.php
create mode 100644 resources/lang/ru-RU/search_string.php
create mode 100644 resources/lang/ru-RU/settings.php
create mode 100644 resources/lang/ru-RU/taxes.php
create mode 100644 resources/lang/ru-RU/transactions.php
create mode 100644 resources/lang/ru-RU/transfers.php
create mode 100644 resources/lang/ru-RU/updates.php
create mode 100644 resources/lang/ru-RU/validation.php
create mode 100644 resources/lang/ru-RU/vendors.php
create mode 100644 resources/lang/ru-RU/widgets.php
create mode 100644 resources/lang/si-LK/passwords.php
create mode 100644 resources/lang/sk-SK/accounts.php
create mode 100644 resources/lang/sk-SK/auth.php
create mode 100644 resources/lang/sk-SK/bills.php
create mode 100644 resources/lang/sk-SK/bulk_actions.php
create mode 100644 resources/lang/sk-SK/categories.php
create mode 100644 resources/lang/sk-SK/companies.php
create mode 100644 resources/lang/sk-SK/countries.php
create mode 100644 resources/lang/sk-SK/currencies.php
create mode 100644 resources/lang/sk-SK/customers.php
create mode 100644 resources/lang/sk-SK/dashboard.php
create mode 100644 resources/lang/sk-SK/dashboards.php
create mode 100644 resources/lang/sk-SK/demo.php
create mode 100644 resources/lang/sk-SK/errors.php
create mode 100644 resources/lang/sk-SK/footer.php
create mode 100644 resources/lang/sk-SK/general.php
create mode 100644 resources/lang/sk-SK/header.php
create mode 100644 resources/lang/sk-SK/import.php
create mode 100644 resources/lang/sk-SK/install.php
create mode 100644 resources/lang/sk-SK/invoices.php
create mode 100644 resources/lang/sk-SK/items.php
create mode 100644 resources/lang/sk-SK/messages.php
create mode 100644 resources/lang/sk-SK/modules.php
create mode 100644 resources/lang/sk-SK/notifications.php
create mode 100644 resources/lang/sk-SK/pagination.php
create mode 100644 resources/lang/sk-SK/passwords.php
create mode 100644 resources/lang/sk-SK/reconciliations.php
create mode 100644 resources/lang/sk-SK/recurring.php
create mode 100644 resources/lang/sk-SK/reports.php
create mode 100644 resources/lang/sk-SK/search_string.php
create mode 100644 resources/lang/sk-SK/settings.php
create mode 100644 resources/lang/sk-SK/taxes.php
create mode 100644 resources/lang/sk-SK/transfers.php
create mode 100644 resources/lang/sk-SK/updates.php
create mode 100644 resources/lang/sk-SK/validation.php
create mode 100644 resources/lang/sl-SI/accounts.php
create mode 100644 resources/lang/sl-SI/auth.php
create mode 100644 resources/lang/sl-SI/bills.php
create mode 100644 resources/lang/sl-SI/bulk_actions.php
create mode 100644 resources/lang/sl-SI/categories.php
create mode 100644 resources/lang/sl-SI/companies.php
create mode 100644 resources/lang/sl-SI/countries.php
create mode 100644 resources/lang/sl-SI/currencies.php
create mode 100644 resources/lang/sl-SI/customers.php
create mode 100644 resources/lang/sl-SI/dashboards.php
create mode 100644 resources/lang/sl-SI/demo.php
create mode 100644 resources/lang/sl-SI/documents.php
create mode 100644 resources/lang/sl-SI/email_templates.php
create mode 100644 resources/lang/sl-SI/errors.php
create mode 100644 resources/lang/sl-SI/footer.php
create mode 100644 resources/lang/sl-SI/general.php
create mode 100644 resources/lang/sl-SI/header.php
create mode 100644 resources/lang/sl-SI/import.php
create mode 100644 resources/lang/sl-SI/install.php
create mode 100644 resources/lang/sl-SI/invoices.php
create mode 100644 resources/lang/sl-SI/items.php
create mode 100644 resources/lang/sl-SI/maintenance.php
create mode 100644 resources/lang/sl-SI/messages.php
create mode 100644 resources/lang/sl-SI/modules.php
create mode 100644 resources/lang/sl-SI/notifications.php
create mode 100644 resources/lang/sl-SI/pagination.php
create mode 100644 resources/lang/sl-SI/passwords.php
create mode 100644 resources/lang/sl-SI/payments.php
create mode 100644 resources/lang/sl-SI/portal.php
create mode 100644 resources/lang/sl-SI/reconciliations.php
create mode 100644 resources/lang/sl-SI/recurring.php
create mode 100644 resources/lang/sl-SI/reports.php
create mode 100644 resources/lang/sl-SI/revenues.php
create mode 100644 resources/lang/sl-SI/search_string.php
create mode 100644 resources/lang/sl-SI/settings.php
create mode 100644 resources/lang/sl-SI/taxes.php
create mode 100644 resources/lang/sl-SI/transactions.php
create mode 100644 resources/lang/sl-SI/transfers.php
create mode 100644 resources/lang/sl-SI/updates.php
create mode 100644 resources/lang/sl-SI/validation.php
create mode 100644 resources/lang/sl-SI/vendors.php
create mode 100644 resources/lang/sl-SI/widgets.php
create mode 100644 resources/lang/sq-AL/accounts.php
create mode 100644 resources/lang/sq-AL/auth.php
create mode 100644 resources/lang/sq-AL/bills.php
create mode 100644 resources/lang/sq-AL/bulk_actions.php
create mode 100644 resources/lang/sq-AL/companies.php
create mode 100644 resources/lang/sq-AL/countries.php
create mode 100644 resources/lang/sq-AL/currencies.php
create mode 100644 resources/lang/sq-AL/customers.php
create mode 100644 resources/lang/sq-AL/dashboards.php
create mode 100644 resources/lang/sq-AL/demo.php
create mode 100644 resources/lang/sq-AL/documents.php
create mode 100644 resources/lang/sq-AL/email_templates.php
create mode 100644 resources/lang/sq-AL/errors.php
create mode 100644 resources/lang/sq-AL/footer.php
create mode 100644 resources/lang/sq-AL/general.php
create mode 100644 resources/lang/sq-AL/header.php
create mode 100644 resources/lang/sq-AL/import.php
create mode 100644 resources/lang/sq-AL/install.php
create mode 100644 resources/lang/sq-AL/invoices.php
create mode 100644 resources/lang/sq-AL/items.php
create mode 100644 resources/lang/sq-AL/maintenance.php
create mode 100644 resources/lang/sq-AL/messages.php
create mode 100644 resources/lang/sq-AL/modules.php
create mode 100644 resources/lang/sq-AL/notifications.php
create mode 100644 resources/lang/sq-AL/pagination.php
create mode 100644 resources/lang/sq-AL/passwords.php
create mode 100644 resources/lang/sq-AL/reconciliations.php
create mode 100644 resources/lang/sq-AL/recurring.php
create mode 100644 resources/lang/sq-AL/reports.php
create mode 100644 resources/lang/sq-AL/search_string.php
create mode 100644 resources/lang/sq-AL/settings.php
create mode 100644 resources/lang/sq-AL/taxes.php
create mode 100644 resources/lang/sq-AL/transfers.php
create mode 100644 resources/lang/sq-AL/updates.php
create mode 100644 resources/lang/sq-AL/validation.php
create mode 100644 resources/lang/sq-AL/widgets.php
create mode 100644 resources/lang/sr-CS/accounts.php
create mode 100644 resources/lang/sr-CS/auth.php
create mode 100644 resources/lang/sr-CS/bills.php
create mode 100644 resources/lang/sr-CS/bulk_actions.php
create mode 100644 resources/lang/sr-CS/companies.php
create mode 100644 resources/lang/sr-CS/countries.php
create mode 100644 resources/lang/sr-CS/currencies.php
create mode 100644 resources/lang/sr-CS/customers.php
create mode 100644 resources/lang/sr-CS/dashboards.php
create mode 100644 resources/lang/sr-CS/demo.php
create mode 100644 resources/lang/sr-CS/documents.php
create mode 100644 resources/lang/sr-CS/errors.php
create mode 100644 resources/lang/sr-CS/footer.php
create mode 100644 resources/lang/sr-CS/import.php
create mode 100644 resources/lang/sr-CS/items.php
create mode 100644 resources/lang/sr-CS/pagination.php
create mode 100644 resources/lang/sr-CS/passwords.php
create mode 100644 resources/lang/sr-CS/search_string.php
create mode 100644 resources/lang/sr-CS/taxes.php
create mode 100644 resources/lang/sr-CS/transfers.php
create mode 100644 resources/lang/sr-CS/updates.php
create mode 100644 resources/lang/sr-CS/widgets.php
create mode 100644 resources/lang/sr-RS/accounts.php
create mode 100644 resources/lang/sr-RS/auth.php
create mode 100644 resources/lang/sr-RS/bills.php
create mode 100644 resources/lang/sr-RS/companies.php
create mode 100644 resources/lang/sr-RS/countries.php
create mode 100644 resources/lang/sr-RS/currencies.php
create mode 100644 resources/lang/sr-RS/customers.php
create mode 100644 resources/lang/sr-RS/dashboard.php
create mode 100644 resources/lang/sr-RS/demo.php
create mode 100644 resources/lang/sr-RS/footer.php
create mode 100644 resources/lang/sr-RS/general.php
create mode 100644 resources/lang/sr-RS/header.php
create mode 100644 resources/lang/sr-RS/import.php
create mode 100644 resources/lang/sr-RS/install.php
create mode 100644 resources/lang/sr-RS/invoices.php
create mode 100644 resources/lang/sr-RS/items.php
create mode 100644 resources/lang/sr-RS/messages.php
create mode 100644 resources/lang/sr-RS/modules.php
create mode 100644 resources/lang/sr-RS/notifications.php
create mode 100644 resources/lang/sr-RS/pagination.php
create mode 100644 resources/lang/sr-RS/passwords.php
create mode 100644 resources/lang/sr-RS/reconciliations.php
create mode 100644 resources/lang/sr-RS/recurring.php
create mode 100644 resources/lang/sr-RS/reports.php
create mode 100644 resources/lang/sr-RS/settings.php
create mode 100644 resources/lang/sr-RS/taxes.php
create mode 100644 resources/lang/sr-RS/transfers.php
create mode 100644 resources/lang/sr-RS/updates.php
create mode 100644 resources/lang/sr-RS/validation.php
create mode 100644 resources/lang/sr-SP/accounts.php
create mode 100644 resources/lang/sr-SP/auth.php
create mode 100644 resources/lang/sr-SP/bills.php
create mode 100644 resources/lang/sr-SP/countries.php
create mode 100644 resources/lang/sr-SP/currencies.php
create mode 100644 resources/lang/sr-SP/footer.php
create mode 100644 resources/lang/sr-SP/header.php
create mode 100644 resources/lang/sr-SP/import.php
create mode 100644 resources/lang/sr-SP/items.php
create mode 100644 resources/lang/sr-SP/notifications.php
create mode 100644 resources/lang/sr-SP/recurring.php
create mode 100644 resources/lang/sr-SP/transfers.php
create mode 100644 resources/lang/sr-SP/updates.php
create mode 100644 resources/lang/sv-SE/accounts.php
create mode 100644 resources/lang/sv-SE/auth.php
create mode 100644 resources/lang/sv-SE/bills.php
create mode 100644 resources/lang/sv-SE/bulk_actions.php
create mode 100644 resources/lang/sv-SE/categories.php
create mode 100644 resources/lang/sv-SE/companies.php
create mode 100644 resources/lang/sv-SE/countries.php
create mode 100644 resources/lang/sv-SE/currencies.php
create mode 100644 resources/lang/sv-SE/customers.php
create mode 100644 resources/lang/sv-SE/dashboards.php
create mode 100644 resources/lang/sv-SE/demo.php
create mode 100644 resources/lang/sv-SE/documents.php
create mode 100644 resources/lang/sv-SE/email_templates.php
create mode 100644 resources/lang/sv-SE/errors.php
create mode 100644 resources/lang/sv-SE/footer.php
create mode 100644 resources/lang/sv-SE/general.php
create mode 100644 resources/lang/sv-SE/header.php
create mode 100644 resources/lang/sv-SE/import.php
create mode 100644 resources/lang/sv-SE/install.php
create mode 100644 resources/lang/sv-SE/invoices.php
create mode 100644 resources/lang/sv-SE/items.php
create mode 100644 resources/lang/sv-SE/maintenance.php
create mode 100644 resources/lang/sv-SE/messages.php
create mode 100644 resources/lang/sv-SE/modules.php
create mode 100644 resources/lang/sv-SE/notifications.php
create mode 100644 resources/lang/sv-SE/pagination.php
create mode 100644 resources/lang/sv-SE/passwords.php
create mode 100644 resources/lang/sv-SE/payments.php
create mode 100644 resources/lang/sv-SE/portal.php
create mode 100644 resources/lang/sv-SE/reconciliations.php
create mode 100644 resources/lang/sv-SE/recurring.php
create mode 100644 resources/lang/sv-SE/reports.php
create mode 100644 resources/lang/sv-SE/revenues.php
create mode 100644 resources/lang/sv-SE/search_string.php
create mode 100644 resources/lang/sv-SE/settings.php
create mode 100644 resources/lang/sv-SE/taxes.php
create mode 100644 resources/lang/sv-SE/transactions.php
create mode 100644 resources/lang/sv-SE/transfers.php
create mode 100644 resources/lang/sv-SE/updates.php
create mode 100644 resources/lang/sv-SE/validation.php
create mode 100644 resources/lang/sv-SE/vendors.php
create mode 100644 resources/lang/sv-SE/widgets.php
create mode 100644 resources/lang/sw-KE/passwords.php
create mode 100644 resources/lang/ta-IN/accounts.php
create mode 100644 resources/lang/ta-IN/auth.php
create mode 100644 resources/lang/ta-IN/countries.php
create mode 100644 resources/lang/th-TH/accounts.php
create mode 100644 resources/lang/th-TH/auth.php
create mode 100644 resources/lang/th-TH/bills.php
create mode 100644 resources/lang/th-TH/companies.php
create mode 100644 resources/lang/th-TH/countries.php
create mode 100644 resources/lang/th-TH/currencies.php
create mode 100644 resources/lang/th-TH/customers.php
create mode 100644 resources/lang/th-TH/dashboard.php
create mode 100644 resources/lang/th-TH/dashboards.php
create mode 100644 resources/lang/th-TH/demo.php
create mode 100644 resources/lang/th-TH/errors.php
create mode 100644 resources/lang/th-TH/footer.php
create mode 100644 resources/lang/th-TH/general.php
create mode 100644 resources/lang/th-TH/header.php
create mode 100644 resources/lang/th-TH/import.php
create mode 100644 resources/lang/th-TH/install.php
create mode 100644 resources/lang/th-TH/invoices.php
create mode 100644 resources/lang/th-TH/items.php
create mode 100644 resources/lang/th-TH/maintenance.php
create mode 100644 resources/lang/th-TH/messages.php
create mode 100644 resources/lang/th-TH/modules.php
create mode 100644 resources/lang/th-TH/notifications.php
create mode 100644 resources/lang/th-TH/pagination.php
create mode 100644 resources/lang/th-TH/passwords.php
create mode 100644 resources/lang/th-TH/reconciliations.php
create mode 100644 resources/lang/th-TH/recurring.php
create mode 100644 resources/lang/th-TH/reports.php
create mode 100644 resources/lang/th-TH/settings.php
create mode 100644 resources/lang/th-TH/taxes.php
create mode 100644 resources/lang/th-TH/transfers.php
create mode 100644 resources/lang/th-TH/updates.php
create mode 100644 resources/lang/th-TH/validation.php
create mode 100644 resources/lang/tr-TR/accounts.php
create mode 100644 resources/lang/tr-TR/auth.php
create mode 100644 resources/lang/tr-TR/bills.php
create mode 100644 resources/lang/tr-TR/bulk_actions.php
create mode 100644 resources/lang/tr-TR/categories.php
create mode 100644 resources/lang/tr-TR/companies.php
create mode 100644 resources/lang/tr-TR/countries.php
create mode 100644 resources/lang/tr-TR/currencies.php
create mode 100644 resources/lang/tr-TR/customers.php
create mode 100644 resources/lang/tr-TR/dashboards.php
create mode 100644 resources/lang/tr-TR/demo.php
create mode 100644 resources/lang/tr-TR/documents.php
create mode 100644 resources/lang/tr-TR/email_templates.php
create mode 100644 resources/lang/tr-TR/errors.php
create mode 100644 resources/lang/tr-TR/footer.php
create mode 100644 resources/lang/tr-TR/general.php
create mode 100644 resources/lang/tr-TR/header.php
create mode 100644 resources/lang/tr-TR/import.php
create mode 100644 resources/lang/tr-TR/install.php
create mode 100644 resources/lang/tr-TR/invoices.php
create mode 100644 resources/lang/tr-TR/items.php
create mode 100644 resources/lang/tr-TR/maintenance.php
create mode 100644 resources/lang/tr-TR/messages.php
create mode 100644 resources/lang/tr-TR/modules.php
create mode 100644 resources/lang/tr-TR/notifications.php
create mode 100644 resources/lang/tr-TR/pagination.php
create mode 100644 resources/lang/tr-TR/passwords.php
create mode 100644 resources/lang/tr-TR/portal.php
create mode 100644 resources/lang/tr-TR/reconciliations.php
create mode 100644 resources/lang/tr-TR/recurring.php
create mode 100644 resources/lang/tr-TR/reports.php
create mode 100644 resources/lang/tr-TR/search_string.php
create mode 100644 resources/lang/tr-TR/settings.php
create mode 100644 resources/lang/tr-TR/taxes.php
create mode 100644 resources/lang/tr-TR/transactions.php
create mode 100644 resources/lang/tr-TR/transfers.php
create mode 100644 resources/lang/tr-TR/updates.php
create mode 100644 resources/lang/tr-TR/validation.php
create mode 100644 resources/lang/tr-TR/vendors.php
create mode 100644 resources/lang/tr-TR/widgets.php
create mode 100644 resources/lang/uk-UA/accounts.php
create mode 100644 resources/lang/uk-UA/auth.php
create mode 100644 resources/lang/uk-UA/bills.php
create mode 100644 resources/lang/uk-UA/bulk_actions.php
create mode 100644 resources/lang/uk-UA/companies.php
create mode 100644 resources/lang/uk-UA/countries.php
create mode 100644 resources/lang/uk-UA/currencies.php
create mode 100644 resources/lang/uk-UA/customers.php
create mode 100644 resources/lang/uk-UA/dashboards.php
create mode 100644 resources/lang/uk-UA/demo.php
create mode 100644 resources/lang/uk-UA/email_templates.php
create mode 100644 resources/lang/uk-UA/errors.php
create mode 100644 resources/lang/uk-UA/footer.php
create mode 100644 resources/lang/uk-UA/general.php
create mode 100644 resources/lang/uk-UA/header.php
create mode 100644 resources/lang/uk-UA/import.php
create mode 100644 resources/lang/uk-UA/install.php
create mode 100644 resources/lang/uk-UA/invoices.php
create mode 100644 resources/lang/uk-UA/items.php
create mode 100644 resources/lang/uk-UA/maintenance.php
create mode 100644 resources/lang/uk-UA/messages.php
create mode 100644 resources/lang/uk-UA/modules.php
create mode 100644 resources/lang/uk-UA/notifications.php
create mode 100644 resources/lang/uk-UA/pagination.php
create mode 100644 resources/lang/uk-UA/passwords.php
create mode 100644 resources/lang/uk-UA/reconciliations.php
create mode 100644 resources/lang/uk-UA/recurring.php
create mode 100644 resources/lang/uk-UA/reports.php
create mode 100644 resources/lang/uk-UA/settings.php
create mode 100644 resources/lang/uk-UA/taxes.php
create mode 100644 resources/lang/uk-UA/transfers.php
create mode 100644 resources/lang/uk-UA/updates.php
create mode 100644 resources/lang/uk-UA/validation.php
create mode 100644 resources/lang/uk-UA/widgets.php
create mode 100644 resources/lang/ur-PK/accounts.php
create mode 100644 resources/lang/ur-PK/auth.php
create mode 100644 resources/lang/ur-PK/bills.php
create mode 100644 resources/lang/ur-PK/companies.php
create mode 100644 resources/lang/ur-PK/countries.php
create mode 100644 resources/lang/ur-PK/currencies.php
create mode 100644 resources/lang/ur-PK/customers.php
create mode 100644 resources/lang/ur-PK/dashboard.php
create mode 100644 resources/lang/ur-PK/demo.php
create mode 100644 resources/lang/ur-PK/errors.php
create mode 100644 resources/lang/ur-PK/footer.php
create mode 100644 resources/lang/ur-PK/general.php
create mode 100644 resources/lang/ur-PK/header.php
create mode 100644 resources/lang/ur-PK/import.php
create mode 100644 resources/lang/ur-PK/install.php
create mode 100644 resources/lang/ur-PK/invoices.php
create mode 100644 resources/lang/ur-PK/items.php
create mode 100644 resources/lang/ur-PK/messages.php
create mode 100644 resources/lang/ur-PK/modules.php
create mode 100644 resources/lang/ur-PK/notifications.php
create mode 100644 resources/lang/ur-PK/pagination.php
create mode 100644 resources/lang/ur-PK/passwords.php
create mode 100644 resources/lang/ur-PK/reconciliations.php
create mode 100644 resources/lang/ur-PK/recurring.php
create mode 100644 resources/lang/ur-PK/reports.php
create mode 100644 resources/lang/ur-PK/settings.php
create mode 100644 resources/lang/ur-PK/taxes.php
create mode 100644 resources/lang/ur-PK/transfers.php
create mode 100644 resources/lang/ur-PK/updates.php
create mode 100644 resources/lang/ur-PK/validation.php
create mode 100644 resources/lang/uz-UZ/accounts.php
create mode 100644 resources/lang/uz-UZ/auth.php
create mode 100644 resources/lang/uz-UZ/bills.php
create mode 100644 resources/lang/uz-UZ/bulk_actions.php
create mode 100644 resources/lang/uz-UZ/companies.php
create mode 100644 resources/lang/uz-UZ/countries.php
create mode 100644 resources/lang/uz-UZ/currencies.php
create mode 100644 resources/lang/uz-UZ/customers.php
create mode 100644 resources/lang/uz-UZ/dashboard.php
create mode 100644 resources/lang/uz-UZ/dashboards.php
create mode 100644 resources/lang/uz-UZ/demo.php
create mode 100644 resources/lang/uz-UZ/email_templates.php
create mode 100644 resources/lang/uz-UZ/errors.php
create mode 100644 resources/lang/uz-UZ/footer.php
create mode 100644 resources/lang/uz-UZ/general.php
create mode 100644 resources/lang/uz-UZ/header.php
create mode 100644 resources/lang/uz-UZ/import.php
create mode 100644 resources/lang/uz-UZ/install.php
create mode 100644 resources/lang/uz-UZ/invoices.php
create mode 100644 resources/lang/uz-UZ/items.php
create mode 100644 resources/lang/uz-UZ/maintenance.php
create mode 100644 resources/lang/uz-UZ/messages.php
create mode 100644 resources/lang/uz-UZ/modules.php
create mode 100644 resources/lang/uz-UZ/notifications.php
create mode 100644 resources/lang/uz-UZ/pagination.php
create mode 100644 resources/lang/uz-UZ/passwords.php
create mode 100644 resources/lang/uz-UZ/reconciliations.php
create mode 100644 resources/lang/uz-UZ/recurring.php
create mode 100644 resources/lang/uz-UZ/reports.php
create mode 100644 resources/lang/uz-UZ/settings.php
create mode 100644 resources/lang/uz-UZ/taxes.php
create mode 100644 resources/lang/uz-UZ/transfers.php
create mode 100644 resources/lang/uz-UZ/updates.php
create mode 100644 resources/lang/uz-UZ/validation.php
create mode 100644 resources/lang/uz-UZ/widgets.php
create mode 100644 resources/lang/vi-VN/accounts.php
create mode 100644 resources/lang/vi-VN/auth.php
create mode 100644 resources/lang/vi-VN/bills.php
create mode 100644 resources/lang/vi-VN/companies.php
create mode 100644 resources/lang/vi-VN/countries.php
create mode 100644 resources/lang/vi-VN/currencies.php
create mode 100644 resources/lang/vi-VN/customers.php
create mode 100644 resources/lang/vi-VN/dashboard.php
create mode 100644 resources/lang/vi-VN/demo.php
create mode 100644 resources/lang/vi-VN/footer.php
create mode 100644 resources/lang/vi-VN/general.php
create mode 100644 resources/lang/vi-VN/header.php
create mode 100644 resources/lang/vi-VN/import.php
create mode 100644 resources/lang/vi-VN/install.php
create mode 100644 resources/lang/vi-VN/invoices.php
create mode 100644 resources/lang/vi-VN/items.php
create mode 100644 resources/lang/vi-VN/messages.php
create mode 100644 resources/lang/vi-VN/modules.php
create mode 100644 resources/lang/vi-VN/notifications.php
create mode 100644 resources/lang/vi-VN/pagination.php
create mode 100644 resources/lang/vi-VN/passwords.php
create mode 100644 resources/lang/vi-VN/reconciliations.php
create mode 100644 resources/lang/vi-VN/recurring.php
create mode 100644 resources/lang/vi-VN/reports.php
create mode 100644 resources/lang/vi-VN/settings.php
create mode 100644 resources/lang/vi-VN/taxes.php
create mode 100644 resources/lang/vi-VN/transfers.php
create mode 100644 resources/lang/vi-VN/updates.php
create mode 100644 resources/lang/vi-VN/validation.php
create mode 100644 resources/lang/zh-CN/accounts.php
create mode 100644 resources/lang/zh-CN/auth.php
create mode 100644 resources/lang/zh-CN/bills.php
create mode 100644 resources/lang/zh-CN/bulk_actions.php
create mode 100644 resources/lang/zh-CN/categories.php
create mode 100644 resources/lang/zh-CN/companies.php
create mode 100644 resources/lang/zh-CN/countries.php
create mode 100644 resources/lang/zh-CN/currencies.php
create mode 100644 resources/lang/zh-CN/customers.php
create mode 100644 resources/lang/zh-CN/dashboards.php
create mode 100644 resources/lang/zh-CN/demo.php
create mode 100644 resources/lang/zh-CN/documents.php
create mode 100644 resources/lang/zh-CN/email_templates.php
create mode 100644 resources/lang/zh-CN/errors.php
create mode 100644 resources/lang/zh-CN/footer.php
create mode 100644 resources/lang/zh-CN/fund_accounts.php
create mode 100644 resources/lang/zh-CN/general.php
create mode 100644 resources/lang/zh-CN/header.php
create mode 100644 resources/lang/zh-CN/import.php
create mode 100644 resources/lang/zh-CN/install.php
create mode 100644 resources/lang/zh-CN/invoices.php
create mode 100644 resources/lang/zh-CN/items.php
create mode 100644 resources/lang/zh-CN/maintenance.php
create mode 100644 resources/lang/zh-CN/messages.php
create mode 100644 resources/lang/zh-CN/modules.php
create mode 100644 resources/lang/zh-CN/notifications.php
create mode 100644 resources/lang/zh-CN/pagination.php
create mode 100644 resources/lang/zh-CN/passwords.php
create mode 100644 resources/lang/zh-CN/portal.php
create mode 100644 resources/lang/zh-CN/reconciliations.php
create mode 100644 resources/lang/zh-CN/recurring.php
create mode 100644 resources/lang/zh-CN/reports.php
create mode 100644 resources/lang/zh-CN/search_string.php
create mode 100644 resources/lang/zh-CN/settings.php
create mode 100644 resources/lang/zh-CN/taxes.php
create mode 100644 resources/lang/zh-CN/transactions.php
create mode 100644 resources/lang/zh-CN/transfers.php
create mode 100644 resources/lang/zh-CN/updates.php
create mode 100644 resources/lang/zh-CN/validation.php
create mode 100644 resources/lang/zh-CN/vendors.php
create mode 100644 resources/lang/zh-CN/widgets.php
create mode 100644 resources/lang/zh-TW/accounts.php
create mode 100644 resources/lang/zh-TW/auth.php
create mode 100644 resources/lang/zh-TW/bills.php
create mode 100644 resources/lang/zh-TW/bulk_actions.php
create mode 100644 resources/lang/zh-TW/companies.php
create mode 100644 resources/lang/zh-TW/countries.php
create mode 100644 resources/lang/zh-TW/currencies.php
create mode 100644 resources/lang/zh-TW/customers.php
create mode 100644 resources/lang/zh-TW/dashboards.php
create mode 100644 resources/lang/zh-TW/demo.php
create mode 100644 resources/lang/zh-TW/email_templates.php
create mode 100644 resources/lang/zh-TW/errors.php
create mode 100644 resources/lang/zh-TW/footer.php
create mode 100644 resources/lang/zh-TW/general.php
create mode 100644 resources/lang/zh-TW/header.php
create mode 100644 resources/lang/zh-TW/import.php
create mode 100644 resources/lang/zh-TW/install.php
create mode 100644 resources/lang/zh-TW/invoices.php
create mode 100644 resources/lang/zh-TW/items.php
create mode 100644 resources/lang/zh-TW/maintenance.php
create mode 100644 resources/lang/zh-TW/messages.php
create mode 100644 resources/lang/zh-TW/modules.php
create mode 100644 resources/lang/zh-TW/notifications.php
create mode 100644 resources/lang/zh-TW/pagination.php
create mode 100644 resources/lang/zh-TW/passwords.php
create mode 100644 resources/lang/zh-TW/reconciliations.php
create mode 100644 resources/lang/zh-TW/recurring.php
create mode 100644 resources/lang/zh-TW/reports.php
create mode 100644 resources/lang/zh-TW/settings.php
create mode 100644 resources/lang/zh-TW/taxes.php
create mode 100644 resources/lang/zh-TW/transfers.php
create mode 100644 resources/lang/zh-TW/updates.php
create mode 100644 resources/lang/zh-TW/validation.php
create mode 100644 resources/lang/zh-TW/widgets.php
create mode 100644 resources/views/auth/forgot/create.blade.php
create mode 100644 resources/views/auth/login/create.blade.php
create mode 100644 resources/views/auth/register/create.blade.php
create mode 100644 resources/views/auth/reset/create.blade.php
create mode 100644 resources/views/auth/users/create.blade.php
create mode 100644 resources/views/auth/users/edit.blade.php
create mode 100644 resources/views/auth/users/index.blade.php
create mode 100644 resources/views/auth/users/show.blade.php
create mode 100644 resources/views/banking/accounts/create.blade.php
create mode 100644 resources/views/banking/accounts/edit.blade.php
create mode 100644 resources/views/banking/accounts/index.blade.php
create mode 100644 resources/views/banking/accounts/show.blade.php
create mode 100644 resources/views/banking/fund_accounts/form.blade.php
create mode 100644 resources/views/banking/fund_accounts/index.blade.php
create mode 100644 resources/views/banking/fund_accounts/store-index.blade.php
create mode 100644 resources/views/banking/reconciliations/create.blade.php
create mode 100644 resources/views/banking/reconciliations/edit.blade.php
create mode 100644 resources/views/banking/reconciliations/index.blade.php
create mode 100644 resources/views/banking/recurring_transactions/create.blade.php
create mode 100644 resources/views/banking/recurring_transactions/edit.blade.php
create mode 100644 resources/views/banking/recurring_transactions/index.blade.php
create mode 100644 resources/views/banking/recurring_transactions/show.blade.php
create mode 100644 resources/views/banking/transactions/create.blade.php
create mode 100644 resources/views/banking/transactions/edit.blade.php
create mode 100644 resources/views/banking/transactions/import.blade.php
create mode 100644 resources/views/banking/transactions/index.blade.php
create mode 100644 resources/views/banking/transactions/print_default.blade.php
create mode 100644 resources/views/banking/transactions/show.blade.php
create mode 100644 resources/views/banking/transfers/create.blade.php
create mode 100644 resources/views/banking/transfers/edit.blade.php
create mode 100644 resources/views/banking/transfers/index.blade.php
create mode 100644 resources/views/banking/transfers/print_default.blade.php
create mode 100644 resources/views/banking/transfers/print_second.blade.php
create mode 100644 resources/views/banking/transfers/print_third.blade.php
create mode 100644 resources/views/banking/transfers/show.blade.php
create mode 100644 resources/views/bulk-actions/auth/users/edit.blade.php
create mode 100644 resources/views/bulk-actions/banking/accounts/edit.blade.php
create mode 100644 resources/views/bulk-actions/banking/transactions/edit.blade.php
create mode 100644 resources/views/bulk-actions/common/companies/edit.blade.php
create mode 100644 resources/views/bulk-actions/common/items/edit.blade.php
create mode 100644 resources/views/bulk-actions/purchases/bills/edit.blade.php
create mode 100644 resources/views/bulk-actions/purchases/vendors/edit.blade.php
create mode 100644 resources/views/bulk-actions/sales/customers/edit.blade.php
create mode 100644 resources/views/bulk-actions/sales/invoices/edit.blade.php
create mode 100644 resources/views/bulk-actions/settings/categories/edit.blade.php
create mode 100644 resources/views/bulk-actions/settings/currencies/edit.blade.php
create mode 100644 resources/views/bulk-actions/settings/taxes/edit.blade.php
create mode 100644 resources/views/business/pages/show.blade.php
create mode 100644 resources/views/common/companies/create.blade.php
create mode 100644 resources/views/common/companies/edit.blade.php
create mode 100644 resources/views/common/companies/index.blade.php
create mode 100644 resources/views/common/dashboards/create.blade.php
create mode 100644 resources/views/common/dashboards/edit.blade.php
create mode 100644 resources/views/common/dashboards/index.blade.php
create mode 100644 resources/views/common/dashboards/show.blade.php
create mode 100644 resources/views/common/import/create.blade.php
create mode 100644 resources/views/common/items/create.blade.php
create mode 100644 resources/views/common/items/edit.blade.php
create mode 100644 resources/views/common/items/index.blade.php
create mode 100644 resources/views/common/reports/create.blade.php
create mode 100644 resources/views/common/reports/edit.blade.php
create mode 100644 resources/views/common/reports/index.blade.php
create mode 100644 resources/views/components/alert/border.blade.php
create mode 100644 resources/views/components/alert/call.blade.php
create mode 100644 resources/views/components/alert/danger.blade.php
create mode 100644 resources/views/components/alert/index.blade.php
create mode 100644 resources/views/components/alert/info.blade.php
create mode 100644 resources/views/components/alert/success.blade.php
create mode 100644 resources/views/components/alert/warning.blade.php
create mode 100644 resources/views/components/button/hover.blade.php
create mode 100644 resources/views/components/button/index.blade.php
create mode 100644 resources/views/components/button/loading.blade.php
create mode 100644 resources/views/components/contacts/form/address.blade.php
create mode 100644 resources/views/components/contacts/form/billing.blade.php
create mode 100644 resources/views/components/contacts/form/buttons.blade.php
create mode 100644 resources/views/components/contacts/form/content.blade.php
create mode 100644 resources/views/components/contacts/form/general.blade.php
create mode 100644 resources/views/components/contacts/form/persons.blade.php
create mode 100644 resources/views/components/contacts/index/buttons.blade.php
create mode 100644 resources/views/components/contacts/index/content.blade.php
create mode 100644 resources/views/components/contacts/index/more-buttons.blade.php
create mode 100644 resources/views/components/contacts/script.blade.php
create mode 100644 resources/views/components/contacts/show/buttons.blade.php
create mode 100644 resources/views/components/contacts/show/content.blade.php
create mode 100644 resources/views/components/contacts/show/more-buttons.blade.php
create mode 100644 resources/views/components/date.blade.php
create mode 100644 resources/views/components/delete-button.blade.php
create mode 100644 resources/views/components/delete-link.blade.php
create mode 100644 resources/views/components/documents/form/advanced.blade.php
create mode 100644 resources/views/components/documents/form/buttons.blade.php
create mode 100644 resources/views/components/documents/form/company.blade.php
create mode 100644 resources/views/components/documents/form/contact.blade.php
create mode 100644 resources/views/components/documents/form/content.blade.php
create mode 100644 resources/views/components/documents/form/item-button.blade.php
create mode 100644 resources/views/components/documents/form/item-columns.blade.php
create mode 100644 resources/views/components/documents/form/items.blade.php
create mode 100644 resources/views/components/documents/form/line-item.blade.php
create mode 100644 resources/views/components/documents/form/main.blade.php
create mode 100644 resources/views/components/documents/form/metadata.blade.php
create mode 100644 resources/views/components/documents/form/note.blade.php
create mode 100644 resources/views/components/documents/form/recurring.blade.php
create mode 100644 resources/views/components/documents/form/recurring_metadata.blade.php
create mode 100644 resources/views/components/documents/form/totals.blade.php
create mode 100644 resources/views/components/documents/index/bulk-action.blade.php
create mode 100644 resources/views/components/documents/index/buttons.blade.php
create mode 100644 resources/views/components/documents/index/content.blade.php
create mode 100644 resources/views/components/documents/index/document.blade.php
create mode 100644 resources/views/components/documents/index/information.blade.php
create mode 100644 resources/views/components/documents/index/more-buttons.blade.php
create mode 100644 resources/views/components/documents/index/recurring_templates.blade.php
create mode 100644 resources/views/components/documents/script.blade.php
create mode 100644 resources/views/components/documents/show/attachment.blade.php
create mode 100644 resources/views/components/documents/show/buttons.blade.php
create mode 100644 resources/views/components/documents/show/children.blade.php
create mode 100644 resources/views/components/documents/show/content.blade.php
create mode 100644 resources/views/components/documents/show/create.blade.php
create mode 100644 resources/views/components/documents/show/get-paid.blade.php
create mode 100644 resources/views/components/documents/show/make-payment.blade.php
create mode 100644 resources/views/components/documents/show/message.blade.php
create mode 100644 resources/views/components/documents/show/more-buttons.blade.php
create mode 100644 resources/views/components/documents/show/receive.blade.php
create mode 100644 resources/views/components/documents/show/restore.blade.php
create mode 100644 resources/views/components/documents/show/schedule.blade.php
create mode 100644 resources/views/components/documents/show/send.blade.php
create mode 100644 resources/views/components/documents/show/template.blade.php
create mode 100644 resources/views/components/documents/template/classic.blade.php
create mode 100644 resources/views/components/documents/template/default.blade.php
create mode 100644 resources/views/components/documents/template/line-item.blade.php
create mode 100644 resources/views/components/documents/template/modern.blade.php
create mode 100644 resources/views/components/dropdown/button.blade.php
create mode 100644 resources/views/components/dropdown/divider.blade.php
create mode 100644 resources/views/components/dropdown/index.blade.php
create mode 100644 resources/views/components/dropdown/link.blade.php
create mode 100644 resources/views/components/email/body.blade.php
create mode 100644 resources/views/components/email/footer.blade.php
create mode 100644 resources/views/components/empty-data.blade.php
create mode 100644 resources/views/components/empty-page.blade.php
create mode 100644 resources/views/components/form/accordion/head.blade.php
create mode 100644 resources/views/components/form/accordion/index.blade.php
create mode 100644 resources/views/components/form/buttons.blade.php
create mode 100644 resources/views/components/form/container.blade.php
create mode 100644 resources/views/components/form/error.blade.php
create mode 100644 resources/views/components/form/group/account.blade.php
create mode 100644 resources/views/components/form/group/attachment.blade.php
create mode 100644 resources/views/components/form/group/category.blade.php
create mode 100644 resources/views/components/form/group/checkbox.blade.php
create mode 100644 resources/views/components/form/group/color.blade.php
create mode 100644 resources/views/components/form/group/contact.blade.php
create mode 100644 resources/views/components/form/group/country.blade.php
create mode 100644 resources/views/components/form/group/currency.blade.php
create mode 100644 resources/views/components/form/group/customer.blade.php
create mode 100644 resources/views/components/form/group/date.blade.php
create mode 100644 resources/views/components/form/group/date_time.blade.php
create mode 100644 resources/views/components/form/group/editor.blade.php
create mode 100644 resources/views/components/form/group/email.blade.php
create mode 100644 resources/views/components/form/group/file.blade.php
create mode 100644 resources/views/components/form/group/import.blade.php
create mode 100644 resources/views/components/form/group/invoice_text.blade.php
create mode 100644 resources/views/components/form/group/locale.blade.php
create mode 100644 resources/views/components/form/group/money.blade.php
create mode 100644 resources/views/components/form/group/number.blade.php
create mode 100644 resources/views/components/form/group/number_digit.blade.php
create mode 100644 resources/views/components/form/group/password.blade.php
create mode 100644 resources/views/components/form/group/payment_method.blade.php
create mode 100644 resources/views/components/form/group/payment_term.blade.php
create mode 100644 resources/views/components/form/group/radio.blade.php
create mode 100644 resources/views/components/form/group/recurring.blade.php
create mode 100644 resources/views/components/form/group/select.blade.php
create mode 100644 resources/views/components/form/group/switch.blade.php
create mode 100644 resources/views/components/form/group/tax.blade.php
create mode 100644 resources/views/components/form/group/text.blade.php
create mode 100644 resources/views/components/form/group/textarea.blade.php
create mode 100644 resources/views/components/form/group/time.blade.php
create mode 100644 resources/views/components/form/group/toggle.blade.php
create mode 100644 resources/views/components/form/group/vendor.blade.php
create mode 100644 resources/views/components/form/icon.blade.php
create mode 100644 resources/views/components/form/index.blade.php
create mode 100644 resources/views/components/form/input/checkbox.blade.php
create mode 100644 resources/views/components/form/input/color.blade.php
create mode 100644 resources/views/components/form/input/editor.blade.php
create mode 100644 resources/views/components/form/input/email.blade.php
create mode 100644 resources/views/components/form/input/file.blade.php
create mode 100644 resources/views/components/form/input/hidden.blade.php
create mode 100644 resources/views/components/form/input/import.blade.php
create mode 100644 resources/views/components/form/input/input.blade.php
create mode 100644 resources/views/components/form/input/money.blade.php
create mode 100644 resources/views/components/form/input/number.blade.php
create mode 100644 resources/views/components/form/input/password.blade.php
create mode 100644 resources/views/components/form/input/radio.blade.php
create mode 100644 resources/views/components/form/input/select.blade.php
create mode 100644 resources/views/components/form/input/text.blade.php
create mode 100644 resources/views/components/form/input/textarea.blade.php
create mode 100644 resources/views/components/form/label.blade.php
create mode 100644 resources/views/components/form/section/head.blade.php
create mode 100644 resources/views/components/form/section/index.blade.php
create mode 100644 resources/views/components/icon.blade.php
create mode 100644 resources/views/components/index/balance.blade.php
create mode 100644 resources/views/components/index/bulkaction/all.blade.php
create mode 100644 resources/views/components/index/bulkaction/index.blade.php
create mode 100644 resources/views/components/index/bulkaction/modal.blade.php
create mode 100644 resources/views/components/index/bulkaction/single.blade.php
create mode 100644 resources/views/components/index/category.blade.php
create mode 100644 resources/views/components/index/container.blade.php
create mode 100644 resources/views/components/index/country.blade.php
create mode 100644 resources/views/components/index/currency.blade.php
create mode 100644 resources/views/components/index/default.blade.php
create mode 100644 resources/views/components/index/disable.blade.php
create mode 100644 resources/views/components/index/search.blade.php
create mode 100644 resources/views/components/index/status.blade.php
create mode 100644 resources/views/components/index/summary.blade.php
create mode 100644 resources/views/components/layouts/admin.blade.php
create mode 100644 resources/views/components/layouts/admin/content.blade.php
create mode 100644 resources/views/components/layouts/admin/footer.blade.php
create mode 100644 resources/views/components/layouts/admin/head.blade.php
create mode 100644 resources/views/components/layouts/admin/header.blade.php
create mode 100644 resources/views/components/layouts/admin/menu.blade.php
create mode 100644 resources/views/components/layouts/admin/notifications.blade.php
create mode 100644 resources/views/components/layouts/admin/scripts.blade.php
create mode 100644 resources/views/components/layouts/auth.blade.php
create mode 100644 resources/views/components/layouts/auth/content.blade.php
create mode 100644 resources/views/components/layouts/auth/footer.blade.php
create mode 100644 resources/views/components/layouts/auth/head.blade.php
create mode 100644 resources/views/components/layouts/auth/scripts.blade.php
create mode 100644 resources/views/components/layouts/auth/slider.blade.php
create mode 100644 resources/views/components/layouts/error.blade.php
create mode 100644 resources/views/components/layouts/error/content.blade.php
create mode 100644 resources/views/components/layouts/error/head.blade.php
create mode 100644 resources/views/components/layouts/error/scripts.blade.php
create mode 100644 resources/views/components/layouts/install.blade.php
create mode 100644 resources/views/components/layouts/install/content.blade.php
create mode 100644 resources/views/components/layouts/install/head.blade.php
create mode 100644 resources/views/components/layouts/install/scripts.blade.php
create mode 100644 resources/views/components/layouts/maintenance.blade.php
create mode 100644 resources/views/components/layouts/maintenance/body.blade.php
create mode 100644 resources/views/components/layouts/maintenance/head.blade.php
create mode 100644 resources/views/components/layouts/modules.blade.php
create mode 100644 resources/views/components/layouts/modules/bar.blade.php
create mode 100644 resources/views/components/layouts/modules/head.blade.php
create mode 100644 resources/views/components/layouts/modules/item.blade.php
create mode 100644 resources/views/components/layouts/modules/my_apps_item.blade.php
create mode 100644 resources/views/components/layouts/modules/releases.blade.php
create mode 100644 resources/views/components/layouts/modules/reviews.blade.php
create mode 100644 resources/views/components/layouts/modules/show/buttons.blade.php
create mode 100644 resources/views/components/layouts/modules/show/changelog.blade.php
create mode 100644 resources/views/components/layouts/modules/show/description.blade.php
create mode 100644 resources/views/components/layouts/modules/show/documentation.blade.php
create mode 100644 resources/views/components/layouts/modules/show/features.blade.php
create mode 100644 resources/views/components/layouts/modules/show/information.blade.php
create mode 100644 resources/views/components/layouts/modules/show/installation.blade.php
create mode 100644 resources/views/components/layouts/modules/show/price.blade.php
create mode 100644 resources/views/components/layouts/modules/show/releases.blade.php
create mode 100644 resources/views/components/layouts/modules/show/reviews.blade.php
create mode 100644 resources/views/components/layouts/modules/show/screenshots.blade.php
create mode 100644 resources/views/components/layouts/modules/show/toggle.blade.php
create mode 100644 resources/views/components/layouts/portal.blade.php
create mode 100644 resources/views/components/layouts/portal/content.blade.php
create mode 100644 resources/views/components/layouts/portal/finish/buttons.blade.php
create mode 100644 resources/views/components/layouts/portal/finish/content.blade.php
create mode 100644 resources/views/components/layouts/portal/footer.blade.php
create mode 100644 resources/views/components/layouts/portal/head.blade.php
create mode 100644 resources/views/components/layouts/portal/header.blade.php
create mode 100644 resources/views/components/layouts/portal/menu.blade.php
create mode 100644 resources/views/components/layouts/portal/scripts.blade.php
create mode 100644 resources/views/components/layouts/preview.blade.php
create mode 100644 resources/views/components/layouts/preview/content.blade.php
create mode 100644 resources/views/components/layouts/preview/footer.blade.php
create mode 100644 resources/views/components/layouts/preview/head.blade.php
create mode 100644 resources/views/components/layouts/preview/header.blade.php
create mode 100644 resources/views/components/layouts/preview/scripts.blade.php
create mode 100644 resources/views/components/layouts/print.blade.php
create mode 100644 resources/views/components/layouts/print/content.blade.php
create mode 100644 resources/views/components/layouts/print/head.blade.php
create mode 100644 resources/views/components/layouts/print/scripts.blade.php
create mode 100644 resources/views/components/layouts/pwa/head.blade.php
create mode 100644 resources/views/components/layouts/signed.blade.php
create mode 100644 resources/views/components/layouts/signed/content.blade.php
create mode 100644 resources/views/components/layouts/signed/footer.blade.php
create mode 100644 resources/views/components/layouts/signed/head.blade.php
create mode 100644 resources/views/components/layouts/signed/header.blade.php
create mode 100644 resources/views/components/layouts/signed/scripts.blade.php
create mode 100644 resources/views/components/layouts/wizard.blade.php
create mode 100644 resources/views/components/layouts/wizard/background.blade.php
create mode 100644 resources/views/components/layouts/wizard/content.blade.php
create mode 100644 resources/views/components/layouts/wizard/head.blade.php
create mode 100644 resources/views/components/layouts/wizard/scripts.blade.php
create mode 100644 resources/views/components/link/hover.blade.php
create mode 100644 resources/views/components/link/index.blade.php
create mode 100644 resources/views/components/link/loading.blade.php
create mode 100644 resources/views/components/loading/absolute.blade.php
create mode 100644 resources/views/components/loading/content.blade.php
create mode 100644 resources/views/components/loading/menu.blade.php
create mode 100644 resources/views/components/media/file.blade.php
create mode 100644 resources/views/components/menu/favorite.blade.php
create mode 100644 resources/views/components/modules/banners.blade.php
create mode 100644 resources/views/components/modules/free.blade.php
create mode 100644 resources/views/components/modules/installed.blade.php
create mode 100644 resources/views/components/modules/item.blade.php
create mode 100644 resources/views/components/modules/items.blade.php
create mode 100644 resources/views/components/modules/nnew.blade.php
create mode 100644 resources/views/components/modules/no_apps.blade.php
create mode 100644 resources/views/components/modules/paid.blade.php
create mode 100644 resources/views/components/modules/pre_sale.blade.php
create mode 100644 resources/views/components/modules/purchased.blade.php
create mode 100644 resources/views/components/modules/raw_items.blade.php
create mode 100644 resources/views/components/nl2br.blade.php
create mode 100644 resources/views/components/pagination.blade.php
create mode 100644 resources/views/components/payment_method.blade.php
create mode 100644 resources/views/components/payment_method/hosted.blade.php
create mode 100644 resources/views/components/payment_method/redirect.blade.php
create mode 100644 resources/views/components/read-only.blade.php
create mode 100644 resources/views/components/reports/detail.blade.php
create mode 100644 resources/views/components/reports/detail/content/footer.blade.php
create mode 100644 resources/views/components/reports/detail/content/header.blade.php
create mode 100644 resources/views/components/reports/detail/table.blade.php
create mode 100644 resources/views/components/reports/detail/table/body.blade.php
create mode 100644 resources/views/components/reports/detail/table/footer.blade.php
create mode 100644 resources/views/components/reports/detail/table/header.blade.php
create mode 100644 resources/views/components/reports/detail/table/row.blade.php
create mode 100644 resources/views/components/reports/fields.blade.php
create mode 100644 resources/views/components/reports/filter.blade.php
create mode 100644 resources/views/components/reports/print.blade.php
create mode 100644 resources/views/components/reports/show.blade.php
create mode 100644 resources/views/components/reports/summary.blade.php
create mode 100644 resources/views/components/reports/summary/chart.blade.php
create mode 100644 resources/views/components/reports/summary/content/footer.blade.php
create mode 100644 resources/views/components/reports/summary/content/header.blade.php
create mode 100644 resources/views/components/reports/summary/table.blade.php
create mode 100644 resources/views/components/reports/summary/table/body.blade.php
create mode 100644 resources/views/components/reports/summary/table/footer.blade.php
create mode 100644 resources/views/components/reports/summary/table/header.blade.php
create mode 100644 resources/views/components/reports/summary/table/row.blade.php
create mode 100644 resources/views/components/script.blade.php
create mode 100644 resources/views/components/script/declaration.blade.php
create mode 100644 resources/views/components/script/exceptions/trackers.blade.php
create mode 100644 resources/views/components/search-string.blade.php
create mode 100644 resources/views/components/show/accordion/head.blade.php
create mode 100644 resources/views/components/show/accordion/index.blade.php
create mode 100644 resources/views/components/show/container.blade.php
create mode 100644 resources/views/components/show/content/index.blade.php
create mode 100644 resources/views/components/show/content/left.blade.php
create mode 100644 resources/views/components/show/content/right.blade.php
create mode 100644 resources/views/components/show/no-records.blade.php
create mode 100644 resources/views/components/show/status.blade.php
create mode 100644 resources/views/components/show/summary/index.blade.php
create mode 100644 resources/views/components/show/summary/left.blade.php
create mode 100644 resources/views/components/show/summary/right.blade.php
create mode 100644 resources/views/components/suggestions.blade.php
create mode 100644 resources/views/components/table/actions-mobile.blade.php
create mode 100644 resources/views/components/table/actions.blade.php
create mode 100644 resources/views/components/table/index.blade.php
create mode 100644 resources/views/components/table/tbody.blade.php
create mode 100644 resources/views/components/table/td.blade.php
create mode 100644 resources/views/components/table/th.blade.php
create mode 100644 resources/views/components/table/thead.blade.php
create mode 100644 resources/views/components/table/tr.blade.php
create mode 100644 resources/views/components/tabs/index.blade.php
create mode 100644 resources/views/components/tabs/nav-link.blade.php
create mode 100644 resources/views/components/tabs/nav-pin.blade.php
create mode 100644 resources/views/components/tabs/nav.blade.php
create mode 100644 resources/views/components/tabs/tab.blade.php
create mode 100644 resources/views/components/tips/fixed.blade.php
create mode 100644 resources/views/components/tips/relative.blade.php
create mode 100644 resources/views/components/title.blade.php
create mode 100644 resources/views/components/tooltip.blade.php
create mode 100644 resources/views/components/transactions/index/bulk-action.blade.php
create mode 100644 resources/views/components/transactions/index/buttons.blade.php
create mode 100644 resources/views/components/transactions/index/content.blade.php
create mode 100644 resources/views/components/transactions/index/more-buttons.blade.php
create mode 100644 resources/views/components/transactions/index/recurring_templates.blade.php
create mode 100644 resources/views/components/transactions/index/transaction.blade.php
create mode 100644 resources/views/components/transactions/script.blade.php
create mode 100644 resources/views/components/transactions/show/attachment.blade.php
create mode 100644 resources/views/components/transactions/show/buttons.blade.php
create mode 100644 resources/views/components/transactions/show/children.blade.php
create mode 100644 resources/views/components/transactions/show/connect.blade.php
create mode 100644 resources/views/components/transactions/show/content.blade.php
create mode 100644 resources/views/components/transactions/show/create.blade.php
create mode 100644 resources/views/components/transactions/show/more-buttons.blade.php
create mode 100644 resources/views/components/transactions/show/schedule.blade.php
create mode 100644 resources/views/components/transactions/show/template.blade.php
create mode 100644 resources/views/components/transactions/show/transfer.blade.php
create mode 100644 resources/views/components/transactions/template/default.blade.php
create mode 100644 resources/views/components/transfers/script.blade.php
create mode 100644 resources/views/components/transfers/show/attachment.blade.php
create mode 100644 resources/views/components/transfers/show/buttons.blade.php
create mode 100644 resources/views/components/transfers/show/content.blade.php
create mode 100644 resources/views/components/transfers/show/create.blade.php
create mode 100644 resources/views/components/transfers/show/more-buttons.blade.php
create mode 100644 resources/views/components/transfers/show/template.blade.php
create mode 100644 resources/views/components/transfers/show/transactions.blade.php
create mode 100644 resources/views/components/transfers/template/default.blade.php
create mode 100644 resources/views/components/transfers/template/second.blade.php
create mode 100644 resources/views/components/transfers/template/third.blade.php
create mode 100644 resources/views/components/update-alert.blade.php
create mode 100644 resources/views/components/widgets/contact.blade.php
create mode 100644 resources/views/components/widgets/header.blade.php
create mode 100644 resources/views/components/widgets/invoice_history.blade.php
create mode 100644 resources/views/components/widgets/last_payment.blade.php
create mode 100644 resources/views/components/widgets/latest_invoices.blade.php
create mode 100644 resources/views/components/widgets/outstanding_balance.blade.php
create mode 100644 resources/views/components/widgets/payment_history.blade.php
create mode 100644 resources/views/errors/403.blade.php
create mode 100644 resources/views/errors/404.blade.php
create mode 100644 resources/views/errors/500.blade.php
create mode 100644 resources/views/install/database/create.blade.php
create mode 100644 resources/views/install/language/create.blade.php
create mode 100644 resources/views/install/requirements/show.blade.php
create mode 100644 resources/views/install/settings/create.blade.php
create mode 100644 resources/views/install/updates/edit.blade.php
create mode 100644 resources/views/install/updates/index.blade.php
create mode 100644 resources/views/livewire/common/search.blade.php
create mode 100644 resources/views/livewire/menu/favorite.blade.php
create mode 100644 resources/views/livewire/menu/favorites.blade.php
create mode 100644 resources/views/livewire/menu/neww.blade.php
create mode 100644 resources/views/livewire/menu/notifications.blade.php
create mode 100644 resources/views/livewire/menu/profile.blade.php
create mode 100644 resources/views/livewire/menu/settings.blade.php
create mode 100644 resources/views/livewire/notification/browser/firefox.blade.php
create mode 100644 resources/views/livewire/notification/browser/index.blade.php
create mode 100644 resources/views/livewire/report/pin.blade.php
create mode 100644 resources/views/livewire/report/pins.blade.php
create mode 100644 resources/views/livewire/tab/pin.blade.php
create mode 100644 resources/views/modals/accounts/create.blade.php
create mode 100644 resources/views/modals/categories/create.blade.php
create mode 100644 resources/views/modals/companies/edit.blade.php
create mode 100644 resources/views/modals/currencies/create.blade.php
create mode 100644 resources/views/modals/customers/create.blade.php
create mode 100644 resources/views/modals/customers/edit.blade.php
create mode 100644 resources/views/modals/documents/item_columns.blade.php
create mode 100644 resources/views/modals/documents/payment.blade.php
create mode 100644 resources/views/modals/invoices/email.blade.php
create mode 100644 resources/views/modals/invoices/share.blade.php
create mode 100644 resources/views/modals/items/create.blade.php
create mode 100644 resources/views/modals/settings/transfer_template.blade.php
create mode 100644 resources/views/modals/taxes/create.blade.php
create mode 100644 resources/views/modals/transactions/connect.blade.php
create mode 100644 resources/views/modals/transactions/email.blade.php
create mode 100644 resources/views/modals/transactions/share.blade.php
create mode 100644 resources/views/modals/vendors/create.blade.php
create mode 100644 resources/views/modals/vendors/edit.blade.php
create mode 100644 resources/views/modules/api_key/create.blade.php
create mode 100644 resources/views/modules/home/index.blade.php
create mode 100644 resources/views/modules/item/documentation.blade.php
create mode 100644 resources/views/modules/item/pre_sale.blade.php
create mode 100644 resources/views/modules/item/show.blade.php
create mode 100644 resources/views/modules/my/index.blade.php
create mode 100644 resources/views/modules/tiles/index.blade.php
create mode 100644 resources/views/portal/dashboard/index.blade.php
create mode 100644 resources/views/portal/invoices/finish.blade.php
create mode 100644 resources/views/portal/invoices/index.blade.php
create mode 100644 resources/views/portal/invoices/preview.blade.php
create mode 100644 resources/views/portal/invoices/show.blade.php
create mode 100644 resources/views/portal/invoices/signed.blade.php
create mode 100644 resources/views/portal/payments/index.blade.php
create mode 100644 resources/views/portal/payments/preview.blade.php
create mode 100644 resources/views/portal/payments/show.blade.php
create mode 100644 resources/views/portal/payments/signed.blade.php
create mode 100644 resources/views/portal/profile/edit.blade.php
create mode 100644 resources/views/purchases/bills/create.blade.php
create mode 100644 resources/views/purchases/bills/edit.blade.php
create mode 100644 resources/views/purchases/bills/index.blade.php
create mode 100644 resources/views/purchases/bills/print.blade.php
create mode 100644 resources/views/purchases/bills/show.blade.php
create mode 100644 resources/views/purchases/recurring_bills/create.blade.php
create mode 100644 resources/views/purchases/recurring_bills/edit.blade.php
create mode 100644 resources/views/purchases/recurring_bills/index.blade.php
create mode 100644 resources/views/purchases/recurring_bills/show.blade.php
create mode 100644 resources/views/purchases/vendors/create.blade.php
create mode 100644 resources/views/purchases/vendors/edit.blade.php
create mode 100644 resources/views/purchases/vendors/index.blade.php
create mode 100644 resources/views/purchases/vendors/show.blade.php
create mode 100644 resources/views/reports/profit_loss/content/footer.blade.php
create mode 100644 resources/views/reports/profit_loss/content/header.blade.php
create mode 100644 resources/views/reports/profit_loss/detail.blade.php
create mode 100644 resources/views/reports/profit_loss/table/footer.blade.php
create mode 100644 resources/views/reports/profit_loss/table/header.blade.php
create mode 100644 resources/views/reports/profit_loss/table/row.blade.php
create mode 100644 resources/views/reports/tax_summary/content/footer.blade.php
create mode 100644 resources/views/reports/tax_summary/content/header.blade.php
create mode 100644 resources/views/reports/tax_summary/table/footer.blade.php
create mode 100644 resources/views/reports/tax_summary/table/header.blade.php
create mode 100644 resources/views/sales/customers/create.blade.php
create mode 100644 resources/views/sales/customers/edit.blade.php
create mode 100644 resources/views/sales/customers/index.blade.php
create mode 100644 resources/views/sales/customers/show.blade.php
create mode 100644 resources/views/sales/invoices/create.blade.php
create mode 100644 resources/views/sales/invoices/edit.blade.php
create mode 100644 resources/views/sales/invoices/index.blade.php
create mode 100644 resources/views/sales/invoices/print_classic.blade.php
create mode 100644 resources/views/sales/invoices/print_default.blade.php
create mode 100644 resources/views/sales/invoices/print_modern.blade.php
create mode 100644 resources/views/sales/invoices/show.blade.php
create mode 100644 resources/views/sales/recurring_invoices/create.blade.php
create mode 100644 resources/views/sales/recurring_invoices/edit.blade.php
create mode 100644 resources/views/sales/recurring_invoices/index.blade.php
create mode 100644 resources/views/sales/recurring_invoices/show.blade.php
create mode 100644 resources/views/settings/categories/create.blade.php
create mode 100644 resources/views/settings/categories/edit.blade.php
create mode 100644 resources/views/settings/categories/index.blade.php
create mode 100644 resources/views/settings/categories/sub_category.blade.php
create mode 100644 resources/views/settings/company/edit.blade.php
create mode 100644 resources/views/settings/currencies/create.blade.php
create mode 100644 resources/views/settings/currencies/edit.blade.php
create mode 100644 resources/views/settings/currencies/index.blade.php
create mode 100644 resources/views/settings/default/edit.blade.php
create mode 100644 resources/views/settings/email-templates/edit.blade.php
create mode 100644 resources/views/settings/email/edit.blade.php
create mode 100644 resources/views/settings/invoice/edit.blade.php
create mode 100644 resources/views/settings/localisation/edit.blade.php
create mode 100644 resources/views/settings/modules/edit.blade.php
create mode 100644 resources/views/settings/navigation/edit.blade.php
create mode 100644 resources/views/settings/schedule/edit.blade.php
create mode 100644 resources/views/settings/taxes/create.blade.php
create mode 100644 resources/views/settings/taxes/edit.blade.php
create mode 100644 resources/views/settings/taxes/index.blade.php
create mode 100644 resources/views/system_settings/databases/form.blade.php
create mode 100644 resources/views/system_settings/databases/index.blade.php
create mode 100644 resources/views/system_settings/partials/navigation.blade.php
create mode 100644 resources/views/system_settings/sidebar/edit.blade.php
create mode 100644 resources/views/system_settings/users/form.blade.php
create mode 100644 resources/views/system_settings/users/index.blade.php
create mode 100644 resources/views/widgets/account_balance.blade.php
create mode 100644 resources/views/widgets/bank_feeds.blade.php
create mode 100644 resources/views/widgets/bar_chart.blade.php
create mode 100644 resources/views/widgets/cash_flow.blade.php
create mode 100644 resources/views/widgets/currencies.blade.php
create mode 100644 resources/views/widgets/donut_chart.blade.php
create mode 100644 resources/views/widgets/line_chart.blade.php
create mode 100644 resources/views/widgets/receivables_payables.blade.php
create mode 100644 resources/views/wizard/companies/edit.blade.php
create mode 100644 resources/views/wizard/currencies/index.blade.php
create mode 100644 resources/views/wizard/finish/index.blade.php
create mode 100644 routes/admin.php
create mode 100644 routes/api.php
create mode 100644 routes/channels.php
create mode 100644 routes/common.php
create mode 100644 routes/console.php
create mode 100644 routes/guest.php
create mode 100644 routes/install.php
create mode 100644 routes/portal.php
create mode 100644 routes/preview.php
create mode 100644 routes/signed.php
create mode 100644 routes/web.php
create mode 100644 routes/wizard.php
create mode 100644 safelist.txt
create mode 100644 serviceworker.js
create mode 100644 storage/app/.gitignore
create mode 100644 storage/app/public/.gitignore
create mode 100644 storage/app/temp/.gitignore
create mode 100644 storage/app/uploads/.gitignore
create mode 100644 storage/debugbar/.gitignore
create mode 100644 storage/fonts/.gitignore
create mode 100644 storage/framework/.gitignore
create mode 100644 storage/framework/testing/.gitignore
create mode 100644 tailwind.config.js
create mode 100644 tests/CreatesApplication.php
create mode 100644 tests/Feature/Auth/UsersTest.php
create mode 100644 tests/Feature/Banking/AccountsTest.php
create mode 100644 tests/Feature/Banking/DocumentTransactionsTest.php
create mode 100644 tests/Feature/Banking/ReconciliationsTest.php
create mode 100644 tests/Feature/Banking/SplitTransactionTest.php
create mode 100644 tests/Feature/Banking/TransactionTaxesTest.php
create mode 100644 tests/Feature/Banking/TransactionsTest.php
create mode 100644 tests/Feature/Banking/TransfersTest.php
create mode 100644 tests/Feature/Commands/BillReminderTest.php
create mode 100644 tests/Feature/Commands/InvoiceReminderTest.php
create mode 100644 tests/Feature/Commands/RecurringCheckTest.php
create mode 100644 tests/Feature/Common/CompaniesTest.php
create mode 100644 tests/Feature/Common/DashboardsTest.php
create mode 100644 tests/Feature/Common/ItemsTest.php
create mode 100644 tests/Feature/Common/ReportsTest.php
create mode 100644 tests/Feature/Common/SourcesTest.php
create mode 100644 tests/Feature/Document/CancelDocumentTest.php
create mode 100644 tests/Feature/Email/TooManyEmailsSentTest.php
create mode 100644 tests/Feature/FeatureTestCase.php
create mode 100644 tests/Feature/PaymentTestCase.php
create mode 100644 tests/Feature/Performance/N1QueryOptimizationTest.php
create mode 100644 tests/Feature/Performance/VendorN1QueryTest.php
create mode 100644 tests/Feature/Purchases/BillsTest.php
create mode 100644 tests/Feature/Purchases/VendorsTest.php
create mode 100644 tests/Feature/Sales/CustomersTest.php
create mode 100644 tests/Feature/Sales/InvoicesTest.php
create mode 100644 tests/Feature/Settings/CategoriesTest.php
create mode 100644 tests/Feature/Settings/CurrenciesTest.php
create mode 100644 tests/Feature/Settings/NavigationTest.php
create mode 100644 tests/Feature/Settings/TaxesTest.php
create mode 100644 tests/Feature/Wizard/CompaniesTest.php
create mode 100644 tests/Feature/Wizard/CurrenciesTest.php
create mode 100644 tests/TestCase.php
create mode 100644 tests/Unit/ExampleTest.php
create mode 100644 tests/Unit/Imports/Banking/TransfersImportTest.php
create mode 100644 tests/Unit/UpdatesTest.php
create mode 100644 tests/Unit/Utilities/CalculationToQuantityTest.php
create mode 100644 tests/Unit/Utilities/DateImportParsingTest.php
create mode 100644 web.config
create mode 100644 webpack.mix.js
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..db545f77
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,16 @@
+.env
+.git
+.gitignore
+.idea
+.vscode
+node_modules
+database/database.sqlite
+storage/debugbar
+storage/framework/cache/data/*
+storage/framework/sessions/*
+storage/framework/views/*
+storage/logs/*
+tests
+npm-debug.log
+yarn-error.log
+
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..4025c3ea
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,18 @@
+; This file is for unifying the coding style for different editors and IDEs.
+; More information at https://editorconfig.org
+
+root = true
+
+[*]
+charset = utf-8
+indent_size = 4
+indent_style = space
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.yml]
+indent_size = 2
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..f7b24102
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,26 @@
+# Set the default behavior, in case people don't have core.autocrlf set.
+* text eol=lf
+
+# Explicitly declare text files you want to always be normalized and converted
+# to native line endings on checkout.
+*.c text
+*.h text
+
+# Declare files that will always have CRLF line endings on checkout.
+*.sln text eol=crlf
+
+# Denote all files that are truly binary and should not be modified.
+*.png binary
+*.jpg binary
+*.gif binary
+*.otf binary
+*.eot binary
+*.svg binary
+*.ttf binary
+*.woff binary
+*.woff2 binary
+
+*.css linguist-vendored
+*.scss linguist-vendored
+*.js linguist-vendored
+CHANGELOG.md export-ignore
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..6914934e
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+patreon: akaunting
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000..fd326bf6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,21 @@
+Please, submit only real issues. Use the forum for support, feature requests, proposals, new versions, help etc. https://akaunting.com/forum
+
+### Steps to reproduce the issue
+
+
+
+### Expected result
+
+
+
+### Actual result
+
+
+
+### System information (Akaunting, PHP versions)
+
+
+
+### Additional comments
+
+
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
new file mode 100644
index 00000000..c58a9459
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -0,0 +1,63 @@
+name: Bug report
+description: File a bug report related to Akaunting
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to fill out this bug report!
+ - type: input
+ id: akaunting
+ attributes:
+ label: Akaunting version
+ description: "Please provide the full Akaunting version of your installation."
+ placeholder: "2.1.20"
+ validations:
+ required: true
+ - type: input
+ id: php
+ attributes:
+ label: PHP version
+ description: "Please provide the full PHP version that is powering Akaunting."
+ placeholder: "7.4.10"
+ validations:
+ required: true
+ - type: input
+ id: os
+ attributes:
+ label: Operating system
+ description: "Which operating system do you use? Please provide the version as well."
+ placeholder: "Ubuntu 20.04"
+ validations:
+ required: true
+ - type: textarea
+ id: steps
+ attributes:
+ label: Steps to reproduce
+ description: Which steps do we need to take to reproduce this error?
+ validations:
+ required: true
+ - type: textarea
+ id: expected
+ attributes:
+ label: Expected result
+ description: What is the expected result?
+ validations:
+ required: true
+ - type: textarea
+ id: actual
+ attributes:
+ label: Actual result
+ description: What is the actual result?
+ validations:
+ required: true
+ - type: textarea
+ id: comments
+ attributes:
+ label: Additional comments
+ description: Anything else we should know about?
+ - type: textarea
+ id: logs
+ attributes:
+ label: Relevant log output
+ description: Copy and paste any relevant log output. No need for backticks.
+ render: shell
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..3cb53d44
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,11 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Feature request
+ url: https://akaunting.com/forum
+ about: 'For ideas or feature requests, start a new discussion'
+ - name: Support, help, and other
+ url: https://akaunting.com/support
+ about: 'This repository is only for reporting bugs'
+ - name: Documentation
+ url: https://github.com/akaunting/docs
+ about: For documentation improvements, open a pull request at the akaunting/docs repository
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 00000000..842a1409
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,51 @@
+name: Tests
+
+on:
+ push:
+ pull_request:
+ schedule:
+ - cron: '0 0 * * *'
+ workflow_dispatch:
+
+jobs:
+ tests:
+
+ name: PHP ${{ matrix.php }}
+
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ php: ['8.1', '8.2', '8.3']
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Cache Composer
+ uses: actions/cache@v4
+ with:
+ path: ~/.composer/cache/files
+ key: php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: bcmath, ctype, dom, fileinfo, intl, gd, json, mbstring, pdo, pdo_sqlite, openssl, sqlite, xml, zip
+ coverage: none
+
+ - name: Copy .env
+ run: cp .env.testing .env
+
+ - name: Install NPM
+ run: npm install
+
+ - name: Compile assets
+ run: npm run production
+
+ - name: Install Composer
+ run: composer test
+
+ - name: Execute tests
+ run: php artisan test --parallel
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..1c68dc9d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,98 @@
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+/node_modules
+/public/hot
+/public/storage
+/public/js
+/public/mix-manifest.json
+/storage/*.key
+/vendor
+/.idea
+/.history
+/.vscode
+/.claude
+/.vagrant
+Homestead.json
+Homestead.yaml
+npm-debug.log
+.env
+robots.txt
+_ide_helper.php
+_ide_helper_models.php
+.phpstorm.meta.php
+/storage/debugbar/*
+.phpunit.result.cache
+modules/*
+!modules/.gitkeep
+.laravelstatsrc
+.DS_Store
diff --git a/.htaccess b/.htaccess
new file mode 100644
index 00000000..cd495c3e
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,49 @@
+# Prevent Directory Listing
+
+ This view is loaded from module: {!! config('$ALIAS$.name') !!}
+ |Hello World
+
+ '));
+ }
+ }
+
+ protected static function getBodyPurifier(): \HTMLPurifier
+ {
+ if (static::$bodyPurifier instanceof \HTMLPurifier) {
+ return static::$bodyPurifier;
+ }
+
+ $config = \HTMLPurifier_Config::createDefault();
+ $config->set('Cache.DefinitionImpl', null);
+ $config->set('URI.DisableJavaScript', true);
+ $config->set('HTML.ForbiddenElements', ['script', 'iframe', 'object', 'embed', 'form', 'input', 'button', 'textarea', 'select', 'option', 'meta', 'link']);
+
+ static::$bodyPurifier = new \HTMLPurifier($config);
+
+ return static::$bodyPurifier;
+ }
+
+ public function getTitleAttribute()
+ {
+ return trans($this->name);
+ }
+
+ public function getGroupAttribute()
+ {
+ if (Str::startsWith($this->alias, 'invoice_')) {
+ $group = 'general.invoices';
+ } elseif (Str::startsWith($this->alias, 'bill_')) {
+ $group = 'general.bills';
+ } elseif (Str::startsWith($this->alias, 'payment_')) {
+ $group = 'general.payments';
+ } else {
+ $group = 'general.others';
+ }
+
+ return $group;
+ }
+
+ /**
+ * Scope to only include email templates of a given alias.
+ *
+ * @param \Illuminate\Database\Eloquent\Builder $query
+ * @param mixed $alias
+ * @return \Illuminate\Database\Eloquent\Builder
+ */
+ public function scopeAlias($query, $alias)
+ {
+ return $query->where('alias', $alias);
+ }
+
+ /**
+ * Scope to only include email templates of a given module alias (class).
+ *
+ * @param \Illuminate\Database\Eloquent\Builder $query
+ * @param string $alias
+ * @return \Illuminate\Database\Eloquent\Builder
+ */
+ public function scopeModuleAlias($query, $alias)
+ {
+ $class = ($alias == 'core') ? 'App\\\\' : 'Modules\\\\' . Str::studly($alias) . '\\\\';
+
+ return $query->where('class', 'like', $class . '%');
+ }
+}
diff --git a/app/Models/Setting/Setting.php b/app/Models/Setting/Setting.php
new file mode 100644
index 00000000..30741cb9
--- /dev/null
+++ b/app/Models/Setting/Setting.php
@@ -0,0 +1,37 @@
+where('key', 'like', $prefix . '.%');
+ }
+}
diff --git a/app/Models/Setting/Tax.php b/app/Models/Setting/Tax.php
new file mode 100644
index 00000000..39e08a48
--- /dev/null
+++ b/app/Models/Setting/Tax.php
@@ -0,0 +1,182 @@
+ 'double',
+ 'enabled' => 'boolean',
+ 'deleted_at' => 'datetime',
+ ];
+
+ /**
+ * Sortable columns.
+ *
+ * @var array
+ */
+ public $sortable = ['name', 'type', 'rate'];
+
+ public function items()
+ {
+ return $this->hasMany('App\Models\Common\ItemTax');
+ }
+
+ public function document_items()
+ {
+ return $this->hasMany('App\Models\Document\DocumentItemTax');
+ }
+
+ public function bill_items()
+ {
+ return $this->document_items()->where('document_item_taxes.type', Document::BILL_TYPE);
+ }
+
+ public function invoice_items()
+ {
+ return $this->document_items()->where('document_item_taxes.type', Document::INVOICE_TYPE);
+ }
+
+ public function scopeName($query, $name)
+ {
+ return $query->where('name', '=', $name);
+ }
+
+ public function scopeRate($query, $rate)
+ {
+ return $query->where('rate', '=', $rate);
+ }
+
+ public function scopeNotRate($query, $rate)
+ {
+ return $query->where('rate', '<>', $rate);
+ }
+
+ public function scopeType($query, $types)
+ {
+ if (empty($types)) {
+ return $query;
+ }
+
+ return $query->whereIn($this->qualifyColumn('type'), (array) $types);
+ }
+
+ public function scopeFixed($query)
+ {
+ return $query->where($this->qualifyColumn('type'), '=', 'fixed');
+ }
+
+ public function scopeNormal($query)
+ {
+ return $query->where($this->qualifyColumn('type'), '=', 'normal');
+ }
+
+ public function scopeInclusive($query)
+ {
+ return $query->where($this->qualifyColumn('type'), '=', 'inclusive');
+ }
+
+ public function scopeCompound($query)
+ {
+ return $query->where($this->qualifyColumn('type'), '=', 'compound');
+ }
+
+ public function scopeWithholding($query)
+ {
+ return $query->where($this->qualifyColumn('type'), '=', 'withholding');
+ }
+
+ public function scopeNotWithholding($query)
+ {
+ return $query->where($this->qualifyColumn('type'), '<>', 'withholding');
+ }
+
+ /**
+ * Get the name including rate.
+ *
+ * @return string
+ */
+ public function getTitleAttribute()
+ {
+ $title = $this->name . ' (';
+
+ if (setting('localisation.percent_position', 'after') == 'after') {
+ $title .= $this->getAttribute('type') == 'fixed' ? $this->rate : $this->rate . '%';
+ } else {
+ $title .= $this->getAttribute('type') == 'fixed' ? $this->rate : '%' . $this->rate;
+ }
+ $title .= ')';
+
+ return $title;
+ }
+
+ /**
+ * Get the line actions.
+ *
+ * @return array
+ */
+ public function getLineActionsAttribute()
+ {
+ $actions = [];
+
+ $actions[] = [
+ 'title' => trans('general.edit'),
+ 'icon' => 'edit',
+ 'url' => route('taxes.edit', $this->id),
+ 'permission' => 'update-settings-taxes',
+ 'attributes' => [
+ 'id' => 'index-line-actions-edit-tax-' . $this->id,
+ ],
+ ];
+
+ $actions[] = [
+ 'type' => 'delete',
+ 'icon' => 'delete',
+ 'route' => 'taxes.destroy',
+ 'permission' => 'delete-settings-taxes',
+ 'attributes' => [
+ 'id' => 'index-line-actions-delete-tax-' . $this->id,
+ ],
+ 'model' => $this,
+ ];
+
+ return $actions;
+ }
+
+ /**
+ * Create a new factory instance for the model.
+ *
+ * @return \Illuminate\Database\Eloquent\Factories\Factory
+ */
+ protected static function newFactory()
+ {
+ return \Database\Factories\Tax::new();
+ }
+}
diff --git a/app/Models/Settings/DatabaseConnection.php b/app/Models/Settings/DatabaseConnection.php
new file mode 100644
index 00000000..e95ad8aa
--- /dev/null
+++ b/app/Models/Settings/DatabaseConnection.php
@@ -0,0 +1,30 @@
+ 'encrypted',
+ 'enabled' => 'boolean',
+ ];
+
+ protected $hidden = ['password'];
+}
diff --git a/app/Notifications/Auth/Invitation.php b/app/Notifications/Auth/Invitation.php
new file mode 100644
index 00000000..4f079d5d
--- /dev/null
+++ b/app/Notifications/Auth/Invitation.php
@@ -0,0 +1,53 @@
+invitation = $invitation;
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ return (new MailMessage)
+ ->from(config('mail.from.address'), config('mail.from.name'))
+ ->line(trans('auth.invitation.message_1'))
+ ->action(trans('auth.invitation.button'), route('register', $this->invitation->token))
+ ->line(trans('auth.invitation.message_2'));
+ }
+}
diff --git a/app/Notifications/Auth/Reset.php b/app/Notifications/Auth/Reset.php
new file mode 100644
index 00000000..ee8cd105
--- /dev/null
+++ b/app/Notifications/Auth/Reset.php
@@ -0,0 +1,61 @@
+token = $token;
+ $this->email = $email;
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ return (new MailMessage)
+ ->from(config('mail.from.address'), config('mail.from.name'))
+ ->line(trans('auth.notification.message_1'))
+ ->action(trans('auth.notification.button'), route('reset', ['token' => $this->token, 'email' => $this->email]))
+ ->line(trans('auth.notification.message_2'));
+ }
+}
diff --git a/app/Notifications/Banking/Transaction.php b/app/Notifications/Banking/Transaction.php
new file mode 100644
index 00000000..a99abe28
--- /dev/null
+++ b/app/Notifications/Banking/Transaction.php
@@ -0,0 +1,159 @@
+transaction = $transaction;
+ $this->template = EmailTemplate::alias($template_alias)->first();
+ $this->attach_pdf = $attach_pdf;
+ $this->custom_mail = $custom_mail;
+ $this->attachments = $attachments;
+ }
+
+ /**
+ * Get the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ if (! empty($this->custom_mail['to'])) {
+ $notifiable->email = $this->custom_mail['to'];
+ }
+
+ $message = $this->initMailMessage();
+
+ $func = is_local_storage() ? 'fromPath' : 'fromStorage';
+
+ // Attach the PDF file
+ if ($this->attach_pdf) {
+ $path = $this->storeTransactionPdfAndGetPath($this->transaction);
+ $file = Attachment::$func($path)->withMime('application/pdf');
+
+ $message->attach($file);
+ }
+
+ // Attach selected attachments
+ if (! empty($this->transaction->attachment)) {
+ foreach ($this->transaction->attachment as $attachment) {
+ if (! in_array($attachment->id, $this->attachments)) {
+ continue;
+ }
+
+ $path = is_local_storage() ? $attachment->getAbsolutePath() : $attachment->getDiskPath();
+ $file = Attachment::$func($path)->withMime($attachment->mime_type);
+
+ $message->attach($file);
+ }
+ }
+
+ return $message;
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable): array
+ {
+ $this->initArrayMessage();
+
+ return [
+ 'template_alias' => $this->template->alias,
+ 'title' => trans('notifications.menu.' . $this->template->alias . '.title'),
+ 'description' => trans('notifications.menu.' . $this->template->alias . '.description', $this->getTagsBinding()),
+ 'transaction_id' => $this->transaction->id,
+ 'contact_name' => $this->transaction->contact->name,
+ 'amount' => $this->transaction->amount,
+ 'transaction_date' => company_date($this->transaction->paid_at),
+ ];
+ }
+
+ public function getTags(): array
+ {
+ return [
+ '{payment_amount}',
+ '{payment_date}',
+ '{payment_guest_link}',
+ '{payment_admin_link}',
+ '{payment_portal_link}',
+ '{contact_name}',
+ '{company_name}',
+ '{company_email}',
+ '{company_tax_number}',
+ '{company_phone}',
+ '{company_address}',
+ ];
+ }
+
+ public function getTagsReplacement(): array
+ {
+ $route_params = [
+ 'company_id' => $this->transaction->company_id,
+ 'transaction' => $this->transaction->id,
+ 'payment' => $this->transaction->id,
+ ];
+
+ return [
+ money($this->transaction->amount, $this->transaction->currency_code),
+ company_date($this->transaction->paid_at),
+ URL::signedRoute('signed.payments.show', $route_params),
+ route('transactions.show', $route_params),
+ route('portal.payments.show', $route_params),
+ $this->transaction->contact->name,
+ $this->transaction->company->name,
+ $this->transaction->company->email,
+ $this->transaction->company->tax_number,
+ $this->transaction->company->phone,
+ nl2br(trim($this->transaction->company->address)),
+ ];
+ }
+}
diff --git a/app/Notifications/Common/DownloadCompleted.php b/app/Notifications/Common/DownloadCompleted.php
new file mode 100644
index 00000000..796cc8f0
--- /dev/null
+++ b/app/Notifications/Common/DownloadCompleted.php
@@ -0,0 +1,81 @@
+translation = $translation;
+ $this->file_name = $file_name;
+ $this->download_url = $download_url;
+
+ $this->onQueue('notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ return (new MailMessage)
+ ->from(config('mail.from.address'), config('mail.from.name'))
+ ->subject(trans('notifications.download.completed.title'))
+ ->line(new HtmlString('
'))
+ ->line(trans('notifications.download.completed.description'))
+ ->action(trans('general.download'), $this->download_url);
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ 'title' => trans('notifications.menu.download_completed.title'),
+ 'description' => trans('notifications.menu.download_completed.description', [
+ 'type' => $this->translation,
+ 'url' => $this->download_url,
+ ]),
+ 'translation' => $this->translation,
+ 'file_name' => $this->file_name,
+ 'download_url' => $this->download_url,
+ ];
+ }
+}
diff --git a/app/Notifications/Common/DownloadFailed.php b/app/Notifications/Common/DownloadFailed.php
new file mode 100644
index 00000000..2badb04e
--- /dev/null
+++ b/app/Notifications/Common/DownloadFailed.php
@@ -0,0 +1,77 @@
+message = $message;
+
+ $this->onQueue('notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ return (new MailMessage)
+ ->from(config('mail.from.address'), config('mail.from.name'))
+ ->subject(trans('notifications.download.failed.title'))
+ ->line(new HtmlString('
'))
+ ->line(trans('notifications.download.failed.description'))
+ ->line(new HtmlString('
'))
+ ->line($this->message)
+ ->line(new HtmlString('
'));
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ 'title' => trans('notifications.menu.download_failed.title'),
+ 'description' => trans('notifications.menu.download_failed.description'),
+ 'message' => $this->message,
+ ];
+ }
+}
diff --git a/app/Notifications/Common/ExportCompleted.php b/app/Notifications/Common/ExportCompleted.php
new file mode 100644
index 00000000..aac6521d
--- /dev/null
+++ b/app/Notifications/Common/ExportCompleted.php
@@ -0,0 +1,81 @@
+translation = $translation;
+ $this->file_name = $file_name;
+ $this->download_url = $download_url;
+
+ $this->onQueue('notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ return (new MailMessage)
+ ->from(config('mail.from.address'), config('mail.from.name'))
+ ->subject(trans('notifications.export.completed.title'))
+ ->line(new HtmlString('
'))
+ ->line(trans('notifications.export.completed.description'))
+ ->action(trans('general.download'), $this->download_url);
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ 'title' => trans('notifications.menu.export_completed.title'),
+ 'description' => trans('notifications.menu.export_completed.description', [
+ 'type' => $this->translation,
+ 'url' => $this->download_url,
+ ]),
+ 'translation' => $this->translation,
+ 'file_name' => $this->file_name,
+ 'download_url' => $this->download_url,
+ ];
+ }
+}
diff --git a/app/Notifications/Common/ExportFailed.php b/app/Notifications/Common/ExportFailed.php
new file mode 100644
index 00000000..5d524975
--- /dev/null
+++ b/app/Notifications/Common/ExportFailed.php
@@ -0,0 +1,77 @@
+message = $message;
+
+ $this->onQueue('notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ return (new MailMessage)
+ ->from(config('mail.from.address'), config('mail.from.name'))
+ ->subject(trans('notifications.export.failed.title'))
+ ->line(new HtmlString('
'))
+ ->line(trans('notifications.export.failed.description'))
+ ->line(new HtmlString('
'))
+ ->line($this->message)
+ ->line(new HtmlString('
'));
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ 'title' => trans('notifications.menu.export_failed.title'),
+ 'description' => trans('notifications.menu.export_failed.description'),
+ 'message' => $this->message,
+ ];
+ }
+}
diff --git a/app/Notifications/Common/ImportCompleted.php b/app/Notifications/Common/ImportCompleted.php
new file mode 100644
index 00000000..99e712c5
--- /dev/null
+++ b/app/Notifications/Common/ImportCompleted.php
@@ -0,0 +1,77 @@
+translation = $translation;
+ $this->total_rows = $total_rows;
+
+ $this->onQueue('notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ $dashboard_url = route('dashboard', ['company_id' => company_id()]);
+
+ return (new MailMessage)
+ ->from(config('mail.from.address'), config('mail.from.name'))
+ ->subject(trans('notifications.import.completed.title'))
+ ->line(new HtmlString('
'))
+ ->line(trans('notifications.import.completed.description'))
+ ->action(trans_choice('general.dashboards', 1), $dashboard_url);
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ 'title' => trans('notifications.menu.import_completed.title'),
+ 'description' => trans('notifications.menu.import_completed.description', [
+ 'type' => $this->translation,
+ 'count' => $this->total_rows,
+ ]),
+ 'translation' => $this->translation,
+ 'total_rows' => $this->total_rows,
+ ];
+ }
+}
diff --git a/app/Notifications/Common/ImportFailed.php b/app/Notifications/Common/ImportFailed.php
new file mode 100644
index 00000000..b04a9fc9
--- /dev/null
+++ b/app/Notifications/Common/ImportFailed.php
@@ -0,0 +1,83 @@
+errors = $errors;
+
+ $this->onQueue('notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ $message = (new MailMessage)
+ ->from(config('mail.from.address'), config('mail.from.name'))
+ ->subject(trans('notifications.import.failed.title'))
+ ->line(new HtmlString('
'))
+ ->line(trans('notifications.import.failed.description'));
+
+ foreach ($this->errors as $error) {
+ $message->line(new HtmlString('
'));
+ $message->line($error);
+ }
+
+ $message->line(new HtmlString('
'));
+
+ return $message;
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ 'title' => trans('notifications.menu.import_failed.title'),
+ 'description' => trans('notifications.menu.import_failed.description'),
+ 'errors' => $this->errors,
+ ];
+ }
+}
diff --git a/app/Notifications/Email/InvalidEmail.php b/app/Notifications/Email/InvalidEmail.php
new file mode 100644
index 00000000..e59bc714
--- /dev/null
+++ b/app/Notifications/Email/InvalidEmail.php
@@ -0,0 +1,80 @@
+email = $email;
+
+ $this->type = $type;
+
+ $this->error = $error;
+
+ $this->onQueue('notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ $dashboard_url = route('dashboard', ['company_id' => company_id()]);
+
+ return (new MailMessage)
+ ->from(config('mail.from.address'), config('mail.from.name'))
+ ->subject(trans('notifications.email.invalid.title', ['type' => $this->type]))
+ ->line(new HtmlString('
'))
+ ->line(trans('notifications.email.invalid.description', ['email' => $this->email]))
+ ->line(new HtmlString('
'))
+ ->line(new HtmlString('' . $this->error . ''))
+ ->action(trans_choice('general.dashboards', 1), $dashboard_url);
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ 'title' => trans('notifications.menu.invalid_email.title', ['type' => $this->type]),
+ 'description' => trans('notifications.menu.invalid_email.description', ['email' => $this->email]),
+ 'email' => $this->email,
+ ];
+ }
+}
diff --git a/app/Notifications/Install/UpdateFailed.php b/app/Notifications/Install/UpdateFailed.php
new file mode 100644
index 00000000..5506bd82
--- /dev/null
+++ b/app/Notifications/Install/UpdateFailed.php
@@ -0,0 +1,125 @@
+event = $event;
+ $this->notifications = config('update.notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ $channels = [];
+
+ foreach ($this->notifications as $channel => $settings) {
+ if (empty($settings['enabled'])) {
+ continue;
+ }
+
+ $channels[] = $channel;
+ }
+
+ return $channels;
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable)
+ {
+ $subject = trans('notifications.update.mail.title', [
+ 'domain' => request()->getHttpHost(),
+ ]);
+
+ $message = trans('notifications.update.mail.description', [
+ 'alias' => $this->getAliasName(),
+ 'current_version' => $this->event->old,
+ 'new_version' => $this->event->new,
+ 'step' => $this->event->step,
+ 'error_message' => $this->event->message,
+ ]);
+
+ return (new MailMessage)
+ ->from($this->notifications['mail']['from'], $this->notifications['mail']['name'])
+ ->subject($subject)
+ ->line($message);
+ }
+
+ /**
+ * Get the Slack representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return SlackMessage
+ */
+ public function toSlack($notifiable)
+ {
+ $message = trans('notifications.update.slack.description', [
+ 'domain' => request()->getHttpHost(),
+ ]);
+
+ return (new SlackMessage)
+ ->error()
+ ->from($this->notifications['slack']['from'], $this->notifications['slack']['emoji'])
+ ->to($this->notifications['slack']['channel'])
+ ->content($message)
+ ->attachment(function ($attachment) {
+ $attachment->fields([
+ 'Alias' => $this->getAliasName(),
+ 'Current Version' => $this->event->old,
+ 'New Version' => $this->event->new,
+ 'Step' => $this->event->step,
+ 'Error Message' => $this->event->message,
+ ]);
+ });
+ }
+
+ protected function getAliasName()
+ {
+ if ($this->event->alias == 'core') {
+ return config('app.name');
+ }
+
+ $module = module($this->event->alias);
+
+ if (empty($module)) {
+ return ucfirst($this->event->alias);
+ }
+
+ return $module->getName();
+ }
+}
diff --git a/app/Notifications/Portal/PaymentReceived.php b/app/Notifications/Portal/PaymentReceived.php
new file mode 100644
index 00000000..28ff24ce
--- /dev/null
+++ b/app/Notifications/Portal/PaymentReceived.php
@@ -0,0 +1,152 @@
+invoice = $invoice;
+ $this->transaction = $transaction;
+ $this->template = EmailTemplate::alias($template_alias)->first();
+ $this->attach_pdf = $attach_pdf;
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ $message = $this->initMailMessage();
+
+ // Attach the PDF file
+ if ($this->attach_pdf) {
+ $func = is_local_storage() ? 'fromPath' : 'fromStorage';
+
+ $path = $this->storeDocumentPdfAndGetPath($this->invoice);
+ $file = Attachment::$func($path)->withMime('application/pdf');
+
+ $message->attach($file);
+ }
+
+ return $message;
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ */
+ public function toArray($notifiable): array
+ {
+ $this->initArrayMessage();
+
+ return [
+ 'template_alias' => $this->template->alias,
+ 'title' => trans('notifications.menu.' . $this->template->alias . '.title'),
+ 'description' => trans('notifications.menu.' . $this->template->alias . '.description', $this->getTagsBinding()),
+ 'invoice_id' => $this->invoice->id,
+ 'invoice_number' => $this->invoice->document_number,
+ 'customer_name' => $this->invoice->contact_name,
+ 'amount' => $this->invoice->amount,
+ 'invoice_at' => $this->invoice->issued_at,
+ 'due_at' => $this->invoice->due_at,
+ 'status' => $this->invoice->status,
+ ];
+ }
+
+ public function getTags(): array
+ {
+ return [
+ '{invoice_number}',
+ '{invoice_total}',
+ '{invoice_due_date}',
+ '{invoice_status}',
+ '{invoice_guest_link}',
+ '{invoice_admin_link}',
+ '{invoice_portal_link}',
+ '{transaction_total}',
+ '{transaction_paid_date}',
+ '{transaction_payment_method}',
+ '{customer_name}',
+ '{company_name}',
+ '{company_email}',
+ '{company_tax_number}',
+ '{company_phone}',
+ '{company_address}',
+ ];
+ }
+
+ public function getTagsReplacement(): array
+ {
+ $route_params = [
+ 'company_id' => $this->invoice->company_id,
+ 'invoice' => $this->invoice->id,
+ ];
+
+ return [
+ $this->invoice->document_number,
+ money($this->invoice->amount, $this->invoice->currency_code),
+ company_date($this->invoice->due_at),
+ trans('documents.statuses.' . $this->invoice->status),
+ URL::signedRoute('signed.invoices.show', $route_params),
+ route('invoices.show', $route_params),
+ route('portal.invoices.show', $route_params),
+ money($this->transaction->amount, $this->transaction->currency_code),
+ company_date($this->transaction->paid_at),
+ $this->transaction->payment_method,
+ $this->invoice->contact_name,
+ $this->invoice->company->name,
+ $this->invoice->company->email,
+ $this->invoice->company->tax_number,
+ $this->invoice->company->phone,
+ nl2br(trim($this->invoice->company->address)),
+ ];
+ }
+}
diff --git a/app/Notifications/Purchase/Bill.php b/app/Notifications/Purchase/Bill.php
new file mode 100644
index 00000000..4ec44e94
--- /dev/null
+++ b/app/Notifications/Purchase/Bill.php
@@ -0,0 +1,113 @@
+bill = $bill;
+ $this->template = EmailTemplate::alias($template_alias)->first();
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ $message = $this->initMailMessage();
+
+ return $message;
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ */
+ public function toArray($notifiable): array
+ {
+ $this->initArrayMessage();
+
+ return [
+ 'template_alias' => $this->template->alias,
+ 'title' => trans('notifications.menu.' . $this->template->alias . '.title'),
+ 'description' => trans('notifications.menu.' . $this->template->alias . '.description', $this->getTagsBinding()),
+ 'bill_id' => $this->bill->id,
+ 'bill_number' => $this->bill->document_number,
+ 'vendor_name' => $this->bill->contact_name,
+ 'amount' => $this->bill->amount,
+ 'billed_date' => company_date($this->bill->issued_at),
+ 'bill_due_date' => company_date($this->bill->due_at),
+ 'status' => $this->bill->status,
+ ];
+ }
+
+ public function getTags(): array
+ {
+ return [
+ '{bill_number}',
+ '{bill_total}',
+ '{bill_amount_due}',
+ '{billed_date}',
+ '{bill_due_date}',
+ '{bill_admin_link}',
+ '{vendor_name}',
+ '{company_name}',
+ '{company_email}',
+ '{company_tax_number}',
+ '{company_phone}',
+ '{company_address}',
+ ];
+ }
+
+ public function getTagsReplacement(): array
+ {
+ $route_params = [
+ 'company_id' => $this->bill->company_id,
+ 'bill' => $this->bill->id,
+ ];
+
+ return [
+ $this->bill->document_number,
+ money($this->bill->amount, $this->bill->currency_code),
+ money($this->bill->amount_due, $this->bill->currency_code),
+ company_date($this->bill->issued_at),
+ company_date($this->bill->due_at),
+ route('bills.show', $route_params),
+ $this->bill->contact_name,
+ $this->bill->company->name,
+ $this->bill->company->email,
+ $this->bill->company->tax_number,
+ $this->bill->company->phone,
+ nl2br(trim($this->bill->company->address)),
+ ];
+ }
+}
diff --git a/app/Notifications/Sale/Invoice.php b/app/Notifications/Sale/Invoice.php
new file mode 100644
index 00000000..73b48d28
--- /dev/null
+++ b/app/Notifications/Sale/Invoice.php
@@ -0,0 +1,166 @@
+invoice = $invoice;
+ $this->template = EmailTemplate::alias($template_alias)->first();
+ $this->attach_pdf = $attach_pdf;
+ $this->custom_mail = $custom_mail;
+ $this->attachments = $attachments;
+ }
+
+ /**
+ * Get the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ */
+ public function toMail($notifiable): MailMessage
+ {
+ if (!empty($this->custom_mail['to'])) {
+ $notifiable->email = $this->custom_mail['to'];
+ }
+
+ $message = $this->initMailMessage();
+
+ $func = is_local_storage() ? 'fromPath' : 'fromStorage';
+
+ // Attach the PDF file
+ if ($this->attach_pdf) {
+ $path = $this->storeDocumentPdfAndGetPath($this->invoice);
+ $file = Attachment::$func($path)->withMime('application/pdf');
+
+ $message->attach($file);
+ }
+
+ // Attach selected attachments
+ if (! empty($this->invoice->attachment)) {
+ foreach ($this->invoice->attachment as $attachment) {
+ if (! in_array($attachment->id, $this->attachments)) {
+ continue;
+ }
+
+ $path = is_local_storage() ? $attachment->getAbsolutePath() : $attachment->getDiskPath();
+ $file = Attachment::$func($path)->withMime($attachment->mime_type);
+
+ $message->attach($file);
+ }
+ }
+
+ return $message;
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ */
+ public function toArray($notifiable): array
+ {
+ $this->initArrayMessage();
+
+ return [
+ 'template_alias' => $this->template->alias,
+ 'title' => trans('notifications.menu.' . $this->template->alias . '.title'),
+ 'description' => trans('notifications.menu.' . $this->template->alias . '.description', $this->getTagsBinding()),
+ 'invoice_id' => $this->invoice->id,
+ 'invoice_number' => $this->invoice->document_number,
+ 'customer_name' => $this->invoice->contact_name,
+ 'amount' => $this->invoice->amount,
+ 'invoiced_date' => company_date($this->invoice->issued_at),
+ 'invoice_due_date' => company_date($this->invoice->due_at),
+ 'status' => $this->invoice->status,
+ ];
+ }
+
+ public function getTags(): array
+ {
+ return [
+ '{invoice_number}',
+ '{invoice_total}',
+ '{invoice_amount_due}',
+ '{invoiced_date}',
+ '{invoice_due_date}',
+ '{invoice_guest_link}',
+ '{invoice_admin_link}',
+ '{invoice_portal_link}',
+ '{customer_name}',
+ '{company_name}',
+ '{company_email}',
+ '{company_tax_number}',
+ '{company_phone}',
+ '{company_address}',
+ ];
+ }
+
+ public function getTagsReplacement(): array
+ {
+ $route_params = [
+ 'company_id' => $this->invoice->company_id,
+ 'invoice' => $this->invoice->id,
+ ];
+
+ return [
+ $this->invoice->document_number,
+ money($this->invoice->amount, $this->invoice->currency_code),
+ money($this->invoice->amount_due, $this->invoice->currency_code),
+ company_date($this->invoice->issued_at),
+ company_date($this->invoice->due_at),
+ URL::signedRoute('signed.invoices.show', $route_params),
+ route('invoices.show', $route_params),
+ route('portal.invoices.show', $route_params),
+ $this->invoice->contact_name,
+ $this->invoice->company->name,
+ $this->invoice->company->email,
+ $this->invoice->company->tax_number,
+ $this->invoice->company->phone,
+ nl2br(trim($this->invoice->company->address)),
+ ];
+ }
+}
diff --git a/app/Observers/Transaction.php b/app/Observers/Transaction.php
new file mode 100644
index 00000000..7f6e2101
--- /dev/null
+++ b/app/Observers/Transaction.php
@@ -0,0 +1,80 @@
+document_id)) {
+ $type = ($transaction->type == 'income') ? Document::INVOICE_TYPE : Document::BILL_TYPE;
+
+ $this->updateDocument($transaction, $type);
+ }
+
+ if (! empty($transaction->split_id)) {
+ $this->updateTransaction($transaction);
+ }
+ }
+
+ protected function updateDocument($transaction, $type)
+ {
+ $document = $transaction->{$type};
+
+ if (empty($document)) {
+ return;
+ }
+
+ $document->transactions_count = $document->transactions->count();
+
+ event(new TransactionsCounted($document));
+
+ $document->status = ($type == Document::INVOICE_TYPE) ? 'sent' : 'received';
+
+ if ($document->transactions_count > 0) {
+ $document->status = 'partial';
+ }
+
+ unset($document->transactions_count);
+
+ $document->save();
+
+ $this->dispatch(new CreateDocumentHistory($document, 0, $this->getDescription($transaction)));
+ }
+
+ protected function getDescription($transaction)
+ {
+ $amount = money((double) $transaction->amount, (string) $transaction->currency_code)->format();
+
+ return trans('messages.success.deleted', ['type' => $amount . ' ' . trans_choice('general.payments', 1)]);
+ }
+
+ protected function updateTransaction($transaction)
+ {
+ $splitted_transaction = Model::find($transaction->split_id);
+
+ if ($splitted_transaction->splits->count() == 0) {
+ $values = [
+ 'type' => $transaction->type,
+ ];
+
+ $this->dispatch(new UpdateTransaction($splitted_transaction, $values));
+ }
+ }
+}
diff --git a/app/Providers/App.php b/app/Providers/App.php
new file mode 100644
index 00000000..81c196d9
--- /dev/null
+++ b/app/Providers/App.php
@@ -0,0 +1,55 @@
+app->register(\Barryvdh\Debugbar\ServiceProvider::class);
+ }
+
+ if (! env_is_production()) {
+ $this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class);
+ }
+
+ Sanctum::ignoreMigrations();
+ }
+
+ /**
+ * Bootstrap any application services.
+ *
+ * @return void
+ */
+ public function boot()
+ {
+ // Laravel db fix
+ Schema::defaultStringLength(191);
+
+ Paginator::useBootstrap();
+
+ Model::preventLazyLoading(config('app.eager_load'));
+
+ Model::handleLazyLoadingViolationUsing(function ($model, $relation) {
+ if (config('logging.default') == 'sentry') {
+ \Sentry\Laravel\Integration::lazyLoadingViolationReporter();
+ } else {
+ $class = get_class($model);
+
+ report("Attempted to lazy load [{$relation}] on model [{$class}].");
+ }
+ });
+ }
+}
diff --git a/app/Providers/Auth.php b/app/Providers/Auth.php
new file mode 100644
index 00000000..4b8b7651
--- /dev/null
+++ b/app/Providers/Auth.php
@@ -0,0 +1,27 @@
+ 'App\Policies\ModelPolicy',
+ ];
+
+ /**
+ * Register any authentication / authorization services.
+ *
+ * @return void
+ */
+ public function boot()
+ {
+ $this->registerPolicies();
+ }
+}
diff --git a/app/Providers/Binding.php b/app/Providers/Binding.php
new file mode 100644
index 00000000..3a4d2a05
--- /dev/null
+++ b/app/Providers/Binding.php
@@ -0,0 +1,22 @@
+ DocumentNumber::class,
+ TransactionNumberInterface::class => TransactionNumber::class,
+ ];
+}
diff --git a/app/Providers/Blade.php b/app/Providers/Blade.php
new file mode 100644
index 00000000..b7a5db9d
--- /dev/null
+++ b/app/Providers/Blade.php
@@ -0,0 +1,55 @@
+";
+ });
+
+ Facade::directive('widget', function ($expression) {
+ return "";
+ });
+
+ Facade::directive('moduleIsEnabled', function ($expression) {
+ return "";
+ });
+
+ Facade::if('readonly', function () {
+ return config('read-only.enabled');
+ });
+
+ Facade::component('form.group.switch', Sswitch::class);
+ Facade::component('media.file', MFile::class);
+ Facade::component('form.input.file', Ffile::class);
+ Facade::component('index.default', Ddefault::class);
+ }
+
+ /**
+ * Register any application services.
+ *
+ * @return void
+ */
+ public function register()
+ {
+ //
+ }
+}
diff --git a/app/Providers/Broadcast.php b/app/Providers/Broadcast.php
new file mode 100644
index 00000000..e41c6aec
--- /dev/null
+++ b/app/Providers/Broadcast.php
@@ -0,0 +1,20 @@
+ [
+ \App\Listeners\Update\CreateModuleUpdatedHistory::class,
+ \App\Listeners\Module\UpdateExtraModules::class,
+ \App\Listeners\Update\V30\Version300::class,
+ \App\Listeners\Update\V30\Version303::class,
+ \App\Listeners\Update\V30\Version304::class,
+ \App\Listeners\Update\V30\Version305::class,
+ \App\Listeners\Update\V30\Version307::class,
+ \App\Listeners\Update\V30\Version309::class,
+ \App\Listeners\Update\V30\Version3013::class,
+ \App\Listeners\Update\V30\Version3014::class,
+ \App\Listeners\Update\V30\Version3015::class,
+ \App\Listeners\Update\V30\Version3016::class,
+ \App\Listeners\Update\V30\Version3017::class,
+ \App\Listeners\Update\V31\Version310::class,
+ \App\Listeners\Update\V31\Version315::class,
+ \App\Listeners\Update\V31\Version317::class,
+ \App\Listeners\Update\V31\Version318::class,
+ \App\Listeners\Update\V31\Version3112::class,
+ \App\Listeners\Update\V31\Version3115::class,
+ \App\Listeners\Update\V31\Version3119::class,
+ \App\Listeners\Update\V32\Version320::class,
+ ],
+ \Illuminate\Routing\Events\PreparingResponse::class => [
+ \App\Listeners\Common\PreparingResponse::class,
+ ],
+ \Illuminate\Auth\Events\Login::class => [
+ \App\Listeners\Auth\Login::class,
+ ],
+ \Illuminate\Auth\Events\Logout::class => [
+ \App\Listeners\Auth\Logout::class,
+ ],
+ //'Illuminate\Console\Events\ScheduledTaskStarting' => [
+ \Illuminate\Console\Events\CommandStarting::class => [
+ \App\Listeners\Common\SkipScheduleInReadOnlyMode::class,
+ ],
+ \App\Events\Auth\LandingPageShowing::class => [
+ \App\Listeners\Auth\AddLandingPages::class,
+ ],
+ \App\Events\Document\DocumentCreated::class => [
+ \App\Listeners\Document\CreateDocumentCreatedHistory::class,
+ \App\Listeners\Document\IncreaseNextDocumentNumber::class,
+ \App\Listeners\Document\SettingFieldCreated::class,
+ ],
+ \App\Events\Document\DocumentReceived::class => [
+ \App\Listeners\Document\MarkDocumentReceived::class,
+ ],
+ \App\Events\Document\DocumentCancelled::class => [
+ \App\Listeners\Document\MarkDocumentCancelled::class,
+ ],
+ \App\Events\Document\DocumentRestored::class => [
+ \App\Listeners\Document\RestoreDocument::class,
+ ],
+ \App\Events\Document\DocumentRecurring::class => [
+ \App\Listeners\Document\SendDocumentRecurringNotification::class,
+ ],
+ \App\Events\Document\DocumentReminded::class => [
+ \App\Listeners\Document\SendDocumentReminderNotification::class,
+ ],
+ \App\Events\Document\PaymentReceived::class => [
+ \App\Listeners\Document\CreateDocumentTransaction::class,
+ \App\Listeners\Document\SendDocumentPaymentNotification::class,
+ ],
+ \App\Events\Document\DocumentMarkedSent::class => [
+ \App\Listeners\Document\MarkDocumentSent::class,
+ ],
+ \App\Events\Document\DocumentSent::class => [
+ \App\Listeners\Document\MarkDocumentSent::class,
+ ],
+ \App\Events\Document\DocumentUpdated::class => [
+ \App\Listeners\Document\SettingFieldUpdated::class,
+ ],
+ \App\Events\Document\DocumentViewed::class => [
+ \App\Listeners\Document\MarkDocumentViewed::class,
+ \App\Listeners\Document\SendDocumentViewNotification::class,
+ ],
+ \App\Events\Install\UpdateFailed::class => [
+ \App\Listeners\Update\SendNotificationOnFailure::class,
+ ],
+ \App\Events\Menu\NotificationsCreated::class => [
+ \App\Listeners\Menu\ShowInNotifications::class,
+ ],
+ \App\Events\Menu\AdminCreated::class => [
+ \App\Listeners\Menu\ShowInAdmin::class,
+ ],
+ \App\Events\Menu\ProfileCreated::class => [
+ \App\Listeners\Menu\ShowInProfile::class,
+ ],
+ \App\Events\Menu\SettingsCreated::class => [
+ \App\Listeners\Menu\ShowInSettings::class,
+ ],
+ \App\Events\Menu\NewwCreated::class => [
+ \App\Listeners\Menu\ShowInNeww::class,
+ ],
+ \App\Events\Menu\PortalCreated::class => [
+ \App\Listeners\Menu\ShowInPortal::class,
+ ],
+ \App\Events\Module\Installed::class => [
+ \App\Listeners\Module\InstallExtraModules::class,
+ \App\Listeners\Module\FinishInstallation::class,
+ ],
+ \App\Events\Module\Uninstalled::class => [
+ \App\Listeners\Module\FinishUninstallation::class,
+ ],
+ \App\Events\Banking\TransactionCreated::class => [
+ \App\Listeners\Banking\IncreaseNextTransactionNumber::class,
+ ],
+ \App\Events\Setting\CategoryDeleted::class => [
+ \App\Listeners\Setting\DeleteCategoryDeletedSubCategories::class,
+ ],
+ \App\Events\Email\TooManyEmailsSent::class => [
+ \App\Listeners\Email\ReportTooManyEmailsSent::class,
+ \App\Listeners\Email\TellFirewallTooManyEmailsSent::class,
+ ],
+ \App\Events\Email\InvalidEmailDetected::class => [
+ \App\Listeners\Email\DisablePersonDueToInvalidEmail::class,
+ \App\Listeners\Email\SendInvalidEmailNotification::class,
+ ],
+ ];
+
+ /**
+ * The subscriber classes to register.
+ *
+ * @var array
+ */
+ protected $subscribe = [
+ \App\Listeners\Common\ClearPlansCache::class,
+ \App\Listeners\Module\ClearCache::class,
+ \App\Listeners\Report\AddAccounts::class,
+ \App\Listeners\Report\AddContacts::class,
+ \App\Listeners\Report\AddCustomers::class,
+ \App\Listeners\Report\AddVendors::class,
+ \App\Listeners\Report\AddExpenseCategories::class,
+ \App\Listeners\Report\AddIncomeCategories::class,
+ \App\Listeners\Report\AddIncomeExpenseCategories::class,
+ \App\Listeners\Report\AddSearchString::class,
+ \App\Listeners\Report\AddRowsToTax::class,
+ \App\Listeners\Report\AddGroup::class,
+ \App\Listeners\Report\AddBasis::class,
+ \App\Listeners\Report\AddPeriod::class,
+ \App\Listeners\Report\AddDate::class,
+ \App\Listeners\Report\AddDiscount::class,
+ ];
+}
diff --git a/app/Providers/Macro.php b/app/Providers/Macro.php
new file mode 100644
index 00000000..e57a7c14
--- /dev/null
+++ b/app/Providers/Macro.php
@@ -0,0 +1,157 @@
+is(config('api.prefix') . '/*');
+ });
+
+ Request::macro('isNotApi', function () {
+ return ! $this->isApi();
+ });
+
+ Request::macro('isAuth', function () {
+ return $this->is('auth/*');
+ });
+
+ Request::macro('isNotAuth', function () {
+ return ! $this->isAuth();
+ });
+
+ Request::macro('isInstall', function () {
+ return $this->is('install/*');
+ });
+
+ Request::macro('isNotInstall', function () {
+ return ! $this->isInstall();
+ });
+
+ Request::macro('isPreview', function ($company_id) {
+ return $this->is($company_id . '/preview/*');
+ });
+
+ Request::macro('isNotPreview', function ($company_id) {
+ return !$this->isPreview($company_id);
+ });
+
+ Request::macro('isSigned', function ($company_id) {
+ return $this->is($company_id . '/signed/*');
+ });
+
+ Request::macro('isNotSigned', function ($company_id) {
+ return ! $this->isSigned($company_id);
+ });
+
+ Request::macro('isPortal', function ($company_id) {
+ return $this->is($company_id . '/portal') || $this->is($company_id . '/portal/*');
+ });
+
+ Request::macro('isNotPortal', function ($company_id) {
+ return ! $this->isPortal($company_id);
+ });
+
+ Request::macro('isWizard', function ($company_id) {
+ return $this->is($company_id . '/wizard') || $this->is($company_id . '/wizard/*');
+ });
+
+ Request::macro('isNotWizard', function ($company_id) {
+ return ! $this->isWizard($company_id);
+ });
+
+ Request::macro('isAdmin', function ($company_id) {
+ return $this->isNotApi()
+ && $this->isNotAuth()
+ && $this->isNotOAuth()
+ && $this->isNotInstall()
+ && $this->isNotSigned($company_id)
+ && $this->isNotPortal($company_id)
+ && $this->isNotWizard($company_id);
+ });
+
+ Request::macro('isNotAdmin', function ($company_id) {
+ return ! $this->isAdmin($company_id);
+ });
+
+ Request::macro('isOAuth', function () {
+ return $this->is(config('oauth.prefix', 'oauth') . '/*');
+ });
+
+ Request::macro('isNotOAuth', function () {
+ return ! $this->isOAuth();
+ });
+
+ Request::macro('isMcp', function () {
+ return $this->is('mcp') || $this->is('mcp/*');
+ });
+
+ Request::macro('isNotMcp', function () {
+ return ! $this->isMcp();
+ });
+
+ Request::macro('isCloudHost', function () {
+ return $this->getHost() == config('cloud.host', 'app.akaunting.com');
+ });
+
+ Request::macro('isNotCloudHost', function () {
+ return ! $this->isCloudHost();
+ });
+
+ Str::macro('filename', function ($string, $separator = '-') {
+ // Replace @ with the word 'at'
+ $string = str_replace('@', $separator.'at'.$separator, $string);
+
+ // Remove all characters that are not the separator, letters, numbers, or whitespace.
+ $string = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', $string);
+
+ // Remove multiple whitespaces
+ $string = preg_replace('/\s+/', ' ', $string);
+
+ return $string;
+ });
+
+ ViewFactory::macro('hasStack', function (...$sections) {
+ foreach ($sections as $section) {
+ if (isset($this->pushes[$section]) || isset($this->prepends[$section])) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+
+ Collection::macro('withChildren', function ($relation, $addChildren) {
+ $list = new Collection();
+
+ foreach ($this as $model) {
+ $addChildren($list, $model, $relation, 0, $addChildren);
+ }
+
+ return $list;
+ });
+ }
+}
diff --git a/app/Providers/Observer.php b/app/Providers/Observer.php
new file mode 100644
index 00000000..27af5bdc
--- /dev/null
+++ b/app/Providers/Observer.php
@@ -0,0 +1,29 @@
+createPayloadUsing(function ($connection, $queue, $payload) {
+ $company_id = company_id();
+
+ if (empty($company_id)) {
+ return [];
+ }
+
+ return ['company_id' => $company_id];
+ });
+
+ app('events')->listen(JobProcessing::class, function ($event) {
+ $payload = $event->job->payload();
+
+ if (! array_key_exists('company_id', $payload)) {
+ return;
+ }
+
+ try {
+ $company = company($payload['company_id']);
+ } catch (\Throwable $e) {
+ $event->job->delete();
+
+ logger()->warning('Company could not be resolved for queued job, job deleted.', [
+ 'company_id' => $payload['company_id'],
+ 'payload' => $payload,
+ 'exception' => $e->getMessage(),
+ ]);
+
+ return;
+ }
+
+ if (empty($company)) {
+ $event->job->delete();
+
+ logger()->warning('Company not found, job deleted.', [
+ 'company_id' => $payload['company_id'],
+ 'payload' => $payload,
+ ]);
+
+ return;
+ }
+
+ $company->makeCurrent();
+
+ // TODO: Move queue control at the beginning of the closure
+ if (should_queue()) {
+ $this->registerModules();
+ }
+ });
+
+ app('events')->listen(JobFailed::class, function ($event) {
+ if (!$event->exception instanceof \Maatwebsite\Excel\Validators\ValidationException) {
+ return;
+ }
+
+ $body = $event->job->getRawBody();
+ if (empty($body) || !is_string($body)) {
+ return;
+ }
+
+ $payload = json_decode($body);
+ if (empty($payload) || empty($payload->data) || empty($payload->data->command)) {
+ return;
+ }
+
+ $excel_job = unserialize($payload->data->command);
+ if (!$excel_job instanceof \Maatwebsite\Excel\Jobs\ReadChunk) {
+ return;
+ }
+
+ $ref = new \ReflectionProperty($excel_job, 'import');
+ $ref->setAccessible(true);
+
+ // Get import class
+ $class = $ref->getValue($excel_job);
+
+ if (!$class instanceof \App\Abstracts\Import && !$class instanceof \App\Abstracts\ImportMultipleSheets) {
+ return;
+ }
+
+ $errors = [];
+
+ foreach ($event->exception->failures() as $failure) {
+ $message = trans('messages.error.import_column', [
+ 'message' => collect($failure->errors())->first(),
+ 'column' => $failure->attribute(),
+ 'line' => $failure->row(),
+ ]);
+
+ $errors[] = $message;
+ }
+
+ if (!empty($errors)) {
+ $class->user->notify(new ImportFailed($errors));
+ }
+ });
+ }
+}
diff --git a/app/Providers/Route.php b/app/Providers/Route.php
new file mode 100644
index 00000000..ebf2851d
--- /dev/null
+++ b/app/Providers/Route.php
@@ -0,0 +1,330 @@
+ $attrs['middleware'],
+ ];
+
+ if (isset($attrs['namespace'])) {
+ // null means don't add
+ if (!is_null($attrs['namespace'])) {
+ $attributes['namespace'] = $attrs['namespace'];
+ }
+ } else {
+ $attributes['namespace'] = 'Modules\\' . module($alias)->getStudlyName() . '\Http\Controllers';
+ }
+
+ if (isset($attrs['prefix'])) {
+ // null means don't add
+ if (!is_null($attrs['prefix'])) {
+ $attributes['prefix'] = '{company_id}/' . $attrs['prefix'];
+ }
+ } else {
+ $attributes['prefix'] = '{company_id}/' . $alias;
+ }
+
+ if (isset($attrs['as'])) {
+ // null means don't add
+ if (!is_null($attrs['as'])) {
+ $attributes['as'] = $attrs['as'];
+ }
+ } else {
+ $attributes['as'] = $alias . '.';
+ }
+
+ return Facade::group($attributes, $routes);
+ });
+
+ Facade::macro('admin', function ($alias, $routes, $attributes = []) {
+ return Facade::module($alias, $routes, array_merge([
+ 'middleware' => 'admin',
+ ], $attributes));
+ });
+
+ Facade::macro('preview', function ($alias, $routes, $attributes = []) {
+ return Facade::module($alias, $routes, array_merge([
+ 'middleware' => 'preview',
+ 'prefix' => 'preview/' . $alias,
+ 'as' => 'preview.' . $alias . '.',
+ ], $attributes));
+ });
+
+ Facade::macro('portal', function ($alias, $routes, $attributes = []) {
+ return Facade::module($alias, $routes, array_merge([
+ 'middleware' => 'portal',
+ 'prefix' => 'portal/' . $alias,
+ 'as' => 'portal.' . $alias . '.',
+ ], $attributes));
+ });
+
+ Facade::macro('signed', function ($alias, $routes, $attributes = []) {
+ return Facade::module($alias, $routes, array_merge([
+ 'middleware' => 'signed',
+ 'prefix' => 'signed/' . $alias,
+ 'as' => 'signed.' . $alias . '.',
+ ], $attributes));
+ });
+
+ Facade::macro('api', function ($alias, $routes, $attributes = []) {
+ return Facade::module($alias, $routes, array_merge([
+ 'namespace' => 'Modules\\' . module($alias)->getStudlyName() . '\Http\Controllers\Api',
+ 'domain' => config('api.domain'),
+ 'middleware' => config('api.middleware'),
+ 'prefix' => config('api.prefix') ? config('api.prefix') . '/' . $alias : $alias,
+ 'as' => 'api.' . $alias . '.',
+ ], $attributes));
+ });
+ }
+
+ /**
+ * Define the routes for the application.
+ *
+ * @return void
+ */
+ public function map()
+ {
+ $this->configureRateLimiting();
+
+ $this->mapInstallRoutes();
+
+ $this->mapApiRoutes();
+
+ $this->mapCommonRoutes();
+
+ $this->mapGuestRoutes();
+
+ $this->mapWizardRoutes();
+
+ $this->mapAdminRoutes();
+
+ $this->mapPreviewRoutes();
+
+ $this->mapPortalRoutes();
+
+ $this->mapSignedRoutes();
+
+ $this->mapWebRoutes();
+ }
+
+ /**
+ * Define the "install" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapInstallRoutes()
+ {
+ Facade::prefix('install')
+ ->middleware('install')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/install.php'));
+ }
+
+ /**
+ * Define the "api" routes for the application.
+ *
+ * These routes are typically stateless.
+ *
+ * @return void
+ */
+ protected function mapApiRoutes()
+ {
+ Facade::prefix(config('api.prefix'))
+ ->domain(config('api.domain'))
+ ->middleware(config('api.middleware'))
+ ->namespace($this->namespace . '\Api')
+ ->group(base_path('routes/api.php'));
+ }
+
+ /**
+ * Define the "common" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapCommonRoutes()
+ {
+ Facade::prefix('{company_id}')
+ ->middleware('common')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/common.php'));
+ }
+
+ /**
+ * Define the "guest" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapGuestRoutes()
+ {
+ Facade::middleware('guest')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/guest.php'));
+ }
+
+ /**
+ * Define the "wizard" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapWizardRoutes()
+ {
+ Facade::prefix('{company_id}/wizard')
+ ->middleware('wizard')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/wizard.php'));
+ }
+
+ /**
+ * Define the "admin" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapAdminRoutes()
+ {
+ Facade::prefix('{company_id}')
+ ->middleware('admin')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/admin.php'));
+ }
+ /**
+ * Define the "preview" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapPreviewRoutes()
+ {
+ Facade::prefix('{company_id}/preview')
+ ->middleware('preview')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/preview.php'));
+ }
+
+ /**
+ * Define the "portal" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapPortalRoutes()
+ {
+ Facade::prefix('{company_id}/portal')
+ ->middleware('portal')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/portal.php'));
+ }
+
+ /**
+ * Define the "signed" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapSignedRoutes()
+ {
+ Facade::prefix('{company_id}/signed')
+ ->middleware('signed')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/signed.php'));
+ }
+
+ /**
+ * Define the "web" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapWebRoutes()
+ {
+ Facade::middleware('web')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/web.php'));
+ }
+
+ /**
+ * Configure the rate limiters for the application.
+ *
+ * @return void
+ */
+ protected function configureRateLimiting()
+ {
+ RateLimiter::for('api', function (Request $request) {
+ return Limit::perMinute(config('app.throttles.api'))
+ ->by($request->user()?->id ?: $request->ip());
+ });
+
+ RateLimiter::for('oauth', function (Request $request) {
+ return Limit::perMinute(config('app.throttles.oauth'))
+ ->by($request->user()?->id ?: $request->ip());
+ });
+
+ RateLimiter::for('dcr', function (Request $request) {
+ // Dynamic Client Registration: Strict rate limiting to prevent spam
+ return [
+ Limit::perHour(10)->by($request->ip()), // 10 per hour per IP
+ Limit::perDay(50)->by($request->ip()), // 50 per day per IP
+ ];
+ });
+
+ RateLimiter::for('import', function (Request $request) {
+ return Limit::perMinute(config('app.throttles.import'));
+ });
+
+ RateLimiter::for('email', function (Request $request) {
+ return [
+ Limit::perDay(config('app.throttles.email.month'), 30),
+ Limit::perMinute(config('app.throttles.email.minute')),
+ ];
+ });
+ }
+}
diff --git a/app/Providers/Validation.php b/app/Providers/Validation.php
new file mode 100644
index 00000000..0158c6a5
--- /dev/null
+++ b/app/Providers/Validation.php
@@ -0,0 +1,158 @@
+pluck('code')->toArray();
+
+ if (in_array($value, $currencies)) {
+ $status = true;
+ }
+
+ if (strlen($value) != 3) {
+ return $status;
+ }
+
+ $currency_code = $value;
+
+ return $status;
+ });
+
+ // Custom message for currency validation
+ Validator::replacer('currency', function($message, $attribute, $rule, $parameters) {
+ return trans('validation.custom.invalid_currency', ['attribute' => $attribute]);
+ });
+
+ // Check currency code is valid
+ Validator::extend('currency_code', function ($attribute, $value, $parameters, $validator) {
+ $status = false;
+
+ $currency_code = $value;
+
+ $currencies = config('money.currencies');
+
+ if (array_key_exists($value, $currencies)) {
+ $status = true;
+ }
+
+ return $status;
+ });
+
+ // Custom message for currency code validation
+ Validator::replacer('currency_code', function($message, $attribute, $rule, $parameters) {
+ return trans('validation.custom.invalid_currency', ['attribute' => $attribute]);
+ });
+
+ // Check amount is valid
+ Validator::extend('amount', function ($attribute, $value, $parameters, $validator) {
+ $status = false;
+
+ if ($value > 0 || in_array($value, $parameters)) {
+ $status = true;
+ }
+
+ if (! preg_match("/^(?=.*?[0-9])[0-9.,]+$/", $value)) {
+ $status = false;
+ }
+
+ return $status;
+ });
+
+ // Custom message for amount validation
+ Validator::replacer('amount', function($message, $attribute, $rule, $parameters) {
+ return trans('validation.custom.invalid_amount', ['attribute' => $attribute]);
+ });
+
+ // Check extension is valid
+ Validator::extend('extension', function ($attribute, $value, $parameters, $validator) {
+ $extension = $value->getClientOriginalExtension();
+
+ return !empty($extension) && in_array($extension, $parameters);
+ },
+ trans('validation.custom.invalid_extension')
+ );
+
+ // Check colour is valid
+ Validator::extend('colour', function ($attribute, $value, $parameters, $validator) {
+ $status = false;
+
+ $colors = ['gray', 'red', 'yellow', 'green', 'blue', 'indigo', 'purple', 'pink'];
+ $variants = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];
+
+ foreach ($colors as $color) {
+ if (! Str::contains($value, $color)) {
+ continue;
+ }
+
+ foreach ($variants as $variant) {
+ $name = $color . '-' . $variant;
+
+ if (Str::contains($value, $name)) {
+ $status = true;
+
+ break;
+ }
+ }
+
+ if ($status) {
+ break;
+ }
+ }
+
+ if (! $status && Str::contains($value, '#')) {
+ $status = true;
+ }
+
+ return $status;
+ },
+ trans('validation.custom.invalid_colour')
+ );
+
+ // Check payment method is valid
+ Validator::extend('payment_method', function ($attribute, $value, $parameters, $validator) {
+ $status = false;
+
+ $methods = Modules::getPaymentMethods('all');
+
+ if (array_key_exists($value, $methods)) {
+ $status = true;
+ }
+
+ return $status;
+ },
+ trans('validation.custom.invalid_payment_method')
+ );
+ }
+
+ /**
+ * Register any application services.
+ *
+ * @return void
+ */
+ public function register()
+ {
+ //
+ }
+}
diff --git a/app/Providers/ViewComposer.php b/app/Providers/ViewComposer.php
new file mode 100644
index 00000000..7c6304d7
--- /dev/null
+++ b/app/Providers/ViewComposer.php
@@ -0,0 +1,55 @@
+getParentKey()) && $this->related instanceof Model) {
+ return $this->query->getWithoutChildren();
+ }
+
+ return ! is_null($this->getParentKey())
+ ? $this->query->get()
+ : $this->related->newCollection();
+ }
+}
diff --git a/app/Reports/DiscountSummary.php b/app/Reports/DiscountSummary.php
new file mode 100644
index 00000000..cdddf486
--- /dev/null
+++ b/app/Reports/DiscountSummary.php
@@ -0,0 +1,131 @@
+ [
+ 'bar' => [
+ 'colors' => [
+ '#8bb475',
+ ],
+ ],
+ 'donut' => [
+ //
+ ],
+ ],
+ 'expense' => [
+ 'bar' => [
+ 'colors' => [
+ '#fb7185',
+ ],
+ ],
+ 'donut' => [
+ //
+ ],
+ ],
+ ];
+
+ public function setTables()
+ {
+ $this->tables = [
+ 'income' => trans_choice('general.incomes', 1),
+ 'expense' => trans_choice('general.expenses', 2),
+ ];
+ }
+
+ public function setData()
+ {
+ $invoices = $this->applyFilters(
+ model: Document::invoice()->with('totals')->accrued(),
+ args: ['date_field' => 'issued_at', 'model_type' => 'invoice'],
+ )->get();
+ Recurring::reflect($invoices, 'issued_at');
+ $this->setTotals($invoices, 'issued_at', false, 'income');
+
+ // Bills
+ $bills = $this->applyFilters(
+ model: Document::bill()->with('totals')->accrued(),
+ args: ['date_field' => 'issued_at', 'model_type' => 'bill'],
+ )->get();
+ Recurring::reflect($bills, 'issued_at');
+ $this->setTotals($bills, 'issued_at', false, 'expense');
+ }
+
+ public function setTotals($items, $date_field, $check_type = false, $table = 'default', $with_tax = true)
+ {
+ event(new TotalCalculating($this, $items, $date_field, $check_type, $table, $with_tax));
+
+ $group_field = $this->getGroup() . '_id';
+
+ foreach ($items as $item) {
+ // Make groups extensible
+ $item = $this->applyGroups($item);
+
+ $date = $this->getFormattedDate(Date::parse($item->$date_field));
+
+ if (!isset($item->$group_field)) {
+ continue;
+ }
+
+ $group = $item->$group_field;
+
+ $totals = $item->totals;
+
+ foreach ($totals as $total) {
+ if (! in_array($total->code, ['item_discount', 'discount'])) {
+ continue;
+ }
+
+ if (
+ !isset($this->row_values[$table][$group])
+ || !isset($this->row_values[$table][$group][$date])
+ || !isset($this->footer_totals[$table][$date])
+ ) {
+ continue;
+ }
+
+ $amount = $this->convertToDefault($total->amount, $item->currency_code, $item->currency_rate);
+
+ $type = ($item->type === Document::INVOICE_TYPE || $item->type === 'income') ? 'income' : 'expense';
+
+ if (($check_type == false) || ($type == 'income')) {
+ $this->row_values[$table][$group][$date] += $amount;
+
+ $this->footer_totals[$table][$date] += $amount;
+ } else {
+ $this->row_values[$table][$group][$date] -= $amount;
+
+ $this->footer_totals[$table][$date] -= $amount;
+ }
+ }
+ }
+
+ event(new TotalCalculated($this, $items, $date_field, $check_type, $table, $with_tax));
+ }
+
+ public function getFields()
+ {
+ return [
+ $this->getGroupField(),
+ $this->getPeriodField(),
+ ];
+ }
+}
diff --git a/app/Reports/ExpenseSummary.php b/app/Reports/ExpenseSummary.php
new file mode 100644
index 00000000..574518f9
--- /dev/null
+++ b/app/Reports/ExpenseSummary.php
@@ -0,0 +1,67 @@
+ [
+ 'colors' => [
+ '#fb7185',
+ ],
+ ],
+ 'donut' => [
+ //
+ ],
+ ];
+
+ public function setTables()
+ {
+ $this->tables = [
+ 'expense' => trans_choice('general.expenses', 2),
+ ];
+ }
+
+ public function setData()
+ {
+ $transactions = $this->applyFilters(
+ model: Transaction::with('recurring')->expense()->isNotTransfer(),
+ args: ['date_field' => 'paid_at', 'model_type' => 'expense'],
+ );
+
+ switch ($this->getBasis()) {
+ case 'cash':
+ // Expenses
+ $expenses = $transactions->get();
+ $this->setTotals($expenses, 'paid_at', false, 'expense');
+
+ break;
+ default:
+ // Bills
+ $bills = $this->applyFilters(
+ model: Document::bill()->with('recurring', 'transactions', 'items')->accrued(),
+ args: ['date_field' => 'issued_at', 'model_type' => 'bill'],
+ )->get();
+ Recurring::reflect($bills, 'issued_at');
+ $this->setTotals($this->flattenDocumentItems($bills), 'issued_at', false, 'expense');
+
+ // Expenses
+ $expenses = $transactions->isNotDocument()->get();
+ Recurring::reflect($expenses, 'paid_at');
+ $this->setTotals($expenses, 'paid_at', false, 'expense');
+
+ break;
+ }
+ }
+}
diff --git a/app/Reports/IncomeExpenseSummary.php b/app/Reports/IncomeExpenseSummary.php
new file mode 100644
index 00000000..e264259e
--- /dev/null
+++ b/app/Reports/IncomeExpenseSummary.php
@@ -0,0 +1,101 @@
+ [
+ 'bar' => [
+ 'colors' => [
+ '#8bb475',
+ ],
+ ],
+ 'donut' => [
+ //
+ ],
+ ],
+ 'expense' => [
+ 'bar' => [
+ 'colors' => [
+ '#fb7185',
+ ],
+ ],
+ 'donut' => [
+ //
+ ],
+ ],
+ ];
+
+ public function setTables()
+ {
+ $this->tables = [
+ 'income' => trans_choice('general.incomes', 1),
+ 'expense' => trans_choice('general.expenses', 2),
+ ];
+ }
+
+ public function setData()
+ {
+ $income_transactions = $this->applyFilters(
+ model: Transaction::with('recurring')->income()->isNotTransfer(),
+ args: ['date_field' => 'paid_at', 'model_type' => 'income'],
+ );
+ $expense_transactions = $this->applyFilters(
+ model: Transaction::with('recurring')->expense()->isNotTransfer(),
+ args: ['date_field' => 'paid_at', 'model_type' => 'expense'],
+ );
+
+ switch ($this->getBasis()) {
+ case 'cash':
+ // Incomes
+ $incomes = $income_transactions->get();
+ $this->setTotals($incomes, 'paid_at', false, 'income');
+
+ // Expenses
+ $expenses = $expense_transactions->get();
+ $this->setTotals($expenses, 'paid_at', false, 'expense');
+
+ break;
+ default:
+ // Invoices
+ $invoices = $this->applyFilters(
+ model: Document::invoice()->with('recurring', 'transactions', 'items')->accrued(),
+ args: ['date_field' => 'issued_at', 'model_type' => 'invoice'],
+ )->get();
+ Recurring::reflect($invoices, 'issued_at');
+ $this->setTotals($this->flattenDocumentItems($invoices), 'issued_at', false, 'income');
+
+ // Incomes
+ $incomes = $income_transactions->isNotDocument()->get();
+ Recurring::reflect($incomes, 'paid_at');
+ $this->setTotals($incomes, 'paid_at', false, 'income');
+
+ // Bills
+ $bills = $this->applyFilters(
+ model: Document::bill()->with('recurring', 'transactions', 'items')->accrued(),
+ args: ['date_field' => 'issued_at', 'model_type' => 'bill'],
+ )->get();
+ Recurring::reflect($bills, 'issued_at');
+ $this->setTotals($this->flattenDocumentItems($bills), 'issued_at', false, 'expense');
+
+ // Expenses
+ $expenses = $expense_transactions->isNotDocument()->get();
+ Recurring::reflect($expenses, 'paid_at');
+ $this->setTotals($expenses, 'paid_at', false, 'expense');
+
+ break;
+ }
+ }
+}
diff --git a/app/Reports/IncomeSummary.php b/app/Reports/IncomeSummary.php
new file mode 100644
index 00000000..2280a94e
--- /dev/null
+++ b/app/Reports/IncomeSummary.php
@@ -0,0 +1,67 @@
+ [
+ 'colors' => [
+ '#8bb475',
+ ],
+ ],
+ 'donut' => [
+ //
+ ],
+ ];
+
+ public function setTables()
+ {
+ $this->tables = [
+ 'income' => trans_choice('general.incomes', 1),
+ ];
+ }
+
+ public function setData()
+ {
+ $transactions = $this->applyFilters(
+ model: Transaction::with('recurring')->income()->isNotTransfer(),
+ args: ['date_field' => 'paid_at', 'model_type' => 'income'],
+ );
+
+ switch ($this->getBasis()) {
+ case 'cash':
+ // Incomes
+ $incomes = $transactions->get();
+ $this->setTotals($incomes, 'paid_at', false, 'income');
+
+ break;
+ default:
+ // Invoices
+ $invoices = $this->applyFilters(
+ model: Document::invoice()->with('recurring', 'transactions', 'items')->accrued(),
+ args: ['date_field' => 'issued_at', 'model_type' => 'invoice'],
+ )->get();
+ Recurring::reflect($invoices, 'issued_at');
+ $this->setTotals($this->flattenDocumentItems($invoices), 'issued_at', false, 'income');
+
+ // Incomes
+ $incomes = $transactions->isNotDocument()->get();
+ Recurring::reflect($incomes, 'paid_at');
+ $this->setTotals($incomes, 'paid_at', false, 'income');
+
+ break;
+ }
+ }
+}
diff --git a/app/Reports/ProfitLoss.php b/app/Reports/ProfitLoss.php
new file mode 100644
index 00000000..dcad8d53
--- /dev/null
+++ b/app/Reports/ProfitLoss.php
@@ -0,0 +1,316 @@
+views['detail'] = 'reports.profit_loss.detail';
+ $this->views['detail.content.header'] = 'reports.profit_loss.content.header';
+ $this->views['detail.content.footer'] = 'reports.profit_loss.content.footer';
+ $this->views['detail.table.header'] = 'reports.profit_loss.table.header';
+ $this->views['detail.table.row'] = 'reports.profit_loss.table.row';
+ $this->views['detail.table.footer'] = 'reports.profit_loss.table.footer';
+ }
+
+ public function setTables()
+ {
+ $this->tables = [
+ Category::INCOME_TYPE => trans_choice('general.incomes', 1),
+ Category::DIRECT_COST_TYPE => trans_choice('general.cogs', 2),
+ Category::EXPENSE_TYPE => trans_choice('general.expenses', 2),
+ ];
+ }
+
+ public function setData()
+ {
+ switch ($this->getBasis()) {
+ case 'cash':
+ $incomes_query = $this->getTransactionQuery(Transaction::INCOME_TYPE);
+ $expenses_query = $this->getTransactionQuery(Transaction::EXPENSE_TYPE);
+
+ // Incomes
+ $incomes = $incomes_query->get();
+ $this->setTotals($incomes, 'paid_at', false, Category::INCOME_TYPE, false);
+
+ // Direct Costs: Expenses
+ $direct_costs_expenses_query = clone $expenses_query; // To avoid affecting the original query used for non-Direct Costs expenses
+ $direct_costs_expenses = $direct_costs_expenses_query->whereHas('category', fn (Builder $q) => $q->directCost())->get();
+ $this->setTotals($direct_costs_expenses, 'paid_at', false, Category::DIRECT_COST_TYPE, false);
+
+ // Expenses
+ $expenses = $expenses_query->whereDoesntHave('category', fn (Builder $q) => $q->directCost())->get();
+ $this->setTotals($expenses, 'paid_at', false, Category::EXPENSE_TYPE, false);
+
+ break;
+ default:
+ $incomes_query = $this->getTransactionQuery(Transaction::INCOME_TYPE);
+ $expenses_query = $this->getTransactionQuery(Transaction::EXPENSE_TYPE);
+ $invoices_query = $this->getDocumentQuery(Document::INVOICE_TYPE);
+ $bills_query = $this->getDocumentQuery(Document::BILL_TYPE);
+
+ // Invoices
+ $invoices = $invoices_query->get();
+ Recurring::reflect($invoices, 'issued_at');
+ $this->setTotals(
+ items: $this->flattenDocumentItems($invoices),
+ date_field: 'issued_at',
+ check_type: false,
+ table: Category::INCOME_TYPE,
+ with_tax: false,
+ );
+
+ // Incomes
+ $incomes = $incomes_query->isNotDocument()->get();
+ Recurring::reflect($incomes, 'paid_at');
+ $this->setTotals($incomes, 'paid_at', false, Category::INCOME_TYPE, false);
+
+ // Bills: Direct Costs & Expenses
+ $bills = $bills_query->get();
+ Recurring::reflect($bills, 'issued_at');
+ $flat_bill_items = $this->flattenDocumentItems($bills);
+ $this->setTotals(
+ items: $flat_bill_items->filter(fn (DocumentItem $i) => $i->category?->isDirectCostCategory()),
+ date_field: 'issued_at',
+ check_type: false,
+ table: Category::DIRECT_COST_TYPE,
+ with_tax: false,
+ );
+ $this->setTotals(
+ items: $flat_bill_items->filter(fn (DocumentItem $i) => ! $i->category?->isDirectCostCategory()),
+ date_field: 'issued_at',
+ check_type: false,
+ table: Category::EXPENSE_TYPE,
+ with_tax: false,
+ );
+
+ // Direct Costs: Expenses
+ $direct_costs_expenses_query = clone $expenses_query; // To avoid affecting the original query used for non-Direct Costs expenses
+ $direct_costs_expenses = $direct_costs_expenses_query->whereHas('category', fn (Builder $q) => $q->directCost())->get();
+ Recurring::reflect($direct_costs_expenses, 'paid_at');
+ $this->setTotals($direct_costs_expenses, 'paid_at', false, Category::DIRECT_COST_TYPE, false);
+
+ // Expenses
+ $expenses = $expenses_query->whereDoesntHave('category', fn (Builder $q) => $q->directCost())->get();
+ Recurring::reflect($expenses, 'paid_at');
+ $this->setTotals($expenses, 'paid_at', false, Category::EXPENSE_TYPE, false);
+
+ break;
+ }
+
+ $this->setGrossProfit();
+ $this->setNetProfit();
+ }
+
+ public function getTransactionQuery(string $type): Builder
+ {
+ return $this->applyFilters(
+ model: Transaction::with('recurring')->$type()->isNotTransfer(),
+ args: ['date_field' => 'paid_at', 'model_type' => $type],
+ );
+ }
+
+ public function getDocumentQuery(string $type): Builder
+ {
+ return $this->applyFilters(
+ model: Document::with('recurring', 'totals', 'transactions', 'items.category')->$type()->accrued(),
+ args: ['date_field' => 'issued_at', 'model_type' => $type],
+ );
+ }
+
+ public function setGrossProfit(): void
+ {
+ foreach ($this->dates as $date) {
+ $income = $this->footer_totals[Category::INCOME_TYPE][$date] ?? 0;
+ $direct_costs = $this->footer_totals[Category::DIRECT_COST_TYPE][$date] ?? 0;
+
+ $this->gross_profit[$date] = $income - $direct_costs;
+ }
+ }
+
+ public function setNetProfit(): void
+ {
+ foreach ($this->footer_totals as $table => $dates) {
+ if (! in_array($table, [Category::INCOME_TYPE, Category::EXPENSE_TYPE])) {
+ continue;
+ }
+
+ foreach ($dates as $date => $total) {
+ if (! isset($this->net_profit[$date])) {
+ $this->net_profit[$date] = 0;
+ }
+
+ if ($table == Category::INCOME_TYPE) {
+ $this->net_profit[$date] += $total;
+
+ continue;
+ }
+
+ $this->net_profit[$date] -= $total;
+ }
+ }
+ }
+
+ public function array(): array
+ {
+ $data = parent::array();
+
+ $net_profit = $this->net_profit;
+ $gross_profit = $this->gross_profit;
+
+ if ($this->has_money) {
+ $net_profit = array_map(fn ($value) => money($value)->format(), $net_profit);
+ $gross_profit = array_map(fn ($value) => money($value)->format(), $gross_profit);
+ }
+
+ $data['gross_profit'] = $gross_profit;
+ $data['net_profit'] = $net_profit;
+
+ return $data;
+ }
+
+ public function getFields(): array
+ {
+ return [
+ $this->getGroupField(),
+ $this->getPeriodField(),
+ $this->getBasisField(),
+ $this->getPercentageField(),
+ ];
+ }
+
+ public function getPercentageField(): array
+ {
+ return [
+ 'type' => 'select',
+ 'name' => 'show_percentage',
+ 'title' => trans('reports.percentage_of_income'),
+ 'icon' => 'percent',
+ 'values' => [
+ 'yes' => trans('general.yes'),
+ 'no' => trans('general.no'),
+ ],
+ 'selected' => 'no',
+ 'attributes' => [
+ 'required' => 'required',
+ ],
+ ];
+ }
+
+ public function showPercentage(): bool
+ {
+ return $this->getSearchStringValue('show_percentage', $this->getSetting('show_percentage')) === 'yes';
+ }
+
+ public function getPercentageOfIncome(string $date, float|int $cell_value): ?string
+ {
+ if (! $this->showPercentage()) {
+ return null;
+ }
+
+ $income_total = $this->footer_totals['income'][$date] ?? 0;
+
+ if ($income_total == 0) {
+ return null;
+ }
+
+ $pct = round($cell_value / $income_total * 100, 1);
+
+ return setting('localisation.percent_position') == 'after'
+ ? $pct . '%'
+ : '%' . $pct;
+ }
+
+ public function getDrillDownUrl(string $date, int|string $id): string
+ {
+ [$date_start, $date_end] = $this->getDateRangeForDrillDown($date);
+
+ $group = $this->getGroup();
+
+ // category_id:519 paid_at>=2026-03-01 paid_at<=2026-03-29
+ $search = implode(
+ separator: ' ',
+ array: [
+ "{$group}_id:{$id}",
+ "paid_at>={$date_start}",
+ "paid_at<={$date_end}",
+ ],
+ );
+
+ return route('transactions.index') . '?list_records=all&search=' . $search;
+ }
+
+ private function getDateRangeForDrillDown(string $date): array
+ {
+ switch ($this->getPeriod()) {
+ case 'yearly':
+ $range = [
+ trim($date) . '-01-01',
+ trim($date) . '-12-31',
+ ];
+
+ break;
+ case 'quarterly':
+ [$d_start, $d_end] = array_map('trim', explode(' - ', $date, 2));
+
+ $range = [
+ Date::createFromFormat('M Y', $d_start)->startOfMonth()->format('Y-m-d'),
+ Date::createFromFormat('M Y', $d_end)->endOfMonth()->format('Y-m-d'),
+ ];
+
+ break;
+ case 'weekly':
+ [$d_start, $d_end] = array_map('trim', explode(' - ', $date, 2));
+
+ $range = [
+ Date::createFromFormat('d M Y', $d_start)->startOfDay()->format('Y-m-d'),
+ Date::createFromFormat('d M Y', $d_end)->endOfDay()->format('Y-m-d'),
+ ];
+
+ break;
+ default: // monthly
+ $range = [
+ Date::createFromFormat('M Y', $date)->startOfMonth()->format('Y-m-d'),
+ Date::createFromFormat('M Y', $date)->endOfMonth()->format('Y-m-d'),
+ ];
+
+ break;
+ }
+
+ // Clamp to report's start_date/end_date if present
+ $report_start = request('start_date');
+ $report_end = request('end_date');
+
+ if ($report_start && $report_end) {
+ $range[0] = max($range[0], $report_start);
+ $range[1] = min($range[1], $report_end);
+ }
+
+ return $range;
+ }
+}
diff --git a/app/Reports/TaxSummary.php b/app/Reports/TaxSummary.php
new file mode 100644
index 00000000..aa463704
--- /dev/null
+++ b/app/Reports/TaxSummary.php
@@ -0,0 +1,227 @@
+views['detail.content.header'] = 'reports.tax_summary.content.header';
+ $this->views['detail.content.footer'] = 'reports.tax_summary.content.footer';
+ $this->views['detail.table.header'] = 'reports.tax_summary.table.header';
+ $this->views['detail.table.footer'] = 'reports.tax_summary.table.footer';
+ }
+
+ public function setTables()
+ {
+ $withholding = ($this->getSetting('withholding') == 'yes') ? 'withholding' : 'notWithholding';
+
+ $taxes = Tax::enabled()->$withholding()->notRate(0)->orderBy('name')->pluck('name')->toArray();
+
+ $this->tables = array_combine($taxes, $taxes);
+ }
+
+ public function setData()
+ {
+ switch ($this->getBasis()) {
+ case 'cash':
+ // Invoice Payments
+ $invoices = $this->applyFilters(
+ model: Transaction::with('recurring', 'invoice', 'invoice.totals')->income()->isDocument()->isNotTransfer(),
+ args: ['date_field' => 'paid_at', 'model_type' => 'income'],
+ )->get();
+ $this->setTotals($invoices, 'paid_at');
+
+ // Bill Payments
+ $bills = $this->applyFilters(
+ model: Transaction::with('recurring', 'bill', 'bill.totals')->expense()->isDocument()->isNotTransfer(),
+ args: ['date_field' => 'paid_at', 'model_type' => 'expense'],
+ )->get();
+ $this->setTotals($bills, 'paid_at');
+
+ break;
+ default:
+ // Invoices
+ $invoices = $this->applyFilters(
+ model: Document::invoice()->with('recurring', 'totals', 'transactions', 'items')->accrued(),
+ args: ['date_field' => 'issued_at', 'model_type' => 'invoice'],
+ )->get();
+ Recurring::reflect($invoices, 'issued_at');
+ $this->setTotals($invoices, 'issued_at');
+
+ // Bills
+ $bills = $this->applyFilters(
+ model: Document::bill()->with('recurring', 'totals', 'transactions', 'items')->accrued(),
+ args: ['date_field' => 'issued_at', 'model_type' => 'bill'],
+ )->get();
+ Recurring::reflect($bills, 'issued_at');
+ $this->setTotals($bills, 'issued_at');
+
+ break;
+ }
+
+ // Incomes
+ $incomes = $this->applyFilters(
+ model: Transaction::with('taxes')->income()->isNotDocument()->isNotTransfer(),
+ args: ['date_field' => 'paid_at', 'model_type' => 'income'],
+ )->get();
+ $this->setTotals($incomes, 'paid_at');
+
+ // Expenses
+ $expenses = $this->applyFilters(
+ model: Transaction::with('taxes')->expense()->isNotDocument()->isNotTransfer(),
+ args: ['date_field' => 'paid_at', 'model_type' => 'expense'],
+ )->get();
+ $this->setTotals($expenses, 'paid_at');
+ }
+
+ public function setTotals($items, $date_field, $check_type = false, $table = 'default', $with_tax = true)
+ {
+ foreach ($items as $item) {
+ // Make groups extensible
+ $item = $this->applyGroups($item);
+
+ $type = ($item->type === Document::INVOICE_TYPE || $item->type === 'income') ? 'income' : 'expense';
+
+ if ($item instanceof Transaction && empty($item->document_id)) {
+ $this->setTransactionTaxTotal($item, $type, $date_field);
+ continue;
+ }
+
+ $date = $this->getFormattedDate(Date::parse($item->$date_field));
+
+ if ($date_field == 'paid_at') {
+ $document_type = ($item->type == 'income') ? 'invoice' : 'bill';
+ $item_totals = $item->$document_type->totals;
+ $type_item = $item->$document_type;
+ } else {
+ $item_totals = $item->totals;
+ }
+
+ foreach ($item_totals as $item_total) {
+ if ($item_total->code != 'tax') {
+ continue;
+ }
+
+ $item_total_name = $item_total->name;
+
+ if (
+ !isset($this->row_values[$item_total_name][$type][$date])
+ || !isset($this->footer_totals[$item_total_name][$date])
+ ) {
+ $item_total_name = Str::lcfirst($item_total_name); // #Clickup@86c3nzq4r
+
+ if (!isset($this->row_values[$item_total_name][$type][$date])
+ || !isset($this->footer_totals[$item_total_name][$date])
+ ) {
+ continue;
+ }
+ }
+
+ if ($date_field == 'paid_at') {
+ if ($type_item->amount != 0) {
+ $rate = ($item->amount * 100) / $type_item->amount;
+ $item_amount = ($item_total->amount / 100) * $rate;
+ } else {
+ $item_amount = $item_total->amount;
+ }
+ } else {
+ $item_amount = $item_total->amount;
+ }
+
+ $amount = $this->convertToDefault($item_amount, $item->currency_code, $item->currency_rate);
+
+ if ($type == 'income') {
+ $this->row_values[$item_total_name][$type][$date] += $amount;
+
+ $this->footer_totals[$item_total_name][$date] += $amount;
+ } else {
+ $this->row_values[$item_total_name][$type][$date] -= $amount;
+
+ $this->footer_totals[$item_total_name][$date] -= $amount;
+ }
+ }
+ }
+ }
+
+ public function setTransactionTaxTotal($item, $type, $date_field)
+ {
+ if (empty($item->taxes)) {
+ return;
+ }
+
+ $date = $this->getFormattedDate(Date::parse($item->$date_field));
+
+ foreach ($item->taxes as $tax) {
+ if (
+ !isset($this->row_values[$tax->name][$type][$date])
+ || !isset($this->footer_totals[$tax->name][$date])
+ ) {
+ continue;
+ }
+
+ $amount = $this->convertToDefault($tax->amount, $item->currency_code, $item->currency_rate);
+
+ if ($type == 'income') {
+ $this->row_values[$tax->name][$type][$date] += $amount;
+
+ $this->footer_totals[$tax->name][$date] += $amount;
+ } else {
+ $this->row_values[$tax->name][$type][$date] -= $amount;
+
+ $this->footer_totals[$tax->name][$date] -= $amount;
+ }
+ }
+ }
+
+ public function getFields()
+ {
+ return [
+ $this->getPeriodField(),
+ $this->getBasisField(),
+ $this->getWithholdingField(),
+ ];
+ }
+
+ public function getWithholdingField()
+ {
+ return [
+ 'type' => 'selectGroup',
+ 'name' => 'withholding',
+ 'title' => trans('taxes.withholding'),
+ 'icon' => 'hand-holding-usd',
+ 'values' => [
+ 'yes' => trans('general.yes'),
+ 'no' => trans('general.no'),
+ ],
+ 'selected' => 'no',
+ 'attributes' => [
+ 'required' => 'required',
+ ],
+ ];
+ }
+}
diff --git a/app/Scopes/Category.php b/app/Scopes/Category.php
new file mode 100644
index 00000000..c9e7ae61
--- /dev/null
+++ b/app/Scopes/Category.php
@@ -0,0 +1,26 @@
+expectsJson()) {
+ return;
+ }*/
+
+ $builder->whereNull('parent_id');
+ }
+}
diff --git a/app/Scopes/Company.php b/app/Scopes/Company.php
new file mode 100644
index 00000000..592ec4c9
--- /dev/null
+++ b/app/Scopes/Company.php
@@ -0,0 +1,51 @@
+isNotTenantable()) {
+ return;
+ }
+
+ $table = $model->getTable();
+
+ // Skip for specific tables
+ // Note: 'notifications' is excluded because Laravel's notification system
+ // links to users (not companies). Queries against notifications should always
+ // be scoped to the authenticated user (e.g. auth()->user()->notifications)
+ // to avoid cross-company data exposure.
+ $skip_tables = [
+ 'jobs', 'firewall_ips', 'firewall_logs', 'migrations', 'notifications', 'role_companies',
+ 'role_permissions', 'sessions', 'user_companies', 'user_dashboards', 'user_permissions', 'user_roles',
+ ];
+
+ if (in_array($table, $skip_tables)) {
+ return;
+ }
+
+ // Skip if already exists
+ if ($this->scopeColumnExists($builder, '', 'company_id')) {
+ return;
+ }
+
+ // Apply company scope
+ $builder->where($table . '.company_id', '=', company_id());
+ }
+}
diff --git a/app/Scopes/Contact.php b/app/Scopes/Contact.php
new file mode 100644
index 00000000..a8f6eb05
--- /dev/null
+++ b/app/Scopes/Contact.php
@@ -0,0 +1,28 @@
+applyNotRecurringScope($builder, $model);
+ }
+}
diff --git a/app/Scopes/Transaction.php b/app/Scopes/Transaction.php
new file mode 100644
index 00000000..0fea4970
--- /dev/null
+++ b/app/Scopes/Transaction.php
@@ -0,0 +1,27 @@
+applyNotRecurringScope($builder, $model);
+
+ $this->applyNotSplitScope($builder, $model);
+ }
+}
diff --git a/app/Traits/Categories.php b/app/Traits/Categories.php
new file mode 100644
index 00000000..734b0e04
--- /dev/null
+++ b/app/Traits/Categories.php
@@ -0,0 +1,342 @@
+type ?? $this->category->type ?? $this->model->type ?? Category::INCOME_TYPE;
+
+ return in_array($type, $this->getIncomeCategoryTypes());
+ }
+
+ public function isExpenseCategory(): bool
+ {
+ $type = $this->type ?? $this->category->type ?? $this->model->type ?? Category::EXPENSE_TYPE;
+
+ return in_array($type, $this->getExpenseCategoryTypes());
+ }
+
+ public function isDirectCostCategory(): bool
+ {
+ $type = $this->type ?? $this->category->type ?? $this->model->type ?? Category::DIRECT_COST_TYPE;
+
+ return in_array($type, $this->getDirectCostCategoryTypes());
+ }
+
+ public function isItemCategory(): bool
+ {
+ $type = $this->type ?? $this->category->type ?? $this->model->type ?? Category::ITEM_TYPE;
+
+ return in_array($type, $this->getItemCategoryTypes());
+ }
+
+ public function isOtherCategory(): bool
+ {
+ $type = $this->type ?? $this->category->type ?? $this->model->type ?? Category::OTHER_TYPE;
+
+ return in_array($type, $this->getOtherCategoryTypes());
+ }
+
+ public function getTypeCategoryTypes(string $type, string $return = 'array'): string|array
+ {
+ switch ($type) {
+ case Category::INCOME_TYPE:
+ $types = $this->getIncomeCategoryTypes($return);
+ break;
+ case Category::EXPENSE_TYPE:
+ $types = $this->getExpenseAndDirectCostCategoryTypes($return);
+ break;
+ case Category::DIRECT_COST_TYPE:
+ $types = $this->getDirectCostCategoryTypes($return);
+ break;
+ case Category::ITEM_TYPE:
+ $types = $this->getItemCategoryTypes($return);
+ break;
+ case Category::OTHER_TYPE:
+ $types = $this->getOtherCategoryTypes($return);
+ break;
+ default:
+ $types = ($return == 'array') ? [$type] : $type;
+ }
+
+ return $types;
+ }
+
+ public function getIncomeCategoryTypes(string $return = 'array'): string|array
+ {
+ return $this->getCategoryTypesByIndex(Category::INCOME_TYPE, $return);
+ }
+
+ public function getExpenseCategoryTypes(string $return = 'array'): string|array
+ {
+ return $this->getCategoryTypesByIndex(Category::EXPENSE_TYPE, $return);
+ }
+
+ public function getDirectCostCategoryTypes(string $return = 'array'): string|array
+ {
+ return $this->getCategoryTypesByIndex(Category::DIRECT_COST_TYPE, $return);
+ }
+
+ public function getExpenseAndDirectCostCategoryTypes(string $return = 'array'): string|array
+ {
+ $types = array_merge($this->getExpenseCategoryTypes(), $this->getDirectCostCategoryTypes());
+
+ return ($return == 'array') ? $types : implode(',', $types);
+ }
+
+ public function getItemCategoryTypes(string $return = 'array'): string|array
+ {
+ return $this->getCategoryTypesByIndex(Category::ITEM_TYPE, $return);
+ }
+
+ public function getOtherCategoryTypes(string $return = 'array'): string|array
+ {
+ return $this->getCategoryTypesByIndex(Category::OTHER_TYPE, $return);
+ }
+
+ public function getCategoryTypesByIndex(string $index, string $return = 'array'): string|array
+ {
+ $types = (string) setting('category.type.' . $index);
+
+ return ($return == 'array') ? explode(',', $types) : $types;
+ }
+
+ public function addIncomeCategoryType(string $new_type): void
+ {
+ $this->addCategoryType($new_type, Category::INCOME_TYPE);
+ }
+
+ public function addExpenseCategoryType(string $new_type): void
+ {
+ $this->addCategoryType($new_type, Category::EXPENSE_TYPE);
+ }
+
+ public function addDirectCostCategoryType(string $new_type): void
+ {
+ $this->addCategoryType($new_type, Category::DIRECT_COST_TYPE);
+ }
+
+ public function addItemCategoryType(string $new_type): void
+ {
+ $this->addCategoryType($new_type, Category::ITEM_TYPE);
+ }
+
+ public function addOtherCategoryType(string $new_type): void
+ {
+ $this->addCategoryType($new_type, Category::OTHER_TYPE);
+ }
+
+ public function addCategoryType(string $new_type, string $index): void
+ {
+ $types = !empty(setting('category.type.' . $index)) ? explode(',', setting('category.type.' . $index)) : [];
+
+ if (in_array($new_type, $types)) {
+ return;
+ }
+
+ $types[] = $new_type;
+
+ setting([
+ 'category.type.' . $index => implode(',', $types),
+ ])->save();
+ }
+
+ public function isGroupCategoryType(): bool
+ {
+ $setting_category_types = setting('category.type');
+
+ foreach ($setting_category_types as $type => $category) {
+ $categories = explode(',', $category);
+
+ if (count($categories) > 1) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function hideCodeCategoryType(string $type, bool $default = true): bool
+ {
+ return $this->hideCodeCategoryTypes($type)[$type] ?? $default;
+ }
+
+ public function hideCodeCategoryTypes(string|array $types): array
+ {
+ $types = is_string($types) ? explode(',', $types) : $types;
+
+ $type_codes = [];
+
+ foreach ($types as $type) {
+ $config_type = config('type.category.' . $type, []);
+
+ $type_codes[$type] = ! empty($config_type['hide']) && in_array('code', $config_type['hide']) ? true : false;
+ }
+
+ return $type_codes;
+ }
+
+ public function getCategoryTypes(bool $translate = true, bool $group = false, array $types = []): array
+ {
+ $category_types = [];
+
+ $configs = empty($types) ? config('type.category') : array_intersect_key(config('type.category'), array_flip($types));
+
+ foreach ($configs as $type => $attr) {
+ if (! is_array($attr)) {
+ continue;
+ }
+
+ if (is_callable($attr['translation']['type'] ?? null)) {
+ $name = $attr['translation']['type']();
+ } else {
+ $plural_type = Str::plural($type);
+
+ $name = $attr['translation']['prefix'] . '.' . $plural_type;
+
+ if (!empty($attr['alias'])) {
+ $name = $attr['alias'] . '::' . $name;
+ }
+
+ $name = $translate ? trans_choice($name, 1) : $name;
+ }
+
+ if ($group) {
+ $group_value = $attr['group'] ?? $type;
+
+ if (is_callable($attr['translation']['group'] ?? null)) {
+ $group_value = $attr['translation']['group']();
+ }
+
+ $category_types[$group_value][$type] = $name;
+ } else {
+ $category_types[$type] = $name;
+ }
+ }
+
+ return $category_types;
+ }
+
+ public function getCategoryTypeLabel(string $type, int $count = 1): string
+ {
+ $config = config('type.category.' . $type, []);
+
+ if (empty($config)) {
+ return $type;
+ }
+
+ if (is_callable($config['translation']['type'] ?? null)) {
+ $name = $config['translation']['type']();
+ } else {
+ $group = $config['group'] ?? $type;
+ $plural_type = $count === 1 ? Str::plural($group, 1) : Str::plural($group);
+ $name = ($config['translation']['prefix'] ?? 'general') . '.' . $plural_type;
+
+ if (! empty($config['alias'])) {
+ $name = $config['alias'] . '::' . $name;
+ }
+ }
+
+ return trans_choice($name, $count);
+ }
+
+ public function getCategoryTabs(): array
+ {
+ $tabs = [];
+ $configs = config('type.category');
+
+ foreach ($configs as $type => $attr) {
+ if (! is_array($attr)) {
+ continue;
+ }
+
+ $tab_key = 'categories-' . ($attr['group'] ?? $type);
+
+ if (isset($tabs[$tab_key])) {
+ $tabs[$tab_key]['key'] .= ',' . $type;
+ continue;
+ }
+
+ if (! empty($attr['translation']['group'])) {
+ if (is_callable($attr['translation']['group'])) {
+ $name = $attr['translation']['group']();
+ } elseif (is_array($attr['translation']['group'])) {
+ $name = trans_choice($attr['translation']['group'][0], $attr['translation']['group'][1]);
+ } else {
+ $name = trans($attr['translation']['group']);
+ }
+ } else {
+ $plural_type = Str::plural($attr['group'] ?? $type);
+
+ $name = $attr['translation']['prefix'] . '.' . $plural_type;
+
+ if (! empty($attr['alias'])) {
+ $name = $attr['alias'] . '::' . $name;
+ }
+
+ $name = trans_choice($name, 2);
+ }
+
+ $tabs[$tab_key] = [
+ 'key' => $type,
+ 'name' => $name,
+ 'show_code' => $attr['show_code'] ?? false,
+ ];
+ }
+
+ return $tabs;
+ }
+
+ public function getCategoryWithoutChildren(int $id): mixed
+ {
+ return Category::getWithoutChildren()->find($id);
+ }
+
+ public function getTransferCategoryId(): mixed
+ {
+ // 1 hour set cache for same query
+ return Cache::remember('transferCategoryId.' . company_id(), 60, function () {
+ return Category::other()->pluck('id')->first();
+ });
+ }
+
+ public function isTransferCategory(): bool
+ {
+ $id = $this->id ?? $this->category->id ?? $this->model->id ?? 0;
+
+ return $id == $this->getTransferCategoryId();
+ }
+
+ public function getChildrenCategoryIds($category)
+ {
+ $ids = [];
+
+ foreach ($category->sub_categories as $sub_category) {
+ $ids[] = $sub_category->id;
+
+ if ($sub_category->sub_categories) {
+ $ids = array_merge($ids, $this->getChildrenCategoryIds($sub_category));
+ }
+ }
+
+ return $ids;
+ }
+
+ /**
+ * Finds existing maximum code and increase it
+ *
+ * @return mixed
+ */
+ public function getNextCategoryCode()
+ {
+ return Category::isNotSubCategory()->get(['code'])->reject(function ($category) {
+ return !preg_match('/^[0-9]*$/', $category->code);
+ })->max('code') + 1;
+ }
+}
diff --git a/app/Traits/Charts.php b/app/Traits/Charts.php
new file mode 100644
index 00000000..77e71282
--- /dev/null
+++ b/app/Traits/Charts.php
@@ -0,0 +1,235 @@
+ [],
+ 'labels' => [],
+ 'values' => [],
+ ];
+
+ public $donut = [
+ 'colors' => [],
+ 'labels' => [],
+ 'values' => [],
+ ];
+
+ public function addToDonutChart($color, $label, $value)
+ {
+ $this->donut['colors'][] = $color;
+ $this->donut['labels'][] = $label;
+ $this->donut['values'][] = (int) $value;
+ }
+
+ public function addMoneyToDonutChart($color, $amount, $description = '')
+ {
+ $label = money($amount)->formatForHumans();
+
+ if (!empty($description)) {
+ $label .= ' - ' . $description;
+ }
+
+ $this->addToDonutChart($color, $label, $amount);
+ }
+
+ public function getDonutChart($name, $width = '100%', $height = 300, $limit = 10)
+ {
+ // Show donut prorated if there is no value
+ if (array_sum($this->donut['values']) == 0) {
+ foreach ($this->donut['values'] as $key => $value) {
+ $this->donut['values'][$key] = 1;
+ }
+ }
+
+ // Get 6 categories by amount
+ $colors = $labels = [];
+ $values = collect($this->donut['values'])->sort()->reverse()->take($limit)->all();
+
+ foreach ($values as $id => $val) {
+ $colors[$id] = $this->donut['colors'][$id];
+ $labels[$id] = $this->donut['labels'][$id];
+ }
+
+ $chart = new Chart();
+
+ $chart->setType('donut')
+ ->setWidth($width)
+ ->setHeight($height)
+ ->setDefaultLocale($this->getDefaultLocaleOfChart())
+ ->setLocales($this->getLocaleTranslationOfChart())
+ ->setLabels(array_values($labels))
+ ->setColors(array_values($colors))
+ ->setDataset($name, 'donut', array_values($values));
+
+ return $chart;
+ }
+
+ public function addToBarChart($color, $label, $value)
+ {
+ $this->bar['colors'][] = $color;
+ $this->bar['labels'][] = $label;
+ $this->bar['values'][] = (int) $value;
+ }
+
+ public function getBarChart($name, $width = '100%', $height = 160)
+ {
+ $chart = new Chart();
+
+ $chart->setType('bar')
+ ->setWidth($width)
+ ->setHeight($height)
+ ->setDefaultLocale($this->getDefaultLocaleOfChart())
+ ->setLocales($this->getLocaleTranslationOfChart())
+ ->setLabels(array_values($this->bar['labels']))
+ ->setColors($this->bar['colors']);
+
+ foreach ($this->bar['values'] as $key => $value) {
+ $chart->setDataset($this->bar['labels'][$key], 'bar', $value);
+ }
+
+ return $chart;
+ }
+
+ public function getChartLabelFormatter($type = 'money', $position = null)
+ {
+ $label = '';
+ $decimal_mark = str_replace("'", "\\'", currency()->getDecimalMark());
+ $thousands_separator = str_replace("'", "\\'", currency()->getThousandsSeparator());
+ $symbol = str_replace("'", "\\'", currency()->getSymbol());
+ $symbol_first = str_replace("'", "\\'", currency()->isSymbolFirst());
+ $precision = str_replace("'", "\\'", currency()->getPrecision());
+ $percent_position = $position ?: setting('localisation.percent_position');
+
+ switch ($type) {
+ case 'integer':
+ $label = new Raw("function(value) {
+ return value
+ }");
+ break;
+ case 'percent':
+ $label = new Raw("function(value) {
+ " . ($percent_position == 'right' ? "return value + '%';" : "return '%' + value;") . "
+ }");
+ break;
+ default:
+ $label = new Raw("function(value) {
+ const moneySettings = {
+ decimal: '" . $decimal_mark . "',
+ thousands: '". $thousands_separator . "',
+ symbol: '" . $symbol . "',
+ isPrefix: '" . $symbol_first . "',
+ precision: '" . $precision . "',
+ };
+
+ const formattedCurrency = function (input, opt = moneySettings) {
+ if (typeof input === 'number') {
+ input = input.toFixed(fixed(opt.precision))
+ }
+
+ function fixed (precision) {
+ return Math.max(0, Math.min(precision, 20));
+ };
+
+ function toStr(value) {
+ return value ? value.toString() : '';
+ };
+
+ function numbersToCurrency(numbers, precision) {
+ var exp = Math.pow(10, precision);
+ var float = parseFloat(numbers) / exp;
+
+ return float.toFixed(fixed(precision));
+ };
+
+ function joinIntegerAndDecimal (integer, decimal, separator) {
+ return decimal ? integer + separator + decimal : integer;
+ };
+
+ if (typeof input === 'number') {
+ input = input.toFixed(fixed(opt.precision));
+ };
+
+ var negative = input.indexOf('-') >= 0 ? '-' : '';
+ var numbers = toStr(input).replace(/\D+/g, '') || '0';
+ var currency = numbersToCurrency(numbers, opt.precision);
+ var parts = toStr(currency).split('.');
+ var integer = parts[0].replace(/(\d)(?=(?:\d{3})+\b)/gm, ('$1' + opt.thousands));
+ var decimal = parts[1];
+
+ if (opt.isPrefix == 1) {
+ return opt.symbol + negative + joinIntegerAndDecimal(integer, decimal, opt.decimal);
+ }
+
+ return negative + joinIntegerAndDecimal(integer, decimal, opt.decimal) + opt.symbol;
+ };
+
+ return formattedCurrency(value, moneySettings);
+ }");
+ }
+
+ return $label;
+ }
+
+ public function getDefaultLocaleOfChart(): string
+ {
+ $default = 'en';
+
+ $short = language()->getShortCode();
+ $long = language()->getLongCode();
+
+ $short_path = public_path('vendor/apexcharts/locales/' . $short . '.json');
+ $long_path = public_path('vendor/apexcharts/locales/' . $long . '.json');
+
+ if (is_file($short_path)) {
+ return $short;
+ }
+
+ if (is_file($long_path)) {
+ return $long;
+ }
+
+ return $default;
+ }
+
+ public function getLocaleTranslationOfChart(?string $locale = null): array
+ {
+ $translations = [];
+
+ $user_locale = $locale ?: $this->getDefaultLocaleOfChart();
+
+ $locales = ($user_locale == 'en') ? [$user_locale] : [$user_locale, 'en'];
+
+ foreach ($locales as $loc) {
+ $translations[] = json_decode(
+ file_get_contents(
+ public_path('vendor/apexcharts/locales/' . $loc . '.json')
+ )
+ );
+ }
+
+ return $translations;
+ }
+
+ // @deprecated version 3.0.0
+ public function addToDonut($color, $label, $value)
+ {
+ $this->addToDonutChart($color, $label, $value);
+ }
+
+ // @deprecated version 3.0.0
+ public function addMoneyToDonut($color, $amount, $description = '')
+ {
+ $this->addMoneyToDonutChart($color, $amount, $description);
+ }
+
+ // @deprecated version 3.0.0
+ public function addToBar($color, $label, $value)
+ {
+ $this->addToBarChart($color, $label, $value);
+ }
+}
diff --git a/app/Traits/Cloud.php b/app/Traits/Cloud.php
new file mode 100644
index 00000000..ea839b76
--- /dev/null
+++ b/app/Traits/Cloud.php
@@ -0,0 +1,47 @@
+moduleIsEnabled('roles')) {
+ return route('roles.roles.index');
+ }
+
+ return route('apps.app.show', [
+ 'alias' => 'roles',
+ 'utm_source' => $location,
+ 'utm_medium' => 'app',
+ 'utm_campaign' => 'roles',
+ ]);
+ }
+
+ public function getCloudBankFeedsUrl($location = 'widget')
+ {
+ if ($this->moduleIsEnabled('bank-feeds')) {
+ return route('bank-feeds.bank-connections.index');
+ }
+
+ return route('apps.app.show', [
+ 'alias' => 'bank-feeds',
+ 'utm_source' => $location,
+ 'utm_medium' => 'app',
+ 'utm_campaign' => 'bank_feeds',
+ ]);
+ }
+
+ public function isCloud()
+ {
+ if (config('app.offline')) {
+ return false;
+ }
+
+ return request()->getHost() == config('cloud.host', 'app.akaunting.com');
+ }
+}
diff --git a/app/Traits/Companies.php b/app/Traits/Companies.php
new file mode 100644
index 00000000..dc593102
--- /dev/null
+++ b/app/Traits/Companies.php
@@ -0,0 +1,208 @@
+request ?: request();
+
+ if (request_is_api($request)) {
+ return $this->getCompanyIdFromApi($request);
+ }
+
+ if (request_is_mcp($request)) {
+ return $this->getCompanyIdFromMcp($request);
+ }
+
+ return $this->getCompanyIdFromWeb($request);
+ }
+
+ public function getCompanyIdFromWeb($request): ?int
+ {
+ return $this->getCompanyIdFromRoute($request) ?: ($this->getCompanyIdFromQuery($request) ?: $this->getCompanyIdFromHeader($request));
+ }
+
+ public function getCompanyIdFromApi($request): ?int
+ {
+ // Priority 0: OAuth token — when the request carries a Bearer token, the token's company_id is the authoritative source.
+ // This ensures an OAuth client can only access the company the token was issued for, regardless of URL or headers.
+ if (config('oauth.enabled', false) && $request->bearerToken()) {
+ $company_id = $this->getCompanyIdFromToken($request);
+
+ if ($company_id) {
+ return $company_id;
+ }
+ }
+
+ // Priority 1: Query string (?company_id=2)
+ $company_id = $this->getCompanyIdFromQuery($request);
+
+ // Priority 2: Header (X-Company: 2)
+ if (! $company_id) {
+ $company_id = $this->getCompanyIdFromHeader($request);
+ }
+
+ // Priority 3: First company of the user (fallback)
+ if (! $company_id) {
+ $company_id = $this->getFirstCompanyOfUser()?->id;
+ }
+
+ return $company_id;
+ }
+
+ public function getCompanyIdFromMcp($request): ?int
+ {
+ // Priority 0: OAuth Token (must be first since it doesn't rely on session or route)
+ $company_id = $this->getCompanyIdFromToken($request);
+
+ // Priority 1: Query string (?company_id=2)
+ if (! $company_id) {
+ $company_id = $this->getCompanyIdFromQuery($request);
+ }
+
+ // Priority 2: Header (X-Company: 2)
+ if (! $company_id) {
+ $company_id = $this->getCompanyIdFromHeader($request);
+ }
+
+ // Priority 3: First company of the user (fallback)
+ if (! $company_id) {
+ $user = null;
+
+ try {
+ $user = auth()->guard('passport')->user();
+ } catch (\Throwable $e) {
+ logger()->debug('OAuth: Passport guard unavailable during MCP company resolution', [
+ 'error' => $e->getMessage(),
+ ]);
+ }
+
+ if (! $user) {
+ $user = auth()->user();
+ }
+
+ if (! $user) {
+ logger()->debug('OAuth: No authenticated user found when trying to get first company');
+
+ return null;
+ }
+
+ $company = $user->withoutEvents(fn () => $user->companies()->enabled()->first());
+
+ $company_id = $company?->id;
+ }
+
+ return $company_id;
+ }
+
+ /**
+ * Get company ID from OAuth access token.
+ *
+ * When a user is authenticated via OAuth (Passport), extract the company_id
+ * that was assigned to the token during authorization approval.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @return int|null
+ */
+ protected function getCompanyIdFromToken($request): ?int
+ {
+ // Check if OAuth is enabled and user is authenticated via Passport
+ if (! config('oauth.enabled')) {
+ logger()->debug('OAuth: Disabled, skipping token company_id extraction');
+
+ return null;
+ }
+
+ try {
+ // Try passport guard first
+ if (auth()->guard('passport')->check()) {
+ $user = auth()->guard('passport')->user();
+
+ if ($user && method_exists($user, 'token')) {
+ $token = $user->token();
+
+ if ($token && isset($token->company_id) && $token->company_id) {
+ logger()->debug('OAuth: Extracted company_id from token', [
+ 'company_id' => $token->company_id,
+ 'user_id' => $user->id,
+ ]);
+
+ return (int) $token->company_id;
+ }
+
+ // Token exists but no company_id stored — use the passport user's first company
+ logger()->debug('OAuth: No company_id on token, falling back to passport user\'s first company');
+ $company = $user->withoutEvents(fn () => $user->companies()->enabled()->first());
+ if ($company) {
+ return (int) $company->id;
+ }
+
+ logger()->debug('OAuth: No companies found for authenticated passport user');
+ }
+
+ logger()->debug('OAuth: No company_id found on authenticated user\'s token');
+ }
+
+ // Fallback: Try to get token from request directly
+ if ($request->bearerToken()) {
+ $tokenId = $request->bearerToken();
+
+ // Try to find the token in database
+ $tokenModel = config('oauth.company_aware', true)
+ ? \Modules\Oauth\Models\AccessToken::withoutGlobalScope('company')->where('id', $tokenId)->first()
+ : null;
+
+ if ($tokenModel && isset($tokenModel->company_id)) {
+ logger()->debug('OAuth: Extracted company_id from token model', [
+ 'company_id' => $tokenModel->company_id,
+ 'token_id' => $tokenModel->id,
+ ]);
+
+ return (int) $tokenModel->company_id;
+ }
+
+ logger()->debug('OAuth: No company_id found on token model for bearer token');
+ }
+ } catch (\Exception $e) {
+ // Silently fail if OAuth token checking fails
+ // This allows fallback to other methods
+ logger()->debug('OAuth: company_id extraction failed', [
+ 'error' => $e->getMessage(),
+ ]);
+ }
+
+ logger()->debug('OAuth: No company_id found in token');
+
+ return null;
+ }
+
+ public function getCompanyIdFromRoute($request): ?int
+ {
+ $route_id = (int) $request->route('company_id');
+ $segment_id = (int) $request->segment(1);
+
+ return $route_id ?: $segment_id;
+ }
+
+ public function getCompanyIdFromQuery($request): ?int
+ {
+ return (int) $request->query('company_id');
+ }
+
+ public function getCompanyIdFromHeader($request): ?int
+ {
+ return (int) $request->header('X-Company');
+ }
+}
diff --git a/app/Traits/Contacts.php b/app/Traits/Contacts.php
new file mode 100644
index 00000000..06cb108c
--- /dev/null
+++ b/app/Traits/Contacts.php
@@ -0,0 +1,103 @@
+type ?? $this->contact->type ?? $this->model->type ?? 'customer';
+
+ return in_array($type, $this->getCustomerTypes());
+ }
+
+ public function isVendor()
+ {
+ $type = $this->type ?? $this->contact->type ?? $this->model->type ?? 'vendor';
+
+ return in_array($type, $this->getVendorTypes());
+ }
+
+ public function isEmployee()
+ {
+ $type = $this->type ?? $this->contact->type ?? $this->model->type ?? 'employee';
+
+ return in_array($type, $this->getEmployeeTypes());
+ }
+
+ public function getCustomerTypes($return = 'array')
+ {
+ return $this->getContactTypes('customer', $return);
+ }
+
+ public function getVendorTypes($return = 'array')
+ {
+ return $this->getContactTypes('vendor', $return);
+ }
+
+ public function getEmployeeTypes($return = 'array')
+ {
+ return $this->getContactTypes('employee', $return);
+ }
+
+ public function getContactTypes($index, $return = 'array')
+ {
+ $types = (string) setting('contact.type.' . $index);
+
+ return ($return == 'array') ? explode(',', $types) : $types;
+ }
+
+ public function addCustomerType($new_type)
+ {
+ $this->addContactType($new_type, 'customer');
+ }
+
+ public function addVendorType($new_type)
+ {
+ $this->addContactType($new_type, 'vendor');
+ }
+
+ public function addEmployeeType($new_type)
+ {
+ $this->addContactType($new_type, 'employee');
+ }
+
+ public function addContactType($new_type, $index)
+ {
+ $types = explode(',', setting('contact.type.' . $index));
+
+ if (in_array($new_type, $types)) {
+ return;
+ }
+
+ $types[] = $new_type;
+
+ setting([
+ 'contact.type.' . $index => implode(',', $types),
+ ])->save();
+ }
+
+ public function getFormattedAddress($city = null, $country = null, $state = null, $zip_code = null)
+ {
+ if (is_null($city)
+ && is_null($country)
+ && is_null($state)
+ && is_null($zip_code)
+ ) {
+ return null;
+ }
+
+ $address_format = (string) setting('default.address_format');
+
+ // Keep formatted address as plain text. Views convert line breaks to
safely.
+ $address_format = str_ireplace(['
', '
', '
'], "\n", $address_format);
+
+ $formatted_address = str_replace(
+ ["{city}", "{country}", "{state}", "{zip_code}", "\n"],
+ [$city, $country, $state, $zip_code, "\n"],
+ $address_format
+ );
+
+ return $formatted_address;
+ }
+}
diff --git a/app/Traits/Currencies.php b/app/Traits/Currencies.php
new file mode 100644
index 00000000..d84aec71
--- /dev/null
+++ b/app/Traits/Currencies.php
@@ -0,0 +1,85 @@
+format() : $money->getAmount();
+ }
+
+ try {
+ $money = $money->$method((double) $rate);
+ } catch (\Throwable $e) {
+ report($e);
+
+ return 0;
+ }
+
+ return $format ? $money->format() : $money->getAmount();
+ }
+
+ public function convertToDefault($amount, $from, $rate, $format = false, $default = null)
+ {
+ $default_currency = $default ?? $this->getDefaultCurrency();
+
+ return $this->convert('divide', $amount, $from, $default_currency, $rate, $format);
+ }
+
+ public function convertFromDefault($amount, $to, $rate, $format = false, $default = null)
+ {
+ $default_currency = $default ?? $this->getDefaultCurrency();
+
+ return $this->convert('multiply', $amount, $default_currency, $to, $rate, $format);
+ }
+
+ public function convertBetween($amount, $from_code, $from_rate, $to_code, $to_rate)
+ {
+ $default_amount = $amount;
+
+ if ($from_code != default_currency()) {
+ $default_amount = $this->convertToDefault($amount, $from_code, $from_rate);
+ }
+
+ $converted_amount = $this->convertFromDefault($default_amount, $to_code, $to_rate);
+
+ return $converted_amount;
+ }
+
+ public function getAmountConvertedToDefault($format = false, $with_tax = true)
+ {
+ return $this->convertToDefault($this->getAmount($with_tax), $this->currency_code, $this->currency_rate, $format);
+ }
+
+ public function getAmountConvertedFromDefault($format = false, $with_tax = true)
+ {
+ return $this->convertFromDefault($this->getAmount($with_tax), $this->currency_code, $this->currency_rate, $format);
+ }
+
+ public function getAmount($with_tax = true)
+ {
+ return $with_tax ? $this->amount : (isset($this->amount_without_tax) ? $this->amount_without_tax : $this->amount);
+ }
+
+ public function getDefaultCurrency()
+ {
+ return !empty($this->default_currency_code) ? $this->default_currency_code : default_currency();
+ }
+
+ public function setDefaultCurrency($code)
+ {
+ $this->default_currency_code = $code;
+ }
+
+ public function unsetDefaultCurrency()
+ {
+ unset($this->default_currency_code);
+ }
+}
diff --git a/app/Traits/Database.php b/app/Traits/Database.php
new file mode 100644
index 00000000..f193323f
--- /dev/null
+++ b/app/Traits/Database.php
@@ -0,0 +1,13 @@
+ '-', 'slash' => '/', 'dot' => '.', 'comma' => ',', 'space' => ' '];
+
+ $date_format = setting('localisation.date_format', $default) ?? $default;
+
+ $char = setting('localisation.date_separator', 'space') ?? 'space';
+ $date_separator = $chars[$char];
+
+ return str_replace(' ', $date_separator, $date_format);
+ }
+
+ public function scopeDateFilter($query, string $field)
+ {
+ [$start, $end] = $this->getStartAndEndDates();
+
+ return $query->whereBetween($field, [$start->toDateTimeString(), $end->toDateTimeString()]);
+ }
+
+ public function getStartAndEndDates($year = null): array
+ {
+ if (request()->filled('start_date') && request()->filled('end_date')) {
+ $start = Date::parse(request('start_date'))->startOfDay();
+ $end = Date::parse(request('end_date'))->endOfDay();
+ } else {
+ $financial_year = $this->getFinancialYear($year);
+
+ $start = $financial_year->copy()->getStartDate()->startOfDay();
+ $end = $financial_year->copy()->getEndDate()->endOfDay();
+ }
+
+ return [$start, $end];
+ }
+
+ public function getFinancialStart($year = null, $date = null): Date
+ {
+ $start_of_year = Date::now()->startOfYear();
+
+ $setting = explode('-', setting('localisation.financial_start'));
+
+ $day = ! empty($setting[0]) ? $setting[0] : $start_of_year->day;
+ $month = ! empty($setting[1]) ? $setting[1] : $start_of_year->month;
+ $year = $year ?? $start_of_year->year;
+
+ $financial_start = Date::create($year, $month, $day);
+ if ((setting('localisation.financial_denote') == 'ends') && ($financial_start->dayOfYear != 1) ||
+ $financial_start->greaterThan($date ?? Date::now())
+ ) {
+ $financial_start->subYear();
+ }
+
+ return $financial_start;
+ }
+
+ public function getFinancialWeek($year = null, $date = null): CarbonPeriod
+ {
+ $today = Date::today();
+ $financial_weeks = $this->getFinancialWeeks($year, $date);
+
+ foreach ($financial_weeks as $week) {
+ if ($today->lessThan($week->getStartDate()) || $today->greaterThan($week->getEndDate())) {
+ continue;
+ }
+
+ $this_week = $week;
+
+ break;
+ }
+
+ if (! isset($this_week)) {
+ $this_week = $financial_weeks[0];
+ }
+
+ return $this_week;
+ }
+
+ public function getFinancialMonth($year = null, $date = null): CarbonPeriod
+ {
+ $today = Date::today();
+ $financial_months = $this->getFinancialMonths($year, $date);
+
+ foreach ($financial_months as $month) {
+ if ($today->lessThan($month->getStartDate()) || $today->greaterThan($month->getEndDate())) {
+ continue;
+ }
+
+ $this_month = $month;
+
+ break;
+ }
+
+ if (! isset($this_month)) {
+ $this_month = $financial_months[0];
+ }
+
+ return $this_month;
+ }
+
+ public function getFinancialQuarter($year = null, $date = null): CarbonPeriod
+ {
+ $today = Date::today();
+ $financial_quarters = $this->getFinancialQuarters($year, $date);
+
+ foreach ($financial_quarters as $quarter) {
+ if ($today->lessThan($quarter->getStartDate()) || $today->greaterThan($quarter->getEndDate())) {
+ continue;
+ }
+
+ $this_quarter = $quarter;
+
+ break;
+ }
+
+ if (! isset($this_quarter)) {
+ $this_quarter = $financial_quarters[0];
+ }
+
+ return $this_quarter;
+ }
+
+ public function getFinancialYear($year = null, $date = null): CarbonPeriod
+ {
+ $financial_start = $this->getFinancialStart($year, $date);
+
+ return CarbonPeriod::create($financial_start, $financial_start->copy()->addYear()->subDay()->endOfDay());
+ }
+
+ public function getFinancialWeeks($year = null, $date = null): array
+ {
+ $weeks = [];
+
+ $start = $this->getFinancialStart($year, $date);
+
+ $w = 52;
+
+ if (request()->filled('start_date') && request()->filled('end_date')) {
+ $w = Date::parse($start->copy())->diffInWeeks(Date::parse(request('end_date'))) + 1;
+ }
+
+ for ($i = 0; $i < $w; $i++) {
+ $weeks[] = CarbonPeriod::create($start->copy()->addWeeks($i), $start->copy()->addWeeks($i + 1)->subDay()->endOfDay());
+ }
+
+ return $weeks;
+ }
+
+ public function getFinancialMonths($year = null, $date = null): array
+ {
+ $months = [];
+
+ $start = $this->getFinancialStart($year, $date);
+
+ $m = 12;
+
+ if (request()->filled('start_date') && request()->filled('end_date')) {
+ $m = Date::parse($start->copy())->diffInMonths(Date::parse(request('end_date'))) + 1;
+ }
+
+ for ($i = 0; $i < $m; $i++) {
+ $months[] = CarbonPeriod::create($start->copy()->addMonths($i), $start->copy()->addMonths($i + 1)->subDay()->endOfDay());
+ }
+
+ return $months;
+ }
+
+ public function getFinancialQuarters($year = null, $date = null): array
+ {
+ $quarters = [];
+
+ $start = $this->getFinancialStart($year, $date);
+
+ $q = 4;
+
+ /*
+ Previously, diffInQuarters was calculated from start_date, which caused errors
+ when the financial start value differed from the default value.
+ Therefore, this change has been made. Ticket: #8106
+ */
+ if (request()->filled('start_date') && request()->filled('end_date')) {
+ $q = Date::parse($start->copy())->diffInQuarters(Date::parse(request('end_date'))) + 1;
+ }
+
+ for ($i = 0; $i < $q; $i++) {
+ $quarters[] = CarbonPeriod::create($start->copy()->addQuarters($i), $start->copy()->addQuarters($i + 1)->subDay()->endOfDay());
+ }
+
+ return $quarters;
+ }
+
+ public function getDatePickerShortcuts(): array
+ {
+ $today = Date::today();
+ $financial_week = $this->getFinancialWeek();
+ $financial_month = $this->getFinancialMonth();
+ $financial_quarter = $this->getFinancialQuarter();
+ $financial_year = $this->getFinancialYear();
+
+ $date_picker_shortcuts = [
+ trans('general.date_range.this_week') => [
+ 'start' => $financial_week->copy()->getStartDate()->toDateString(),
+ 'end' => $financial_week->copy()->getEndDate()->toDateString(),
+ ],
+ trans('general.date_range.this_month') => [
+ 'start' => $financial_month->copy()->getStartDate()->toDateString(),
+ 'end' => $financial_month->copy()->getEndDate()->toDateString(),
+ ],
+ trans('general.date_range.this_quarter') => [
+ 'start' => $financial_quarter->copy()->getStartDate()->toDateString(),
+ 'end' => $financial_quarter->copy()->getEndDate()->toDateString(),
+ ],
+ trans('general.date_range.this_year') => [
+ 'start' => $financial_year->copy()->getStartDate()->toDateString(),
+ 'end' => $financial_year->copy()->getEndDate()->toDateString(),
+ ],
+ trans('general.date_range.year_to_date') => [
+ 'start' => $financial_year->copy()->getStartDate()->toDateString(),
+ 'end' => $today->copy()->toDateString(),
+ ],
+ trans('general.date_range.previous_week') => [
+ 'start' => $financial_week->copy()->getStartDate()->subWeek()->toDateString(),
+ 'end' => $financial_week->copy()->getEndDate()->subWeek()->toDateString(),
+ ],
+ trans('general.date_range.previous_month') => [
+ 'start' => $financial_month->copy()->getStartDate()->subMonth()->toDateString(),
+ 'end' => $financial_month->copy()->getEndDate()->subMonth()->endOfMonth()->toDateString(),
+ ],
+ trans('general.date_range.previous_quarter') => [
+ 'start' => $financial_quarter->copy()->getStartDate()->subQuarter()->toDateString(),
+ 'end' => $financial_quarter->copy()->getEndDate()->subQuarter()->toDateString(),
+ ],
+ trans('general.date_range.previous_year') => [
+ 'start' => $financial_year->copy()->getStartDate()->subYear()->toDateString(),
+ 'end' => $financial_year->copy()->getEndDate()->subYear()->toDateString(),
+ ],
+ ];
+
+ return $date_picker_shortcuts;
+ }
+
+ public function getDailyDateFormat(): string
+ {
+ return 'd M Y';
+ }
+
+ public function getWeeklyDateFormat(): string
+ {
+ return 'W - M Y';
+ }
+
+ public function getMonthlyDateFormat(): string
+ {
+ return 'M Y';
+ }
+
+ public function getQuarterlyDateFormat(): string
+ {
+ return 'M Y';
+ }
+
+ public function getYearlyDateFormat(): string
+ {
+ return 'Y';
+ }
+
+ public function getPeriodicDate(Date $date, string $period, string $year): string
+ {
+ $formatted_date = '';
+
+ switch ($period) {
+ case 'yearly':
+ $financial_year = $this->getFinancialYear($year, $date);
+
+ if ($date->greaterThanOrEqualTo($financial_year->getStartDate()) && $date->lessThanOrEqualTo($financial_year->getEndDate())) {
+ if (setting('localisation.financial_denote') == 'begins') {
+ $formatted_date = $financial_year->copy()->getStartDate()->format($this->getYearlyDateFormat());
+ } else {
+ $formatted_date = $financial_year->copy()->getEndDate()->format($this->getYearlyDateFormat());
+ }
+ }
+
+ break;
+ case 'quarterly':
+ $quarters = $this->getFinancialQuarters($year, $date);
+
+ foreach ($quarters as $quarter) {
+ if ($date->lessThan($quarter->getStartDate()) || $date->greaterThan($quarter->getEndDate())) {
+ continue;
+ }
+
+ $start = $quarter->copy()->getStartDate()->format($this->getQuarterlyDateFormat($year));
+ $end = $quarter->copy()->getEndDate()->format($this->getQuarterlyDateFormat($year));
+
+ $formatted_date = $start . ' - ' . $end;
+
+ break;
+ }
+
+ break;
+ case 'weekly':
+ $weeks = $this->getFinancialWeeks($year, $date);
+
+ foreach ($weeks as $week) {
+ if ($date->lessThan($week->getStartDate()) || $date->greaterThan($week->getEndDate())) {
+ continue;
+ }
+
+ $start = $week->copy()->getStartDate()->format($this->getDailyDateFormat($year));
+ $end = $week->copy()->getEndDate()->format($this->getDailyDateFormat($year));
+
+ $formatted_date = $start . ' - ' . $end;
+
+ break;
+ }
+
+ break;
+ default:
+ $formatted_date = $date->copy()->format($this->getMonthlyDateFormat($year));
+
+ break;
+ }
+
+ return $formatted_date;
+ }
+
+ public function getTimezones(): array
+ {
+ // The list of available timezone groups to use.
+ $use_zones = ['Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific'];
+
+ // Get the list of time zones from the server.
+ $zones = \DateTimeZone::listIdentifiers();
+
+ return collect($zones)
+ ->mapWithKeys(function ($timezone) use ($use_zones) {
+ if (! in_array(str($timezone)->before('/'), $use_zones)) {
+ return [];
+ }
+
+ return [$timezone => str($timezone)->after('/')->value()];
+ })
+ ->groupBy(function ($item, $key) {
+ return str($key)->before('/')->value();
+ }, preserveKeys: true)
+ ->toArray();
+ }
+
+ // @deprecated 3.1
+ public function scopeMonthsOfYear($query, string $field)
+ {
+ return $this->scopeDateFilter($query, $field);
+ }
+}
diff --git a/app/Traits/Documents.php b/app/Traits/Documents.php
new file mode 100644
index 00000000..21934977
--- /dev/null
+++ b/app/Traits/Documents.php
@@ -0,0 +1,316 @@
+type ?? $this->document->type ?? $this->model->type ?? 'invoice';
+
+ return Str::endsWith($type, '-recurring');
+ }
+
+ public function isNotRecurringDocument(): bool
+ {
+ return ! $this->isRecurringDocument();
+ }
+
+ public function getRecurringDocumentTypes() : array
+ {
+ $types = array_keys(config('type.document'));
+
+ $recurring_types = [];
+
+ foreach ($types as $type) {
+ if (Str::endsWith($type, '-recurring')) {
+ $recurring_types[] = $type;
+ }
+ }
+
+ return $recurring_types;
+ }
+
+ /**
+ * Deprecated. Use the DocumentNumber::getNextNumber() method instead.
+ *
+ * @deprecated This method is deprecated and will be removed in future versions.
+ */
+ public function getNextDocumentNumber(string $type): string
+ {
+ return app(DocumentNumber::class)->getNextNumber($type, null);
+ }
+
+ /**
+ * Deprecated. Use the DocumentNumber::increaseNextNumber() method instead.
+ *
+ * @deprecated This method is deprecated and will be removed in future versions.
+ */
+ public function increaseNextDocumentNumber(string $type): void
+ {
+ app(DocumentNumber::class)->increaseNextNumber($type, null);
+ }
+
+ public function getDocumentStatuses(string $type): Collection
+ {
+ $list = [
+ 'invoice' => [
+ 'draft',
+ 'sent',
+ 'viewed',
+ 'approved',
+ 'partial',
+ 'paid',
+ 'overdue',
+ 'unpaid',
+ 'cancelled',
+ ],
+ 'bill' => [
+ 'draft',
+ 'received',
+ 'partial',
+ 'paid',
+ 'overdue',
+ 'unpaid',
+ 'cancelled',
+ ],
+ ];
+
+ // @todo get dynamic path
+ //$trans_key = $this->getTextDocumentStatuses($type);
+ $trans_key = 'documents.statuses.';
+
+ $statuses = collect($list[$type])->each(function ($code) use ($type, $trans_key) {
+ $item = new \stdClass();
+ $item->code = $code;
+ $item->name = trans($trans_key . $code);
+
+ return $item;
+ });
+
+ return $statuses;
+ }
+
+ public function getDocumentStatusesForFuture()
+ {
+ return [
+ 'draft',
+ 'sent',
+ 'received',
+ 'viewed',
+ 'partial',
+ ];
+ }
+
+ public function getDocumentFileName(Document $document, string $separator = '-', string $extension = 'pdf'): string
+ {
+ return $this->getSafeDocumentNumber($document, $separator) . $separator . time() . '.' . $extension;
+ }
+
+ public function getSafeDocumentNumber(Document $document, string $separator = '-'): string
+ {
+ return Str::slug($document->document_number, $separator, language()->getShortCode());
+ }
+
+ protected function getTextDocumentStatuses($type)
+ {
+ $default_key = config('type.document.' . $type . '.translation.prefix') . '.statuses.';
+
+ $translation = DocumentComponent::getTextFromConfig($type, 'document_status', $default_key);
+
+ if (!empty($translation)) {
+ return $translation;
+ }
+
+ $alias = config('type.document.' . $type . '.alias');
+
+ if (!empty($alias)) {
+ $translation = $alias . '::' . config('type.document.' . $type . '.translation.prefix') . '.statuses';
+
+ if (is_array(trans($translation))) {
+ return $translation . '.';
+ }
+ }
+
+ return 'documents.statuses.';
+ }
+
+ // This function will be remoed in the future
+ protected function getSettingKey($type, $setting_key)
+ {
+ return $this->getDocumentSettingKey($type, $setting_key);
+ }
+
+ protected function getDocumentSettingKey($type, $setting_key)
+ {
+ $key = '';
+ $alias = config('type.document.' . $type . '.alias');
+
+ if (! empty($alias)) {
+ $key .= $alias . '.';
+ }
+
+ $prefix = config('type.document.' . $type . '.setting.prefix');
+
+ if (! empty($prefix)) {
+ $key .= $prefix . '.' . $setting_key;
+ } else {
+ $key .= $setting_key;
+ }
+
+ return $key;
+ }
+
+ public function storeDocumentPdfAndGetPath($document)
+ {
+ event(new \App\Events\Document\DocumentPrinting($document));
+
+ $view = view($document->template_path, ['invoice' => $document, 'document' => $document])->render();
+ $html = mb_convert_encoding($view, 'HTML-ENTITIES', 'UTF-8');
+
+ $pdf = app('dompdf.wrapper');
+ $pdf->loadHTML($html);
+
+ $file_name = $this->getDocumentFileName($document);
+
+ $pdf_path = get_storage_path('app/temp/' . $file_name);
+
+ // Save the PDF file into temp folder
+ $pdf->save($pdf_path);
+
+ return $pdf_path;
+ }
+
+ public function getTotalsForFutureDocuments($type = 'invoice', $documents = null)
+ {
+ $totals = [
+ 'overdue' => 0,
+ 'open' => 0,
+ 'draft' => 0,
+ ];
+
+ $today = Date::today()->toDateString();
+
+ // Eager load transactions with currency to prevent N+1 queries when calling getAmountConvertedToDefault()
+ $documents = $documents ?: Document::type($type)->with(['transactions', 'transactions.currency'])->future();
+
+ $documents->each(function ($document) use (&$totals, $today) {
+ if (! in_array($document->status, $this->getDocumentStatusesForFuture())) {
+ return;
+ }
+
+ $payments = 0;
+
+ if ($document->status == 'draft') {
+ $totals['draft'] += $document->getAmountConvertedToDefault();
+
+ return;
+ }
+
+ if ($document->status == 'partial') {
+ foreach ($document->transactions as $transaction) {
+ $payments += $transaction->getAmountConvertedToDefault();
+ }
+ }
+
+ // Check if the document is open or overdue
+ if ($document->due_at > $today) {
+ $totals['open'] += $document->getAmountConvertedToDefault() - $payments;
+ } else {
+ $totals['overdue'] += $document->getAmountConvertedToDefault() - $payments;
+ }
+ });
+
+ return $totals;
+ }
+
+ public function canNotifyTheContactOfDocument(Document $document): bool
+ {
+ $config = config('type.document.' . $document->type . '.notification');
+
+ if (! $config['notify_contact']) {
+ return false;
+ }
+
+ if (! $document->contact || ($document->contact->enabled == 0)) {
+ return false;
+ }
+
+ if (empty($document->contact_email)) {
+ return false;
+ }
+
+ // Check if ietf.org has MX records signaling a server with email capabilites
+ $validator = new EmailValidator();
+ $validations = new MultipleValidationWithAnd([
+ new RFCValidation(),
+ new DNSCheckValidation(),
+ ]);
+ if (! $validator->isValid($document->contact_email, $validations)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function getRealTypeOfDocument(string $type): string
+ {
+ $type = $this->getRealTypeOfRecurringDocument($type);
+
+ return $type;
+ }
+
+ public function getRealTypeOfRecurringDocument(string $recurring_type): string
+ {
+ return Str::replace('-recurring', '', $recurring_type);
+ }
+
+ public function getDocumentTemplates($type)
+ {
+ $templates = new \stdClass();
+ $templates->templates = collect();
+ $config_templates = config('type.document.' . $type . '.templates', [
+ [
+ 'id' => 'default',
+ 'name' => trans('settings.invoice.default'),
+ 'image' => asset('public/img/invoice_templates/default.png'),
+ 'template' => 'default',
+ ],
+ [
+ 'id' => 'classic',
+ 'name' => trans('settings.invoice.classic'),
+ 'image' => asset('public/img/invoice_templates/classic.png'),
+ 'template' => 'classic',
+ ],
+ [
+ 'id' => 'modern',
+ 'name' => trans('settings.invoice.modern'),
+ 'image' => asset('public/img/invoice_templates/modern.png'),
+ 'template' => 'modern',
+ ],
+ ]);
+
+ foreach ($config_templates as $config_template) {
+ $templates->templates->push($config_template);
+ }
+
+ event(new DocumentTemplates($type, $templates));
+
+ return $templates->templates;
+ }
+}
diff --git a/app/Traits/Emails.php b/app/Traits/Emails.php
new file mode 100644
index 00000000..fd30fe44
--- /dev/null
+++ b/app/Traits/Emails.php
@@ -0,0 +1,51 @@
+ null, $decay_per_month);
+
+ if ($can_send) {
+ // Check if the user has reached the limit of emails per minute
+ $key_per_minute = 'email-minute:' . user_id();
+ $limit_per_minute = config('app.throttles.email.minute');
+
+ $can_send = RateLimiter::attempt($key_per_minute, $limit_per_minute, fn() => null);
+ }
+
+ if ($can_send) {
+ $this->dispatch($job);
+
+ return [
+ 'success' => true,
+ 'error' => false,
+ 'data' => '',
+ 'message' => '',
+ ];
+ }
+
+ event(new TooManyEmailsSent(user_id()));
+
+ return [
+ 'success' => false,
+ 'error' => true,
+ 'data' => null,
+ 'message' => 'Too many emails sent!',
+ ];
+ }
+}
diff --git a/app/Traits/HasApiTokens.php b/app/Traits/HasApiTokens.php
new file mode 100644
index 00000000..fc8b5afb
--- /dev/null
+++ b/app/Traits/HasApiTokens.php
@@ -0,0 +1,83 @@
+hasMany(\Laravel\Passport\Passport::clientModel(), 'user_id');
+ }
+
+ /**
+ * Get all of the access tokens for the user.
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
+ public function tokens()
+ {
+ return $this->hasMany(\Laravel\Passport\Passport::tokenModel(), 'user_id')->orderBy('created_at', 'desc');
+ }
+
+ /**
+ * Get the current access token being used by the user.
+ *
+ * @return \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null
+ */
+ public function token()
+ {
+ return $this->accessToken;
+ }
+
+ /**
+ * Determine if the current API token has a given scope.
+ *
+ * @param string $scope
+ * @return bool
+ */
+ public function tokenCan($scope)
+ {
+ return $this->accessToken ? $this->accessToken->can($scope) : false;
+ }
+
+ /**
+ * Create a new personal access token for the user.
+ *
+ * @param string $name
+ * @param array $scopes
+ * @return \Laravel\Passport\PersonalAccessTokenResult
+ */
+ public function createToken($name, array $scopes = [])
+ {
+ return Container::getInstance()->make(\Laravel\Passport\PersonalAccessTokenFactory::class)->make(
+ $this->getKey(), $name, $scopes
+ );
+ }
+
+ /**
+ * Set the current access token for the user.
+ *
+ * @param \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null $accessToken
+ * @return $this
+ */
+ public function withAccessToken($accessToken)
+ {
+ $this->accessToken = $accessToken;
+
+ return $this;
+ }
+}
diff --git a/app/Traits/Import.php b/app/Traits/Import.php
new file mode 100644
index 00000000..bd71ff90
--- /dev/null
+++ b/app/Traits/Import.php
@@ -0,0 +1,583 @@
+getImportViewPath($group, $type);
+
+ // Get import blade variables
+ $path = $this->getImportPath($group, $type);
+ $title_type = $this->getImportTitleType($group, $type);
+ $sample_file = $this->getImportSampleFile($group, $type);
+ $form_params = $this->getImportFormParams($group, $type, $path, $route);
+ $document_link = $this->getImportDocumentLink($group, $type);
+
+ // Create the import view
+ $import = new \stdClass();
+ $import->view = $view;
+ $import->data = compact('group', 'type', 'route', 'path', 'title_type', 'sample_file', 'form_params', 'document_link');
+
+ event(new ImportViewCreating($import));
+
+ event(new ImportViewCreated($import));
+
+ return [
+ $import->view,
+ $import->data
+ ];
+ }
+
+ public function getAccountId($row)
+ {
+ $id = isset($row['account_id']) ? $row['account_id'] : null;
+
+ if (empty($id) && !empty($row['account_name'])) {
+ $id = $this->getAccountIdFromName($row);
+ }
+
+ if (empty($id) && !empty($row['account_number'])) {
+ $id = $this->getAccountIdFromNumber($row);
+ }
+
+ if (empty($id) && !empty($row['currency_code'])) {
+ $id = $this->getAccountIdFromCurrency($row);
+ }
+
+ return is_null($id) ? $id : (int) $id;
+ }
+
+ public function getCategoryId($row, $type = null)
+ {
+ $id = isset($row['category_id']) ? $row['category_id'] : null;
+
+ $type = !empty($type) ? $type : (!empty($row['type']) ? $row['type'] : Category::INCOME_TYPE);
+
+ if (empty($id) && !empty($row['category_name'])) {
+ $id = $this->getCategoryIdFromName($row, $type);
+ }
+
+ return is_null($id) ? $id : (int) $id;
+ }
+
+ public function getCategoryType($type)
+ {
+ return array_key_exists($type, config('type.category')) ? $type : Category::OTHER_TYPE;
+ }
+
+ public function getContactId($row, $type = null)
+ {
+ $id = isset($row['contact_id']) ? $row['contact_id'] : null;
+
+ $type = !empty($type) ? $type : (!empty($row['type']) ? (($row['type'] == Transaction::INCOME_TYPE) ? Contact::CUSTOMER_TYPE : Contact::VENDOR_TYPE) : Contact::CUSTOMER_TYPE);
+
+ if (empty($row['contact_id']) && !empty($row['contact_email'])) {
+ $id = $this->getContactIdFromEmail($row, $type);
+ }
+
+ if (empty($id) && !empty($row['contact_name'])) {
+ $id = $this->getContactIdFromName($row, $type);
+ }
+
+ return is_null($id) ? $id : (int) $id;
+ }
+
+ public function getCurrencyCode($row)
+ {
+ // Uploaded file may not include a currency_code column — fall back to the
+ // company default instead of crashing on an undefined array key.
+ if (empty($row['currency_code'])) {
+ return default_currency();
+ }
+
+ $currency = Currency::where('code', $row['currency_code'])->first();
+
+ if (!empty($currency)) {
+ return $currency->code;
+ }
+
+ try {
+ $data = [
+ 'company_id' => company_id(),
+ 'code' => $row['currency_code'],
+ 'name' => isset($row['currency_name']) ? $row['currency_name'] : currency($row['currency_code'])->getName(),
+ 'rate' => isset($row['currency_rate']) ? $row['currency_rate'] : 1,
+ 'symbol' => isset($row['currency_symbol']) ? $row['currency_symbol'] : currency($row['currency_code'])->getSymbol(),
+ 'precision' => isset($row['currency_precision']) ? $row['currency_precision'] : currency($row['currency_code'])->getPrecision(),
+ 'decimal_mark' => isset($row['currency_decimal_mark']) ? $row['currency_decimal_mark'] : currency($row['currency_code'])->getDecimalMark(),
+ 'thousands_separator' => isset($row['currency_thousands_separator']) ? $row['currency_thousands_separator'] : currency($row['currency_code'])->getThousandsSeparator(),
+ 'created_from' => !empty($row['created_from']) ? $row['created_from'] : $this->getSourcePrefix() . 'import',
+ 'created_by' => !empty($row['created_by']) ? $row['created_by'] : user()?->id,
+ ];
+ } catch (\OutOfBoundsException $e) {
+ return default_currency();
+ }
+
+ Validator::validate($data, (new CurrencyRequest)->rules());
+
+ $currency = $this->dispatch(new CreateCurrency($data));
+
+ return $currency->code;
+ }
+
+ public function getCreatedById($row)
+ {
+ if (empty($row['created_by'])) {
+ return $this->user?->id;
+ }
+
+ $user = user_model_class()::where('email', $row['created_by'])->first();
+
+ if (! empty($user)) {
+ return $user->id;
+ }
+
+ return $this->user->id;
+ }
+
+ public function getDocumentId($row)
+ {
+ $id = isset($row['document_id']) ? $row['document_id'] : null;
+
+ if (empty($id) && !empty($row['document_number'])) {
+ $id = Document::number($row['document_number'])->pluck('id')->first();
+ }
+
+ if (empty($id) && !empty($row['invoice_number'])) {
+ $id = Document::invoice()->number($row['invoice_number'])->pluck('id')->first();
+ }
+
+ if (empty($id) && !empty($row['bill_number'])) {
+ $id = Document::bill()->number($row['bill_number'])->pluck('id')->first();
+ }
+
+ if (empty($id) && !empty($row['invoice_bill_number'])) {
+ if ($row['type'] == Transaction::INCOME_TYPE) {
+ $id = Document::invoice()->number($row['invoice_bill_number'])->pluck('id')->first();
+ } else {
+ $id = Document::bill()->number($row['invoice_bill_number'])->pluck('id')->first();
+ }
+ }
+
+ return is_null($id) ? $id : (int) $id;
+ }
+
+ public function getParentId($row)
+ {
+ $id = isset($row['parent_id']) ? $row['parent_id'] : null;
+
+ if (empty($row['parent_number']) && empty($row['parent_name'])){
+ return null;
+ }
+
+ if (empty($id) && (!empty($row['document_number']) || !empty($row['invoice_number']) || !empty($row['bill_number']))) {
+ $id = Document::number($row['parent_number'])->pluck('id')->first();
+ }
+
+ if (empty($id) && isset($row['number'])) {
+ $id = Transaction::number($row['parent_number'])->pluck('id')->first();
+ }
+
+ if (empty($id) && isset($row['parent_name'])) {
+ $id = Category::type($row['type'])->withSubCategory()->where('name', $row['parent_name'])->pluck('id')->first();
+ }
+
+ return is_null($id) ? $id : (int) $id;
+ }
+
+ public function getPaymentMethod($row)
+ {
+ Modules::clearPaymentMethodsCache();
+
+ $methods = Modules::getPaymentMethods('all');
+
+ $payment_method = isset($row['payment_method']) ? $row['payment_method'] : null;
+
+ if (array_key_exists($payment_method, $methods)) {
+ return $payment_method;
+ }
+
+ if (module_is_enabled('offline-payments')) {
+ $offline_payment = $this->dispatch(new \Modules\OfflinePayments\Jobs\CreatePaymentMethod([
+ 'name' => $payment_method,
+ 'customer' => 1,
+ 'order' => count($methods) + 1,
+ 'description' => '',
+ ]));
+
+ $payment_method = $offline_payment['code'];
+ }
+
+ return $payment_method;
+ }
+
+ public function getItemId($row, $type = null)
+ {
+ $id = isset($row['item_id']) ? $row['item_id'] : null;
+
+ $type = !empty($type) ? $type : (!empty($row['item_type']) ? $row['item_type'] : 'product');
+
+ if (empty($id) && !empty($row['item_name'])) {
+ $id = $this->getItemIdFromName($row, $type);
+ }
+
+ return is_null($id) ? $id : (int) $id;
+ }
+
+ public function getTaxId($row)
+ {
+ $id = isset($row['tax_id']) ? $row['tax_id'] : null;
+
+ if (empty($id) && !empty($row['tax_name'])) {
+ $id = Tax::name($row['tax_name'])->pluck('id')->first();
+ }
+
+ if (empty($id) && !empty($row['tax_rate'])) {
+ $id = $this->getTaxIdFromRate($row);
+ }
+
+ return is_null($id) ? $id : (int) $id;
+ }
+
+ public function getAccountIdFromCurrency($row)
+ {
+ $account_id = Account::where('currency_code', $row['currency_code'])->pluck('id')->first();
+
+ if (!empty($account_id)) {
+ return $account_id;
+ }
+
+ $data = [
+ 'company_id' => company_id(),
+ 'type' => !empty($row['account_type']) ? $row['account_type'] : 'bank',
+ 'currency_code' => $row['currency_code'],
+ 'name' => !empty($row['account_name']) ? $row['account_name'] : $row['currency_code'],
+ 'number' => !empty($row['account_number']) ? $row['account_number'] : (string) rand(1, 10000),
+ 'opening_balance' => !empty($row['opening_balance']) ? $row['opening_balance'] : 0,
+ 'enabled' => 1,
+ 'created_from' => !empty($row['created_from']) ? $row['created_from'] : $this->getSourcePrefix() . 'import',
+ 'created_by' => !empty($row['created_by']) ? $row['created_by'] : user()?->id,
+ ];
+
+ Validator::validate($data, (new AccountRequest)->rules());
+
+ $account = $this->dispatch(new CreateAccount($data));
+
+ return $account->id;
+ }
+
+ public function getAccountIdFromName($row)
+ {
+ $account_id = Account::where('name', $row['account_name'])->pluck('id')->first();
+
+ if (!empty($account_id)) {
+ return $account_id;
+ }
+
+ $data = [
+ 'company_id' => company_id(),
+ 'type' => !empty($row['account_type']) ? $row['account_type'] : 'bank',
+ 'name' => $row['account_name'],
+ 'number' => !empty($row['account_number']) ? $row['account_number'] : (string) rand(1, 10000),
+ 'currency_code' => !empty($row['currency_code']) ? $row['currency_code'] : default_currency(),
+ 'opening_balance' => !empty($row['opening_balance']) ? $row['opening_balance'] : 0,
+ 'enabled' => 1,
+ 'created_from' => !empty($row['created_from']) ? $row['created_from'] : $this->getSourcePrefix() . 'import',
+ 'created_by' => !empty($row['created_by']) ? $row['created_by'] : user()?->id,
+ ];
+
+ Validator::validate($data, (new AccountRequest)->rules());
+
+ $account = $this->dispatch(new CreateAccount($data));
+
+ return $account->id;
+ }
+
+ public function getAccountIdFromNumber($row)
+ {
+ $account_id = Account::where('account_number', $row['account_number'])->pluck('id')->first();
+
+ if (!empty($account_id)) {
+ return $account_id;
+ }
+
+ $data = [
+ 'company_id' => company_id(),
+ 'type' => !empty($row['account_type']) ? $row['account_type'] : 'bank',
+ 'number' => $row['account_number'],
+ 'name' => !empty($row['account_name']) ? $row['account_name'] : $row['account_number'],
+ 'currency_code' => !empty($row['currency_code']) ? $row['currency_code'] : default_currency(),
+ 'opening_balance' => !empty($row['opening_balance']) ? $row['opening_balance'] : 0,
+ 'enabled' => 1,
+ 'created_from' => !empty($row['created_from']) ? $row['created_from'] : $this->getSourcePrefix() . 'import',
+ 'created_by' => !empty($row['created_by']) ? $row['created_by'] : user()?->id,
+ ];
+
+ Validator::validate($data, (new AccountRequest)->rules());
+
+ $account = $this->dispatch(new CreateAccount($data));
+
+ return $account->id;
+ }
+
+ public function getCategoryIdFromName($row, $type)
+ {
+ $category_id = Category::type($type)->withSubCategory()->where('name', $row['category_name'])->pluck('id')->first();
+
+ if (!empty($category_id)) {
+ return $category_id;
+ }
+
+ $data = [
+ 'company_id' => company_id(),
+ 'name' => $row['category_name'],
+ 'type' => $type,
+ 'color' => !empty($row['category_color']) ? $row['category_color'] : '#' . dechex(rand(0x000000, 0xFFFFFF)),
+ 'enabled' => 1,
+ 'created_from' => !empty($row['created_from']) ? $row['created_from'] : $this->getSourcePrefix() . 'import',
+ 'created_by' => !empty($row['created_by']) ? $row['created_by'] : user()?->id,
+ ];
+
+ Validator::validate($data, (new CategoryRequest)->rules());
+
+ $category = $this->dispatch(new CreateCategory($data));
+
+ return $category->id;
+ }
+
+ public function getContactIdFromEmail($row, $type)
+ {
+ $contact_id = Contact::type($type)->where('email', $row['contact_email'])->pluck('id')->first();
+
+ if (!empty($contact_id)) {
+ return $contact_id;
+ }
+
+ $data = [
+ 'company_id' => company_id(),
+ 'email' => $row['contact_email'],
+ 'type' => $type,
+ 'name' => !empty($row['contact_name']) ? $row['contact_name'] : $row['contact_email'],
+ 'currency_code' => !empty($row['contact_currency']) ? $row['contact_currency'] : default_currency(),
+ 'enabled' => 1,
+ 'created_from' => !empty($row['created_from']) ? $row['created_from'] : $this->getSourcePrefix() . 'import',
+ 'created_by' => !empty($row['created_by']) ? $row['created_by'] : user()?->id,
+ ];
+
+ Validator::validate($data, (new ContactRequest)->rules());
+
+ $contact = $this->dispatch(new CreateContact($data));
+
+ return $contact->id;
+ }
+
+ public function getContactIdFromName($row, $type)
+ {
+ $contact_id = Contact::type($type)->where('name', $row['contact_name'])->pluck('id')->first();
+
+ if (!empty($contact_id)) {
+ return $contact_id;
+ }
+
+ $data = [
+ 'company_id' => company_id(),
+ 'name' => $row['contact_name'],
+ 'type' => $type,
+ 'email' => !empty($row['contact_email']) ? $row['contact_email'] : null,
+ 'currency_code' => !empty($row['contact_currency']) ? $row['contact_currency'] : default_currency(),
+ 'enabled' => 1,
+ 'created_from' => !empty($row['created_from']) ? $row['created_from'] : $this->getSourcePrefix() . 'import',
+ 'created_by' => !empty($row['created_by']) ? $row['created_by'] : user()?->id,
+ ];
+
+ Validator::validate($data, (new ContactRequest)->rules());
+
+ $contact = $this->dispatch(new CreateContact($data));
+
+ return $contact->id;
+ }
+
+ public function getItemIdFromName($row, $type = null)
+ {
+ $type = !empty($type) ? $type : (!empty($row['item_type']) ? $row['item_type'] : 'product');
+
+ $item_id = Item::type($type)->where('name', $row['item_name'])->pluck('id')->first();
+
+ if (!empty($item_id)) {
+ return $item_id;
+ }
+
+ $data = [
+ 'company_id' => company_id(),
+ 'type' => $type,
+ 'name' => $row['item_name'],
+ 'description' => !empty($row['item_description']) ? $row['item_description'] : null,
+ 'sale_price' => !empty($row['sale_price']) ? $row['sale_price'] : (!empty($row['price']) ? $row['price'] : 0),
+ 'purchase_price' => !empty($row['purchase_price']) ? $row['purchase_price'] : (!empty($row['price']) ? $row['price'] : 0),
+ 'enabled' => 1,
+ 'created_from' => !empty($row['created_from']) ? $row['created_from'] : $this->getSourcePrefix() . 'import',
+ 'created_by' => !empty($row['created_by']) ? $row['created_by'] : user()?->id,
+ ];
+
+ Validator::validate($data, (new ItemRequest())->rules());
+
+ $item = $this->dispatch(new CreateItem($data));
+
+ return $item->id;
+ }
+
+ public function getTaxIdFromRate($row, $type = 'normal')
+ {
+ $tax_id = Tax::type($type)->where('rate', $row['tax_rate'])->pluck('id')->first();
+
+ if (!empty($tax_id)) {
+ return $tax_id;
+ }
+
+ $data = [
+ 'company_id' => company_id(),
+ 'rate' => $row['tax_rate'],
+ 'type' => $type,
+ 'name' => !empty($row['tax_name']) ? $row['tax_name'] : (string) $row['tax_rate'],
+ 'enabled' => 1,
+ 'created_from' => !empty($row['created_from']) ? $row['created_from'] : $this->getSourcePrefix() . 'import',
+ 'created_by' => !empty($row['created_by']) ? $row['created_by'] : user()?->id,
+ ];
+
+ Validator::validate($data, (new TaxRequest())->rules());
+
+ $tax = $this->dispatch(new CreateTax($data));
+
+ return $tax->id;
+ }
+
+ protected function getImportPath($group, $type)
+ {
+ $path = config('import.' . $group . '.' . $type . '.path');
+
+ if (! empty($path)) {
+ return str_replace('company_id', company_id(), $path);
+ }
+
+ return company_id() . '/' . $group . '/' . $type;
+ }
+
+ protected function getImportTitleType($group, $type)
+ {
+ $title_type = config('import.' . $group . '.' . $type . '.title_type');
+
+ if (! empty($title_type)) {
+ return $this->findTranslation($title_type);
+ }
+
+ $module = module($group);
+
+ $title_type = trans_choice('general.' . str_replace('-', '_', $type), 2);
+
+ if ($module instanceof Module) {
+ $title_type = trans_choice($group . '::general.' . str_replace('-', '_', $type), 2);
+ }
+
+ return $title_type;
+ }
+
+ protected function getImportSampleFile($group, $type)
+ {
+ $sample_file = config('import.' . $group . '.' . $type . '.sample_file');
+
+ if (! empty($sample_file)) {
+ return url($sample_file);
+ }
+
+ $module = module($group);
+
+ $sample_file = url('public/files/import/' . $type . '.xlsx');
+
+ if ($module instanceof Module) {
+ $sample_file = url('modules/' . $module->getStudlyName() . '/Resources/assets/' . $type . '.xlsx');
+ }
+
+ return $sample_file;
+ }
+
+ protected function getImportFormParams($group, $type, $path = null, $route = null)
+ {
+ $form_params = config('import.' . $group . '.' . $type . '.form_params');
+
+ if (! empty($form_params)) {
+ return $form_params;
+ }
+
+ $form_params = [
+ 'id' => 'import',
+ '@submit.prevent' => 'onSubmit',
+ '@keydown' => 'form.errors.clear($event.target.name)',
+ 'files' => true,
+ 'role' => 'form',
+ 'class' => 'form-loading-button',
+ 'novalidate' => true,
+ 'route' => '',
+ 'url' => '',
+ ];
+
+ if (! empty($route)) {
+ $form_params['route'] = $route;
+ } else {
+ $form_params['url'] = $path . '/import';
+ }
+
+ return $form_params;
+ }
+
+ protected function getImportDocumentLink($group, $type)
+ {
+ return null;
+ }
+
+ protected function getImportViewPath($group, $type)
+ {
+ $view = config('import.' . $group . '.' . $type . '.view');
+
+ if (! empty($view)) {
+ return $view;
+ }
+
+ $view = 'common.import.create';
+
+ return $view;
+ }
+}
diff --git a/app/Traits/Jobs.php b/app/Traits/Jobs.php
new file mode 100644
index 00000000..b254d198
--- /dev/null
+++ b/app/Traits/Jobs.php
@@ -0,0 +1,83 @@
+getDispatchFunction();
+
+ return $this->$function($job);
+ }
+
+ /**
+ * Dispatch a job to its appropriate handler.
+ *
+ * @param mixed $command
+ * @return mixed
+ */
+ public function dispatchQueue($job)
+ {
+ return app(Dispatcher::class)->dispatch($job);
+ }
+
+ /**
+ * Dispatch a command to its appropriate handler in the current process.
+ *
+ * Queuable jobs will be dispatched to the "sync" queue.
+ *
+ * @param mixed $command
+ * @param mixed $handler
+ * @return mixed
+ */
+ public function dispatchSync($job, $handler = null)
+ {
+ return app(Dispatcher::class)->dispatchSync($job, $handler);
+ }
+
+ /**
+ * Dispatch a job to its appropriate handler and return a response array for ajax calls.
+ *
+ * @param mixed $job
+ * @return mixed
+ */
+ public function ajaxDispatch($job)
+ {
+ try {
+ $data = $this->dispatch($job);
+
+ $response = [
+ 'success' => true,
+ 'error' => false,
+ 'data' => $data,
+ 'message' => '',
+ ];
+ } catch (Exception | Throwable $e) {
+ $response = [
+ 'success' => false,
+ 'error' => true,
+ 'data' => null,
+ 'code' => $e->getCode(),
+ 'message' => $e->getMessage(),
+ ];
+ }
+
+ return $response;
+ }
+
+ public function getDispatchFunction()
+ {
+ return should_queue() ? 'dispatchQueue' : 'dispatchSync';
+ }
+}
diff --git a/app/Traits/Media.php b/app/Traits/Media.php
new file mode 100644
index 00000000..968cd70f
--- /dev/null
+++ b/app/Traits/Media.php
@@ -0,0 +1,63 @@
+
+ *
+ * Whether the model should automatically reload its media relationship after modification.
+ */
+trait Media
+{
+ use Mediable;
+
+ /**
+ * Relationship for all attached media.
+ * @return \Illuminate\Database\Eloquent\Relations\MorphToMany
+ */
+ public function media()
+ {
+ $media = $this->morphToMany(config('mediable.model'), 'mediable')
+ ->withPivot('tag', 'order')
+ ->orderBy('order');
+
+ // Skip deleted media if not detached
+ if (config('mediable.detach_on_soft_delete') == false) {
+ $media->whereNull('deleted_at');
+ }
+
+ return $media;
+ }
+
+ public function attachMedia($media, $tags): void
+ {
+ $tags = (array)$tags;
+ $increments = $this->getOrderValueForTags($tags);
+
+ $ids = $this->extractPrimaryIds($media);
+
+ foreach ($tags as $tag) {
+ $attach = [];
+
+ foreach ($ids as $id) {
+ $attach[$id] = [
+ 'company_id' => company_id(),
+ 'created_from' => source_name(),
+ 'created_by' => user_id(),
+ 'tag' => $tag,
+ 'order' => ++$increments[$tag],
+ ];
+ }
+
+ $this->media()->attach($attach);
+ }
+
+ $this->markMediaDirty($tags);
+ }
+}
diff --git a/app/Traits/Modules.php b/app/Traits/Modules.php
new file mode 100644
index 00000000..58bc8602
--- /dev/null
+++ b/app/Traits/Modules.php
@@ -0,0 +1,659 @@
+ [
+ 'token' => $apiKey,
+ ]
+ ];
+
+ if (! $response = static::getResponse('POST', 'token/check', $data)) {
+ return false;
+ }
+
+ $result = json_decode($response->getBody());
+
+ return $result->success ? true : false;
+ }
+
+ // Get All Modules
+ public function getModules($data = [])
+ {
+ $key = 'apps.app.' . $this->getDataKeyOfModules($data);
+
+ $items = Cache::get($key);
+
+ if (! empty($items)) {
+ return $items;
+ }
+
+ $items = static::getResponseData('GET', 'apps/items');
+
+ Cache::put($key, $items, Date::now()->addHour());
+
+ return $items;
+ }
+
+ // Get Module
+ public function getModule($alias)
+ {
+ $item = static::getResponseData('GET', 'apps/' . $alias);
+
+ return $item;
+ }
+
+ public function getModuleIsubscribe($alias)
+ {
+ if (! $response = static::getResponse('GET', 'apps/' . $alias . '/isubscribe')) {
+ return [];
+ }
+
+ $body = json_decode($response->getBody());
+
+ if (! is_object($body)) {
+ return [];
+ }
+
+ return $body;
+ }
+
+ public function getModuleDocumentation($alias, $data = [])
+ {
+ $key = 'apps.' . $alias . '.docs.' . $this->getDataKeyOfModules($data);
+
+ $documentation = Cache::get($key);
+
+ if (! empty($documentation)) {
+ return $documentation;
+ }
+
+ $documentation = static::getResponseData('GET', 'apps/docs/' . $alias);
+
+ Cache::put($key, $documentation, Date::now()->addHour());
+
+ return $documentation;
+ }
+
+ public function getModuleReleases($alias, $data = [])
+ {
+ $key = 'apps.' . $alias . '.releases.' . $this->getDataKeyOfModules($data);
+
+ $releases = Cache::get($key);
+
+ if (! empty($releases)) {
+ return $releases;
+ }
+
+ $releases = static::getResponseData('GET', 'apps/' . $alias . '/releases', $data);
+
+ Cache::put($key, $releases, Date::now()->addHour());
+
+ return $releases;
+ }
+
+ public function getModuleReviews($alias, $data = [])
+ {
+ $key = 'apps.' . $alias . '.reviews.' . $this->getDataKeyOfModules($data);
+
+ $reviews = Cache::get($key);
+
+ if (! empty($reviews)) {
+ return $reviews;
+ }
+
+ $reviews = static::getResponseData('GET', 'apps/' . $alias . '/reviews', $data);
+
+ Cache::put($key, $reviews, Date::now()->addHour());
+
+ return $reviews;
+ }
+
+ public function getModuleTestimonials($alias, $data = [])
+ {
+ $key = 'apps.' . $alias . '.testimonials.' . $this->getDataKeyOfModules($data);
+
+ $testimonials = Cache::get($key);
+
+ if (! empty($testimonials)) {
+ return $testimonials;
+ }
+
+ $testimonials = static::getResponseData('GET', 'apps/' . $alias . '/testimonials', $data);
+
+ Cache::put($key, $testimonials, Date::now()->addHour());
+
+ return $testimonials;
+ }
+
+ public function getBannersOfModules($data = [])
+ {
+ $key = 'apps.banners.' . $this->getDataKeyOfModules($data);
+
+ $banners = Cache::get($key);
+
+ if (! empty($banners)) {
+ return $banners;
+ }
+
+ $banners = static::getResponseData('GET', 'apps/banners');
+
+ Cache::put($key, $banners, Date::now()->addHour());
+
+ return $banners;
+ }
+
+ public function getCategoriesOfModules($data = [])
+ {
+ $key = 'apps.categories.' . $this->getDataKeyOfModules($data);
+
+ $categories = Cache::get($key);
+
+ if (! empty($categories)) {
+ return $categories;
+ }
+
+ $categories = static::getResponseData('GET', 'apps/categories');
+
+ Cache::put($key, $categories, Date::now()->addHour());
+
+ return $categories;
+ }
+
+ public function getModulesByCategory($alias, $data = [])
+ {
+ $key = 'apps.categories.' . $alias . '.' . $this->getDataKeyOfModules($data);
+
+ $category = Cache::get($key);
+
+ if (! empty($category)) {
+ return $category;
+ }
+
+ $category = static::getResponseData('GET', 'apps/categories/' . $alias, $data);
+
+ Cache::put($key, $category, Date::now()->addHour());
+
+ return $category;
+ }
+
+ public function getVendorsOfModules($data = [])
+ {
+ $key = 'apps.vendors.' . $this->getDataKeyOfModules($data);
+
+ $vendors = Cache::get($key);
+
+ if (! empty($vendors)) {
+ return $vendors;
+ }
+
+ $vendors = static::getResponseData('GET', 'apps/vendors');
+
+ Cache::put($key, $vendors, Date::now()->addHour());
+
+ return $vendors;
+ }
+
+ public function getModulesByVendor($alias, $data = [])
+ {
+ $key = 'apps.vendors.' . $alias . '.' . $this->getDataKeyOfModules($data);
+
+ $vendor = Cache::get($key);
+
+ if (! empty($vendor)) {
+ return $vendor;
+ }
+
+ $vendor = static::getResponseData('GET', 'apps/vendors/' . $alias, $data);
+
+ Cache::put($key, $vendor, Date::now()->addHour());
+
+ return $vendor;
+ }
+
+ public function getMyModules($data = [])
+ {
+ return static::getResponseData('GET', 'apps/my', $data);
+ }
+
+ public function getInstalledModules()
+ {
+ $key = 'apps.installed.' . company_id();
+
+ if ($installed = Cache::get($key)) {
+ return $installed;
+ }
+
+ $installed = [];
+
+ Module::all()->each(function($module) use (&$installed) {
+ if (! $this->moduleExists($module->alias)) {
+ return;
+ }
+
+ if (! $result = $this->getModule($module->alias)) {
+ return;
+ }
+
+ $installed[] = $result;
+ });
+
+ Cache::put($key, $installed, Date::now()->addHours(6));
+
+ return $installed;
+ }
+
+ public function getPreSaleModules($data = [])
+ {
+ $key = 'apps.pre_sale.' . $this->getDataKeyOfModules($data);
+
+ $pre_sale = Cache::get($key);
+
+ if (! empty($pre_sale)) {
+ return $pre_sale;
+ }
+
+ $pre_sale = static::getResponseData('GET', 'apps/pre_sale', $data);
+
+ Cache::put($key, $pre_sale, Date::now()->addHour());
+
+ return $pre_sale;
+ }
+
+ public function getPaidModules($data = [])
+ {
+ $key = 'apps.paid.' . $this->getDataKeyOfModules($data);
+
+ $paid = Cache::get($key);
+
+ if (! empty($paid)) {
+ return $paid;
+ }
+
+ $paid = static::getResponseData('GET', 'apps/paid', $data);
+
+ Cache::put($key, $paid, Date::now()->addHour());
+
+ return $paid;
+ }
+
+ public function getNewModules($data = [])
+ {
+ $key = 'apps.new.' . $this->getDataKeyOfModules($data);
+
+ $new = Cache::get($key);
+
+ if (! empty($new)) {
+ return $new;
+ }
+
+ $new = static::getResponseData('GET', 'apps/new', $data);
+
+ Cache::put($key, $new, Date::now()->addHour());
+
+ return $new;
+ }
+
+ public function getFreeModules($data = [])
+ {
+ $key = 'apps.free.' . $this->getDataKeyOfModules($data);
+
+ $free = Cache::get($key);
+
+ if (! empty($free)) {
+ return $free;
+ }
+
+ $free = static::getResponseData('GET', 'apps/free', $data);
+
+ Cache::put($key, $free, Date::now()->addHour());
+
+ return $free;
+ }
+
+ public function getFeaturedModules($data = [])
+ {
+ $key = 'apps.featured.' . $this->getDataKeyOfModules($data);
+
+ $featured = Cache::get($key);
+
+ if (! empty($featured)) {
+ return $featured;
+ }
+
+ $featured = static::getResponseData('GET', 'apps/featured', $data);
+
+ Cache::put($key, $featured, Date::now()->addHour());
+
+ return $featured;
+ }
+
+ public function getPopularModules($data = [])
+ {
+ $key = 'apps.popular.' . $this->getDataKeyOfModules($data);
+
+ $popular = Cache::get($key);
+
+ if (! empty($popular)) {
+ return $popular;
+ }
+
+ $popular = static::getResponseData('GET', 'apps/popular', $data);
+
+ Cache::put($key, $popular, Date::now()->addHour());
+
+ return $popular;
+ }
+
+ public function getSearchModules($data = [])
+ {
+ return static::getResponseData('GET', 'apps/search', $data);
+ }
+
+ public function getTestimonialModules($data = [])
+ {
+ $key = 'apps.testimonials.' . $this->getDataKeyOfModules($data);
+
+ return Cache::remember($key, Date::now()->addHours(6), function () use ($data) {
+ return static::getResponseData('GET', 'apps/testimonials', $data);
+ });
+ }
+
+ public function getWidgetsOfModules($data = [])
+ {
+ $key = 'apps.widgets.' . $this->getDataKeyOfModules($data);
+
+ return Cache::remember($key, Date::now()->addHours(6), function () {
+ return static::getResponseData('GET', 'apps/widgets');
+ });
+ }
+
+ public function getModulesByWidget($alias, $data = [])
+ {
+ $key = 'apps.widgets.' . $alias . '.' . $this->getDataKeyOfModules($data);
+
+ return Cache::remember($key, Date::now()->addHours(6), function () use ($alias, $data) {
+ return static::getResponseData('GET', 'apps/widgets/' . $alias, $data);
+ });
+ }
+
+ public function getCoreVersion()
+ {
+ $data['query'] = Info::all();
+
+ if (! $response = static::getResponse('GET', 'core/version', $data)) {
+ return [];
+ }
+
+ return $response->json();
+ }
+
+ public function moduleExists($alias)
+ {
+ if (! module($alias) instanceof \Akaunting\Module\Module) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function moduleIsEnabled($alias): bool
+ {
+ if (! $this->moduleExists($alias)) {
+ return false;
+ }
+
+ return module($alias)->enabled();
+ }
+
+ public function moduleIsDisabled($alias): bool
+ {
+ return ! $this->moduleIsEnabled($alias);
+ }
+
+ public function getModulesLimitOfSubscription()
+ {
+ $limit = new \stdClass();
+
+ $limit->action_status = true;
+ $limit->view_status = true;
+ $limit->message = "Success";
+
+ if (! config('app.installed') || running_in_test()) {
+ return $limit;
+ }
+
+ if (is_cloud()) {
+ return $limit;
+ }
+
+ $modules = module()->all();
+
+ $versions = Versions::all($modules);
+
+ foreach ($versions as $alias => $version) {
+ if ($alias == 'core') {
+ continue;
+ }
+
+ $module_limit = $this->getModuleLimitOfSubscription($alias, $version);
+
+ if ($module_limit->action_status === false) {
+ $limit->action_status = false;
+ $limit->view_status = false;
+ $limit->message = $module_limit->message;
+
+ // Clear cache to reflect changes
+ Cache::forget('updates');
+ Cache::forget('versions');
+ }
+ }
+
+ return $limit;
+ }
+
+ public function getModuleLimitOfSubscription($alias, $version = null)
+ {
+ $limit = new \stdClass();
+
+ $limit->action_status = true;
+ $limit->view_status = true;
+ $limit->message = "Success";
+
+ if (empty($version)) {
+ $version = Versions::getVersionByAlias($alias);
+ }
+
+ if (! $version->subscription) {
+ return $limit;
+ }
+
+ if (! in_array($version->subscription->action_status, ['disabled', 'uninstalled'])) {
+ return $limit;
+ }
+
+ $module_companies = Module::allCompanies()->enabled()->alias($alias)->get();
+
+ if (! $module_companies->count()) {
+ return $limit;
+ }
+
+ $limit->action_status = false;
+ $limit->view_status = false;
+ $limit->message = "Not able to app $alias.";
+
+ foreach ($module_companies as $module) {
+ switch ($version->subscription->action_status) {
+ case 'disabled':
+ dispatch(new DisableModule($alias, $module->company_id));
+ break;
+ case 'uninstalled':
+ dispatch(new UninstallModule($alias, $module->company_id));
+ break;
+ default:
+ // Do nothing
+ break;
+ }
+ }
+
+ return $limit;
+ }
+
+ public function loadSubscriptions()
+ {
+ $key = 'apps.subscriptions';
+
+ return Cache::remember($key, Date::now()->addHours(6), function () {
+ $data = [];
+
+ if (! is_cloud()) {
+ $data['headers'] = [
+ 'X-Akaunting-Modules' => implode(',', module()->getAvailable()),
+ ];
+ }
+
+ return (array) static::getResponseData('GET', 'apps/subscriptions', $data);
+ });
+ }
+
+ public function loadSuggestions()
+ {
+ $key = 'apps.suggestions';
+
+ return Cache::remember($key, Date::now()->addHours(6), function () {
+ $data = [];
+
+ $suggestions = (array) static::getResponseData('GET', 'apps/suggestions');
+
+ foreach ($suggestions as $suggestion) {
+ $data[$suggestion->path] = $suggestion;
+ }
+
+ return $data;
+ });
+ }
+
+ public function loadNotifications()
+ {
+ $key = 'apps.notifications';
+
+ return Cache::remember($key, Date::now()->addHours(6), function () {
+ $data = [];
+
+ $notifications = (array) static::getResponseData('GET', 'apps/notifications');
+
+ foreach ($notifications as $notification) {
+ $data[$notification->path][] = $notification;
+ }
+
+ return $data;
+ });
+ }
+
+ public function loadTips()
+ {
+ $key = 'apps.tips';
+
+ return Cache::remember($key, Date::now()->addHours(6), function () {
+ $data = [];
+
+ $tips = (array) static::getResponseData('GET', 'apps/tips');
+
+ foreach ($tips as $tip) {
+ $data[$tip->path][] = $tip;
+ }
+
+ return $data;
+ });
+ }
+
+ public function getSubscription($alias)
+ {
+ $data = $this->loadSubscriptions();
+
+ if (! empty($data) && array_key_exists($alias, $data)) {
+ return $data[$alias];
+ }
+
+ return false;
+ }
+
+ public function getSuggestions($path)
+ {
+ $data = $this->loadSuggestions();
+
+ if (! empty($data) && array_key_exists($path, $data)) {
+ return $data[$path];
+ }
+
+ return false;
+ }
+
+ public function getNotifications($path): array
+ {
+ $data = $this->loadNotifications();
+
+ if (! empty($data) && array_key_exists($path, $data)) {
+ return (array) $data[$path];
+ }
+
+ return [];
+ }
+
+ public function getTips($path): array
+ {
+ $data = $this->loadTips();
+
+ if (! empty($data) && array_key_exists($path, $data)) {
+ return (array) $data[$path];
+ }
+
+ return [];
+ }
+
+ public function getPageNumberOfModules($data = [])
+ {
+ if (empty($data['query']) || empty($data['query']['page'])) {
+ return 1;
+ }
+
+ return $data['query']['page'];
+ }
+
+ public function getDataKeyOfModules($data = [])
+ {
+ $result = 'language.' . language()->getShortCode() . '.page.' . $this->getPageNumberOfModules($data);
+
+ if (isset($data['query']['page'])) {
+ unset($data['query']['page']);
+ }
+
+ if (isset($data['query'])){
+ foreach($data['query'] as $key => $value) {
+ $result .= '.' . $key . '.' . $value;
+ }
+ }
+
+ return $result;
+ }
+
+ public function registerModules(): void
+ {
+ app(\Akaunting\Module\Contracts\ActivatorInterface::class)->register();
+ }
+}
diff --git a/app/Traits/Omnipay.php b/app/Traits/Omnipay.php
new file mode 100644
index 00000000..d2b8fbc3
--- /dev/null
+++ b/app/Traits/Omnipay.php
@@ -0,0 +1,210 @@
+ $invoice->amount,
+ 'currency' => $invoice->currency_code,
+ 'transactionId' => $invoice->id,
+ 'returnUrl' => $this->getReturnUrl($invoice),
+ 'cancelUrl' => $this->getCancelUrl($invoice),
+ ];
+
+ $options = array_merge($default_options, $extra_options);
+
+ try {
+ $response = $this->gateway->authorize($options)->send();
+ } catch (\Exception $e) {
+ $this->logger->info($this->module->getName() . ':: Invoice: ' . $invoice->id . ' - Error: '. $e->getMessage());
+
+ $message = $e->getMessage();
+
+ return response()->json([
+ 'error' => $message,
+ 'redirect' => false,
+ 'success' => false,
+ 'data' => false,
+ ]);
+ }
+
+ if ($response->isSuccessful()) {
+ $this->setReference($invoice, $response->$reference());
+
+ $options[lcfirst(str_replace('get', '', $reference))] = $response->$reference();
+
+ $response = $this->gateway->capture($options)->send();
+
+ return $this->finish($invoice, $request);
+ }
+
+ if ($response->isRedirect()) {
+ $this->setReference($invoice, $response->$reference());
+
+ return response()->json([
+ 'error' => false,
+ 'redirect' => $response->getRedirectUrl(),
+ 'success' => false,
+ 'data' => $response->getRedirectData(),
+ ]);
+ }
+
+ return $this->failure($invoice, $response);
+ }
+
+ public function purchase($invoice, $request, $extra_options = [])
+ {
+ $default_options = [
+ 'amount' => $invoice->amount - $invoice->paid,
+ 'currency' => $invoice->currency_code,
+ 'transactionId' => $invoice->id,
+ 'returnUrl' => $this->getReturnUrl($invoice),
+ 'cancelUrl' => $this->getCancelUrl($invoice),
+ ];
+
+ $options = array_merge($default_options, $extra_options);
+
+ try {
+ $response = $this->gateway->purchase($options)->send();
+ } catch (\Exception $e) {
+ $this->logger->info($this->module->getName() . ':: Invoice: ' . $invoice->id . ' - Error: '. $e->getMessage());
+
+ $message = $e->getMessage();
+
+ return response()->json([
+ 'error' => $message,
+ 'redirect' => false,
+ 'success' => false,
+ 'data' => false,
+ ]);
+ }
+
+ if ($response->isSuccessful()) {
+ $this->setReference($invoice, $response->getTransactionReference());
+
+ return $this->finish($invoice, $request);
+ }
+
+ if ($response->isRedirect()) {
+ $this->setReference($invoice, $response->getTransactionReference());
+
+ return response()->json([
+ 'error' => false,
+ 'redirect' => $response->getRedirectUrl(),
+ 'success' => false,
+ 'data' => $response->getRedirectData(),
+ ]);
+ }
+
+ return $this->failure($invoice, $response);
+ }
+
+ public function completePurchase($invoice, $request, $extra_options = [])
+ {
+ $default_options = [
+ 'amount' => $invoice->amount,
+ 'currency' => $invoice->currency_code,
+ 'transactionId' => $invoice->id,
+ 'transactionReference' => $this->getReference($invoice),
+ //'returnUrl' => $this->getReturnUrl($invoice),
+ //'cancelUrl' => $this->getCancelUrl($invoice),
+ ];
+
+ $options = array_merge($default_options, $extra_options);
+
+ $response = $this->gateway->completePurchase($options)->send();
+
+ if ($response->isSuccessful()) {
+ return $this->finish($invoice, $request);
+ }
+
+ if ($response->isCancelled()) {
+ return $this->cancel($invoice);
+ }
+
+ return $this->failure($invoice, $response, true);
+ }
+
+ public function failure($invoice, $response, $force_redirect = false)
+ {
+ $data = $response->getData();
+ $message = $response->getMessage();
+
+ if (isset($data['error'])) {
+ $this->logger->info($this->module->getName() . ':: Invoice: ' . $invoice->id . ' - Error Type: ' . $data['error']['type'] . ' - Error Message: ' . $message);
+ } else {
+ $this->logger->info($this->module->getName() . ':: Invoice: ' . $invoice->id . ' - Error Message: ' . $message);
+ }
+
+ $invoice_url = $this->getInvoiceUrl($invoice);
+
+ flash($message)->error()->important();
+
+ if ($force_redirect) {
+ return redirect($invoice_url);
+ }
+
+ return response()->json([
+ 'error' => $message,
+ 'redirect' => $invoice_url,
+ 'success' => false,
+ 'data' => false,
+ ]);
+ }
+
+ public function all()
+ {
+ return $this->callFactory('all');
+ }
+
+ public function replace($gateways)
+ {
+ return $this->callFactory('replace', [$gateways]);
+ }
+
+ public function register($class_name)
+ {
+ return $this->callFactory('register', [$class_name]);
+ }
+
+ public function create($class, $http_client = null, $http_request = null)
+ {
+ $this->gateway = $this->callFactory('create', [$class, $http_client, $http_request]);
+
+ return $this->gateway;
+ }
+
+ public function callFactory($method, $parameters = [])
+ {
+ $factory = $this->getFactory();
+
+ return call_user_func_array(array($factory, $method), (array) $parameters);
+ }
+
+ public function getFactory()
+ {
+ if (is_null($this->factory)) {
+ $this->factory = new \Omnipay\Common\GatewayFactory();
+ }
+
+ return $this->factory;
+ }
+
+ public function setCardFirstLastName(&$request)
+ {
+ $contact = explode(" ", $request['cardName']);
+
+ $last_name = array_pop($contact);
+ $first_name = implode(" ", $contact);
+
+ $request['cardFirstName'] = $first_name;
+ $request['cardLastName'] = $last_name;
+ }
+}
diff --git a/app/Traits/Owners.php b/app/Traits/Owners.php
new file mode 100644
index 00000000..24df9558
--- /dev/null
+++ b/app/Traits/Owners.php
@@ -0,0 +1,18 @@
+ownable ?: true;
+
+ return ($ownable === true) && in_array('created_by', $this->getFillable());
+ }
+
+ public function isNotOwnable()
+ {
+ return !$this->isOwnable();
+ }
+}
diff --git a/app/Traits/Permissions.php b/app/Traits/Permissions.php
new file mode 100644
index 00000000..142205de
--- /dev/null
+++ b/app/Traits/Permissions.php
@@ -0,0 +1,514 @@
+ 'create',
+ 'r' => 'read',
+ 'u' => 'update',
+ 'd' => 'delete',
+ ];
+ }
+
+ public function attachPermissionsByRoleNames($roles)
+ {
+ foreach ($roles as $role_name => $permissions) {
+ $role = $this->createRole($role_name);
+
+ foreach ($permissions as $id => $permission) {
+ $this->attachPermissionsByAction($role, $id, $permission);
+ }
+ }
+ }
+
+ public function attachPermissionsToAdminRoles($permissions)
+ {
+ $this->applyPermissionsToRoles($this->getDefaultAdminRoles(), 'attach', $permissions);
+ }
+
+ public function attachPermissionsToPortalRoles($permissions)
+ {
+ $this->applyPermissionsToRoles($this->getDefaultPortalRoles(), 'attach', $permissions);
+ }
+
+ public function attachPermissionsToAllRoles($permissions, $require = 'read-admin-panel')
+ {
+ $this->applyPermissionsToRoles($this->getRoles($require), 'attach', $permissions);
+ }
+
+ public function detachPermissionsByRoleNames($roles)
+ {
+ foreach ($roles as $role_name => $permissions) {
+ foreach ($permissions as $permission_name) {
+ $this->detachPermission($role_name, $permission_name);
+ }
+ }
+ }
+
+ public function detachPermissionsFromAdminRoles($permissions)
+ {
+ $this->applyPermissionsToRoles($this->getDefaultAdminRoles(), 'detach', $permissions);
+ }
+
+ public function detachPermissionsFromPortalRoles($permissions)
+ {
+ $this->applyPermissionsToRoles($this->getDefaultPortalRoles(), 'detach', $permissions);
+ }
+
+ public function detachPermissionsFromAllRoles($permissions, $require = 'read-admin-panel')
+ {
+ $this->applyPermissionsToRoles($this->getRoles($require), 'detach', $permissions, $require);
+ }
+
+ public function applyPermissionsToRoles($roles, $apply, $permissions)
+ {
+ $roles->each(function ($role) use ($apply, $permissions) {
+ $f1 = $apply . 'PermissionsByAction';
+ $f2 = $apply . 'Permission';
+
+ foreach ($permissions as $id => $permission) {
+ if ($this->isActionList($permission)) {
+ $this->$f1($role, $id, $permission);
+
+ continue;
+ }
+
+ $this->$f2($role, $permission);
+ }
+ });
+ }
+
+ public function updatePermissionNames($permissions)
+ {
+ $actions = $this->getActionsMap();
+
+ foreach ($permissions as $old => $new) {
+ foreach ($actions as $action) {
+ $old_name = $action . '-' . $old;
+
+ $permission = Permission::where('name', $old_name)->first();
+
+ if (empty($permission)) {
+ continue;
+ }
+
+ $new_name = $action . '-' . $new;
+ $new_display_name = $this->getPermissionDisplayName($new_name);
+
+ $permission->update([
+ 'name' => $new_name,
+ 'display_name' => $new_display_name,
+ ]);
+ }
+ }
+ }
+
+ public function attachDefaultModulePermissions($module, $require = null)
+ {
+ $this->attachModuleReportPermissions($module, $require);
+
+ $this->attachModuleWidgetPermissions($module, $require);
+
+ $this->attachModuleSettingPermissions($module, $require);
+ }
+
+ public function attachModuleReportPermissions($module, $require = null)
+ {
+ if (is_string($module)) {
+ $module = module($module);
+ }
+
+ if (empty($module->get('reports'))) {
+ return;
+ }
+
+ $permissions = [];
+
+ foreach ($module->get('reports') as $class) {
+ if (!class_exists($class)) {
+ continue;
+ }
+
+ $permissions[] = $this->createModuleReportPermission($module, $class);
+ }
+
+ $require
+ ? $this->attachPermissionsToAllRoles($permissions, $require)
+ : $this->attachPermissionsToAdminRoles($permissions);
+ }
+
+ public function attachModuleWidgetPermissions($module, $require = null)
+ {
+ if (is_string($module)) {
+ $module = module($module);
+ }
+
+ if (empty($module->get('widgets'))) {
+ return;
+ }
+
+ $permissions = [];
+
+ foreach ($module->get('widgets') as $class) {
+ if (!class_exists($class)) {
+ continue;
+ }
+
+ $permissions[] = $this->createModuleWidgetPermission($module, $class);
+ }
+
+ $require
+ ? $this->attachPermissionsToAllRoles($permissions, $require)
+ : $this->attachPermissionsToAdminRoles($permissions);
+ }
+
+ public function attachModuleSettingPermissions($module, $require = null)
+ {
+ if (is_string($module)) {
+ $module = module($module);
+ }
+
+ if (empty($module->get('settings'))) {
+ return;
+ }
+
+ $permissions = [];
+
+ $permissions[] = $this->createModuleSettingPermission($module, 'read');
+ $permissions[] = $this->createModuleSettingPermission($module, 'update');
+
+ $require
+ ? $this->attachPermissionsToAllRoles($permissions, $require)
+ : $this->attachPermissionsToAdminRoles($permissions);
+ }
+
+ public function createModuleReportPermission($module, $class)
+ {
+ if (is_string($module)) {
+ $module = module($module);
+ }
+
+ if (!class_exists($class)) {
+ return;
+ }
+
+ $name = Reports::getPermission($class);
+ $display_name = 'Read ' . $module->getName() . ' Reports ' . Reports::getDefaultName($class);
+
+ return $this->createPermission($name, $display_name);
+ }
+
+ public function createModuleWidgetPermission($module, $class)
+ {
+ if (is_string($module)) {
+ $module = module($module);
+ }
+
+ if (!class_exists($class)) {
+ return;
+ }
+
+ $name = Widgets::getPermission($class);
+ $display_name = 'Read ' . $module->getName() . ' Widgets ' . Widgets::getDefaultName($class);
+
+ return $this->createPermission($name, $display_name);
+ }
+
+ public function createModuleSettingPermission($module, $action)
+ {
+ return $this->createModuleControllerPermission($module, $action, 'settings');
+ }
+
+ public function createModuleControllerPermission($module, $action, $controller)
+ {
+ if (is_string($module)) {
+ $module = module($module);
+ }
+
+ $name = $action . '-' . $module->getAlias() . '-' . $controller;
+ $display_name = Str::title($action) . ' ' . $module->getName() . ' ' . Str::title($controller);
+
+ return $this->createPermission($name, $display_name);
+ }
+
+ public function createRole($name, $display_name = null, $description = null)
+ {
+ $alias = !empty($this->alias) ? $this->alias : $name;
+
+ if (empty($display_name)) {
+ $display_name = $this->findTranslation([
+ 'auth.roles.' . Str::replace('-', '_', $name) . '.name',
+ $alias . '::permissions.roles.' . Str::replace('-', '_', $name) . '.name',
+ $alias . '::auth.roles.' . Str::replace('-', '_', $name) . '.name',
+ ]);
+
+ if (empty($display_name)) {
+ $display_name = Str::title(Str::replace('-', ' ', $name));
+ }
+ }
+
+ if (empty($description)) {
+ $description = $this->findTranslation([
+ 'auth.roles.' . Str::replace('-', '_', $name) . '.description',
+ $alias . '::permissions.roles.' . Str::replace('-', '_', $name) . '.description',
+ $alias . '::auth.roles.' . Str::replace('-', '_', $name) . '.description',
+ ]);
+
+ if (empty($description)) {
+ $description = $display_name;
+ }
+ }
+
+ return role_model_class()::firstOrCreate([
+ 'name' => $name,
+ ], [
+ 'display_name' => $display_name,
+ 'description' => $description,
+ ]);
+ }
+
+ public function createPermission($name, $display_name = null, $description = null)
+ {
+ $display_name = $display_name ?? $this->getPermissionDisplayName($name);
+
+ return Permission::firstOrCreate([
+ 'name' => $name,
+ ], [
+ 'display_name' => $display_name,
+ 'description' => $description ?? $display_name,
+ ]);
+ }
+
+ public function attachPermission($role, $permission)
+ {
+ if (is_string($permission)) {
+ $permission = $this->createPermission($permission);
+ }
+
+ if ($role->hasPermission($permission->name)) {
+ return;
+ }
+
+ $role->attachPermission($permission);
+ }
+
+ public function detachPermission($role, $permission, $delete = true)
+ {
+ if (is_string($role)) {
+ $role = role_model_class()::where('name', $role)->first();
+ }
+
+ if (empty($role)) {
+ return;
+ }
+
+ if (is_string($permission)) {
+ $permission = Permission::where('name', $permission)->first();
+ }
+
+ if (empty($permission)) {
+ return;
+ }
+
+ if ($role->hasPermission($permission->name)) {
+ $role->detachPermission($permission);
+ }
+
+ if ($delete === false) {
+ return;
+ }
+
+ $permission->delete();
+ }
+
+ public function isActionList($permission)
+ {
+ if (!is_string($permission)) {
+ return false;
+ }
+
+ // c || c,r,u,d
+ return (Str::length($permission) == 1) || Str::contains($permission, ',');
+ }
+
+ public function attachPermissionsByAction($role, $page, $action_list)
+ {
+ $this->applyPermissionsByAction('attach', $role, $page, $action_list);
+ }
+
+ public function detachPermissionsByAction($role, $page, $action_list)
+ {
+ $this->applyPermissionsByAction('detach', $role, $page, $action_list);
+ }
+
+ public function applyPermissionsByAction($apply, $role, $page, $action_list)
+ {
+ $function = $apply . 'Permission';
+
+ $actions_map = collect($this->getActionsMap());
+
+ $actions = explode(',', $action_list);
+
+ foreach ($actions as $short_action) {
+ $action = $actions_map->get($short_action);
+
+ $name = $action . '-' . $page;
+
+ $this->$function($role, $name);
+ }
+ }
+
+ public function getPermissionDisplayName($name)
+ {
+ if (!empty($this->alias)) {
+ $name = str_replace($this->alias, '{Module Placeholder}', $name);
+ }
+
+ $name = Str::title(str_replace('-', ' ', $name));
+
+ if (!empty($this->alias)) {
+ $name = str_replace('{Module Placeholder}', module($this->alias)->getName(), $name);
+ }
+
+ return $name;
+ }
+
+ public function getRoles($require = 'read-admin-panel')
+ {
+ return role_model_class()::all()->filter(function ($role) use ($require) {
+ return $require ? $role->hasPermission($require) : true;
+ });
+ }
+
+ public function getDefaultAdminRoles($custom = null)
+ {
+ $roles = role_model_class()::whereIn('name', $custom ?? ['super_admin', 'admin'])->get();
+
+ if ($roles->isNotEmpty()) {
+ return $roles;
+ }
+
+ return $this->getRoles('read-admin-panel');
+ }
+
+ public function getDefaultPortalRoles($custom = null)
+ {
+ $roles = role_model_class()::whereIn('name', $custom ?? ['customer'])->get();
+
+ if ($roles->isNotEmpty()) {
+ return $roles;
+ }
+
+ return $this->getRoles('read-client-portal');
+ }
+
+ /**
+ * Assign permissions middleware to default controller methods.
+ *
+ * @return void
+ */
+ public function assignPermissionsToController()
+ {
+ // No need to check for permission in console
+ if (app()->runningInConsole()) {
+ return;
+ }
+
+ $table = request_is_api() ? request()->segment(2) : '';
+
+ // Find the proper controller for common API endpoints
+ if (in_array($table, ['contacts', 'documents'])) {
+ $controller = '';
+
+ // Look for type in search variable like api/contacts?search=type:customer
+ $type = $this->getSearchStringValue('type');
+
+ if (! empty($type)) {
+ $alias = config('type.' . Str::singular($table) . '.' . $type . '.alias');
+ $group = config('type.' . Str::singular($table) . '.' . $type . '.group');
+ $prefix = config('type.' . Str::singular($table) . '.' . $type . '.permission.prefix');
+
+ // if use module set module alias
+ if (! empty($alias)) {
+ $controller .= $alias . '-';
+ }
+
+ // if controller in folder it must
+ if (! empty($group)) {
+ $controller .= $group . '-';
+ }
+
+ $controller .= $prefix;
+ }
+ } else {
+ $route = app(Route::class);
+
+ // Get the controller array
+ $arr = array_reverse(explode('\\', explode('@', $route->getAction()['uses'])[0]));
+
+ $controller = '';
+
+ // Add module
+ if (isset($arr[3]) && isset($arr[4])) {
+ if (strtolower($arr[4]) == 'modules') {
+ $controller .= Str::kebab($arr[3]) . '-';
+ } elseif (isset($arr[5]) && (strtolower($arr[5]) == 'modules')) {
+ $controller .= Str::kebab($arr[4]) . '-';
+ }
+ }
+
+ // Add folder
+ if (! in_array(strtolower($arr[1]), ['api', 'controllers'])) {
+ $controller .= Str::kebab($arr[1]) . '-';
+ }
+
+ // Add file
+ $controller .= Str::kebab($arr[0]);
+
+ // Skip ACL
+ $skip = ['portal-dashboard'];
+ if (in_array($controller, $skip)) {
+ return;
+ }
+
+ // App\Http\Controllers\FooBar -->> foo-bar
+ // App\Http\Controllers\FooBar\Main -->> foo-bar-main
+ // Modules\Blog\Http\Controllers\Posts -->> blog-posts
+ // Modules\Blog\Http\Controllers\Portal\Posts -->> blog-portal-posts
+ }
+
+ // Add CRUD permission check
+ $this->middleware('permission:create-' . $controller)->only('create', 'store', 'duplicate', 'import');
+ $this->middleware('permission:read-' . $controller)->only('index', 'show', 'edit', 'export');
+ $this->middleware('permission:update-' . $controller)->only('update', 'enable', 'disable', 'markSent', 'markCancelled', 'markReceived', 'markApproved', 'markRefused', 'restoreInvoice', 'restoreBill', 'end');
+ $this->middleware('permission:delete-' . $controller)->only('destroy');
+ }
+
+ public function canAccessMenuItem($title, $permissions)
+ {
+ $permissions = Arr::wrap($permissions);
+
+ $item = new \stdClass();
+ $item->title = $title;
+ $item->permissions = $permissions;
+
+ event(new \App\Events\Menu\ItemAuthorizing($item));
+
+ return user()->canAny($item->permissions);
+ }
+}
diff --git a/app/Traits/Plans.php b/app/Traits/Plans.php
new file mode 100644
index 00000000..f7f85ad6
--- /dev/null
+++ b/app/Traits/Plans.php
@@ -0,0 +1,104 @@
+getPlanLimitByType('user');
+ }
+
+ public function getCompanyLimitOfPlan(): object
+ {
+ return $this->getPlanLimitByType('company');
+ }
+
+ public function getInvoiceLimitOfPlan(): object
+ {
+ return $this->getPlanLimitByType('invoice');
+ }
+
+ public function getAnyActionLimitOfPlan(): object
+ {
+ $user_limit = $this->getUserLimitOfPlan();
+ $company_limit = $this->getCompanyLimitOfPlan();
+ $invoice_limit = $this->getInvoiceLimitOfPlan();
+
+ if (! $user_limit->action_status) {
+ return $user_limit;
+ }
+
+ if (! $company_limit->action_status) {
+ return $company_limit;
+ }
+
+ if (! $invoice_limit->action_status) {
+ return $invoice_limit;
+ }
+
+ $limit = new \stdClass();
+ $limit->action_status = true;
+ $limit->view_status = true;
+ $limit->message = "Success";
+
+ return $limit;
+ }
+
+ public function getPlanLimitByType($type): object
+ {
+ // A self-hosted installation must not depend on Akaunting Cloud to
+ // create its own users, companies, or invoices.
+ if (! config('app.installed') || running_in_test() || config('app.offline')) {
+ $limit = new \stdClass();
+
+ $limit->action_status = true;
+ $limit->view_status = true;
+ $limit->message = "Success";
+
+ return $limit;
+ }
+
+ if (! $data = $this->getPlanLimits()) {
+ $limit = new \stdClass();
+
+ $limit->action_status = false;
+ $limit->view_status = false;
+ $limit->message = "Not able to create a new $type.";
+
+ return $limit;
+ }
+
+ $limit = $data->$type;
+
+ $limit->message = str_replace('{company_id}', company_id(), $limit->message);
+
+ return $limit;
+ }
+
+ public function getPlanLimits(): bool|object
+ {
+ $key = 'plans.limits';
+
+ return Cache::remember($key, Date::now()->addHour(), function () {
+ $url = 'plans/limits';
+
+ if (! $data = static::getResponseData('GET', $url, ['timeout' => 10])) {
+ return false;
+ }
+
+ return $data;
+ });
+ }
+}
diff --git a/app/Traits/Recurring.php b/app/Traits/Recurring.php
new file mode 100644
index 00000000..edaf5f3a
--- /dev/null
+++ b/app/Traits/Recurring.php
@@ -0,0 +1,233 @@
+recurring()->create([
+ 'company_id' => $this->company_id,
+ 'frequency' => $frequency,
+ 'interval' => $interval,
+ 'started_at' => $started_at,
+ 'status' => $status,
+ 'limit_by' => $limit_by,
+ 'limit_count' => $limit_count,
+ 'limit_date' => $limit_date,
+ 'auto_send' => $auto_send,
+ 'created_from' => $source,
+ 'created_by' => $owner,
+ ]);
+ }
+
+ public function updateRecurring($request)
+ {
+ if (empty($request['recurring_frequency']) || ($request['recurring_frequency'] == 'no')) {
+ $this->recurring()->delete();
+
+ return;
+ }
+
+ $frequency = ($request['recurring_frequency'] != 'custom') ? $request['recurring_frequency'] : $request['recurring_custom_frequency'];
+ $interval = (($request['recurring_frequency'] != 'custom') || ($request['recurring_interval'] < 1)) ? 1 : (int) $request['recurring_interval'];
+ $started_at = !empty($request['recurring_started_at']) ? $request['recurring_started_at'] : Date::now();
+ $limit_by = !empty($request['recurring_limit']) ? $request['recurring_limit'] : 'count';
+ $limit_count = isset($request['recurring_limit_count']) ? (int) $request['recurring_limit_count'] : 0;
+ $limit_date = !empty($request['recurring_limit_date']) ? $request['recurring_limit_date'] : null;
+ $auto_send = !empty($request['recurring_send_email']) ? $request['recurring_send_email'] : 0;
+
+ $recurring = $this->recurring();
+ $model_exists = $recurring->count();
+
+ $data = [
+ 'company_id' => $this->company_id,
+ 'frequency' => $frequency,
+ 'interval' => $interval,
+ 'started_at' => $started_at,
+ 'limit_by' => $limit_by,
+ 'limit_count' => $limit_count,
+ 'limit_date' => $limit_date,
+ 'auto_send' => $auto_send,
+ ];
+
+ if (! empty($request['recurring_status'])) {
+ $data['status'] = $request['recurring_status'];
+ }
+
+ if ($model_exists) {
+ $recurring->update($data);
+ } else {
+ $source = !empty($request['created_from']) ? $request['created_from'] : source_name();
+ $owner = !empty($request['created_by']) ? (int) $request['created_by'] : user_id();
+
+ $recurring->create(array_merge($data, [
+ 'status' => Model::ACTIVE_STATUS,
+ 'created_from' => $source,
+ 'created_by' => $owner,
+ ]));
+ }
+ }
+
+ public function getRecurringSchedule()
+ {
+ $config = new ArrayTransformerConfig();
+ $config->enableLastDayOfMonthFix();
+ $config->setVirtualLimit($this->getRecurringVirtualLimit());
+
+ $transformer = new ArrayTransformer();
+ $transformer->setConfig($config);
+
+ return $transformer->transform($this->getRecurringRule());
+ }
+
+ public function getRecurringRule()
+ {
+ $rule = (new Rule())
+ ->setStartDate($this->getRecurringRuleStartDate())
+ ->setTimezone($this->getRecurringRuleTimeZone())
+ ->setFreq($this->getRecurringRuleFrequency())
+ ->setInterval($this->getRecurringRuleInterval());
+
+ if ($this->limit_by == 'date') {
+ $rule->setUntil($this->getRecurringRuleUntilDate());
+ } elseif ($this->limit_count != 0) {
+ // 0 means infinite
+ $rule->setCount($this->getRecurringRuleCount());
+ }
+
+ return $rule;
+ }
+
+ public function getRecurringRuleStartDate()
+ {
+ return $this->getRecurringRuleDate($this->started_at);
+ }
+
+ public function getRecurringRuleUntilDate()
+ {
+ return $this->getRecurringRuleDate($this->limit_date);
+ }
+
+ public function getRecurringRuleTodayDate()
+ {
+ return $this->getRecurringRuleDate(Date::today()->toDateTimeString());
+ }
+
+ public function getRecurringRuleTomorrowDate()
+ {
+ return $this->getRecurringRuleDate(Date::tomorrow()->toDateTimeString());
+ }
+
+ public function getRecurringRuleDate($date)
+ {
+ return new \DateTime($date, new \DateTimeZone($this->getRecurringRuleTimeZone()));
+ }
+
+ public function getRecurringRuleTimeZone()
+ {
+ return setting('localisation.timezone');
+ }
+
+ public function getRecurringRuleCount()
+ {
+ return $this->limit_count;
+ }
+
+ public function getRecurringRuleFrequency()
+ {
+ return strtoupper($this->frequency);
+ }
+
+ public function getRecurringRuleInterval()
+ {
+ return $this->interval;
+ }
+
+ public function getRecurringVirtualLimit()
+ {
+ switch ($this->frequency) {
+ case 'yearly':
+ $limit = '2';
+ break;
+ case 'monthly':
+ $limit = '24';
+ break;
+ case 'weekly':
+ $limit = '104';
+ break;
+ case 'daily':
+ default;
+ $limit = '732';
+ break;
+ }
+
+ return $limit;
+ }
+
+ public function getNextRecurring()
+ {
+ if (! $schedule = $this->getRecurringSchedule()) {
+ return false;
+ }
+
+ $schedule = $schedule->startsAfter($this->getRecurringRuleTodayDate());
+
+ if ($schedule->count() == 0) {
+ return false;
+ }
+
+ if (! $next = $schedule->current()) {
+ return false;
+ }
+
+ return $next->getStart();
+ }
+
+ public function getFirstRecurring()
+ {
+ if (! $schedule = $this->getRecurringSchedule()) {
+ return false;
+ }
+
+ if (! $first = $schedule->first()) {
+ return false;
+ }
+
+ return $first->getStart();
+ }
+
+ public function getLastRecurring()
+ {
+ if (! $schedule = $this->getRecurringSchedule()) {
+ return false;
+ }
+
+ if (! $last = $schedule->last()) {
+ return false;
+ }
+
+ return $last->getStart();
+ }
+}
diff --git a/app/Traits/Relationships.php b/app/Traits/Relationships.php
new file mode 100644
index 00000000..cac38556
--- /dev/null
+++ b/app/Traits/Relationships.php
@@ -0,0 +1,70 @@
+model = $model;
+ $record->relationships = $relationships;
+
+ event(new RelationshipCounting($record));
+
+ $counter = [];
+
+ foreach ((array) $record->relationships as $relationship => $text) {
+ if (!$c = $model->$relationship()->count()) {
+ continue;
+ }
+
+ $text = Str::contains($text, '::') ? $text : 'general.' . $text;
+ $counter[] = (($c > 1) ? $c . ' ' : null ) . strtolower(trans_choice($text, ($c > 1) ? 2 : 1));
+ }
+
+ return $counter;
+ }
+
+ /**
+ * Mass delete relationships with events being fired.
+ *
+ * @param $model
+ * @param $relationships
+ * @param $permanently
+ */
+ public function deleteRelationships($model, $relationships, $permanently = false): void
+ {
+ $record = new \stdClass();
+ $record->model = $model;
+ $record->relationships = $relationships;
+
+ event(new RelationshipDeleting($record));
+
+ foreach ((array) $record->relationships as $relationship) {
+ if (empty($model->$relationship)) {
+ continue;
+ }
+
+ $items = [];
+ $relation = $model->$relationship;
+
+ if ($relation instanceof Collection) {
+ $items = $relation->all();
+ } else {
+ $items[] = $relation;
+ }
+
+ $function = $permanently ? 'forceDelete' : 'delete';
+
+ foreach ((array) $items as $item) {
+ $item->$function();
+ }
+ }
+ }
+}
diff --git a/app/Traits/Scopes.php b/app/Traits/Scopes.php
new file mode 100644
index 00000000..a051c079
--- /dev/null
+++ b/app/Traits/Scopes.php
@@ -0,0 +1,114 @@
+scopeColumnExists($builder, $model->getTable(), 'type')) {
+ return;
+ }
+
+ // Apply not recurring scope
+ $builder->isNotRecurring();
+ }
+
+ public function applyNotSplitScope(Builder $builder, Model $model): void
+ {
+ // Skip if type already set
+ if ($this->scopeColumnExists($builder, $model->getTable(), 'type')) {
+ return;
+ }
+
+ // Apply not split scope
+ $builder->isNotSplit();
+ }
+
+ public function scopeColumnExists(Builder $builder, string $table, string $column): bool
+ {
+ $query = $builder->getQuery();
+
+ foreach ((array) $query->wheres as $key => $where) {
+ if (empty($where) || empty($where['column'])) {
+ continue;
+ }
+
+ // Skip Expression objects (e.g. DB::raw()) — they are not
+ // simple "table.column" strings and cannot be parsed here.
+ // Fixes CLOUD-PROD-LARAVEL-1TKA
+ if (! is_string($where['column'])) {
+ continue;
+ }
+
+ if (strstr($where['column'], '.')) {
+ $whr = explode('.', $where['column']);
+
+ $where['table'] = $whr[0];
+ $where['column'] = $whr[1];
+ }
+
+ if (! empty($where['table']) && ! empty($table) && ($where['table'] != $table)) {
+ continue;
+ }
+
+ if ($where['column'] != $column) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public function scopeValueExists(Builder $builder, string $table, string $column, string $value): bool
+ {
+ $query = $builder->getQuery();
+
+ foreach ((array) $query->wheres as $key => $where) {
+ if (empty($where) || empty($where['column']) || empty($where['value'])) {
+ continue;
+ }
+
+ // Skip Expression objects — same guard as scopeColumnExists
+ if (! is_string($where['column'])) {
+ continue;
+ }
+
+ if (strstr($where['column'], '.')) {
+ $whr = explode('.', $where['column']);
+
+ $where['table'] = $whr[0];
+ $where['column'] = $whr[1];
+ }
+
+ if (! empty($where['table']) && ! empty($table) && ($where['table'] != $table)) {
+ continue;
+ }
+
+ if ($where['column'] != $column) {
+ continue;
+ }
+
+ if (! Str::endsWith($where['value'], $value)) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ // @deprecated version 3.0.0
+ public function scopeExists($builder, $column): bool
+ {
+ return $this->scopeColumnExists($builder, '', $column);
+ }
+}
diff --git a/app/Traits/SearchString.php b/app/Traits/SearchString.php
new file mode 100644
index 00000000..a121aca3
--- /dev/null
+++ b/app/Traits/SearchString.php
@@ -0,0 +1,196 @@
+=2021-02-01 issued_at<=2021-02-10
+ *
+ * Examples (spaced):
+ * search=age > 30
+ * search=title : "Hello World"
+ *
+ * Returns a string for single-value operators (:, =) and an array when the
+ * same column appears multiple times (e.g. range queries with > / <).
+ * Surrounding quotes are stripped from returned values.
+ */
+ public function getSearchStringValue(
+ string $name,
+ string $default = '',
+ string $input = '',
+ ): string|array {
+ $value = $default;
+
+ $input = $input ?: request('search', '');
+
+ // Normalise spaced operators (e.g. "age > 30") into compact form ("age>30")
+ // so the rest of the parsing logic only needs to handle one format.
+ $input = preg_replace('/\b(' . preg_quote($name, '/') . ')\s*(>=|<=|>|<|=|:)\s*/', '$1$2', $input);
+
+ $columns = explode(' ', $input);
+
+ foreach ($columns as $column) {
+ // Operators ordered longest-first to avoid partial matches (>= before >).
+ $variable = preg_split('/(>=|<=|>|<|=|:)/', $column, 2);
+
+ if ($name === 'searchable' && count($variable) === 1 && preg_match('/^".*"$/', $variable[0])) {
+ return trim($variable[0], '"');
+ }
+
+ if (empty($variable[0]) || $variable[0] !== $name || ! isset($variable[1]) || $variable[1] === '') {
+ continue;
+ }
+
+ $extracted = trim($variable[1], '"\'');
+
+ if (str_contains($column, ':')) {
+ return $extracted;
+ }
+
+ if (! is_array($value)) {
+ $value = [];
+ }
+
+ $value[] = $extracted;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Get the operator for a named column in the search string, mapped to an Eloquent-compatible operator.
+ * The `:` operator maps to `=` (exact match).
+ * The `not` prefix inverts the operator (e.g. `not amount>100` → `<=`).
+ *
+ * Examples without `not`:
+ * search=amount>=100 → '>='
+ * search=amount<=100 → '<='
+ * search=amount>100 → '>'
+ * search=amount<100 → '<'
+ * search=amount:100 → '='
+ * search=amount=100 → '='
+ *
+ * Examples with `not`:
+ * search=not amount>=100 → '<'
+ * search=not amount<=100 → '>'
+ * search=not amount>100 → '<='
+ * search=not amount<100 → '>='
+ * search=not amount:100 → '!='
+ * search=not amount=100 → '!='
+ */
+ public function getSearchStringOperator(
+ string $name,
+ string $default = '=',
+ string $input = '',
+ ): string {
+ $input = $input ?: request('search', '');
+
+ $columns = explode(' ', $input);
+
+ foreach ($columns as $index => $column) {
+ if (! str_starts_with($column, $name)) {
+ continue;
+ }
+
+ $rest = substr($column, strlen($name));
+
+ if (! preg_match('/^(>=|<=|>|<|=|:)/', $rest, $matches)) {
+ continue;
+ }
+
+ $operator = $matches[1] === ':' ? '=' : $matches[1];
+ $negated = isset($columns[$index - 1]) && $columns[$index - 1] === 'not';
+
+ if (! $negated) {
+ return $operator;
+ }
+
+ return match ($operator) {
+ '>=' => '<',
+ '>' => '<=',
+ '<=' => '>',
+ '<' => '>=',
+ default => '!=',
+ };
+ }
+
+ return $default;
+ }
+
+ /**
+ * Strip tokens from a search string whose keys are not recognised columns
+ * for the given model class. Tokens whose keys appear in neither the model's
+ * search-string config nor the default keywords / columns are removed before
+ * the string is passed to usingSearchString().
+ *
+ * Falls back to returning $input unchanged when the model has no config entry.
+ */
+ public function stripUnknownSearchStringTokens(
+ string $input,
+ string $model_class,
+ ): string {
+ $model_config_columns = config('search-string.' . $model_class . '.columns', null);
+
+ if ($model_config_columns === null) {
+ return $input;
+ }
+
+ $valid_columns = array_unique(array_merge(
+ array_keys($model_config_columns),
+ array_values(config('search-string.default.keywords', [])),
+ array_keys(config('search-string.default.columns', [])),
+ ));
+
+ // Collect key aliases from column configs.
+ // A 'key' may be a plain string alias (e.g. 'invoiced_at') or a regex
+ // pattern (e.g. '/^(invoiced_at|billed_at)$/'). Plain aliases are
+ // merged into $valid_columns; regex patterns are kept separately and
+ // tested with preg_match inside the callback below.
+ $key_patterns = [];
+
+ foreach ($model_config_columns as $column_config) {
+ if (! is_array($column_config) || ! isset($column_config['key'])) {
+ continue;
+ }
+
+ $key = $column_config['key'];
+
+ if (is_string($key) && strlen($key) >= 2 && $key[0] === '/' && $key[-1] === '/') {
+ $key_patterns[] = $key;
+ } elseif (is_string($key)) {
+ $valid_columns[] = $key;
+ }
+ }
+
+ $valid_columns = array_unique($valid_columns);
+
+ // Match optional "not " prefix + key + operator + value (quoted or unquoted)
+ $input = preg_replace_callback(
+ pattern: '/\b(?:not\s+)?(\w+)\s*(?:>=|<=|>|<|=|:)\s*(?:"[^"]*"|\S+)/',
+ callback: function (array $matches) use ($valid_columns, $key_patterns): string {
+ $token = $matches[1];
+
+ if (in_array($token, $valid_columns, strict: true)) {
+ return $matches[0];
+ }
+
+ foreach ($key_patterns as $pattern) {
+ if (preg_match($pattern, $token)) {
+ return $matches[0];
+ }
+ }
+
+ return '';
+ },
+ subject: $input,
+ );
+
+ return trim(preg_replace('/\s+/', ' ', $input));
+ }
+}
diff --git a/app/Traits/Settings.php b/app/Traits/Settings.php
new file mode 100644
index 00000000..04b1d9e3
--- /dev/null
+++ b/app/Traits/Settings.php
@@ -0,0 +1,30 @@
+all();
+
+ if (! empty($settings)) {
+ return setting($key, $default);
+ }
+
+ $company_id = $this->getCompanyId();
+
+ if (empty($company_id)) {
+ return $default;
+ }
+
+ $value = Setting::companyId($company_id)->where('key', $key)->pluck('value')->first();
+
+ return $value ?: $default;
+ }
+}
diff --git a/app/Traits/SiteApi.php b/app/Traits/SiteApi.php
new file mode 100644
index 00000000..c7073245
--- /dev/null
+++ b/app/Traits/SiteApi.php
@@ -0,0 +1,86 @@
+ false, 'base_uri' => static::$base_uri]);
+
+ $headers['headers'] = [
+ 'Authorization' => 'Bearer ' . Info::getApiKey(),
+ 'Accept' => 'application/json',
+ 'Referer' => app()->runningInConsole() ? config('app.url') : url('/'),
+ 'Akaunting' => Version::short(),
+ 'Language' => language()->getShortCode(),
+ 'Information' => json_encode(Info::all()),
+ ];
+
+ $data = array_merge([
+ 'timeout' => 30,
+ 'referer' => true,
+ 'http_errors' => false,
+ ], $extra_data);
+
+ $options = array_merge_recursive($data, $headers);
+
+ try {
+ $response = $client->request($method, $path, $options);
+ } catch (ConnectException | Exception | RequestException $e) {
+ $response = $e;
+ }
+
+ return $response;
+ }
+
+ public static function getResponse($method, $path, $data = [], $status_code = 200)
+ {
+ $response = static::siteApiRequest($method, $path, $data);
+
+ $is_exception = (($response instanceof ConnectException) || ($response instanceof Exception) || ($response instanceof RequestException));
+
+ if (!$response || $is_exception || ($response->getStatusCode() != $status_code)) {
+ return false;
+ }
+
+ return $response;
+ }
+
+ public static function getResponseBody($method, $path, $data = [], $status_code = 200)
+ {
+ if (! $response = static::getResponse($method, $path, $data, $status_code)) {
+ return [];
+ }
+
+ $body = json_decode($response->getBody());
+
+ return $body;
+ }
+
+ public static function getResponseData($method, $path, $data = [], $status_code = 200)
+ {
+ if (! $body = static::getResponseBody($method, $path, $data, $status_code)) {
+ return [];
+ }
+
+ if (! is_object($body)) {
+ return [];
+ }
+
+ return $body->data;
+ }
+}
diff --git a/app/Traits/Sources.php b/app/Traits/Sources.php
new file mode 100644
index 00000000..810f9191
--- /dev/null
+++ b/app/Traits/Sources.php
@@ -0,0 +1,72 @@
+sourcable ?: true;
+
+ return ($sourcable === true) && in_array('created_from', $this->getFillable());
+ }
+
+ public function isNotSourcable(): bool
+ {
+ return ! $this->isSourcable();
+ }
+
+ public function getSourceName($request = null, $alias = null): string
+ {
+ $prefix = $this->getSourcePrefix($alias);
+
+ if (app()->runningInConsole()) {
+ $source = $prefix . 'console';
+ }
+
+ if (empty($source)) {
+ $request = $request ?: request();
+
+ if ($request instanceof QueueCollection || running_in_queue()) {
+ $source = $prefix . 'queue';
+ } else {
+ $source = $request->isApi() ? $prefix . 'api' : null;
+ }
+ }
+
+ if (empty($source)) {
+ $source = $prefix . 'ui';
+ }
+
+ return $source;
+ }
+
+ public function getSourcePrefix($alias = null)
+ {
+ $alias = is_null($alias) ? $this->getSourceAlias() : $alias;
+
+ return $alias . '::';
+ }
+
+ public function getSourceAlias()
+ {
+ $prefix = '';
+
+ $namespaces = explode('\\', get_class($this));
+
+ if (empty($namespaces[0]) || (empty($namespaces[1]))) {
+ return $prefix;
+ }
+
+ if ($namespaces[0] != 'Modules') {
+ return 'core';
+ }
+
+ $prefix = Str::kebab($namespaces[1]);
+
+ return $prefix;
+ }
+}
diff --git a/app/Traits/Tailwind.php b/app/Traits/Tailwind.php
new file mode 100644
index 00000000..156627a5
--- /dev/null
+++ b/app/Traits/Tailwind.php
@@ -0,0 +1,113 @@
+ '#6b7280',
+ 'gray-50' => '#f9fafb',
+ 'gray-100' => '#f3f4f6',
+ 'gray-200' => '#e5e7eb',
+ 'gray-300' => '#d1d5db',
+ 'gray-400' => '#9ca3af',
+ 'gray-500' => '#6b7280',
+ 'gray-600' => '#4b5563',
+ 'gray-700' => '#374151',
+ 'gray-800' => '#1f2937',
+ 'gray-900' => '#111827',
+
+ 'red' => '#cc0000',
+ 'red-50' => '#fcf2f2',
+ 'red-100' => '#fae6e6',
+ 'red-200' => '#f2bfbf',
+ 'red-300' => '#eb9999',
+ 'red-400' => '#db4d4d',
+ 'red-500' => '#cc0000',
+ 'red-600' => '#b80000',
+ 'red-700' => '#990000',
+ 'red-800' => '#7a0000',
+ 'red-900' => '#640000',
+
+ 'yellow' => '#eab308',
+ 'yellow-50' => '#fefce8',
+ 'yellow-100' => '#fef9c3',
+ 'yellow-200' => '#fef08a',
+ 'yellow-300' => '#fde047',
+ 'yellow-400' => '#facc15',
+ 'yellow-500' => '#eab308',
+ 'yellow-600' => '#ca8a04',
+ 'yellow-700' => '#a16207',
+ 'yellow-800' => '#854d0e',
+ 'yellow-900' => '#713f12',
+
+ 'green' => '#6ea152',
+ 'green-50' => '#f8faf6',
+ 'green-100' => '#f1f6ee',
+ 'green-200' => '#dbe8d4',
+ 'green-300' => '#c5d9ba',
+ 'green-400' => '#9abd86',
+ 'green-500' => '#6ea152',
+ 'green-600' => '#63914a',
+ 'green-700' => '#53793e',
+ 'green-800' => '#426131',
+ 'green-900' => '#364f28',
+
+ 'blue' => '#006ea6',
+ 'blue-50' => '#f2f8fb',
+ 'blue-100' => '#e6f1f6',
+ 'blue-200' => '#bfdbe9',
+ 'blue-300' => '#99c5db',
+ 'blue-400' => '#4d9ac1',
+ 'blue-500' => '#006ea6',
+ 'blue-600' => '#006395',
+ 'blue-700' => '#00537d',
+ 'blue-800' => '#004264',
+ 'blue-900' => '#003651',
+
+ 'indigo' => '#6366f1',
+ 'indigo-50' => '#eef2ff',
+ 'indigo-100' => '#e0e7ff',
+ 'indigo-200' => '#c7d2fe',
+ 'indigo-300' => '#a5b4fc',
+ 'indigo-400' => '#818cf8',
+ 'indigo-500' => '#6366f1',
+ 'indigo-600' => '#4f46e5',
+ 'indigo-700' => '#4338ca',
+ 'indigo-800' => '#3730a3',
+ 'indigo-900' => '#312e81',
+
+ 'purple' => '#55588b',
+ 'purple-50' => '#f7f7f9',
+ 'purple-100' => '#eeeef3',
+ 'purple-200' => '#d5d5e2',
+ 'purple-300' => '#bbbcd1',
+ 'purple-400' => '#888aae',
+ 'purple-500' => '#55588b',
+ 'purple-600' => '#4d4f7d',
+ 'purple-700' => '#404268',
+ 'purple-800' => '#333553',
+ 'purple-900' => '#2a2b44',
+
+ 'pink' => '#ec4899',
+ 'pink-50' => '#fdf2f8',
+ 'pink-100' => '#fce7f3',
+ 'pink-200' => '#fbcfe8',
+ 'pink-300' => '#f9a8d4',
+ 'pink-400' => '#f472b6',
+ 'pink-500' => '#ec4899',
+ 'pink-600' => '#db2777',
+ 'pink-700' => '#be185d',
+ 'pink-800' => '#9d174d',
+ 'pink-900' => '#831843',
+ ];
+
+ return Arr::exists($colors, $class)
+ ? $colors[$class]
+ : $class;
+ }
+}
diff --git a/app/Traits/Tenants.php b/app/Traits/Tenants.php
new file mode 100644
index 00000000..f02095eb
--- /dev/null
+++ b/app/Traits/Tenants.php
@@ -0,0 +1,30 @@
+tenantable ?? true;
+
+ return ($tenantable === true) && in_array('company_id', $this->getFillable());
+ }
+
+ public function isNotTenantable()
+ {
+ return !$this->isTenantable();
+ }
+}
diff --git a/app/Traits/Trackers.php b/app/Traits/Trackers.php
new file mode 100644
index 00000000..689db009
--- /dev/null
+++ b/app/Traits/Trackers.php
@@ -0,0 +1,43 @@
+ (string) company_id(),
+ 'locale' => (string) app()->getLocale(),
+ 'timezone' => (string) config('app.timezone'),
+ 'app_type' => (string) static::getAppType(),
+ 'route_name' => (string) static::getRouteName(),
+ ];
+ }
+
+ public static function getAppType(): string
+ {
+ $hostname = gethostname();
+
+ if (Str::contains($hostname, '-queue-')) {
+ $app_type = 'queue';
+ } elseif (Str::contains($hostname, '-cron-')) {
+ $app_type = 'cron';
+ } elseif (request_is_api()) {
+ $app_type = 'api';
+ } elseif (app()->runningInConsole()) {
+ $app_type = 'console';
+ } else {
+ $app_type = 'ui';
+ }
+
+ return $app_type;
+ }
+
+ public static function getRouteName(): ?string
+ {
+ return request()->route()?->getName();
+ }
+}
diff --git a/app/Traits/Transactions.php b/app/Traits/Transactions.php
new file mode 100644
index 00000000..3fcb2780
--- /dev/null
+++ b/app/Traits/Transactions.php
@@ -0,0 +1,262 @@
+type ?? $this->transaction->type ?? $this->model->type ?? Transaction::INCOME_TYPE;
+
+ return in_array($type, $this->getIncomeTypes());
+ }
+
+ public function isNotIncome(): bool
+ {
+ return ! $this->isIncome();
+ }
+
+ public function isExpense(): bool
+ {
+ $type = $this->type ?? $this->transaction->type ?? $this->model->type ?? Transaction::EXPENSE_TYPE;
+
+ return in_array($type, $this->getExpenseTypes());
+ }
+
+ public function isNotExpense(): bool
+ {
+ return ! $this->isExpense();
+ }
+
+ public function isRecurringTransaction(): bool
+ {
+ $type = $this->type ?? $this->transaction->type ?? $this->model->type ?? Transaction::INCOME_TYPE;
+
+ return Str::endsWith($type, '-recurring');
+ }
+
+ public function isNotRecurringTransaction(): bool
+ {
+ return ! $this->isRecurringTransaction();
+ }
+
+ public function isTransferTransaction(): bool
+ {
+ $type = $this->type ?? $this->transaction->type ?? $this->model->type ?? Transaction::INCOME_TYPE;
+
+ return Str::endsWith($type, '-transfer');
+ }
+
+ public function isNotTransferTransaction(): bool
+ {
+ return ! $this->isTransferTransaction();
+ }
+
+ public function isSplitTransaction(): bool
+ {
+ $type = $this->type ?? $this->transaction->type ?? $this->model->type ?? Transaction::INCOME_TYPE;
+
+ return Str::endsWith($type, '-split');
+ }
+
+ public function isNotSplitTransaction(): bool
+ {
+ return ! $this->isSplitTransaction();
+ }
+
+ public function isDocumentTransaction(): bool
+ {
+ $document_id = $this->document_id ?? $this->transaction->document_id ?? $this->model->document_id ?? null;
+
+ return ! empty($document_id);
+ }
+
+ public function isNotDocumentTransaction(): bool
+ {
+ return ! $this->isDocumentTransaction();
+ }
+
+ public function getIncomeTypes(string $return = 'array'): string|array
+ {
+ return $this->getTransactionTypes(Transaction::INCOME_TYPE, $return);
+ }
+
+ public function getExpenseTypes(string $return = 'array'): string|array
+ {
+ return $this->getTransactionTypes(Transaction::EXPENSE_TYPE, $return);
+ }
+
+ public function getTransactionTypes(string $index, string $return = 'array'): string|array
+ {
+ $types = (string) setting('transaction.type.' . $index);
+
+ if ($return == 'array') {
+ return $types === '' ? [] : explode(',', $types);
+ }
+
+ return $types;
+ }
+
+ public function addIncomeType(string $new_type): void
+ {
+ $this->addTransactionType($new_type, 'income');
+ }
+
+ public function addExpenseType(string $new_type): void
+ {
+ $this->addTransactionType($new_type, 'expense');
+ }
+
+ public function addTransactionType(string $new_type, string $index): void
+ {
+ $types = explode(',', setting('transaction.type.' . $index));
+
+ if (in_array($new_type, $types)) {
+ return;
+ }
+
+ $types[] = $new_type;
+
+ setting([
+ 'transaction.type.' . $index => implode(',', $types),
+ ])->save();
+ }
+
+ public function getTransactionFileName(Transaction $transaction, string $separator = '-', string $extension = 'pdf'): string
+ {
+ return $this->getSafeTransactionNumber($transaction, $separator) . $separator . time() . '.' . $extension;
+ }
+
+ public function getSafeTransactionNumber(Transaction $transaction, string $separator = '-'): string
+ {
+ return Str::slug($transaction->id, $separator, language()->getShortCode());
+ }
+
+ protected function getTransactionSettingKey(string $type, string $setting_key): string
+ {
+ $key = '';
+ $alias = config('type.transaction.' . $type . '.alias');
+
+ if (!empty($alias)) {
+ $key .= $alias . '.';
+ }
+
+ $prefix = config('type.transaction.' . $type . '.setting.prefix');
+
+ $key .= $prefix . '.' . $setting_key;
+
+ return $key;
+ }
+
+ public function storeTransactionPdfAndGetPath(Transaction $transaction): string
+ {
+ event(new TransactionPrinting($transaction));
+
+ $real_type = $this->getRealTypeTransaction($transaction->type);
+
+ $view = view('banking.transactions.print_default', compact('transaction', 'real_type'))->render();
+ $html = mb_convert_encoding($view, 'HTML-ENTITIES', 'UTF-8');
+
+ $pdf = app('dompdf.wrapper');
+ $pdf->loadHTML($html);
+
+ $file_name = $this->getTransactionFileName($transaction);
+
+ $pdf_path = get_storage_path('app/temp/' . $file_name);
+
+ // Save the PDF file into temp folder
+ $pdf->save($pdf_path);
+
+ return $pdf_path;
+ }
+
+ public function getTranslationsForConnect(string $type = Transaction::INCOME_TYPE): array
+ {
+ $document_type = config('type.transaction.' . $type . '.document_type');
+ $contact_type = config('type.transaction.' . $type . '.contact_type');
+
+ return [
+ 'title' => trans('general.connect') . ' ' . trans_choice('general.' . Str::plural($document_type), 1),
+ 'cancel' => trans('general.cancel'),
+ 'save' => trans('general.save'),
+ 'action' => trans('general.actions'),
+ 'document' => trans_choice('general.' . Str::plural($document_type), 1),
+ 'total' => trans('invoices.total'),
+ 'category' => trans_choice('general.categories', 1),
+ 'account' => trans_choice('general.accounts', 1),
+ 'amount' => trans('general.amount'),
+ 'number' => trans_choice('general.numbers', 1),
+ 'notes' => trans_choice('general.notes', 2),
+ 'contact' => trans_choice('general.' . Str::plural($contact_type), 1),
+ 'no_data' => trans('general.no_data'),
+ 'placeholder_search' => trans('general.placeholder.search'),
+ 'add_an' => trans('general.form.add_an', ['field' => trans_choice('general.' . Str::plural($document_type), 1)]),
+ 'transaction' => trans_choice('general.' . Str::plural($type), 1),
+ 'difference' => trans('general.difference'),
+ 'connect_tax' => trans('messages.warning.connect_tax', ['type' => $type]),
+ ];
+ }
+
+ public function getTransactionFormRoutesOfType(string $type): array
+ {
+ return [
+ 'contact_index' => route(Str::plural(config('type.transaction.' . $type . '.contact_type')) . '.index'),
+ 'contact_modal' => route('modals.' . Str::plural(config('type.transaction.' . $type . '.contact_type')) . '.create'),
+ 'category_index' => route('modals.categories.create', ['type' => $type]),
+ 'category_modal' => route('categories.index', ['search' => 'type:' . $type]),
+ ];
+ }
+
+ public function getTypeTransaction(string $type = Transaction::INCOME_TYPE): string
+ {
+ return array_key_exists($type, config('type.transaction')) ? $type : Transaction::INCOME_TYPE;
+ }
+
+ public function getRealTypeTransaction(string $type): string
+ {
+ $type = $this->getRealTypeOfRecurringTransaction($type);
+ $type = $this->getRealTypeOfTransferTransaction($type);
+ $type = $this->getRealTypeOfSplitTransaction($type);
+
+ return $type;
+ }
+
+ public function getTypeRecurringTransaction(string $type = Transaction::INCOME_RECURRING_TYPE): string
+ {
+ if (! Str::contains($type, '-recurring')) {
+ return Transaction::INCOME_RECURRING_TYPE;
+ }
+
+ return array_key_exists($type, config('type.transaction')) ? $type : Transaction::INCOME_RECURRING_TYPE;
+ }
+
+ public function getRealTypeOfRecurringTransaction(string $recurring_type): string
+ {
+ return Str::replace('-recurring', '', $recurring_type);
+ }
+
+ public function getRealTypeOfTransferTransaction(string $transfer_type): string
+ {
+ return Str::replace('-transfer', '', $transfer_type);
+ }
+
+ public function getRealTypeOfSplitTransaction(string $transfer_type): string
+ {
+ return Str::replace('-split', '', $transfer_type);
+ }
+
+ public function getNextTransactionNumber(string $type = 'income', string $suffix = ''): string
+ {
+ return app(TransactionNumber::class)->getNextNumber($type, $suffix, null);
+ }
+
+ public function increaseNextTransactionNumber(string $type = 'income', string $suffix = ''): void
+ {
+ app(TransactionNumber::class)->increaseNextNumber($type, $suffix, null);
+ }
+}
diff --git a/app/Traits/Translations.php b/app/Traits/Translations.php
new file mode 100644
index 00000000..3655473b
--- /dev/null
+++ b/app/Traits/Translations.php
@@ -0,0 +1,41 @@
+getAlias() : $alias;
+
+ return $alias === 'core' ? base_path() : module_path($alias);
+ }
+
+ /**
+ * delete the files.
+ */
+ public function deleteFiles(array $files, $alias = ''): void
+ {
+ $path = $this->getPathByAlias($alias);
+
+ foreach ($files as $file) {
+ File::delete($path . '/' . $file);
+ }
+ }
+
+ /**
+ * delete the folders.
+ */
+ public function deleteFolders(array $folders, $alias = ''): void
+ {
+ $path = $this->getPathByAlias($alias);
+
+ foreach ($folders as $folder) {
+ File::deleteDirectory($path . '/' . $folder);
+ }
+ }
+
+ /**
+ * Run single migration.
+ */
+ public function runMigration(string $file_name, $alias = ''): void
+ {
+ $path = $this->getPathByAlias($alias);
+
+ $semi_path = str($path)->contains('modules') ? '/Database/Migrations/' : '/database/migrations/';
+
+ $migration_file = $path . $semi_path . $file_name . '.php';
+
+ if (File::missing($migration_file)) {
+ return;
+ }
+
+ $migration_file = str($migration_file)->replace(base_path(), '');
+
+ Artisan::call('migrate', ['--force' => true, '--path' => $migration_file]);
+ }
+
+ /**
+ * Run multiple migrations.
+ */
+ public function runMigrations(array $file_names, $alias = ''): void
+ {
+ foreach ($file_names as $file_name) {
+ $this->runMigration($file_name, $alias);
+ }
+ }
+}
diff --git a/app/Traits/Uploads.php b/app/Traits/Uploads.php
new file mode 100644
index 00000000..d75ca972
--- /dev/null
+++ b/app/Traits/Uploads.php
@@ -0,0 +1,216 @@
+isValid()) {
+ return $path;
+ }
+
+ $this->validateUploadedFile($file);
+
+ $path = $this->getMediaFolder($folder, $company_id);
+
+ $file_name = $this->getMediaFileName($file);
+
+ return MediaUploader::makePrivate()
+ ->beforeSave(function(MediaModel $media) {
+ $media->company_id = company_id();
+ $media->created_from = source_name();
+ $media->created_by = user_id();
+ })
+ ->fromSource($file)
+ ->toDirectory($path)
+ ->useFilename($file_name)
+ ->upload();
+ }
+
+ public function importMedia($file, $folder = 'settings', $company_id = null, $disk = null)
+ {
+ $path = '';
+
+ if (! $disk) {
+ $disk = config('mediable.default_disk');
+ }
+
+ $this->validateImportedFilePath($file);
+
+ $path = $this->getMediaFolder($folder, $company_id) . '/' . basename($file);
+
+ return MediaUploader::makePrivate()
+ ->beforeSave(function(MediaModel $media) {
+ $media->company_id = company_id();
+ $media->created_from = source_name();
+ $media->created_by = user_id();
+ })
+ ->importPath($disk, $path);
+ }
+
+ public function deleteMediaModel($model, $parameter, $request = null)
+ {
+ $medias = $model->$parameter;
+
+ if (! $medias) {
+ return;
+ }
+
+ $multiple = true;
+
+ if ($medias instanceof \App\Models\Common\Media) {
+ $multiple = false;
+
+ $medias = [$medias];
+ }
+
+ $already_uploaded = [];
+
+ if ($request && isset($request['uploaded_' . $parameter])) {
+ $uploaded = ($multiple) ? $request['uploaded_' . $parameter] : [$request['uploaded_' . $parameter]];
+
+ if (count($medias) == count($uploaded)) {
+ return;
+ }
+
+ foreach ($uploaded as $old_media) {
+ $already_uploaded[] = $old_media['id'];
+ }
+ }
+
+ foreach ((array) $medias as $media) {
+ if (in_array($media->id, $already_uploaded)) {
+ continue;
+ }
+
+ MediaModel::where('id', $media->id)->delete();
+ }
+ }
+
+ public function getMediaFolder($folder, $company_id = null)
+ {
+ if (! $company_id) {
+ $company_id = company_id();
+ }
+
+ $date = Date::now()->format('Y/m/d');
+
+ // 2021/04/09/34235/invoices
+ return $date . '/' . $company_id . '/' . $folder;
+ }
+
+ public function getMediaPathOnStorage($media)
+ {
+ if (! is_object($media)) {
+ return false;
+ }
+
+ $path = $media->getDiskPath();
+
+ if (! $media->fileExists()) {
+ return false;
+ }
+
+ return $path;
+ }
+
+ public function streamMedia($media, $disposition = 'attachment')
+ {
+ return response()->streamDownload(
+ function() use ($media) {
+ $stream = $media->stream();
+
+ while ($bytes = $stream->read(1024)) {
+ echo $bytes;
+ }
+ },
+ $media->basename,
+ [
+ 'Content-Type' => $media->mime_type,
+ 'Content-Length' => $media->size,
+ ],
+ $disposition,
+ );
+ }
+
+ public function isLocalStorage()
+ {
+ return config('filesystems.disks.' . config('filesystems.default') . '.driver') == 'local';
+ }
+
+ public function getMediaFileName($file): string
+ {
+ $file_name = $this->filename($file);
+
+ if (Str::length($file_name) > '110') {
+ $file_name = Str::limit($file_name, 110);
+ }
+
+ return $file_name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function filename($file): string
+ {
+ return pathinfo((string)$file->getClientOriginalName(), PATHINFO_FILENAME);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function extension($file): string
+ {
+ $extension = $file->getClientOriginalExtension();
+
+ if ($extension) {
+ return $extension;
+ }
+
+ return (string)$file->guessExtension();
+ }
+
+ protected function validateUploadedFile($file): void
+ {
+ $mimes = (string) config('filesystems.mimes');
+ $maxSize = (int) config('filesystems.max_size') * 1024;
+
+ $validator = validator(
+ ['file' => $file],
+ ['file' => 'file|mimes:' . $mimes . '|max:' . $maxSize]
+ );
+
+ if ($validator->fails()) {
+ throw ValidationException::withMessages([
+ 'file' => $validator->errors()->first('file'),
+ ]);
+ }
+ }
+
+ protected function validateImportedFilePath($file): void
+ {
+ $extension = Str::lower(pathinfo((string) $file, PATHINFO_EXTENSION));
+
+ $allowed = collect(explode(',', (string) config('filesystems.mimes')))
+ ->map(fn ($mime) => Str::lower(trim($mime)))
+ ->filter()
+ ->values()
+ ->all();
+
+ if (empty($extension) || ! in_array($extension, $allowed, true)) {
+ throw ValidationException::withMessages([
+ 'file' => trans('validation.mimes', ['values' => implode(', ', $allowed)]),
+ ]);
+ }
+ }
+}
diff --git a/app/Traits/Users.php b/app/Traits/Users.php
new file mode 100644
index 00000000..8db6c27b
--- /dev/null
+++ b/app/Traits/Users.php
@@ -0,0 +1,138 @@
+runningInConsole() ? true : false;
+ }
+
+ $company = $user->withoutEvents(function () use ($user, $id) {
+ return $user->companies()->where('id', $id)->first();
+ });
+
+ return !empty($company);
+ }
+
+ public function isNotUserCompany($id)
+ {
+ return !$this->isUserCompany($id);
+ }
+
+ /**
+ * Check user dashboard assignment
+ *
+ * @param $id
+ *
+ * @return boolean
+ */
+ public function isUserDashboard($id)
+ {
+ $user = user();
+
+ if (empty($user)) {
+ return app()->runningInConsole() ? true : false;
+ }
+
+ $dashboard = $user->withoutEvents(function () use ($user, $id) {
+ return $user->dashboards()->where('id', $id)->first();
+ });
+
+ return !empty($dashboard);
+ }
+
+ public function isNotUserDashboard($id)
+ {
+ return !$this->isUserDashboard($id);
+ }
+
+ /**
+ * Get the fist company of active user
+ *
+ * @return null|\App\Models\Common\Company
+ */
+ public function getFirstCompanyOfUser()
+ {
+ $user = user();
+
+ if (empty($user)) {
+ return null;
+ }
+
+ $company = $user->withoutEvents(function () use ($user) {
+ return $user->companies()->enabled()->first();
+ });
+
+ if (empty($company)) {
+ return null;
+ }
+
+ return $company;
+ }
+
+ public function getLandingPageOfUser()
+ {
+ $user = user();
+
+ if (empty($user)) {
+ return route('login');
+ }
+
+ $route_name = $user->isCustomer()
+ ? 'portal.dashboard'
+ : (Route::has($user->landing_page) ? $user->landing_page : 'dashboard');
+
+ $company_id = company_id() ?: $this->getFirstCompanyOfUser()?->id;
+
+ if (empty($company_id)) {
+ return route('login');
+ }
+
+ return route($route_name, ['company_id' => $company_id]);
+ }
+
+ /**
+ * Checks if the given user has a pending invitation.
+ *
+ * @return bool
+ */
+ public function hasPendingInvitation()
+ {
+ return $this->getPendingInvitation() ? true : false;
+ }
+
+ /**
+ * Returns if the given user has a pending invitation.
+ *
+ * @return null|UserInvitation
+ */
+ public function getPendingInvitation()
+ {
+ return UserInvitation::where('user_id', $this->id)->first();
+ }
+}
diff --git a/app/Traits/ViewComponents.php b/app/Traits/ViewComponents.php
new file mode 100644
index 00000000..3f9e4e4a
--- /dev/null
+++ b/app/Traits/ViewComponents.php
@@ -0,0 +1,746 @@
+ $value) {
+ if (in_array($key, $excludes)) {
+ continue;
+ }
+
+ $this->{$key} = $this->getParentData($key, $value);
+ }
+ }
+
+ public function getTextFromConfig($type, $config_key, $default_key = '', $trans_type = 'trans')
+ {
+ $translation = '';
+
+ // if set config translation config_key
+ if ($translation = config('type.' . static::OBJECT_TYPE . '.' . $type . '.translation.' . $config_key)) {
+ return $translation;
+ }
+
+ $alias = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias');
+ $prefix = config('type.' . static::OBJECT_TYPE . '.' . $type . '.translation.prefix');
+
+ if (! empty($alias)) {
+ $alias .= '::';
+ }
+
+ // This magic trans key..
+ $translations = [
+ 'general' => $alias . 'general.' . $default_key,
+ 'prefix' => $alias . $prefix . '.' . $default_key,
+ 'config_general' => $alias . 'general.' . $config_key,
+ 'config_prefix' => $alias . $prefix . '.' . $config_key,
+ ];
+
+ switch ($trans_type) {
+ case 'trans':
+ foreach ($translations as $trans) {
+ if (is_string(trans($trans)) && trans($trans) !== $trans) {
+ return $trans;
+ }
+ }
+
+ break;
+ case 'trans_choice':
+ foreach ($translations as $trans_choice) {
+ if (is_string(trans($trans_choice)) && trans_choice($trans_choice, 1) !== $trans_choice) {
+ return $trans_choice;
+ }
+ }
+
+ break;
+ }
+
+ return $translation;
+ }
+
+ public function getRouteFromConfig($type, $config_key, $config_parameters = [], $modal = false)
+ {
+ $route = '';
+
+ // if set config translation config_key
+ if ($route = config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.' . $config_key)) {
+ return $route;
+ }
+
+ $alias = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias');
+ $prefix = config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.prefix');
+
+ // if use module set module alias
+ if (! empty($alias)) {
+ $route .= $alias . '.';
+ }
+
+ if ($modal == true) {
+ $route .= 'modals.';
+ }
+
+ if (! empty($prefix)) {
+ $route .= $prefix . '.';
+ }
+
+ $route .= $config_key;
+
+ try {
+ route($route, $config_parameters);
+ } catch (\Exception $e) {
+ try {
+ $route = Str::plural($type, 2) . '.' . $config_key;
+
+ route($route, $config_parameters);
+ } catch (\Exception $e) {
+ $route = '';
+ }
+ }
+
+ return $route;
+ }
+
+ public function getRouteParamsFromConfig($type, $config_key)
+ {
+ $params = config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.params.' . $config_key, []);
+
+ return $params;
+ }
+
+ public function getPermissionFromConfig($type, $config_key)
+ {
+ $permission = '';
+
+ // if set config translation config_key
+ if ($permission = config('type.' . static::OBJECT_TYPE . '.' . $type . '.permission.' . $config_key)) {
+ return $permission;
+ }
+
+ $alias = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias');
+ $group = config('type.' . static::OBJECT_TYPE . '.' . $type . '.group');
+ $prefix = config('type.' . static::OBJECT_TYPE . '.' . $type . '.permission.prefix');
+
+ $permission = $config_key . '-';
+
+ // if use module set module alias
+ if (! empty($alias)) {
+ $permission .= $alias . '-';
+ }
+
+ // if controller in folder it must
+ if (! empty($group)) {
+ $permission .= $group . '-';
+ }
+
+ $permission .= $prefix;
+
+ return $permission;
+ }
+
+ public function getHideFromConfig($type, $config_key)
+ {
+ $hide = false;
+
+ $hides = config('type.' . static::OBJECT_TYPE . '.' . $type . '.hide');
+
+ if (! empty($hides) && (in_array($config_key, $hides))) {
+ $hide = true;
+ }
+
+ return $hide;
+ }
+
+ public function getClassFromConfig($type, $config_key)
+ {
+ $class_key = 'type.' . $type . '.class.' . $config_key;
+
+ return config($class_key, '');
+ }
+
+ public function getCategoryFromConfig($type)
+ {
+ $category_type = '';
+
+ // if set config translation config_key
+ if ($category_type = config('type.' . static::OBJECT_TYPE . '.' . $type . '.category_type')) {
+ return $category_type;
+ }
+
+ switch ($type) {
+ case 'bill':
+ case 'expense':
+ case 'purchase':
+ $category_type = Category::EXPENSE_TYPE;
+ break;
+ case 'item':
+ $category_type = Category::ITEM_TYPE;
+ break;
+ case 'other':
+ $category_type = Category::OTHER_TYPE;
+ break;
+ case 'transfer':
+ $category_type = 'transfer';
+ break;
+ default:
+ $category_type = Category::INCOME_TYPE;
+ break;
+ }
+
+ return $category_type;
+ }
+
+ public function getScriptFromConfig($type, $config_key)
+ {
+ $script_key = config('type.' . static::OBJECT_TYPE . '.' . $type . '.script.' . $config_key, '');
+
+ return $script_key;
+ }
+
+ public function getTabActiveFromSetting($type)
+ {
+ $tabs = setting('favorites.tab.' . user()->id, []);
+
+ if (empty($tabs)) {
+ return false;
+ }
+
+ $tabs = json_decode($tabs, true);
+
+ return $tabs[$type] ?? false;
+ }
+
+ protected function getTextPage($type, $textPage)
+ {
+ if (! empty($textPage)) {
+ return $textPage;
+ }
+
+ $config_route_prefix = config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.prefix', static::DEFAULT_PLURAL_TYPE);
+
+ $page = str_replace('-', '_', $config_route_prefix);
+
+ $translation = $this->getTextFromConfig($type, 'page', $page);
+
+ if (! empty($translation)) {
+ return $translation;
+ }
+
+ return 'general.' . $page;
+ }
+
+ protected function getGroup($type, $group)
+ {
+ if (! empty($group)) {
+ return $group;
+ }
+
+ return config('type.' . static::OBJECT_TYPE . '.' . $type . '.group', static::DEFAULT_PLURAL_TYPE);
+ }
+
+ protected function getPage($type, $page)
+ {
+ if (! empty($page)) {
+ return $page;
+ }
+
+ return Str::plural($type);
+ }
+
+ protected function getPermissionCreate($type, $permissionCreate)
+ {
+ if (! empty($permissionCreate)) {
+ return $permissionCreate;
+ }
+
+ $permissionCreate = $this->getPermissionFromConfig($type, 'create');
+
+ return $permissionCreate;
+ }
+
+ protected function getPermissionUpdate($type, $permissionUpdate)
+ {
+ if (! empty($permissionUpdate)) {
+ return $permissionUpdate;
+ }
+
+ $permissionUpdate = $this->getPermissionFromConfig($type, 'update');
+
+ return $permissionUpdate;
+ }
+
+ protected function getPermissionDelete($type, $permissionDelete)
+ {
+ if (! empty($permissionDelete)) {
+ return $permissionDelete;
+ }
+
+ $permissionDelete = $this->getPermissionFromConfig($type, 'delete');
+
+ return $permissionDelete;
+ }
+
+ protected function getIndexRoute($type, $indexRoute)
+ {
+ if (! empty($indexRoute)) {
+ return $indexRoute;
+ }
+
+ $route = $this->getRouteFromConfig($type, 'index');
+
+ if (!empty($route)) {
+ return $route;
+ }
+
+ return static::DEFAULT_PLURAL_TYPE . '.index';
+ }
+
+ protected function getShowRoute($type, $showRoute)
+ {
+ if (! empty($showRoute)) {
+ return $showRoute;
+ }
+
+ $route = $this->getRouteFromConfig($type, 'show', 1);
+
+ if (!empty($route)) {
+ return $route;
+ }
+
+ return static::DEFAULT_PLURAL_TYPE . '.show';
+ }
+
+ protected function getCreateRoute($type, $createRoute)
+ {
+ if (! empty($createRoute)) {
+ return $createRoute;
+ }
+
+ $route = $this->getRouteFromConfig($type, 'create');
+
+ if (! empty($route)) {
+ return $route;
+ }
+
+ return static::DEFAULT_PLURAL_TYPE . '.create';
+ }
+
+ protected function getEditRoute($type, $editRoute)
+ {
+ if (! empty($editRoute)) {
+ return $editRoute;
+ }
+
+ $route = $this->getRouteFromConfig($type, 'edit', 1);
+
+ if (! empty($route)) {
+ return $route;
+ }
+
+ return static::DEFAULT_PLURAL_TYPE . '.edit';
+ }
+
+ protected function getDuplicateRoute($type, $duplicateRoute)
+ {
+ if (! empty($duplicateRoute)) {
+ return $duplicateRoute;
+ }
+
+ $route = $this->getRouteFromConfig($type, 'duplicate', 1);
+
+ if (! empty($route)) {
+ return $route;
+ }
+
+ return static::DEFAULT_PLURAL_TYPE . '.duplicate';
+ }
+
+ protected function getDeleteRoute($type, $deleteRoute)
+ {
+ if (! empty($deleteRoute)) {
+ return $deleteRoute;
+ }
+
+ $route = $this->getRouteFromConfig($type, 'destroy', 1);
+
+ if (! empty($route)) {
+ return $route;
+ }
+
+ return static::DEFAULT_PLURAL_TYPE . '.destroy';
+ }
+
+ protected function getCancelRoute($type, $cancelRoute)
+ {
+ if (! empty($cancelRoute)) {
+ return $cancelRoute;
+ }
+
+ $route = $this->getRouteFromConfig($type, 'index');
+
+ if (! empty($route)) {
+ return $route;
+ }
+
+ return static::DEFAULT_PLURAL_TYPE . '.index';
+ }
+
+ protected function getImportRoute($importRoute)
+ {
+ if (! empty($importRoute)) {
+ return $importRoute;
+ }
+
+ $route = 'import.create';
+
+ return $route;
+ }
+
+ protected function getImportRouteParameters($type, $importRouteParameters)
+ {
+ if (! empty($importRouteParameters)) {
+ return $importRouteParameters;
+ }
+
+ $alias = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias');
+ $group = config('type.' . static::OBJECT_TYPE . '.' . $type . '.group');
+ $prefix = config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.prefix');
+
+ if (empty($group) && ! empty($alias)){
+ $group = $alias;
+ } else if (empty($group) && empty($alias)) {
+ $group = 'sales';
+ }
+
+ $importRouteParameters = [
+ 'group' => $group,
+ 'type' => $prefix,
+ ];
+
+ return $importRouteParameters;
+ }
+
+ protected function getExportRoute($type, $exportRoute)
+ {
+ if (! empty($exportRoute)) {
+ return $exportRoute;
+ }
+
+ $route = $this->getRouteFromConfig($type, 'export');
+
+ if (! empty($route)) {
+ return $route;
+ }
+
+ return static::DEFAULT_PLURAL_TYPE . '.export';
+ }
+
+ protected function getSearchStringModel($type, $searchStringModel)
+ {
+ if (! empty($searchStringModel)) {
+ return $searchStringModel;
+ }
+
+ $search_string_model = config('type.' . static::OBJECT_TYPE . '.' . $type . '.search_string_model');
+
+ if (! empty($search_string_model)) {
+ return $search_string_model;
+ }
+
+ if ($group = config('type.' . static::OBJECT_TYPE . '.' . $type . '.group')) {
+ $group = Str::studly(Str::singular($group)) . '\\';
+ }
+
+ $prefix = Str::studly(Str::singular(config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.prefix')));
+
+ if ($alias = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias')) {
+ $searchStringModel = 'Modules\\' . Str::studly($alias) .'\Models\\' . $group . $prefix;
+ } else {
+ $searchStringModel = 'App\Models\\' . $group . $prefix;
+ }
+
+ return $searchStringModel;
+ }
+
+ protected function getBulkActionClass($type, $bulkActionClass)
+ {
+ if (! empty($bulkActionClass)) {
+ return $bulkActionClass;
+ }
+
+ $bulk_actions = config('type.' . static::OBJECT_TYPE . '.' . $type . '.bulk_actions');
+
+ if (! empty($bulk_actions)) {
+ return $bulk_actions;
+ }
+
+ $file_name = '';
+
+ if ($group = config('type.' . static::OBJECT_TYPE . '.' . $type . '.group')) {
+ $file_name .= Str::studly($group) . '\\';
+ }
+
+ if ($prefix = config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.prefix')) {
+ $file_name .= Str::studly($prefix);
+ }
+
+ if ($alias = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias')) {
+ $module = module($alias);
+
+ if (! $module instanceof Module) {
+ $b = new \stdClass();
+ $b->actions = [];
+
+ event(new BulkActionsAdding($b));
+
+ return $b->actions;
+ }
+
+ $bulkActionClass = 'Modules\\' . $module->getStudlyName() . '\BulkActions\\' . $file_name;
+ } else {
+ $bulkActionClass = 'App\BulkActions\\' . $file_name;
+ }
+
+ return $bulkActionClass;
+ }
+
+ protected function getBulkActionRouteParameters($type, $bulkActionRouteParameters)
+ {
+ if (! empty($bulkActionRouteParameters)) {
+ return $bulkActionRouteParameters;
+ }
+
+ $group = config('type.' . static::OBJECT_TYPE . '.' . $type . '.group');
+
+ if (! empty(config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias'))) {
+ $group = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias');
+ }
+
+ $bulkActionRouteParameters = [
+ 'group' => $group,
+ 'type' => config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.prefix')
+ ];
+
+ return $bulkActionRouteParameters;
+ }
+
+ protected function getClassBulkAction($type, $classBulkAction)
+ {
+ if (! empty($classBulkAction)) {
+ return $classBulkAction;
+ }
+
+ $class = $this->getClassFromConfig($type, 'bulk_action');
+
+ if (! empty($class)) {
+ return $class;
+ }
+
+ return 'ltr:pr-6 rtl:pl-6 hidden sm:table-cell';
+ }
+
+ protected function getImageEmptyPage($type, $imageEmptyPage)
+ {
+ if (! empty($imageEmptyPage)) {
+ return $imageEmptyPage;
+ }
+
+ $image_empty_page = config('type.' . static::OBJECT_TYPE . '.' . $type . '.image_empty_page');
+
+ if (! empty($image_empty_page)) {
+ return $image_empty_page;
+ }
+
+ $page = str_replace('-', '_', config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.prefix', 'invoices'));
+ $image_path = 'public/img/empty_pages/' . $page . '.png';
+
+ if ($alias = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias')) {
+ $image_path = 'modules/' . Str::studly($alias) . '/Resources/assets/img/empty_pages/' . $page . '.png';
+ }
+
+ return $image_path;
+ }
+
+ protected function getTextEmptyPage($type, $textEmptyPage)
+ {
+ if (! empty($textEmptyPage)) {
+ return $textEmptyPage;
+ }
+
+ $page = str_replace('-', '_', config('type.' . static::OBJECT_TYPE . '.' . $type . '.route.prefix', 'invoices'));
+
+ $translation = $this->getTextFromConfig($type, 'empty_page', 'empty.' . $page);
+
+ if (! empty($translation)) {
+ return $translation;
+ }
+
+ return 'general.empty.' . $page;
+ }
+
+ protected function getTextSectionTitle($type, $key, $default_key = '')
+ {
+ $translation = $this->getTextFromConfig($type, 'section_'. $key . '_title', $key);
+
+ if (! empty($translation)) {
+ return $translation;
+ }
+
+ if ($default_key) {
+ return $default_key;
+ }
+
+ return 'general.' . $key;
+ }
+
+ protected function getTextSectionDescription($type, $key, $default_key = '')
+ {
+ $translation = $this->getTextFromConfig($type, 'section_'. $key . '_description', 'form_description.' . $key);
+
+ if (! empty($translation)) {
+ return $translation;
+ }
+
+ if ($default_key) {
+ return $default_key;
+ }
+
+ return 'general.form_description.' . $key;
+ }
+
+ protected function getUrlDocsPath($type, $urlDocsPath)
+ {
+ return null;
+ }
+
+ public function getSuggestionModule()
+ {
+ return !empty($this->suggestions) ? Arr::random($this->suggestions) : false;
+ }
+
+ public function getSuggestionModules()
+ {
+ if ((! $user = user()) || $user->cannot('read-modules-home')) {
+ return [];
+ }
+
+ if (! $path = Route::current()->uri()) {
+ return [];
+ }
+
+ $path = str_replace('{company_id}/', '', $path);
+
+ if (! $suggestions = $this->getSuggestions($path)) {
+ return [];
+ }
+
+ $modules = [];
+
+ foreach ($suggestions->modules as $s_module) {
+ if ($this->moduleIsEnabled($s_module->alias)) {
+ continue;
+ }
+
+ $s_module->action_url = company_id() . '/' . $s_module->action_url;
+
+ $modules[] = $s_module;
+ }
+
+ if (empty($modules)) {
+ return [];
+ }
+
+ return $modules;
+ }
+
+ protected function getFormRoute($type, $formRoute, $model = false)
+ {
+ if (! empty($formRoute)) {
+ return $formRoute;
+ }
+
+ $prefix = 'store';
+ $parameters = [];
+
+ if (! empty($model)) {
+ $prefix = 'update';
+ $parameters = [$model->id];
+ }
+
+ $route = $this->getRouteFromConfig($type, $prefix, $parameters);
+
+ return (! empty($model)) ? [$route, $model->id] : $route;
+ }
+
+ protected function getFormMethod($type, $formMethod, $model = false)
+ {
+ if (! empty($formMethod)) {
+ return $formMethod;
+ }
+
+ $method = 'POST';
+
+ if (! empty($model)) {
+ $method = 'PATCH';
+ }
+
+ return $method;
+ }
+
+ protected function getAlias($type, $alias)
+ {
+ if (!empty($alias)) {
+ return $alias;
+ }
+
+ if ($alias = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias')) {
+ return $alias;
+ }
+
+ return 'core';
+ }
+
+ protected function getScriptFolder($type, $folder)
+ {
+ if (!empty($folder)) {
+ return $folder;
+ }
+
+ if ($folder = config('type.' . static::OBJECT_TYPE . '.' . $type . '.script.folder')) {
+ return $folder;
+ }
+
+ return '';
+ }
+
+ protected function getScriptFile($type, $file)
+ {
+ if (!empty($file)) {
+ return $file;
+ }
+
+ if ($file = config('type.' . static::OBJECT_TYPE . '.' . $type . '.script.file')) {
+ return $file;
+ }
+
+ return '';
+ }
+}
diff --git a/app/Utilities/BusinessNavigation.php b/app/Utilities/BusinessNavigation.php
new file mode 100644
index 00000000..6aeb952a
--- /dev/null
+++ b/app/Utilities/BusinessNavigation.php
@@ -0,0 +1,39 @@
+ $page) {
+ $section['pages'][$pageIndex]['title'] = self::title(
+ $pageTitles[$sectionSlug][$page['slug']] ?? null,
+ $page['title']
+ );
+ }
+ }
+ unset($section);
+
+ return $navigation;
+ }
+
+ private static function title($value, string $default): string
+ {
+ $value = trim((string) $value);
+
+ return $value === '' ? $default : $value;
+ }
+}
diff --git a/app/Utilities/Console.php b/app/Utilities/Console.php
new file mode 100644
index 00000000..b98392f7
--- /dev/null
+++ b/app/Utilities/Console.php
@@ -0,0 +1,56 @@
+setTimeout($timeout);
+
+ $process->mustRun();
+
+ $output = $process->getOutput();
+
+ if (static::isValidOutput($output)) {
+ return true;
+ }
+ } catch (Throwable $e) {
+ $output = $e->getMessage();
+ }
+
+ logger('Console output:: ' . $output);
+
+ return static::formatOutput($output);
+ }
+
+ public static function formatOutput($output)
+ {
+ $output = nl2br($output);
+ $output = str_replace(['"', "'"], '', $output);
+ $output = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $output);
+
+ return $output;
+ }
+
+ public static function isValidOutput($output)
+ {
+ $errors = [
+ 'Content-Type: application/json',
+ 'CSRF token mismatch',
+ ];
+
+ return !Str::contains($output, $errors);
+ }
+}
diff --git a/app/Utilities/Date.php b/app/Utilities/Date.php
new file mode 100644
index 00000000..059821fa
--- /dev/null
+++ b/app/Utilities/Date.php
@@ -0,0 +1,140 @@
+bound('translator')) {
+ $appLocale = app()->getLocale();
+ }
+
+ if (app()->bound('config')) {
+ $fallbackLocale = app('config')->get('app.fallback_locale');
+ }
+ } catch (\Throwable $e) {
+ }
+ }
+
+ $candidates = array_merge(
+ $locales,
+ [static::getLocale()],
+ [$appLocale],
+ [$fallbackLocale],
+ ['en']
+ );
+
+ $normalized = [];
+
+ foreach ($candidates as $locale) {
+ if (empty($locale)) {
+ continue;
+ }
+
+ $normalized[] = $locale;
+
+ $language = static::getLanguageFromLocale($locale);
+
+ if ($language !== $locale) {
+ $normalized[] = $language;
+ }
+ }
+
+ return array_values(array_unique($normalized));
+ }
+}
diff --git a/app/Utilities/DocumentNumber.php b/app/Utilities/DocumentNumber.php
new file mode 100644
index 00000000..7275028e
--- /dev/null
+++ b/app/Utilities/DocumentNumber.php
@@ -0,0 +1,39 @@
+resolveTypeAlias($type);
+
+ $prefix = setting($type . '.number_prefix');
+ $next = (string) setting($type . '.number_next');
+ $digit = (int) setting($type . '.number_digit');
+
+ return $prefix . str_pad($next, $digit, '0', STR_PAD_LEFT);
+ }
+
+ public function increaseNextNumber(string $type, ?Contact $contact): void
+ {
+ $type = $this->resolveTypeAlias($type);
+
+ $next = setting($type . '.number_next', 1) + 1;
+
+ setting([$type . '.number_next' => $next]);
+ setting()->save();
+ }
+
+ protected function resolveTypeAlias(string $type): string
+ {
+ if ($alias = config('type.document.' . $type . '.alias')) {
+ return $alias . '.' . str_replace('-', '_', $type);
+ }
+
+ return $type;
+ }
+}
diff --git a/app/Utilities/Export.php b/app/Utilities/Export.php
new file mode 100644
index 00000000..cf4ff8d0
--- /dev/null
+++ b/app/Utilities/Export.php
@@ -0,0 +1,57 @@
+ids) && method_exists($class, 'sheets') && is_array($sheets = $class->sheets())) {
+ $class->ids = ! empty($ids = (new $sheets[array_key_first($sheets)])->collection()->pluck('id')->toArray()) ? $ids : [0];
+ }
+
+ if (should_queue()) {
+ $disk = 'temp';
+
+ if (config('excel.temporary_files.remote_disk') !== null) {
+ $disk = config('excel.temporary_files.remote_disk');
+ $file_name = config('excel.temporary_files.remote_prefix') . $file_name;
+ }
+
+ $class->queue($file_name, $disk)->onQueue('exports')->chain([
+ new CreateMediableForExport(user(), $file_name, $translation),
+ ]);
+
+ $message = trans('messages.success.export_queued', ['type' => $translation]);
+
+ flash($message)->success();
+
+ return back();
+ } else {
+ return $class->download($file_name);
+ }
+ } catch (Throwable $e) {
+ report($e);
+ flash($e->getMessage())->error()->important();
+
+ return back();
+ }
+ }
+}
diff --git a/app/Utilities/FundAccountSpreadsheet.php b/app/Utilities/FundAccountSpreadsheet.php
new file mode 100644
index 00000000..18860ebb
--- /dev/null
+++ b/app/Utilities/FundAccountSpreadsheet.php
@@ -0,0 +1,297 @@
+ 'company_name',
+ '银行名称' => 'bank_name',
+ '银行类型' => 'bank_type',
+ '账户账号' => 'account_number',
+ '预留手机号' => 'reserved_phone',
+ '登录密码' => 'login_password',
+ '备注' => 'notes',
+ ];
+
+ private const STORE_COLUMNS = [
+ '公司名称' => 'company_name',
+ '账户名称' => 'account_name',
+ '账户账号' => 'account_number',
+ '预留手机号' => 'reserved_phone',
+ '登录密码' => 'login_password',
+ '备注' => 'notes',
+ ];
+
+ public function downloadTemplate(string $platform): StreamedResponse
+ {
+ $spreadsheet = $this->makeSpreadsheet($platform, collect());
+ $filename = $this->title($platform) . '-导入模板.xlsx';
+
+ return $this->download($spreadsheet, $filename);
+ }
+
+ public function downloadAccounts(string $platform, Collection $accounts): StreamedResponse
+ {
+ $spreadsheet = $this->makeSpreadsheet($platform, $accounts);
+ $filename = $this->title($platform) . '-批量数据-' . now()->format('Ymd-His') . '.xlsx';
+
+ return $this->download($spreadsheet, $filename);
+ }
+
+ public function import(string $platform, UploadedFile $file): int
+ {
+ try {
+ return $this->readAndStore($platform, $file);
+ } catch (ValidationException $exception) {
+ throw $exception;
+ } catch (Throwable $exception) {
+ report($exception);
+
+ throw ValidationException::withMessages([
+ 'import' => trans('fund_accounts.import_invalid_file'),
+ ]);
+ }
+ }
+
+ private function makeSpreadsheet(string $platform, Collection $accounts): Spreadsheet
+ {
+ $spreadsheet = new Spreadsheet();
+ $sheet = $spreadsheet->getActiveSheet();
+ $columns = $this->columns($platform);
+ $columnCount = count($columns);
+ $lastColumn = Coordinate::stringFromColumnIndex($columnCount);
+
+ $sheet->setTitle(mb_substr($this->title($platform), 0, 31));
+ $sheet->freezePane('A2');
+ $sheet->setAutoFilter("A1:{$lastColumn}1");
+ $sheet->getRowDimension(1)->setRowHeight(26);
+
+ foreach (array_keys($columns) as $index => $heading) {
+ $column = Coordinate::stringFromColumnIndex($index + 1);
+ $sheet->setCellValueExplicit("{$column}1", $heading, DataType::TYPE_STRING);
+ }
+
+ $header = $sheet->getStyle("A1:{$lastColumn}1");
+ $header->getFont()->setBold(true)->getColor()->setARGB('FFFFFFFF');
+ $header->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setARGB('FF4F7D3B');
+ $header->getAlignment()->setVertical('center');
+
+ foreach ($accounts->values() as $rowIndex => $account) {
+ $excelRow = $rowIndex + 2;
+
+ foreach (array_values($columns) as $columnIndex => $field) {
+ $column = Coordinate::stringFromColumnIndex($columnIndex + 1);
+ $value = $account->{$field};
+
+ $sheet->setCellValueExplicit(
+ "{$column}{$excelRow}",
+ is_null($value) ? '' : (string) $value,
+ DataType::TYPE_STRING
+ );
+ }
+ }
+
+ foreach (array_values($columns) as $index => $field) {
+ $column = Coordinate::stringFromColumnIndex($index + 1);
+ $sheet->getColumnDimension($column)->setWidth($this->columnWidth($field));
+ $sheet->getStyle("{$column}2:{$column}" . (self::MAX_ROWS + 1))
+ ->getNumberFormat()
+ ->setFormatCode(NumberFormat::FORMAT_TEXT);
+ }
+
+ return $spreadsheet;
+ }
+
+ private function readAndStore(string $platform, UploadedFile $file): int
+ {
+ $reader = IOFactory::createReaderForFile($file->getRealPath());
+ $reader->setReadDataOnly(true);
+
+ $spreadsheet = $reader->load($file->getRealPath());
+
+ try {
+ $sheet = $spreadsheet->getActiveSheet();
+ $columns = $this->columns($platform);
+ $expectedHeadings = array_keys($columns);
+ $actualHeadings = [];
+
+ foreach ($expectedHeadings as $index => $heading) {
+ $column = Coordinate::stringFromColumnIndex($index + 1);
+ $actualHeadings[] = trim($this->cellString($sheet->getCell("{$column}1")->getValue()));
+ }
+
+ if ($actualHeadings !== $expectedHeadings) {
+ throw ValidationException::withMessages([
+ 'import' => trans('fund_accounts.import_header_mismatch', [
+ 'headers' => implode('、', $expectedHeadings),
+ ]),
+ ]);
+ }
+
+ $highestRow = $sheet->getHighestDataRow();
+
+ if ($highestRow > self::MAX_ROWS + 1) {
+ throw ValidationException::withMessages([
+ 'import' => trans('fund_accounts.import_too_many_rows', ['count' => self::MAX_ROWS]),
+ ]);
+ }
+
+ $rows = [];
+ $errors = [];
+ $fields = array_values($columns);
+ $attributes = array_flip($columns);
+
+ for ($excelRow = 2; $excelRow <= $highestRow; $excelRow++) {
+ $row = [];
+
+ foreach ($fields as $index => $field) {
+ $column = Coordinate::stringFromColumnIndex($index + 1);
+ $value = $this->cellString($sheet->getCell("{$column}{$excelRow}")->getValue());
+ $row[$field] = $field === 'login_password' ? $value : trim($value);
+ }
+
+ if ($this->rowIsEmpty($row)) {
+ continue;
+ }
+
+ $validator = Validator::make($row, $this->rules($platform), [], $attributes);
+
+ if ($validator->fails()) {
+ $errors[] = trans('fund_accounts.import_row_error', [
+ 'row' => $excelRow,
+ 'message' => $validator->errors()->first(),
+ ]);
+
+ continue;
+ }
+
+ $rows[] = $row;
+ }
+
+ if (! empty($errors)) {
+ throw ValidationException::withMessages(['import' => $errors]);
+ }
+
+ if (empty($rows)) {
+ throw ValidationException::withMessages([
+ 'import' => trans('fund_accounts.import_empty'),
+ ]);
+ }
+
+ DB::transaction(function () use ($platform, $rows) {
+ foreach ($rows as $row) {
+ if ($platform === 'bank') {
+ $row['account_name'] = $row['bank_name'];
+ } else {
+ $row['bank_name'] = null;
+ $row['bank_type'] = null;
+ }
+
+ FundAccount::create(array_merge($row, [
+ 'company_id' => company_id(),
+ 'platform' => $platform,
+ 'created_from' => 'core::import',
+ 'created_by' => user()->id,
+ ]));
+ }
+ });
+
+ return count($rows);
+ } finally {
+ $spreadsheet->disconnectWorksheets();
+ }
+ }
+
+ private function download(Spreadsheet $spreadsheet, string $filename): StreamedResponse
+ {
+ return response()->streamDownload(function () use ($spreadsheet) {
+ $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
+ $writer->setPreCalculateFormulas(false);
+ $writer->save('php://output');
+ $spreadsheet->disconnectWorksheets();
+ }, $filename, [
+ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'Cache-Control' => 'no-store, no-cache, must-revalidate',
+ ]);
+ }
+
+ private function columns(string $platform): array
+ {
+ return $platform === 'bank' ? self::BANK_COLUMNS : self::STORE_COLUMNS;
+ }
+
+ private function rules(string $platform): array
+ {
+ return [
+ 'company_name' => ['required', 'string', 'max:191'],
+ 'account_name' => [$platform === 'bank' ? 'nullable' : 'required', 'nullable', 'string', 'max:191'],
+ 'account_number' => ['required', 'string', 'max:191'],
+ 'bank_name' => [$platform === 'bank' ? 'required' : 'nullable', 'nullable', 'string', 'max:191'],
+ 'bank_type' => [$platform === 'bank' ? 'required' : 'nullable', 'nullable', 'string', 'max:191'],
+ 'login_password' => ['nullable', 'string', 'max:191'],
+ 'reserved_phone' => ['nullable', 'string', 'max:191'],
+ 'notes' => ['nullable', 'string', 'max:2000'],
+ ];
+ }
+
+ private function rowIsEmpty(array $row): bool
+ {
+ foreach ($row as $value) {
+ if ($value !== '') {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private function cellString(mixed $value): string
+ {
+ if ($value instanceof RichText) {
+ return $value->getPlainText();
+ }
+
+ if (is_null($value)) {
+ return '';
+ }
+
+ return (string) $value;
+ }
+
+ private function columnWidth(string $field): int
+ {
+ return match ($field) {
+ 'company_name', 'account_name', 'account_number', 'login_password' => 24,
+ 'bank_name' => 20,
+ 'bank_type', 'reserved_phone' => 18,
+ 'notes' => 36,
+ default => 16,
+ };
+ }
+
+ private function title(string $platform): string
+ {
+ $key = $platform === 'bank' ? 'bank_accounts' : $platform . '_accounts';
+
+ return trans('fund_accounts.' . $key);
+ }
+}
diff --git a/app/Utilities/Import.php b/app/Utilities/Import.php
new file mode 100644
index 00000000..ab7e9f2b
--- /dev/null
+++ b/app/Utilities/Import.php
@@ -0,0 +1,104 @@
+file('import');
+
+ if ($should_queue) {
+ self::importQueue($class, $file, $translation);
+ } else {
+ $class->import($file);
+ }
+
+ $message = trans(
+ 'messages.success.' . ($should_queue ? 'import_queued' : 'imported'),
+ ['type' => $translation]
+ );
+ } catch (Throwable $e) {
+ if (! $e instanceof SheetNotFoundException) {
+ report($e);
+ }
+
+ $message = self::flashFailures($e);
+
+ $success = false;
+ }
+
+ return [
+ 'success' => $success,
+ 'error' => ! $success,
+ 'data' => null,
+ 'message' => $message,
+ ];
+ }
+
+ /**
+ * Import the excel file
+ *
+ * @param AbstractsImport|ImportMultipleSheets $class
+ */
+ protected static function importQueue($class, $file, string $translation): void
+ {
+ $rows = $class->toArray($file);
+
+ $total_rows = 0;
+
+ if (! empty($rows[0])) {
+ $total_rows = count($rows[0]);
+ } else if (! empty($sheets = $class->sheets())) {
+ // The uploaded file's sheet names may not match the expected keys
+ // (e.g. a single-sheet file, or differently named sheets), so the
+ // expected key may be absent from $rows — default to 0 instead of
+ // crashing on an undefined array key.
+ $total_rows = count($rows[array_keys($sheets)[0]] ?? []);
+ }
+
+ $class->queue($file)->onQueue('imports')->chain([
+ new NotifyUser(user(), new ImportCompleted($translation, $total_rows))
+ ]);
+ }
+
+ protected static function flashFailures(Throwable $e): string
+ {
+ if (! $e instanceof ValidationException) {
+ return $e->getMessage();
+ }
+
+ foreach ($e->failures() as $failure) {
+ $message = trans('messages.error.import_column', [
+ 'message' => collect($failure->errors())->first(),
+ 'column' => $failure->attribute(),
+ 'line' => $failure->row(),
+ ]);
+
+ flash($message)->error()->important();
+ }
+
+ return '';
+ }
+}
diff --git a/app/Utilities/Info.php b/app/Utilities/Info.php
new file mode 100644
index 00000000..b93ec6f9
--- /dev/null
+++ b/app/Utilities/Info.php
@@ -0,0 +1,104 @@
+ static::getApiKey(),
+ 'ip' => static::ip(),
+ ];
+
+ if (! empty($info) || is_cloud()) {
+ if (is_cloud()) {
+ $basic['companies'] = 0;
+ }
+
+ return array_merge(static::versions(), $info, $basic);
+ }
+
+ $users_count = user_model_class()::query()->isNotCustomer()->count();
+
+ $info = array_merge(static::versions(), $basic, [
+ 'companies' => Company::count(),
+ 'users' => $users_count,
+ 'invoices' => Document::allCompanies()->invoice()->count(),
+ 'customers' => Contact::allCompanies()->customer()->count(),
+ 'php_extensions' => static::phpExtensions(),
+ ]);
+
+ return $info;
+ }
+
+ public static function versions()
+ {
+ static $versions = [];
+
+ if (! empty($versions)) {
+ return $versions;
+ }
+
+ $versions = [
+ 'akaunting' => Version::short(),
+ 'laravel' => InstalledVersions::getPrettyVersion('laravel/framework'),
+ 'php' => static::phpVersion(),
+ 'mysql' => static::mysqlVersion(),
+ 'guzzle' => InstalledVersions::getPrettyVersion('guzzlehttp/guzzle'),
+ 'livewire' => InstalledVersions::getPrettyVersion('livewire/livewire'),
+ 'omnipay' => InstalledVersions::getPrettyVersion('league/omnipay'),
+ ];
+
+ return $versions;
+ }
+
+ public static function phpVersion()
+ {
+ return phpversion();
+ }
+
+ public static function phpExtensions()
+ {
+ return get_loaded_extensions();
+ }
+
+ public static function mysqlVersion()
+ {
+ static $version;
+
+ if (empty($version) && (config('database.default') === 'mysql')) {
+ $version = DB::selectOne('select version() as mversion')->mversion;
+ }
+
+ if (isset($version)) {
+ return $version;
+ }
+
+ return 'N/A';
+ }
+
+ public static function ip()
+ {
+ return request()->header('CF_CONNECTING_IP')
+ ? request()->header('CF_CONNECTING_IP')
+ : request()->ip();
+ }
+
+ public static function getApiKey(): string
+ {
+ $setting = new class() { use Settings; };
+
+ return (string) ($setting->getSettingValue('apps.api_key', '') ?? '');
+ }
+}
diff --git a/app/Utilities/Installer.php b/app/Utilities/Installer.php
new file mode 100644
index 00000000..85331462
--- /dev/null
+++ b/app/Utilities/Installer.php
@@ -0,0 +1,324 @@
+ 'Safe Mode']);
+ }
+
+ if (ini_get('register_globals')) {
+ $requirements[] = trans('install.requirements.disabled', ['feature' => 'Register Globals']);
+ }
+
+ if (ini_get('magic_quotes_gpc')) {
+ $requirements[] = trans('install.requirements.disabled', ['feature' => 'Magic Quotes']);
+ }
+
+ if (!ini_get('file_uploads')) {
+ $requirements[] = trans('install.requirements.enabled', ['feature' => 'File Uploads']);
+ }
+
+ if (!function_exists('proc_open')) {
+ $requirements[] = trans('install.requirements.enabled', ['feature' => 'proc_open']);
+ }
+
+ if (!function_exists('proc_close')) {
+ $requirements[] = trans('install.requirements.enabled', ['feature' => 'proc_close']);
+ }
+
+ if (!class_exists('PDO')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'MySQL PDO']);
+ }
+
+ if (!extension_loaded('bcmath')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'BCMath']);
+ }
+
+ if (!extension_loaded('ctype')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'Ctype']);
+ }
+
+ if (!extension_loaded('curl')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'cURL']);
+ }
+
+ if (!extension_loaded('dom')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'DOM']);
+ }
+
+ if (!extension_loaded('fileinfo')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'FileInfo']);
+ }
+
+ if (!extension_loaded('intl')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'Intl']);
+ }
+
+ if (!extension_loaded('gd')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'GD']);
+ }
+
+ if (!extension_loaded('json')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'JSON']);
+ }
+
+ if (!extension_loaded('mbstring')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'Mbstring']);
+ }
+
+ if (!extension_loaded('openssl')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'OpenSSL']);
+ }
+
+ if (!extension_loaded('tokenizer')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'Tokenizer']);
+ }
+
+ if (!extension_loaded('xml')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'XML']);
+ }
+
+ if (!extension_loaded('zip')) {
+ $requirements[] = trans('install.requirements.extension', ['extension' => 'ZIP']);
+ }
+
+ if (!is_writable(base_path('storage/app'))) {
+ $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/app']);
+ }
+
+ if (!is_writable(base_path('storage/app/uploads'))) {
+ $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/app/uploads']);
+ }
+
+ if (!is_writable(base_path('storage/framework'))) {
+ $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/framework']);
+ }
+
+ if (!is_writable(base_path('storage/logs'))) {
+ $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/logs']);
+ }
+
+ if (Console::run('help') !== true) {
+ $requirements[] = trans('install.error.php_version', ['php_version' => AKAUNTING_PHP]);
+ }
+
+ return $requirements;
+ }
+
+ /**
+ * Create a default .env file.
+ *
+ * @return void
+ */
+ public static function createDefaultEnvFile()
+ {
+ // Rename file
+ if (!is_file(base_path('.env')) && is_file(base_path('.env.example'))) {
+ File::move(base_path('.env.example'), base_path('.env'));
+ }
+
+ // Update .env file
+ static::updateEnv([
+ 'APP_KEY' => 'base64:'.base64_encode(random_bytes(32)),
+ ]);
+ }
+
+ public static function createDbTables($host, $port, $database, $username, $password, $prefix = null)
+ {
+ if (!static::isDbValid($host, $port, $database, $username, $password)) {
+ return false;
+ }
+
+ // Set database details
+ static::saveDbVariables($host, $port, $database, $username, $password, $prefix);
+
+ // Try to increase the maximum execution time
+ set_time_limit(300); // 5 minutes
+
+ // Create tables
+ Artisan::call('migrate', ['--force' => true]);
+
+ // Create Permissions
+ Artisan::call('db:seed', ['--class' => 'Database\Seeds\Permissions', '--force' => true]);
+
+ return true;
+ }
+
+ /**
+ * Check if the database exists and is accessible.
+ *
+ * @param $host
+ * @param $port
+ * @param $database
+ * @param $host
+ * @param $database
+ * @param $username
+ * @param $password
+ *
+ * @return bool
+ */
+ public static function isDbValid($host, $port, $database, $username, $password)
+ {
+ Config::set('database.connections.install_test', [
+ 'host' => $host,
+ 'port' => $port,
+ 'database' => $database,
+ 'username' => $username,
+ 'password' => $password,
+ 'driver' => $connection = config('database.default', 'mysql'),
+ 'charset' => config("database.connections.$connection.charset", 'utf8mb4'),
+ ]);
+
+ try {
+ DB::connection('install_test')->getPdo();
+ } catch (\Exception $e) {
+ return false;
+ }
+
+ // Purge test connection
+ DB::purge('install_test');
+
+ return true;
+ }
+
+ public static function saveDbVariables($host, $port, $database, $username, $password, $prefix = null)
+ {
+ $prefix = !empty($prefix) ? $prefix : strtolower(Str::random(3) . '_');
+
+ // Update .env file
+ static::updateEnv([
+ 'DB_HOST' => $host,
+ 'DB_PORT' => $port,
+ 'DB_DATABASE' => $database,
+ 'DB_USERNAME' => $username,
+ 'DB_PASSWORD' => '"' . $password . '"',
+ 'DB_PREFIX' => $prefix,
+ ]);
+
+ $con = config('database.default', 'mysql');
+
+ // Change current connection
+ $db = Config::get('database.connections.' . $con);
+
+ $db['host'] = $host;
+ $db['database'] = $database;
+ $db['username'] = $username;
+ $db['password'] = $password;
+ $db['prefix'] = $prefix;
+
+ Config::set('database.connections.' . $con, $db);
+
+ DB::purge($con);
+ DB::reconnect($con);
+ }
+
+ public static function createCompany($name, $email, $locale)
+ {
+ dispatch_sync(new CreateCompany([
+ 'name' => $name,
+ 'domain' => '',
+ 'email' => $email,
+ 'currency' => 'USD',
+ 'locale' => $locale,
+ 'enabled' => '1',
+ ]));
+ }
+
+ public static function createUser($email, $password, $locale)
+ {
+ dispatch_sync(new CreateUser([
+ 'name' => '',
+ 'email' => $email,
+ 'password' => $password,
+ 'locale' => $locale,
+ 'companies' => ['1'],
+ 'roles' => ['1'],
+ 'enabled' => '1',
+ ]));
+ }
+
+ public static function finalTouches()
+ {
+ // Update .env file
+ $env = [
+ 'APP_LOCALE' => session('locale'),
+ 'APP_INSTALLED' => 'true',
+ 'APP_DEBUG' => 'false',
+ 'FIREWALL_ENABLED' => 'true',
+ 'MODEL_CACHE_ENABLED' => 'true',
+ ];
+
+ if (!app()->runningInConsole()) {
+ $env['APP_URL'] = request()->getUriForPath('');
+ }
+
+ static::updateEnv($env);
+
+ // Rename the robots.txt file
+ try {
+ File::move(base_path('robots.txt.dist'), base_path('robots.txt'));
+ } catch (\Exception $e) {
+ // nothing to do
+ }
+ }
+
+ public static function updateEnv($data)
+ {
+ if (empty($data) || !is_array($data) || !is_file(base_path('.env'))) {
+ return false;
+ }
+
+ $env = file_get_contents(base_path('.env'));
+
+ $env = explode("\n", $env);
+
+ foreach ($data as $data_key => $data_value) {
+ $updated = false;
+
+ foreach ($env as $env_key => $env_value) {
+ $entry = explode('=', $env_value, 2);
+
+ // Check if new or old key
+ if ($entry[0] == $data_key) {
+ $env[$env_key] = $data_key . '=' . $data_value;
+ $updated = true;
+ } else {
+ $env[$env_key] = $env_value;
+ }
+ }
+
+ // Lets create if not available
+ if (!$updated) {
+ $env[] = $data_key . '=' . $data_value;
+ }
+ }
+
+ $env = implode("\n", $env);
+
+ file_put_contents(base_path('.env'), $env);
+
+ return true;
+ }
+}
diff --git a/app/Utilities/ModuleActivator.php b/app/Utilities/ModuleActivator.php
new file mode 100644
index 00000000..4060288c
--- /dev/null
+++ b/app/Utilities/ModuleActivator.php
@@ -0,0 +1,179 @@
+cache = $app['cache'];
+ $this->config = $app['config'];
+
+ $this->load();
+ }
+
+ public function is(Module $module, bool $active): bool
+ {
+ if (app()->runningInConsole()) {
+ return true;
+ }
+
+ if (running_in_install() && in_array($module->getAlias(), ['offline-payments', 'paypal-standard'])) {
+ return true;
+ }
+
+ if (! isset($this->statuses[$module->getAlias()])) {
+ return false;
+ }
+
+ return $this->statuses[$module->getAlias()] === $active;
+ }
+
+ public function enable(Module $module): void
+ {
+ $this->setActive($module, true);
+ }
+
+ public function disable(Module $module): void
+ {
+ $this->setActive($module, false);
+ }
+
+ public function setActive(Module $module, bool $active): void
+ {
+ $this->statuses[$module->getAlias()] = $active;
+
+ $this->flushCache();
+
+ if (empty($this->company_id)) {
+ $company_id = $this->getCompanyId();
+
+ if (empty($company_id)) {
+ return;
+ }
+
+ $this->company_id = $company_id;
+ }
+
+ $model = Model::companyId($this->company_id)->alias($module->getAlias())->first();
+
+ if (! empty($model)) {
+ $model->enabled = $active;
+ $model->save();
+
+ return;
+ }
+
+ Model::create([
+ 'company_id' => $this->company_id,
+ 'alias' => $module->getAlias(),
+ 'enabled' => $active,
+ 'created_from' => 'core::activator',
+ ]);
+ }
+
+ public function delete(Module $module): void
+ {
+ if (! isset($this->statuses[$module->getAlias()])) {
+ return;
+ }
+
+ unset($this->statuses[$module->getAlias()]);
+
+ Model::companyId($this->company_id)->alias($module->getAlias())->delete();
+
+ $this->flushCache();
+ }
+
+ public function reset(): void
+ {
+ $this->statuses = [];
+
+ $this->flushCache();
+ }
+
+ public function load(): void
+ {
+ $this->statuses = $this->getStatusesByCompany();
+ }
+
+ public function getStatusesByCompany(): array
+ {
+ if (! $this->config->get('module.cache.enabled')) {
+ return $this->readDatabase();
+ }
+
+ $key = $this->config->get('module.cache.key') . '.statuses';
+ $lifetime = $this->config->get('module.cache.lifetime');
+
+ return $this->cache->remember($key, $lifetime, function () {
+ return $this->readDatabase();
+ });
+ }
+
+ public function readDatabase(): array
+ {
+ if (app()->runningInConsole()) {
+ return [];
+ }
+
+ $company_id = $this->getCompanyId();
+
+ if (empty($company_id)) {
+ return [];
+ }
+
+ $this->company_id = $company_id;
+
+ $modules = Model::companyId($this->company_id)->pluck('enabled', 'alias')->toArray();
+
+ foreach ($modules as $alias => $enabled) {
+ if (in_array($alias, ['offline-payments', 'paypal-standard'])) {
+ continue;
+ }
+
+ $subscription = $this->getSubscription($alias);
+
+ if (! is_object($subscription)) {
+ continue;
+ }
+
+ $modules[$alias] = $subscription->status;
+ }
+
+ return $modules;
+ }
+
+ public function flushCache(): void
+ {
+ $key = $this->config->get('module.cache.key') . '.statuses';
+
+ $this->cache->forget($key);
+ }
+
+ public function register(): void
+ {
+ $this->load();
+
+ app()->register(\Akaunting\Module\Providers\Bootstrap::class, true);
+ }
+}
diff --git a/app/Utilities/Modules.php b/app/Utilities/Modules.php
new file mode 100644
index 00000000..c839029b
--- /dev/null
+++ b/app/Utilities/Modules.php
@@ -0,0 +1,92 @@
+contact;
+ }
+
+ if ($contact && ($type != 'all')) {
+ $payment_methods = Cache::get($cache_customer);
+ }
+
+ if (!empty($payment_methods)) {
+ return $payment_methods;
+ }
+
+ $list = [];
+
+ $modules = new \stdClass();
+ $modules->payment_methods = [];
+
+ // Fire the event to get the list of payment methods
+ event(new PaymentMethodShowing($modules));
+
+ foreach ((array) $modules->payment_methods as $method) {
+ if (!isset($method['name']) || !isset($method['code'])) {
+ continue;
+ }
+
+ if (($contact && empty($method['customer'])) && ($type != 'all')) {
+ continue;
+ }
+
+ $list[] = $method;
+ }
+
+ static::sortPaymentMethods($list);
+
+ foreach ($list as $method) {
+ $payment_methods[$method['code']] = $method['name'];
+ }
+
+ if ($contact && ($type != 'all')) {
+ Cache::put($cache_customer, $payment_methods, Date::now()->addHour(6));
+ } else {
+ Cache::put($cache_admin, $payment_methods, Date::now()->addHour(6));
+ }
+
+ return ($payment_methods) ? $payment_methods : [];
+ }
+
+ public static function clearPaymentMethodsCache()
+ {
+ Cache::forget(static::getPaymentMethodsCacheKey('admin'));
+ Cache::forget(static::getPaymentMethodsCacheKey('customer'));
+ }
+
+ public static function getPaymentMethodsCacheKey($type)
+ {
+ return 'payment_methods.' . company_id() . '.' . $type;
+ }
+
+ protected static function sortPaymentMethods(&$list)
+ {
+ $sort_order = [];
+
+ foreach ($list as $key => $value) {
+ $sort_order[$key] = !empty($value['order']) ? $value['order'] : 0;
+ }
+
+ if (empty($sort_order)) {
+ return;
+ }
+
+ array_multisort($sort_order, SORT_ASC, $list);
+ }
+}
diff --git a/app/Utilities/Overrider.php b/app/Utilities/Overrider.php
new file mode 100644
index 00000000..1ee26999
--- /dev/null
+++ b/app/Utilities/Overrider.php
@@ -0,0 +1,140 @@
+ $timezone]);
+ date_default_timezone_set(config('app.timezone'));
+
+ // Email
+ $email_protocol = setting('email.protocol', 'mail');
+ config(['mail.default' => $email_protocol]);
+ config(['mail.from.name' => setting('company.name')]);
+ config(['mail.from.address' => setting('company.email')]);
+
+ if ($email_protocol == 'sendmail') {
+ config(['mail.mailers.sendmail.path' => setting('email.sendmail_path')]);
+ } elseif ($email_protocol == 'smtp') {
+ config(['mail.mailers.smtp.host' => setting('email.smtp_host')]);
+ config(['mail.mailers.smtp.port' => setting('email.smtp_port')]);
+ config(['mail.mailers.smtp.username' => setting('email.smtp_username')]);
+ config(['mail.mailers.smtp.password' => setting('email.smtp_password')]);
+ config(['mail.mailers.smtp.encryption' => setting('email.smtp_encryption')]);
+ }
+
+ // Locale
+ if (! session('locale')) {
+ $locale = user()->locale ?? setting('default.locale');
+
+ app()->setLocale($locale);
+ }
+
+ // Set locale for Money package
+ Money::setLocale(app()->getLocale());
+
+ // Money
+ config(['money.defaults.currency' => setting('default.currency')]);
+
+ // Set app url dynamically if empty
+ if (! config('app.url')) {
+ config(['app.url' => url('/')]);
+ }
+ }
+
+ protected static function loadCategoryTypes()
+ {
+ $category = new Category;
+
+ $income_types = $category->getIncomeCategoryTypes('string');
+ $expense_types = $category->getExpenseCategoryTypes('string');
+ $item_types = $category->getItemCategoryTypes('string');
+ $other_types = $category->getOtherCategoryTypes('string');
+
+ $search_string = config('search-string');
+
+ foreach ($search_string as $model => &$model_config) {
+ $route = $model_config['columns']['category_id']['route'] ?? null;
+
+ // Only update category_id routes that point to categories.index
+ if (!is_array($route) || ($route[0] ?? '') !== 'categories.index' || !isset($route[1])) {
+ continue;
+ }
+
+ // Longest match first (income,expense must come before income)
+ $replacements = [
+ 'type:' . Category::INCOME_TYPE . ',' . Category::EXPENSE_TYPE => 'type:' . $income_types . ',' . $expense_types,
+ 'type:' . Category::INCOME_TYPE => 'type:' . $income_types,
+ 'type:' . Category::EXPENSE_TYPE => 'type:' . $expense_types,
+ 'type:' . Category::ITEM_TYPE => 'type:' . $item_types,
+ 'type:' . Category::OTHER_TYPE => 'type:' . $other_types,
+ ];
+
+ foreach ($replacements as $search => $replace) {
+ if (Str::contains($route[1], $search)) {
+ $model_config['columns']['category_id']['route'][1] = Str::replace($search, $replace, $route[1]);
+ break;
+ }
+ }
+ }
+
+ config(['search-string' => $search_string]);
+ }
+
+ protected static function loadCurrencies()
+ {
+ $currencies = Currency::all();
+
+ foreach ($currencies as $currency) {
+ // If currency is not set in config, add it
+ if (! config("money.currencies.{$currency->code}")) {
+ config(['money.currencies.' . $currency->code => [
+ 'code' => $currency->code,
+ 'subunit' => 100,
+ ]]);
+ }
+
+ config(['money.currencies.' . $currency->code . '.name' => $currency->name]);
+ config(['money.currencies.' . $currency->code . '.rate' => $currency->rate]);
+ config(['money.currencies.' . $currency->code . '.precision' => $currency->precision]);
+ config(['money.currencies.' . $currency->code . '.symbol' => $currency->symbol]);
+ config(['money.currencies.' . $currency->code . '.symbol_first' => $currency->symbol_first]);
+ config(['money.currencies.' . $currency->code . '.decimal_mark' => $currency->decimal_mark]);
+ config(['money.currencies.' . $currency->code . '.thousands_separator' => $currency->thousands_separator]);
+ }
+
+ // Set currencies with new settings
+ \Akaunting\Money\Currency::setCurrencies(config('money.currencies'));
+ }
+}
diff --git a/app/Utilities/QueueCollection.php b/app/Utilities/QueueCollection.php
new file mode 100644
index 00000000..660db5d0
--- /dev/null
+++ b/app/Utilities/QueueCollection.php
@@ -0,0 +1,10 @@
+getFinancialYear();
+
+ foreach ($items as $key => $item) {
+ // @todo cache recurrings
+ if (! $item->recurring || !empty($item->parent_id)) {
+ continue;
+ }
+
+ foreach ($item->recurring->getRecurringSchedule() as $schedule) {
+ $issued = Date::parse($item->$issued_date_field);
+ $start = $schedule->getStart();
+ $start_date = Date::parse($start->format('Y-m-d'));
+
+ if (($issued->format('Y-m') == $start->format('Y-m')) && ($issued->format('d') >= $start->format('d'))) {
+ continue;
+ }
+
+ if ($start_date->lessThan($financial_year->getStartDate()) || $start_date->greaterThan($financial_year->getEndDate())) {
+ continue;
+ }
+
+ $clone = clone $item;
+
+ if ($clone instanceof Document) {
+ // Days between invoiced/billed and due date
+ $diff_days = Date::parse($clone->due_at)->diffInDays(Date::parse($clone->$issued_date_field));
+
+ $clone->due_at = $start_date->copy()->addDays($diff_days)->format('Y-m-d');
+ }
+
+ $clone->parent_id = $item->id;
+ $clone->created_at = $start_date->format('Y-m-d');
+ $clone->$issued_date_field = $start_date->format('Y-m-d');
+
+ $items->push($clone);
+ }
+ }
+ }
+}
diff --git a/app/Utilities/Reports.php b/app/Utilities/Reports.php
new file mode 100644
index 00000000..5590d82d
--- /dev/null
+++ b/app/Utilities/Reports.php
@@ -0,0 +1,164 @@
+each(function ($module) use (&$list) {
+ $m = module($module->alias);
+
+ if (! $m || $m->disabled() || empty($m->get('reports'))) {
+ return;
+ }
+
+ $list = array_merge($list, (array) $m->get('reports'));
+ });
+
+ // Added New Event
+ $report_classes = collect($list);
+
+ event(new ReportClassesCreated($report_classes));
+
+ $list = $report_classes->all();
+
+ foreach ($list as $class) {
+ if (! class_exists($class) || ($check_permission && static::cannotRead($class))) {
+ continue;
+ }
+
+ $classes[$class] = static::getDefaultName($class);
+ }
+
+ return $classes;
+ }
+
+ public static function getClassInstance($model, $load_data = true)
+ {
+ if (is_string($model)) {
+ $model = Report::where('class', $model)->first();
+ }
+
+ if ((! $model instanceof Report) || ! class_exists($model->class)) {
+ return false;
+ }
+
+ // Use the static cache from isModuleEnabled() instead of creating
+ // a new instance and re-reading module JSON from disk each time.
+ if (! empty($model) && ($model->alias != 'core') && ! static::isModuleEnabled($model->class)) {
+ return false;
+ }
+
+ $class = $model->class;
+
+ return new $class($model, $load_data);
+ }
+
+ public static function canShow($class)
+ {
+ return (static::isModuleEnabled($class) && static::canRead($class));
+ }
+
+ public static function cannotShow($class)
+ {
+ return ! static::canShow($class);
+ }
+
+ public static function canRead($class)
+ {
+ return user()->can(static::getPermission($class));
+ }
+
+ public static function cannotRead($class)
+ {
+ return ! static::canRead($class);
+ }
+
+ public static function getPermission($class)
+ {
+ $arr = explode('\\', $class);
+
+ $prefix = 'read-';
+
+ // Add module
+ if ($alias = static::getModuleAlias($arr)) {
+ $prefix .= $alias . '-';
+ }
+
+ $prefix .= 'reports-';
+
+ $class_name = end($arr);
+
+ $permission = $prefix . Str::kebab($class_name);
+
+ return str_replace('--', '-', $permission);
+ }
+
+ public static function getDefaultName($class)
+ {
+ return (new $class())->getDefaultName();
+ }
+
+ public static function isModuleEnabled($class)
+ {
+ if (! $alias = static::getModuleAlias($class)) {
+ return true;
+ }
+
+ static $cache = [];
+
+ if (! array_key_exists($alias, $cache)) {
+ $cache[$alias] = module_is_enabled($alias);
+ }
+
+ return $cache[$alias];
+ }
+
+ public static function isModuleDisabled($class)
+ {
+ return ! static::isModuleEnabled($class);
+ }
+
+ public static function isModule($class)
+ {
+ $arr = is_array($class) ? $class : explode('\\', $class);
+
+ return (strtolower($arr[0]) == 'modules');
+ }
+
+ public static function isNotModule($class)
+ {
+ return ! static::isModule($class);
+ }
+
+ public static function getModuleAlias($class)
+ {
+ if (static::isNotModule($class)) {
+ return false;
+ }
+
+ $arr = is_array($class) ? $class : explode('\\', $class);
+
+ return Str::kebab($arr[1]);
+ }
+}
diff --git a/app/Utilities/SidebarPermissions.php b/app/Utilities/SidebarPermissions.php
new file mode 100644
index 00000000..d526ab6e
--- /dev/null
+++ b/app/Utilities/SidebarPermissions.php
@@ -0,0 +1,88 @@
+id;
+ $settings = self::settings();
+
+ if (in_array($userKey, $settings['configured'] ?? [], true)) {
+ return $userKey;
+ }
+
+ return 'role_' . SystemAccess::roleName($user);
+ }
+
+ public static function allowedKeys(User $user): ?array
+ {
+ $settings = self::settings();
+ $subject = self::subjectKey($user);
+
+ if (! in_array($subject, $settings['configured'] ?? [], true)) {
+ return null;
+ }
+
+ return array_values(array_unique((array) ($settings['subjects'][$subject] ?? [])));
+ }
+
+ public static function navigationFor(User $user): array
+ {
+ $navigation = BusinessNavigation::all();
+ $allowed = self::allowedKeys($user);
+
+ if ($allowed === null) {
+ return $navigation;
+ }
+
+ return array_values(array_filter(array_map(function (array $section) use ($allowed) {
+ $sectionKey = $section['slug'];
+
+ if (in_array($sectionKey, $allowed, true)) {
+ return $section;
+ }
+
+ $pages = array_values(array_filter($section['pages'] ?? [], function (array $page) use ($allowed, $sectionKey) {
+ return in_array($sectionKey . '/' . $page['slug'], $allowed, true);
+ }));
+
+ if (! empty($pages)) {
+ $section['pages'] = $pages;
+
+ return $section;
+ }
+
+ return null;
+ }, $navigation)));
+ }
+
+ public static function allKeys(): array
+ {
+ $keys = [];
+
+ foreach (BusinessNavigation::all() as $section) {
+ $keys[] = $section['slug'];
+
+ foreach ($section['pages'] ?? [] as $page) {
+ $keys[] = $section['slug'] . '/' . $page['slug'];
+ }
+ }
+
+ return $keys;
+ }
+}
diff --git a/app/Utilities/Str.php b/app/Utilities/Str.php
new file mode 100644
index 00000000..44d4c0bc
--- /dev/null
+++ b/app/Utilities/Str.php
@@ -0,0 +1,57 @@
+count() === 1) {
+ $initial = static::getInitialFromOneWord($value, $words, $length);
+ } else {
+ $initial = static::getInitialFromMultipleWords($words, $length);
+ }
+
+ $initial = strtoupper($initial);
+
+ if (language()->direction() == 'rtl') {
+ $initial = collect(mb_str_split($initial))->reverse()->implode('');
+ }
+
+ return $initial;
+ }
+
+ public static function getInitialFromOneWord($value, $words, $length)
+ {
+ $initial = (string) $words->first();
+
+ if (strlen($value) >= $length) {
+ $initial = IStr::substr($value, 0, $length);
+ }
+
+ return $initial;
+ }
+
+ public static function getInitialFromMultipleWords($words, $length)
+ {
+ // otherwise, use initial char from each word
+ $initials = new Collection();
+
+ $words->each(function ($word) use ($initials) {
+ $initials->push(IStr::substr($word, 0, 1));
+ });
+
+ return static::selectInitialFromMultipleInitials($initials, $length);
+ }
+
+ public static function selectInitialFromMultipleInitials($initials, $length)
+ {
+ return $initials->slice(0, $length)->implode('');
+ }
+}
diff --git a/app/Utilities/SystemAccess.php b/app/Utilities/SystemAccess.php
new file mode 100644
index 00000000..4632792b
--- /dev/null
+++ b/app/Utilities/SystemAccess.php
@@ -0,0 +1,73 @@
+hasRole($role)) {
+ return $role;
+ }
+ }
+
+ return '';
+ }
+
+ public static function canOpenSettings(?User $user = null): bool
+ {
+ return in_array(self::roleName($user), [self::SUPER_ADMIN, self::ADMIN], true);
+ }
+
+ public static function isSuperAdmin(?User $user = null): bool
+ {
+ return self::roleName($user) === self::SUPER_ADMIN;
+ }
+
+ public static function canManageUser(User $actor, User $target): bool
+ {
+ if (self::isSuperAdmin($actor)) {
+ return true;
+ }
+
+ return self::roleName($actor) === self::ADMIN
+ && self::roleName($target) === self::USER;
+ }
+
+ public static function assignableRoles(?User $actor = null): array
+ {
+ $actor ??= user();
+
+ if (self::isSuperAdmin($actor)) {
+ return [
+ self::SUPER_ADMIN => '超级管理员',
+ self::ADMIN => '普通管理员',
+ self::USER => '普通用户',
+ ];
+ }
+
+ return [self::USER => '普通用户'];
+ }
+
+ public static function roleLabels(): array
+ {
+ return [
+ self::SUPER_ADMIN => '超级管理员',
+ self::ADMIN => '普通管理员',
+ self::USER => '普通用户',
+ ];
+ }
+}
diff --git a/app/Utilities/TransactionNumber.php b/app/Utilities/TransactionNumber.php
new file mode 100644
index 00000000..80884b75
--- /dev/null
+++ b/app/Utilities/TransactionNumber.php
@@ -0,0 +1,62 @@
+ $prefix . str_pad($next, $digit, '0', STR_PAD_LEFT);
+ $number_exists = fn($type, $number) => $this->numberExists($type, $number);
+
+ $transaction_number = $get_number($prefix, $next, $digit);
+
+ if ($number_exists($type, $transaction_number)) {
+ do {
+ $next++;
+
+ $transaction_number = $get_number($prefix, $next, $digit);
+ } while ($number_exists($type, $transaction_number));
+
+ setting(['transaction' . $suffix . '.number_next' => $next]);
+ setting()->save();
+ }
+
+ return $transaction_number;
+
+ }
+
+ public function numberExists($type, $number)
+ {
+ $number_exists = new Transaction;
+
+ if (Str::endsWith($type, '-recurring')) {
+ $number_exists = $number_exists->isRecurring();
+ }
+
+ if (Str::endsWith($type, '-split')) {
+ $number_exists = $number_exists->isSplit();
+ }
+
+ $number_exists = $number_exists->where('number', $number);
+
+ return $number_exists->exists();
+ }
+
+ public function increaseNextNumber($type, $suffix = '', ?Contact $contact): void
+ {
+ $next = setting('transaction' . $suffix . '.number_next', 1) + 1;
+
+ setting(['transaction' . $suffix . '.number_next' => $next]);
+ setting()->save();
+ }
+}
diff --git a/app/Utilities/Versions.php b/app/Utilities/Versions.php
new file mode 100644
index 00000000..eef8f25d
--- /dev/null
+++ b/app/Utilities/Versions.php
@@ -0,0 +1,248 @@
+addHours(6), function () use ($modules) {
+ $info = Info::all();
+
+ $versions = [];
+
+ // Check core first
+ try {
+ $url = 'core/version/' . $info['akaunting'] . '/' . $info['php'] . '/' . $info['mysql'] . '/' . $info['companies'];
+ } catch (\Exception $e) {
+ // Handle exception
+ report('Error fetching core version: ( $info = ' . json_encode($info) . ')' . $e->getMessage());
+
+ return $versions;
+ }
+
+ # Installed modules start
+ $modules = Arr::wrap($modules);
+
+ $installed_modules = [];
+ $module_version = '?modules=';
+
+ foreach ($modules as $module) {
+ if (is_string($module)) {
+ $module = module($module);
+ }
+
+ if (! $module instanceof \Akaunting\Module\Module) {
+ continue;
+ }
+
+ $alias = $module->get('alias');
+
+ $installed_modules[] = $alias;
+ }
+
+ $module_version .= implode(',', $installed_modules);
+
+ $url .= $module_version;
+ # Installed modules end
+
+ $versions['core'] = static::getLatestVersion($url, $info['akaunting']);
+
+ // Then modules
+ foreach ($modules as $module) {
+ if (is_string($module)) {
+ $module = module($module);
+ }
+
+ if (! $module instanceof \Akaunting\Module\Module) {
+ continue;
+ }
+
+ $alias = $module->get('alias');
+ $version = $module->get('version');
+
+ $url = 'apps/' . $alias . '/version/' . $version . '/' . $info['akaunting'];
+
+ $versions[$alias] = static::getLatestVersion($url, $version);
+ }
+
+ return $versions;
+ });
+ }
+
+ public static function getVersionByAlias($alias)
+ {
+ $info = Info::all();
+
+ // Check core first
+ $url = 'core/version/' . $info['akaunting'] . '/' . $info['php'] . '/' . $info['mysql'] . '/' . $info['companies'];
+ $version = $info['akaunting'];
+
+ if ($alias != 'core') {
+ $version = module($alias) ? module($alias)->get('version') : '1.0.0';
+
+ $url = 'apps/' . $alias . '/version/' . $version . '/' . $info['akaunting'];
+ }
+
+ // Get data from cache
+ $versions = Cache::get('versions', []);
+
+ $versions[$alias] = static::getLatestVersion($url, $version);
+
+ Cache::put('versions', $versions, Date::now()->addHours(6));
+
+ return $versions[$alias];
+ }
+
+ public static function getLatestVersion($url, $latest)
+ {
+ $version = new \stdClass();
+
+ $version->can_update = true;
+ $version->latest = $latest;
+ $version->errors = false;
+ $version->message = '';
+ $version->subscription = null;
+
+ if (! $body = static::getResponseBody('GET', $url, ['timeout' => 10])) {
+ return $version;
+ }
+
+ if (! is_object($body)) {
+ return $version;
+ }
+
+ $version->can_update = $body->success;
+ $version->latest = $body->data->latest;
+ $version->errors = $body->errors;
+ $version->message = $body->message;
+ $version->subscription = $body->data?->subscription ?? null;
+
+ return $version;
+ }
+
+ public static function enforceSubscriptionStatus($alias, $version): void
+ {
+ if (! $version->subscription) {
+ return;
+ }
+
+ if ($version->subscription->expired_at > Date::now()->startOfDay()) {
+ return;
+ }
+
+ $status = 'active';
+
+ switch ($version->subscription->status) {
+ case 'expired':
+ case 'canceled':
+ $status = 'disabled';
+ break;
+ case 'chargeback':
+ case 'not_paid':
+ case 'none':
+ case 'refund':
+ $status = 'uninstalled';
+ break;
+ default:
+ // Do nothing
+ break;
+ }
+
+ if ($status == 'active') {
+ return;
+ }
+
+ $module_companies = Module::allCompanies()->alias($alias)->get();
+
+ foreach ($module_companies as $module) {
+ switch ($status) {
+ case 'disabled':
+ dispatch(new DisableModule($alias, $module->company_id));
+ break;
+ case 'uninstalled':
+ dispatch(new UninstallModule($alias, $module->company_id));
+ break;
+ default:
+ // Do nothing
+ break;
+ }
+ }
+ }
+
+ public static function getUpdates()
+ {
+ return Cache::remember('updates', Date::now()->addHours(6), function () {
+ $updates = [];
+
+ $modules = module()->all();
+
+ $versions = static::all($modules);
+
+ foreach ($versions as $alias => $latest_version) {
+ if ($alias == 'core') {
+ $installed_version = version('short');
+ } else {
+ $module = module($alias);
+
+ if (! $module instanceof \Akaunting\Module\Module) {
+ continue;
+ }
+
+ $installed_version = $module->get('version');
+ }
+
+ if (version_compare($installed_version, $latest_version->latest, '>=')) {
+ continue;
+ }
+
+ $updates[$alias] = $latest_version;
+ }
+
+ return $updates;
+ });
+ }
+
+ public static function shouldUpdate($listener_version, $old_version, $new_version): bool
+ {
+ // Don't update if "listener" is same or lower than "old" version
+ if (version_compare($listener_version, $old_version, '<=')) {
+ return false;
+ }
+
+ // Don't update if "listener" is higher than "new" version
+ if (version_compare($listener_version, $new_version, '>')) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/app/Utilities/Widgets.php b/app/Utilities/Widgets.php
new file mode 100644
index 00000000..b5c5c8df
--- /dev/null
+++ b/app/Utilities/Widgets.php
@@ -0,0 +1,222 @@
+each(function ($module) use (&$list, $alias) {
+ if (! in_array($alias, [$module->alias, 'all'])) {
+ return;
+ }
+
+ $m = module($module->alias);
+
+ if (! $m || $m->disabled() || empty($m->get('widgets'))) {
+ return;
+ }
+
+ $list = array_merge($list, (array) $m->get('widgets'));
+ });
+
+ // Added New Event
+ $widget_classes = collect($list);
+
+ event(new WidgetClassesCreated($widget_classes));
+
+ $list = $widget_classes->all();
+
+ foreach ($list as $class) {
+ if (! class_exists($class) || ($check_permission && ! static::canRead($class))) {
+ continue;
+ }
+
+ $classes[$class] = static::getDefaultName($class);
+ }
+
+ return $classes;
+ }
+
+ public static function getClassInstance($model)
+ {
+ if (is_string($model)) {
+ $class_name = $model;
+
+ if (! class_exists($class_name)) {
+ return false;
+ }
+
+ $model = Widget::where('dashboard_id', session('dashboard_id'))->where('class', $class_name)->first();
+
+ if (! empty($model) && ($model->alias != 'core') && (new static)->moduleIsDisabled($model->alias)) {
+ return false;
+ }
+
+ if (! $model instanceof Widget) {
+ $class = (new $class_name());
+
+ $model = new Widget();
+ $model->id = 0;
+ $model->company_id = company_id();
+ $model->dashboard_id = session('dashboard_id');
+ $model->class = $class_name;
+ $model->name = $class->getDefaultName();
+ $model->sort = 99;
+ $model->settings = $class->getDefaultSettings();
+ }
+ } else {
+ if ((! $model instanceof Widget) || ! class_exists($model->class)) {
+ return false;
+ }
+
+ if (($model->alias != 'core') && (new static)->moduleIsDisabled($model->alias)) {
+ return false;
+ }
+
+ $class_name = $model->class;
+ }
+
+ return new $class_name($model);
+ }
+
+ public static function show($model, ...$arguments)
+ {
+ if (! $class = static::getClassInstance($model)) {
+ return '';
+ }
+
+ return $class->show(...$arguments);
+ }
+
+ public static function canShow($class)
+ {
+ return (static::isModuleEnabled($class) && static::canRead($class));
+ }
+
+ public static function cannotShow($class)
+ {
+ return ! static::canShow($class);
+ }
+
+ public static function canRead($class)
+ {
+ return user()->can(static::getPermission($class));
+ }
+
+ public static function cannotRead($class)
+ {
+ return ! static::canRead($class);
+ }
+
+ public static function getPermission($class)
+ {
+ $arr = explode('\\', $class);
+
+ $prefix = 'read-';
+
+ // Add module
+ if ($alias = static::getModuleAlias($arr)) {
+ $prefix .= $alias . '-';
+ }
+
+ $prefix .= 'widgets-';
+
+ $class_name = end($arr);
+
+ $permission = $prefix . Str::kebab($class_name);
+
+ return str_replace('--', '-', $permission);
+ }
+
+ public static function getDefaultName($class)
+ {
+ return (new $class())->getDefaultName();
+ }
+
+ public static function isModuleEnabled($class)
+ {
+ if (! $alias = static::getModuleAlias($class)) {
+ return true;
+ }
+
+ if (module_is_enabled($alias)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public static function isModuleDisabled($class)
+ {
+ return ! static::isModuleEnabled($class);
+ }
+
+ public static function isModule($class)
+ {
+ $arr = is_array($class) ? $class : explode('\\', $class);
+
+ return (strtolower($arr[0]) == 'modules');
+ }
+
+ public static function isNotModule($class)
+ {
+ return ! static::isModule($class);
+ }
+
+ public static function getModuleAlias($class)
+ {
+ if (static::isNotModule($class)) {
+ return false;
+ }
+
+ $arr = is_array($class) ? $class : explode('\\', $class);
+
+ return Str::kebab($arr[1]);
+ }
+
+ public static function getCoreWidgets()
+ {
+ return static::$core_widgets;
+ }
+
+ public static function setCoreWidgets($widgets)
+ {
+ static::$core_widgets = $widgets;
+ }
+
+ public static function optimizeCoreWidgets()
+ {
+ $core_widgets = collect(static::getCoreWidgets());
+
+ $core_widgets->pop();
+
+ $core_widgets->push('App\Widgets\BankFeeds');
+
+ static::setCoreWidgets($core_widgets->all());
+ }
+}
diff --git a/app/Utilities/helpers.php b/app/Utilities/helpers.php
new file mode 100644
index 00000000..10525554
--- /dev/null
+++ b/app/Utilities/helpers.php
@@ -0,0 +1,483 @@
+user();
+ }
+}
+
+if (! function_exists('user_id')) {
+ /**
+ * Get id of current user.
+ */
+ function user_id(): int|null
+ {
+ return user()?->id;
+ }
+}
+
+if (! function_exists('company_date_format')) {
+ /**
+ * Get the date format of company.
+ */
+ function company_date_format(): string
+ {
+ $date_time = new class() { use DateTime; };
+
+ return $date_time->getCompanyDateFormat();
+ }
+}
+
+if (! function_exists('company_date')) {
+ /**
+ * Format the given date based on company settings.
+ */
+ function company_date($date): string
+ {
+ return Date::parse($date)->format(company_date_format());
+ }
+}
+
+if (! function_exists('show_widget')) {
+ /**
+ * Show a widget.
+ *
+ * @return string
+ */
+ function show_widget()
+ {
+ $arguments = func_get_args();
+
+ $model = array_shift($arguments);
+
+ return Widgets::show($model, ...$arguments);
+ }
+}
+
+if (! function_exists('company')) {
+ /**
+ * Get current/any company model.
+ */
+ function company(int|null $id = null): Company|null
+ {
+ $company = null;
+
+ if (is_null($id)) {
+ $company = Company::getCurrent();
+ }
+
+ if (is_numeric($id)) {
+ $company = Company::find($id);
+ }
+
+ return $company;
+ }
+}
+
+if (! function_exists('module_is_enabled')) {
+ /**
+ * Check if a module is enabled.
+ */
+ function module_is_enabled(string $alias): bool
+ {
+ $module = new class() { use Modules; };
+
+ return $module->moduleIsEnabled($alias);
+ }
+}
+
+if (! function_exists('company_id')) {
+ /**
+ * Get id of current company.
+ */
+ function company_id(): int|null
+ {
+ return company()?->id;
+ }
+}
+
+if (! function_exists('team')) {
+ /**
+ * Get team of current company.
+ */
+ function team()
+ {
+ return company()?->team() !== null ? company()?->team() : company()?->owner?->team();
+ }
+}
+
+if (! function_exists('team_id')) {
+ /**
+ * Get id of current company team.
+ */
+ function team_id()
+ {
+ return team()?->id;
+ }
+}
+
+if (! function_exists('should_queue')) {
+ /**
+ * Check if queue is enabled.
+ */
+ function should_queue(): bool
+ {
+ return config('queue.default') != 'sync';
+ }
+}
+
+if (! function_exists('source_name')) {
+ /**
+ * Get the current source.
+ */
+ function source_name(string|null $alias = null): string
+ {
+ $tmp = new class() { use Sources; };
+
+ return $tmp->getSourceName(null, $alias);
+ }
+}
+
+if (! function_exists('cache_prefix')) {
+ /**
+ * Cache system added company_id prefix.
+ */
+ function cache_prefix(): string
+ {
+ return company_id() . '_';
+ }
+}
+
+if (! function_exists('array_values_recursive')) {
+ /**
+ * Get array values recursively.
+ */
+ function array_values_recursive(array $array): array
+ {
+ $flat = [];
+
+ foreach($array as $value) {
+ if (is_array($value)) {
+ $flat = array_merge($flat, array_values_recursive($value));
+ } else {
+ $flat[] = $value;
+ }
+ }
+
+ return $flat;
+ }
+}
+
+if (! function_exists('running_in_install')) {
+ /**
+ * Detect if application is running in queue.
+ */
+ function running_in_install(): bool
+ {
+ return request_is_install() && env('APP_INSTALLED', false) == false;
+ }
+}
+
+if (! function_exists('running_in_queue')) {
+ /**
+ * Detect if application is running in queue.
+ */
+ function running_in_queue(): bool
+ {
+ return app()->runningConsoleCommand([
+ 'queue:work',
+ 'queue:listen',
+ 'horizon',
+ ]);
+ }
+}
+
+if (! function_exists('running_in_schedule')) {
+ /**
+ * Detect if application is running in schedule.
+ */
+ function running_in_schedule(): bool
+ {
+ return app()->runningConsoleCommand([
+ 'schedule:run',
+ 'schedule:work',
+ ]);
+ }
+}
+
+if (! function_exists('running_in_test')) {
+ /**
+ * Detect if application is running in test.
+ */
+ function running_in_test(): bool
+ {
+ return env_is_testing() && app()->runningInConsole();
+ }
+}
+
+if (! function_exists('simple_icons')) {
+ /**
+ * Get the simple icon content
+ */
+ function simple_icons(string $name): string
+ {
+ $path = base_path('vendor/simple-icons/simple-icons/icons/' . $name . '.svg');
+
+ return file_get_contents($path);
+ }
+}
+
+if (! function_exists('default_currency')) {
+ /**
+ * Get the default currency code
+ */
+ function default_currency(): string
+ {
+ return setting('default.currency');
+ }
+}
+
+if (! function_exists('env_is_production')) {
+ /**
+ * Determine if the application is in the production environment
+ */
+ function env_is_production(): bool
+ {
+ return config('app.env') === 'production';
+ }
+}
+
+if (! function_exists('env_is_development')) {
+ /**
+ * Determine if the application is in the development environment
+ */
+ function env_is_development(): bool
+ {
+ return config('app.env') === 'development';
+ }
+}
+
+if (! function_exists('env_is_build')) {
+ /**
+ * Determine if the application is in the build environment
+ */
+ function env_is_build(): bool
+ {
+ return config('app.env') === 'build';
+ }
+}
+
+if (! function_exists('env_is_local')) {
+ /**
+ * Determine if the application is in the local environment
+ */
+ function env_is_local(): bool
+ {
+ return config('app.env') === 'local';
+ }
+}
+
+if (! function_exists('env_is_testing')) {
+ /**
+ * Determine if the application is in the testing environment
+ */
+ function env_is_testing(): bool
+ {
+ return config('app.env') === 'testing';
+ }
+}
+
+if (! function_exists('is_local_storage')) {
+ /**
+ * Determine if the storage is local.
+ */
+ function is_local_storage(): bool
+ {
+ $driver = config('filesystems.disks.' . config('filesystems.default') . '.driver');
+
+ return $driver == 'local';
+ }
+}
+
+if (! function_exists('is_cloud_storage')) {
+ /**
+ * Determine if the storage is cloud.
+ */
+ function is_cloud_storage(): bool
+ {
+ return ! is_local_storage();
+ }
+}
+
+if (! function_exists('get_storage_path')) {
+ /**
+ * Get the path from the storage.
+ */
+ function get_storage_path(string $path = ''): string
+ {
+ return is_local_storage()
+ ? storage_path($path)
+ : Storage::path($path);
+ }
+}
+
+if (! function_exists('user_model_class')) {
+ function user_model_class(): string
+ {
+ return config('auth.providers.users.model');
+ }
+}
+
+if (! function_exists('role_model_class')) {
+ function role_model_class(): string
+ {
+ return config('laratrust.models.role');
+ }
+}
+
+if (! function_exists('team_model_class')) {
+ function team_model_class(): string
+ {
+ return config('laratrust.models.team');
+ }
+}
+
+if (! function_exists('search_string_value')) {
+ function search_string_value(string $name, string $default = '', string $input = ''): string|array
+ {
+ $search = new class() { use SearchString; };
+
+ return $search->getSearchStringValue($name, $default, $input);
+ }
+}
+
+if (! function_exists('is_cloud')) {
+ function is_cloud(): bool
+ {
+ $cloud = new class() { use Cloud; };
+
+ return $cloud->isCloud();
+ }
+}
+
+if (! function_exists('request_is_install')) {
+ function request_is_install(Request|null $request = null): bool
+ {
+ $r = $request ?: request();
+
+ return $r->is('install/*');
+ }
+}
+
+if (! function_exists('request_is_api')) {
+ function request_is_api(Request|null $request = null): bool
+ {
+ $r = $request ?: request();
+
+ return $r->is(config('api.prefix') . '/*');
+ }
+}
+
+if (! function_exists('request_is_mcp')) {
+ function request_is_mcp(Request|null $request = null): bool
+ {
+ $r = $request ?: request();
+
+ return $r->is('mcp') || $r->is('mcp/*');
+ }
+}
+
+if (! function_exists('request_is_oauth_api')) {
+ /**
+ * Returns true when the current request is an API call authenticated
+ * via an OAuth Bearer token (as set by AuthenticateOnceWithDynamicApi middleware).
+ */
+ function request_is_oauth_api(Request|null $request = null): bool
+ {
+ $r = $request ?: request();
+
+ return request_is_api($r) && $r->attributes->get('auth_method') === 'oauth';
+ }
+}
+
+if (! function_exists('request_is_auth')) {
+ function request_is_auth(Request|null $request = null): bool
+ {
+ $r = $request ?: request();
+
+ return $r->is('auth/*');
+ }
+}
+
+if (! function_exists('request_is_signed')) {
+ function request_is_signed(Request|null $request = null, int $company_id = null): bool
+ {
+ if (is_null($company_id)) {
+ return false;
+ }
+
+ $r = $request ?: request();
+
+ return $r->is($company_id . '/signed/*');
+ }
+}
+
+if (! function_exists('request_is_portal')) {
+ function request_is_portal(Request|null $request = null, int $company_id = null): bool
+ {
+ if (is_null($company_id)) {
+ return false;
+ }
+
+ $r = $request ?: request();
+
+ return $r->is($company_id . '/portal') || $r->is($company_id . '/portal/*');
+ }
+}
+
+if (! function_exists('calculation_to_quantity')) {
+ function calculation_to_quantity($quantity)
+ {
+ $quantity = trim((string) $quantity);
+
+ if ($quantity === '') {
+ throw new \InvalidArgumentException('Invalid mathematical expression.');
+ }
+
+ if (! preg_match('/^[0-9,+\-x*\/().\s]+$/', $quantity)) {
+ throw new \InvalidArgumentException('Invalid mathematical expression.');
+ }
+
+ $quantity = str_replace(',', '.', $quantity);
+ $quantity = str_ireplace('x', '*', $quantity);
+
+ try {
+ $result = eval('return ' . $quantity . ';');
+ } catch (\Throwable $e) {
+ throw new \InvalidArgumentException('Error evaluating the expression: ' . $e->getMessage());
+ }
+
+ if (! is_numeric($result)) {
+ throw new \InvalidArgumentException('Invalid mathematical expression.');
+ }
+
+ return $result;
+ }
+}
diff --git a/app/View/Components/Alert.php b/app/View/Components/Alert.php
new file mode 100644
index 00000000..943bccdd
--- /dev/null
+++ b/app/View/Components/Alert.php
@@ -0,0 +1,142 @@
+rounded = $rounded;
+ $this->border = $border;
+
+ $this->type = $type;
+
+ $this->color = $this->getColor($color);
+ $this->icon = $this->getIcon($icon);
+
+ $this->title = $title;
+ $this->description = $description;
+
+ $this->message = $message;
+
+ $this->list = $list;
+ $this->actions = $actions;
+
+ $this->dismiss = $dismiss;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.alert.index');
+ }
+
+ protected function getColor($color)
+ {
+ if (! empty($color)) {
+ return $color;
+ }
+
+ switch ($this->type) {
+ case 'success':
+ $color = 'green';
+ break;
+ case 'info':
+ $color = 'blue';
+ break;
+ case 'warning':
+ $color = 'orange';
+ break;
+ case 'danger':
+ case 'error':
+ $color = 'red';
+ break;
+ default:
+ $color = 'green';
+ break;
+ }
+
+ return $color;
+ }
+
+ protected function getIcon($icon)
+ {
+ if (! empty($icon)) {
+ return $icon;
+ }
+
+ switch ($this->type) {
+ case 'success':
+ $icon = 'check_circle';
+ break;
+ case 'info':
+ $icon = 'info';
+ break;
+ case 'warning':
+ $icon = 'warning';
+ break;
+ case 'danger':
+ case 'error':
+ $icon = 'error';
+ break;
+ default:
+ $icon = 'check_circle';
+ break;
+ }
+
+ return $icon;
+ }
+}
diff --git a/app/View/Components/Alert/Border.php b/app/View/Components/Alert/Border.php
new file mode 100644
index 00000000..ad00dde7
--- /dev/null
+++ b/app/View/Components/Alert/Border.php
@@ -0,0 +1,18 @@
+type = !empty($type) ? $type : 'button';
+ $this->override = $this->getOverride($override);
+
+ $this->kind = $kind;
+ $this->class = $this->getClass($class);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.button.index');
+ }
+
+ protected function getOverride($override)
+ {
+ return explode(',', $override);
+ }
+
+ protected function getClass($class)
+ {
+ $default = 'px-3 py-1.5 mb-3 sm:mb-0 rounded-xl text-sm font-medium leading-6';
+
+ switch ($this->kind) {
+ case 'primary':
+ $default .= ' bg-green hover:bg-green-700 text-white disabled:bg-green-100';
+ break;
+ case 'secondary':
+ $default .= ' bg-purple hover:bg-purple-700 text-white disabled:bg-purple-100';
+ break;
+ case 'disabled':
+ $default .= ' bg-gray-100 disabled:bg-gray-100';
+ break;
+ default:
+ $default .= ' bg-gray-100 hover:bg-gray-200 disabled:bg-gray-50';
+ }
+
+ if (in_array('class', $this->override)) {
+ return $class;
+ }
+
+ return $default;
+ }
+}
diff --git a/app/View/Components/Button/Hover.php b/app/View/Components/Button/Hover.php
new file mode 100644
index 00000000..d51010f1
--- /dev/null
+++ b/app/View/Components/Button/Hover.php
@@ -0,0 +1,36 @@
+color = $color;
+ $this->groupHover = $groupHover;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.button.hover');
+ }
+}
diff --git a/app/View/Components/Contacts/Form/Address.php b/app/View/Components/Contacts/Form/Address.php
new file mode 100644
index 00000000..3507926c
--- /dev/null
+++ b/app/View/Components/Contacts/Form/Address.php
@@ -0,0 +1,18 @@
+type = $type;
+ $this->contact = $contact;
+ $this->contact_persons = ($contact) ? $contact->contact_persons : [];
+ $this->currencies = $this->getCurrencies($currencies);
+ $this->currency_code = ($contact) ? $contact->currency_code : default_currency();
+
+ $this->alias = $this->getAlias($type, $alias);
+ $this->folder = $this->getScriptFolder($type, $folder);
+ $this->file = $this->getScriptFile($type, $file);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.contacts.script');
+ }
+
+ protected function getCurrencies($currencies)
+ {
+ if (!empty($currencies)) {
+ return $currencies;
+ }
+
+ return Currency::enabled()->orderBy('name')->get()->makeHidden(['id', 'company_id', 'created_at', 'updated_at', 'deleted_at']);
+ }
+}
diff --git a/app/View/Components/Contacts/Show/Buttons.php b/app/View/Components/Contacts/Show/Buttons.php
new file mode 100644
index 00000000..eb9c8788
--- /dev/null
+++ b/app/View/Components/Contacts/Show/Buttons.php
@@ -0,0 +1,18 @@
+ 0,
+ 'open' => 0,
+ 'overdue' => 0,
+ ];
+
+ $this->counts = [];
+
+ // Handle documents
+ $docs = $this->contact->isCustomer() ? 'invoices' : 'bills';
+
+ // Eager load documents with necessary relations to prevent lazy loading
+ $this->documents = $this->contact->$docs()
+ ->with(['transactions', 'transactions.currency', 'contact', 'last_history', 'items', 'totals'])
+ ->get();
+
+ $this->counts['documents'] = $this->documents->count();
+
+ $today = Date::today()->toDateString();
+
+ foreach ($this->documents as $item) {
+ // Already in transactions
+ if ($item->status == 'paid' || $item->status == 'cancelled') {
+ continue;
+ }
+
+ $transactions = 0;
+
+ foreach ($item->transactions as $transaction) {
+ $transactions += $transaction->getAmountConvertedToDefault();
+ }
+
+ // Check if it's open or overdue invoice
+ if ($item->due_at > $today) {
+ $totals['open'] += $item->getAmountConvertedToDefault() - $transactions;
+ } else {
+ $totals['overdue'] += $item->getAmountConvertedToDefault() - $transactions;
+ }
+ }
+
+ // Handle payments - eager load necessary relations to prevent lazy loading
+ $this->transactions = $this->contact->transactions()
+ ->with(['account', 'category', 'currency', 'contact', 'document', 'recurring'])
+ ->get();
+
+ $this->counts['transactions'] = $this->transactions->count();
+
+ // Prepare data
+ $this->transactions->each(function ($item) use (&$totals) {
+ $totals['paid'] += $item->getAmountConvertedToDefault();
+ });
+
+ $open_amount = money($totals['open']);
+ $overdue_amount = money($totals['overdue']);
+ $paid_amount = money($totals['paid']);
+
+ $summary_amounts = [
+ 'open_exact' => $open_amount->format(),
+ 'open_for_humans' => $open_amount->formatForHumans(),
+ 'overdue_exact' => $overdue_amount->format(),
+ 'overdue_for_humans' => $overdue_amount->formatForHumans(),
+ 'paid_exact' => $paid_amount->format(),
+ 'paid_for_humans' => $paid_amount->formatForHumans(),
+ ];
+
+ $this->summary_amounts = $summary_amounts;
+
+ $this->transactions = $this->paginate($this->transactions->sortByDesc('paid_at'));
+ $this->documents = $this->paginate($this->documents->sortByDesc('issued_at'));
+
+ return view('components.contacts.show.content');
+ }
+
+ /**
+ * Generate a pagination collection.
+ *
+ * @param array|Collection $items
+ * @param int $perPage
+ * @param int $page
+ * @param array $options
+ *
+ * @return LengthAwarePaginator
+ */
+ public function paginate($items, $perPage = null, $page = null, $options = [])
+ {
+ $perPage = $perPage ?: (int) request('limit', setting('default.list_limit', '25'));
+
+ $page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
+
+ $items = $items instanceof Collection ? $items : Collection::make($items);
+
+ return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
+ }
+}
diff --git a/app/View/Components/Contacts/Show/MoreButtons.php b/app/View/Components/Contacts/Show/MoreButtons.php
new file mode 100644
index 00000000..c5db328d
--- /dev/null
+++ b/app/View/Components/Contacts/Show/MoreButtons.php
@@ -0,0 +1,18 @@
+rawDate = $date;
+ $this->format = $this->getFormat($format);
+ $this->function = $function;
+
+ $this->date = $this->getFormatDate($date);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.date');
+ }
+
+ protected function getFormat($format)
+ {
+ if (! empty($format)) {
+ return $format;
+ }
+
+ $date_time = new class() {
+ use DateTime;
+ };
+
+ return $date_time->getCompanyDateFormat();
+ }
+
+ protected function getFormatDate($date)
+ {
+ if (! empty($this->function)) {
+ $date = UDate::parse($date)->{$this->function}();
+
+ return Str::ucfirst($date);
+ }
+
+ return UDate::parse($date)->format($this->format);
+ }
+}
diff --git a/app/View/Components/DeleteButton.php b/app/View/Components/DeleteButton.php
new file mode 100644
index 00000000..a0e57ef8
--- /dev/null
+++ b/app/View/Components/DeleteButton.php
@@ -0,0 +1,288 @@
+label = $this->getLabel($label);
+
+ $this->model = $model;
+ $this->modelId = $modelId;
+ $this->modelName = $modelName;
+ $this->modelTitle = $modelTitle;
+ $this->modelTable = $model->getTable();
+
+ $this->text = $text;
+ $this->type = $type;
+
+ $this->action = $this->getAction($action, $route, $url);
+ $this->route = $route;
+ $this->url = $url;
+
+ $this->title = $this->getTitle($title);
+ $this->message = $this->getMessage($message);
+
+ $this->cancelText = $this->getCancelText($cancelText);
+ $this->deleteText = $this->getDeleteText($deleteText);
+
+ $this->id = $this->getId();
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.delete-button');
+ }
+
+ protected function getId()
+ {
+ if (! empty($this->model)) {
+ return $this->model->{$this->modelId};
+ }
+
+ if (! empty($this->route) && is_array($this->route)) {
+ return $this->route[1];
+ }
+
+ return mt_rand();
+ }
+
+ protected function getLabel($label)
+ {
+ if (! empty($label)) {
+ return $label;
+ }
+
+ return trans('general.delete');
+ }
+
+ protected function getAction($action, $route, $url)
+ {
+ if (! empty($action)) {
+ return $action;
+ }
+
+ if (! empty($route)) {
+ return $this->getRouteAction($route);
+ }
+
+ if (! empty($url)) {
+ return $this->getUrlAction($url);
+ }
+
+ return '';
+ }
+
+ /**
+ * Get the action for a "url" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getUrlAction($options)
+ {
+ if (is_array($options)) {
+ return url($options[0], array_slice($options, 1));
+ }
+
+ if (! empty($this->model)) {
+ return url($options, $this->model->{$this->modelId});
+ }
+
+ return url($options);
+ }
+
+ /**
+ * Get the action for a "route" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getRouteAction($options)
+ {
+ if (is_array($options)) {
+ $parameters = array_slice($options, 1);
+
+ if (array_keys($options) === [0, 1]) {
+ $parameters = head($parameters);
+ }
+
+ return route($options[0], $parameters);
+ }
+
+ if (! empty($this->model)) {
+ return route($options, $this->model->{$this->modelId});
+ }
+
+ return route($options);
+ }
+
+ protected function getTitle($title)
+ {
+ if (! empty($title)) {
+ return $title;
+ }
+
+ $type = '';
+
+ if (! empty($this->model)) {
+ $type = $this->getModelTitle();
+ }
+
+ return ! empty($type) ? trans('general.title.delete', ['type' => $type]) : trans('general.delete');
+ }
+
+ protected function getMessage($cancelText)
+ {
+ if (! empty($cancelText)) {
+ return $cancelText;
+ }
+
+ $name = '';
+ $type = '';
+
+ if (! empty($this->model)) {
+ $page = '';
+
+ if (! empty($this->route)) {
+ if (! is_array($this->route)) {
+ $string = $this->route;
+ }
+
+ if (is_array($this->route)) {
+ $string = $this->route[0];
+ }
+
+ $page = explode('.', $string)[0];
+ } elseif (! empty($this->url)) {
+ $page = explode('/', $this->url)[1];
+ }
+
+ $text = $this->text ? $this->text : $page;
+ $name = e($this->model->{$this->modelName});
+ $name = addslashes($name);
+ $name = Str::replace(['\"', '"'], '"', $name);
+
+ $type = mb_strtolower($this->getModelTitle());
+
+ $message = trans('general.delete_confirm', ['name' => '' . $name . '', 'type' => $type]);
+
+ return $message;
+ }
+
+ return trans('general.delete_confirm', ['name' => '' . $name . '', 'type' => $type]);
+ }
+
+ protected function getModelTitle()
+ {
+ if (! empty($this->modelTitle)) {
+ return $this->modelTitle;
+ }
+
+ $group = 'core';
+ $page = '';
+
+ if (! empty($this->route)) {
+ if (is_array($this->route)) {
+ $string = $this->route[0];
+ } else {
+ $string = $this->route;
+ }
+
+ $paths = explode('.', $string);
+
+ $page = $paths[0];
+ } elseif (! empty($this->url)) {
+ $paths = explode('/', $this->url);
+
+ $page = $paths[1];
+ }
+
+ $title = trans_choice('general.' . $page, 1);
+
+ if (module($page) != null) {
+ $group = $page;
+ $page = (! empty($this->route)) ? $paths[1] : $paths[2];
+
+ $title = trans_choice($group . '::general.' . str_replace('-', '_', $page), 1);
+ }
+
+ return $title;
+ }
+
+ protected function getCancelText($cancelText)
+ {
+ if (! empty($cancelText)) {
+ return $cancelText;
+ }
+
+ return trans('general.cancel');
+ }
+
+ protected function getDeleteText($deleteText)
+ {
+ if (! empty($deleteText)) {
+ return $deleteText;
+ }
+
+ return trans('general.delete');
+ }
+}
diff --git a/app/View/Components/DeleteLink.php b/app/View/Components/DeleteLink.php
new file mode 100644
index 00000000..65dd9ee7
--- /dev/null
+++ b/app/View/Components/DeleteLink.php
@@ -0,0 +1,301 @@
+label = $this->getLabel($label);
+
+ $this->model = $model;
+ $this->modelId = $modelId;
+ $this->modelName = $modelName;
+ $this->modelTitle = $modelTitle;
+ $this->modelTable = $model->getTable();
+
+ $this->text = $text;
+ $this->type = $type;
+
+ $this->action = $this->getAction($action, $route, $url);
+ $this->route = $route;
+ $this->url = $url;
+
+ $this->title = $this->getTitle($title);
+ $this->message = $this->getMessage($message);
+
+ $this->cancelText = $this->getCancelText($cancelText);
+ $this->deleteText = $this->getDeleteText($deleteText);
+
+ $this->id = $this->getId();
+
+ $this->override = $override;
+
+ $this->class = $this->getClass($class);
+ $this->textClass = ! empty($textClass) ? $textClass : 'w-full h-full flex items-center rounded-md px-2 text-sm hover:bg-lilac-100';
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.delete-link');
+ }
+
+ protected function getId()
+ {
+ if (! empty($this->model)) {
+ return $this->model->{$this->modelId};
+ }
+
+ if (! empty($this->route) && is_array($this->route)) {
+ return $this->route[1];
+ }
+
+ return mt_rand();
+ }
+
+ protected function getLabel($label)
+ {
+ if (! empty($label)) {
+ return $label;
+ }
+
+ return trans('general.delete');
+ }
+
+ protected function getAction($action, $route, $url)
+ {
+ if (! empty($action)) {
+ return $action;
+ }
+
+ if (! empty($route)) {
+ return $this->getRouteAction($route);
+ }
+
+ if (! empty($url)) {
+ return $this->getUrlAction($url);
+ }
+
+ return '';
+ }
+
+ /**
+ * Get the action for a "url" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getUrlAction($options)
+ {
+ if (is_array($options)) {
+ return url($options[0], array_slice($options, 1));
+ }
+
+ if (! empty($this->model)) {
+ return url($options, $this->model->{$this->modelId});
+ }
+
+ return url($options);
+ }
+
+ /**
+ * Get the action for a "route" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getRouteAction($options)
+ {
+ if (is_array($options)) {
+ $parameters = array_slice($options, 1);
+
+ if (array_keys($options) === [0, 1]) {
+ $parameters = head($parameters);
+ }
+
+ return route($options[0], $parameters);
+ }
+
+ if (! empty($this->model)) {
+ return route($options, $this->model->{$this->modelId});
+ }
+
+ return route($options);
+ }
+
+ protected function getTitle($title)
+ {
+ if (! empty($title)) {
+ return $title;
+ }
+
+ $type = '';
+
+ if (! empty($this->model)) {
+ $type = $this->getModelTitle();
+ }
+
+ return ! empty($type) ? trans('general.title.delete', ['type' => $type]) : trans('general.delete');
+ }
+
+ protected function getMessage($cancelText)
+ {
+ if (!empty($cancelText)) {
+ return $cancelText;
+ }
+
+ $name = '';
+ $type = '';
+
+ if (! empty($this->model)) {
+ $page = '';
+
+ if (! empty($this->route)) {
+ $page = explode('.', $this->route)[0];
+ } elseif (! empty($this->url)) {
+ $page = explode('/', $this->url)[1];
+ }
+
+ $text = $this->text ? $this->text : $page;
+ $name = e($this->model->{$this->modelName});
+ $name = addslashes($name);
+ $name = Str::replace(['\"', '"'], '"', $name);
+
+ $type = mb_strtolower($this->getModelTitle());
+
+ $message = trans('general.delete_confirm', ['name' => '' . $name . '', 'type' => $type]);
+
+ return $message;
+ }
+
+ return trans('general.delete_confirm', ['name' => '' . $name . '', 'type' => $type]);
+ }
+
+ protected function getModelTitle()
+ {
+ if (! empty($this->modelTitle)) {
+ return $this->modelTitle;
+ }
+
+ $group = 'core';
+ $page = '';
+
+ if (! empty($this->route)) {
+ $paths = explode('.', $this->route);
+
+ $page = $paths[0];
+ } elseif (! empty($this->url)) {
+ $paths = explode('/', $this->url);
+
+ $page = $paths[1];
+ }
+
+ $title = trans_choice('general.' . $page, 1);
+
+ if (module($page) != null) {
+ $group = $page;
+ $page = (! empty($this->route)) ? $paths[1] : $paths[2];
+
+ $title = trans_choice($group . '::general.' . $page, 1);
+ }
+
+ return $title;
+ }
+
+ protected function getCancelText($cancelText)
+ {
+ if (! empty($cancelText)) {
+ return $cancelText;
+ }
+
+ return trans('general.cancel');
+ }
+
+ protected function getDeleteText($deleteText)
+ {
+ if (! empty($deleteText)) {
+ return $deleteText;
+ }
+
+ return trans('general.delete');
+ }
+
+ protected function getClass($class)
+ {
+ $default_class = 'w-full flex items-center text-red sm:text-purple px-2 h-9 leading-9 whitespace-nowrap';
+
+ $explode = explode(',', $this->override);
+
+ if (count($explode) && in_array('class', $explode)) {
+ $default_class = $class;
+ } else {
+ $default_class .= ' ' . $class;
+ }
+
+ return $default_class;
+ }
+}
diff --git a/app/View/Components/Documents/Form/Advanced.php b/app/View/Components/Documents/Form/Advanced.php
new file mode 100644
index 00000000..86c119fd
--- /dev/null
+++ b/app/View/Components/Documents/Form/Advanced.php
@@ -0,0 +1,18 @@
+type . '.route.parameter');
+
+ return view('components.documents.form.company', compact('company', 'inputNameType'));
+ }
+}
diff --git a/app/View/Components/Documents/Form/Contact.php b/app/View/Components/Documents/Form/Contact.php
new file mode 100644
index 00000000..01ffbfb2
--- /dev/null
+++ b/app/View/Components/Documents/Form/Contact.php
@@ -0,0 +1,230 @@
+type = $type;
+ $this->contact = $contact;
+ $this->contacts = $contacts;
+ $this->searchRoute = $searchRoute;
+ $this->createRoute = $createRoute;
+ $this->error = ($error) ?: "form.errors.get('contact_id')" ;
+
+ $this->textAddContact = $this->getTextAddContact($type, $textAddContact);
+ $this->textCreateNewContact = $this->getTextCreateNewContact($type, $textCreateNewContact);
+ $this->textEditContact = $this->getTextEditContact($type, $textEditContact);
+ $this->textContactInfo = $this->getTextContactInfo($type, $textContactInfo);
+ $this->textChooseDifferentContact = $this->getTextChooseDifferentContact($type, $textChooseDifferentContact);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ if (empty($this->contacts)) {
+ $this->contacts = Model::{$this->type}()->enabled()->orderBy('name')->take(setting('default.select_limit'))->get();
+
+ if (!empty($this->contact) && (!$this->contacts->contains('id', $contact->id))) {
+ $this->contacts->push($this->contact);
+ }
+ }
+
+ if (empty($this->searchRoute)) {
+ switch ($this->type) {
+ case 'customer':
+ $this->searchRoute = route('customers.index');
+ break;
+ case 'vendor':
+ $this->searchRoute = route('vendors.index');
+ break;
+ }
+ }
+
+ if (empty($this->createRoute)) {
+ switch ($this->type) {
+ case 'customer':
+ $this->createRoute = route('modals.customers.create');
+ break;
+ case 'vendor':
+ $this->createRoute = route('modals.vendors.create');
+ break;
+ }
+ }
+
+ #todo 3rd part apps
+ $this->placeholder = trans('general.placeholder.contact_search', ['type' => trans_choice('general.' . Str::plural($this->type, 2), 1)]);
+
+ return view('components.documents.form.contact');
+ }
+
+ protected function getTextAddContact($type, $textAddContact)
+ {
+ if (!empty($textAddContact)) {
+ return $textAddContact;
+ }
+
+ switch ($type) {
+ case 'bill':
+ case 'expense':
+ case 'purchase':
+ $textAddContact = [
+ 'general.form.add',
+ 'general.vendors'
+ ];
+ break;
+ default:
+ $textAddContact = [
+ 'general.form.add',
+ 'general.customers'
+ ];
+ break;
+ }
+
+ return $textAddContact;
+ }
+
+ protected function getTextCreateNewContact($type, $textCreateNewContact)
+ {
+ if (!empty($textCreateNewContact) && is_array($textCreateNewContact)) {
+ return trans($textCreateNewContact[0], ['type' => trans_choice($textCreateNewContact[1], 1)]);
+ }
+
+ switch ($type) {
+ case 'bill':
+ case 'expense':
+ case 'purchase':
+ $textCreateNewContact = [
+ 'general.form.add_new',
+ 'general.vendors'
+ ];
+ break;
+ default:
+ $textCreateNewContact = [
+ 'general.form.add_new',
+ 'general.customers'
+ ];
+ break;
+ }
+
+ return $textCreateNewContact;
+ }
+
+ protected function getTextEditContact($type, $textEditContact)
+ {
+ if (!empty($textEditContact)) {
+ return $textEditContact;
+ }
+
+ switch ($type) {
+ case 'bill':
+ case 'expense':
+ case 'purchase':
+ $textEditContact = [
+ 'general.form.contact_edit',
+ 'general.vendors'
+ ];
+ break;
+ default:
+ $textEditContact = [
+ 'general.form.contact_edit',
+ 'general.customers'
+ ];
+ break;
+ }
+
+ return $textEditContact;
+ }
+
+ protected function getTextContactInfo($type, $textContactInfo)
+ {
+ if (!empty($textContactInfo)) {
+ return $textContactInfo;
+ }
+
+ switch ($type) {
+ case 'bill':
+ case 'expense':
+ case 'purchase':
+ $textContactInfo = 'bills.bill_from';
+ break;
+ default:
+ $textContactInfo = 'invoices.bill_to';
+ break;
+ }
+
+ return $textContactInfo;
+ }
+
+ protected function getTextChooseDifferentContact($type, $textChooseDifferentContact)
+ {
+ if (!empty($textChooseDifferentContact)) {
+ return $textChooseDifferentContact;
+ }
+
+ switch ($type) {
+ case 'bill':
+ case 'expense':
+ case 'purchase':
+ $textChooseDifferentContact = [
+ 'general.form.choose_different',
+ 'general.vendors'
+ ];
+ break;
+ default:
+ $textChooseDifferentContact = [
+ 'general.form.choose_different',
+ 'general.customers'
+ ];
+ break;
+ }
+
+ return $textChooseDifferentContact;
+ }
+}
diff --git a/app/View/Components/Documents/Form/Content.php b/app/View/Components/Documents/Form/Content.php
new file mode 100644
index 00000000..b7c40415
--- /dev/null
+++ b/app/View/Components/Documents/Form/Content.php
@@ -0,0 +1,24 @@
+document)) {
+ $status = $this->document->status;
+ }
+
+ return view('components.documents.form.content', compact('status'));
+ }
+}
diff --git a/app/View/Components/Documents/Form/Footer.php b/app/View/Components/Documents/Form/Footer.php
new file mode 100644
index 00000000..e45bfe60
--- /dev/null
+++ b/app/View/Components/Documents/Form/Footer.php
@@ -0,0 +1,18 @@
+type = $type;
+ $this->isSale = $isSale;
+ $this->isPurchase = $isPurchase;
+ $this->searchUrl = $this->getSearchUrl($searchUrl);
+ $this->searchCharLimit = $searchCharLimit;
+ $this->searchListKey = $searchListKey;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ $price_type = $this->getPriceType($this->type, $this->isSale, $this->isPurchase);
+
+ $items = Item::priceType($price_type)->enabled()->orderBy('name')->take(setting('default.select_limit'))->get();
+
+ foreach ($items as $item) {
+ $price = $item->{$price_type . '_price'};
+
+ $item->price = $price;
+ }
+
+ $price = $price_type . '_price';
+
+ return view('components.documents.form.item-button', compact('items', 'price'));
+ }
+
+ protected function getSearchUrl($url)
+ {
+ if (empty($url)) {
+ return route('items.index');
+ }
+
+ return $url;
+ }
+
+ protected function getPriceType($type, $is_sale, $is_purchase)
+ {
+ if (!empty($is_sale)) {
+ return 'sale';
+ }
+
+ if (!empty($is_purchase)) {
+ return 'purchase';
+ }
+
+ switch ($type) {
+ case 'bill':
+ case 'expense':
+ case 'purchase':
+ $type = 'purchase';
+ break;
+ case 'sale':
+ case 'income':
+ case 'invoice':
+ default:
+ $type = 'sale';
+ }
+
+ return $type;
+ }
+}
diff --git a/app/View/Components/Documents/Form/ItemColumns.php b/app/View/Components/Documents/Form/ItemColumns.php
new file mode 100644
index 00000000..6a62101e
--- /dev/null
+++ b/app/View/Components/Documents/Form/ItemColumns.php
@@ -0,0 +1,31 @@
+type = $type;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.documents.form.item-columns');
+ }
+}
diff --git a/app/View/Components/Documents/Form/Items.php b/app/View/Components/Documents/Form/Items.php
new file mode 100644
index 00000000..63187725
--- /dev/null
+++ b/app/View/Components/Documents/Form/Items.php
@@ -0,0 +1,21 @@
+orderBy('name')->get();
+
+ return view('components.documents.form.items', compact('taxes'));
+ }
+}
diff --git a/app/View/Components/Documents/Form/LineItem.php b/app/View/Components/Documents/Form/LineItem.php
new file mode 100644
index 00000000..9ba17e85
--- /dev/null
+++ b/app/View/Components/Documents/Form/LineItem.php
@@ -0,0 +1,18 @@
+document = $document;
+ $this->hideShow = $hideShow;
+
+ // Load relations if not loaded to prevent lazy loading
+ $relations = ['contact', 'last_history', 'items', 'totals'];
+
+ foreach ($relations as $relation) {
+ if (! $document->relationLoaded($relation)) {
+ $document->load($relation);
+ }
+ }
+
+ $this->showRoute = $this->getShowRoute($document->contact->type, $showRoute);
+ $this->showDocumentRoute = $this->getShowRoute($document->type, $showDocumentRoute);
+ $this->placement = (! empty($placement)) ? $placement : 'left';
+ $this->id = (! empty($id)) ? $id : 'tooltip-information-' . $document->id;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.documents.index.information');
+ }
+}
diff --git a/app/View/Components/Documents/Index/MoreButtons.php b/app/View/Components/Documents/Index/MoreButtons.php
new file mode 100644
index 00000000..58276c5f
--- /dev/null
+++ b/app/View/Components/Documents/Index/MoreButtons.php
@@ -0,0 +1,18 @@
+type = $type;
+ $this->document = $document;
+ $this->items = $items;
+ $this->currencies = $this->getCurrencies($currencies);
+ $this->currency_code = ($document) ? $document->currency_code : default_currency();
+ $this->taxes = $this->getTaxes($taxes);
+
+ $this->alias = $this->getAlias($type, $alias);
+ $this->folder = $this->getScriptFolder($type, $folder);
+ $this->file = $this->getScriptFile($type, $file);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.documents.script');
+ }
+
+ protected function getCurrencies($currencies)
+ {
+ if (!empty($currencies)) {
+ return $currencies;
+ }
+
+ return Currency::enabled()->orderBy('name')->get()->makeHidden(['id', 'company_id', 'created_at', 'updated_at', 'deleted_at']);
+ }
+
+ protected function getTaxes($taxes)
+ {
+ if (!empty($taxes)) {
+ return $taxes;
+ }
+
+ return Tax::enabled()->orderBy('name')->get()->makeHidden(['company_id', 'created_at', 'updated_at', 'deleted_at']);
+ }
+}
diff --git a/app/View/Components/Documents/Show/Attachment.php b/app/View/Components/Documents/Show/Attachment.php
new file mode 100644
index 00000000..8bb1e027
--- /dev/null
+++ b/app/View/Components/Documents/Show/Attachment.php
@@ -0,0 +1,39 @@
+transaction_attachment = collect();
+
+ // Eager load transactions with their media/attachments to prevent N+1 queries
+ if (!$this->document->relationLoaded('transactions')) {
+ $this->document->load(['transactions.media', 'transactions']);
+ }
+
+ if ($this->document->transactions->count()) {
+ foreach ($this->document->transactions as $transaction) {
+ if (! $transaction->attachment) {
+ continue;
+ }
+
+ foreach ($transaction->attachment as $file) {
+ $this->transaction_attachment->push($file);
+ }
+ }
+ }
+
+ return view('components.documents.show.attachment');
+ }
+}
diff --git a/app/View/Components/Documents/Show/Buttons.php b/app/View/Components/Documents/Show/Buttons.php
new file mode 100644
index 00000000..9d774cf3
--- /dev/null
+++ b/app/View/Components/Documents/Show/Buttons.php
@@ -0,0 +1,18 @@
+where('recurable_id', $this->document->id)
+ ->first();
+
+ $this->type_lowercase = Str::lower(trans_choice($this->textPage, 2));
+
+ return view('components.documents.show.children', compact('recurring'));
+ }
+}
diff --git a/app/View/Components/Documents/Show/Content.php b/app/View/Components/Documents/Show/Content.php
new file mode 100644
index 00000000..d8f790f1
--- /dev/null
+++ b/app/View/Components/Documents/Show/Content.php
@@ -0,0 +1,18 @@
+description = ($this->document->isRecurringDocument()) ? 'documents.slider.create_recurring' : 'documents.slider.create';
+
+ $this->user_name = $this->document->owner->name;
+
+ $this->type_lowercase = Str::lower(trans_choice($this->textPage, 1));
+
+ $this->created_date = '' . company_date($this->document->created_at) . '';
+
+ return view('components.documents.show.create');
+ }
+}
diff --git a/app/View/Components/Documents/Show/GetPaid.php b/app/View/Components/Documents/Show/GetPaid.php
new file mode 100644
index 00000000..41d476ec
--- /dev/null
+++ b/app/View/Components/Documents/Show/GetPaid.php
@@ -0,0 +1,32 @@
+description = trans('general.amount_due') . ': ' . '' . money($this->document->amount_due, $this->document->currency_code) . '';
+
+ if (
+ request()->isSigned($this->document->company_id)
+ || request()->isPreview($this->document->company_id)
+ || request()->isPortal($this->document->company_id)
+ ) {
+ $this->text_document_transaction = 'documents.portal_transaction';
+ }
+
+ return view('components.documents.show.get-paid');
+ }
+}
diff --git a/app/View/Components/Documents/Show/MakePayment.php b/app/View/Components/Documents/Show/MakePayment.php
new file mode 100644
index 00000000..3eeeb0cf
--- /dev/null
+++ b/app/View/Components/Documents/Show/MakePayment.php
@@ -0,0 +1,32 @@
+description = trans('general.amount_due') . ': ' . '' . money($this->document->amount_due, $this->document->currency_code) . '';
+
+ if (
+ request()->isSigned($this->document->company_id)
+ || request()->isPreview($this->document->company_id)
+ || request()->isPortal($this->document->company_id)
+ ) {
+ $this->text_document_transaction = 'documents.portal_transaction';
+ }
+
+ return view('components.documents.show.make-payment');
+ }
+}
diff --git a/app/View/Components/Documents/Show/Message.php b/app/View/Components/Documents/Show/Message.php
new file mode 100644
index 00000000..c9cb274c
--- /dev/null
+++ b/app/View/Components/Documents/Show/Message.php
@@ -0,0 +1,44 @@
+type = $type;
+ $this->backgroundColor = $backgroundColor;
+ $this->textColor = $textColor;
+ $this->message = $message;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.documents.show.message');
+ }
+}
diff --git a/app/View/Components/Documents/Show/MoreButtons.php b/app/View/Components/Documents/Show/MoreButtons.php
new file mode 100644
index 00000000..7a087db6
--- /dev/null
+++ b/app/View/Components/Documents/Show/MoreButtons.php
@@ -0,0 +1,18 @@
+description = $this->document->isRecurringDocument() ? 'documents.slider.create_recurring' : 'general.last_received';
+
+ $this->last_received = $this->document->histories()->status('received')->latest()->first();
+
+ $this->user_name = ($this->last_received) ? $this->last_received->owner->name : trans('general.na');
+
+ $this->type_lowercase = Str::lower(trans_choice($this->textPage, 1));
+
+ $date = ($this->last_received) ? company_date($this->last_received->created_at) : trans('general.na');
+
+ $this->last_received_date = '' . $date . '';
+
+ return view('components.documents.show.receive');
+ }
+}
diff --git a/app/View/Components/Documents/Show/Restore.php b/app/View/Components/Documents/Show/Restore.php
new file mode 100644
index 00000000..ee087c1b
--- /dev/null
+++ b/app/View/Components/Documents/Show/Restore.php
@@ -0,0 +1,39 @@
+description = 'documents.slider.cancel';
+
+ $this->last_cancelled = $this->document->histories()->status('cancelled')->latest()->first();
+
+ $this->user_name = ($this->last_cancelled) ? $this->last_cancelled->owner->name : trans('general.na');
+
+ $this->type_lowercase = Str::lower(trans_choice($this->textPage, 1));
+
+ $this->last_cancelled_date = '' . company_date($this->last_cancelled->created_at) . '';
+
+ return view('components.documents.show.restore');
+ }
+}
diff --git a/app/View/Components/Documents/Show/Schedule.php b/app/View/Components/Documents/Show/Schedule.php
new file mode 100644
index 00000000..381f38ce
--- /dev/null
+++ b/app/View/Components/Documents/Show/Schedule.php
@@ -0,0 +1,36 @@
+where('recurable_id', $this->document->id)
+ ->first();
+
+ $started_date = '' . company_date($recurring->started_at) . '';
+ $frequency = Str::lower(trans('recurring.' . str_replace(['daily', 'ly'], ['days', 's'], $recurring->frequency)));
+ $invertal = $recurring->interval;
+
+ $this->description = trans('transactions.slider.schedule', [
+ 'frequency' => $frequency,
+ 'interval' => $invertal,
+ 'date' => $started_date
+ ]);
+
+ return view('components.documents.show.schedule', compact('recurring'));
+ }
+}
diff --git a/app/View/Components/Documents/Show/Send.php b/app/View/Components/Documents/Show/Send.php
new file mode 100644
index 00000000..14f7dede
--- /dev/null
+++ b/app/View/Components/Documents/Show/Send.php
@@ -0,0 +1,45 @@
+description = $this->document->isRecurringDocument() ? 'documents.slider.create_recurring' : 'general.last_sent';
+
+ $this->histories = $this->document->histories()->status('sent')->latest()->get();
+
+ $this->last_sent = $this->histories->first();
+
+ $this->user_name = ($this->last_sent) ? $this->last_sent->owner->name : trans('general.na');
+
+ $this->type_lowercase = Str::lower(trans_choice($this->textPage, 1));
+
+ $date = ($this->last_sent) ? company_date($this->last_sent->created_at) : trans('general.na');
+
+ $this->last_sent_date = '' . $date . '';
+
+ return view('components.documents.show.send');
+ }
+}
diff --git a/app/View/Components/Documents/Show/Template.php b/app/View/Components/Documents/Show/Template.php
new file mode 100644
index 00000000..15ef793c
--- /dev/null
+++ b/app/View/Components/Documents/Show/Template.php
@@ -0,0 +1,18 @@
+id = $id;
+ $this->override = explode(',', $override);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.dropdown.index');
+ }
+}
diff --git a/app/View/Components/Dropdown/Button.php b/app/View/Components/Dropdown/Button.php
new file mode 100644
index 00000000..85157875
--- /dev/null
+++ b/app/View/Components/Dropdown/Button.php
@@ -0,0 +1,18 @@
+href = $href;
+ $this->target = $target;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.dropdown.link');
+ }
+}
diff --git a/app/View/Components/EmptyPage.php b/app/View/Components/EmptyPage.php
new file mode 100644
index 00000000..5f595bfa
--- /dev/null
+++ b/app/View/Components/EmptyPage.php
@@ -0,0 +1,370 @@
+alias = (module($alias) === null) ? 'core': $alias;
+ $this->group = $group;
+ $this->page = $page;
+ $this->docsCategory = $docsCategory;
+
+ $this->title = $this->getTitle($title);
+ $this->createButtonTitle = $createButtonTitle;
+ $this->importButtonTitle = $importButtonTitle;
+
+ $this->description = $this->getDescription($description);
+
+ $this->imageEmptyPage = $imageEmptyPage;
+ $this->image = $this->getImage($page, $image);
+
+ $this->checkPermissionCreate = $checkPermissionCreate;
+ $this->permissionCreate = $this->getPermissionCreate($page, $group, $permissionCreate);
+
+ $this->hideButtonCreate = $hideButtonCreate;
+ $this->hideButtonImport = $hideButtonImport;
+ $this->hideDocsDescription = $hideDocsDescription;
+
+ $this->buttons = $this->getButtons($page, $group, $buttons);
+
+ $this->suggestions = $this->getSuggestionModules();
+ $this->suggestion = $this->getSuggestionModule();
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.empty-page');
+ }
+
+ protected function getTitle($title = null, $number = 2)
+ {
+ if (! empty($title)) {
+ return $title;
+ }
+
+ switch ($this->alias) {
+ case 'core':
+ $text = 'general.' . $this->page;
+ $text2 = 'general.' . Str::replace('-', '_', $this->page);
+ break;
+ default:
+ $text = $this->alias . '::general.' . $this->page;
+ $text2 = $this->alias . '::general.' . Str::replace('-', '_', $this->page);
+ }
+
+ $title = trans_choice($text, $number);
+
+ if ($title == $text) {
+ $title = trans_choice($text2, $number);
+ }
+
+ return $title;
+ }
+
+ protected function getDescription($description)
+ {
+ if (! empty($description)) {
+ return $description;
+ }
+
+ switch ($this->alias) {
+ case 'core':
+ $text = 'general.empty.' . $this->page;
+ $text2 = 'general.empty.' . Str::replace('-', '_', $this->page);
+ break;
+ default:
+ $text = $this->alias . '::general.empty.' . $this->page;
+ $text2 = $this->alias . '::general.empty.' . Str::replace('-', '_', $this->page);
+ }
+
+ $description = trans($text);
+
+ if ($description == $text) {
+ $description = trans($text2);
+ }
+
+ if ($this->hideDocsDescription) {
+ $docs_url = $this->getDocsUrl();
+
+ if (! empty($docs_url)) {
+ $description .= ' ' . trans('general.empty.documentation', ['url' => $docs_url]);
+ }
+ }
+
+ return $description;
+ }
+
+ protected function getDocsUrl()
+ {
+ return null;
+ }
+
+ protected function getImage($page, $image)
+ {
+ if (! empty($image)) {
+ return $image;
+ }
+
+ if (! empty($this->imageEmptyPage)) {
+ return asset($this->imageEmptyPage);
+ }
+
+ $path = 'public/img/empty_pages/' . $page . '.png';
+
+ if ($this->alias != 'core') {
+ $path = 'modules/' . Str::studly($this->alias) . '/Resources/assets/img/empty-' . $page . '.png';
+
+ if (! file_exists($path)) {
+ $path = 'public/img/empty_pages/default.png';
+ }
+ }
+
+ return asset($path);
+ }
+
+ protected function getPermissionCreate($page, $group, $permissionCreate)
+ {
+ if (! empty($permissionCreate)) {
+ return $permissionCreate;
+ }
+
+ $pages = [
+ 'reconciliations' => 'create-banking-reconciliations',
+ 'transfers' => 'create-banking-transfers',
+ 'vendors' => 'create-purchases-vendors',
+ 'customers' => 'create-sales-customers',
+ 'taxes' => 'create-settings-taxes',
+ 'items' => 'create-common-items',
+ ];
+
+ if (array_key_exists($page, $pages)) {
+ $permissionCreate = $pages[$page];
+ }
+
+ if (empty($permissionCreate) && !empty($group)) {
+ $permissionCreate = 'create-' . $group . '-' . $page;
+ }
+
+ return $permissionCreate;
+ }
+
+ protected function getButtons($page, $group, $buttons)
+ {
+ if (! empty($buttons)) {
+ $suggestion = $this->getSuggestionModule();
+
+ if (! empty($suggestion)) {
+ return array_slice($buttons, 0, 2);
+ } else {
+ return array_slice($buttons, 0, 3);
+ }
+ }
+
+ if (! $this->hideButtonCreate) {
+ $buttons[] = $this->getCreateButton($page, $group);
+ }
+
+ if (! $this->hideButtonImport) {
+ $buttons[] = $this->getImportButton();
+ }
+
+ return $buttons;
+ }
+
+ protected function getCreateButton($page, $group)
+ {
+ try {
+ $route = route($group . '.' . $page . '.create');
+ } catch (\Exception $e) {
+ $route = route($page . '.create');
+ }
+
+ $title = $this->createButtonTitle;
+
+ if (! $title) {
+ $title = $this->getTitle(null, 1);
+ }
+
+ return [
+ 'url' => $route,
+ 'permission' => $this->permissionCreate,
+ 'text' => trans('general.title.new', ['type' => $title]),
+ 'description' => trans('general.empty.actions.new', ['type' => strtolower($title)]),
+ 'active_badge' => true,
+ 'stack' => 'create_button',
+ ];
+ }
+
+ protected function getImportButton()
+ {
+ $importRoute = $this->getImportRoute($this->importRoute);
+ $importRouteParameters = $this->getImportRouteParameters($this->importRouteParameters);
+
+ $title = $this->importButtonTitle;
+
+ if (! $title) {
+ $title = $this->getTitle();
+ }
+
+ return [
+ 'url' => route($importRoute, $importRouteParameters),
+ 'permission' => $this->permissionCreate,
+ 'text' => trans('import.title', ['type' => $title]),
+ 'description' => trans('general.empty.actions.import', ['type' => strtolower($title)]),
+ 'active_badge' => false,
+ 'stack' => 'import_button',
+ ];
+ }
+
+ protected function getImportRoute($importRoute)
+ {
+ if (! empty($importRoute)) {
+ return $importRoute;
+ }
+
+ $route = 'import.create';
+
+ return $route;
+ }
+
+ protected function getImportRouteParameters($importRouteParameters)
+ {
+ if (! empty($importRouteParameters)) {
+ return $importRouteParameters;
+ }
+
+ return array_slice(request()->segments(), -2, 2, true) ;
+ }
+
+ public function getSuggestionModule()
+ {
+ return ! empty($this->suggestions) ? Arr::random($this->suggestions) : false;
+ }
+
+ public function getSuggestionModules()
+ {
+ if ((! $user = user()) || $user->cannot('read-modules-home')) {
+ return [];
+ }
+
+ if (! $path = Route::current()->uri()) {
+ return [];
+ }
+
+ $path = str_replace('{company_id}/', '', $path);
+
+ if (! $suggestions = $this->getSuggestions($path)) {
+ return [];
+ }
+
+ $modules = [];
+
+ foreach ($suggestions->modules as $s_module) {
+ if ($this->moduleIsEnabled($s_module->alias)) {
+ continue;
+ }
+
+ $s_module->action_url = company_id() . '/' . $s_module->action_url;
+
+ $modules[] = $s_module;
+ }
+
+ if (empty($modules)) {
+ return [];
+ }
+
+ return $modules;
+ }
+}
diff --git a/app/View/Components/Form.php b/app/View/Components/Form.php
new file mode 100644
index 00000000..edd48eda
--- /dev/null
+++ b/app/View/Components/Form.php
@@ -0,0 +1,132 @@
+method = Str::upper($method);
+ $this->action = $this->getAction($action, $route, $url);
+ $this->model = $model;
+ $this->class = $class;
+ $this->role = $role;
+ $this->novalidate = $novalidate;
+ $this->enctype = $enctype;
+ $this->acceptCharset = $acceptCharset;
+ $this->submit = $submit;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.form.index');
+ }
+
+ protected function getAction($action, $route, $url)
+ {
+ if (!empty($action)) {
+ return $action;
+ }
+
+ if (!empty($route)) {
+ return $this->getRouteAction($route);
+ }
+
+ if (!empty($url)) {
+ return $this->getUrlAction($url);
+ }
+
+ return '';
+ }
+
+ /**
+ * Get the action for a "url" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getUrlAction($options)
+ {
+ if (is_array($options)) {
+ return url($options[0], array_slice($options, 1));
+ }
+
+ return url($options);
+ }
+
+ /**
+ * Get the action for a "route" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getRouteAction($options)
+ {
+ if (is_array($options)) {
+ $parameters = array_slice($options, 1);
+
+ if (array_keys($options) === [0, 1]) {
+ $parameters = head($parameters);
+ }
+
+ return route($options[0], $parameters);
+ }
+
+ return route($options);
+ }
+}
diff --git a/app/View/Components/Form/Accordion.php b/app/View/Components/Form/Accordion.php
new file mode 100644
index 00000000..16519537
--- /dev/null
+++ b/app/View/Components/Form/Accordion.php
@@ -0,0 +1,46 @@
+type = $type;
+ $this->icon = $this->getIcon($icon);
+ $this->open = $open;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.form.accordion.index');
+ }
+
+ protected function getIcon($icon)
+ {
+ if (! empty($icon)) {
+ return $icon;
+ }
+
+ return 'expand_more';
+ }
+}
diff --git a/app/View/Components/Form/Buttons.php b/app/View/Components/Form/Buttons.php
new file mode 100644
index 00000000..a541cc94
--- /dev/null
+++ b/app/View/Components/Form/Buttons.php
@@ -0,0 +1,139 @@
+groupClass = $this->getGroupClass($groupClass);
+
+ $this->cancel = $this->getCancel($cancel, $cancelRoute, $cancelUrl);
+ $this->cancelClass = $this->getCancelClass($cancelClass);
+ $this->cancelText = $this->getCancelText($cancelText);
+ $this->withoutCancel = $withoutCancel;
+
+ $this->saveDisabled = ! empty($saveDisabled) ? $saveDisabled : 'form.loading';
+ $this->saveLoading = ! empty($saveLoading) ? $saveLoading : 'form.loading';
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.form.buttons');
+ }
+
+ protected function getGroupClass($groupClass)
+ {
+ if (! empty($groupClass)) {
+ return $groupClass;
+ }
+
+ return $this->groupClass;
+ }
+
+ protected function getCancel($cancel, $route, $url)
+ {
+ if (! empty($cancel)) {
+ return $cancel;
+ }
+
+ if (! empty($route)) {
+ return $this->getRouteAction($route);
+ }
+
+ if (! empty($url)) {
+ return $this->getUrlAction($url);
+ }
+
+ return '';
+ }
+
+ /**
+ * Get the action for a "url" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getUrlAction($options)
+ {
+ if (is_array($options)) {
+ return url($options[0], array_slice($options, 1));
+ }
+
+ return url($options);
+ }
+
+ /**
+ * Get the action for a "route" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getRouteAction($options)
+ {
+ if (is_array($options)) {
+ $parameters = array_slice($options, 1);
+
+ if (array_keys($options) === [0, 1]) {
+ $parameters = head($parameters);
+ }
+
+ return route($options[0], $parameters);
+ }
+
+ return route($options);
+ }
+
+ protected function getCancelClass($cancelClass)
+ {
+ if (! empty($cancelClass)) {
+ return $cancelClass;
+ }
+
+ return $this->cancelClass;
+ }
+
+ protected function getCancelText($cancelText)
+ {
+ if (! empty($cancelText)) {
+ return $cancelText;
+ }
+
+ return trans('general.cancel');
+ }
+}
\ No newline at end of file
diff --git a/app/View/Components/Form/Group/Account.php b/app/View/Components/Form/Group/Account.php
new file mode 100644
index 00000000..3616b164
--- /dev/null
+++ b/app/View/Components/Form/Group/Account.php
@@ -0,0 +1,73 @@
+name)) {
+ $this->name = 'account_id';
+ }
+
+ $this->path = route('modals.accounts.create');
+
+ if (empty($this->accounts) && ! empty($this->options)) {
+ $this->accounts = $this->options;
+ } else if (empty($this->accounts)) {
+ $this->accounts = $this->getAccounts();
+ }
+
+ $model = $this->getParentData('model');
+
+ $account_id = old('account.id', old('account_id', null));
+
+ if (! empty($account_id)) {
+ $this->selected = $account_id;
+
+ if (! $this->accounts->has($account_id)) {
+ $account = Model::with('currency')->find($account_id);
+
+ $this->accounts->push($account);
+ }
+ }
+
+ if (! empty($model) && ! empty($model->{$this->name})) {
+ $this->selected = $model->{$this->name};
+
+ $selected_account = $model->account;
+ }
+
+ if (! empty($selected_account) && ! $this->accounts->contains('id', $selected_account->id)) {
+ $this->accounts->push($selected_account);
+ }
+
+ if ($this->selected === null) {
+ $this->selected = setting('default.account');
+ }
+
+ // Share accounts with all views
+ view()->share('accounts', $this->accounts);
+
+ return view('components.form.group.account');
+ }
+
+ protected function getAccounts()
+ {
+ return Model::with('currency')->enabled()->orderBy('name')->get();
+ }
+}
diff --git a/app/View/Components/Form/Group/Attachment.php b/app/View/Components/Form/Group/Attachment.php
new file mode 100644
index 00000000..50d6da9f
--- /dev/null
+++ b/app/View/Components/Form/Group/Attachment.php
@@ -0,0 +1,80 @@
+ 'form-file dropzone-column w-1/2 h-32.5',
+ ];
+
+ public $file_types;
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ $this->setFileTypes();
+
+ $this->custom_attributes = $this->setCustomAttributes();
+
+ return view('components.form.group.attachment');
+ }
+
+ protected function setFileTypes()
+ {
+ $this->file_types = [];
+
+ $file_type_mimes = explode(',', config('filesystems.mimes'));
+
+ $file_types = [];
+
+ foreach ($file_type_mimes as $mime) {
+ $file_types[] = '.' . $mime;
+ }
+
+ $this->file_types = implode(',', $file_types);
+ }
+
+ protected function setCustomAttributes()
+ {
+ $attributes = [];
+
+ if (! empty($this->required)) {
+ $attributes['required'] = $this->required;
+ }
+
+ if (! empty($this->disabled)) {
+ $attributes['disabled'] = $this->disabled;
+ }
+
+ if (! empty($this->readonly)) {
+ $attributes['readonly'] = $this->readonly;
+ }
+
+ if (! empty($this->options)) {
+ $attributes['options'] = $this->options;
+ }
+
+ if (! empty($this->multiple)) {
+ $attributes['multiple'] = $this->multiple;
+ }
+
+ foreach ($this->custom_attributes as $key => $value) {
+ $attributes[$key] = $value;
+ }
+
+ return $attributes;
+ }
+}
diff --git a/app/View/Components/Form/Group/Category.php b/app/View/Components/Form/Group/Category.php
new file mode 100644
index 00000000..a7ca6ee1
--- /dev/null
+++ b/app/View/Components/Form/Group/Category.php
@@ -0,0 +1,184 @@
+ 'id',
+ 'value' => 'name',
+ ];
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ if (empty($this->name)) {
+ $this->name = 'category_id';
+ }
+
+ $types = $this->getTypeCategoryTypes($this->type);
+ $types_string = implode(',', $types);
+
+ $this->path = route('modals.categories.create', ['type' => $this->type]);
+ $this->remoteAction = route('categories.index', ['search' => 'type:' . $types_string . ' enabled:1']);
+
+ $typeLabels = $this->getCategoryTypes(types: $types);
+
+ $is_code = false;
+
+ foreach (config('type.category', []) as $type => $config) {
+ if (! in_array($type, $types)) {
+ continue;
+ }
+
+ if (empty($config['hide']) || ! in_array('code', $config['hide'])) {
+ $is_code = true;
+ $this->group = true;
+ break;
+ }
+ }
+
+ $order_by = $is_code ? 'code' : 'name';
+
+ if ($this->group) {
+ $this->option_field = [
+ 'key' => 'id',
+ 'value' => 'title',
+ ];
+ }
+
+ $query = Model::type($types);
+
+ $query->enabled()
+ ->orderBy($order_by);
+
+ if (! $this->group) {
+ $query->take(setting('default.select_limit'));
+ }
+
+ $this->categories = $query->get();
+
+ if ($this->group) {
+ $groups = [];
+
+ foreach ($this->categories as $category) {
+ $group = $typeLabels[$category->type] ?? trans_choice('general.others', 1);
+
+ $category->title = ($category->code ? $category->code . ' - ' : '') . $category->name;
+ $category->group = $group;
+
+ $groups[$group][$category->id] = $category;
+ }
+
+ ksort($groups);
+
+ $this->categories = $groups;
+ }
+
+ $model = $this->getParentData('model');
+ $selected_category = null;
+
+ $categoryExists = function ($categoryId): bool {
+ if (! $this->group) {
+ return $this->categories->contains(function ($category) use ($categoryId) {
+ return (int) $category->id === (int) $categoryId;
+ });
+ }
+
+ foreach ($this->categories as $group_categories) {
+ foreach ($group_categories as $category) {
+ if ((int) $category->id === (int) $categoryId) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ };
+
+ $appendCategory = function ($category) use ($typeLabels): void {
+ if (empty($category)) {
+ return;
+ }
+
+ $category->title = ($category->code ? $category->code . ' - ' : '') . $category->name;
+
+ if (! $this->group) {
+ $this->categories->push($category);
+
+ return;
+ }
+
+ $group = $typeLabels[$category->type] ?? trans_choice('general.others', 1);
+
+ if (! isset($this->categories[$group])) {
+ $this->categories[$group] = [];
+ }
+
+ $this->categories[$group][$category->id] = $category;
+
+ ksort($this->categories);
+ };
+
+ $category_id = old('category.id', old('category_id', null));
+
+ if (! empty($category_id)) {
+ $this->selected = $category_id;
+
+ if (! $categoryExists($category_id)) {
+ $category = Model::find($category_id);
+
+ $appendCategory($category);
+ }
+ }
+
+ if (! empty($model) && ! empty($model->category_id)) {
+ $this->selected = $model->category_id;
+
+ $selected_category = $model->category;
+ }
+
+ if ($this->selected === null && in_array($this->type, [Model::INCOME_TYPE, Model::EXPENSE_TYPE])) {
+ $this->selected = setting('default.' . $this->type . '_category');
+
+ $selected_category = Model::find($this->selected);
+ }
+
+ if (empty($selected_category) && ! empty($this->selected)) {
+ $selected_category = Model::find($this->selected);
+ }
+
+ if (! empty($selected_category)) {
+ $selected_category_id = $selected_category->id;
+
+ if (! $categoryExists($selected_category_id)) {
+ $appendCategory($selected_category);
+ }
+ }
+
+ return view('components.form.group.category');
+ }
+}
diff --git a/app/View/Components/Form/Group/Checkbox.php b/app/View/Components/Form/Group/Checkbox.php
new file mode 100644
index 00000000..05b62d45
--- /dev/null
+++ b/app/View/Components/Form/Group/Checkbox.php
@@ -0,0 +1,27 @@
+name)) {
+ $this->name = 'contact_id';
+ }
+
+ if (empty($this->label)) {
+ $this->label = trans_choice('general.' . Str::plural($this->type), 1);
+ }
+
+ if (empty($this->contacts) && ! empty($this->options)) {
+ $this->contacts = $this->options;
+ } else if (empty($this->contacts)) {
+ $this->contacts = Model::type($this->type)->enabled()->orderBy('name')->take(setting('default.select_limit'))->get();
+ }
+
+ $this->setRoutes();
+
+ $model = $this->getParentData('model');
+
+ $contact_id = old('contact.id', old('contact_id', null));
+
+ if (! empty($contact_id)) {
+ $this->selected = $contact_id;
+
+ if (! $this->contacts->has($contact_id)) {
+ $contact = Model::find($contact_id);
+
+ $this->contacts->push($contact);
+ }
+ }
+
+ if (! empty($model) && ! empty($model->contact_id)) {
+ $this->selected = $model->contact_id;
+
+ $selected_contact = $model->contact;
+ }
+
+ if (! empty($selected_contact) && ! $this->contacts->has($selected_contact->id)) {
+ $this->contacts->push($selected_contact);
+ }
+
+ return view($this->view);
+ }
+
+ public function setRoutes(): void
+ {
+ $alias = config('type.contact.' . $this->type . '.alias');
+ $prefix = config('type.contact.' . $this->type . '.route.prefix');
+
+ $parameters = ['search' => 'enabled:1'];
+
+ $this->path = ! empty($alias) ? route("{$alias}.modals.{$prefix}.create") : route("modals.{$prefix}.create");
+ $this->remoteAction = ! empty($alias) ? route("{$alias}.{$prefix}.index", $parameters) : route("{$prefix}.index", $parameters);
+ }
+}
diff --git a/app/View/Components/Form/Group/Country.php b/app/View/Components/Form/Group/Country.php
new file mode 100644
index 00000000..9180693f
--- /dev/null
+++ b/app/View/Components/Form/Group/Country.php
@@ -0,0 +1,28 @@
+name)) {
+ $this->name = 'country';
+ }
+
+ if ($this->selected === null && empty($this->getParentData('model'))) {
+ $this->selected = setting('company.country');
+ }
+
+ return view('components.form.group.country');
+ }
+}
diff --git a/app/View/Components/Form/Group/Currency.php b/app/View/Components/Form/Group/Currency.php
new file mode 100644
index 00000000..1e07611d
--- /dev/null
+++ b/app/View/Components/Form/Group/Currency.php
@@ -0,0 +1,60 @@
+name)) {
+ $this->name = 'currency_code';
+ }
+
+ $this->path = route('modals.currencies.create');
+
+ $this->field = [
+ 'key' => 'code',
+ 'value' => 'name'
+ ];
+
+ $this->currencies = Model::enabled()->orderBy('name')->pluck('name', 'code');
+
+ if (! empty($this->options)) {
+ $this->currencies = $this->options;
+ }
+
+ $currency_id = old('currency.id', old('currency_id', null));
+
+ if (! empty($currency_id)) {
+ $this->selected = $currency_id;
+
+ if (! $this->currencies->has($currency_id)) {
+ $currency = Model::find($currency_id);
+
+ $this->currencies->put($currency->id, $currency->name);
+ }
+ }
+
+ if ($this->selected === null && empty($this->getParentData('model'))) {
+ $this->selected = default_currency();
+ }
+
+ return view('components.form.group.currency');
+ }
+}
diff --git a/app/View/Components/Form/Group/Customer.php b/app/View/Components/Form/Group/Customer.php
new file mode 100644
index 00000000..28d7ec5b
--- /dev/null
+++ b/app/View/Components/Form/Group/Customer.php
@@ -0,0 +1,10 @@
+ 'form-file dropzone-column sm:w-1/2 h-32.5',
+ ];
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ if (! empty($this->options)) {
+ $options = [];
+
+ foreach ($this->options as $option) {
+ $options[$option->id] = $option->name;
+ }
+
+ $this->options = $options;
+ }
+
+ $this->options['maxFilesize'] = config('filesystems.max_size');
+
+ return view('components.form.group.file');
+ }
+}
diff --git a/app/View/Components/Form/Group/Import.php b/app/View/Components/Form/Group/Import.php
new file mode 100644
index 00000000..a5e7ba2b
--- /dev/null
+++ b/app/View/Components/Form/Group/Import.php
@@ -0,0 +1,38 @@
+ 'form-file dropzone-column sm:w-1/2 h-32.5',
+ ];
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ if (! empty($this->options)) {
+ $options = [];
+
+ foreach ($this->options as $option) {
+ $options[$option->id] = $option->name;
+ }
+
+ $this->options = $options;
+ }
+
+ $this->options['maxFilesize'] = config('filesystems.max_size');
+
+ return view('components.form.group.import');
+ }
+}
diff --git a/app/View/Components/Form/Group/InvoiceText.php b/app/View/Components/Form/Group/InvoiceText.php
new file mode 100644
index 00000000..4cb6c6ae
--- /dev/null
+++ b/app/View/Components/Form/Group/InvoiceText.php
@@ -0,0 +1,20 @@
+selected === null && empty($this->getParentData('model'))) {
+ $this->selected = setting('default.locale', config('app.locale', 'en-GB'));
+ }
+
+ return view('components.form.group.locale');
+ }
+}
diff --git a/app/View/Components/Form/Group/Money.php b/app/View/Components/Form/Group/Money.php
new file mode 100644
index 00000000..193ee3c9
--- /dev/null
+++ b/app/View/Components/Form/Group/Money.php
@@ -0,0 +1,20 @@
+name)) {
+ $this->name = 'number_digit';
+ }
+
+ $this->number_digits = [
+ '1' => '1',
+ '2' => '2',
+ '3' => '3',
+ '4' => '4',
+ '5' => '5',
+ '6' => '6',
+ '7' => '7',
+ '8' => '8',
+ '9' => '9',
+ '10' => '10',
+ '11' => '11',
+ '12' => '12',
+ '13' => '13',
+ '14' => '14',
+ '15' => '15',
+ '16' => '16',
+ '17' => '17',
+ '18' => '18',
+ '19' => '19',
+ '20' => '20',
+ ];
+
+ if (empty($this->selected) && empty($this->getParentData('model'))) {
+ $this->selected = setting('invoice.number_digit');
+ }
+
+ return view('components.form.group.number_digit');
+ }
+}
diff --git a/app/View/Components/Form/Group/Password.php b/app/View/Components/Form/Group/Password.php
new file mode 100644
index 00000000..78228b60
--- /dev/null
+++ b/app/View/Components/Form/Group/Password.php
@@ -0,0 +1,20 @@
+name)) {
+ $this->name = 'payment_method';
+ }
+
+ $this->payment_methods = Modules::getPaymentMethods();
+
+ if ($this->selected === null && empty($this->getParentData('model'))) {
+ $this->selected = setting('default.payment_method');
+ }
+
+ return view('components.form.group.payment_method');
+ }
+}
diff --git a/app/View/Components/Form/Group/PaymentTerm.php b/app/View/Components/Form/Group/PaymentTerm.php
new file mode 100644
index 00000000..4629a8b6
--- /dev/null
+++ b/app/View/Components/Form/Group/PaymentTerm.php
@@ -0,0 +1,42 @@
+name = 'temp_payment_term';
+
+ $payment_terms = [
+ '0' => trans('settings.invoice.due_receipt'),
+ '7' => trans('settings.invoice.due_days', ['days' => 7]),
+ '15' => trans('settings.invoice.due_days', ['days' => 15]),
+ '30' => trans('settings.invoice.due_days', ['days' => 30]),
+ '45' => trans('settings.invoice.due_days', ['days' => 45]),
+ '60' => trans('settings.invoice.due_days', ['days' => 60]),
+ '90' => trans('settings.invoice.due_days', ['days' => 90]),
+ 'custom' => trans('settings.invoice.due_custom'),
+ ];
+
+ if (empty($this->options)) {
+ $this->options = $this->getOptions($payment_terms);
+ }
+
+ if (! array_key_exists($this->selected, $payment_terms)) {
+ $this->value = $this->selected;
+ $this->selected = 'custom';
+ }
+
+ return view('components.form.group.payment_term');
+ }
+}
diff --git a/app/View/Components/Form/Group/Radio.php b/app/View/Components/Form/Group/Radio.php
new file mode 100644
index 00000000..e4d30a2a
--- /dev/null
+++ b/app/View/Components/Form/Group/Radio.php
@@ -0,0 +1,30 @@
+type = $this->getType($type);
+
+ $this->interval = $this->getInterval($interval);
+
+ $this->frequency = $this->getFrequency($frequency, $interval);
+ $this->frequencies = $this->getFrequencies($frequencies);
+
+ $this->customFrequency = $this->getCustomFrequency($frequency, $customFrequency, $interval);
+ $this->customFrequencies = $this->getCustomFrequencies($customFrequencies);
+
+ $this->limit = $this->getLimit($limit);
+ $this->limits = $this->getLimits($limits);
+
+ $this->startedValue = $this->getStartedValue($startedValue);
+ $this->limitCount = $this->getLimitCount($limitCount);
+ $this->limitDateValue = $this->getLimitDateValue($limitDateValue);
+
+ $this->sendEmailShow = $this->getSendEmailShow($sendEmailShow);
+ $this->sendEmail = $this->getSendEmail($sendEmail);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.form.group.recurring');
+ }
+
+ protected function getType($type)
+ {
+ if (! empty($type)) {
+ return $type;
+ }
+
+ return 'invoice';
+ }
+
+ protected function getFrequency($frequency, $interval = 0)
+ {
+ if ($interval > 1) {
+ return 'custom';
+ }
+
+ if (! empty($frequency)) {
+ return $frequency;
+ }
+
+ return 'monthly';
+ }
+
+ protected function getFrequencies($frequencies)
+ {
+ if (! empty($frequencies)) {
+ return $frequencies;
+ }
+
+ return [
+ 'daily' => trans('recurring.daily'),
+ 'weekly' => trans('recurring.weekly'),
+ 'monthly' => trans('recurring.monthly'),
+ 'yearly' => trans('recurring.yearly'),
+ 'custom' => trans('recurring.custom'),
+ ];
+ }
+
+ protected function getInterval($interval)
+ {
+ if (! empty($interval)) {
+ return $interval;
+ }
+
+ return '';
+ }
+
+ protected function getCustomFrequency($frequency, $customFrequency, $interval = 0)
+ {
+ if ($interval > 1) {
+ return $frequency;
+ }
+
+ if (! empty($customFrequency)) {
+ return $customFrequency;
+ }
+
+ return 'monthly';
+ }
+
+ protected function getCustomFrequencies($customFrequencies)
+ {
+ if (! empty($customFrequencies)) {
+ return $customFrequencies;
+ }
+
+ return [
+ 'daily' => trans('recurring.days'),
+ 'weekly' => trans('recurring.weeks'),
+ 'monthly' => trans('recurring.months'),
+ 'yearly' => trans('recurring.years'),
+ ];
+ }
+
+ protected function getLimit($limit)
+ {
+ if (! empty($limit)) {
+ return $limit;
+ }
+
+ return 'never';
+ }
+
+ protected function getLimits($limits)
+ {
+ if (! empty($limits)) {
+ return $limits;
+ }
+
+ return [
+ 'after' => trans('recurring.after'),
+ 'on' => trans('recurring.on'),
+ 'never' => trans('recurring.never'),
+ ];
+ }
+
+ protected function getStartedValue($startedValue)
+ {
+ if (! empty($startedValue)) {
+ return $startedValue;
+ }
+
+ return Date::now()->toDateString();
+ }
+
+ protected function getLimitCount($limitCount)
+ {
+ if (! empty($limitCount)) {
+ return $limitCount;
+ }
+
+ return 0;
+ }
+
+ protected function getLimitDateValue($limitDateValue)
+ {
+ if (! empty($limitDateValue)) {
+ return $limitDateValue;
+ }
+
+ return Date::now()->toDateString();
+ }
+
+ protected function getSendEmailShow($sendEmailShow)
+ {
+ if (! empty($sendEmailShow)) {
+ return $sendEmailShow;
+ }
+
+ return false;
+ }
+
+ protected function getSendEmail($sendEmail)
+ {
+ if (! empty($sendEmail)) {
+ return $sendEmail;
+ }
+
+ return false;
+ }
+}
diff --git a/app/View/Components/Form/Group/Select.php b/app/View/Components/Form/Group/Select.php
new file mode 100644
index 00000000..797b6062
--- /dev/null
+++ b/app/View/Components/Form/Group/Select.php
@@ -0,0 +1,20 @@
+name)) {
+ $this->name = 'tax_id';
+ }
+
+ $this->path = route('modals.taxes.create');
+ $this->remoteAction = route('taxes.index', ['search' => 'enabled:1']);
+
+ $this->field = [
+ 'key' => 'id',
+ 'value' => 'title'
+ ];
+
+ $this->taxes = Model::enabled()->orderBy('name')->get();
+
+ $model = $this->getParentData('model');
+
+ $tax_id = old('tax_ids', old('tax.id', old('tax_id', null)));
+
+ if (! empty($tax_id)) {
+ $this->selected = ($this->multiple) ? (array) $tax_id : $tax_id;
+
+ foreach ($tax_id as $id) {
+ if (! $this->taxes->has($id)) {
+ $tax = Model::find($id);
+
+ $this->taxes->put($tax->id, $tax->title);
+ }
+ }
+ }
+
+ if (! empty($model) && ! empty($model->{$this->name})) {
+ $this->selected = $model->{$this->name};
+ }
+
+ if ($this->selected === null && $this->multiple) {
+ $this->selected = (setting('default.tax')) ? [setting('default.tax')] : null;
+ } else if ($this->selected === null) {
+ $this->selected = setting('default.tax', null);
+ }
+
+ return view('components.form.group.tax');
+ }
+}
diff --git a/app/View/Components/Form/Group/Text.php b/app/View/Components/Form/Group/Text.php
new file mode 100644
index 00000000..cffc6d4b
--- /dev/null
+++ b/app/View/Components/Form/Group/Text.php
@@ -0,0 +1,20 @@
+options)) {
+ $options = [];
+
+ foreach ($this->options as $option) {
+ $options[$option->id] = $option->name;
+ }
+
+ $this->options = $options;
+ }
+
+ return view('components.form.input.file');
+ }
+}
diff --git a/app/View/Components/Form/Input/Hidden.php b/app/View/Components/Form/Input/Hidden.php
new file mode 100644
index 00000000..a59b345f
--- /dev/null
+++ b/app/View/Components/Form/Input/Hidden.php
@@ -0,0 +1,20 @@
+options)) {
+ $options = [];
+
+ foreach ($this->options as $option) {
+ $options[$option->id] = $option->name;
+ }
+
+ $this->options = $options;
+ }
+
+ return view('components.form.input.import');
+ }
+}
diff --git a/app/View/Components/Form/Input/Input.php b/app/View/Components/Form/Input/Input.php
new file mode 100644
index 00000000..803e6187
--- /dev/null
+++ b/app/View/Components/Form/Input/Input.php
@@ -0,0 +1,20 @@
+spacingVertical = $spacingVertical;
+ $this->spacingHorizontal = $spacingHorizontal;
+ $this->columnNumber = $columnNumber;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.form.section.index');
+ }
+}
diff --git a/app/View/Components/Icon.php b/app/View/Components/Icon.php
new file mode 100644
index 00000000..10d31f15
--- /dev/null
+++ b/app/View/Components/Icon.php
@@ -0,0 +1,86 @@
+icon = $icon;
+ $this->class = ($simpleIcons) ? 'w-8 h-8 ' . $class : $class;
+ $this->filled = $filled;
+ $this->rounded = $rounded;
+ $this->sharp = $sharp;
+ $this->simpleIcons = $simpleIcons;
+ $this->custom = $custom;
+ $this->alias = $alias;
+
+ if ($custom) {
+ $this->icon = $this->getCustomIcon($icon, $alias);
+ }
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.icon');
+ }
+
+ protected function getCustomIcon($icon, $alias)
+ {
+ $slug = Str::replace('custom-', '', $icon);
+
+ $base_path = 'public/img/icons/';
+
+ if (! empty($alias)) {
+ $base_path = 'modules/' . Str::studly($alias) . '/Resources/assets/img/icons/';
+ }
+
+ $path = base_path($base_path . $slug . '.svg');
+
+ if (! file_exists($path)) {
+ $path = 'public/img/akaunting-logo-purple.svg';
+ }
+
+ return $path;
+ }
+}
diff --git a/app/View/Components/Index/Balance.php b/app/View/Components/Index/Balance.php
new file mode 100644
index 00000000..28c513e2
--- /dev/null
+++ b/app/View/Components/Index/Balance.php
@@ -0,0 +1,71 @@
+amount = $this->getAmount($amount);
+ $this->textColor = $this->getTextColor($amount);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.index.balance');
+ }
+
+ /**
+ * Formats the amount according to the location context.
+ *
+ * @param float $amount
+ * @return string
+ */
+ protected function getAmount($amount)
+ {
+ return money($amount, setting('default.currency'), true);
+ }
+
+ /**
+ * Gets the class of color considering given amount.
+ *
+ * @param float $amount
+ * @return string|null
+ */
+ protected function getTextColor($amount)
+ {
+ switch ($amount) {
+ case $amount > 0:
+ return 'text-green';
+ case $amount < 0:
+ return 'text-red';
+ default:
+ return '';
+ }
+ }
+}
diff --git a/app/View/Components/Index/Bulkaction.php b/app/View/Components/Index/Bulkaction.php
new file mode 100644
index 00000000..677f7a54
--- /dev/null
+++ b/app/View/Components/Index/Bulkaction.php
@@ -0,0 +1,108 @@
+class = $class;
+ $this->text = $text;
+ $this->path = $path;
+ $this->actions = $this->getActions($actions);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.index.bulkaction.index');
+ }
+
+ protected function getActions($actions)
+ {
+ if (! empty($actions)) {
+ return $actions;
+ }
+
+ if (class_exists($this->class)) {
+ $bulk_action = app($this->class);
+
+ event(new BulkActionsAdding($bulk_action));
+
+ $this->text = $bulk_action->text;
+
+ if (is_array($bulk_action->path)) {
+ $this->path = route('bulk-actions.action', $bulk_action->path);
+ } else {
+ $this->path = url('common/bulk-actions/' . $bulk_action->path);
+ }
+ } else {
+ $bulk_action = new \stdClass();
+ $bulk_action->text = '';
+ $bulk_action->path = '';
+ $bulk_action->actions = [];
+ $bulk_action->icons = [];
+
+ event(new BulkActionsAdding($bulk_action));
+
+ if (is_array($bulk_action->path)) {
+ $this->path = route('bulk-actions.action', $bulk_action->path);
+ } else {
+ $this->path = url('common/bulk-actions/' . $bulk_action->path);
+ }
+ }
+
+ $query = [];
+
+ if (request()->has('page')) {
+ $query['page'] = request()->get('page');
+ }
+
+ if (request()->has('limit')) {
+ $query['limit'] = request()->get('limit');
+ }
+
+ if ($query) {
+ $this->path .= '?' . http_build_query($query);
+ }
+
+ $actions = [];
+
+ if ($bulk_action->actions) {
+ foreach ($bulk_action->actions as $key => $action) {
+ if ((isset($action['permission']) && ! user()->can($action['permission']))) {
+ continue;
+ }
+
+ if (empty($action['icon']) && array_key_exists($key, $bulk_action->icons)) {
+ $action['icon'] = $bulk_action->icons[$key];
+ }
+
+ $actions[$key] = $action;
+ }
+ }
+
+ return $actions;
+ }
+}
diff --git a/app/View/Components/Index/Category.php b/app/View/Components/Index/Category.php
new file mode 100644
index 00000000..595a8b02
--- /dev/null
+++ b/app/View/Components/Index/Category.php
@@ -0,0 +1,120 @@
+model = $model;
+
+ $this->name = $this->getName($name, $model);
+ $this->backgroundColor = $this->getBackgroundColor($backgroundColor, $model);
+ $this->textColor = $this->getTextColor($textColor, $this->backgroundColor);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.index.category');
+ }
+
+ protected function getName($name, $model)
+ {
+ if (! empty($name)) {
+ return $name;
+ }
+
+ if (! empty($model)) {
+ $name = $model->name;
+ }
+
+ return $name;
+ }
+
+ protected function getBackgroundColor($backgroundColor, $model)
+ {
+ if (! empty($backgroundColor)) {
+ return $backgroundColor;
+ }
+
+ if (! empty($model)) {
+ if (Str::contains($model->color, ['#'])) {
+ $this->backgroundStyle = $model->color;
+
+ return $backgroundColor;
+ }
+
+ $backgroundColor = 'bg-' . $model->color;
+ }
+
+ return $backgroundColor;
+ }
+
+ protected function getTextColor($textColor, $backgroundColor)
+ {
+ if (! empty($textColor)) {
+ return $textColor;
+ }
+
+ if (! empty($backgroundColor)) {
+ $x = explode('-', $backgroundColor);
+
+ $textColor = 'text-black';
+
+ if ($x[1] >= 500) {
+ $textColor = 'text-white';
+ }
+ }
+
+ return $textColor;
+ }
+}
diff --git a/app/View/Components/Index/Country.php b/app/View/Components/Index/Country.php
new file mode 100644
index 00000000..14af1023
--- /dev/null
+++ b/app/View/Components/Index/Country.php
@@ -0,0 +1,46 @@
+code = $code;
+ $this->country = trans('general.na');
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ if (! empty($this->code) && array_key_exists($this->code, trans('countries'))) {
+ $this->country = trans('countries.' . $this->code);
+ }
+
+ return view('components.index.country');
+ }
+}
diff --git a/app/View/Components/Index/Currency.php b/app/View/Components/Index/Currency.php
new file mode 100644
index 00000000..a9ef781d
--- /dev/null
+++ b/app/View/Components/Index/Currency.php
@@ -0,0 +1,45 @@
+code = $code;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ $code = ($this->code) ? $this->code : default_currency();
+
+ $this->currency = currency($code)->getName();
+
+ return view('components.index.currency');
+ }
+}
diff --git a/app/View/Components/Index/Ddefault.php b/app/View/Components/Index/Ddefault.php
new file mode 100644
index 00000000..ce1c8bae
--- /dev/null
+++ b/app/View/Components/Index/Ddefault.php
@@ -0,0 +1,63 @@
+id = 'tooltip-default-' . mt_rand(1, time());
+ $this->position = $position;
+ $this->icon = $icon;
+ $this->iconType = $iconType;
+ $this->text = $text;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.index.default');
+ }
+}
diff --git a/app/View/Components/Index/Disable.php b/app/View/Components/Index/Disable.php
new file mode 100644
index 00000000..16a53c45
--- /dev/null
+++ b/app/View/Components/Index/Disable.php
@@ -0,0 +1,80 @@
+id = 'tooltip-disable-' . mt_rand(1, time());
+ $this->position = $position;
+ $this->icon = $icon;
+ $this->iconType = $iconType;
+ $this->disableText = $this->getDisableText($text, $disableText);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.index.disable');
+ }
+
+ protected function getDisableText($text, $disableText)
+ {
+ if (! empty($disableText)) {
+ return $disableText;
+ }
+
+ return trans('general.disabled_type', ['type' => Str::lower($text)]);
+ }
+}
diff --git a/app/View/Components/Index/Search.php b/app/View/Components/Index/Search.php
new file mode 100644
index 00000000..5ba715c9
--- /dev/null
+++ b/app/View/Components/Index/Search.php
@@ -0,0 +1,121 @@
+searchString = $searchString;
+ $this->bulkAction = $bulkAction;
+ $this->action = $this->getAction($action, $route, $url);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.index.search');
+ }
+
+ protected function getAction($action, $route, $url)
+ {
+ if (! empty($action)) {
+ return $action;
+ }
+
+ if (! empty($route)) {
+ return $this->getRouteAction($route);
+ }
+
+ if (! empty($url)) {
+ return $this->getUrlAction($url);
+ }
+
+ return '';
+ }
+
+ /**
+ * Get the action for a "url" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getUrlAction($options)
+ {
+ if (is_array($options)) {
+ return url($options[0], array_slice($options, 1));
+ }
+
+ return url($options);
+ }
+
+ /**
+ * Get the action for a "route" option.
+ *
+ * @param array|string $options
+ *
+ * @return string
+ */
+ protected function getRouteAction($options)
+ {
+ if (is_array($options)) {
+ $parameters = array_slice($options, 1);
+
+ if (array_keys($options) === [0, 1]) {
+ $parameters = head($parameters);
+ }
+
+ return route($options[0], $parameters);
+ }
+
+ return route($options);
+ }
+}
diff --git a/app/View/Components/Index/Status.php b/app/View/Components/Index/Status.php
new file mode 100644
index 00000000..ca48bce0
--- /dev/null
+++ b/app/View/Components/Index/Status.php
@@ -0,0 +1,56 @@
+backgroundColor = ! empty($backgroundColor) ? $backgroundColor : 'bg-lilac-900';
+ $this->textColor = ! empty($textColor) ? $textColor : 'text-purple';
+ $this->status = $status;
+ $this->textStatus = $this->getTextStatus($textStatus);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.index.status');
+ }
+
+ protected function getTextStatus($textStatus)
+ {
+ if (! empty($textStatus)) {
+ return $textStatus;
+ }
+
+ $textStatus = trans('documents.statuses.' . $this->status);
+
+ return $textStatus;
+ }
+}
diff --git a/app/View/Components/Index/Summary.php b/app/View/Components/Index/Summary.php
new file mode 100644
index 00000000..fb207452
--- /dev/null
+++ b/app/View/Components/Index/Summary.php
@@ -0,0 +1,31 @@
+items = $items;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.index.summary');
+ }
+}
diff --git a/app/View/Components/Layouts/Admin.php b/app/View/Components/Layouts/Admin.php
new file mode 100644
index 00000000..f7de6430
--- /dev/null
+++ b/app/View/Components/Layouts/Admin.php
@@ -0,0 +1,18 @@
+companies = $this->getCompanies();
+
+ $this->notification_count = $this->getNotificationCount();
+
+ return view('components.layouts.admin.menu');
+ }
+
+ public function getCompanies()
+ {
+ $companies = [];
+
+ if ($user = user()) {
+ $companies = $user->companies()->enabled()->limit(10)->get()->sortBy('name');
+ }
+
+ return $companies;
+ }
+
+ public function getNotificationCount()
+ {
+ // Get nofitications
+ $notifications = new \stdClass();
+ $notifications->notifications = collect();
+ $notifications->keyword = '';
+
+ event(new NotificationsCreated($notifications));
+
+ return $notifications->notifications->count();
+ }
+}
diff --git a/app/View/Components/Layouts/Admin/Notifications.php b/app/View/Components/Layouts/Admin/Notifications.php
new file mode 100644
index 00000000..f525034a
--- /dev/null
+++ b/app/View/Components/Layouts/Admin/Notifications.php
@@ -0,0 +1,57 @@
+notifications = $this->getNotify();
+
+ return view('components.layouts.admin.notifications');
+ }
+
+ public function getNotify()
+ {
+ if (! $path = Route::current()->uri()) {
+ return [];
+ }
+
+ $path = str_replace('{company_id}/', '', $path);
+ $path = str_replace('{company_id}', '', $path);
+
+ $notify = [];
+ $notifications = $this->getNotifications($path);
+
+ // Push to a stack
+ foreach ($notifications as $notification) {
+ $path = str_replace('/', '#', $notification->path);
+
+ $message = str_replace('#path#', $path, $notification->message);
+ $message = str_replace('#token#', csrf_token(), $message);
+ $message = str_replace('#url#', route('dashboard'), $message);
+ $message = str_replace('#company_id#', company_id(), $message);
+
+ if (! setting('notifications.' . $notification->path . '.' . $notification->id . '.status', 1)) {
+ continue;
+ }
+
+ $notify[] = $message;
+ }
+
+ return $notify;
+ }
+}
diff --git a/app/View/Components/Layouts/Modules.php b/app/View/Components/Layouts/Modules.php
new file mode 100644
index 00000000..631bc989
--- /dev/null
+++ b/app/View/Components/Layouts/Modules.php
@@ -0,0 +1,23 @@
+keyword = request()->get('keyword');
+ $this->categories = $this->getCategories();
+ $this->popular = $this->getPopularModules();
+
+ return view('components.layouts.modules.bar');
+ }
+
+ protected function getCategories()
+ {
+ $categories = collect([
+ '*' => trans('general.all_type', ['type' => trans_choice('general.categories', 2)]),
+ ]);
+
+ if (setting('apps.api_key')) {
+ $categories = Cache::remember('modules.categories.' . language()->getShortCode(), Date::now()->addHour(6), function () {
+ return collect($this->getCategoriesOfModules())->pluck('name', 'slug')
+ ->prepend(trans('general.all_type', ['type' => trans_choice('general.categories', 2)]), '*');
+ });
+ }
+
+ return $categories;
+ }
+}
diff --git a/app/View/Components/Layouts/Modules/Releases.php b/app/View/Components/Layouts/Modules/Releases.php
new file mode 100644
index 00000000..bf58e7fa
--- /dev/null
+++ b/app/View/Components/Layouts/Modules/Releases.php
@@ -0,0 +1,26 @@
+releases = $releases;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.layouts.modules.releases');
+ }
+}
diff --git a/app/View/Components/Layouts/Modules/Reviews.php b/app/View/Components/Layouts/Modules/Reviews.php
new file mode 100644
index 00000000..476bfd65
--- /dev/null
+++ b/app/View/Components/Layouts/Modules/Reviews.php
@@ -0,0 +1,26 @@
+reviews = $reviews;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.layouts.modules.reviews');
+ }
+}
diff --git a/app/View/Components/Layouts/Portal/Menu.php b/app/View/Components/Layouts/Portal/Menu.php
new file mode 100644
index 00000000..2d26e429
--- /dev/null
+++ b/app/View/Components/Layouts/Portal/Menu.php
@@ -0,0 +1,34 @@
+companies = $this->getCompanies();
+
+ return view('components.layouts.portal.menu');
+ }
+
+ public function getCompanies()
+ {
+ if ($user = user()) {
+ $companies = $user->companies()->enabled()->limit(10)->get()->sortBy('name');
+ } else {
+ $companies = [];
+ }
+
+ return $companies;
+ }
+}
diff --git a/app/View/Components/Layouts/Wizard.php b/app/View/Components/Layouts/Wizard.php
new file mode 100644
index 00000000..cf039ac0
--- /dev/null
+++ b/app/View/Components/Layouts/Wizard.php
@@ -0,0 +1,18 @@
+company = $this->getCompany();
+
+ $this->translations = $this->getTransalations();
+
+ $this->currencies = $this->getCurrencies();
+
+ // Prepare codes
+ $this->currency_codes = $this->getCurrencyCodes();
+
+ $this->modules = $this->getFeaturedModules([
+ 'query' => [
+ 'limit' => 5
+ ]
+ ]);
+
+ return view('components.layouts.wizard.scripts');
+ }
+
+ protected function getCompany()
+ {
+ $company = company();
+
+ $company->api_key = setting('apps.api_key');
+ $company->financial_start = setting('localisation.financial_start');
+
+ $logo_id = setting('company.logo');
+
+ $logo = false;
+
+ if ($logo_id) {
+ $logo = Media::find($logo_id);
+
+ if ($logo) {
+ $logo->path = route('uploads.get', $logo->id);
+ }
+ }
+
+ $company->logo = $logo;
+
+ return $company;
+ }
+
+ /* Wizard page transactions */
+ protected function getTransalations()
+ {
+ return [
+ 'company' => [
+ 'title' => trans_choice('general.companies', 1),
+ 'api_key' => trans('modules.api_key'),
+ 'form_enter' => trans('general.form.enter'),
+ 'get_api_key' => trans('modules.get_api_key'),
+ 'tax_number' => trans('general.tax_number'),
+ 'financial_start' => trans('settings.localisation.financial_start'),
+ 'address' => trans('settings.company.address'),
+ 'logo' => trans('settings.company.logo'),
+ 'skip' => trans('companies.skip_step'),
+ 'save' => trans('general.save'),
+ 'country' => trans_choice('general.countries', 1),
+ ],
+
+ 'currencies' => [
+ 'title' => trans_choice('general.currencies', 2),
+ 'add_new' => trans('general.add_new'),
+ 'no_currency' => trans('currencies.no_currency'),
+ 'new_currency' => trans('currencies.new_currency'),
+ 'create_currency' => trans('currencies.create_currency'),
+ 'name' => trans('general.name'),
+ 'code' => trans('currencies.code'),
+ 'rate' => trans('currencies.rate'),
+ 'default' => trans('currencies.default'),
+ 'enabled' => trans('general.enabled'),
+ 'actions' => trans('general.actions') ,
+ 'yes' => trans('general.yes'),
+ 'no' => trans('general.no'),
+ 'edit' => trans('general.edit'),
+ 'delete' => trans('general.delete'),
+ 'save' => trans('general.save'),
+ 'precision' => trans('currencies.precision'),
+ 'symbol' => trans('currencies.symbol.symbol'),
+ 'position' => trans('currencies.symbol.position'),
+ 'decimal_mark' => trans('currencies.decimal_mark'),
+ 'thousands_separator' => trans('currencies.thousands_separator'),
+ 'previous' => trans('pagination.previous'),
+ 'next' => trans('pagination.next'),
+ 'delete_confirm' => trans('general.delete_confirm'),
+ 'cancel' => trans('general.cancel'),
+ ],
+
+ 'finish' => [
+ 'title' => trans('modules.ready'),
+ 'recommended_apps' => trans('modules.recommended_apps'),
+ 'no_apps' => trans('modules.no_apps'),
+ 'developer' => trans('modules.developer'),
+ 'from' => trans('general.from'),
+ 'apps_managing' => trans('modules.apps_managing'),
+ 'reviews' => trans('modules.tab.reviews'),
+ 'previous' => trans('companies.skip_step'),
+ 'go_to_dashboard' => trans('general.go_to_dashboard'),
+ 'create_first_invoice' => trans('general.create_first_invoice'),
+ 'error_message' => trans('errors.title.500'),
+ ]
+ ];
+ }
+
+ protected function getCurrencies()
+ {
+ $currencies = collect();
+
+ Currency::all()->each(function ($currency) use (&$currencies) {
+ $currency->default = default_currency() == $currency->code;
+
+ $currencies->push($currency);
+ });
+
+ return $currencies;
+ }
+
+ protected function getCurrencyCodes()
+ {
+ $codes = [];
+ $money_currencies = MoneyCurrency::getCurrencies();
+
+ foreach ($money_currencies as $key => $item) {
+ $codes[$key] = $key;
+ }
+
+ return $codes;
+ }
+}
diff --git a/app/View/Components/Link.php b/app/View/Components/Link.php
new file mode 100644
index 00000000..d89551ad
--- /dev/null
+++ b/app/View/Components/Link.php
@@ -0,0 +1,66 @@
+override = $this->getOverride($override);
+
+ $this->kind = $kind;
+ $this->class = $this->getClass($class);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.link.index');
+ }
+
+ protected function getOverride($override)
+ {
+ return explode(',', $override);
+ }
+
+ protected function getClass($class)
+ {
+ $default = 'px-3 py-1.5 mb-3 sm:mb-0 rounded-xl text-sm font-medium leading-6';
+
+ switch ($this->kind) {
+ case 'primary':
+ $default .= ' bg-green hover:bg-green-700 text-white disabled:bg-green-100';
+ break;
+ case 'secondary':
+ $default .= ' bg-purple hover:bg-purple-700 text-white disabled:bg-purple-100';
+ break;
+ default:
+ $default .= ' bg-gray-100 hover:bg-gray-200 disabled:bg-gray-50';
+ }
+
+ if (in_array('class', $this->override)) {
+ return $class;
+ }
+
+ return $default;
+ }
+}
diff --git a/app/View/Components/Link/Hover.php b/app/View/Components/Link/Hover.php
new file mode 100644
index 00000000..66159994
--- /dev/null
+++ b/app/View/Components/Link/Hover.php
@@ -0,0 +1,36 @@
+color = $color;
+ $this->groupHover = $groupHover;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.link.hover');
+ }
+}
diff --git a/app/View/Components/Media/Ffile.php b/app/View/Components/Media/Ffile.php
new file mode 100644
index 00000000..5b5f9079
--- /dev/null
+++ b/app/View/Components/Media/Ffile.php
@@ -0,0 +1,36 @@
+file = $file;
+ $this->column_name = ! empty($column_name) ? $column_name : 'attachment';
+ $this->options = ! empty($options) ? $options : false;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.media.file');
+ }
+}
diff --git a/app/View/Components/Menu/Favorite.php b/app/View/Components/Menu/Favorite.php
new file mode 100644
index 00000000..3d2cb44f
--- /dev/null
+++ b/app/View/Components/Menu/Favorite.php
@@ -0,0 +1,41 @@
+title = $title;
+ $this->icon = $icon;
+ $this->route = $route;
+ $this->url = $url;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.menu.favorite');
+ }
+}
diff --git a/app/View/Components/Modules/Banners.php b/app/View/Components/Modules/Banners.php
new file mode 100644
index 00000000..7c84b346
--- /dev/null
+++ b/app/View/Components/Modules/Banners.php
@@ -0,0 +1,12 @@
+module = $model;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.modules.item');
+ }
+}
diff --git a/app/View/Components/Modules/Items.php b/app/View/Components/Modules/Items.php
new file mode 100644
index 00000000..6f7262e9
--- /dev/null
+++ b/app/View/Components/Modules/Items.php
@@ -0,0 +1,257 @@
+limit = $limit;
+ $this->seeMore = $this->getSeeMore($seeMore, $model);
+ $this->modules = $this->getModel($model);
+ $this->installedStatus = $this->getInstalledStatus();
+
+ $this->view = $this->getView();
+ $this->type = $this->getType();
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view($this->view);
+ }
+
+ protected function getSeeMore($seeMore, $model)
+ {
+ if (empty($seeMore)) {
+ return $seeMore;
+ }
+
+ if (! empty($model) && ($model->current_page < $model->last_page)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function getModel($model)
+ {
+ if (! empty($model)) {
+ if (isset($model->data)) {
+ return $model->data;
+ }
+
+ return $model;
+ }
+
+ $model = [];
+
+ switch ($this->type) {
+ case 'banners':
+ $model = $this->getBanners();
+ break;
+ case 'new':
+ $model = $this->getNew($this->limit);
+ break;
+ case 'paid':
+ $model = $this->getPaid($this->limit);
+ break;
+ case 'free':
+ $model = $this->getFree($this->limit);
+ break;
+ case 'pre_sale':
+ $model = $this->getPreSale($this->limit);
+ break;
+ case 'purchased':
+ $model = $this->getPurchased($this->limit);
+ break;
+ case 'installed':
+ $model = $this->getInstalled();
+ break;
+ case 'no-apps':
+ $model = $this->getTestimonials();
+ break;
+ }
+
+ return $model;
+ }
+
+ protected function getView()
+ {
+ if (! empty($this->view)) {
+ return $this->view;
+ }
+
+ return 'components.modules.items';
+ }
+
+ protected function getBanners()
+ {
+ $model = $this->getBannersOfModules();
+
+ return $model;
+ }
+
+ protected function getNew($limit)
+ {
+ $model = [];
+
+ $response = $this->getNewModules([
+ 'query' => [
+ 'limit' => $limit
+ ]
+ ]);
+
+ if ($response) {
+ $model = $response->data;
+ }
+
+ return $model;
+ }
+
+ protected function getFree($limit)
+ {
+ $model = [];
+
+ $response = $this->getFreeModules([
+ 'query' => [
+ 'limit' => $limit
+ ]
+ ]);
+
+ if ($response) {
+ $model = $response->data;
+ }
+
+ return $model;
+ }
+
+ protected function getPaid($limit)
+ {
+ $model = [];
+
+ $response = $this->getPaidModules([
+ 'query' => [
+ 'limit' => $limit
+ ]
+ ]);
+
+ if ($response) {
+ $model = $response->data;
+ }
+
+ return $model;
+ }
+
+ protected function getPreSale($limit)
+ {
+ $model = [];
+
+ $response = $this->getPreSaleModules([
+ 'query' => [
+ 'limit' => $limit
+ ]
+ ]);
+
+ if ($response) {
+ $model = $response->data;
+ }
+
+ return $model;
+ }
+
+ protected function getPurchased($limit)
+ {
+ $model = [];
+ $data = [];
+
+ if ($limit != 4) {
+ $data = [
+ 'query' => [
+ 'limit' => $limit
+ ]
+ ];
+ }
+
+ $response = $this->getMyModules($data);
+
+ if ($response) {
+ $model = $response;
+ }
+
+ return $model;
+ }
+
+ protected function getInstalled()
+ {
+ $model = [];
+
+ $response = $this->getInstalledModules();
+
+ if ($response) {
+ $model = $response;
+ }
+
+ return $model;
+ }
+
+ protected function getTestimonials()
+ {
+ $model = [];
+
+ $response = $this->getTestimonialModules();
+
+ if ($response) {
+ $model = $response;
+ }
+
+ return $model;
+ }
+
+ protected function getInstalledStatus()
+ {
+ $installed = Module::where('company_id', '=', company_id())->pluck('enabled', 'alias')->toArray();
+
+ return $installed;
+ }
+
+ protected function getType()
+ {
+ if (! empty($this->type)) {
+ return $this->type;
+ }
+
+ $name = Route::currentRouteName();
+
+ $keys = explode('.', $name);
+
+ return count($keys) > 2 ? $keys[1] : last($keys);
+ }
+}
diff --git a/app/View/Components/Modules/Nnew.php b/app/View/Components/Modules/Nnew.php
new file mode 100644
index 00000000..7f54a63e
--- /dev/null
+++ b/app/View/Components/Modules/Nnew.php
@@ -0,0 +1,12 @@
+items = $items;
+ $this->limits = $this->getLimits($limits);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.pagination');
+ }
+
+ protected function getLimits($limits)
+ {
+ if (! empty($limits)) {
+ return $limits;
+ }
+
+ $limits = [
+ '10' => '10',
+ '25' => '25',
+ '50' => '50',
+ '100' => '100'
+ ];
+
+ return $limits;
+ }
+}
diff --git a/app/View/Components/PaymentMethod.php b/app/View/Components/PaymentMethod.php
new file mode 100644
index 00000000..c5f625b2
--- /dev/null
+++ b/app/View/Components/PaymentMethod.php
@@ -0,0 +1,81 @@
+code = $code;
+ $this->method = $method;
+ $this->type = $type;
+
+ $this->payment_methods = $this->getPaymentMethods($payment_methods, $type);
+ $this->payment_method = $this->getPaymentMethod($payment_method, $code);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.payment_method');
+ }
+
+ protected function getPaymentMethods($payment_methods, $type)
+ {
+ if (! empty($payment_methods)) {
+ return $payment_methods;
+ }
+
+ // check here protal or admin panel..
+ if (empty($type)) {
+ $type = Str::contains(request()?->route()?->getName(), 'portal') ? 'customer' : 'all';
+ }
+
+ $payment_methods = Modules::getPaymentMethods($type);
+
+ return $payment_methods;
+ }
+
+ protected function getPaymentMethod($payment_method, $code)
+ {
+ if (! empty($payment_methods)) {
+ return $payment_methods;
+ }
+
+ if (! empty($this->payment_methods[$code])) {
+ return $this->payment_methods[$code];
+ }
+
+ if (! empty($this->payment_methods[$this->method])) {
+ return $this->payment_methods[$this->method];
+ }
+
+ if (! empty($this->payment_methods[$payment_method])) {
+ return $this->payment_methods[$payment_method];
+ }
+
+ return false;
+ }
+}
diff --git a/app/View/Components/Script.php b/app/View/Components/Script.php
new file mode 100644
index 00000000..1268585a
--- /dev/null
+++ b/app/View/Components/Script.php
@@ -0,0 +1,72 @@
+alias = $alias;
+ $this->folder = $folder;
+ $this->file = $file;
+
+ $this->source = $this->getSource($alias, $folder, $file);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.script');
+ }
+
+ protected function getSource($alias, $folder, $file)
+ {
+ $path = 'public/js/';
+ $version = version('short');
+
+ if ($alias != 'core') {
+ try {
+ $module = module($alias);
+
+ if ($module) {
+ $path = 'modules/' . $module->getStudlyName() . '/Resources/assets/js/';
+ $version = module_version($alias);
+ }
+ } catch (\Exception $e) {
+
+ }
+ }
+
+ if (! empty($folder)) {
+ $path .= $folder . '/';
+ }
+
+ $path .= $file . '.min.js?v=' . $version;
+
+ return $path;
+ }
+}
diff --git a/app/View/Components/Script/Declaration.php b/app/View/Components/Script/Declaration.php
new file mode 100644
index 00000000..768aca18
--- /dev/null
+++ b/app/View/Components/Script/Declaration.php
@@ -0,0 +1,65 @@
+kind = $kind;
+ $this->value = $value;
+
+ $this->scripts = $this->getScripts();
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.script.declaration');
+ }
+
+ protected function getScripts()
+ {
+ $scripts = '';
+
+ foreach ($this->value as $key => $value) {
+ $scripts .= $this->getScript($key, $value) . "\n";
+ }
+
+ return $scripts;
+ }
+
+ protected function getScript($key, $value = null)
+ {
+ $script = $this->kind . ' ' . $key;
+
+ if (! is_null($value)) {
+ $script .= ' = ' . Js::from($value)->toHtml() . ';';
+ } else {
+ $script .= ' = ' . 'null;';
+ }
+
+ return $script;
+ }
+}
diff --git a/app/View/Components/Script/Exceptions/Trackers.php b/app/View/Components/Script/Exceptions/Trackers.php
new file mode 100644
index 00000000..0b4de28f
--- /dev/null
+++ b/app/View/Components/Script/Exceptions/Trackers.php
@@ -0,0 +1,144 @@
+channel = $this->getChannel($channel);
+ $this->action = $this->getAction($action);
+ $this->ip = $this->getIp($ip);
+ $this->tags = $this->getTags($tags);
+ $this->params = $this->getParams($params);
+ }
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.script.exceptions.trackers');
+ }
+
+ public function getChannel($channel)
+ {
+ if (! empty($channel)) {
+ return $channel;
+ }
+
+ return config('logging.default');
+ }
+
+ public function getAction($action)
+ {
+ if (! empty($action)) {
+ return $action;
+ }
+
+ switch ($this->channel) {
+ case 'bugsnag':
+ $action = config('bugsnag.api_key');
+ break;
+ case 'sentry':
+ $action = config('sentry.dsn');
+ break;
+ }
+
+ return $action;
+ }
+
+ public function getIp($ip)
+ {
+ if (! empty($ip)) {
+ return $ip;
+ }
+
+ return Info::ip();
+ }
+
+ public function getTags($tags)
+ {
+ if (! empty($tags)) {
+ return $tags;
+ }
+
+ return static::getTrackerTags();
+ }
+
+ public function getParams($params)
+ {
+ if (! empty($params)) {
+ return $params;
+ }
+
+ switch ($this->channel) {
+ case 'bugsnag':
+ $params = [
+ 'app_version' => version('short'),
+ ];
+ break;
+ case 'sentry':
+ $params = [
+ 'release' => version('short'),
+ 'traces_sample_rate' => static::sentryTracesSampleRate(),
+ 'replays_session_sample_rate' => static::sentryReplaysSessionSampleRate(),
+ 'replays_on_error_sample_rate' => static::sentryReplaysOnErrorSampleRate(),
+ ];
+ break;
+ }
+
+ return $params;
+ }
+
+ public static function sentryTracesSampleRate()
+ {
+ $user_agent = request()->userAgent();
+
+ $filter_agents = explode(',', env('SENTRY_TRACES_FILTER_AGENTS'));
+
+ foreach ($filter_agents as $filter_agent) {
+ if (! Str::contains($user_agent, $filter_agent)) {
+ continue;
+ }
+
+ return 0.0;
+ }
+
+ return (float) config('sentry.traces_sample_rate', 1.0);
+ }
+
+ public static function sentryReplaysSessionSampleRate()
+ {
+ return (float) config('sentry.replays_session_sample_rate', 0.1);
+ }
+
+ public static function sentryReplaysOnErrorSampleRate()
+ {
+ return (float) config('sentry.replays_on_error_sample_rate', 1.0);
+ }
+}
diff --git a/app/View/Components/SearchString.php b/app/View/Components/SearchString.php
new file mode 100644
index 00000000..5ed5ef68
--- /dev/null
+++ b/app/View/Components/SearchString.php
@@ -0,0 +1,292 @@
+model = $model;
+ $this->filters = $filters;
+ $this->filtered = $filtered;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ if (empty($this->filters)) {
+ $search_string = config('search-string');
+
+ $this->filters = [];
+
+ if (!empty($search_string[$this->model])) {
+ $columns = $search_string[$this->model]['columns'];
+
+ foreach ($columns as $column => $options) {
+ // This column skip for filter
+ if (! empty($options['searchable'])) {
+ continue;
+ }
+
+ // This column skip for filter
+ if (in_array($column, $this->skip_columns)) {
+ continue;
+ }
+
+ if (!is_array($options)) {
+ $column = $options;
+ }
+
+ if (!$this->isFilter($column, $options)) {
+ continue;
+ }
+
+ $this->filters[] = [
+ 'key' => $this->getFilterKey($column, $options),
+ 'value' => $this->getFilterName($column, $options),
+ 'type' => $this->getFilterType($options),
+ 'url' => $this->getFilterUrl($column, $options),
+ 'values' => $this->getFilterValues($column, $options),
+ 'value_option_fields' => $options['fields'] ?? [],
+ //'operators' => $options['operators'] ?? $this->getOperators($options['type'] ?? 'string'),
+ 'operator' => $options['operator'] ?? '=',
+ 'multiple' => $options['multiple'] ?? false,
+ ];
+ }
+ }
+ }
+
+ return view('components.search-string');
+ }
+
+ protected function isFilter($column, $options)
+ {
+ $filter = true;
+
+ if (empty($this->getFilterUrl($column, $options)) && (!isset($options['date']) && !isset($options['boolean']) && !isset($options['values']))) {
+ $filter = false;
+ }
+
+ return $filter;
+ }
+
+ protected function getFilterKey($column, $options)
+ {
+ if (isset($options['key'])) {
+ $column = $options['key'];
+ }
+
+ if (isset($options['relationship']) && isset($options['foreign_key']) && ! empty($options['foreign_key'])) {
+ $column .= '.' . $options['foreign_key'];
+ }
+
+ if (isset($options['relationship']) && ! isset($options['foreign_key'])) {
+ $column .= '.id';
+ }
+
+ return $column;
+ }
+
+ protected function getFilterName($column, $options)
+ {
+ $column = last(explode('.', $column));
+
+ if (strpos($column, '_id') !== false) {
+ $column = str_replace('_id', '', $column);
+ } else if (strpos($column, '_code') !== false) {
+ $column = str_replace('_code', '', $column);
+ }
+
+ if (! empty($options['translation']) && ! isset($options['boolean'])) {
+ return $this->findTranslation($options['translation']);
+ }
+
+ if (!empty($options['key'])) {
+ $column = $options['key'];
+ }
+
+ $plural = Str::plural($column, 2);
+
+ if (strpos($this->model, 'Modules') !== false) {
+ $module_class = explode('\\', $this->model);
+
+ $prefix = Str::kebab($module_class[1]) . '::';
+
+ $translation_keys[] = $prefix . 'general.';
+ $translation_keys[] = $prefix . 'search_string.columns.';
+ }
+
+ $translation_keys[] = 'general.';
+ $translation_keys[] = 'search_string.columns.';
+
+ foreach ($translation_keys as $translation_key) {
+ if (trans_choice($translation_key . $plural, 1) !== $translation_key . $plural) {
+ return trans_choice($translation_key . $plural, 1);
+ }
+
+ if (trans($translation_key . $column) !== $translation_key . $column) {
+ return trans($translation_key . $column);
+ }
+ }
+
+ return $column;
+ }
+
+ protected function getFilterType($options)
+ {
+ $type = 'select';
+
+ if (isset($options['boolean'])) {
+ $type = 'boolean';
+ }
+
+ if (isset($options['date'])) {
+ $type = 'date';
+ }
+
+ return $type;
+ }
+
+ protected function getFilterUrl($column, $options)
+ {
+ $url = '';
+
+ if (isset($options['boolean']) || isset($options['date'])) {
+ return $url;
+ }
+
+ if (!empty($options['route'])) {
+ if (is_array($options['route'])) {
+ $url = route($options['route'][0], $options['route'][1]);
+ } else {
+ $url = route($options['route']);
+ }
+ } else {
+ if (strpos($this->model, 'Modules') !== false) {
+ $module_class = explode('\\', $this->model);
+
+ $url .= Str::kebab($module_class[1]) . '::';
+ }
+
+ if (strpos($column, '_id') !== false) {
+ $column = str_replace('_id', '', $column);
+ }
+
+ $plural = Str::plural($column, 2);
+
+ try {
+ $url = route($url . $plural . '.index');
+ } catch (\Exception $e) {
+ $url = '';
+ }
+ }
+
+ return $url;
+ }
+
+ protected function getFilterValues($column, $options)
+ {
+ $values = [];
+
+ if (isset($options['boolean'])) {
+ $values = [
+ [
+ 'key' => 0,
+ 'value' => empty($options['translation']) ? trans('general.no') : $this->findTranslation($options['translation'][0], 1),
+ ],
+ [
+ 'key' => 1,
+ 'value' => empty($options['translation']) ? trans('general.yes') : $this->findTranslation($options['translation'][1], 1),
+ ],
+ ];
+ } elseif (isset($options['values'])) {
+ foreach ($options['values'] as $key => $value) {
+ $name = $this->findTranslation($value, 1);
+ if (! empty($name)) {
+ $values[$key] = $name;
+ }
+ }
+ } elseif ($search = request()->get('search', false)) {
+ $fields = explode(' ', $search);
+
+ foreach ($fields as $field) {
+ if (strpos($field, ':') === false) {
+ continue;
+ }
+
+ $filters = explode(':', $field);
+
+ if ($filters[0] != $column) {
+ continue;
+ }
+ }
+ }
+
+ return $values;
+ }
+
+ protected function getOperators($type)
+ {
+ $operators = [
+ 'equal' => [
+ 'enabled' => true,
+ 'symbol' => [
+ 'sign' => '=',
+ 'icon' => 'drag_handle',
+ ],
+ 'text' => trans('general.is'),
+ ],
+ 'not_equal' => [
+ 'enabled' => true,
+ 'symbol' => [
+ 'sign' => '!=',
+ 'img' => asset('public/img/tailwind_icons/not-equal.svg'),
+ ],
+ 'text' => trans('general.isnot'),
+ ],
+ 'range' => [
+ 'enabled' => false,
+ 'symbol' => [
+ 'sign' => '><',
+ 'class' => 'transform rotate-90',
+ 'icon' => 'height',
+ ],
+ 'text' => trans('general.range'),
+ ],
+ ];
+
+ if ($type == 'date') {
+ $operators['range']['enabled'] = true;
+ }
+
+ return $operators;
+ }
+}
diff --git a/app/View/Components/Show/Accordion.php b/app/View/Components/Show/Accordion.php
new file mode 100644
index 00000000..d38c1bef
--- /dev/null
+++ b/app/View/Components/Show/Accordion.php
@@ -0,0 +1,46 @@
+type = $type;
+ $this->icon = $this->getIcon($icon);
+ $this->open = $open;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.show.accordion.index');
+ }
+
+ protected function getIcon($icon)
+ {
+ if (! empty($icon)) {
+ return $icon;
+ }
+
+ return 'expand_more';
+ }
+}
diff --git a/app/View/Components/Show/NoRecords.php b/app/View/Components/Show/NoRecords.php
new file mode 100644
index 00000000..9939abf7
--- /dev/null
+++ b/app/View/Components/Show/NoRecords.php
@@ -0,0 +1,144 @@
+ [
+ 'transactions' => 'accounts.create-income',
+ 'transfers' => 'accounts.create-transfer',
+ ],
+ 'customer' => [
+ 'invoices' => 'customers.create-invoice',
+ 'transactions' => 'customers.create-income',
+ ],
+ 'vendor' => [
+ 'bills' => 'vendors.create-bill',
+ 'transactions' => 'vendors.create-expense',
+ ],
+ ];
+
+ /**
+ * Create a new component instance.
+ *
+ * @return void
+ */
+ public function __construct(
+ string $type = '', $model = false, string $page = '', string $group = '',
+ string $backgroundColor = '', string $textColor = '',
+ string $image = '', string $description = '', string $url = '', string $textAction = ''
+ ) {
+ $this->type = $type;
+ $this->model = $model;
+ $this->page = $page;
+ $this->group = $group;
+ $this->backgroundColor = ! empty($backgroundColor) ? $backgroundColor : 'bg-lilac-900';
+ $this->textColor = ! empty($textColor) ? $textColor : 'text-purple';
+ $this->image = $this->getImage($image);
+ $this->description = $this->getDescription($description);
+ $this->url = $this->getUrl($url);
+ $this->textAction = $this->getTextAction($textAction);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.show.no-records');
+ }
+
+ protected function getImage($image)
+ {
+ if (! empty($image)) {
+ return $image;
+ }
+
+ $image = match ($this->type) {
+ 'account' => 'public/img/no_records/accounts_' . $this->page . '.png',
+ 'customer' => 'public/img/no_records/customers_' . $this->page . '.png',
+ 'vendor' => 'public/img/no_records/vendors_' . $this->page . '.png',
+ default => '',
+ };
+
+ return $image;
+ }
+
+ protected function getDescription($description)
+ {
+ if (! empty($description)) {
+ return $description;
+ }
+
+ $prefix = Str::plural($this->type);
+
+ $description = match ($this->type) {
+ 'account', 'customer', 'vendor' => trans($prefix . '.no_records.' . $this->page),
+ default => '',
+ };
+
+ return $description;
+ }
+
+ protected function getUrl($url)
+ {
+ if (! empty($url)) {
+ return $url;
+ }
+
+ if (array_key_exists($this->type, $this->urls) && array_key_exists($this->page, $this->urls[$this->type])) {
+ return route($this->urls[$this->type][$this->page], $this->model->id);
+ }
+
+ return $url;
+ }
+
+ protected function getTextAction($textAction)
+ {
+ if (! empty($textAction)) {
+ return $textAction;
+ }
+
+ $textAction = match ($this->type) {
+ 'account', 'customer', 'vendor' => trans('general.title.new', ['type' => trans_choice('general.' . $this->page, 1)]),
+ default => trans('modules.learn_more'),
+ };
+
+ return $textAction;
+ }
+}
diff --git a/app/View/Components/Show/Right.php b/app/View/Components/Show/Right.php
new file mode 100644
index 00000000..e998ce92
--- /dev/null
+++ b/app/View/Components/Show/Right.php
@@ -0,0 +1,21 @@
+backgroundColor = ! empty($backgroundColor) ? $backgroundColor : 'bg-lilac-900';
+ $this->textColor = ! empty($textColor) ? $textColor : 'text-purple';
+ $this->status = $status;
+ $this->textStatus = $this->getTextStatus($textStatus);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.show.status');
+ }
+
+ protected function getTextStatus($textStatus)
+ {
+ if (! empty($textStatus)) {
+ return $textStatus;
+ }
+
+ $textStatus = trans('documents.statuses.' . $this->status);
+
+ return $textStatus;
+ }
+}
diff --git a/app/View/Components/Suggestions.php b/app/View/Components/Suggestions.php
new file mode 100644
index 00000000..efe0b9b4
--- /dev/null
+++ b/app/View/Components/Suggestions.php
@@ -0,0 +1,81 @@
+suggestions = $this->setSuggestions($suggestions);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.suggestions');
+ }
+
+ protected function setSuggestions()
+ {
+ // No need to add suggestions in console
+ if (app()->runningInConsole() || !config('app.installed')) {
+ return [];
+ }
+
+ if ((! $user = user()) || $user->cannot('read-modules-home')) {
+ return [];
+ }
+
+ if (! $path = Route::current()->uri()) {
+ return [];
+ }
+
+ $path = str_replace('{company_id}/', '', $path);
+
+ if (! $suggestions = $this->getSuggestions($path)) {
+ return [];
+ }
+
+ $modules = [];
+
+ foreach ($suggestions->modules as $s_module) {
+ if ($this->moduleIsEnabled($s_module->alias)) {
+ continue;
+ }
+
+ $s_module->action_url = company_id() . '/' . $s_module->action_url;
+
+ $modules[] = $s_module;
+ }
+
+ if (empty($modules)) {
+ return [];
+ }
+
+ if (count($modules) < 3) {
+ return $modules;
+ }
+
+ return Arr::random($modules, 2);
+ }
+}
diff --git a/app/View/Components/Table/Actions.php b/app/View/Components/Table/Actions.php
new file mode 100644
index 00000000..fb94ac37
--- /dev/null
+++ b/app/View/Components/Table/Actions.php
@@ -0,0 +1,114 @@
+model = $model;
+ $this->actions = $this->getActions($actions);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.table.actions');
+ }
+
+ protected function getActions($actions)
+ {
+ if (empty($actions)) {
+ $actions = [];
+
+ if ($this->model && ! empty($this->model->line_actions)) {
+ $actions = $this->model->line_actions;
+ }
+ }
+
+ foreach ($actions as $key => $action) {
+ $attributes = [];
+
+ if (! empty($action['attributes'])) {
+ $attributes = $action['attributes'];
+ }
+
+ $actions[$key]['attributes'] = $this->getAttributes($attributes);
+ }
+
+ return $actions;
+ }
+
+ /**
+ * Build an HTML attribute string from an array.
+ *
+ * @param array $attributes
+ *
+ * @return string
+ */
+ public function getAttributes($attributes)
+ {
+ $html = [];
+
+ foreach ((array) $attributes as $key => $value) {
+ $element = $this->attributeElement($key, $value);
+
+ if (! is_null($element)) {
+ $html[] = $element;
+ }
+ }
+
+ return count($html) > 0 ? ' ' . implode(' ', $html) : '';
+ }
+
+ /**
+ * Build a single attribute element.
+ *
+ * @param string $key
+ * @param string $value
+ *
+ * @return string
+ */
+ protected function attributeElement($key, $value)
+ {
+ // For numeric keys we will assume that the value is a boolean attribute
+ // where the presence of the attribute represents a true value and the
+ // absence represents a false value.
+ // This will convert HTML attributes such as "required" to a correct
+ // form instead of using incorrect numerics.
+ if (is_numeric($key)) {
+ return $value;
+ }
+
+ // Treat boolean attributes as HTML properties
+ if (is_bool($value) && $key !== 'value') {
+ return $value ? $key : '';
+ }
+
+ if (is_array($value) && $key === 'class') {
+ return 'class=' . implode(' ', $value);
+ }
+
+ if (! is_null($value)) {
+ return $key . '=' . e($value, false);
+ }
+ }
+}
diff --git a/app/View/Components/Table/Tbody.php b/app/View/Components/Table/Tbody.php
new file mode 100644
index 00000000..4c2ddafe
--- /dev/null
+++ b/app/View/Components/Table/Tbody.php
@@ -0,0 +1,18 @@
+override = $this->getOverride($override);
+
+ $this->kind = $kind;
+ $this->hiddenMobile = $hiddenMobile;
+ $this->class = $this->getClass($class);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.table.td');
+ }
+
+ protected function getOverride($override)
+ {
+ return explode(',', $override);
+ }
+
+ protected function getClass($class)
+ {
+ if (in_array('class', $this->override)) {
+ return $class;
+ }
+
+ if ($this->hiddenMobile) {
+ $class = $class . ' ' . 'hidden sm:table-cell';
+ }
+
+ $default = 'py-4 whitespace-nowrap text-sm font-normal text-black truncate';
+
+ switch ($this->kind) {
+ case 'amount':
+ $default = $class . ' ltr:pl-6 rtl:pr-6 ltr:text-right rtl:text-left ' . $default;
+ break;
+ case 'right':
+ $default = $class . ' ltr:pl-6 rtl:pr-6 ltr:text-right rtl:text-left ' . $default;
+ break;
+ case 'bulkaction':
+ $default = $class . 'ltr:pr-6 rtl:pl-6 hidden sm:table-cell';
+ break;
+ case 'action':
+ $default = 'p-0';
+ break;
+ case 'cursor-none':
+ $default = $class . ' cursor-default ' . $default;
+ break;
+ default:
+ $default = $class . ' ltr:pr-6 rtl:pl-6 ltr:text-left rtl:text-right cursor-pointer ' . $default;
+ }
+
+ return $default;
+ }
+}
diff --git a/app/View/Components/Table/Th.php b/app/View/Components/Table/Th.php
new file mode 100644
index 00000000..570301f2
--- /dev/null
+++ b/app/View/Components/Table/Th.php
@@ -0,0 +1,75 @@
+override = $this->getOverride($override);
+
+ $this->kind = $kind;
+ $this->hiddenMobile = $hiddenMobile;
+ $this->class = $this->getClass($class);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.table.th');
+ }
+
+ protected function getOverride($override)
+ {
+ return explode(',', $override);
+ }
+
+ protected function getClass($class)
+ {
+ if (in_array('class', $this->override)) {
+ return $class;
+ }
+
+ if ($this->hiddenMobile) {
+ $class = $class . ' ' . 'hidden sm:table-cell';
+ }
+
+ $default = 'py-3 text-xs font-medium text-black tracking-wider';
+
+ switch ($this->kind) {
+ case 'amount':
+ $default = $class . ' ltr:pl-6 rtl:pr-6 ltr:text-right rtl:text-left ' . $default;
+ break;
+ case 'right':
+ $default = $class . ' ltr:pl-6 rtl:pr-6 ltr:text-right rtl:text-left' . $default;
+ break;
+ case 'bulkaction':
+ $default = $class . 'ltr:pr-6 rtl:pl-6 hidden sm:table-cell';
+ break;
+ default:
+ $default = $class . ' ltr:pr-6 rtl:pl-6 ltr:text-left rtl:text-right ' . $default;
+ }
+
+ return $default;
+ }
+}
diff --git a/app/View/Components/Table/Thead.php b/app/View/Components/Table/Thead.php
new file mode 100644
index 00000000..eddbe8f5
--- /dev/null
+++ b/app/View/Components/Table/Thead.php
@@ -0,0 +1,18 @@
+class = $this->getClass($class);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.table.tr');
+ }
+
+ protected function getClass($class)
+ {
+ if (! empty($class)) {
+ return $class;
+ }
+
+ $self = new ReflectionProperty($this::class, 'methodCache');
+ $self->setAccessible(true);
+
+ $values = $self->getValue();
+
+ $self = new ReflectionProperty($this::class, 'factory');
+ $self->setAccessible(true);
+
+ $factory = $self->getValue();
+
+ if (array_key_exists('App\View\Components\Table\Tbody', $values)
+ && ($factory instanceof \Illuminate\View\Factory && $factory->getLoopStack())
+ ) {
+ return 'relative flex items-center px-1 group border-b hover:bg-gray-100';
+ }
+
+ else if (array_key_exists('App\View\Components\Table\Thead', $values)) {
+ return 'flex items-center px-1';
+ }
+
+ return '';
+ }
+}
diff --git a/app/View/Components/Tips.php b/app/View/Components/Tips.php
new file mode 100644
index 00000000..2d6504f8
--- /dev/null
+++ b/app/View/Components/Tips.php
@@ -0,0 +1,104 @@
+position = $position;
+ $this->path = $path;
+ $this->tips = collect();
+
+ $this->setTips($tips);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ switch ($this->position) {
+ case 'fixed':
+ $view = 'components.tips.fixed';
+ break;
+ default:
+ $view = 'components.tips.relative';
+ }
+
+ if ($this->tips->count() > 1) {
+ $view = 'components.tips.relative';
+ }
+
+ return view($view);
+ }
+
+ protected function setTips($tips)
+ {
+ if (! empty($tips)) {
+ $this->tips = $tips;
+ }
+
+ if (! $path = Route::current()->uri()) {
+ return;
+ }
+
+ $path = Str::replace('{company_id}/', '', $path);
+
+ if (! $tips = $this->getTips($path)) {
+ return;
+ }
+
+ $rows = collect();
+
+ shuffle($tips);
+
+ foreach ($tips as $tip) {
+ if ($tip->position != $this->position) {
+ continue;
+ }
+
+ if (! empty($tip->alias) && $this->moduleIsEnabled($tip->alias)) {
+ continue;
+ }
+
+ if (Str::contains($tip->action, '{company_id}')) {
+ $tip->action = Str::replace('{company_id}', company_id(), $tip->action);
+ }
+
+ $rows->push($tip);
+ }
+
+ if ($rows->count()) {
+ $row = $rows->shuffle()->first();
+
+ $this->tips->push($row);
+ }
+ }
+}
diff --git a/app/View/Components/Title.php b/app/View/Components/Title.php
new file mode 100644
index 00000000..ce424d47
--- /dev/null
+++ b/app/View/Components/Title.php
@@ -0,0 +1,46 @@
+textSize = $this->getTextSize($textSize);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.title');
+ }
+
+ protected function getTextSize($textSize)
+ {
+ switch ($textSize) {
+ case 'short':
+ $textSize = '15';
+ break;
+ default:
+ $textSize = '25';
+ break;
+ }
+
+ return $textSize;
+ }
+}
diff --git a/app/View/Components/Tooltip.php b/app/View/Components/Tooltip.php
new file mode 100644
index 00000000..65d9d065
--- /dev/null
+++ b/app/View/Components/Tooltip.php
@@ -0,0 +1,163 @@
+id = $this->getId($id);
+ $this->placement = $this->getPlacement($placement);
+ $this->tooltipPosition = $this->getTooltipPosition($tooltipPosition);
+
+ $this->backgroundColor = $this->getBackgroundColor($backgroundColor);
+ $this->textColor = $this->getTextColor($textColor);
+ $this->borderColor = $this->getBorderColor($borderColor);
+
+ $this->message = $this->getMessage($message);
+ $this->size = $this->getSize($size);
+ $this->whitespace = $this->getWhiteSpace($whitespace);
+ $this->width = $width;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.tooltip');
+ }
+
+ protected function getId($id)
+ {
+ if (! empty($id)) {
+ return $id;
+ }
+
+ return 'tooltip-' . Str::random(19);
+ }
+
+ protected function getPlacement($placement)
+ {
+ if (! empty($placement)) {
+ return $placement;
+ }
+
+ return 'top';
+ }
+
+ protected function getTooltipPosition($tooltipPosition)
+ {
+ if (! empty($tooltipPosition)) {
+ return $tooltipPosition;
+ }
+
+ switch ($this->placement) {
+ case 'bottom':
+ $tooltipPosition = "-top-1 before:border-b-0 before:border-r-0";
+ break;
+ case 'left':
+ $tooltipPosition = "-right-1 before:border-b-0 before:border-l-0";
+ break;
+ case 'right':
+ $tooltipPosition = "-left-1 before:border-t-0 before:border-r-0";
+ break;
+ case 'top':
+ default:
+ $tooltipPosition = "-bottom-1 before:border-t-0 before:border-l-0";
+ break;
+ }
+
+ return $tooltipPosition;
+ }
+
+ protected function getBackgroundColor($backgroundColor)
+ {
+ if (! empty($backgroundColor)) {
+ return $backgroundColor;
+ }
+
+ return 'bg-white';
+ }
+
+ protected function getTextColor($textColor)
+ {
+ if (! empty($textColor)) {
+ return $textColor;
+ }
+
+ return 'text-gray-900';
+ }
+
+ protected function getBorderColor($borderColor)
+ {
+ if (! empty($borderColor)) {
+ return $borderColor;
+ }
+
+ return 'border-gray-200';
+ }
+
+ protected function getMessage($message)
+ {
+ if (! empty($message)) {
+ return $message;
+ }
+
+ return trans('general.na');
+ }
+
+ protected function getSize($size)
+ {
+ if (! empty($size)) {
+ return $size;
+ }
+
+ return 'w-auto';
+ }
+
+ protected function getWhiteSpace($whitespace)
+ {
+ if (! empty($whitespace)) {
+ return $whitespace;
+ }
+
+ return 'whitespace-normal';
+ }
+}
diff --git a/app/View/Components/Transactions/Index/BulkAction.php b/app/View/Components/Transactions/Index/BulkAction.php
new file mode 100644
index 00000000..1d507ef1
--- /dev/null
+++ b/app/View/Components/Transactions/Index/BulkAction.php
@@ -0,0 +1,18 @@
+type = $type;
+ $this->transaction = $transaction;
+
+ $this->alias = $this->getAlias($type, $alias);
+ $this->folder = $this->getScriptFolder($type, $folder);
+ $this->file = $this->getScriptFile($type, $file);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.transactions.script');
+ }
+}
diff --git a/app/View/Components/Transactions/Show/Attachment.php b/app/View/Components/Transactions/Show/Attachment.php
new file mode 100644
index 00000000..4a79b3cc
--- /dev/null
+++ b/app/View/Components/Transactions/Show/Attachment.php
@@ -0,0 +1,18 @@
+model = ! empty($model) ? $model : $transfer;
+ $this->transfer = ! empty($model) ? $model : $transfer;
+
+ $this->alias = $this->getAlias($type, $alias);
+ $this->folder = $this->getScriptFolder($type, $folder);
+ $this->file = $this->getScriptFile($type, $file);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.transfers.script');
+ }
+}
diff --git a/app/View/Components/Transfers/Show/Attachment.php b/app/View/Components/Transfers/Show/Attachment.php
new file mode 100644
index 00000000..ae126917
--- /dev/null
+++ b/app/View/Components/Transfers/Show/Attachment.php
@@ -0,0 +1,18 @@
+alerts = $this->getAlerts($alerts);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.update-alert');
+ }
+
+ public function getAlerts()
+ {
+ $alerts = [];
+
+ $updates = Versions::getUpdates();
+
+ if (! $updates) {
+ return $alerts;
+ }
+
+ foreach ($updates as $alias => $update) {
+ if (! $update->errors) {
+ continue;
+ }
+
+ foreach ($update->errors as $key => $error) {
+ switch ($key) {
+ case 'core':
+ $type = 'danger';
+ break;
+ case 'expires':
+ case 'compatible':
+ $type = 'warning';
+ break;
+ default:
+ $type = 'danger';
+ }
+
+ if (is_object($error) || is_array($error)) {
+ foreach ($error as $message) {
+ $alerts[$type][] = $message;
+ }
+ } else {
+ $alerts[$type][] = $error;
+ }
+ }
+ }
+
+ return $alerts;
+ }
+}
diff --git a/app/View/Components/Widgets/Contact.php b/app/View/Components/Widgets/Contact.php
new file mode 100644
index 00000000..2c914a1b
--- /dev/null
+++ b/app/View/Components/Widgets/Contact.php
@@ -0,0 +1,52 @@
+model = ! empty($model) ? $model : user()->contact;
+ $this->contact = ! empty($contact) ? $contact : $this->model;
+ }
+
+ /**
+ * Determine if the given full_name is the currently selected full_name.
+ *
+ * @param string $full_name
+ * @return string
+ */
+ public function shortName($full_name)
+ {
+ if (empty($full_name)) {
+ return trans('general.na');
+ }
+
+ $names = explode(' ', $full_name);
+
+ return strtoupper(substr($names[0], 0, 1) . substr(end($names), 0, 1));
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.widgets.contact');
+ }
+}
diff --git a/app/View/Components/Widgets/InvoiceHistory.php b/app/View/Components/Widgets/InvoiceHistory.php
new file mode 100644
index 00000000..99e96c3f
--- /dev/null
+++ b/app/View/Components/Widgets/InvoiceHistory.php
@@ -0,0 +1,50 @@
+contact = ! empty($contact) ? $contact : user()->contact;
+ $this->model = $model;
+ $this->invoices = $this->getPayment($model, $invoices);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.widgets.invoice_history');
+ }
+
+ protected function getPayment($model, $invoices)
+ {
+ if (! empty($model)) {
+ return $model;
+ }
+
+ if (! empty($invoices)) {
+ return $invoices;
+ }
+
+ return $this->contact->invoices()->orderBy('created_at', 'desc')->limit(3)->get();
+ }
+}
diff --git a/app/View/Components/Widgets/LastPayment.php b/app/View/Components/Widgets/LastPayment.php
new file mode 100644
index 00000000..78b458a4
--- /dev/null
+++ b/app/View/Components/Widgets/LastPayment.php
@@ -0,0 +1,50 @@
+contact = ! empty($contact) ? $contact : user()->contact;
+ $this->model = $model;
+ $this->payment = $this->getPayment($model, $payment);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.widgets.last_payment');
+ }
+
+ protected function getPayment($model, $payment)
+ {
+ if (! empty($model)) {
+ return $model;
+ }
+
+ if (! empty($payment)) {
+ return $payment;
+ }
+
+ return $this->contact->income_transactions()->orderBy('created_at', 'desc')->first();
+ }
+}
diff --git a/app/View/Components/Widgets/LatestInvoices.php b/app/View/Components/Widgets/LatestInvoices.php
new file mode 100644
index 00000000..07caa785
--- /dev/null
+++ b/app/View/Components/Widgets/LatestInvoices.php
@@ -0,0 +1,50 @@
+contact = ! empty($contact) ? $contact : user()->contact;
+ $this->model = $model;
+ $this->invoices = $this->getInvoices($model, $invoices);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.widgets.latest_invoices');
+ }
+
+ protected function getInvoices($model, $invoices)
+ {
+ if (! empty($model)) {
+ return $model;
+ }
+
+ if (! empty($invoices)) {
+ return $invoices;
+ }
+
+ return $this->contact->invoices()->orderBy('created_at', 'desc')->limit(3)->get();
+ }
+}
diff --git a/app/View/Components/Widgets/OutstandingBalance.php b/app/View/Components/Widgets/OutstandingBalance.php
new file mode 100644
index 00000000..4c1a8538
--- /dev/null
+++ b/app/View/Components/Widgets/OutstandingBalance.php
@@ -0,0 +1,32 @@
+contact = ! empty($contact) ? $contact : user()->contact;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.widgets.outstanding_balance');
+ }
+}
diff --git a/app/View/Components/Widgets/PaymentHistory.php b/app/View/Components/Widgets/PaymentHistory.php
new file mode 100644
index 00000000..3f8ce186
--- /dev/null
+++ b/app/View/Components/Widgets/PaymentHistory.php
@@ -0,0 +1,50 @@
+contact = ! empty($contact) ? $contact : user()->contact;
+ $this->model = $model;
+ $this->payments = $this->getPayment($model, $payments);
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|string
+ */
+ public function render()
+ {
+ return view('components.widgets.payment_history');
+ }
+
+ protected function getPayment($model, $payment)
+ {
+ if (! empty($model)) {
+ return $model;
+ }
+
+ if (! empty($payment)) {
+ return $payment;
+ }
+
+ return $this->contact->income_transactions()->orderBy('created_at', 'desc')->limit(3)->get();
+ }
+}
diff --git a/app/View/Presenters/Menu.php b/app/View/Presenters/Menu.php
new file mode 100644
index 00000000..78f4369f
--- /dev/null
+++ b/app/View/Presenters/Menu.php
@@ -0,0 +1,280 @@
+
+
+
+
';
+ }
+
+ /**
+ * {@inheritdoc }.
+ */
+ public function getHeaderWrapper($item)
+ {
+ return '' . $item->title . '
';
+ }
+
+ /**
+ * {@inheritdoc }.
+ */
+ public function getMenuWithDropDownWrapper($item)
+ {
+ $id = Str::slug($item->title);
+
+ return '
+
+
+
+
+
+
+
|NT*{1ROYnK8};Byp4z&_g?9rdK%uVBK}_!po|o z2=4K!!?sD=`i$8#%v6Bl7_vis6s$>Ru@MT7j*pI5ax!9gasC;9Hn$>mOKWo=kS)mh z>7ht+L=7bMfxahMWBlzOc;CizKXlXChMdcaF|Oc?Tye*{w$9!6{<|&}%5^I_Q4L2* zOWOau2FeJn49a^v< zn-=?@U0Q(P548Bn3De?_Kj_fnp?6%iObh+YYhL@h@n@G96id5_L)7r@v8i$4Go=O% zBf||$uro4%FAGpi?1ZWD`?ng&gKv1pJ8!?HFnj-lA9~ZdLU(uwCtrKp+it(MoV)tg zd+vV2!4n@OehCyY6p2WRV%*)40&!myNg#q^yqwS(FaBF>3SII{DFl%v5qg
#67CsSSIh|%jKd1U28*fF@*X}?4;5Rc&yzn5xXaHP zeQtK2<$43ogs5fXn4?o{&JBMh(2-)bF}YXFO@o-H Ch!xB18Qt&nCAT z3P=)3ksBBW;dMz~vde>Y>07Yw;PG%X?9g?@^4+K5@?o7gYWa3~H@Qb#FLlLit%WU3 zI$i~^I^*HAENs*$=Ign6Q`J(V$#})gNc}$D5|mi0PF@)}$V ^h(ie~;JBrA5-BU*tXrdM=1A1}PMK!rNjJ&BUt^FP4laTCHX+-fY?n zCFnpvRziQ%cg9Jv;-0<5z9~f^4lwRKqW|!D#$6!X 6jpgz}RKW27Kug0Mr56jCE##`_=A3Rjml&KEmIT73W6 zr3D`Qza*~#&me3Uu$`z5xi1_Vs*cww7-@hDBhmM+dfx@rNMknL+K?6_QY*yQi}A7^ z-TbQa&wRzc*+|ToJ?lnA%1`&_rYdIN=Dx&ORm`UwYJb0(Q`NK?@X8@^6L{x<*a;dV zBI$k)_~C%nLvo@FfqBDFj3>6u`_g-dm25R_Ozgbuj dVP@IF(X)MLCHl7#|Z6CM2|&Z`cv-%7&1R6TmhcMcgB9!!}ABw;pFUxo13 zi Y2v;wy?6Yko5tUZ0$)wN?|td7a?SzQ z3ejum``veuBUCfa0e# &y4!m+wdDtLgW>F9k2#2cSjH^;2Y`8rFlh8Z{;N_)oWP z#WXs;`y}X99zh==J_P0Xa4u>si!>6Z6v&KNwzQ9zO`@^sZF<63ua|=D-*!$+llV}0 z@qm$#H%lcMeXnx@TZQ2=iT%rEVrzd-sgP-7?b0vl)-rO~TIQc#8-;5ljh@<)hp+FL z>h0FQ`0^vxf0%Z_{D4n-Hu2ZkN*yPeMonU*8ruEP^&h-5^u4X|3!h3@>|^~7H<{**xd8xdf)^W (_7YQLQtPBj$R#X>ASW5hoHM!gb zvcPx}sxM^uEy4>@Uy>Aiov=WCVITW_|fE`srk zqCX&t?JGD*;^1Pwb9{5>_>1lX|IxX@c8+Lw_m{7A?_Bb `M3-)98=gA)dy0LC>If3}XU&8-cbP4(npeuv!BrM2UkF$3?N&XPDa0A%e3ELsE zv}5&aWt|vEU_d(2kj|N%mIgltnk}2FQ>*Ba;`%DrID4TodvK0)!Xk&t48iU6
, by listening to the
+ | Response after the App is done. If you disable this, you have to add them
+ | in your template yourself. See http://phpdebugbar.com/docs/rendering.html
+ |
+ */
+
+ 'inject' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | DebugBar route prefix
+ |--------------------------------------------------------------------------
+ |
+ | Sometimes you want to set route prefix to be used by DebugBar to load
+ | its resources from. Usually the need comes from misconfigured web server or
+ | from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97
+ |
+ */
+ 'route_prefix' => '_debugbar',
+
+ /*
+ |--------------------------------------------------------------------------
+ | DebugBar route domain
+ |--------------------------------------------------------------------------
+ |
+ | By default DebugBar route served from the same domain that request served.
+ | To override default domain, specify it as a non-empty value.
+ */
+ 'route_domain' => null,
+
+ /*
+ |--------------------------------------------------------------------------
+ | DebugBar theme
+ |--------------------------------------------------------------------------
+ |
+ | Switches between light and dark theme. If set to auto it will respect system preferences
+ | Possible values: auto, light, dark
+ */
+ 'theme' => env('DEBUGBAR_THEME', 'auto'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Backtrace stack limit
+ |--------------------------------------------------------------------------
+ |
+ | By default, the DebugBar limits the number of frames returned by the 'debug_backtrace()' function.
+ | If you need larger stacktraces, you can increase this number. Setting it to 0 will result in no limit.
+ */
+ 'debug_backtrace_limit' => 50,
+];
diff --git a/config/dompdf.php b/config/dompdf.php
new file mode 100644
index 00000000..2a6c4eb2
--- /dev/null
+++ b/config/dompdf.php
@@ -0,0 +1,284 @@
+ env('DOMPDF_DISK', null),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Settings
+ |--------------------------------------------------------------------------
+ |
+ | Set some default values. It is possible to add all defines that can be set
+ | in dompdf_config.inc.php. You can also override the entire config file.
+ |
+ */
+ 'show_warnings' => false, // Throw an Exception on warnings from dompdf
+
+ 'public_path' => null, // Override the public path if needed
+
+ /*
+ * Dejavu Sans font is missing glyphs for converted entities, turn it off if you need to show € and £.
+ */
+ 'convert_entities' => false,
+
+ 'options' => [
+ /**
+ * The location of the DOMPDF font directory
+ *
+ * The location of the directory where DOMPDF will store fonts and font metrics
+ * Note: This directory must exist and be writable by the webserver process.
+ * *Please note the trailing slash.*
+ *
+ * Notes regarding fonts:
+ * Additional .afm font metrics can be added by executing load_font.php from command line.
+ *
+ * Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must
+ * be embedded in the pdf file or the PDF may not display correctly. This can significantly
+ * increase file size unless font subsetting is enabled. Before embedding a font please
+ * review your rights under the font license.
+ *
+ * Any font specification in the source HTML is translated to the closest font available
+ * in the font directory.
+ *
+ * The pdf standard "Base 14 fonts" are:
+ * Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
+ * Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
+ * Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
+ * Symbol, ZapfDingbats.
+ */
+ "font_dir" => storage_path('fonts'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782)
+
+ /**
+ * The location of the DOMPDF font cache directory
+ *
+ * This directory contains the cached font metrics for the fonts used by DOMPDF.
+ * This directory can be the same as DOMPDF_FONT_DIR
+ *
+ * Note: This directory must exist and be writable by the webserver process.
+ */
+ "font_cache" => storage_path('fonts'),
+
+ /**
+ * The location of a temporary directory.
+ *
+ * The directory specified must be writeable by the webserver process.
+ * The temporary directory is required to download remote images and when
+ * using the PFDLib back end.
+ */
+ "temp_dir" => sys_get_temp_dir(),
+
+ /**
+ * ==== IMPORTANT ====
+ *
+ * dompdf's "chroot": Prevents dompdf from accessing system files or other
+ * files on the webserver. All local files opened by dompdf must be in a
+ * subdirectory of this directory. DO NOT set it to '/' since this could
+ * allow an attacker to use dompdf to read any files on the server. This
+ * should be an absolute path.
+ * This is only checked on command line call by dompdf.php, but not by
+ * direct class use like:
+ * $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
+ */
+ "chroot" => realpath(base_path()),
+
+ /**
+ * Protocol whitelist
+ *
+ * Protocols and PHP wrappers allowed in URIs, and the validation rules
+ * that determine if a resouce may be loaded. Full support is not guaranteed
+ * for the protocols/wrappers specified
+ * by this array.
+ *
+ * @var array
+ */
+ 'allowed_protocols' => [
+ "file://" => ["rules" => []],
+ "data://" => ["rules" => []]
+ ],
+
+ /**
+ * @var string
+ */
+ 'log_output_file' => null,
+
+ /**
+ * Whether to enable font subsetting or not.
+ */
+ "enable_font_subsetting" => true,
+
+ /**
+ * The PDF rendering backend to use
+ *
+ * Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and
+ * 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will
+ * fall back on CPDF. 'GD' renders PDFs to graphic files. {@link
+ * Canvas_Factory} ultimately determines which rendering class to instantiate
+ * based on this setting.
+ *
+ * Both PDFLib & CPDF rendering backends provide sufficient rendering
+ * capabilities for dompdf, however additional features (e.g. object,
+ * image and font support, etc.) differ between backends. Please see
+ * {@link PDFLib_Adapter} for more information on the PDFLib backend
+ * and {@link CPDF_Adapter} and lib/class.pdf.php for more information
+ * on CPDF. Also see the documentation for each backend at the links
+ * below.
+ *
+ * The GD rendering backend is a little different than PDFLib and
+ * CPDF. Several features of CPDF and PDFLib are not supported or do
+ * not make any sense when creating image files. For example,
+ * multiple pages are not supported, nor are PDF 'objects'. Have a
+ * look at {@link GD_Adapter} for more information. GD support is
+ * experimental, so use it at your own risk.
+ *
+ * @link http://www.pdflib.com
+ * @link http://www.ros.co.nz/pdf
+ * @link http://www.php.net/image
+ */
+ "pdf_backend" => "CPDF",
+
+ /**
+ * PDFlib license key
+ *
+ * If you are using a licensed, commercial version of PDFlib, specify
+ * your license key here. If you are using PDFlib-Lite or are evaluating
+ * the commercial version of PDFlib, comment out this setting.
+ *
+ * @link http://www.pdflib.com
+ *
+ * If pdflib present in web server and auto or selected explicitely above,
+ * a real license code must exist!
+ */
+ //"DOMPDF_PDFLIB_LICENSE" => "your license key here",
+
+ /**
+ * html target media view which should be rendered into pdf.
+ * List of types and parsing rules for future extensions:
+ * http://www.w3.org/TR/REC-html40/types.html
+ * screen, tty, tv, projection, handheld, print, braille, aural, all
+ * Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3.
+ * Note, even though the generated pdf file is intended for print output,
+ * the desired content might be different (e.g. screen or projection view of html file).
+ * Therefore allow specification of content here.
+ */
+ "default_media_type" => "screen",
+
+ /**
+ * The default paper size.
+ *
+ * North America standard is "letter"; other countries generally "a4"
+ *
+ * @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.)
+ */
+ "default_paper_size" => "a4",
+
+ /**
+ * The default paper orientation.
+ *
+ * The orientation of the page (portrait or landscape).
+ *
+ * @var string
+ */
+ 'default_paper_orientation' => "portrait",
+
+ /**
+ * The default font family
+ *
+ * Used if no suitable fonts can be found. This must exist in the font folder.
+ * @var string
+ */
+ "default_font" => "DejaVu Sans, sans-serif",
+
+ /**
+ * Image DPI setting
+ *
+ * This setting determines the default DPI setting for images and fonts. The
+ * DPI may be overridden for inline images by explictly setting the
+ * image's width & height style attributes (i.e. if the image's native
+ * width is 600 pixels and you specify the image's width as 72 points,
+ * the image will have a DPI of 600 in the rendered PDF. The DPI of
+ * background images can not be overridden and is controlled entirely
+ * via this parameter.
+ *
+ * For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI).
+ * If a size in html is given as px (or without unit as image size),
+ * this tells the corresponding size in pt.
+ * This adjusts the relative sizes to be similar to the rendering of the
+ * html page in a reference browser.
+ *
+ * In pdf, always 1 pt = 1/72 inch
+ *
+ * Rendering resolution of various browsers in px per inch:
+ * Windows Firefox and Internet Explorer:
+ * SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:?
+ * Linux Firefox:
+ * about:config *resolution: Default:96
+ * (xorg screen dimension in mm and Desktop font dpi settings are ignored)
+ *
+ * Take care about extra font/image zoom factor of browser.
+ *
+ * In images, size in pixel attribute, img css style, are overriding
+ * the real image dimension in px for rendering.
+ *
+ * @var int
+ */
+ "dpi" => 96,
+
+ /**
+ * Enable inline PHP
+ *
+ * If this setting is set to true then DOMPDF will automatically evaluate
+ * inline PHP contained within tags.
+ *
+ * Enabling this for documents you do not trust (e.g. arbitrary remote html
+ * pages) is a security risk. Set this option to false if you wish to process
+ * untrusted documents.
+ *
+ * @var bool
+ */
+ "enable_php" => false,
+
+ /**
+ * Enable inline Javascript
+ *
+ * If this setting is set to true then DOMPDF will automatically insert
+ * JavaScript code contained within tags.
+ *
+ * @var bool
+ */
+ "enable_javascript" => true,
+
+ /**
+ * Enable remote file access
+ *
+ * If this setting is set to true, DOMPDF will access remote sites for
+ * images and CSS files as required.
+ * This is required for part of test case www/test/image_variants.html through www/examples.php
+ *
+ * Attention!
+ * This can be a security risk, in particular in combination with DOMPDF_ENABLE_PHP and
+ * allowing remote access to dompdf.php or on allowing remote html code to be passed to
+ * $dompdf = new DOMPDF(, $dompdf->load_html(...,
+ * This allows anonymous users to download legally doubtful internet content which on
+ * tracing back appears to being downloaded by your server, or allows malicious php code
+ * in remote html pages to be executed by your server with your account privileges.
+ *
+ * @var bool
+ */
+ "enable_remote" => true,
+
+ /**
+ * A ratio applied to the fonts height to be more like browsers' line height
+ */
+ "font_height_ratio" => 1.1,
+
+ /**
+ * Use the HTML5 Lib parser
+ *
+ * @deprecated This feature is now always on in dompdf 2.x
+ * @var bool
+ */
+ "enable_html5_parser" => true,
+ ],
+
+];
diff --git a/config/excel.php b/config/excel.php
new file mode 100644
index 00000000..6d107518
--- /dev/null
+++ b/config/excel.php
@@ -0,0 +1,355 @@
+ [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Chunk size
+ |--------------------------------------------------------------------------
+ |
+ | When using FromQuery, the query is automatically chunked.
+ | Here you can specify how big the chunk should be.
+ |
+ */
+ 'chunk_size' => env('EXCEL_EXPORTS_CHUNK_SIZE', 100),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Pre-calculate formulas during export
+ |--------------------------------------------------------------------------
+ */
+ 'pre_calculate_formulas' => env('EXCEL_EXPORTS_PRE_CALCULATE_FORMULAS', false),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Enable strict null comparison
+ |--------------------------------------------------------------------------
+ |
+ | When enabling strict null comparison empty cells ('') will
+ | be added to the sheet.
+ */
+ 'strict_null_comparison' => env('EXCEL_EXPORTS_STRING_NULL_COMPARISON', false),
+
+ /*
+ |--------------------------------------------------------------------------
+ | CSV Settings
+ |--------------------------------------------------------------------------
+ |
+ | Configure e.g. delimiter, enclosure and line ending for CSV exports.
+ |
+ */
+ 'csv' => [
+ 'delimiter' => ',',
+ 'enclosure' => '"',
+ 'line_ending' => PHP_EOL,
+ 'use_bom' => false,
+ 'include_separator_line' => false,
+ 'excel_compatibility' => false,
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Worksheet properties
+ |--------------------------------------------------------------------------
+ |
+ | Configure e.g. default title, creator, subject,...
+ |
+ */
+ 'properties' => [
+ 'creator' => 'Akaunting',
+ 'lastModifiedBy' => '',
+ 'title' => '',
+ 'description' => '',
+ 'subject' => '',
+ 'keywords' => '',
+ 'category' => '',
+ 'manager' => '',
+ 'company' => '',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Export validations
+ |--------------------------------------------------------------------------
+ |
+ | Number of rows that will have the dropdown
+ |
+ */
+ 'row_count' => env('EXCEL_EXPORTS_ROW_COUNT', 250),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Export validations
+ |--------------------------------------------------------------------------
+ |
+ | Number of columns to be auto sized
+ |
+ */
+ 'column_count' => env('EXCEL_EXPORTS_COLUMN_COUNT', 25),
+ ],
+
+ 'imports' => [
+
+ 'chunk_size' => env('EXCEL_IMPORTS_CHUNK_SIZE', 100),
+
+ 'row_limit' => env('EXCEL_IMPORTS_ROW_LIMIT', 1000),
+
+ 'extensions' => env('EXCEL_IMPORTS_EXTENSIONS', 'xls,xlsx'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Read Only
+ |--------------------------------------------------------------------------
+ |
+ | When dealing with imports, you might only be interested in the
+ | data that the sheet exists. By default we ignore all styles,
+ | however if you want to do some logic based on style data
+ | you can enable it by setting read_only to false.
+ |
+ */
+ 'read_only' => env('EXCEL_IMPORTS_READ_ONLY', true),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Ignore Empty
+ |--------------------------------------------------------------------------
+ |
+ | When dealing with imports, you might be interested in ignoring
+ | rows that have null values or empty strings. By default rows
+ | containing empty strings or empty values are not ignored but can be
+ | ignored by enabling the setting ignore_empty to true.
+ |
+ */
+ 'ignore_empty' => env('EXCEL_IMPORTS_IGNORE_EMPTY', true),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Heading Row Formatter
+ |--------------------------------------------------------------------------
+ |
+ | Configure the heading row formatter.
+ | Available options: none|slug|custom
+ |
+ */
+ 'heading_row' => [
+ 'formatter' => 'slug',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | CSV Settings
+ |--------------------------------------------------------------------------
+ |
+ | Configure e.g. delimiter, enclosure and line ending for CSV imports.
+ |
+ */
+ 'csv' => [
+ 'delimiter' => ',',
+ 'enclosure' => '"',
+ 'escape_character' => '\\',
+ 'contiguous' => false,
+ 'input_encoding' => 'UTF-8',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Worksheet properties
+ |--------------------------------------------------------------------------
+ |
+ | Configure e.g. default title, creator, subject,...
+ |
+ */
+ 'properties' => [
+ 'creator' => 'Akaunting',
+ 'lastModifiedBy' => '',
+ 'title' => '',
+ 'description' => '',
+ 'subject' => '',
+ 'keywords' => '',
+ 'category' => '',
+ 'manager' => '',
+ 'company' => '',
+ ],
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Extension detector
+ |--------------------------------------------------------------------------
+ |
+ | Configure here which writer type should be used when
+ | the package needs to guess the correct type
+ | based on the extension alone.
+ |
+ */
+ 'extension_detector' => [
+ 'xlsx' => 'Xlsx',
+ 'xlsm' => 'Xlsx',
+ 'xltx' => 'Xlsx',
+ 'xltm' => 'Xlsx',
+ 'xls' => 'Xls',
+ 'xlt' => 'Xls',
+ 'ods' => 'Ods',
+ 'ots' => 'Ods',
+ 'slk' => 'Slk',
+ 'xml' => 'Xml',
+ 'gnumeric' => 'Gnumeric',
+ 'htm' => 'Html',
+ 'html' => 'Html',
+ 'csv' => 'Csv',
+ 'tsv' => 'Csv',
+
+ /*
+ |--------------------------------------------------------------------------
+ | PDF Extension
+ |--------------------------------------------------------------------------
+ |
+ | Configure here which Pdf driver should be used by default.
+ | Available options: Excel::MPDF | Excel::TCPDF | Excel::DOMPDF
+ |
+ */
+ 'pdf' => 'Dompdf',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Value Binder
+ |--------------------------------------------------------------------------
+ |
+ | PhpSpreadsheet offers a way to hook into the process of a value being
+ | written to a cell. In there some assumptions are made on how the
+ | value should be formatted. If you want to change those defaults,
+ | you can implement your own default value binder.
+ |
+ | Possible value binders:
+ |
+ | [x] Maatwebsite\Excel\DefaultValueBinder::class
+ | [x] PhpOffice\PhpSpreadsheet\Cell\StringValueBinder::class
+ | [x] PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder::class
+ |
+ */
+ 'value_binder' => [
+ 'default' => 'Maatwebsite\Excel\DefaultValueBinder',
+ ],
+
+ 'cache' => [
+ /*
+ |--------------------------------------------------------------------------
+ | Default cell caching driver
+ |--------------------------------------------------------------------------
+ |
+ | By default PhpSpreadsheet keeps all cell values in memory, however when
+ | dealing with large files, this might result into memory issues. If you
+ | want to mitigate that, you can configure a cell caching driver here.
+ | When using the illuminate driver, it will store each value in a the
+ | cache store. This can slow down the process, because it needs to
+ | store each value. You can use the "batch" store if you want to
+ | only persist to the store when the memory limit is reached.
+ |
+ | Drivers: memory|illuminate|batch
+ |
+ */
+ 'driver' => env('EXCEL_CACHE_DRIVER', 'memory'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Batch memory caching
+ |--------------------------------------------------------------------------
+ |
+ | When dealing with the "batch" caching driver, it will only
+ | persist to the store when the memory limit is reached.
+ | Here you can tweak the memory limit to your liking.
+ |
+ */
+ 'batch' => [
+ 'memory_limit' => env('EXCEL_CACHE_BATCH_MEMORY_LIMIT', 60000),
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Illuminate cache
+ |--------------------------------------------------------------------------
+ |
+ | When using the "illuminate" caching driver, it will automatically use
+ | your default cache store. However if you prefer to have the cell
+ | cache on a separate store, you can configure the store name here.
+ | You can use any store defined in your cache config. When leaving
+ | at "null" it will use the default store.
+ |
+ */
+ 'illuminate' => [
+ 'store' => null,
+ ],
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Transaction Handler
+ |--------------------------------------------------------------------------
+ |
+ | By default the import is wrapped in a transaction. This is useful
+ | for when an import may fail and you want to retry it. With the
+ | transactions, the previous import gets rolled-back.
+ |
+ | You can disable the transaction handler by setting this to null.
+ | Or you can choose a custom made transaction handler here.
+ |
+ | Supported handlers: null|db
+ |
+ */
+ 'transactions' => [
+ 'handler' => env('EXCEL_TRANSACTIONS_HANDLER', 'db'),
+ ],
+
+ 'temporary_files' => [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Local Temporary Path
+ |--------------------------------------------------------------------------
+ |
+ | When exporting and importing files, we use a temporary file, before
+ | storing reading or downloading. Here you can customize that path.
+ |
+ */
+ 'local_path' => storage_path('app/temp'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Remote Temporary Disk
+ |--------------------------------------------------------------------------
+ |
+ | When dealing with a multi server setup with queues in which you
+ | cannot rely on having a shared local temporary path, you might
+ | want to store the temporary file on a shared disk. During the
+ | queue executing, we'll retrieve the temporary file from that
+ | location instead. When left to null, it will always use
+ | the local path. This setting only has effect when using
+ | in conjunction with queued imports and exports.
+ |
+ */
+ 'remote_disk' => env('EXCEL_TEMPORARY_FILES_REMOTE_DISK'),
+ 'remote_prefix' => env('EXCEL_TEMPORARY_FILES_REMOTE_PREFIX'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Force Resync
+ |--------------------------------------------------------------------------
+ |
+ | When dealing with a multi server setup as above, it's possible
+ | for the clean up that occurs after entire queue has been run to only
+ | cleanup the server that the last AfterImportJob runs on. The rest of the server
+ | would still have the local temporary file stored on it. In this case your
+ | local storage limits can be exceeded and future imports won't be processed.
+ | To mitigate this you can set this config value to be true, so that after every
+ | queued chunk is processed the local temporary file is deleted on the server that
+ | processed it.
+ |
+ */
+ 'force_resync_remote' => env('EXCEL_TEMPORARY_FILES_FORCE_RESYNC_REMOTE'),
+
+ ],
+
+];
diff --git a/config/filesystems.php b/config/filesystems.php
new file mode 100644
index 00000000..d6566e25
--- /dev/null
+++ b/config/filesystems.php
@@ -0,0 +1,136 @@
+ env('FILESYSTEM_DISK', 'uploads'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Default Cloud Filesystem Disk
+ |--------------------------------------------------------------------------
+ |
+ | Many applications store files both locally and in the cloud. For this
+ | reason, you may specify a default "cloud" driver here. This driver
+ | will be bound as the Cloud disk implementation in the container.
+ |
+ */
+
+ 'cloud' => 'uploads',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Allowed file mimes
+ |--------------------------------------------------------------------------
+ */
+
+ 'mimes' => env('FILESYSTEM_MIMES', 'pdf,jpeg,jpg,png'),
+
+
+ /*
+ |--------------------------------------------------------------------------
+ | Allowed file max size, in MB
+ |--------------------------------------------------------------------------
+ */
+
+ 'max_size' => env('FILESYSTEM_MAX_SIZE', '2'),
+
+
+ /*
+ |--------------------------------------------------------------------------
+ | Allowed image max width, in pixes
+ |--------------------------------------------------------------------------
+ */
+
+ 'max_width' => env('FILESYSTEM_MAX_WIDTH', '1000'),
+
+
+ /*
+ |--------------------------------------------------------------------------
+ | Allowed image max height, in pixes
+ |--------------------------------------------------------------------------
+ */
+
+ 'max_height' => env('FILESYSTEM_MAX_HEIGHT', '1000'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Filesystem Disks
+ |--------------------------------------------------------------------------
+ |
+ | Here you may configure as many filesystem "disks" as you wish, and you
+ | may even configure multiple disks of the same driver. Defaults have
+ | been set up for each driver as an example of the required values.
+ |
+ | Supported Drivers: "local", "ftp", "sftp", "s3"
+ |
+ */
+
+ 'disks' => [
+
+ 'local' => [
+ 'driver' => 'local',
+ 'root' => storage_path('app'),
+ 'throw' => false,
+ ],
+
+ 'public' => [
+ 'driver' => 'local',
+ 'root' => storage_path('app/public'),
+ 'url' => app()->runningInConsole() ? '' : url('/') . '/storage',
+ 'visibility' => 'public',
+ 'throw' => false,
+ ],
+
+ 'temp' => [
+ 'driver' => 'local',
+ 'root' => storage_path('app/temp'),
+ 'url' => app()->runningInConsole() ? '' : url('/') . '/temp',
+ 'visibility' => 'private',
+ 'throw' => false,
+ ],
+
+ 'uploads' => [
+ 'driver' => 'local',
+ 'root' => storage_path('app/uploads'),
+ 'url' => app()->runningInConsole() ? '' : url('/') . '/uploads',
+ 'visibility' => 'private',
+ 'throw' => false,
+ ],
+
+ 's3' => [
+ 'driver' => 'local',
+ 'root' => storage_path('app/uploads'),
+ 'url' => app()->runningInConsole() ? '' : url('/') . '/uploads',
+ 'visibility' => 'private',
+ 'throw' => false,
+ ],
+
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Symbolic Links
+ |--------------------------------------------------------------------------
+ |
+ | Here you may configure the symbolic links that will be created when the
+ | `storage:link` Artisan command is executed. The array keys should be
+ | the locations of the links and the values should be their targets.
+ |
+ */
+
+ 'links' => [
+ public_path('storage') => storage_path('app/public'),
+ ],
+
+];
diff --git a/config/firewall.php b/config/firewall.php
new file mode 100644
index 00000000..d3675728
--- /dev/null
+++ b/config/firewall.php
@@ -0,0 +1,466 @@
+ env('FIREWALL_ENABLED', false),
+
+ 'whitelist' => explode(',', env('FIREWALL_WHITELIST', '')),
+
+ 'models' => [
+ 'user' => '\App\Models\Auth\User',
+ // 'log' => '\App\Models\YourLogModel',
+ // 'ip' => '\App\Models\YourIpModel',
+ ],
+
+ 'log' => [
+ 'max_request_size' => 2048,
+ ],
+
+ 'cron' => [
+ 'enabled' => env('FIREWALL_CRON_ENABLED', true),
+ 'expression' => env('FIREWALL_CRON_EXPRESSION', '* * * * *'),
+ ],
+
+ 'responses' => [
+
+ 'block' => [
+ 'view' => env('FIREWALL_BLOCK_VIEW', null),
+ 'redirect' => env('FIREWALL_BLOCK_REDIRECT', null),
+ 'abort' => env('FIREWALL_BLOCK_ABORT', false),
+ 'code' => env('FIREWALL_BLOCK_CODE', 403),
+ ],
+
+ ],
+
+ 'notifications' => [
+
+ 'mail' => [
+ 'enabled' => env('FIREWALL_EMAIL_ENABLED', false),
+ 'name' => env('FIREWALL_EMAIL_NAME', 'Akaunting Firewall'),
+ 'from' => env('FIREWALL_EMAIL_FROM', 'firewall@mydomain.com'),
+ 'to' => env('FIREWALL_EMAIL_TO', 'admin@mydomain.com'),
+ 'queue' => env('FIREWALL_EMAIL_QUEUE', 'default'),
+ ],
+
+ 'slack' => [
+ 'enabled' => env('FIREWALL_SLACK_ENABLED', false),
+ 'emoji' => env('FIREWALL_SLACK_EMOJI', ':fire:'),
+ 'from' => env('FIREWALL_SLACK_FROM', 'Akaunting Firewall'),
+ 'to' => env('FIREWALL_SLACK_TO'), // webhook url
+ 'channel' => env('FIREWALL_SLACK_CHANNEL', null), // set null to use the default channel of webhook
+ 'queue' => env('FIREWALL_SLACK_QUEUE', 'default'),
+ ],
+
+ ],
+
+ 'all_middleware' => [
+ 'firewall.ip',
+ 'firewall.agent',
+ 'firewall.bot',
+ 'firewall.geo',
+ 'firewall.lfi',
+ 'firewall.php',
+ 'firewall.referrer',
+ 'firewall.rfi',
+ 'firewall.session',
+ //'firewall.sqli',
+ 'firewall.swear',
+ 'firewall.xss',
+ //'App\Http\Middleware\YourCustomRule',
+ ],
+
+ 'middleware' => [
+
+ 'ip' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_IP_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['all'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+ ],
+
+ 'agent' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_AGENT_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['all'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ // https://github.com/jenssegers/agent
+ 'browsers' => [
+ 'allow' => [], // i.e. 'Chrome', 'Firefox'
+ 'block' => [], // i.e. 'IE'
+ ],
+
+ 'platforms' => [
+ 'allow' => [], // i.e. 'Ubuntu', 'Windows'
+ 'block' => [], // i.e. 'OS X'
+ ],
+
+ 'devices' => [
+ 'allow' => [], // i.e. 'Desktop', 'Mobile'
+ 'block' => [], // i.e. 'Tablet'
+ ],
+
+ 'properties' => [
+ 'allow' => [], // i.e. 'Gecko', 'Version/5.1.7'
+ 'block' => [], // i.e. 'AppleWebKit'
+ ],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_AGENT_AUTO_BLOCK_ATTEMPTS', 5),
+ 'frequency' => 1 * 60, // 1 minute
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'bot' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_BOT_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['all'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ // https://github.com/JayBizzle/Crawler-Detect/blob/master/raw/Crawlers.txt
+ 'crawlers' => [
+ 'allow' => [], // i.e. 'GoogleSites', 'GuzzleHttp'
+ 'block' => [], // i.e. 'Holmes'
+ ],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_BOT_AUTO_BLOCK_ATTEMPTS', 5),
+ 'frequency' => 1 * 60, // 1 minute
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'geo' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_GEO_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['all'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'continents' => [
+ 'allow' => [], // i.e. 'Africa'
+ 'block' => [], // i.e. 'Europe'
+ ],
+
+ 'regions' => [
+ 'allow' => [], // i.e. 'California'
+ 'block' => [], // i.e. 'Nevada'
+ ],
+
+ 'countries' => [
+ 'allow' => [], // i.e. 'Albania'
+ 'block' => [], // i.e. 'Madagascar'
+ ],
+
+ 'cities' => [
+ 'allow' => [], // i.e. 'Istanbul'
+ 'block' => [], // i.e. 'London'
+ ],
+
+ // ipapi, extremeiplookup, ipstack, ipdata, ipinfo
+ 'service' => 'ipapi',
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_GEO_AUTO_BLOCK_ATTEMPTS', 3),
+ 'frequency' => 5 * 60, // 5 minutes
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'lfi' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_LFI_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['get', 'delete'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'inputs' => [
+ 'only' => [], // i.e. 'first_name'
+ 'except' => [], // i.e. 'password'
+ ],
+
+ 'patterns' => [
+ '#\.\/#is',
+ ],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_LFI_AUTO_BLOCK_ATTEMPTS', 3),
+ 'frequency' => 5 * 60, // 5 minutes
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'login' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_LOGIN_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_LOGIN_AUTO_BLOCK_ATTEMPTS', 10),
+ 'frequency' => 1 * 60, // 1 minute
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'php' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_PHP_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['get', 'post', 'delete'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'inputs' => [
+ 'only' => [], // i.e. 'first_name'
+ 'except' => [], // i.e. 'password'
+ ],
+
+ 'patterns' => [
+ 'bzip2://',
+ 'expect://',
+ 'glob://',
+ 'phar://',
+ 'php://',
+ 'ogg://',
+ 'rar://',
+ 'ssh2://',
+ 'zip://',
+ 'zlib://',
+ ],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_PHP_AUTO_BLOCK_ATTEMPTS', 3),
+ 'frequency' => 5 * 60, // 5 minutes
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'referrer' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_REFERRER_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['all'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'blocked' => [],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_REFERRER_AUTO_BLOCK_ATTEMPTS', 3),
+ 'frequency' => 5 * 60, // 5 minutes
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'rfi' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_RFI_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['get', 'post', 'delete'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'inputs' => [
+ 'only' => [], // i.e. 'first_name'
+ 'except' => [
+ 'body', // for custom email add link
+ ], // i.e. 'password'
+ ],
+
+ 'patterns' => [
+ '#(http|ftp){1,1}(s){0,1}://.*#i',
+ ],
+
+ 'exceptions' => [],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_RFI_AUTO_BLOCK_ATTEMPTS', 3),
+ 'frequency' => 5 * 60, // 5 minutes
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'session' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_SESSION_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['get', 'post', 'delete'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'inputs' => [
+ 'only' => [], // i.e. 'first_name'
+ 'except' => [], // i.e. 'password'
+ ],
+
+ 'patterns' => [
+ '@[\|:]O:\d{1,}:"[\w_][\w\d_]{0,}":\d{1,}:{@i',
+ '@[\|:]a:\d{1,}:{@i',
+ ],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_SESSION_AUTO_BLOCK_ATTEMPTS', 3),
+ 'frequency' => 5 * 60, // 5 minutes
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'sqli' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_SQLI_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['get', 'delete'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'inputs' => [
+ 'only' => [], // i.e. 'first_name'
+ 'except' => [], // i.e. 'password'
+ ],
+
+ 'patterns' => [
+ '#[\d\W](union select|union join|union distinct)[\d\W]#is',
+ '#[\d\W](union|union select|insert|from|where|concat|into|cast|truncate|select|delete|having)[\d\W]#is',
+ ],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_SQLI_AUTO_BLOCK_ATTEMPTS', 3),
+ 'frequency' => 5 * 60, // 5 minutes
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'swear' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_SWEAR_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['post', 'put', 'patch'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'inputs' => [
+ 'only' => [], // i.e. 'first_name'
+ 'except' => [], // i.e. 'password'
+ ],
+
+ 'words' => [],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_SWEAR_AUTO_BLOCK_ATTEMPTS', 3),
+ 'frequency' => 5 * 60, // 5 minutes
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'url' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_URL_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['all'],
+
+ 'inspections' => [], // i.e. 'admin'
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_URL_AUTO_BLOCK_ATTEMPTS', 5),
+ 'frequency' => 1 * 60, // 1 minute
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ 'whitelist' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_WHITELIST_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['all'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+ ],
+
+ 'xss' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_XSS_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['post', 'put', 'patch'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'inputs' => [
+ 'only' => [], // i.e. 'first_name'
+ 'except' => [], // i.e. 'password'
+ ],
+
+ 'patterns' => [
+ // Evil starting attributes
+ '#(<[^>]+[\x00-\x20\"\'\/])(form|formaction|on\w*|style|xmlns|xlink:href)[^>]*>?#iUu',
+
+ // javascript:, livescript:, vbscript:, mocha: protocols (literal)
+ '!((java|live|vb)script|mocha|feed|data):(\w)*!iUu',
+ '#-moz-binding[\x00-\x20]*:#u',
+
+ // HTML entity-encoded protocol bypass (e.g. javascript: or java\u0073cript:)
+ '/j[\s\S]*a[\s\S]*v[\s\S]*a[\s\S]*s[\s\S]*c[\s\S]*r[\s\S]*i[\s\S]*p[\s\S]*t[\s\S]*:/iu',
+
+ // Unneeded tags
+ '#*(applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base|img)[^>]*>?#i'
+ ],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_XSS_AUTO_BLOCK_ATTEMPTS', 3),
+ 'frequency' => 5 * 60, // 5 minutes
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ // Custom middleware
+ 'too_many_emails_sent' => [
+ 'enabled' => env('FIREWALL_MIDDLEWARE_TOO_MANY_EMAILS_SENT_ENABLED', env('FIREWALL_ENABLED', true)),
+
+ 'methods' => ['post'],
+
+ 'routes' => [
+ 'only' => [], // i.e. 'contact'
+ 'except' => [], // i.e. 'admin/*'
+ ],
+
+ 'auto_block' => [
+ 'attempts' => env('FIREWALL_MIDDLEWARE_TOO_MANY_EMAILS_SENT_AUTO_BLOCK_ATTEMPTS', 20),
+ 'frequency' => 1 * 60, // 1 minute
+ 'period' => 30 * 60, // 30 minutes
+ ],
+ ],
+
+ ],
+
+];
diff --git a/config/hashing.php b/config/hashing.php
new file mode 100644
index 00000000..bcd3be4c
--- /dev/null
+++ b/config/hashing.php
@@ -0,0 +1,52 @@
+ 'bcrypt',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Bcrypt Options
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify the configuration options that should be used when
+ | passwords are hashed using the Bcrypt algorithm. This will allow you
+ | to control the amount of time it takes to hash the given password.
+ |
+ */
+
+ 'bcrypt' => [
+ 'rounds' => env('BCRYPT_ROUNDS', 10),
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Argon Options
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify the configuration options that should be used when
+ | passwords are hashed using the Argon algorithm. These will allow you
+ | to control the amount of time it takes to hash the given password.
+ |
+ */
+
+ 'argon' => [
+ 'memory' => 65536,
+ 'threads' => 1,
+ 'time' => 4,
+ ],
+
+];
diff --git a/config/ide-helper.php b/config/ide-helper.php
new file mode 100644
index 00000000..1d579eba
--- /dev/null
+++ b/config/ide-helper.php
@@ -0,0 +1,246 @@
+ '_ide_helper',
+ 'format' => 'php',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Where to write the PhpStorm specific meta file
+ |--------------------------------------------------------------------------
+ |
+ | PhpStorm also supports the directory `.phpstorm.meta.php/` with arbitrary
+ | files in it, should you need additional files for your project; e.g.
+ | `.phpstorm.meta.php/laravel_ide_Helper.php'.
+ |
+ */
+ 'meta_filename' => '.phpstorm.meta.php',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Fluent helpers
+ |--------------------------------------------------------------------------
+ |
+ | Set to true to generate commonly used Fluent methods
+ |
+ */
+
+ 'include_fluent' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Factory Builders
+ |--------------------------------------------------------------------------
+ |
+ | Set to true to generate factory generators for better factory()
+ | method auto-completion.
+ |
+ */
+
+ 'include_factory_builders' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Write Model Magic methods
+ |--------------------------------------------------------------------------
+ |
+ | Set to false to disable write magic methods of model
+ |
+ */
+
+ 'write_model_magic_where' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Write Model relation count properties
+ |--------------------------------------------------------------------------
+ |
+ | Set to false to disable writing of relation count properties to model DocBlocks.
+ |
+ */
+
+ 'write_model_relation_count_properties' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Write Eloquent Model Mixins
+ |--------------------------------------------------------------------------
+ |
+ | This will add the necessary DocBlock mixins to the model class
+ | contained in the Laravel Framework. This helps the IDE with
+ | auto-completion.
+ |
+ | Please be aware that this setting changes a file within the /vendor directory.
+ |
+ */
+
+ 'write_eloquent_model_mixins' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Helper files to include
+ |--------------------------------------------------------------------------
+ |
+ | Include helper files. By default not included, but can be toggled with the
+ | -- helpers (-H) option. Extra helper files can be included.
+ |
+ */
+
+ 'include_helpers' => false,
+
+ 'helper_files' => array(
+ base_path() . '/vendor/laravel/framework/src/Illuminate/Support/helpers.php',
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Model locations to include
+ |--------------------------------------------------------------------------
+ |
+ | Define in which directories the ide-helper:models command should look
+ | for models.
+ |
+ | glob patterns are supported to easier reach models in sub-directories,
+ | e.g. `app/Services/* /Models` (without the space)
+ |
+ */
+
+ 'model_locations' => array(
+ 'app/Models',
+ 'modules/*/Models'
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Models to ignore
+ |--------------------------------------------------------------------------
+ |
+ | Define which models should be ignored.
+ |
+ */
+
+ 'ignored_models' => array(
+
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Extra classes
+ |--------------------------------------------------------------------------
+ |
+ | These implementations are not really extended, but called with magic functions
+ |
+ */
+
+ 'extra' => array(
+ 'Eloquent' => array('Illuminate\Database\Eloquent\Builder', 'Illuminate\Database\Query\Builder'),
+ 'Session' => array('Illuminate\Session\Store'),
+ ),
+
+ 'magic' => array(),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Interface implementations
+ |--------------------------------------------------------------------------
+ |
+ | These interfaces will be replaced with the implementing class. Some interfaces
+ | are detected by the helpers, others can be listed below.
+ |
+ */
+
+ 'interfaces' => array(
+
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Support for custom DB types
+ |--------------------------------------------------------------------------
+ |
+ | This setting allow you to map any custom database type (that you may have
+ | created using CREATE TYPE statement or imported using database plugin
+ | / extension to a Doctrine type.
+ |
+ | Each key in this array is a name of the Doctrine2 DBAL Platform. Currently valid names are:
+ | 'postgresql', 'db2', 'drizzle', 'mysql', 'oracle', 'sqlanywhere', 'sqlite', 'mssql'
+ |
+ | This name is returned by getName() method of the specific Doctrine/DBAL/Platforms/AbstractPlatform descendant
+ |
+ | The value of the array is an array of type mappings. Key is the name of the custom type,
+ | (for example, "jsonb" from Postgres 9.4) and the value is the name of the corresponding Doctrine2 type (in
+ | our case it is 'json_array'. Doctrine types are listed here:
+ | http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html
+ |
+ | So to support jsonb in your models when working with Postgres, just add the following entry to the array below:
+ |
+ | "postgresql" => array(
+ | "jsonb" => "json_array",
+ | ),
+ |
+ */
+ 'custom_db_types' => array(
+
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Support for camel cased models
+ |--------------------------------------------------------------------------
+ |
+ | There are some Laravel packages (such as Eloquence) that allow for accessing
+ | Eloquent model properties via camel case, instead of snake case.
+ |
+ | Enabling this option will support these packages by saving all model
+ | properties as camel case, instead of snake case.
+ |
+ | For example, normally you would see this:
+ |
+ | * @property \Illuminate\Support\Carbon $created_at
+ | * @property \Illuminate\Support\Carbon $updated_at
+ |
+ | With this enabled, the properties will be this:
+ |
+ | * @property \Illuminate\Support\Carbon $createdAt
+ | * @property \Illuminate\Support\Carbon $updatedAt
+ |
+ | Note, it is currently an all-or-nothing option.
+ |
+ */
+ 'model_camel_case_properties' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Property Casts
+ |--------------------------------------------------------------------------
+ |
+ | Cast the given "real type" to the given "type".
+ |
+ */
+ 'type_overrides' => array(
+ 'integer' => 'int',
+ 'boolean' => 'bool',
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Include DocBlocks from classes
+ |--------------------------------------------------------------------------
+ |
+ | Include DocBlocks from classes to allow additional code inspection for
+ | magic methods and properties.
+ |
+ */
+ 'include_class_docblocks' => false,
+
+);
diff --git a/config/image.php b/config/image.php
new file mode 100644
index 00000000..b106809e
--- /dev/null
+++ b/config/image.php
@@ -0,0 +1,20 @@
+ 'gd'
+
+);
diff --git a/config/imagecache.php b/config/imagecache.php
new file mode 100644
index 00000000..99a1cc8a
--- /dev/null
+++ b/config/imagecache.php
@@ -0,0 +1,71 @@
+ null,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Storage paths
+ |--------------------------------------------------------------------------
+ |
+ | The following paths will be searched for the image filename, submitted
+ | by URI.
+ |
+ | Define as many directories as you like.
+ |
+ */
+
+ 'paths' => array(
+ public_path('upload'),
+ public_path('images')
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Manipulation templates
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify your own manipulation filter templates.
+ | The keys of this array will define which templates
+ | are available in the URI:
+ |
+ | {route}/{template}/{filename}
+ |
+ | The values of this array will define which filter class
+ | will be applied, by its fully qualified name.
+ |
+ */
+
+ 'templates' => array(
+ 'small' => 'Intervention\Image\Templates\Small',
+ 'medium' => 'Intervention\Image\Templates\Medium',
+ 'large' => 'Intervention\Image\Templates\Large',
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Image Cache Lifetime
+ |--------------------------------------------------------------------------
+ |
+ | Lifetime in minutes of the images handled by the imagecache route.
+ |
+ */
+
+ 'lifetime' => 43200,
+
+);
diff --git a/config/import.php b/config/import.php
new file mode 100644
index 00000000..c0d187c9
--- /dev/null
+++ b/config/import.php
@@ -0,0 +1,36 @@
+ [
+
+ // Type
+ 'transactions' => [
+
+ //'path' => 'banking/transactions',
+ //'title_type => 'transactions',
+ //'sample_file' => 'public/files/import/transactions.xlsx',
+ /*'form_params' => [
+ 'id' => 'import',
+ '@submit.prevent' => 'onSubmit',
+ '@keydown' => 'form.errors.clear($event.target.name)',
+ 'files' => true,
+ 'role' => 'form',
+ 'class' => 'form-loading-button',
+ 'novalidate' => true,
+ 'route' => '',
+ 'url' => '',
+ ],*/
+ 'document_link' => '',
+ 'view' => 'banking.transactions.import',
+
+ ],
+ ],
+
+];
diff --git a/config/language.php b/config/language.php
new file mode 100644
index 00000000..9606a9d4
--- /dev/null
+++ b/config/language.php
@@ -0,0 +1,231 @@
+ true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Enable Language Home Route
+ |--------------------------------------------------------------------------
+ |
+ | This option enable language route to set language and return
+ | to url('/')
+ |
+ */
+ 'home' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Add Language Code
+ |--------------------------------------------------------------------------
+ |
+ | This option will add the language code to the redirected url
+ |
+ */
+ 'url' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Set strategy
+ |--------------------------------------------------------------------------
+ |
+ | This option will determine the strategy used to determine the back url.
+ | It can be 'session' (default) or 'referer'
+ |
+ */
+ 'back' => 'session',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Carbon Language
+ |--------------------------------------------------------------------------
+ |
+ | This option the language of carbon library.
+ |
+ */
+ 'carbon' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Date Language
+ |--------------------------------------------------------------------------
+ |
+ | This option the language of jenssegers/date library.
+ |
+ */
+ 'date' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Auto Change Language
+ |--------------------------------------------------------------------------
+ |
+ | This option allows to change website language to user's
+ | browser language.
+ |
+ */
+ 'auto' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Routes Prefix
+ |--------------------------------------------------------------------------
+ |
+ | This option indicates the prefix for language routes.
+ |
+ */
+ 'prefix' => 'languages',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Middleware
+ |--------------------------------------------------------------------------
+ |
+ | This option indicates the middleware to change language.
+ |
+ */
+ 'middleware' => 'Akaunting\Language\Middleware\SetLocale',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Controller
+ |--------------------------------------------------------------------------
+ |
+ | This option indicates the controller to be used.
+ |
+ */
+ 'controller' => 'Akaunting\Language\Controllers\Language',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Flags
+ |--------------------------------------------------------------------------
+ |
+ | This option indicates the flags features.
+ |
+ */
+ 'flags' => ['width' => '22px', 'ul_class' => 'menu', 'li_class' => '', 'img_class' => ''],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Language code mode
+ |--------------------------------------------------------------------------
+ |
+ | This option indicates the language code and name to be used, short/long
+ | and english/native.
+ | Short: language code (en)
+ | Long: languagecode-COUNTRYCODE (en-GB)
+ |
+ */
+ 'mode' => ['code' => 'long', 'name' => 'native'],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Allowed languages
+ |--------------------------------------------------------------------------
+ |
+ | This options indicates the language allowed languages.
+ |
+ */
+ 'allowed' => [
+ 'ar-SA',
+ 'de-DE',
+ 'el-GR',
+ 'en-AU',
+ 'en-GB',
+ 'en-US',
+ 'es-ES',
+ 'es-MX',
+ 'fr-FR',
+ 'hi-IN',
+ 'id-ID',
+ 'it-IT',
+ 'ms-MY',
+ 'nl-NL',
+ 'pl-PL',
+ 'pt-BR',
+ 'ru-RU',
+ 'tr-TR',
+ 'zh-CN',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | All Languages
+ |--------------------------------------------------------------------------
+ |
+ | This option indicates the language codes and names.
+ |
+ */
+ 'all' => [
+ ['short' => 'ar', 'long' => 'ar-SA', 'direction' => 'rtl', 'english' => 'Arabic', 'native' => 'العربية'],
+ ['short' => 'az', 'long' => 'az-AZ', 'direction' => 'ltr', 'english' => 'Azerbaijani', 'native' => 'Azərbaycan'],
+ ['short' => 'bg', 'long' => 'bg-BG', 'direction' => 'ltr', 'english' => 'Bulgarian', 'native' => 'български'],
+ ['short' => 'bn', 'long' => 'bn-BD', 'direction' => 'ltr', 'english' => 'Bengali', 'native' => 'বাংলা'],
+ ['short' => 'bs', 'long' => 'bs-BA', 'direction' => 'ltr', 'english' => 'Bosnian', 'native' => 'Bosanski'],
+ ['short' => 'ca', 'long' => 'ca-ES', 'direction' => 'ltr', 'english' => 'Catalan', 'native' => 'Català'],
+ ['short' => 'cn', 'long' => 'zh-CN', 'direction' => 'ltr', 'english' => 'Chinese (S)', 'native' => '简体中文'],
+ ['short' => 'cs', 'long' => 'cs-CZ', 'direction' => 'ltr', 'english' => 'Czech', 'native' => 'Čeština'],
+ ['short' => 'da', 'long' => 'da-DK', 'direction' => 'ltr', 'english' => 'Danish', 'native' => 'Dansk'],
+ ['short' => 'de', 'long' => 'de-DE', 'direction' => 'ltr', 'english' => 'German', 'native' => 'Deutsch'],
+ ['short' => 'de', 'long' => 'de-AT', 'direction' => 'ltr', 'english' => 'Austrian', 'native' => 'Österreichisches Deutsch'],
+ ['short' => 'fi', 'long' => 'fi-FI', 'direction' => 'ltr', 'english' => 'Finnish', 'native' => 'Suomi'],
+ ['short' => 'fr', 'long' => 'fr-FR', 'direction' => 'ltr', 'english' => 'French', 'native' => 'Français'],
+ ['short' => 'ea', 'long' => 'es-AR', 'direction' => 'ltr', 'english' => 'Spanish (Argentina)', 'native' => 'Español de Argentina'],
+ ['short' => 'el', 'long' => 'el-GR', 'direction' => 'ltr', 'english' => 'Greek', 'native' => 'Ελληνικά'],
+ ['short' => 'en', 'long' => 'en-AU', 'direction' => 'ltr', 'english' => 'English (AU)', 'native' => 'English (AU)'],
+ ['short' => 'en', 'long' => 'en-CA', 'direction' => 'ltr', 'english' => 'English (CA)', 'native' => 'English (CA)'],
+ ['short' => 'en', 'long' => 'en-GB', 'direction' => 'ltr', 'english' => 'English (GB)', 'native' => 'English (GB)'],
+ ['short' => 'en', 'long' => 'en-US', 'direction' => 'ltr', 'english' => 'English (US)', 'native' => 'English (US)'],
+ ['short' => 'es', 'long' => 'es-ES', 'direction' => 'ltr', 'english' => 'Spanish', 'native' => 'Español'],
+ ['short' => 'et', 'long' => 'et-EE', 'direction' => 'ltr', 'english' => 'Estonian', 'native' => 'Eesti'],
+ ['short' => 'he', 'long' => 'he-IL', 'direction' => 'rtl', 'english' => 'Hebrew', 'native' => 'עִבְרִית'],
+ ['short' => 'hi', 'long' => 'hi-IN', 'direction' => 'ltr', 'english' => 'Hindi', 'native' => 'हिन्दी'],
+ ['short' => 'hr', 'long' => 'hr-HR', 'direction' => 'ltr', 'english' => 'Croatian', 'native' => 'Hrvatski'],
+ ['short' => 'hu', 'long' => 'hu-HU', 'direction' => 'ltr', 'english' => 'Hungarian', 'native' => 'Magyar'],
+ ['short' => 'hy', 'long' => 'hy-AM', 'direction' => 'ltr', 'english' => 'Armenian', 'native' => 'Հայերեն',],
+ ['short' => 'id', 'long' => 'id-ID', 'direction' => 'ltr', 'english' => 'Indonesian', 'native' => 'Bahasa Indonesia'],
+ ['short' => 'is', 'long' => 'is-IS', 'direction' => 'ltr', 'english' => 'Icelandic', 'native' => 'Íslenska'],
+ ['short' => 'it', 'long' => 'it-IT', 'direction' => 'ltr', 'english' => 'Italian', 'native' => 'Italiano'],
+ ['short' => 'ir', 'long' => 'fa-IR', 'direction' => 'rtl', 'english' => 'Persian', 'native' => 'فارسی'],
+ ['short' => 'jp', 'long' => 'ja-JP', 'direction' => 'ltr', 'english' => 'Japanese', 'native' => '日本語'],
+ ['short' => 'ka', 'long' => 'ka-GE', 'direction' => 'ltr', 'english' => 'Georgian', 'native' => 'ქართული'],
+ ['short' => 'ko', 'long' => 'ko-KR', 'direction' => 'ltr', 'english' => 'Korean', 'native' => '한국어'],
+ ['short' => 'lt', 'long' => 'lt-LT', 'direction' => 'ltr', 'english' => 'Lithuanian', 'native' => 'Lietuvių'],
+ ['short' => 'lv', 'long' => 'lv-LV', 'direction' => 'ltr', 'english' => 'Latvian', 'native' => 'Latviešu valoda'],
+ ['short' => 'mk', 'long' => 'mk-MK', 'direction' => 'ltr', 'english' => 'Macedonian', 'native' => 'Македонски јазик'],
+ ['short' => 'ms', 'long' => 'ms-MY', 'direction' => 'ltr', 'english' => 'Malay', 'native' => 'Bahasa Melayu'],
+ ['short' => 'mx', 'long' => 'es-MX', 'direction' => 'ltr', 'english' => 'Mexico', 'native' => 'Español de México'],
+ ['short' => 'nb', 'long' => 'nb-NO', 'direction' => 'ltr', 'english' => 'Norwegian', 'native' => 'Norsk Bokmål'],
+ ['short' => 'ne', 'long' => 'ne-NP', 'direction' => 'ltr', 'english' => 'Nepali', 'native' => 'नेपाली'],
+ ['short' => 'nl', 'long' => 'nl-NL', 'direction' => 'ltr', 'english' => 'Dutch', 'native' => 'Nederlands'],
+ ['short' => 'pl', 'long' => 'pl-PL', 'direction' => 'ltr', 'english' => 'Polish', 'native' => 'Polski'],
+ ['short' => 'pt-BR', 'long' => 'pt-BR', 'direction' => 'ltr', 'english' => 'Brazilian', 'native' => 'Português do Brasil'],
+ ['short' => 'pt', 'long' => 'pt-PT', 'direction' => 'ltr', 'english' => 'Portuguese', 'native' => 'Português'],
+ ['short' => 'ro', 'long' => 'ro-RO', 'direction' => 'ltr', 'english' => 'Romanian', 'native' => 'Română'],
+ ['short' => 'ru', 'long' => 'ru-RU', 'direction' => 'ltr', 'english' => 'Russian', 'native' => 'Русский'],
+ ['short' => 'sr', 'long' => 'sr-RS', 'direction' => 'ltr', 'english' => 'Serbian (Cyrillic)', 'native' => 'Српски језик'],
+ ['short' => 'sr', 'long' => 'sr-CS', 'direction' => 'ltr', 'english' => 'Serbian (Latin)', 'native' => 'Српски језик'],
+ ['short' => 'sq', 'long' => 'sq-AL', 'direction' => 'ltr', 'english' => 'Albanian', 'native' => 'Shqip'],
+ ['short' => 'sk', 'long' => 'sk-SK', 'direction' => 'ltr', 'english' => 'Slovak', 'native' => 'Slovenčina'],
+ ['short' => 'sl', 'long' => 'sl-SI', 'direction' => 'ltr', 'english' => 'Slovenian', 'native' => 'Slovenščina'],
+ ['short' => 'sv', 'long' => 'sv-SE', 'direction' => 'ltr', 'english' => 'Swedish', 'native' => 'Svenska'],
+ ['short' => 'th', 'long' => 'th-TH', 'direction' => 'ltr', 'english' => 'Thai', 'native' => 'ไทย'],
+ ['short' => 'tr', 'long' => 'tr-TR', 'direction' => 'ltr', 'english' => 'Turkish', 'native' => 'Türkçe'],
+ ['short' => 'tw', 'long' => 'zh-TW', 'direction' => 'ltr', 'english' => 'Chinese (T)', 'native' => '繁體中文'],
+ ['short' => 'uk', 'long' => 'uk-UA', 'direction' => 'ltr', 'english' => 'Ukrainian', 'native' => 'Українська'],
+ ['short' => 'ur', 'long' => 'ur-PK', 'direction' => 'rtl', 'english' => 'Urdu (Pakistan)', 'native' => 'اردو'],
+ ['short' => 'uz', 'long' => 'uz-UZ', 'direction' => 'ltr', 'english' => 'Uzbek', 'native' => 'O\'zbek'],
+ ['short' => 'vi', 'long' => 'vi-VN', 'direction' => 'ltr', 'english' => 'Vietnamese', 'native' => 'Tiếng Việt'],
+ ],
+
+];
diff --git a/config/laratrust.php b/config/laratrust.php
new file mode 100644
index 00000000..3b2300fd
--- /dev/null
+++ b/config/laratrust.php
@@ -0,0 +1,360 @@
+ true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Which permissions and role checker to use.
+ |--------------------------------------------------------------------------
+ |
+ | Defines if you want to use the roles and permissions checker.
+ | Available:
+ | - default: Check for the roles and permissions using the method that Laratrust
+ has always used.
+ | - query: Check for the roles and permissions using direct queries to the database.
+ | This method doesn't support cache yet.
+ |
+ */
+ 'checker' => 'default',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Cache
+ |--------------------------------------------------------------------------
+ |
+ | Manage Laratrust's cache configurations. It uses the driver defined in the
+ | config/cache.php file.
+ |
+ */
+ 'cache' => [
+ /*
+ |--------------------------------------------------------------------------
+ | Use cache in the package
+ |--------------------------------------------------------------------------
+ |
+ | Defines if Laratrust will use Laravel's Cache to cache the roles and permissions.
+ | NOTE: Currently the database check does not use cache.
+ |
+ */
+ 'enabled' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Time to store in cache Laratrust's roles and permissions.
+ |--------------------------------------------------------------------------
+ |
+ | Determines the time in SECONDS to store Laratrust's roles and permissions in the cache.
+ |
+ */
+ 'expiration_time' => 3600,
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust User Models
+ |--------------------------------------------------------------------------
+ |
+ | This is the array that contains the information of the user models.
+ | This information is used in the add-trait command, and for the roles and
+ | permissions relationships with the possible user models.
+ |
+ | The key in the array is the name of the relationship inside the roles and permissions.
+ |
+ */
+ 'user_models' => [
+ 'users' => 'App\Models\Auth\User',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Models
+ |--------------------------------------------------------------------------
+ |
+ | These are the models used by Laratrust to define the roles, permissions and teams.
+ | If you want the Laratrust models to be in a different namespace or
+ | to have a different name, you can do it here.
+ |
+ */
+ 'models' => [
+ /**
+ * Role model
+ */
+ 'role' => 'App\Models\Auth\Role',
+
+ /**
+ * Permission model
+ */
+ 'permission' => 'App\Models\Auth\Permission',
+
+ /**
+ * Team model
+ */
+ 'team' => 'App\Models\Auth\Team',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Tables
+ |--------------------------------------------------------------------------
+ |
+ | These are the tables used by Laratrust to store all the authorization data.
+ |
+ */
+ 'tables' => [
+ /**
+ * Roles table.
+ */
+ 'roles' => 'roles',
+
+ /**
+ * Permissions table.
+ */
+ 'permissions' => 'permissions',
+
+ /**
+ * Teams table.
+ */
+ 'teams' => 'teams',
+
+ /**
+ * Role - User intermediate table.
+ */
+ 'role_user' => 'user_roles',
+
+ /**
+ * Permission - User intermediate table.
+ */
+ 'permission_user' => 'user_permissions',
+
+ /**
+ * Permission - Role intermediate table.
+ */
+ 'permission_role' => 'role_permissions',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Foreign Keys
+ |--------------------------------------------------------------------------
+ |
+ | These are the foreign keys used by laratrust in the intermediate tables.
+ |
+ */
+ 'foreign_keys' => [
+ /**
+ * User foreign key on Laratrust's role_user and permission_user tables.
+ */
+ 'user' => 'user_id',
+
+ /**
+ * Role foreign key on Laratrust's role_user and permission_role tables.
+ */
+ 'role' => 'role_id',
+
+ /**
+ * Role foreign key on Laratrust's permission_user and permission_role tables.
+ */
+ 'permission' => 'permission_id',
+
+ /**
+ * Role foreign key on Laratrust's role_user and permission_user tables.
+ */
+ 'team' => 'team_id',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Middleware
+ |--------------------------------------------------------------------------
+ |
+ | This configuration helps to customize the Laratrust middleware behavior.
+ |
+ */
+ 'middleware' => [
+ /**
+ * Define if the laratrust middleware are registered automatically in the service provider
+ */
+ 'register' => false,
+
+ /**
+ * Method to be called in the middleware return case.
+ * Available: abort|redirect
+ */
+ 'handling' => 'abort',
+
+ /**
+ * Handlers for the unauthorized method in the middlewares.
+ * The name of the handler must be the same as the handling.
+ */
+ 'handlers' => [
+ /**
+ * Aborts the execution with a 403 code.
+ */
+ 'abort' => [
+ 'code' => 403,
+ 'message' => 'User does not have any of the necessary access rights.'
+ ],
+ /**
+ * Redirects the user to the given url.
+ * If you want to flash a key to the session,
+ * you can do it by setting the key and the content of the message
+ * If the message content is empty it won't be added to the redirection.
+ */
+ 'redirect' => [
+ 'url' => 'auth/login',
+ 'message' => [
+ 'key' => 'error',
+ 'content' => ''
+ ]
+ ]
+ ]
+ ],
+
+ 'teams' => [
+ /*
+ |--------------------------------------------------------------------------
+ | Use teams feature in the package
+ |--------------------------------------------------------------------------
+ |
+ | Defines if Laratrust will use the teams feature.
+ | Please check the docs to see what you need to do in case you have the package already configured.
+ |
+ */
+ 'enabled' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Strict check for roles/permissions inside teams
+ |--------------------------------------------------------------------------
+ |
+ | Determines if a strict check should be done when checking if a role or permission
+ | is attached inside a team.
+ | If it's false, when checking a role/permission without specifying the team,
+ | it will check only if the user has attached that role/permission ignoring the team.
+ |
+ */
+ 'strict_check' => false,
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Magic 'isAbleTo' Method
+ |--------------------------------------------------------------------------
+ |
+ | Supported cases for the magic is able to method (Refer to the docs).
+ | Available: camel_case|snake_case|kebab_case
+ |
+ */
+ 'magic_is_able_to_method_case' => 'kebab_case',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Permissions as Gates
+ |--------------------------------------------------------------------------
+ |
+ | Determines if you can check if a user has a permission using the "can" method.
+ |
+ */
+ 'permissions_as_gates' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Panel
+ |--------------------------------------------------------------------------
+ |
+ | Section to manage everything related with the admin panel for the roles and permissions.
+ |
+ */
+ 'panel' => [
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Panel Register
+ |--------------------------------------------------------------------------
+ |
+ | This manages if routes used for the admin panel should be registered.
+ | Turn this value to false if you don't want to use Laratrust admin panel
+ |
+ */
+ 'register' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Panel Path
+ |--------------------------------------------------------------------------
+ |
+ | This is the URI path where Laratrust panel for roles and permissions
+ | will be accessible from.
+ |
+ */
+ 'path' => 'laratrust',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Panel Path
+ |--------------------------------------------------------------------------
+ |
+ | The route where the go back link should point
+ |
+ */
+ 'go_back_route' => '/',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Laratrust Panel Route Middleware
+ |--------------------------------------------------------------------------
+ |
+ | These middleware will get attached onto each Laratrust panel route.
+ |
+ */
+ 'middleware' => ['web'],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Enable permissions assignment
+ |--------------------------------------------------------------------------
+ |
+ | Enable/Disable the permissions assignment to the users.
+ |
+ */
+ 'assign_permissions_to_user' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Add restriction to roles in the panel
+ |--------------------------------------------------------------------------
+ |
+ | Configure which roles can not be editable, deletable and removable.
+ | To add a role to the restriction, use name of the role here.
+ |
+ */
+ 'roles_restrictions' => [
+ // The user won't be able to remove roles already assigned to users.
+ 'not_removable' => [],
+
+ // The user won't be able to edit the role and the permissions assigned.
+ 'not_editable' => [],
+
+ // The user won't be able to delete the role.
+ 'not_deletable' => [],
+ ],
+ ],
+
+];
diff --git a/config/laravel-model-caching.php b/config/laravel-model-caching.php
new file mode 100644
index 00000000..57865442
--- /dev/null
+++ b/config/laravel-model-caching.php
@@ -0,0 +1,13 @@
+ env('MODEL_CACHE_ENABLED', true),
+
+ 'cache-prefix' => env('MODEL_CACHE_PREFIX', 'model'),
+
+ 'use-database-keying' => env('MODEL_CACHE_USE_DATABASE_KEYING', true),
+
+ 'store' => env('MODEL_CACHE_STORE', 'array'),
+
+];
diff --git a/config/livewire.php b/config/livewire.php
new file mode 100644
index 00000000..8033a556
--- /dev/null
+++ b/config/livewire.php
@@ -0,0 +1,159 @@
+ 'App\\Http\\Livewire',
+
+ /*
+ |---------------------------------------------------------------------------
+ | View Path
+ |---------------------------------------------------------------------------
+ |
+ | This value is used to specify where Livewire component Blade templates are
+ | stored when running file creation commands like `artisan make:livewire`.
+ | It is also used if you choose to omit a component's render() method.
+ |
+ */
+
+ 'view_path' => resource_path('views/livewire'),
+
+ /*
+ |---------------------------------------------------------------------------
+ | Layout
+ |---------------------------------------------------------------------------
+ | The view that will be used as the layout when rendering a single component
+ | as an entire page via `Route::get('/post/create', CreatePost::class);`.
+ | In this case, the view returned by CreatePost will render into $slot.
+ |
+ */
+
+ 'layout' => 'components.layouts.admin',
+
+ /*
+ |---------------------------------------------------------------------------
+ | Lazy Loading Placeholder
+ |---------------------------------------------------------------------------
+ | Livewire allows you to lazy load components that would otherwise slow down
+ | the initial page load. Every component can have a custom placeholder or
+ | you can define the default placeholder view for all components below.
+ |
+ */
+
+ 'lazy_placeholder' => null,
+
+ /*
+ |---------------------------------------------------------------------------
+ | Temporary File Uploads
+ |---------------------------------------------------------------------------
+ |
+ | Livewire handles file uploads by storing uploads in a temporary directory
+ | before the file is stored permanently. All file uploads are directed to
+ | a global endpoint for temporary storage. You may configure this below:
+ |
+ */
+
+ 'temporary_file_upload' => [
+ 'disk' => null, // Example: 'local', 's3' | Default: 'default'
+ 'rules' => null, // Example: ['file', 'mimes:png,jpg'] | Default: ['required', 'file', 'max:12288'] (12MB)
+ 'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp'
+ 'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1'
+ 'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs...
+ 'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
+ 'mov', 'avi', 'wmv', 'mp3', 'm4a',
+ 'jpg', 'jpeg', 'mpga', 'webp', 'wma',
+ ],
+ 'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated...
+ ],
+
+ /*
+ |---------------------------------------------------------------------------
+ | Render On Redirect
+ |---------------------------------------------------------------------------
+ |
+ | This value determines if Livewire will run a component's `render()` method
+ | after a redirect has been triggered using something like `redirect(...)`
+ | Setting this to true will render the view once more before redirecting
+ |
+ */
+
+ 'render_on_redirect' => false,
+/*
+ |---------------------------------------------------------------------------
+ | Eloquent Model Binding
+ |---------------------------------------------------------------------------
+ |
+ | Previous versions of Livewire supported binding directly to eloquent model
+ | properties using wire:model by default. However, this behavior has been
+ | deemed too "magical" and has therefore been put under a feature flag.
+ |
+ */
+
+ 'legacy_model_binding' => false,
+
+ /*
+ |---------------------------------------------------------------------------
+ | Auto-inject Frontend Assets
+ |---------------------------------------------------------------------------
+ |
+ | By default, Livewire automatically injects its JavaScript and CSS into the
+ |
and