diff --git a/packages/desktop-client/src/components/formula/codeMirror-excelLanguage.tsx b/packages/desktop-client/src/components/formula/codeMirror-excelLanguage.tsx index 126433dcdc..88afe02cb8 100644 --- a/packages/desktop-client/src/components/formula/codeMirror-excelLanguage.tsx +++ b/packages/desktop-client/src/components/formula/codeMirror-excelLanguage.tsx @@ -148,6 +148,7 @@ const LOGICAL_FUNCTIONS = new Set([ const TEXT_FUNCTIONS = new Set([ 'TEXT', + 'FIXED', 'CONCATENATE', 'LEFT', 'RIGHT', diff --git a/packages/desktop-client/src/components/formula/queryModeFunctions.ts b/packages/desktop-client/src/components/formula/queryModeFunctions.ts index 2fba45bbdf..861bbfd522 100644 --- a/packages/desktop-client/src/components/formula/queryModeFunctions.ts +++ b/packages/desktop-client/src/components/formula/queryModeFunctions.ts @@ -511,6 +511,14 @@ export const queryModeFunctions: Record = { { name: 'format', description: 'Format' }, ], }, + FIXED: { + name: 'FIXED', + description: t('Formats a number to a fixed amount of decimal places.'), + parameters: [ + { name: 'number', description: 'Number' }, + { name: 'decimals', description: 'Decimals' }, + ], + }, REPT: { name: 'REPT', description: t('Repeats text specified number of times.'), diff --git a/packages/desktop-client/src/components/formula/transactionModeFunctions.ts b/packages/desktop-client/src/components/formula/transactionModeFunctions.ts index 01ae0df11a..74466ccfde 100644 --- a/packages/desktop-client/src/components/formula/transactionModeFunctions.ts +++ b/packages/desktop-client/src/components/formula/transactionModeFunctions.ts @@ -122,6 +122,14 @@ export const transactionModeFunctions: Record = { { name: 'format', description: 'Format' }, ], }, + FIXED: { + name: 'FIXED', + description: t('Formats a number to a fixed amount of decimal places.'), + parameters: [ + { name: 'number', description: 'Number' }, + { name: 'decimals', description: 'Decimals' }, + ], + }, REPT: { name: 'REPT', description: t('Repeats text specified number of times.'), diff --git a/packages/desktop-client/src/hooks/useFormulaExecution.ts b/packages/desktop-client/src/hooks/useFormulaExecution.ts index 4d47190a26..cd76a0567c 100644 --- a/packages/desktop-client/src/hooks/useFormulaExecution.ts +++ b/packages/desktop-client/src/hooks/useFormulaExecution.ts @@ -1,5 +1,7 @@ import { useEffect, useState } from 'react'; +import { HyperFormula } from 'hyperformula'; + import { send } from 'loot-core/platform/client/fetch'; import * as monthUtils from 'loot-core/shared/months'; import { q, type Query } from 'loot-core/shared/query'; @@ -40,7 +42,6 @@ export function useFormulaExecution( let cancelled = false; async function executeFormula() { - const { HyperFormula } = await import('hyperformula'); let hfInstance: ReturnType | null = null; if (!formula || !formula.startsWith('=')) { @@ -118,6 +119,7 @@ export function useFormulaExecution( hfInstance = HyperFormula.buildEmpty({ licenseKey: 'gpl-v3', localeLang: typeof locale === 'string' ? locale : 'en-US', + language: 'enUS', }); // Add a sheet and set the formula in cell A1 diff --git a/packages/loot-core/src/server/rules/action.ts b/packages/loot-core/src/server/rules/action.ts index fb1ba58f1c..242ef1595c 100644 --- a/packages/loot-core/src/server/rules/action.ts +++ b/packages/loot-core/src/server/rules/action.ts @@ -2,6 +2,7 @@ import * as dateFns from 'date-fns'; import * as Handlebars from 'handlebars'; import { HyperFormula } from 'hyperformula'; +import enUS from 'hyperformula/i18n/languages/enUS'; import { amountToInteger } from 'loot-core/shared/util'; @@ -10,9 +11,18 @@ import { currentDay, format, parseDate } from '../../shared/months'; import { FIELD_TYPES } from '../../shared/rules'; import { type TransactionForRules } from '../transactions/transaction-rules'; -import { CustomFunctionsPlugin } from './customFunctions'; +import { + CustomFunctionsPlugin, + customFunctionsTranslations, +} from './customFunctions'; import { assert } from './rule-utils'; +HyperFormula.registerLanguage('enUS', enUS); +HyperFormula.registerFunctionPlugin( + CustomFunctionsPlugin, + customFunctionsTranslations, +); + const ACTION_OPS = [ 'set', 'set-split-amount', @@ -258,10 +268,9 @@ export class Action { } try { - HyperFormula.registerFunctionPlugin(CustomFunctionsPlugin); - hfInstance = HyperFormula.buildEmpty({ licenseKey: 'gpl-v3', + language: 'enUS', }); const sheetName = hfInstance.addSheet('Sheet1'); diff --git a/packages/loot-core/src/server/rules/customFunctions.ts b/packages/loot-core/src/server/rules/customFunctions.ts index f8af1aeb2d..bebd3a9233 100644 --- a/packages/loot-core/src/server/rules/customFunctions.ts +++ b/packages/loot-core/src/server/rules/customFunctions.ts @@ -15,6 +15,17 @@ export class CustomFunctionsPlugin extends FunctionPlugin { }, ); } + + fixed(ast: ProcedureAst, state: InterpreterState) { + return this.runFunction( + ast.args, + state, + this.metadata('FIXED'), + (number: number, decimals: number = 0) => { + return Number(number).toFixed(decimals); + }, + ); + } } CustomFunctionsPlugin.implementedFunctions = { @@ -29,4 +40,22 @@ CustomFunctionsPlugin.implementedFunctions = { }, ], }, + FIXED: { + method: 'fixed', + parameters: [ + { argumentType: FunctionArgumentType.NUMBER }, + { + argumentType: FunctionArgumentType.NUMBER, + optionalArg: true, + defaultValue: 0, + }, + ], + }, +}; + +export const customFunctionsTranslations = { + enUS: { + INTEGER_TO_AMOUNT: 'INTEGER_TO_AMOUNT', + FIXED: 'FIXED', + }, }; diff --git a/upcoming-release-notes/6645.md b/upcoming-release-notes/6645.md new file mode 100644 index 0000000000..f046886423 --- /dev/null +++ b/upcoming-release-notes/6645.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [matt-fidd] +--- + +Add FIXED to EXCEL functions