taler-typescript-core

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

commit 6274c66b7e79ee96f4d49c45ff5017d5141969b2
parent ff35b68f10d8982e40eabf828310bbf5af29df95
Author: Sebastian <sebasjm@gmail.com>
Date:   Mon,  3 Nov 2025 13:06:06 -0300

fix payto normalizing

Diffstat:
Mpackages/aml-backoffice-ui/src/pages/decision/Summary.tsx | 72++++++++++++++++++++++++++++++++++++++++--------------------------------
Mpackages/taler-util/src/iban.test.ts | 1-
Mpackages/taler-util/src/payto.ts | 3++-
Mpackages/taler-util/src/paytos.test.ts | 20++++++++++++++++++--
Mpackages/taler-util/src/talerconfig.test.ts | 1-
5 files changed, 60 insertions(+), 37 deletions(-)

diff --git a/packages/aml-backoffice-ui/src/pages/decision/Summary.tsx b/packages/aml-backoffice-ui/src/pages/decision/Summary.tsx @@ -17,16 +17,16 @@ import { AbsoluteTime, AmlDecisionRequest, assertUnreachable, + encodeCrock, HttpStatusCode, opEmptySuccess, - parsePaytoUri, - stringifyPaytoUri, + Paytos, + succeedOrThrow, TalerError, TOPS_AmlEventsName, } from "@gnu-taler/taler-util"; import { Attention, - Button, ButtonBetter, LocalNotificationBanner, useExchangeApiContext, @@ -129,46 +129,54 @@ export function Summary({ onMove(undefined); } - const fullPayto = !newPayto ? undefined : parsePaytoUri(newPayto); - if (fullPayto && decision.accountName) { - fullPayto.params["receiver-name"] = decision.accountName; + const fullPayto = !newPayto ? undefined : Paytos.fromString(newPayto); + if (fullPayto && fullPayto.type === "ok" && decision.accountName) { + fullPayto.body.params["receiver-name"] = decision.accountName; } - const request: Omit<AmlDecisionRequest, "officer_sig"> = { - h_payto: account!, - decision_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()), - justification: decision.justification!, - payto_uri: !fullPayto ? undefined : stringifyPaytoUri(fullPayto), - keep_investigating: decision.keep_investigating ?? false, - new_rules: { - expiration_time: AbsoluteTime.toProtocolTimestamp(decision.deadline!), - rules: decision.rules!, - successor_measure: decision.onExpire_measure, - custom_measures: decision.custom_measures ?? {}, - }, - attributes_expiration: decision.attributes?.expiration - ? AbsoluteTime.toProtocolTimestamp(decision.attributes.expiration) - : undefined, - events: decision.triggering_events, - attributes: decision.attributes?.data, - properties: decision.properties!, - new_measures: - !decision.new_measures || !decision.new_measures.length - ? undefined - : decision.new_measures.join(" "), - }; + const request: undefined | Omit<AmlDecisionRequest, "officer_sig"> = + CANT_SUBMIT + ? undefined + : { + h_payto: account!, + decision_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()), + justification: decision.justification!, + payto_uri: + !fullPayto || fullPayto.type === "fail" + ? undefined + : Paytos.toFullString(fullPayto.body), + keep_investigating: decision.keep_investigating ?? false, + new_rules: { + expiration_time: AbsoluteTime.toProtocolTimestamp( + decision.deadline!, + ), + rules: decision.rules!, + successor_measure: decision.onExpire_measure, + custom_measures: decision.custom_measures ?? {}, + }, + attributes_expiration: decision.attributes?.expiration + ? AbsoluteTime.toProtocolTimestamp(decision.attributes.expiration) + : undefined, + events: decision.triggering_events, + attributes: decision.attributes?.data, + properties: decision.properties!, + new_measures: + !decision.new_measures || !decision.new_measures.length + ? undefined + : decision.new_measures.join(" "), + }; const [submitConfirmation, setSubmitConfirmation] = useState<boolean>(false); const requiresConfirmation = MROS_REPORT_COMPLETED; const submit = safeFunctionHandler( - async () => { + async (req) => { if (requiresConfirmation && !submitConfirmation) { setSubmitConfirmation(true); return opEmptySuccess(); } - return lib.exchange.makeAmlDesicion(session, request); + return lib.exchange.makeAmlDesicion(session, req); }, - CANT_SUBMIT ? undefined : [], + !request ? undefined : [request], ); submit.onSuccess = clearUp; diff --git a/packages/taler-util/src/iban.test.ts b/packages/taler-util/src/iban.test.ts @@ -25,6 +25,5 @@ test("iban validation", (t) => { test("iban generation", (t) => { let iban1 = generateIban("DE", 10); - console.log("generated IBAN", iban1); t.assert(validateIban(iban1).type === "valid"); }); diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts @@ -339,12 +339,13 @@ export namespace Paytos { bic: string | undefined, params: Record<string, string> = {}, ): PaytoIBAN { + iban = iban.toUpperCase() as IbanString return { targetType: PaytoType.IBAN, iban, bic, params, - normalizedPath: iban.toLocaleLowerCase(), + normalizedPath: iban, fullPath: !bic ? iban : `${bic}/${iban}`, displayName: iban, }; diff --git a/packages/taler-util/src/paytos.test.ts b/packages/taler-util/src/paytos.test.ts @@ -57,19 +57,35 @@ test("basic x-taler-bank payto string", (t) => { t.is(result.account, "accountName"); }); -test("parsing payto and stringify again", (t) => { +test("parsing payto and stringify again on normalized strings are unchanged", (t) => { const payto1 = "payto://iban/DE1231231231?reciever-name=John%20Doe"; t.is( Paytos.toFullString(succeedOrThrow(Paytos.fromString(payto1))), payto1 as Paytos.FullPaytoString, ); - const normalized = "payto://iban/de1231231231"; + const normalized = "payto://iban/DE1231231231"; t.is( Paytos.toNormalizedString(succeedOrThrow(Paytos.fromString(payto1))), normalized as Paytos.NormalizedPaytoString, ); }); +test("parsing payto and stringify again converts to the normal form", (t) => { + const fullPayto_not_normalized = "payto://iban/de1231231231?reciever-name=John%20Doe"; + // after normalization the country code is uppercased + const fullPayto_normalized = "payto://iban/DE1231231231?reciever-name=John%20Doe" as Paytos.FullPaytoString; + t.is( + Paytos.toFullString(succeedOrThrow(Paytos.fromString(fullPayto_not_normalized))), + fullPayto_normalized, + ); + + const normalized_lowercase = "payto://iban/DE1231231231"; + const normalized_uppercase = "payto://iban/DE1231231231" as Paytos.NormalizedPaytoString; + t.is( + Paytos.toNormalizedString(succeedOrThrow(Paytos.fromString(normalized_lowercase))), + normalized_uppercase, + ); +}); test("parsing payto with % carh", (t) => { const payto1 = "payto://iban/DE7763544441436?receiver-name=Test%20123%2B-%24%25%5E%3Cem%3Ehi%3C%2Fem%3E" as Paytos.FullPaytoString; diff --git a/packages/taler-util/src/talerconfig.test.ts b/packages/taler-util/src/talerconfig.test.ts @@ -113,7 +113,6 @@ test("path expansion", (t) => { }); test("recursive path resolution", (t) => { - console.log("recursive test"); const config = new Configuration(); config.setString("paths", "a", "x${b}"); config.setString("paths", "b", "y${a}");