/* This file is part of GNU Taler (C) 2020 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ /** * Imports. */ import { ConfirmPayResultType, PreparePayResultType, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { GlobalTestState, MerchantApiClient } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV2, createWalletDaemonWithClient, withdrawViaBankV2, } from "../harness/helpers.js"; /** * Run test for basic, bank-integrated withdrawal and payment. */ export async function runPaymentShareTest(t: GlobalTestState) { // Set up test environment const { walletClient: firstWallet, bank, exchange, merchant, } = await createSimpleTestkudosEnvironmentV2(t); const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); // Withdraw digital cash into the wallet. await withdrawViaBankV2(t, { walletClient: firstWallet, bank, exchange, amount: "TESTKUDOS:20", }); await firstWallet.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); const { walletClient: secondWallet } = await createWalletDaemonWithClient(t, { name: "wallet2", }); await withdrawViaBankV2(t, { walletClient: secondWallet, bank, exchange, amount: "TESTKUDOS:20", }); await secondWallet.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); // create two orders to pay async function createOrder(amount: string) { const order = { summary: "Buy me!", amount, fulfillment_url: "taler://fulfillment-success/thx", }; const args = { order }; const auth = {}; const orderResp = await merchantClient.createOrder({ order: args.order, }); const orderStatus = await merchantClient.queryPrivateOrderStatus({ orderId: orderResp.order_id, }); t.assertTrue(orderStatus.order_status === "unpaid"); return { id: orderResp.order_id, uri: orderStatus.taler_pay_uri }; } /** * FIRST CASE, create in first wallet and pay in the second wallet * first wallet should not be able to continue */ { const order = await createOrder("TESTKUDOS:5"); // Claim the order with the first wallet const claimFirstWallet = await firstWallet.call( WalletApiOperation.PreparePayForUri, { talerPayUri: order.uri }, ); t.assertTrue( claimFirstWallet.status === PreparePayResultType.PaymentPossible, ); //share order from the first wallet const { privatePayUri } = await firstWallet.call( WalletApiOperation.SharePayment, { merchantBaseUrl: merchant.makeInstanceBaseUrl(), orderId: order.id, }, ); //claim from the second wallet const claimSecondWallet = await secondWallet.call( WalletApiOperation.PreparePayForUri, { talerPayUri: privatePayUri }, ); t.assertTrue( claimSecondWallet.status === PreparePayResultType.PaymentPossible, ); //pay from the second wallet const r2 = await secondWallet.call(WalletApiOperation.ConfirmPay, { proposalId: claimSecondWallet.proposalId, }); t.assertTrue(r2.type === ConfirmPayResultType.Done); { const first = await firstWallet.call(WalletApiOperation.GetBalances, {}); const second = await secondWallet.call( WalletApiOperation.GetBalances, {}, ); t.assertAmountEquals(first.balances[0].available, "TESTKUDOS:19.53"); t.assertAmountEquals(second.balances[0].available, "TESTKUDOS:14.23"); } // Claim the order with the first wallet const claimFirstWalletAgain = await firstWallet.call( WalletApiOperation.PreparePayForUri, { talerPayUri: order.uri }, ); t.assertTrue( claimFirstWalletAgain.status === PreparePayResultType.AlreadyConfirmed, ); const r1 = await firstWallet.call(WalletApiOperation.ConfirmPay, { proposalId: claimFirstWallet.proposalId, }); t.assertTrue(r1.type === ConfirmPayResultType.Done); { const first = await firstWallet.call(WalletApiOperation.GetBalances, {}); const second = await secondWallet.call( WalletApiOperation.GetBalances, {}, ); t.assertAmountEquals(first.balances[0].available, "TESTKUDOS:19.53"); t.assertAmountEquals(second.balances[0].available, "TESTKUDOS:14.23"); } } /** * SECOND CASE, create in first wallet and share to the second wallet * pay with the first wallet, second wallet should not be able to continue */ { const order = await createOrder("TESTKUDOS:3"); // Claim the order with the first wallet const claimFirstWallet = await firstWallet.call( WalletApiOperation.PreparePayForUri, { talerPayUri: order.uri }, ); t.assertTrue( claimFirstWallet.status === PreparePayResultType.PaymentPossible, ); //share order from the first wallet const { privatePayUri } = await firstWallet.call( WalletApiOperation.SharePayment, { merchantBaseUrl: merchant.makeInstanceBaseUrl(), orderId: order.id, }, ); //claim from the second wallet const claimSecondWallet = await secondWallet.call( WalletApiOperation.PreparePayForUri, { talerPayUri: privatePayUri }, ); t.assertTrue( claimSecondWallet.status === PreparePayResultType.PaymentPossible, ); //pay from the second wallet const r2 = await firstWallet.call(WalletApiOperation.ConfirmPay, { proposalId: claimFirstWallet.proposalId, }); t.assertTrue(r2.type === ConfirmPayResultType.Done); const bal1 = await firstWallet.call(WalletApiOperation.GetBalances, {}); t.assertAmountEquals(bal1.balances[0].available, "TESTKUDOS:16.18"); const bal2 = await secondWallet.call(WalletApiOperation.GetBalances, {}); t.assertAmountEquals(bal2.balances[0].available, "TESTKUDOS:14.23"); // Claim the order with the first wallet const claimSecondWalletAgain = await secondWallet.call( WalletApiOperation.PreparePayForUri, { talerPayUri: order.uri }, ); t.assertTrue( claimSecondWalletAgain.status === PreparePayResultType.AlreadyConfirmed, ); } } runPaymentShareTest.suites = ["wallet"];