/* This file is part of GNU Taler (C) 2022 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 */ import { AccessToken, AmountString, Logger, TalerCoreBankHttpClient, TalerCorebankApi, TalerError } from "@gnu-taler/taler-util"; import { Attention, LocalNotificationBanner, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { useBankCoreApiContext } from "../context/config.js"; import { useBackendState } from "../hooks/backend.js"; import { getTimeframesForDate } from "./admin/AdminHome.js"; const logger = new Logger("PublicHistoriesPage"); interface Props { onCancel: () => void; } type Options = { dayMetric: boolean; hourMetric: boolean; monthMetric: boolean; yearMetric: boolean; compareWithPrevious: boolean; endOnFirstFail: boolean; includeHeader: boolean; } /** * Show histories of public accounts. */ export function DownloadStats({ onCancel }: Props): VNode { const { i18n } = useTranslationContext(); const { state: credentials } = useBackendState(); const creds = credentials.status !== "loggedIn" || !credentials.isUserAdministrator ? undefined : credentials const { api } = useBankCoreApiContext(); const [options, setOptions] = useState({ compareWithPrevious: true, dayMetric: true, endOnFirstFail: false, hourMetric: true, includeHeader: true, monthMetric: true, yearMetric: true, }) const [lastStep, setLastStep] = useState<{ step: number, total: number }>() const [downloaded, setDownloaded] = useState() const referenceDates = [new Date()] const [notification, notify, handleError] = useLocalNotification() if (!creds) { return
only admin can download stats
} return (

Download bank stats

{ e.preventDefault() }} >
Include hour metric
Include day metric
Include month metric
Include year metric
Include table header
Add previous metric for compare
Fail on first error
{!lastStep || lastStep.step === lastStep.total ?
:
downloading... {Math.round((((lastStep.step / lastStep.total))* 100) )}
} {!downloaded ? ); } async function fetchAllStatus(api: TalerCoreBankHttpClient, token: AccessToken, options: Options, references: Date[], progres: (current: number, total: number) => void): Promise { const allMetrics: TalerCorebankApi.MonitorTimeframeParam[] = []; if (options.hourMetric) { allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.hour) } if (options.dayMetric) { allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.day) } if (options.monthMetric) { allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.month) } if (options.yearMetric) { allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.year) } /** * conver request into frames */ const allFrames = allMetrics.flatMap(timeframe => references.map(reference => ({ reference, timeframe, moment: getTimeframesForDate(reference, timeframe) })) ) const total = allFrames.length /** * call API for info */ const allInfo = await allFrames.reduce(async (prev, frame, index) => { const accumulatedMap = await prev progres(index, total) // await delay() const previous = options.compareWithPrevious ? (await api.getMonitor(token, { timeframe: frame.timeframe, which: frame.moment.previous })) : undefined if (previous && previous.type === "fail" && options.endOnFirstFail) { throw TalerError.fromUncheckedDetail(previous.detail) } const current = await api.getMonitor(token, { timeframe: frame.timeframe, which: frame.moment.current }) if (current.type === "fail" && options.endOnFirstFail) { throw TalerError.fromUncheckedDetail(current.detail) } const metricName = TalerCorebankApi.MonitorTimeframeParam[allMetrics[index]] accumulatedMap[metricName] = { reference: frame.reference, current: current.type !== "ok" ? undefined : current.body, previous: !previous || previous.type !== "ok" ? undefined : previous.body, } return accumulatedMap }, Promise.resolve({} as Record)) progres(total, total) /** * conver into table format * */ const table: Array = []; if (options.includeHeader) { table.push(["date", "metric", "reference", "talerInCount", "talerInVolume", "talerOutCount", "talerOutVolume", "cashinCount", "cashinFiatVolume", "cashinRegionalVolume", "cashoutCount", "cashoutFiatVolume", "cashoutRegionalVolume",]) } Object.entries(allInfo).forEach(([name, data]) => { if (data.current) { const row: TableRow = { date: data.reference.getTime(), metric: name, reference: "current", ...dataToRow(data.current) } table.push((Object.values(row) as string[])) } if (data.previous) { const row: TableRow = { date: data.reference.getTime(), metric: name, reference: "previous", ...dataToRow(data.previous) } table.push((Object.values(row) as string[])) } }) const csv = table.reduce((acc, row) => { return acc + row.join(",") + "\n" }, "") return csv } type JustData = Omit, "date">, "reference"> function dataToRow(info: TalerCorebankApi.MonitorResponse): JustData { return { talerInCount: info.talerInCount, talerInVolume: info.talerInVolume, talerOutCount: info.talerOutCount, talerOutVolume: info.talerOutVolume, cashinCount: info.type === "no-conversions" ? undefined : info.cashinCount, cashinFiatVolume: info.type === "no-conversions" ? undefined : info.cashinFiatVolume, cashinRegionalVolume: info.type === "no-conversions" ? undefined : info.cashinRegionalVolume, cashoutCount: info.type === "no-conversions" ? undefined : info.cashoutCount, cashoutFiatVolume: info.type === "no-conversions" ? undefined : info.cashoutFiatVolume, cashoutRegionalVolume: info.type === "no-conversions" ? undefined : info.cashoutRegionalVolume, } } type Data = { reference: Date, previous: TalerCorebankApi.MonitorResponse | undefined; current: TalerCorebankApi.MonitorResponse | undefined; } type TableRow = { date: number, metric: string, reference: "current" | "previous", cashinCount?: number; cashinRegionalVolume?: AmountString; cashinFiatVolume?: AmountString; cashoutCount?: number; cashoutRegionalVolume?: AmountString; cashoutFiatVolume?: AmountString; talerInCount: number; talerInVolume: AmountString; talerOutCount: number; talerOutVolume: AmountString; } async function delay() { return new Promise(res => { setTimeout(( )=> { res(null) }, 500) }) }