wallet-core: return pending status instead of error
This allows clients to get the transaction ID of the confirmed payment.
This commit is contained in:
parent
72ca5ee8dd
commit
cbf848dd2a
@ -18,7 +18,7 @@
|
|||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { PreparePayResultType, TalerErrorCode } from "@gnu-taler/taler-util";
|
import { PreparePayResultType, TalerErrorCode } from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { Wallet, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { GlobalTestState, MerchantPrivateApi } from "../harness/harness.js";
|
import { GlobalTestState, MerchantPrivateApi } from "../harness/harness.js";
|
||||||
import {
|
import {
|
||||||
createSimpleTestkudosEnvironment,
|
createSimpleTestkudosEnvironment,
|
||||||
@ -55,7 +55,6 @@ export async function runDenomUnofferedTest(t: GlobalTestState) {
|
|||||||
fulfillment_url: "taler://fulfillment-success/thx",
|
fulfillment_url: "taler://fulfillment-success/thx",
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
|
||||||
const orderResp = await MerchantPrivateApi.createOrder(
|
const orderResp = await MerchantPrivateApi.createOrder(
|
||||||
merchant,
|
merchant,
|
||||||
"default",
|
"default",
|
||||||
@ -86,34 +85,34 @@ export async function runDenomUnofferedTest(t: GlobalTestState) {
|
|||||||
preparePayResult.status === PreparePayResultType.PaymentPossible,
|
preparePayResult.status === PreparePayResultType.PaymentPossible,
|
||||||
);
|
);
|
||||||
|
|
||||||
const exc = await t.assertThrowsTalerErrorAsync(async () => {
|
const confirmResp = await wallet.client.call(WalletApiOperation.ConfirmPay, {
|
||||||
await wallet.client.call(WalletApiOperation.ConfirmPay, {
|
proposalId: preparePayResult.proposalId,
|
||||||
proposalId: preparePayResult.proposalId,
|
});
|
||||||
});
|
|
||||||
|
const tx = await wallet.client.call(WalletApiOperation.GetTransactionById, {
|
||||||
|
transactionId: confirmResp.transactionId,
|
||||||
});
|
});
|
||||||
|
|
||||||
t.assertTrue(
|
t.assertTrue(
|
||||||
exc.hasErrorCode(TalerErrorCode.WALLET_PENDING_OPERATION_FAILED),
|
tx.error?.code === TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME: We might want a more specific error code here!
|
const merchantErrorCode = ((tx.error as any).errorResponse as any)
|
||||||
t.assertDeepEqual(
|
|
||||||
exc.errorDetail.innerError.code,
|
|
||||||
TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
|
|
||||||
);
|
|
||||||
const merchantErrorCode = (exc.errorDetail.innerError.errorResponse as any)
|
|
||||||
.code;
|
.code;
|
||||||
t.assertDeepEqual(
|
t.assertDeepEqual(
|
||||||
merchantErrorCode,
|
merchantErrorCode,
|
||||||
TalerErrorCode.MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND,
|
TalerErrorCode.MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
await wallet.client.call(WalletApiOperation.AddExchange, {
|
await wallet.client.call(WalletApiOperation.AddExchange, {
|
||||||
exchangeBaseUrl: exchange.baseUrl,
|
exchangeBaseUrl: exchange.baseUrl,
|
||||||
forceUpdate: true,
|
forceUpdate: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await wallet.client.call(WalletApiOperation.DeleteTransaction, {
|
||||||
|
transactionId: confirmResp.transactionId,
|
||||||
|
});
|
||||||
|
|
||||||
// Now withdrawal should work again.
|
// Now withdrawal should work again.
|
||||||
await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
|
await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
|
||||||
|
|
||||||
|
@ -1625,28 +1625,11 @@ export async function runPayForConfirmPay(
|
|||||||
.runReadOnly(async (tx) =>
|
.runReadOnly(async (tx) =>
|
||||||
tx.operationRetries.get(RetryTags.byPaymentProposalId(proposalId)),
|
tx.operationRetries.get(RetryTags.byPaymentProposalId(proposalId)),
|
||||||
);
|
);
|
||||||
const maxRetry = 3;
|
return {
|
||||||
const numRetry = opRetry?.retryInfo.retryCounter ?? 0;
|
type: ConfirmPayResultType.Pending,
|
||||||
if (
|
lastError: opRetry?.lastError,
|
||||||
res.errorDetail.code ===
|
transactionId: makeTransactionId(TransactionType.Payment, proposalId),
|
||||||
TalerErrorCode.WALLET_PAY_MERCHANT_SERVER_ERROR &&
|
};
|
||||||
numRetry < maxRetry
|
|
||||||
) {
|
|
||||||
logger.trace("hiding transient error from caller");
|
|
||||||
// Pretend the operation is pending instead of reporting
|
|
||||||
// an error, but only up to maxRetry attempts.
|
|
||||||
await storeOperationPending(
|
|
||||||
ws,
|
|
||||||
RetryTags.byPaymentProposalId(proposalId),
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
type: ConfirmPayResultType.Pending,
|
|
||||||
lastError: opRetry?.lastError,
|
|
||||||
transactionId: makeTransactionId(TransactionType.Payment, proposalId),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
throw Error("payment failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case OperationAttemptResultType.Pending:
|
case OperationAttemptResultType.Pending:
|
||||||
logger.trace("reporting pending as confirmPay response");
|
logger.trace("reporting pending as confirmPay response");
|
||||||
|
Loading…
Reference in New Issue
Block a user