diff --git a/lib/data/models/company_model.dart b/lib/data/models/company_model.dart index 6dad8b14a..24f05f07b 100644 --- a/lib/data/models/company_model.dart +++ b/lib/data/models/company_model.dart @@ -118,6 +118,8 @@ abstract class CompanyEntity extends Object stockNotificationThreshold: 0, stockNotification: true, invoiceTaskLock: false, + convertPaymentCurrency: false, + convertExpenseCurrency: false, groups: BuiltList(), taxRates: BuiltList(), taskStatuses: BuiltList(), @@ -296,6 +298,12 @@ abstract class CompanyEntity extends Object @BuiltValueField(wireName: 'invoice_task_lock') bool get invoiceTaskLock; + @BuiltValueField(wireName: 'convert_payment_currency') + bool get convertPaymentCurrency; + + @BuiltValueField(wireName: 'convert_expense_currency') + bool get convertExpenseCurrency; + BuiltList get groups; BuiltList get activities; @@ -706,6 +714,8 @@ abstract class CompanyEntity extends Object ..invoiceTaskLock = false ..matomoUrl = '' ..matomoId = '' + ..convertPaymentCurrency = false + ..convertExpenseCurrency = false ..systemLogs.replace(BuiltList()) ..subscriptions.replace(BuiltList()) ..recurringExpenses.replace(BuiltList()) diff --git a/lib/data/models/company_model.g.dart b/lib/data/models/company_model.g.dart index 853b5a979..6bf848dcd 100644 --- a/lib/data/models/company_model.g.dart +++ b/lib/data/models/company_model.g.dart @@ -167,6 +167,12 @@ class _$CompanyEntitySerializer implements StructuredSerializer { 'invoice_task_lock', serializers.serialize(object.invoiceTaskLock, specifiedType: const FullType(bool)), + 'convert_payment_currency', + serializers.serialize(object.convertPaymentCurrency, + specifiedType: const FullType(bool)), + 'convert_expense_currency', + serializers.serialize(object.convertExpenseCurrency, + specifiedType: const FullType(bool)), 'groups', serializers.serialize(object.groups, specifiedType: @@ -594,6 +600,14 @@ class _$CompanyEntitySerializer implements StructuredSerializer { result.invoiceTaskLock = serializers.deserialize(value, specifiedType: const FullType(bool)) as bool; break; + case 'convert_payment_currency': + result.convertPaymentCurrency = serializers.deserialize(value, + specifiedType: const FullType(bool)) as bool; + break; + case 'convert_expense_currency': + result.convertExpenseCurrency = serializers.deserialize(value, + specifiedType: const FullType(bool)) as bool; + break; case 'groups': result.groups.replace(serializers.deserialize(value, specifiedType: const FullType( @@ -1661,6 +1675,10 @@ class _$CompanyEntity extends CompanyEntity { @override final bool invoiceTaskLock; @override + final bool convertPaymentCurrency; + @override + final bool convertExpenseCurrency; + @override final BuiltList groups; @override final BuiltList activities; @@ -1829,6 +1847,8 @@ class _$CompanyEntity extends CompanyEntity { this.stockNotificationThreshold, this.stockNotification, this.invoiceTaskLock, + this.convertPaymentCurrency, + this.convertExpenseCurrency, this.groups, this.activities, this.taxRates, @@ -1976,6 +1996,10 @@ class _$CompanyEntity extends CompanyEntity { stockNotification, 'CompanyEntity', 'stockNotification'); BuiltValueNullFieldError.checkNotNull( invoiceTaskLock, 'CompanyEntity', 'invoiceTaskLock'); + BuiltValueNullFieldError.checkNotNull( + convertPaymentCurrency, 'CompanyEntity', 'convertPaymentCurrency'); + BuiltValueNullFieldError.checkNotNull( + convertExpenseCurrency, 'CompanyEntity', 'convertExpenseCurrency'); BuiltValueNullFieldError.checkNotNull(groups, 'CompanyEntity', 'groups'); BuiltValueNullFieldError.checkNotNull( activities, 'CompanyEntity', 'activities'); @@ -2133,6 +2157,8 @@ class _$CompanyEntity extends CompanyEntity { stockNotificationThreshold == other.stockNotificationThreshold && stockNotification == other.stockNotification && invoiceTaskLock == other.invoiceTaskLock && + convertPaymentCurrency == other.convertPaymentCurrency && + convertExpenseCurrency == other.convertExpenseCurrency && groups == other.groups && activities == other.activities && taxRates == other.taxRates && @@ -2216,7 +2242,7 @@ class _$CompanyEntity extends CompanyEntity { $jc( $jc( $jc( - $jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, enableCustomSurchargeTaxes1.hashCode), enableCustomSurchargeTaxes2.hashCode), enableCustomSurchargeTaxes3.hashCode), enableCustomSurchargeTaxes4.hashCode), sizeId.hashCode), industryId.hashCode), subdomain.hashCode), portalMode.hashCode), portalDomain.hashCode), updateProducts.hashCode), convertProductExchangeRate.hashCode), convertRateToClient.hashCode), fillProducts.hashCode), enableProductCost.hashCode), enableProductQuantity.hashCode), enableProductDiscount.hashCode), defaultTaskIsDateBased.hashCode), defaultQuantity.hashCode), showProductDetails.hashCode), clientCanRegister.hashCode), isLarge.hashCode), isDisabled.hashCode), enableShopApi.hashCode), companyKey.hashCode), firstDayOfWeek.hashCode), firstMonthOfYear.hashCode), numberOfInvoiceTaxRates.hashCode), numberOfItemTaxRates.hashCode), numberOfExpenseTaxRates.hashCode), expenseInclusiveTaxes.hashCode), sessionTimeout.hashCode), passwordTimeout.hashCode), oauthPasswordRequired.hashCode), markdownEnabled.hashCode), markdownEmailEnabled.hashCode), useCommaAsDecimalPlace.hashCode), reportIncludeDrafts.hashCode), reportIncludeDeleted.hashCode), useQuoteTermsOnConversion.hashCode), enableApplyingPayments.hashCode), trackInventory.hashCode), stockNotificationThreshold.hashCode), stockNotification.hashCode), invoiceTaskLock.hashCode), groups.hashCode), activities.hashCode), taxRates.hashCode), taskStatuses.hashCode), taskStatusMap.hashCode), companyGateways.hashCode), expenseCategories.hashCode), users.hashCode), clients.hashCode), products.hashCode), invoices.hashCode), recurringInvoices.hashCode), recurringExpenses.hashCode), payments.hashCode), quotes.hashCode), credits.hashCode), purchaseOrders.hashCode), bankAccounts.hashCode), transactions.hashCode), transactionRules.hashCode), tasks.hashCode), projects.hashCode), expenses.hashCode), vendors.hashCode), designs.hashCode), documents.hashCode), tokens.hashCode), webhooks.hashCode), subscriptions.hashCode), paymentTerms.hashCode), systemLogs.hashCode), clientRegistrationFields.hashCode), customFields.hashCode), slackWebhookUrl.hashCode), googleAnalyticsKey.hashCode), matomoUrl.hashCode), matomoId.hashCode), markExpensesInvoiceable.hashCode), markExpensesPaid.hashCode), invoiceExpenseDocuments.hashCode), invoiceTaskDocuments.hashCode), + $jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, enableCustomSurchargeTaxes1.hashCode), enableCustomSurchargeTaxes2.hashCode), enableCustomSurchargeTaxes3.hashCode), enableCustomSurchargeTaxes4.hashCode), sizeId.hashCode), industryId.hashCode), subdomain.hashCode), portalMode.hashCode), portalDomain.hashCode), updateProducts.hashCode), convertProductExchangeRate.hashCode), convertRateToClient.hashCode), fillProducts.hashCode), enableProductCost.hashCode), enableProductQuantity.hashCode), enableProductDiscount.hashCode), defaultTaskIsDateBased.hashCode), defaultQuantity.hashCode), showProductDetails.hashCode), clientCanRegister.hashCode), isLarge.hashCode), isDisabled.hashCode), enableShopApi.hashCode), companyKey.hashCode), firstDayOfWeek.hashCode), firstMonthOfYear.hashCode), numberOfInvoiceTaxRates.hashCode), numberOfItemTaxRates.hashCode), numberOfExpenseTaxRates.hashCode), expenseInclusiveTaxes.hashCode), sessionTimeout.hashCode), passwordTimeout.hashCode), oauthPasswordRequired.hashCode), markdownEnabled.hashCode), markdownEmailEnabled.hashCode), useCommaAsDecimalPlace.hashCode), reportIncludeDrafts.hashCode), reportIncludeDeleted.hashCode), useQuoteTermsOnConversion.hashCode), enableApplyingPayments.hashCode), trackInventory.hashCode), stockNotificationThreshold.hashCode), stockNotification.hashCode), invoiceTaskLock.hashCode), convertPaymentCurrency.hashCode), convertExpenseCurrency.hashCode), groups.hashCode), activities.hashCode), taxRates.hashCode), taskStatuses.hashCode), taskStatusMap.hashCode), companyGateways.hashCode), expenseCategories.hashCode), users.hashCode), clients.hashCode), products.hashCode), invoices.hashCode), recurringInvoices.hashCode), recurringExpenses.hashCode), payments.hashCode), quotes.hashCode), credits.hashCode), purchaseOrders.hashCode), bankAccounts.hashCode), transactions.hashCode), transactionRules.hashCode), tasks.hashCode), projects.hashCode), expenses.hashCode), vendors.hashCode), designs.hashCode), documents.hashCode), tokens.hashCode), webhooks.hashCode), subscriptions.hashCode), paymentTerms.hashCode), systemLogs.hashCode), clientRegistrationFields.hashCode), customFields.hashCode), slackWebhookUrl.hashCode), googleAnalyticsKey.hashCode), matomoUrl.hashCode), matomoId.hashCode), markExpensesInvoiceable.hashCode), markExpensesPaid.hashCode), invoiceExpenseDocuments.hashCode), invoiceTaskDocuments.hashCode), invoiceTaskTimelog.hashCode), invoiceTaskDatelog.hashCode), invoiceTaskProject.hashCode), @@ -2285,6 +2311,8 @@ class _$CompanyEntity extends CompanyEntity { ..add('stockNotificationThreshold', stockNotificationThreshold) ..add('stockNotification', stockNotification) ..add('invoiceTaskLock', invoiceTaskLock) + ..add('convertPaymentCurrency', convertPaymentCurrency) + ..add('convertExpenseCurrency', convertExpenseCurrency) ..add('groups', groups) ..add('activities', activities) ..add('taxRates', taxRates) @@ -2564,6 +2592,16 @@ class CompanyEntityBuilder set invoiceTaskLock(bool invoiceTaskLock) => _$this._invoiceTaskLock = invoiceTaskLock; + bool _convertPaymentCurrency; + bool get convertPaymentCurrency => _$this._convertPaymentCurrency; + set convertPaymentCurrency(bool convertPaymentCurrency) => + _$this._convertPaymentCurrency = convertPaymentCurrency; + + bool _convertExpenseCurrency; + bool get convertExpenseCurrency => _$this._convertExpenseCurrency; + set convertExpenseCurrency(bool convertExpenseCurrency) => + _$this._convertExpenseCurrency = convertExpenseCurrency; + ListBuilder _groups; ListBuilder get groups => _$this._groups ??= new ListBuilder(); @@ -2932,6 +2970,8 @@ class CompanyEntityBuilder _stockNotificationThreshold = $v.stockNotificationThreshold; _stockNotification = $v.stockNotification; _invoiceTaskLock = $v.invoiceTaskLock; + _convertPaymentCurrency = $v.convertPaymentCurrency; + _convertExpenseCurrency = $v.convertExpenseCurrency; _groups = $v.groups.toBuilder(); _activities = $v.activities.toBuilder(); _taxRates = $v.taxRates.toBuilder(); @@ -3072,6 +3112,8 @@ class CompanyEntityBuilder stockNotificationThreshold: BuiltValueNullFieldError.checkNotNull(stockNotificationThreshold, 'CompanyEntity', 'stockNotificationThreshold'), stockNotification: BuiltValueNullFieldError.checkNotNull(stockNotification, 'CompanyEntity', 'stockNotification'), invoiceTaskLock: BuiltValueNullFieldError.checkNotNull(invoiceTaskLock, 'CompanyEntity', 'invoiceTaskLock'), + convertPaymentCurrency: BuiltValueNullFieldError.checkNotNull(convertPaymentCurrency, 'CompanyEntity', 'convertPaymentCurrency'), + convertExpenseCurrency: BuiltValueNullFieldError.checkNotNull(convertExpenseCurrency, 'CompanyEntity', 'convertExpenseCurrency'), groups: groups.build(), activities: activities.build(), taxRates: taxRates.build(), diff --git a/lib/ui/settings/expense_settings.dart b/lib/ui/settings/expense_settings.dart index 10497beca..6060955ce 100644 --- a/lib/ui/settings/expense_settings.dart +++ b/lib/ui/settings/expense_settings.dart @@ -70,6 +70,14 @@ class _ExpenseSettingsState extends State { onChanged: (value) => viewModel.onCompanyChanged( company.rebuild((b) => b..markExpensesPaid = value)), ), + SwitchListTile( + activeColor: Theme.of(context).colorScheme.secondary, + title: Text(localization.convertCurrencyHelp), + value: company.convertExpenseCurrency ?? false, + subtitle: Text(localization.convertExpenseCurrencyHelp), + onChanged: (value) => viewModel.onCompanyChanged( + company.rebuild((b) => b..convertExpenseCurrency = value)), + ), SwitchListTile( activeColor: Theme.of(context).colorScheme.secondary, title: Text(localization.addDocumentsToInvoice), diff --git a/lib/ui/settings/payment_settings.dart b/lib/ui/settings/payment_settings.dart index a8bed5a0d..621966a9e 100644 --- a/lib/ui/settings/payment_settings.dart +++ b/lib/ui/settings/payment_settings.dart @@ -171,7 +171,7 @@ class _PaymentSettingsState extends State { ), SizedBox(height: 8), FormCard(children: [ - if (!state.uiState.settingsUIState.isFiltered) + if (!state.uiState.settingsUIState.isFiltered) ...[ BoolDropdownButton( label: localization.enableApplyingPaymentsLater, value: company.enableApplyingPayments, @@ -179,6 +179,14 @@ class _PaymentSettingsState extends State { onChanged: (value) => viewModel.onCompanyChanged( company.rebuild((b) => b..enableApplyingPayments = value)), ), + BoolDropdownButton( + label: localization.convertCurrency, + value: company.convertPaymentCurrency, + helpLabel: localization.convertPaymentCurrencyHelp, + onChanged: (value) => viewModel.onCompanyChanged( + company.rebuild((b) => b..convertPaymentCurrency = value)), + ), + ], BoolDropdownButton( label: localization.allowOverPayment, value: settings.clientPortalAllowOverPayment, diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index 52bff8817..bd85941b9 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -16,6 +16,10 @@ mixin LocalizationsProvider on LocaleCodeAware { static final Map> _localizedValues = { 'en': { // STARTER: lang key - do not remove comment + 'convert_payment_currency_help': + 'Set an exchange rate when entering a manual payment', + 'convert_expense_currency_help': + 'Set an exchange rate when creating an expense', 'matomo_url': 'Matomo URL', 'matomo_id': 'Matomo Id', 'action_add_to_invoice': 'Add To Invoice', @@ -92367,6 +92371,14 @@ mixin LocalizationsProvider on LocaleCodeAware { _localizedValues[localeCode]['matomo_id'] ?? _localizedValues['en']['matomo_id']; + String get convertPaymentCurrencyHelp => + _localizedValues[localeCode]['convert_payment_currency_help'] ?? + _localizedValues['en']['convert_payment_currency_help']; + + String get convertExpenseCurrencyHelp => + _localizedValues[localeCode]['convert_expense_currency_help'] ?? + _localizedValues['en']['convert_expense_currency_help']; + // STARTER: lang field - do not remove comment String lookup(String key) {