diff --git a/fyo/model/doc.ts b/fyo/model/doc.ts index c089448f..f7eed3ca 100644 --- a/fyo/model/doc.ts +++ b/fyo/model/doc.ts @@ -12,7 +12,7 @@ import { OptionField, RawValue, Schema, - TargetField, + TargetField } from 'schemas/types'; import { getIsNullOrUndef, getMapFromList, getRandomString } from 'utils'; import { markRaw } from 'vue'; @@ -23,7 +23,7 @@ import { getMissingMandatoryMessage, getPreDefaultValues, setChildDocIdx, - shouldApplyFormula, + shouldApplyFormula } from './helpers'; import { setName } from './naming'; import { @@ -41,7 +41,7 @@ import { ReadOnlyMap, RequiredMap, TreeViewSettings, - ValidationMap, + ValidationMap } from './types'; import { validateOptions, validateRequired } from './validationFunction'; @@ -191,6 +191,7 @@ export class Doc extends Observable { if (typeof fieldname === 'object') { return await this.setMultiple(fieldname as DocValueMap); } + console.log(fieldname, value); if (!this._canSet(fieldname, value)) { return false; diff --git a/models/baseModels/Invoice/Invoice.ts b/models/baseModels/Invoice/Invoice.ts index 8a7cabff..d1c8002b 100644 --- a/models/baseModels/Invoice/Invoice.ts +++ b/models/baseModels/Invoice/Invoice.ts @@ -42,6 +42,14 @@ export abstract class Invoice extends Transactional { return !!this.fyo.singles?.AccountingSettings?.enableDiscounting; } + get isMultiCurrency() { + if (!this.currency) { + return false; + } + + return this.fyo.singles.SystemSettings!.currency !== this.currency; + } + async validate() { await super.validate(); if ( @@ -126,10 +134,12 @@ export abstract class Invoice extends Transactional { if (this.currency === currency) { return 1.0; } - return await getExchangeRate({ + const exchangeRate = await getExchangeRate({ fromCurrency: this.currency!, toCurrency: currency as string, }); + + return parseFloat(exchangeRate.toFixed(2)); } async getTaxSummary() { @@ -285,7 +295,15 @@ export abstract class Invoice extends Transactional { }, dependsOn: ['party'], }, - exchangeRate: { formula: async () => await this.getExchangeRate() }, + exchangeRate: { + formula: async () => { + if (this.exchangeRate && this.exchangeRate !== 1) { + return this.exchangeRate; + } + + return await this.getExchangeRate(); + }, + }, netTotal: { formula: async () => this.getSum('items', 'amount', false) }, baseNetTotal: { formula: async () => this.netTotal!.mul(this.exchangeRate!), diff --git a/models/baseModels/Party/Party.ts b/models/baseModels/Party/Party.ts index 6dbeafca..db500e4f 100644 --- a/models/baseModels/Party/Party.ts +++ b/models/baseModels/Party/Party.ts @@ -87,7 +87,11 @@ export class Party extends Doc { dependsOn: ['role'], }, currency: { - formula: async () => this.fyo.singles.SystemSettings!.currency as string, + formula: async () => { + if (!this.currency) { + return this.fyo.singles.SystemSettings!.currency as string; + } + }, }, }; diff --git a/models/helpers.ts b/models/helpers.ts index 09d84d48..e78580ef 100644 --- a/models/helpers.ts +++ b/models/helpers.ts @@ -1,13 +1,12 @@ import { Fyo, t } from 'fyo'; import { Doc } from 'fyo/model/doc'; import { Action, ColumnConfig, DocStatus, RenderData } from 'fyo/model/types'; -import { NotFoundError } from 'fyo/utils/errors'; import { DateTime } from 'luxon'; import { Money } from 'pesa'; import { Router } from 'vue-router'; import { AccountRootType, - AccountRootTypeEnum, + AccountRootTypeEnum } from './baseModels/Account/types'; import { InvoiceStatus, ModelNameEnum } from './types'; @@ -196,14 +195,12 @@ export async function getExchangeRate({ toCurrency: string; date?: string; }) { - if (!date) { - date = DateTime.local().toISODate(); + if (!fetch) { + return 1; } - if (!fromCurrency || !toCurrency) { - throw new NotFoundError( - 'Please provide `fromCurrency` and `toCurrency` to get exchange rate.' - ); + if (!date) { + date = DateTime.local().toISODate(); } const cacheKey = `currencyExchangeRate:${date}:${fromCurrency}:${toCurrency}`; @@ -215,26 +212,23 @@ export async function getExchangeRate({ ); } - if (!exchangeRate && fetch) { - try { - const res = await fetch( - ` https://api.vatcomply.com/rates?date=${date}&base=${fromCurrency}&symbols=${toCurrency}` - ); - const data = await res.json(); - exchangeRate = data.rates[toCurrency]; + if (exchangeRate && exchangeRate !== 1) { + return exchangeRate; + } - if (localStorage) { - localStorage.setItem(cacheKey, String(exchangeRate)); - } - } catch (error) { - console.error(error); - throw new NotFoundError( - `Could not fetch exchange rate for ${fromCurrency} -> ${toCurrency}`, - false - ); - } - } else { - exchangeRate = 1; + try { + const res = await fetch( + `https://api.vatcomply.com/rates?date=${date}&base=${fromCurrency}&symbols=${toCurrency}` + ); + const data = await res.json(); + exchangeRate = data.rates[toCurrency]; + } catch (error) { + console.error(error); + exchangeRate ??= 1; + } + + if (localStorage) { + localStorage.setItem(cacheKey, String(exchangeRate)); } return exchangeRate; @@ -256,3 +250,6 @@ export function isCredit(rootType: AccountRootType) { return true; } } + +// @ts-ignore +window.gex = getExchangeRate; diff --git a/schemas/core/SystemSettings.json b/schemas/core/SystemSettings.json index 92c33fb8..ba67d038 100644 --- a/schemas/core/SystemSettings.json +++ b/schemas/core/SystemSettings.json @@ -88,6 +88,7 @@ "label": "Currency", "fieldtype": "AutoComplete", "default": "INR", + "readOnly": true, "required": true }, { diff --git a/src/components/Controls/Base.vue b/src/components/Controls/Base.vue index dbd34c79..dc3ce130 100644 --- a/src/components/Controls/Base.vue +++ b/src/components/Controls/Base.vue @@ -151,13 +151,16 @@ export default { }, methods: { getInputClassesFromProp(classes) { - if (this.inputClass) { - if (typeof this.inputClass === 'function') { - classes = this.inputClass(classes); - } else { - classes.push(this.inputClass); - } + if (!this.inputClass) { + return classes; } + + if (typeof this.inputClass === 'function') { + classes = this.inputClass(classes); + } else { + classes.push(this.inputClass); + } + return classes; }, focus() { diff --git a/src/components/Controls/ExchangeRate.vue b/src/components/Controls/ExchangeRate.vue new file mode 100644 index 00000000..73d3de66 --- /dev/null +++ b/src/components/Controls/ExchangeRate.vue @@ -0,0 +1,102 @@ + + + diff --git a/src/pages/InvoiceForm.vue b/src/pages/InvoiceForm.vue index 6347b404..8fe6b237 100644 --- a/src/pages/InvoiceForm.vue +++ b/src/pages/InvoiceForm.vue @@ -3,6 +3,16 @@