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:
Florian Dold 2023-01-13 00:31:29 +01:00
parent 72ca5ee8dd
commit cbf848dd2a
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
2 changed files with 18 additions and 36 deletions

View File

@ -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" });

View File

@ -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");