mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-07-20 07:45:20 +00:00
Fix exchange rate parity across all document types
- Fix exchange-rate service types to match actual backend response shapes (exchangeRate array, activeProvider success/error, used currencies as strings) - Add ExchangeRateConverter to payments, expenses, and recurring invoices - Set currency_id from customer currency in invoice/estimate selectCustomer() - Load globalStore.currencies in ExchangeRateConverter on mount - Pass driver/key/driver_config params to getSupportedCurrencies in provider modal - Fix OpenExchangeRateDriver validateConnection to use base=USD (free plan compat) - Fix checkActiveCurrencies SQLite whereJsonContains with array values - Remove broken currency/companyCurrency props from ExpenseCreateView, use stores - Show base currency equivalent in document line items and totals when exchange rate is active
This commit is contained in:
@@ -36,7 +36,7 @@ class OpenExchangeRateDriver extends ExchangeRateDriver
|
||||
|
||||
public function validateConnection(): array
|
||||
{
|
||||
$url = "{$this->baseUrl}/latest.json?app_id={$this->apiKey}&base=INR&symbols=USD";
|
||||
$url = "{$this->baseUrl}/latest.json?app_id={$this->apiKey}&base=USD&symbols=EUR";
|
||||
$response = Http::get($url)->json();
|
||||
|
||||
if (array_key_exists('error', $response)) {
|
||||
|
||||
@@ -25,17 +25,42 @@ class ExchangeRateProviderService
|
||||
|
||||
public function checkActiveCurrencies($request)
|
||||
{
|
||||
return ExchangeRateProvider::whereJsonContains('currencies', $request->currencies)
|
||||
->where('active', true)
|
||||
->get();
|
||||
$currencies = $request->currencies;
|
||||
|
||||
if (empty($currencies)) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$query = ExchangeRateProvider::where('active', true);
|
||||
|
||||
foreach ($currencies as $currency) {
|
||||
$query->orWhere(function ($q) use ($currency) {
|
||||
$q->where('active', true)
|
||||
->whereJsonContains('currencies', $currency);
|
||||
});
|
||||
}
|
||||
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
public function checkUpdateActiveCurrencies(ExchangeRateProvider $provider, $request)
|
||||
{
|
||||
return ExchangeRateProvider::where('active', $request->active)
|
||||
->where('id', '<>', $provider->id)
|
||||
->whereJsonContains('currencies', $request->currencies)
|
||||
->get();
|
||||
$currencies = $request->currencies;
|
||||
|
||||
if (empty($currencies)) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$query = ExchangeRateProvider::where('id', '<>', $provider->id)
|
||||
->where('active', true);
|
||||
|
||||
$query->where(function ($q) use ($currencies) {
|
||||
foreach ($currencies as $currency) {
|
||||
$q->orWhereJsonContains('currencies', $currency);
|
||||
}
|
||||
});
|
||||
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
public function checkProviderStatus($request)
|
||||
|
||||
@@ -8,15 +8,16 @@ export interface CreateExchangeRateProviderPayload {
|
||||
key: string
|
||||
active?: boolean
|
||||
currencies?: string[]
|
||||
driver_config?: Record<string, string>
|
||||
}
|
||||
|
||||
// Normalized response types (what callers receive)
|
||||
export interface ExchangeRateResponse {
|
||||
exchange_rate: number
|
||||
exchangeRate: number | null
|
||||
}
|
||||
|
||||
export interface ActiveProviderResponse {
|
||||
has_active_provider: boolean
|
||||
exchange_rate: number | null
|
||||
hasActiveProvider: boolean
|
||||
}
|
||||
|
||||
export interface SupportedCurrenciesResponse {
|
||||
@@ -24,7 +25,8 @@ export interface SupportedCurrenciesResponse {
|
||||
}
|
||||
|
||||
export interface UsedCurrenciesResponse {
|
||||
activeUsedCurrencies: Currency[]
|
||||
activeUsedCurrencies: string[]
|
||||
allUsedCurrencies: string[]
|
||||
}
|
||||
|
||||
export interface BulkCurrenciesResponse {
|
||||
@@ -38,8 +40,23 @@ export interface BulkUpdatePayload {
|
||||
}>
|
||||
}
|
||||
|
||||
export interface ConfigOption {
|
||||
key: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface ConfigDriversResponse {
|
||||
exchange_rate_drivers: string[]
|
||||
exchange_rate_drivers: ConfigOption[]
|
||||
}
|
||||
|
||||
export interface ConfigServersResponse {
|
||||
currency_converter_servers: ConfigOption[]
|
||||
}
|
||||
|
||||
export interface SupportedCurrenciesParams {
|
||||
driver: string
|
||||
key: string
|
||||
driver_config?: Record<string, string>
|
||||
}
|
||||
|
||||
export const exchangeRateService = {
|
||||
@@ -73,24 +90,35 @@ export const exchangeRateService = {
|
||||
},
|
||||
|
||||
// Exchange Rates
|
||||
// Backend returns { exchangeRate: [number] } or { error: string }
|
||||
async getRate(currencyId: number): Promise<ExchangeRateResponse> {
|
||||
const { data } = await client.get(`${API.CURRENCIES}/${currencyId}/exchange-rate`)
|
||||
return data
|
||||
const raw = data as Record<string, unknown>
|
||||
|
||||
if (raw.exchangeRate && Array.isArray(raw.exchangeRate)) {
|
||||
return { exchangeRate: Number(raw.exchangeRate[0]) ?? null }
|
||||
}
|
||||
|
||||
return { exchangeRate: null }
|
||||
},
|
||||
|
||||
// Backend returns { success: true, message: "provider_active" } or { error: "no_active_provider" }
|
||||
async getActiveProvider(currencyId: number): Promise<ActiveProviderResponse> {
|
||||
const { data } = await client.get(`${API.CURRENCIES}/${currencyId}/active-provider`)
|
||||
return data
|
||||
const raw = data as Record<string, unknown>
|
||||
|
||||
return { hasActiveProvider: raw.success === true }
|
||||
},
|
||||
|
||||
// Currency lists
|
||||
async getSupportedCurrencies(): Promise<SupportedCurrenciesResponse> {
|
||||
const { data } = await client.get(API.SUPPORTED_CURRENCIES)
|
||||
async getSupportedCurrencies(params: SupportedCurrenciesParams): Promise<SupportedCurrenciesResponse> {
|
||||
const { data } = await client.get(API.SUPPORTED_CURRENCIES, { params })
|
||||
return data
|
||||
},
|
||||
|
||||
async getUsedCurrencies(): Promise<UsedCurrenciesResponse> {
|
||||
const { data } = await client.get(API.USED_CURRENCIES)
|
||||
// Backend returns { activeUsedCurrencies: string[], allUsedCurrencies: string[] }
|
||||
async getUsedCurrencies(params?: { provider_id?: number }): Promise<UsedCurrenciesResponse> {
|
||||
const { data } = await client.get(API.USED_CURRENCIES, { params })
|
||||
return data
|
||||
},
|
||||
|
||||
@@ -105,12 +133,14 @@ export const exchangeRateService = {
|
||||
},
|
||||
|
||||
// Config
|
||||
// Backend returns { exchange_rate_drivers: Array<{ key, value }> }
|
||||
async getDrivers(): Promise<ConfigDriversResponse> {
|
||||
const { data } = await client.get(API.CONFIG, { params: { key: 'exchange_rate_drivers' } })
|
||||
return data
|
||||
},
|
||||
|
||||
async getCurrencyConverterServers(): Promise<Record<string, unknown>> {
|
||||
// Backend returns { currency_converter_servers: Array<{ key, value }> }
|
||||
async getCurrencyConverterServers(): Promise<ConfigServersResponse> {
|
||||
const { data } = await client.get(API.CONFIG, { params: { key: 'currency_converter_servers' } })
|
||||
return data
|
||||
},
|
||||
|
||||
@@ -430,6 +430,9 @@ export const useEstimateStore = defineStore('estimate', {
|
||||
const response = await customerService.get(id)
|
||||
this.newEstimate.customer = response.data as unknown as Customer
|
||||
this.newEstimate.customer_id = response.data.id
|
||||
if (response.data.currency) {
|
||||
this.newEstimate.currency_id = (response.data.currency as { id: number }).id
|
||||
}
|
||||
return response
|
||||
},
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
label="name"
|
||||
track-by="name"
|
||||
:content-loading="isFetchingInitialData"
|
||||
:options="currencies"
|
||||
:options="globalStore.currencies"
|
||||
searchable
|
||||
:can-deselect="false"
|
||||
:placeholder="$t('customers.select_currency')"
|
||||
@@ -140,6 +140,16 @@
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Exchange Rate -->
|
||||
<ExchangeRateConverter
|
||||
:store="expenseStore"
|
||||
store-prop="currentExpense"
|
||||
:v="{ exchange_rate: { $error: false, $errors: [], $touch: () => {} } }"
|
||||
:is-loading="isFetchingInitialData"
|
||||
:is-edit="isEdit"
|
||||
:customer-currency="expenseStore.currentExpense.currency_id"
|
||||
/>
|
||||
|
||||
<!-- Customer -->
|
||||
<BaseInputGroup
|
||||
:content-loading="isFetchingInitialData"
|
||||
@@ -237,24 +247,19 @@ import { ref, computed, onBeforeUnmount } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useExpenseStore } from '../store'
|
||||
import { useGlobalStore } from '../../../../stores/global.store'
|
||||
import { useCompanyStore } from '../../../../stores/company.store'
|
||||
import { ExchangeRateConverter } from '../../../shared/document-form'
|
||||
import type { ExpenseCategory } from '../../../../types/domain/expense'
|
||||
import type { Customer } from '../../../../types/domain/customer'
|
||||
import type { Currency } from '../../../../types/domain/currency'
|
||||
|
||||
interface Props {
|
||||
currencies?: Currency[]
|
||||
companyCurrency?: Currency | null
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
currencies: () => [],
|
||||
companyCurrency: null,
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
const expenseStore = useExpenseStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const companyStore = useCompanyStore()
|
||||
|
||||
const isSaving = ref<boolean>(false)
|
||||
const isFetchingInitialData = ref<boolean>(false)
|
||||
@@ -291,7 +296,7 @@ function onFileInputRemove(): void {
|
||||
}
|
||||
|
||||
function onCurrencyChange(currencyId: number): void {
|
||||
const found = props.currencies.find((c) => c.id === currencyId)
|
||||
const found = globalStore.currencies.find((c: Currency) => c.id === currencyId)
|
||||
expenseStore.currentExpense.selectedCurrency = found ?? null
|
||||
}
|
||||
|
||||
@@ -314,9 +319,12 @@ async function searchCustomer(search: string): Promise<Customer[]> {
|
||||
}
|
||||
|
||||
async function loadData(): Promise<void> {
|
||||
if (!isEdit.value && props.companyCurrency) {
|
||||
expenseStore.currentExpense.currency_id = props.companyCurrency.id
|
||||
expenseStore.currentExpense.selectedCurrency = props.companyCurrency
|
||||
await globalStore.fetchCurrencies()
|
||||
|
||||
const companyCurrency = companyStore.selectedCompanyCurrency
|
||||
if (!isEdit.value && companyCurrency) {
|
||||
expenseStore.currentExpense.currency_id = companyCurrency.id
|
||||
expenseStore.currentExpense.selectedCurrency = companyCurrency
|
||||
}
|
||||
|
||||
isFetchingInitialData.value = true
|
||||
|
||||
@@ -125,6 +125,16 @@
|
||||
label="key"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Exchange Rate -->
|
||||
<ExchangeRateConverter
|
||||
:store="invoiceStore"
|
||||
store-prop="newInvoice"
|
||||
:v="{ exchange_rate: { $error: false, $errors: [], $touch: () => {} } }"
|
||||
:is-loading="isLoading"
|
||||
:is-edit="isEdit"
|
||||
:customer-currency="invoiceStore.newInvoice.currency_id"
|
||||
/>
|
||||
</BaseInputGrid>
|
||||
</div>
|
||||
</template>
|
||||
@@ -134,6 +144,8 @@ import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { useRecurringInvoiceStore } from '@v2/features/company/recurring-invoices/store'
|
||||
import { useInvoiceStore } from '../store'
|
||||
import { ExchangeRateConverter } from '../../../shared/document-form'
|
||||
import type { FrequencyOption } from '@v2/features/company/recurring-invoices/store'
|
||||
|
||||
interface Props {
|
||||
@@ -147,6 +159,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
})
|
||||
|
||||
const recurringInvoiceStore = useRecurringInvoiceStore()
|
||||
const invoiceStore = useInvoiceStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
const isLoadingNextDate = ref<boolean>(false)
|
||||
|
||||
@@ -404,13 +404,15 @@ export const useInvoiceStore = defineStore('invoice', {
|
||||
},
|
||||
|
||||
async selectCustomer(id: number): Promise<unknown> {
|
||||
// This would use customerService in a full implementation
|
||||
const { customerService } = await import(
|
||||
'../../../api/services/customer.service'
|
||||
)
|
||||
const response = await customerService.get(id)
|
||||
this.newInvoice.customer = response.data as unknown as Customer
|
||||
this.newInvoice.customer_id = response.data.id
|
||||
if (response.data.currency) {
|
||||
this.newInvoice.currency_id = (response.data.currency as { id: number }).id
|
||||
}
|
||||
return response
|
||||
},
|
||||
|
||||
|
||||
@@ -116,6 +116,16 @@
|
||||
</div>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Exchange Rate -->
|
||||
<ExchangeRateConverter
|
||||
:store="paymentStore"
|
||||
store-prop="currentPayment"
|
||||
:v="{ exchange_rate: { $error: false, $errors: [], $touch: () => {} } }"
|
||||
:is-loading="isLoadingContent"
|
||||
:is-edit="isEdit"
|
||||
:customer-currency="paymentStore.currentPayment.currency_id"
|
||||
/>
|
||||
|
||||
<!-- Payment Mode -->
|
||||
<BaseInputGroup
|
||||
:content-loading="isLoadingContent"
|
||||
@@ -180,13 +190,17 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import { usePaymentStore } from '../store'
|
||||
import { useCompanyStore } from '../../../../stores/company.store'
|
||||
import { invoiceService } from '../../../../api/services/invoice.service'
|
||||
import { customerService } from '../../../../api/services/customer.service'
|
||||
import { ExchangeRateConverter } from '../../../shared/document-form'
|
||||
import type { Invoice } from '../../../../types/domain/invoice'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
const paymentStore = usePaymentStore()
|
||||
const companyStore = useCompanyStore()
|
||||
|
||||
const isSaving = ref<boolean>(false)
|
||||
const isLoadingInvoices = ref<boolean>(false)
|
||||
@@ -225,9 +239,11 @@ if (route.query.customer) {
|
||||
paymentStore.currentPayment.customer_id = Number(route.query.customer)
|
||||
}
|
||||
|
||||
paymentStore.fetchPaymentInitialData(isEdit.value, {
|
||||
id: isEdit.value ? (route.params.id as string) : undefined,
|
||||
})
|
||||
paymentStore.fetchPaymentInitialData(
|
||||
isEdit.value,
|
||||
{ id: isEdit.value ? (route.params.id as string) : undefined },
|
||||
companyStore.selectedCompanyCurrency ?? undefined,
|
||||
)
|
||||
|
||||
// Create-from-invoice: pre-select the invoice and its customer
|
||||
if (route.params.id && !isEdit.value) {
|
||||
@@ -262,8 +278,23 @@ async function onCustomerChange(customerId: number): Promise<void> {
|
||||
|
||||
isLoadingInvoices.value = true
|
||||
try {
|
||||
const response = await invoiceService.list(params as never)
|
||||
invoiceList.value = [...(response.data as unknown as Invoice[])]
|
||||
const [invoiceResponse, customerResponse] = await Promise.all([
|
||||
invoiceService.list(params as never),
|
||||
customerService.get(customerId),
|
||||
])
|
||||
|
||||
invoiceList.value = [...(invoiceResponse.data as unknown as Invoice[])]
|
||||
|
||||
// Set currency from customer
|
||||
if (customerResponse.data) {
|
||||
const customer = customerResponse.data
|
||||
paymentStore.currentPayment.customer = customer
|
||||
paymentStore.currentPayment.selectedCustomer = customer
|
||||
if (customer.currency) {
|
||||
paymentStore.currentPayment.currency = customer.currency
|
||||
paymentStore.currentPayment.currency_id = customer.currency.id
|
||||
}
|
||||
}
|
||||
|
||||
if (paymentStore.currentPayment.invoice_id) {
|
||||
selectedInvoice.value =
|
||||
|
||||
@@ -212,11 +212,18 @@ async function fetchCurrencies(): Promise<void> {
|
||||
|
||||
isFetchingCurrencies.value = true
|
||||
try {
|
||||
const params: Record<string, string> = { driver, key }
|
||||
const driverConfig: Record<string, string> = {}
|
||||
if (currencyConverter.value.type) {
|
||||
params.type = currencyConverter.value.type
|
||||
driverConfig.type = currencyConverter.value.type
|
||||
}
|
||||
const res = await exchangeRateService.getSupportedCurrencies()
|
||||
if (currencyConverter.value.url) {
|
||||
driverConfig.url = currencyConverter.value.url
|
||||
}
|
||||
const res = await exchangeRateService.getSupportedCurrencies({
|
||||
driver,
|
||||
key,
|
||||
driver_config: Object.keys(driverConfig).length ? driverConfig : undefined,
|
||||
})
|
||||
supportedCurrencies.value = res.supportedCurrencies ?? []
|
||||
} finally {
|
||||
isFetchingCurrencies.value = false
|
||||
|
||||
@@ -128,6 +128,15 @@
|
||||
:amount="total"
|
||||
:currency="selectedCurrency"
|
||||
/>
|
||||
<span
|
||||
v-if="showBaseCurrencyEquivalent"
|
||||
class="block text-xs text-muted mt-1"
|
||||
>
|
||||
<BaseFormatMoney
|
||||
:amount="baseCurrencyTotal"
|
||||
:currency="companyCurrency"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
<div class="flex items-center justify-center w-6 h-10 mx-2">
|
||||
<BaseIcon
|
||||
@@ -184,6 +193,7 @@ import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { required, between, maxLength, helpers, minValue } from '@vuelidate/validators'
|
||||
import useVuelidate from '@vuelidate/core'
|
||||
import { useCompanyStore } from '../../../stores/company.store'
|
||||
import DocumentItemRowTax from './DocumentItemRowTax.vue'
|
||||
import DragIcon from '@v2/components/icons/DragIcon.vue'
|
||||
import { generateClientId } from '../../../utils'
|
||||
@@ -221,6 +231,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const companyStore = useCompanyStore()
|
||||
|
||||
const formData = computed<DocumentFormData>(() => {
|
||||
return props.store[props.storeProp] as DocumentFormData
|
||||
@@ -285,6 +296,17 @@ const totalSimpleTax = computed<number>(() => {
|
||||
|
||||
const totalTax = computed<number>(() => totalSimpleTax.value)
|
||||
|
||||
const companyCurrency = computed(() => companyStore.selectedCompanyCurrency)
|
||||
|
||||
const showBaseCurrencyEquivalent = computed<boolean>(() => {
|
||||
return !!(formData.value.exchange_rate && (props.store as Record<string, unknown>).showExchangeRate)
|
||||
})
|
||||
|
||||
const baseCurrencyTotal = computed<number>(() => {
|
||||
if (!formData.value.exchange_rate) return 0
|
||||
return Math.round(total.value * Number(formData.value.exchange_rate))
|
||||
})
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
|
||||
@@ -217,12 +217,20 @@
|
||||
<BaseFormatMoney :amount="store.getTotal" :currency="defaultCurrency" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Base currency equivalent -->
|
||||
<div v-if="showBaseCurrencyEquivalent" class="flex items-center justify-end w-full mt-1">
|
||||
<label class="text-xs text-muted">
|
||||
≈ <BaseFormatMoney :amount="baseCurrencyGrandTotal" :currency="companyCurrency" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import TaxSelectPopup from './TaxSelectPopup.vue'
|
||||
import { useCompanyStore } from '../../../stores/company.store'
|
||||
import { generateClientId } from '../../../utils'
|
||||
import type { Currency } from '../../../types/domain/currency'
|
||||
import type { TaxType } from '../../../types/domain/tax'
|
||||
@@ -245,6 +253,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
isLoading: false,
|
||||
})
|
||||
|
||||
const companyStore = useCompanyStore()
|
||||
const taxModal = ref<HTMLElement | null>(null)
|
||||
|
||||
const formData = computed<DocumentFormData>(() => {
|
||||
@@ -263,6 +272,17 @@ const defaultCurrencySymbol = computed<string>(() => {
|
||||
return (curr?.symbol as string) ?? '$'
|
||||
})
|
||||
|
||||
const companyCurrency = computed(() => companyStore.selectedCompanyCurrency)
|
||||
|
||||
const showBaseCurrencyEquivalent = computed<boolean>(() => {
|
||||
return !!(formData.value.exchange_rate && (props.store as Record<string, unknown>).showExchangeRate)
|
||||
})
|
||||
|
||||
const baseCurrencyGrandTotal = computed<number>(() => {
|
||||
if (!formData.value.exchange_rate) return 0
|
||||
return Math.round(props.store.getTotal * Number(formData.value.exchange_rate))
|
||||
})
|
||||
|
||||
watch(
|
||||
() => formData.value.items,
|
||||
() => setDiscount(),
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch, computed, ref, onBeforeUnmount } from 'vue'
|
||||
import { watch, computed, ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { exchangeRateService } from '../../../api/services/exchange-rate.service'
|
||||
import { useCompanyStore } from '../../../stores/company.store'
|
||||
import { useGlobalStore } from '../../../stores/global.store'
|
||||
@@ -79,6 +79,10 @@ const globalStore = useGlobalStore()
|
||||
const hasActiveProvider = ref<boolean>(false)
|
||||
const isFetching = ref<boolean>(false)
|
||||
|
||||
onMounted(() => {
|
||||
globalStore.fetchCurrencies()
|
||||
})
|
||||
|
||||
const formData = computed<DocumentFormData>(() => {
|
||||
return props.store[props.storeProp] as DocumentFormData
|
||||
})
|
||||
@@ -139,12 +143,10 @@ function checkForActiveProvider(): void {
|
||||
exchangeRateService
|
||||
.getActiveProvider(Number(props.customerCurrency))
|
||||
.then((res) => {
|
||||
if (res.has_active_provider) {
|
||||
hasActiveProvider.value = true
|
||||
}
|
||||
hasActiveProvider.value = res.hasActiveProvider
|
||||
})
|
||||
.catch(() => {
|
||||
// Silently fail
|
||||
hasActiveProvider.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -176,11 +178,7 @@ async function getCurrentExchangeRate(v: number | string | null | undefined): Pr
|
||||
isFetching.value = true
|
||||
try {
|
||||
const res = await exchangeRateService.getRate(Number(v))
|
||||
if (res && res.exchange_rate != null) {
|
||||
formData.value.exchange_rate = res.exchange_rate
|
||||
} else {
|
||||
formData.value.exchange_rate = null
|
||||
}
|
||||
formData.value.exchange_rate = res.exchangeRate
|
||||
} catch {
|
||||
// Silently fail
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user