commit 868f4b92a3a147916f0a0f37a22282e9352c2e70
parent d072cf6369a355627a97f0fff8ba3fade947eca0
Author: Sebastian <sebasjm@taler-systems.com>
Date: Fri, 23 Jan 2026 10:31:40 -0300
fix #10907
Diffstat:
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),