taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 39fd544b71f538613a96c299076e0864d46abfd5
parent 2e448ac3a000529bc4748a8b6219c51d29f9c008
Author: Florian Dold <florian@dold.me>
Date:   Tue, 27 Jan 2026 22:49:55 +0100

aml: improve interface for prop derivation, add rudimentary tests

Diffstat:
Mpackages/aml-backoffice-ui/src/pages/decision/Properties.tsx | 3+--
Apackages/taler-util/src/aml/properties.test.ts | 45+++++++++++++++++++++++++++++++++++++++++++++
Mpackages/taler-util/src/aml/properties.ts | 84++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
3 files changed, 104 insertions(+), 28 deletions(-)

diff --git a/packages/aml-backoffice-ui/src/pages/decision/Properties.tsx b/packages/aml-backoffice-ui/src/pages/decision/Properties.tsx @@ -331,7 +331,7 @@ function propertiesByDialect( } function calculatePropertiesBasedOnState( - currentLimits: LegitimizationRuleSet, + currentLimits: LegitimizationRuleSet, // FIXME: Not necessary. state: AccountProperties, request: DecisionRequest, dialect: AmlSpaDialect, @@ -359,7 +359,6 @@ function calculatePropertiesBasedOnState( result[prop] = info[prop].deriveProperty( FORM_ID, newNewAttributes, - currentLimits, state, ); return result; diff --git a/packages/taler-util/src/aml/properties.test.ts b/packages/taler-util/src/aml/properties.test.ts @@ -0,0 +1,45 @@ +/* + This file is part of GNU Taler + (C) 2026 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import test from "ava"; +import { TalerAmlProperties } from "../taler-account-properties.js"; +import { TalerFormAttributes } from "../taler-form-attributes.js"; +import { deriveTopsAmlProperties } from "./properties.js"; + +test("prop derivation for TOPS", (t) => { + { + const props = deriveTopsAmlProperties("custom_does_not_exist132", {}, {}); + t.deepEqual(props, {}); + } + { + const props = deriveTopsAmlProperties("vqf_902_1_officer", {}, {}); + t.deepEqual(props, { + [TalerAmlProperties.ACCOUNT_OPEN]: true, + }); + } + { + const props = deriveTopsAmlProperties( + "vqf_902_4", + { + [TalerFormAttributes.RISK_CLASSIFICATION_LEVEL]: "HIGH_RISK", + }, + {}, + ); + t.deepEqual(props, { + [TalerAmlProperties.HIGH_RISK_CUSTOMER]: true, + }); + } +}); diff --git a/packages/taler-util/src/aml/properties.ts b/packages/taler-util/src/aml/properties.ts @@ -1,6 +1,6 @@ import { TalerAmlProperties } from "../taler-account-properties.js"; import { TalerFormAttributes } from "../taler-form-attributes.js"; -import { AccountProperties, LegitimizationRuleSet } from "../types-taler-exchange.js"; +import { AccountProperties } from "../types-taler-exchange.js"; /** * List of account properties required by TOPS @@ -43,13 +43,13 @@ export type PropertiesDerivationFunctionByPropertyName<T extends string> = { */ deriveProperty: ( formId: string, - newAttributes: Record<keyof typeof TalerFormAttributes, unknown>, - limits: LegitimizationRuleSet, + newAttributes: AmlFormAttributesMap, state: AccountProperties, ) => string | boolean | undefined; }; }; +// FIXME: Does this enum really belong in aml/properties.ts? export enum KnownForms { vqf_902_1_customer, vqf_902_1_officer, @@ -65,6 +65,22 @@ export enum KnownForms { vqf_902_15, } +/** + * Type of account properties for TOPS AML. + * Maps account property names to the property value. + */ +export type TopsAccountPropertiesMap = { + [x in (typeof TOPS_AccountProperties)[number]]?: any; +}; + +/** + * Type of form attributes for TOPS AML. + * Maps form attribute names to the attribute value. + */ +export type AmlFormAttributesMap = { + [x in keyof typeof TalerFormAttributes]?: any; +}; + export function isOneOf(formId: string, ...allowedForms: KnownForms[]) { return ( -1 !== @@ -81,7 +97,7 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa (typeof TOPS_AccountProperties)[number] > = { ACCOUNT_OPEN: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { if ( isOneOf( formId, @@ -96,7 +112,7 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa }, }, PEP_DOMESTIC: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { if (isOneOf(formId, KnownForms.vqf_902_4)) { return !!attributes[TalerFormAttributes.PEP_DOMESTIC]; } @@ -104,7 +120,7 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa }, }, PEP_FOREIGN: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { if (isOneOf(formId, KnownForms.vqf_902_4)) { return !!attributes[TalerFormAttributes.PEP_FOREIGN]; } @@ -112,7 +128,7 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa }, }, PEP_INTERNATIONAL_ORGANIZATION: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { if (isOneOf(formId, KnownForms.vqf_902_4)) { return !!attributes[TalerFormAttributes.PEP_INTERNATIONAL_ORGANIZATION]; } @@ -120,7 +136,7 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa }, }, HIGH_RISK_CUSTOMER: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { if (isOneOf(formId, KnownForms.vqf_902_4)) { return ( attributes[TalerFormAttributes.RISK_CLASSIFICATION_LEVEL] === @@ -131,7 +147,7 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa }, }, HIGH_RISK_COUNTRY: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { if (isOneOf(formId, KnownForms.vqf_902_4)) { return ( attributes[TalerFormAttributes.COUNTRY_RISK_NATIONALITY_LEVEL] === @@ -142,22 +158,22 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa }, }, ACCOUNT_IDLE: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { return undefined; }, }, CUSTOMER_LABEL: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { return undefined; }, }, FILE_NOTE: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { return undefined; }, }, INVESTIGATION_STATE: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { if (isOneOf(formId, KnownForms.vqf_902_14)) { if ( attributes[TalerFormAttributes.INCRISK_RESULT] === "SIMPLE_SUSPICION" @@ -165,18 +181,15 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa return "REPORTED_SUSPICION_SIMPLE"; } if ( - attributes[TalerFormAttributes.INCRISK_RESULT] === "SUBSTANTIATED_SUSPICION" + attributes[TalerFormAttributes.INCRISK_RESULT] === + "SUBSTANTIATED_SUSPICION" ) { return "REPORTED_SUSPICION_SUBSTANTIATED"; } - if ( - attributes[TalerFormAttributes.INCRISK_RESULT] === "NO_SUSPICION" - ) { + if (attributes[TalerFormAttributes.INCRISK_RESULT] === "NO_SUSPICION") { return "INVESTIGATION_COMPLETED_WITHOUT_SUSPICION"; } - if ( - attributes[TalerFormAttributes.INCRISK_RESULT] === "OTHER" - ) { + if (attributes[TalerFormAttributes.INCRISK_RESULT] === "OTHER") { return null as any; } } @@ -185,27 +198,27 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa }, }, INVESTIGATION_TRIGGER: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { return undefined; }, }, SANCTION_LIST_BEST_MATCH: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { return undefined; }, }, SANCTION_LIST_CONFIDENCE: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { return undefined; }, }, SANCTION_LIST_RATING: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { return undefined; }, }, SANCTION_LIST_SUPPRESS: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { return undefined; }, }, @@ -215,8 +228,27 @@ export const GLS_AML_PROPERTIES: PropertiesDerivationFunctionByPropertyName< (typeof GLS_AccountProperties)[number] > = { FILE_NOTE: { - deriveProperty(formId, attributes, limits, state) { + deriveProperty(formId, attributes, state) { return undefined; }, }, }; + +export function deriveTopsAmlProperties( + formId: string, + newAttributes: AmlFormAttributesMap, + oldProperties: TopsAccountPropertiesMap, +): TopsAccountPropertiesMap { + const props: TopsAccountPropertiesMap = {}; + for (const propName of TOPS_AccountProperties) { + const propVal = PropertiesDerivation_TOPS[propName].deriveProperty( + formId, + newAttributes, + oldProperties, + ); + if (propVal !== undefined) { + props[propName] = propVal; + } + } + return props; +}