fix wallet DB

This commit is contained in:
Florian Dold 2020-08-24 20:00:15 +05:30
parent 0e88ef9bd2
commit 7deefd5b2d
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
5 changed files with 185 additions and 27 deletions

View File

@ -17,35 +17,41 @@
/** /**
* Imports. * Imports.
*/ */
import { runTest, GlobalTestState, MerchantPrivateApi } from "./harness"; import {
import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers"; runTest,
GlobalTestState,
MerchantPrivateApi,
MerchantService,
BankServiceInterface,
MerchantServiceInterface,
WalletCli,
ExchangeServiceInterface,
} from "./harness";
import {
createSimpleTestkudosEnvironment,
withdrawViaBank,
SimpleTestEnvironment,
} from "./helpers";
import { PreparePayResultType, URL } from "taler-wallet-core"; import { PreparePayResultType, URL } from "taler-wallet-core";
import axios from "axios"; import axios from "axios";
/** async function testRefundApiWithFulfillmentUrl(
* Test case for the refund API of the merchant backend. t: GlobalTestState,
*/ env: {
runTest(async (t: GlobalTestState) => { merchant: MerchantServiceInterface;
// Set up test environment bank: BankServiceInterface;
wallet: WalletCli;
const { exchange: ExchangeServiceInterface;
wallet, },
bank, ): Promise<void> {
exchange, const { wallet, bank, exchange, merchant } = env;
merchant,
} = await createSimpleTestkudosEnvironment(t);
// Withdraw digital cash into the wallet.
await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
// Set up order. // Set up order.
const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", { const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
order: { order: {
summary: "Buy me!", summary: "Buy me!",
amount: "TESTKUDOS:5", amount: "TESTKUDOS:5",
fulfillment_url: "taler://fulfillment-success/thx", fulfillment_url: "https://example.com/fulfillment",
}, },
}); });
@ -131,7 +137,150 @@ runTest(async (t: GlobalTestState) => {
publicOrderStatusResp = await axios.get(publicOrderStatusUrl.href, { publicOrderStatusResp = await axios.get(publicOrderStatusUrl.href, {
validateStatus: () => true, validateStatus: () => true,
}); });
console.log(publicOrderStatusResp.data) console.log(publicOrderStatusResp.data);
// We didn't give any authentication, so this should be forbidden // We didn't give any authentication, so we should get a fulfillment URL back
t.assertTrue(publicOrderStatusResp.status === 403); t.assertTrue(publicOrderStatusResp.status === 202);
const fu = publicOrderStatusResp.data.fulfillment_url;
t.assertTrue(typeof fu === "string" && fu.startsWith("https://example.com"));
}
async function testRefundApiWithFulfillmentMessage(
t: GlobalTestState,
env: {
merchant: MerchantServiceInterface;
bank: BankServiceInterface;
wallet: WalletCli;
exchange: ExchangeServiceInterface;
},
): Promise<void> {
const { wallet, bank, exchange, merchant } = env;
// Set up order.
const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
order: {
summary: "Buy me!",
amount: "TESTKUDOS:5",
fulfillment_message: "Thank you for buying foobar",
},
});
let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
orderId: orderResp.order_id,
});
t.assertTrue(orderStatus.order_status === "unpaid");
const talerPayUri = orderStatus.taler_pay_uri;
const orderId = orderResp.order_id;
// Make wallet pay for the order
let preparePayResult = await wallet.preparePay({
talerPayUri,
});
t.assertTrue(
preparePayResult.status === PreparePayResultType.PaymentPossible,
);
const r2 = await wallet.apiRequest("confirmPay", {
proposalId: preparePayResult.proposalId,
});
t.assertTrue(r2.type === "response");
// Check if payment was successful.
orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
orderId: orderResp.order_id,
});
t.assertTrue(orderStatus.order_status === "paid");
preparePayResult = await wallet.preparePay({
talerPayUri,
});
t.assertTrue(
preparePayResult.status === PreparePayResultType.AlreadyConfirmed,
);
await MerchantPrivateApi.giveRefund(merchant, {
amount: "TESTKUDOS:5",
instance: "default",
justification: "foo",
orderId: orderResp.order_id,
});
orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
orderId: orderResp.order_id,
});
t.assertTrue(orderStatus.order_status === "paid");
t.assertAmountEquals(orderStatus.refund_amount, "TESTKUDOS:5");
// Now test what the merchant gives as a response for various requests to the
// public order status URL!
let publicOrderStatusUrl = new URL(
`orders/${orderId}`,
merchant.makeInstanceBaseUrl(),
);
publicOrderStatusUrl.searchParams.set(
"h_contract",
preparePayResult.contractTermsHash,
);
let publicOrderStatusResp = await axios.get(publicOrderStatusUrl.href, {
validateStatus: () => true,
});
console.log(publicOrderStatusResp.data);
t.assertTrue(publicOrderStatusResp.status === 200);
t.assertAmountEquals(publicOrderStatusResp.data.refund_amount, "TESTKUDOS:5");
publicOrderStatusUrl = new URL(
`orders/${orderId}`,
merchant.makeInstanceBaseUrl(),
);
publicOrderStatusResp = await axios.get(publicOrderStatusUrl.href, {
validateStatus: () => true,
});
console.log(publicOrderStatusResp.data);
// We didn't give any authentication, so we should get a fulfillment URL back
t.assertTrue(publicOrderStatusResp.status === 202);
const fu = publicOrderStatusResp.data.fulfillment_message;
t.assertTrue(typeof fu === "string" && fu.startsWith("Thank you"));
}
/**
* Test case for the refund API of the merchant backend.
*/
runTest(async (t: GlobalTestState) => {
// Set up test environment
const {
wallet,
bank,
exchange,
merchant,
} = await createSimpleTestkudosEnvironment(t);
// Withdraw digital cash into the wallet.
await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
await testRefundApiWithFulfillmentUrl(t, {
wallet,
bank,
exchange,
merchant,
});
await testRefundApiWithFulfillmentMessage(t, {
wallet,
bank,
exchange,
merchant,
});
}); });

View File

@ -8,7 +8,7 @@ import { IDBFactory, IDBDatabase } from "idb-bridge";
* with each major change. When incrementing the major version, * with each major change. When incrementing the major version,
* the wallet should import data from the previous version. * the wallet should import data from the previous version.
*/ */
const TALER_DB_NAME = "taler-walletdb-v7"; const TALER_DB_NAME = "taler-walletdb-v8";
/** /**
* Current database minor version, should be incremented * Current database minor version, should be incremented

View File

@ -686,7 +686,7 @@ async function processDownloadProposalImpl(
contractData: { contractData: {
amount, amount,
contractTermsHash: contractTermsHash, contractTermsHash: contractTermsHash,
fulfillmentUrl: parsedContractTerms.fulfillment_url, fulfillmentUrl: parsedContractTerms.fulfillment_url ?? "",
merchantBaseUrl: parsedContractTerms.merchant_base_url, merchantBaseUrl: parsedContractTerms.merchant_base_url,
merchantPub: parsedContractTerms.merchant_pub, merchantPub: parsedContractTerms.merchant_pub,
merchantSig: proposalResp.sig, merchantSig: proposalResp.sig,

View File

@ -235,7 +235,6 @@ export async function getTransactions(
return; return;
} }
const info: OrderShortInfo = { const info: OrderShortInfo = {
fulfillmentUrl: pr.contractData.fulfillmentUrl,
merchant: pr.contractData.merchant, merchant: pr.contractData.merchant,
orderId: pr.contractData.orderId, orderId: pr.contractData.orderId,
products: pr.contractData.products, products: pr.contractData.products,
@ -243,6 +242,9 @@ export async function getTransactions(
summary_i18n: pr.contractData.summaryI18n, summary_i18n: pr.contractData.summaryI18n,
contractTermsHash: pr.contractData.contractTermsHash, contractTermsHash: pr.contractData.contractTermsHash,
}; };
if (pr.contractData.fulfillmentUrl !== "") {
info.fulfillmentUrl = pr.contractData.fulfillmentUrl;
}
const paymentTransactionId = makeEventId( const paymentTransactionId = makeEventId(
TransactionType.Payment, TransactionType.Payment,
pr.proposalId, pr.proposalId,

View File

@ -1271,7 +1271,14 @@ export interface AllowedExchangeInfo {
export interface WalletContractData { export interface WalletContractData {
products?: Product[]; products?: Product[];
summaryI18n: { [lang_tag: string]: string } | undefined; summaryI18n: { [lang_tag: string]: string } | undefined;
fulfillmentUrl?: string;
/**
* Fulfillment URL, or the empty string if the order has no fulfillment URL.
*
* Stored as a non-nullable string as we use this field for IndexedDB indexing.
*/
fulfillmentUrl: string;
contractTermsHash: string; contractTermsHash: string;
fulfillmentMessage?: string; fulfillmentMessage?: string;
fulfillmentMessageI18n?: InternationalizedString; fulfillmentMessageI18n?: InternationalizedString;