taler-typescript-core

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

commit 868f4b92a3a147916f0a0f37a22282e9352c2e70
parent d072cf6369a355627a97f0fff8ba3fade947eca0
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Fri, 23 Jan 2026 10:31:40 -0300

fix #10907

Diffstat:
Mpackages/merchant-backoffice-ui/src/components/menu/SideBar.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/hooks/instance.ts | 21+--------------------
Mpackages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.tsx | 10+++++++++-
Mpackages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx | 28++++++++++++++++------------
Mpackages/taler-harness/src/integrationtests/test-merchant-bank-bad-wire-target.ts | 46++++++++++++++++++----------------------------
Mpackages/taler-util/src/http-client/merchant.ts | 13+------------
Mpackages/taler-util/src/types-taler-merchant.ts | 3+++
7 files changed, 49 insertions(+), 74 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx @@ -277,7 +277,7 @@ export function Sidebar({ mobile }: Props): VNode { : simplifiedKycStatus === MerchantAccountKycStatusSimplified.ERROR ? { - backgroundColor: "darkred", + backgroundColor: "#e93c3c", color: "black", } : simplifiedKycStatus === diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts @@ -68,26 +68,6 @@ export function revalidateInstanceKYCDetails() { ); } -/** - * @deprecated use useInstanceKYCDetailsLongPolling - * @returns - */ -export function useInstanceKYCDetails() { - const { state, lib } = useSessionContext(); - - async function fetcher([token]: [AccessToken]) { - return await lib.instance.getCurrentInstanceKycStatus(token, {}); - } - - const { data, error } = useSWR< - TalerMerchantManagementResultByMethod<"getCurrentInstanceKycStatus">, - TalerHttpError - >([state.token, "getCurrentIntanceKycStatus"], fetcher); - - if (data) return data; - if (error) return error; - return undefined; -} // FIXME: move to web-utils and reuse export function useAsyncWithRetry<Res>( @@ -240,6 +220,7 @@ function getLongPollingReason( case MerchantAccountKycStatus.EXCHANGE_INTERNAL_ERROR: case MerchantAccountKycStatus.EXCHANGE_GATEWAY_TIMEOUT: case MerchantAccountKycStatus.EXCHANGE_UNREACHABLE: + case MerchantAccountKycStatus.UNSUPPORTED_ACCOUNT: case MerchantAccountKycStatus.EXCHANGE_STATUS_INVALID: case MerchantAccountKycStatus.MERCHANT_INTERNAL_ERROR: return undefined; diff --git a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.tsx @@ -134,7 +134,7 @@ function PendingTable({ return <i18n.Translate>Warning</i18n.Translate>; case TalerMerchantApi.MerchantAccountKycStatusSimplified .ERROR: - return <i18n.Translate>Error</i18n.Translate>; + return <span style={{color:"#e93c3c", fontWeight: "bold"}}><i18n.Translate>Error</i18n.Translate></span>; default: assertUnreachable(st); } @@ -225,6 +225,14 @@ function PendingTable({ administrator or check again later. </i18n.Translate> ); + case TalerMerchantApi.MerchantAccountKycStatus + .UNSUPPORTED_ACCOUNT: + return ( + <i18n.Translate> + Payment service provider can't make a wire transfer + to this account. + </i18n.Translate> + ); default: assertUnreachable(e.status); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx @@ -65,18 +65,6 @@ export default function ListKYC(_p: Props): VNode { case HttpStatusCode.GatewayTimeout: { return <div />; } - case HttpStatusCode.BadGateway: { - break; - // return ( - // <ListPage - // status={result.body} - // onGetInfo={_p.onGetInfo} - // onShowInstructions={() => { - // setShowingInstructions(true) - // }} - // /> - // ); - } case HttpStatusCode.ServiceUnavailable: { return <div />; } @@ -348,6 +336,22 @@ function ShowInstructionForKycRedirect({ </ConfirmModal> ); } + case TalerMerchantApi.MerchantAccountKycStatus.UNSUPPORTED_ACCOUNT: { + return ( + <ConfirmModal + label={i18n.str`Ok`} + description={i18n.str`Unsupported account`} + active + onCancel={onCancel} + > + <p style={{ paddingTop: 0 }}> + <i18n.Translate> + This exchange does not support the given account. + </i18n.Translate> + </p> + </ConfirmModal> + ); + } case TalerMerchantApi.MerchantAccountKycStatus.EXCHANGE_STATUS_INVALID: { return ( diff --git a/packages/taler-harness/src/integrationtests/test-merchant-bank-bad-wire-target.ts b/packages/taler-harness/src/integrationtests/test-merchant-bank-bad-wire-target.ts @@ -22,6 +22,7 @@ import { AmountString, Duration, PreparePayResultType, + TalerExchangeHttpClient, TalerMerchantApi, TalerMerchantInstanceHttpClient, j2s, @@ -60,41 +61,30 @@ export async function runMerchantBankBadWireTargetTest(t: GlobalTestState) { { adminAccessToken: merchantAdminAccessToken }, ); - // Order that can only be paid within five minutes. - const order: TalerMerchantApi.Order = { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "taler://fulfillment-success/thx", - pay_deadline: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.addDuration( - AbsoluteTime.now(), - Duration.fromSpec({ minutes: 5 }), - ), - ), - refund_deadline: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.zero()), - wire_transfer_deadline: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.addDuration( - AbsoluteTime.now(), - Duration.fromSpec({ minutes: 10 }), - ), - ), - }; + const exchangeClient = new TalerExchangeHttpClient(exchange.baseUrl); + + const keys = succeedOrThrow(await exchangeClient.getKeys()) + // KYC should be disabled + t.assertTrue(!keys.kyc_enabled) + const merchantClient = new TalerMerchantInstanceHttpClient( merchant.makeInstanceBaseUrl("minst2"), ); - const orderResp = succeedOrThrow( - await merchantClient.createOrder(accessToken, { - order, - }), - ); + const kycStatus = + succeedOrThrow<TalerMerchantApi.MerchantAccountKycRedirectsResponse | void>( + await merchantClient.getCurrentInstanceKycStatus(accessToken), + ); - let orderStatus = succeedOrThrow( - await merchantClient.getOrderDetails(accessToken, orderResp.order_id), - ); + t.assertTrue(!!kycStatus); - t.assertTrue(orderStatus.order_status === "unpaid"); + console.log(j2s(kycStatus)); + t.assertTrue(kycStatus.kyc_data.length === 1); + t.assertTrue( + kycStatus.kyc_data[0].status === + TalerMerchantApi.MerchantAccountKycStatus.UNSUPPORTED_ACCOUNT, + ); } runMerchantBankBadWireTargetTest.suites = ["merchant"]; diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts @@ -783,18 +783,7 @@ export class TalerMerchantInstanceHttpClient { async getCurrentInstanceKycStatus( token: AccessToken, params: TalerMerchantApi.GetKycStatusRequestParams = {}, - ): Promise< - | OperationOk<TalerMerchantApi.MerchantAccountKycRedirectsResponse> - | OperationOk<void> - | OperationAlternative< - HttpStatusCode.BadGateway, - TalerMerchantApi.MerchantAccountKycRedirectsResponse - > - | OperationFail<HttpStatusCode.Unauthorized> - | OperationFail<HttpStatusCode.NotFound> - | OperationFail<HttpStatusCode.ServiceUnavailable> - | OperationFail<HttpStatusCode.GatewayTimeout> - > { + ) { const url = new URL(`private/kyc`, this.baseUrl); if (params.wireHash) { diff --git a/packages/taler-util/src/types-taler-merchant.ts b/packages/taler-util/src/types-taler-merchant.ts @@ -2087,6 +2087,7 @@ export interface MerchantAccountKycRedirectsResponse { export enum MerchantAccountKycStatus { NO_EXCHANGE_KEY = "no-exchange-keys", + UNSUPPORTED_ACCOUNT = "unsupported-account", KYC_WIRE_IMPOSSIBLE = "kyc-wire-impossible", KYC_WIRE_REQUIRED = "kyc-wire-required", KYC_REQUIRED = "kyc-required", @@ -2129,6 +2130,7 @@ export function getMerchantAccountKycStatusSimplified( case MerchantAccountKycStatus.KYC_WIRE_IMPOSSIBLE: case MerchantAccountKycStatus.LOGIC_BUG: case MerchantAccountKycStatus.EXCHANGE_STATUS_INVALID: + case MerchantAccountKycStatus.UNSUPPORTED_ACCOUNT: return MerchantAccountKycStatusSimplified.ERROR; default: assertUnreachable(st); @@ -4290,6 +4292,7 @@ export const codecForAccountKycRedirects = export const codecForMerchantAccountKycStatus = codecForEither( codecForConstString(MerchantAccountKycStatus.AWAITING_AML_REVIEW), + codecForConstString(MerchantAccountKycStatus.UNSUPPORTED_ACCOUNT), codecForConstString(MerchantAccountKycStatus.EXCHANGE_GATEWAY_TIMEOUT), codecForConstString(MerchantAccountKycStatus.EXCHANGE_INTERNAL_ERROR), codecForConstString(MerchantAccountKycStatus.EXCHANGE_STATUS_INVALID),