implement freezing for payments
This commit is contained in:
parent
408d8e9fc8
commit
a09359bd39
@ -80,6 +80,12 @@ export interface TransactionCommon {
|
||||
// but its transactionId will remain unchanged
|
||||
pending: boolean;
|
||||
|
||||
/**
|
||||
* True if the transaction encountered a problem that might be
|
||||
* permanent. A frozen transaction won't be automatically retried.
|
||||
*/
|
||||
frozen: boolean;
|
||||
|
||||
// Raw amount of the transaction (exclusive of fees or other extra costs)
|
||||
amountRaw: AmountString;
|
||||
|
||||
|
@ -112,13 +112,6 @@ export async function runDenomUnofferedTest(t: GlobalTestState) {
|
||||
merchantErrorCode,
|
||||
TalerErrorCode.MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND,
|
||||
);
|
||||
|
||||
const purchId = makeEventId(TransactionType.Payment, preparePayResult.proposalId);
|
||||
await wallet.client.call(WalletApiOperation.DeleteTransaction, {
|
||||
transactionId: purchId,
|
||||
});
|
||||
|
||||
// Now, delete the purchase and refresh operation.
|
||||
}
|
||||
|
||||
await wallet.client.call(WalletApiOperation.AddExchange, {
|
||||
|
@ -1276,6 +1276,12 @@ export interface PurchaseRecord {
|
||||
* Continue querying the refund status until this deadline has expired.
|
||||
*/
|
||||
autoRefundDeadline: Timestamp | undefined;
|
||||
|
||||
/**
|
||||
* Is the payment frozen? I.e. did we encounter
|
||||
* an error where it doesn't make sense to retry.
|
||||
*/
|
||||
payFrozen?: boolean;
|
||||
}
|
||||
|
||||
export const WALLET_BACKUP_STATE_KEY = "walletBackupState";
|
||||
|
@ -93,6 +93,7 @@ import {
|
||||
readSuccessResponseJsonOrErrorCode,
|
||||
readSuccessResponseJsonOrThrow,
|
||||
readTalerErrorResponse,
|
||||
readUnexpectedResponseDetails,
|
||||
throwUnexpectedRequestError,
|
||||
} from "../util/http.js";
|
||||
import {
|
||||
@ -1209,6 +1210,26 @@ async function submitPay(
|
||||
};
|
||||
}
|
||||
|
||||
if (resp.status === HttpResponseStatus.BadRequest) {
|
||||
const errDetails = await readUnexpectedResponseDetails(resp);
|
||||
logger.warn("unexpected 400 response for /pay");
|
||||
logger.warn(j2s(errDetails));
|
||||
await ws.db
|
||||
.mktx((x) => ({ purchases: x.purchases }))
|
||||
.runReadWrite(async (tx) => {
|
||||
const purch = await tx.purchases.get(proposalId);
|
||||
if (!purch) {
|
||||
return;
|
||||
}
|
||||
purch.payFrozen = true;
|
||||
purch.lastPayError = errDetails;
|
||||
delete purch.payRetryInfo;
|
||||
await tx.purchases.put(purch);
|
||||
});
|
||||
// FIXME: Maybe introduce a new return type for this instead of throwing?
|
||||
throw new OperationFailedAndReportedError(errDetails);
|
||||
}
|
||||
|
||||
if (resp.status === HttpResponseStatus.Conflict) {
|
||||
const err = await readTalerErrorResponse(resp);
|
||||
if (
|
||||
|
@ -235,7 +235,11 @@ async function gatherPurchasePending(
|
||||
resp: PendingOperationsResponse,
|
||||
): Promise<void> {
|
||||
await tx.purchases.iter().forEach((pr) => {
|
||||
if (pr.paymentSubmitPending && pr.abortStatus === AbortStatus.None) {
|
||||
if (
|
||||
pr.paymentSubmitPending &&
|
||||
pr.abortStatus === AbortStatus.None &&
|
||||
!pr.payFrozen
|
||||
) {
|
||||
const timestampDue = pr.payRetryInfo?.nextRetry ?? getTimestampNow();
|
||||
resp.pendingOperations.push({
|
||||
type: PendingTaskType.Pay,
|
||||
|
@ -168,6 +168,7 @@ export async function getTransactions(
|
||||
TransactionType.Withdrawal,
|
||||
wsr.withdrawalGroupId,
|
||||
),
|
||||
frozen: false,
|
||||
...(wsr.lastError ? { error: wsr.lastError } : {}),
|
||||
});
|
||||
});
|
||||
@ -215,6 +216,7 @@ export async function getTransactions(
|
||||
TransactionType.Withdrawal,
|
||||
r.initialWithdrawalGroupId,
|
||||
),
|
||||
frozen: false,
|
||||
...(r.lastError ? { error: r.lastError } : {}),
|
||||
});
|
||||
});
|
||||
@ -230,6 +232,7 @@ export async function getTransactions(
|
||||
amountRaw: Amounts.stringify(dg.effectiveDepositAmount),
|
||||
amountEffective: Amounts.stringify(dg.totalPayCost),
|
||||
pending: !dg.timestampFinished,
|
||||
frozen: false,
|
||||
timestamp: dg.timestampCreated,
|
||||
targetPaytoUri: dg.wire.payto_uri,
|
||||
transactionId: makeEventId(
|
||||
@ -288,6 +291,7 @@ export async function getTransactions(
|
||||
transactionId: paymentTransactionId,
|
||||
proposalId: pr.proposalId,
|
||||
info: info,
|
||||
frozen: pr.payFrozen ?? false,
|
||||
...(err ? { error: err } : {}),
|
||||
});
|
||||
|
||||
@ -351,6 +355,7 @@ export async function getTransactions(
|
||||
amountEffective: Amounts.stringify(amountEffective),
|
||||
amountRaw: Amounts.stringify(amountRaw),
|
||||
pending: false,
|
||||
frozen: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -372,6 +377,7 @@ export async function getTransactions(
|
||||
amountEffective: Amounts.stringify(tipRecord.tipAmountEffective),
|
||||
amountRaw: Amounts.stringify(tipRecord.tipAmountRaw),
|
||||
pending: !tipRecord.pickedUpTimestamp,
|
||||
frozen: false,
|
||||
timestamp: tipRecord.acceptedTimestamp,
|
||||
transactionId: makeEventId(
|
||||
TransactionType.Tip,
|
||||
|
@ -64,6 +64,7 @@ export enum HttpResponseStatus {
|
||||
NoContent = 204,
|
||||
Gone = 210,
|
||||
NotModified = 304,
|
||||
BadRequest = 400,
|
||||
PaymentRequired = 402,
|
||||
NotFound = 404,
|
||||
Conflict = 409,
|
||||
|
Loading…
Reference in New Issue
Block a user