mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-23 13:14:08 +00:00
Exchange rate providers are now pluggable via the module Registry. The four built-in drivers (currency_converter, currency_freak, currency_layer, open_exchange_rate) move from a static config array into App\\Providers\\DriverRegistryProvider, which calls Registry::registerExchangeRateDriver() for each during app boot with metadata the frontend needs: label (i18n key), website (help-text URL), and config_fields (schema for driver-specific driver_config JSON).
The Currency Converter's server-type selector and dedicated URL field — previously hardcoded in ExchangeRateProviderModal.vue — are now just another config_fields entry with a visible_when rule that shows the URL input only when type=DEDICATED. Any module that wants to ship a custom driver gets the same treatment for free: declare config_fields in the registration, and the host app's modal renders them automatically.
ExchangeRateDriverFactory::make() falls back to Registry::driverMeta() when a name isn't in the local built-in map, and availableDrivers() merges both sources. ConfigController handles the exchange_rate_drivers key specially by mapping Registry::allDrivers('exchange_rate') to enriched option objects, so the config-file route still works for every other key. The static exchange_rate_drivers + currency_converter_servers arrays in config/invoiceshelf.php are deleted.
Unit tests cover the new Registry::register/flushDrivers, the factory merging built-ins with Registry-contributed drivers, and the factory rejecting unknown names. A feature test exercises the end-to-end /api/v1/config?key=exchange_rate_drivers response shape.
NOTE: this commit depends on invoiceshelf/modules package commit e44d951 which adds the Registry driver API. The package needs to be released and pinned in composer.json before a fresh composer install on this commit will work.
572 lines
18 KiB
PHP
572 lines
18 KiB
PHP
<?php
|
|
|
|
use App\Models\Customer;
|
|
use App\Models\CustomField;
|
|
use App\Models\Estimate;
|
|
use App\Models\ExchangeRateProvider;
|
|
use App\Models\Expense;
|
|
use App\Models\Invoice;
|
|
use App\Models\Item;
|
|
use App\Models\Note;
|
|
use App\Models\Payment;
|
|
use App\Models\TaxType;
|
|
|
|
return [
|
|
/*
|
|
* Minimum php version.
|
|
*/
|
|
'min_php_version' => '8.4.0',
|
|
|
|
/*
|
|
* Minimum mysql version.
|
|
*/
|
|
|
|
'min_mysql_version' => '5.7.7',
|
|
|
|
/*
|
|
* Minimum mariadb version.
|
|
*/
|
|
|
|
'min_mariadb_version' => '10.2.7',
|
|
|
|
/*
|
|
* Minimum pgsql version.
|
|
*/
|
|
|
|
'min_pgsql_version' => '9.2.0',
|
|
|
|
/*
|
|
* Minimum sqlite version.
|
|
*/
|
|
|
|
'min_sqlite_version' => '3.35.0',
|
|
|
|
/*
|
|
* Marketplace and updater base URL.
|
|
*
|
|
* The marketplace client (App\Services\Module\ModuleInstaller) and the
|
|
* updater (App\Services\Update\Updater) both build their HTTP client base
|
|
* URI from this value via App\Traits\SiteApi::getRemote(). Override via
|
|
* INVOICESHELF_BASE_URL in .env to point a self-hosted instance or local
|
|
* dev environment at a non-production marketplace (e.g. a local checkout
|
|
* of the invoiceshelf/website repo).
|
|
*/
|
|
'base_url' => env('INVOICESHELF_BASE_URL', 'https://invoiceshelf.com'),
|
|
|
|
/*
|
|
* Paths protected from cleanup during updates.
|
|
* The updater will never delete files under these prefixes.
|
|
*/
|
|
'update_protected_paths' => [
|
|
'.env',
|
|
'storage',
|
|
'vendor',
|
|
'node_modules',
|
|
'Modules',
|
|
'public/storage',
|
|
'.git',
|
|
'bootstrap/cache',
|
|
'manifest.json',
|
|
'android',
|
|
'ios',
|
|
'mobile',
|
|
],
|
|
|
|
/*
|
|
* List of languages supported by InvoiceShelf.
|
|
*/
|
|
'languages' => [
|
|
['code' => 'ar', 'name' => 'Arabic'],
|
|
['code' => 'bg', 'name' => 'Bulgarian'],
|
|
['code' => 'zh_CN', 'name' => 'Chinese (Simplified)'],
|
|
['code' => 'zh', 'name' => 'Chinese (Traditional)'],
|
|
['code' => 'hr', 'name' => 'Croatian'],
|
|
['code' => 'cs', 'name' => 'Czech'],
|
|
['code' => 'nl', 'name' => 'Dutch'],
|
|
['code' => 'en', 'name' => 'English'],
|
|
['code' => 'fi', 'name' => 'Finnish'],
|
|
['code' => 'fr', 'name' => 'French'],
|
|
['code' => 'de', 'name' => 'German'],
|
|
['code' => 'el', 'name' => 'Greek'],
|
|
['code' => 'he', 'name' => 'עברית'],
|
|
['code' => 'hi', 'name' => 'Hindi'],
|
|
['code' => 'id', 'name' => 'Indonesian'],
|
|
['code' => 'it', 'name' => 'Italian'],
|
|
['code' => 'ja', 'name' => 'Japanese'],
|
|
['code' => 'ko', 'name' => 'Korean'],
|
|
['code' => 'lv', 'name' => 'Latvian'],
|
|
['code' => 'lt', 'name' => 'Lithuanian'],
|
|
['code' => 'mk', 'name' => 'Macedonian'],
|
|
['code' => 'no', 'name' => 'Norwegian'],
|
|
['code' => 'fa', 'name' => 'Persian'],
|
|
['code' => 'pl', 'name' => 'Polish'],
|
|
['code' => 'pt', 'name' => 'Portuguese'],
|
|
['code' => 'pt_BR', 'name' => 'Portuguese (Brazilian)'],
|
|
['code' => 'ro', 'name' => 'Romanian'],
|
|
['code' => 'ru', 'name' => 'Russian'],
|
|
['code' => 'sr', 'name' => 'Serbian Latin'],
|
|
['code' => 'sk', 'name' => 'Slovak'],
|
|
['code' => 'sl', 'name' => 'Slovenian'],
|
|
['code' => 'es', 'name' => 'Spanish'],
|
|
['code' => 'sv', 'name' => 'Svenska'],
|
|
['code' => 'th', 'name' => 'ไทย'],
|
|
['code' => 'vi', 'name' => 'Tiếng Việt'],
|
|
['code' => 'tr', 'name' => 'Turkish'],
|
|
['code' => 'uk', 'name' => 'Ukrainian'],
|
|
['code' => 'ur', 'name' => 'اردو'],
|
|
],
|
|
|
|
/*
|
|
* List of Fiscal Years
|
|
*/
|
|
'fiscal_years' => [
|
|
['key' => 'settings.preferences.fiscal_years.january_december', 'value' => '1-12'],
|
|
['key' => 'settings.preferences.fiscal_years.february_january', 'value' => '2-1'],
|
|
['key' => 'settings.preferences.fiscal_years.march_february', 'value' => '3-2'],
|
|
['key' => 'settings.preferences.fiscal_years.april_march', 'value' => '4-3'],
|
|
['key' => 'settings.preferences.fiscal_years.may_april', 'value' => '5-4'],
|
|
['key' => 'settings.preferences.fiscal_years.june_may', 'value' => '6-5'],
|
|
['key' => 'settings.preferences.fiscal_years.july_june', 'value' => '7-6'],
|
|
['key' => 'settings.preferences.fiscal_years.august_july', 'value' => '8-7'],
|
|
['key' => 'settings.preferences.fiscal_years.september_august', 'value' => '9-8'],
|
|
['key' => 'settings.preferences.fiscal_years.october_september', 'value' => '10-9'],
|
|
['key' => 'settings.preferences.fiscal_years.november_october', 'value' => '11-10'],
|
|
['key' => 'settings.preferences.fiscal_years.december_november', 'value' => '12-11'],
|
|
],
|
|
|
|
/*
|
|
* List of convert estimate options
|
|
*/
|
|
'convert_estimate_options' => [
|
|
['key' => 'settings.preferences.no_action', 'value' => 'no_action'],
|
|
['key' => 'settings.preferences.delete_estimate', 'value' => 'delete_estimate'],
|
|
['key' => 'settings.preferences.mark_estimate_as_accepted', 'value' => 'mark_estimate_as_accepted'],
|
|
],
|
|
|
|
/*
|
|
* List of retrospective edits
|
|
*/
|
|
'retrospective_edits' => [
|
|
['key' => 'settings.preferences.allow', 'value' => 'allow'],
|
|
['key' => 'settings.preferences.disable_on_invoice_partial_paid', 'value' => 'disable_on_invoice_partial_paid'],
|
|
['key' => 'settings.preferences.disable_on_invoice_paid', 'value' => 'disable_on_invoice_paid'],
|
|
['key' => 'settings.preferences.disable_on_invoice_sent', 'value' => 'disable_on_invoice_sent'],
|
|
],
|
|
|
|
/*
|
|
* List of setting menu
|
|
*/
|
|
'setting_menu' => [
|
|
[
|
|
'title' => 'settings.menu_title.company_information',
|
|
'group' => '',
|
|
'name' => 'Company information',
|
|
'link' => '/admin/settings/company-info',
|
|
'icon' => 'BuildingOfficeIcon',
|
|
'owner_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'settings.menu_title.preferences',
|
|
'group' => '',
|
|
'name' => 'Preferences',
|
|
'link' => '/admin/settings/preferences',
|
|
'icon' => 'CogIcon',
|
|
'owner_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'settings.menu_title.customization',
|
|
'group' => '',
|
|
'name' => 'Customization',
|
|
'link' => '/admin/settings/customization',
|
|
'icon' => 'PencilSquareIcon',
|
|
'owner_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'settings.roles.title',
|
|
'group' => '',
|
|
'name' => 'Company Roles',
|
|
'link' => '/admin/settings/roles',
|
|
'icon' => 'UserGroupIcon',
|
|
'owner_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'settings.menu_title.exchange_rate',
|
|
'group' => '',
|
|
'name' => 'Exchange Rate Provider',
|
|
'link' => '/admin/settings/exchange-rate',
|
|
'icon' => 'BanknotesIcon',
|
|
'owner_only' => false,
|
|
'ability' => 'view-exchange-rate-provider',
|
|
'model' => ExchangeRateProvider::class,
|
|
],
|
|
[
|
|
'title' => 'settings.menu_title.notifications',
|
|
'group' => '',
|
|
'name' => 'Notifications',
|
|
'link' => '/admin/settings/notifications',
|
|
'icon' => 'BellIcon',
|
|
'owner_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'settings.menu_title.tax_types',
|
|
'group' => '',
|
|
'name' => 'Tax types',
|
|
'link' => '/admin/settings/tax-types',
|
|
'icon' => 'CheckCircleIcon',
|
|
'owner_only' => false,
|
|
'ability' => 'view-tax-type',
|
|
'model' => TaxType::class,
|
|
],
|
|
[
|
|
'title' => 'settings.menu_title.payment_modes',
|
|
'group' => '',
|
|
'name' => 'Payment modes',
|
|
'link' => '/admin/settings/payment-modes',
|
|
'icon' => 'CreditCardIcon',
|
|
'owner_only' => false,
|
|
'ability' => 'view-payment',
|
|
'model' => Payment::class,
|
|
],
|
|
[
|
|
'title' => 'settings.menu_title.custom_fields',
|
|
'group' => '',
|
|
'name' => 'Custom fields',
|
|
'link' => '/admin/settings/custom-fields',
|
|
'icon' => 'CubeIcon',
|
|
'owner_only' => false,
|
|
'ability' => 'view-custom-field',
|
|
'model' => CustomField::class,
|
|
],
|
|
[
|
|
'title' => 'settings.menu_title.notes',
|
|
'group' => '',
|
|
'name' => 'Notes',
|
|
'link' => '/admin/settings/notes',
|
|
'icon' => 'ClipboardDocumentCheckIcon',
|
|
'owner_only' => false,
|
|
'ability' => 'view-all-notes',
|
|
'model' => Note::class,
|
|
],
|
|
[
|
|
'title' => 'settings.menu_title.expense_category',
|
|
'group' => '',
|
|
'name' => 'Expense Category',
|
|
'link' => '/admin/settings/expense-categories',
|
|
'icon' => 'ClipboardDocumentListIcon',
|
|
'owner_only' => false,
|
|
'ability' => 'view-expense',
|
|
'model' => Expense::class,
|
|
],
|
|
[
|
|
'title' => 'settings.mail.company_mail_config',
|
|
'group' => '',
|
|
'name' => 'Mail Configuration',
|
|
'link' => '/admin/settings/mail-config',
|
|
'icon' => 'EnvelopeIcon',
|
|
'owner_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
],
|
|
|
|
/*
|
|
* List of main menu
|
|
*/
|
|
'main_menu' => [
|
|
[
|
|
'title' => 'navigation.dashboard',
|
|
'group' => 'main',
|
|
'group_label' => '',
|
|
'priority' => 10,
|
|
'link' => '/admin/dashboard',
|
|
'icon' => 'HomeIcon',
|
|
'name' => 'Dashboard',
|
|
'owner_only' => false,
|
|
'ability' => 'dashboard',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.customers',
|
|
'group' => 'main',
|
|
'group_label' => '',
|
|
'priority' => 20,
|
|
'link' => '/admin/customers',
|
|
'icon' => 'UserIcon',
|
|
'name' => 'Customers',
|
|
'owner_only' => false,
|
|
'ability' => 'view-customer',
|
|
'model' => Customer::class,
|
|
],
|
|
[
|
|
'title' => 'navigation.items',
|
|
'group' => 'main',
|
|
'group_label' => '',
|
|
'priority' => 30,
|
|
'link' => '/admin/items',
|
|
'icon' => 'StarIcon',
|
|
'name' => 'Items',
|
|
'owner_only' => false,
|
|
'ability' => 'view-item',
|
|
'model' => Item::class,
|
|
],
|
|
[
|
|
'title' => 'navigation.estimates',
|
|
'group' => 'documents',
|
|
'group_label' => 'navigation.documents',
|
|
'priority' => 10,
|
|
'link' => '/admin/estimates',
|
|
'icon' => 'DocumentIcon',
|
|
'name' => 'Estimates',
|
|
'owner_only' => false,
|
|
'ability' => 'view-estimate',
|
|
'model' => Estimate::class,
|
|
],
|
|
[
|
|
'title' => 'navigation.invoices',
|
|
'group' => 'documents',
|
|
'group_label' => 'navigation.documents',
|
|
'priority' => 20,
|
|
'link' => '/admin/invoices',
|
|
'icon' => 'DocumentTextIcon',
|
|
'name' => 'Invoices',
|
|
'owner_only' => false,
|
|
'ability' => 'view-invoice',
|
|
'model' => Invoice::class,
|
|
],
|
|
[
|
|
'title' => 'navigation.payments',
|
|
'group' => 'documents',
|
|
'group_label' => 'navigation.documents',
|
|
'priority' => 30,
|
|
'link' => '/admin/payments',
|
|
'icon' => 'CreditCardIcon',
|
|
'name' => 'Payments',
|
|
'owner_only' => false,
|
|
'ability' => 'view-payment',
|
|
'model' => Payment::class,
|
|
],
|
|
[
|
|
'title' => 'navigation.expenses',
|
|
'group' => 'documents',
|
|
'group_label' => 'navigation.documents',
|
|
'priority' => 40,
|
|
'link' => '/admin/expenses',
|
|
'icon' => 'CalculatorIcon',
|
|
'name' => 'Expenses',
|
|
'owner_only' => false,
|
|
'ability' => 'view-expense',
|
|
'model' => Expense::class,
|
|
],
|
|
[
|
|
'title' => 'navigation.modules',
|
|
'group' => 'admin',
|
|
'group_label' => 'navigation.admin',
|
|
'priority' => 10,
|
|
'link' => '/admin/modules',
|
|
'icon' => 'PuzzlePieceIcon',
|
|
'name' => 'Modules',
|
|
'owner_only' => false,
|
|
'ability' => 'manage modules',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.members',
|
|
'group' => 'admin',
|
|
'group_label' => 'navigation.admin',
|
|
'priority' => 20,
|
|
'link' => '/admin/members',
|
|
'icon' => 'UsersIcon',
|
|
'name' => 'Members',
|
|
'owner_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.reports',
|
|
'group' => 'admin',
|
|
'group_label' => 'navigation.admin',
|
|
'priority' => 30,
|
|
'link' => '/admin/reports',
|
|
'icon' => 'ChartBarIcon',
|
|
'name' => 'Reports',
|
|
'owner_only' => false,
|
|
'ability' => 'view-financial-reports',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.settings',
|
|
'group' => 'admin',
|
|
'group_label' => 'navigation.admin',
|
|
'priority' => 40,
|
|
'link' => '/admin/settings',
|
|
'icon' => 'CogIcon',
|
|
'name' => 'Settings',
|
|
'owner_only' => false,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
],
|
|
|
|
/*
|
|
* List of admin mode menu (super admin only)
|
|
*/
|
|
'admin_menu' => [
|
|
[
|
|
'title' => 'navigation.dashboard',
|
|
'group' => 1,
|
|
'link' => '/admin/administration/dashboard',
|
|
'icon' => 'ServerIcon',
|
|
'name' => 'AdminDashboard',
|
|
'owner_only' => false,
|
|
'super_admin_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.companies',
|
|
'group' => 1,
|
|
'link' => '/admin/administration/companies',
|
|
'icon' => 'BuildingOfficeIcon',
|
|
'name' => 'AdminCompanies',
|
|
'owner_only' => false,
|
|
'super_admin_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.all_users',
|
|
'group' => 1,
|
|
'link' => '/admin/administration/users',
|
|
'icon' => 'UsersIcon',
|
|
'name' => 'AdminUsers',
|
|
'owner_only' => false,
|
|
'super_admin_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.modules',
|
|
'group' => 1,
|
|
'link' => '/admin/administration/modules',
|
|
'icon' => 'PuzzlePieceIcon',
|
|
'name' => 'AdminModules',
|
|
'owner_only' => false,
|
|
'super_admin_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.settings',
|
|
'group' => 1,
|
|
'link' => '/admin/administration/settings/mail-configuration',
|
|
'icon' => 'CogIcon',
|
|
'name' => 'AdminSettings',
|
|
'owner_only' => false,
|
|
'super_admin_only' => true,
|
|
'ability' => '',
|
|
'model' => '',
|
|
],
|
|
],
|
|
|
|
/*
|
|
* List of customer portal menu
|
|
*/
|
|
'customer_menu' => [
|
|
[
|
|
'title' => 'navigation.dashboard',
|
|
'link' => '/customer/dashboard',
|
|
'icon' => '',
|
|
'name' => '',
|
|
'ability' => '',
|
|
'owner_only' => false,
|
|
'group' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.invoices',
|
|
'link' => '/customer/invoices',
|
|
'icon' => '',
|
|
'name' => '',
|
|
'ability' => '',
|
|
'owner_only' => false,
|
|
'group' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.estimates',
|
|
'link' => '/customer/estimates',
|
|
'icon' => '',
|
|
'name' => '',
|
|
'owner_only' => false,
|
|
'ability' => '',
|
|
'group' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.payments',
|
|
'link' => '/customer/payments',
|
|
'icon' => '',
|
|
'name' => '',
|
|
'owner_only' => false,
|
|
'ability' => '',
|
|
'group' => '',
|
|
'model' => '',
|
|
],
|
|
[
|
|
'title' => 'navigation.settings',
|
|
'link' => '/customer/settings',
|
|
'icon' => '',
|
|
'name' => '',
|
|
'owner_only' => false,
|
|
'ability' => '',
|
|
'group' => '',
|
|
'model' => '',
|
|
],
|
|
],
|
|
|
|
/*
|
|
* List of recurring invoice status
|
|
*/
|
|
'recurring_invoice_status' => [
|
|
'create_status' => [
|
|
['key' => 'settings.preferences.active', 'value' => 'ACTIVE'],
|
|
['key' => 'settings.preferences.on_hold', 'value' => 'ON_HOLD'],
|
|
],
|
|
'update_status' => [
|
|
['key' => 'settings.preferences.active', 'value' => 'ACTIVE'],
|
|
['key' => 'settings.preferences.on_hold', 'value' => 'ON_HOLD'],
|
|
['key' => 'settings.preferences.completed', 'value' => 'COMPLETED'],
|
|
],
|
|
],
|
|
|
|
/*
|
|
* Exchange rate drivers and Currency Converter server options used to live here as
|
|
* static arrays. Both have moved into the module Registry — built-in drivers are
|
|
* registered by App\Providers\DriverRegistryProvider, and custom drivers can be
|
|
* registered by modules via Registry::registerExchangeRateDriver(). The driver
|
|
* list is served to the frontend by ConfigController via the same
|
|
* /api/v1/config?key=exchange_rate_drivers endpoint.
|
|
*/
|
|
|
|
/*
|
|
* List of Custom field supported models
|
|
*/
|
|
'custom_field_models' => [
|
|
'Customer',
|
|
'Estimate',
|
|
'Invoice',
|
|
'Payment',
|
|
'Expense',
|
|
],
|
|
];
|