taler-typescript-core

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

commit 5dabf9f4103562b9315600667792459c0e7ed9c8
parent 71273a95e2b3b64bf40a414583a1ffac811dc611
Author: Sebastian <sebasjm@gmail.com>
Date:   Fri,  4 Jul 2025 07:06:24 -0300

fix #10150

Diffstat:
Mpackages/taler-util/src/aml/reporting.ts | 49+++++++++++++++++++++++++++++++++++++++++++++----
Mpackages/taler-util/src/http-client/exchange-client.ts | 18++++++------------
Mpackages/taler-util/src/types-taler-exchange.ts | 12++++++++++++
3 files changed, 63 insertions(+), 16 deletions(-)

diff --git a/packages/taler-util/src/aml/reporting.ts b/packages/taler-util/src/aml/reporting.ts @@ -356,7 +356,7 @@ export async function fetchTopsInfoFromServer( const allQueries = eventList.map(async ([_key, value]) => { const key = _key as keyof EventType; - const response = await api.getAmlKycStatistics(officer, value.event, { + const response = await api.getAmlKycStatistics(officer, [value.event], { since: value.start, until: value.end, }); @@ -367,7 +367,7 @@ export async function fetchTopsInfoFromServer( const resultMap = allResponses.reduce((prev, event) => { prev[event.key] = - event.response.type === "ok" ? event.response.body.counter : undefined; + event.response.type === "ok" ? event.response.body.statistics[0].counter : undefined; return prev; }, {} as CounterResultByEventName<EventType>); @@ -384,9 +384,50 @@ export async function fetchVqfInfoFromServer( type EventType = typeof VQF_EVENTS_THIS_YEAR; const eventList = Object.entries(VQF_EVENTS_THIS_YEAR); + // type QueryAndEvent = { query: string; eventName: string }; + // type RawTime = AbsoluteTime["t_ms"]; + // // group by start & end + // const groupedEvents = eventList.reduce( + // (prev, [query, metric]) => { + // if (!prev.has(metric.start.t_ms)) { + // prev.set(metric.start.t_ms, new Map<RawTime, QueryAndEvent[]>()); + // } + // const st = prev.get(metric.start.t_ms)!; + // if (!st.has(metric.end.t_ms)) { + // st.set(metric.end.t_ms, []); + // } + // const ed = st.get(metric.end.t_ms)!; + + // ed.push({ + // query, + // eventName: metric.event, + // }); + // return prev; + // }, + // {} as Map<RawTime, Map<RawTime, QueryAndEvent[]>>, + // ); + + // groupedEvents.entries() + // const groupedEventsList = Object.entries(groupedEvents).flatMap( + // ([startStr, map]) => { + // return Object.entries(map).flatMap(([endStr, list]) => { + // const start = + // startStr === "never" + // ? AbsoluteTime.never() + // : AbsoluteTime.fromMilliseconds(Number.parseInt(startStr, 10)); + // const end = + // endStr === "never" + // ? AbsoluteTime.never() + // : AbsoluteTime.fromMilliseconds(Number.parseInt(endStr, 10)); + + // return list; + // }); + // }, + // ); + const allQueries = eventList.map(async ([_key, value]) => { const key = _key as keyof EventType; - const response = await api.getAmlKycStatistics(officer, value.event, { + const response = await api.getAmlKycStatistics(officer, [value.event], { since: value.start, until: value.end, }); @@ -397,7 +438,7 @@ export async function fetchVqfInfoFromServer( const resultMap = allResponses.reduce((prev, event) => { prev[event.key] = - event.response.type === "ok" ? event.response.body.counter : undefined; + event.response.type === "ok" ? event.response.body.statistics[0].counter : undefined; return prev; }, {} as CounterResultByEventName<EventType>); diff --git a/packages/taler-util/src/http-client/exchange-client.ts b/packages/taler-util/src/http-client/exchange-client.ts @@ -84,6 +84,7 @@ import { codecForAccountKycStatus, codecForAmlDecisionsResponse, codecForAmlKycAttributes, + codecForAmlStatisticsResponse, codecForAmlWalletKycCheckResponse, codecForAvailableMeasureSummary, codecForEventCounter, @@ -927,25 +928,18 @@ export class TalerExchangeHttpClient { } /** - * https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-kyc-statistics-$NAME + * https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-kyc-statistics-$NAMES * */ async getAmlKycStatistics( auth: OfficerAccount, - name: string, + names: string[], filter: { since?: AbsoluteTime; until?: AbsoluteTime; } = {}, - ): Promise< - | OperationFail< - | HttpStatusCode.Forbidden - | HttpStatusCode.NotFound - | HttpStatusCode.Conflict - > - | OperationOk<EventCounter> - > { - const url = new URL(`aml/${auth.id}/kyc-statistics/${name}`, this.baseUrl); + ) { + const url = new URL(`aml/${auth.id}/kyc-statistics/${names.join(" ")}`, this.baseUrl); if (filter.since !== undefined && filter.since.t_ms !== "never") { url.searchParams.set("start_date", String(filter.since.t_ms)); @@ -964,7 +958,7 @@ export class TalerExchangeHttpClient { }); switch (resp.status) { case HttpStatusCode.Ok: - return opSuccessFromHttp(resp, codecForEventCounter()); + return opSuccessFromHttp(resp, codecForAmlStatisticsResponse()); case HttpStatusCode.Conflict: case HttpStatusCode.NotFound: case HttpStatusCode.Forbidden: diff --git a/packages/taler-util/src/types-taler-exchange.ts b/packages/taler-util/src/types-taler-exchange.ts @@ -2087,7 +2087,13 @@ export interface KycCheckPublicInformation { // something more??!? } +export interface AmlStatisticsResponse { + statistics: EventCounter[]; +} export interface EventCounter { + // Name of the statistic that is being returned. + name: string; + // Number of events of the specified type in // the given range. counter: Integer; @@ -2607,8 +2613,14 @@ export const codecForExchangeKeysResponse = (): Codec<ExchangeKeysResponse> => .deprecatedProperty("rewards_allowed") .build("TalerExchangeApi.ExchangeKeysResponse"); +export const codecForAmlStatisticsResponse = (): Codec<AmlStatisticsResponse> => + buildCodecForObject<AmlStatisticsResponse>() + .property("statistics", codecForList(codecForEventCounter())) + .build("TalerExchangeApi.AmlStatisticsResponse"); + export const codecForEventCounter = (): Codec<EventCounter> => buildCodecForObject<EventCounter>() + .property("name", codecForString()) .property("counter", codecForNumber()) .build("TalerExchangeApi.EventCounter");