updated preparePay API according to spec
This commit is contained in:
parent
86fd5f2440
commit
43655adff0
@ -550,7 +550,7 @@ export enum TalerErrorCode {
|
||||
DEPOSIT_INVALID_WIRE_FORMAT_JSON = 1210,
|
||||
|
||||
/**
|
||||
* The hash of the given wire address does not match the hash specified in the proposal data.
|
||||
* The hash of the given wire address does not match the wire hash specified in the proposal data.
|
||||
* Returned with an HTTP status code of #MHD_HTTP_BAD_REQUEST (400).
|
||||
* (A value of 0 indicates that the error is generated client-side).
|
||||
*/
|
||||
@ -1403,6 +1403,13 @@ export enum TalerErrorCode {
|
||||
*/
|
||||
PAY_EXCHANGE_FAILED = 2135,
|
||||
|
||||
/**
|
||||
* The merchant backend couldn't verify the order payment because of a database failure.
|
||||
* Returned with an HTTP status code of #MHD_HTTP_INTERNAL_SERVER_ERROR (500).
|
||||
* (A value of 0 indicates that the error is generated client-side).
|
||||
*/
|
||||
PAID_DB_ERROR = 2146,
|
||||
|
||||
/**
|
||||
* The order is not known.
|
||||
* Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404).
|
||||
@ -2677,6 +2684,13 @@ export enum TalerErrorCode {
|
||||
*/
|
||||
MERCHANT_ORDER_GET_REPLY_MALFORMED = 2922,
|
||||
|
||||
/**
|
||||
* The token used to authenticate the client is invalid for this order.
|
||||
* Returned with an HTTP status code of #MHD_HTTP_FORBIDDEN (403).
|
||||
* (A value of 0 indicates that the error is generated client-side).
|
||||
*/
|
||||
MERCHANT_GET_ORDER_INVALID_TOKEN = 2923,
|
||||
|
||||
/**
|
||||
* The signature from the exchange on the deposit confirmation is invalid. Returned with a "400 Bad Request" status code.
|
||||
* Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0).
|
||||
@ -3062,6 +3076,13 @@ export enum TalerErrorCode {
|
||||
*/
|
||||
WALLET_CORE_API_OPERATION_UNKNOWN = 7007,
|
||||
|
||||
/**
|
||||
* The given taler://pay URI is invalid.
|
||||
* Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0).
|
||||
* (A value of 0 indicates that the error is generated client-side).
|
||||
*/
|
||||
WALLET_INVALID_TALER_PAY_URI = 7008,
|
||||
|
||||
/**
|
||||
* The exchange does not know about the reserve (yet), and thus withdrawal can't progress.
|
||||
* Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404).
|
||||
|
@ -43,6 +43,7 @@ import { NodeHttpLib } from "./NodeHttpLib";
|
||||
import * as nacl from "../crypto/primitives/nacl-fast";
|
||||
import { addPaytoQueryParams } from "../util/payto";
|
||||
import { handleCoreApiRequest } from "../walletCoreApiHandler";
|
||||
import { PreparePayResultType } from "../types/walletTypes";
|
||||
|
||||
const logger = new Logger("taler-wallet-cli.ts");
|
||||
|
||||
@ -58,19 +59,19 @@ async function doPay(
|
||||
options: { alwaysYes: boolean } = { alwaysYes: true },
|
||||
): Promise<void> {
|
||||
const result = await wallet.preparePayForUri(payUrl);
|
||||
if (result.status === "error") {
|
||||
console.error("Could not pay:", result.error);
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
if (result.status === "insufficient-balance") {
|
||||
if (result.status === PreparePayResultType.InsufficientBalance) {
|
||||
console.log("contract", result.contractTermsRaw);
|
||||
console.error("insufficient balance");
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
if (result.status === "paid") {
|
||||
console.log("already paid!");
|
||||
if (result.status === PreparePayResultType.AlreadyConfirmed) {
|
||||
if (result.paid) {
|
||||
console.log("already paid!");
|
||||
} else {
|
||||
console.log("payment already in progress");
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
return;
|
||||
}
|
||||
@ -502,16 +503,17 @@ advancedCli
|
||||
await withWallet(args, async (wallet) => {
|
||||
const res = await wallet.preparePayForUri(args.payPrepare.url);
|
||||
switch (res.status) {
|
||||
case "error":
|
||||
console.log("error:", res.error);
|
||||
break;
|
||||
case "insufficient-balance":
|
||||
case PreparePayResultType.InsufficientBalance:
|
||||
console.log("insufficient balance");
|
||||
break;
|
||||
case "paid":
|
||||
console.log("already paid");
|
||||
case PreparePayResultType.AlreadyConfirmed:
|
||||
if (res.paid) {
|
||||
console.log("already paid!");
|
||||
} else {
|
||||
console.log("payment in progress");
|
||||
}
|
||||
break;
|
||||
case "payment-possible":
|
||||
case PreparePayResultType.PaymentPossible:
|
||||
console.log("payment possible");
|
||||
break;
|
||||
default:
|
||||
|
@ -48,19 +48,19 @@ import {
|
||||
OperationErrorDetails,
|
||||
PreparePayResult,
|
||||
RefreshReason,
|
||||
PreparePayResultType,
|
||||
} from "../types/walletTypes";
|
||||
import * as Amounts from "../util/amounts";
|
||||
import { AmountJson } from "../util/amounts";
|
||||
import { Logger } from "../util/logging";
|
||||
import { parsePayUri } from "../util/taleruri";
|
||||
import { guardOperationException } from "./errors";
|
||||
import { guardOperationException, OperationFailedError } from "./errors";
|
||||
import { createRefreshGroup, getTotalRefreshCost } from "./refresh";
|
||||
import { InternalWalletState } from "./state";
|
||||
import { getTimestampNow, timestampAddDuration } from "../util/time";
|
||||
import { strcmp, canonicalJson } from "../util/helpers";
|
||||
import {
|
||||
readSuccessResponseJsonOrThrow,
|
||||
} from "../util/http";
|
||||
import { readSuccessResponseJsonOrThrow } from "../util/http";
|
||||
import { TalerErrorCode } from "../TalerErrorCode";
|
||||
|
||||
/**
|
||||
* Logger.
|
||||
@ -783,7 +783,7 @@ export async function submitPay(
|
||||
coins: purchase.coinDepositPermissions,
|
||||
session_id: purchase.lastSessionId,
|
||||
};
|
||||
|
||||
|
||||
logger.trace("making pay request", JSON.stringify(reqBody, undefined, 2));
|
||||
|
||||
const resp = await ws.http.postJson(payUrl, reqBody);
|
||||
@ -860,10 +860,13 @@ export async function preparePayForUri(
|
||||
const uriResult = parsePayUri(talerPayUri);
|
||||
|
||||
if (!uriResult) {
|
||||
return {
|
||||
status: "error",
|
||||
error: "URI not supported",
|
||||
};
|
||||
throw OperationFailedError.fromCode(
|
||||
TalerErrorCode.WALLET_INVALID_TALER_PAY_URI,
|
||||
`invalid taler://pay URI (${talerPayUri})`,
|
||||
{
|
||||
talerPayUri,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let proposalId = await startDownloadProposal(
|
||||
@ -911,7 +914,7 @@ export async function preparePayForUri(
|
||||
if (!res) {
|
||||
console.log("not confirming payment, insufficient coins");
|
||||
return {
|
||||
status: "insufficient-balance",
|
||||
status: PreparePayResultType.InsufficientBalance,
|
||||
contractTermsRaw: d.contractTermsRaw,
|
||||
proposalId: proposal.proposalId,
|
||||
};
|
||||
@ -923,14 +926,14 @@ export async function preparePayForUri(
|
||||
const totalFees = Amounts.sub(costInfo.totalCost, res.paymentAmount).amount;
|
||||
|
||||
return {
|
||||
status: "payment-possible",
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
contractTermsRaw: d.contractTermsRaw,
|
||||
proposalId: proposal.proposalId,
|
||||
totalFees,
|
||||
};
|
||||
}
|
||||
|
||||
if (uriResult.sessionId && purchase.lastSessionId !== uriResult.sessionId) {
|
||||
if (purchase.lastSessionId !== uriResult.sessionId) {
|
||||
console.log(
|
||||
"automatically re-submitting payment with different session ID",
|
||||
);
|
||||
@ -942,14 +945,28 @@ export async function preparePayForUri(
|
||||
p.lastSessionId = uriResult.sessionId;
|
||||
await tx.put(Stores.purchases, p);
|
||||
});
|
||||
await submitPay(ws, proposalId);
|
||||
const r = await submitPay(ws, proposalId);
|
||||
return {
|
||||
status: PreparePayResultType.AlreadyConfirmed,
|
||||
contractTermsRaw: purchase.contractTermsRaw,
|
||||
paid: true,
|
||||
nextUrl: r.nextUrl,
|
||||
};
|
||||
} else if (!purchase.timestampFirstSuccessfulPay) {
|
||||
return {
|
||||
status: PreparePayResultType.AlreadyConfirmed,
|
||||
contractTermsRaw: purchase.contractTermsRaw,
|
||||
paid: false,
|
||||
};
|
||||
} else if (purchase.paymentSubmitPending) {
|
||||
return {
|
||||
status: PreparePayResultType.AlreadyConfirmed,
|
||||
contractTermsRaw: purchase.contractTermsRaw,
|
||||
paid: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "paid",
|
||||
contractTermsRaw: purchase.contractTermsRaw,
|
||||
nextUrl: getNextUrl(purchase.contractData),
|
||||
};
|
||||
// FIXME: we don't handle aborted payments correctly here.
|
||||
throw Error("BUG: invariant violation (purchase status)");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -337,34 +337,36 @@ export interface NextUrlResult {
|
||||
lastSessionId: string | undefined;
|
||||
}
|
||||
|
||||
export const enum PreparePayResultType {
|
||||
PaymentPossible = "payment-possible",
|
||||
InsufficientBalance = "insufficient-balance",
|
||||
AlreadyConfirmed = "already-confirmed",
|
||||
}
|
||||
|
||||
export type PreparePayResult =
|
||||
| PreparePayResultError
|
||||
| PreparePayResultInsufficientBalance
|
||||
| PreparePayResultPaid
|
||||
| PreparePayResultAlreadyConfirmed
|
||||
| PreparePayResultPaymentPossible;
|
||||
|
||||
export interface PreparePayResultPaymentPossible {
|
||||
status: "payment-possible";
|
||||
status: PreparePayResultType.PaymentPossible;
|
||||
proposalId: string;
|
||||
contractTermsRaw: string;
|
||||
totalFees: AmountJson;
|
||||
}
|
||||
|
||||
export interface PreparePayResultInsufficientBalance {
|
||||
status: "insufficient-balance";
|
||||
status: PreparePayResultType.InsufficientBalance;
|
||||
proposalId: string;
|
||||
contractTermsRaw: any;
|
||||
}
|
||||
|
||||
export interface PreparePayResultError {
|
||||
status: "error";
|
||||
error: string;
|
||||
}
|
||||
|
||||
export interface PreparePayResultPaid {
|
||||
status: "paid";
|
||||
export interface PreparePayResultAlreadyConfirmed {
|
||||
status: PreparePayResultType.AlreadyConfirmed;
|
||||
contractTermsRaw: any;
|
||||
nextUrl: string;
|
||||
paid: boolean;
|
||||
// Only specified if paid.
|
||||
nextUrl?: string;
|
||||
}
|
||||
|
||||
export interface BankWithdrawDetails {
|
||||
|
@ -24,7 +24,7 @@
|
||||
*/
|
||||
import * as i18n from "../i18n";
|
||||
|
||||
import { PreparePayResult } from "../../types/walletTypes";
|
||||
import { PreparePayResult, PreparePayResultType } from "../../types/walletTypes";
|
||||
|
||||
import { renderAmount, ProgressButton } from "../renderHtml";
|
||||
import * as wxApi from "../wxApi";
|
||||
@ -58,15 +58,11 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }): JSX.Element {
|
||||
insufficientBalance = true;
|
||||
}
|
||||
|
||||
if (payStatus.status === "error") {
|
||||
return <span>Error: {payStatus.error}</span>;
|
||||
}
|
||||
|
||||
if (payStatus.status === "payment-possible") {
|
||||
totalFees = payStatus.totalFees;
|
||||
}
|
||||
|
||||
if (payStatus.status === "paid" && numTries === 0) {
|
||||
if (payStatus.status === PreparePayResultType.AlreadyConfirmed && numTries === 0) {
|
||||
return (
|
||||
<span>
|
||||
You have already paid for this article. Click{" "}
|
||||
|
Loading…
Reference in New Issue
Block a user