#!/usr/bin/env python3 from taler.util.amount import Amount from tests import check_single_balance def test_withdrawal(exchange, bank, wallet): bank_user = bank.register_random_user() # assert that we start with no transactions result = wallet.cmd("getTransactions") assert not result["transactions"] # test withdrawal amount_raw = Amount.parse("TESTKUDOS:5") wallet.testing_withdraw(amount_raw.stringify(), exchange.url, bank.url) # check that balance is correct result = wallet.cmd("getBalances") amount_effective = Amount("TESTKUDOS", 4, 84000000) check_single_balance(result["balances"], amount_effective) # assert that withdrawal shows up properly in transactions result = wallet.cmd("getTransactions") assert len(result["transactions"]) == 1 transaction = result["transactions"][0] assert transaction["type"] == "withdrawal" assert Amount.parse(transaction["amountEffective"]) == amount_effective assert Amount.parse(transaction["amountRaw"]) == amount_raw assert transaction["exchangeBaseUrl"] == exchange.url assert not transaction["pending"] withdrawal_details = transaction["withdrawalDetails"] assert withdrawal_details["type"] == "manual-transfer" payto_list = ["payto://x-taler-bank/localhost/Exchange"] assert withdrawal_details["exchangePaytoUris"] == payto_list # get a withdrawal URI bank_uri_resp = bank.generate_withdraw_uri(bank_user, "TESTKUDOS:5") uri = bank_uri_resp.taler_withdraw_uri assert uri.startswith("taler+http://withdraw") # get withdrawal details from URI result = wallet.cmd("getWithdrawalDetailsForUri", {"talerWithdrawUri": uri}) assert Amount.parse(result["amount"]) == amount_raw assert result["defaultExchangeBaseUrl"] == exchange.url assert len(result["possibleExchanges"]) == 1 assert result["possibleExchanges"][0]["exchangeBaseUrl"] == exchange.url assert result["possibleExchanges"][0]["currency"] == "TESTKUDOS" assert result["possibleExchanges"][0]["paytoUris"] == payto_list # check withdrawal details for amount request = {"exchangeBaseUrl": exchange.url, "amount": amount_raw.stringify()} result = wallet.cmd("getWithdrawalDetailsForAmount", request) assert Amount.parse(result["amountRaw"]) == amount_raw assert Amount.parse(result["amountEffective"]) == amount_effective assert result["paytoUris"] == payto_list assert not result["tosAccepted"] # get ToS result = wallet.cmd("getExchangeTos", {"exchangeBaseUrl": exchange.url}) assert result["currentEtag"] == exchange.terms_etag assert result["tos"] == exchange.tos # accept ToS request = {"exchangeBaseUrl": exchange.url, "etag": exchange.terms_etag} wallet.cmd("setExchangeTosAccepted", request) # check that ToS are now shown as accepted request = {"exchangeBaseUrl": exchange.url, "amount": amount_raw.stringify()} result = wallet.cmd("getWithdrawalDetailsForAmount", request) assert result["tosAccepted"] # accept withdrawal request = {"exchangeBaseUrl": exchange.url, "talerWithdrawUri": uri} result = wallet.cmd("acceptBankIntegratedWithdrawal", request) assert result["confirmTransferUrl"].startswith(bank.url + "confirm-withdrawal/") confirm_url = result["confirmTransferUrl"] # Let the wallet do its work. At this point, the bank-integrated # withdrawal won't have succeeded yet, as it's not confirmed at the bank side. wallet.run_pending() # check that balance is correct result = wallet.cmd("getBalances") check_single_balance(result["balances"], amount_effective, amount_effective) # assert that 2nd withdrawal shows up properly in transactions result = wallet.cmd("getTransactions") assert len(result["transactions"]) == 2 transaction = result["transactions"][0] assert transaction["type"] == "withdrawal" assert Amount.parse(transaction["amountEffective"]) == amount_effective assert Amount.parse(transaction["amountRaw"]) == amount_raw assert transaction["exchangeBaseUrl"] == exchange.url assert transaction["pending"] withdrawal_details = transaction["withdrawalDetails"] assert withdrawal_details["type"] == "taler-bank-integration-api" assert not withdrawal_details["confirmed"] assert withdrawal_details["bankConfirmationUrl"] == confirm_url # new withdrawal is newer than old one timestamp0 = result["transactions"][0]["timestamp"]["t_ms"] timestamp1 = result["transactions"][1]["timestamp"]["t_ms"] assert timestamp0 > timestamp1 # now we actually confirm the withdrawal bank.confirm_withdrawal(bank_user, bank_uri_resp.withdrawal_id) # It might take some time until the exchange knows about the reserve, # so we'll try until it works. wallet.run_until_done() # check that balance is correct result = wallet.cmd("getBalances") check_single_balance( result["balances"], Amount.parse("TESTKUDOS:9.68"), Amount.parse("TESTKUDOS:0"), ) # check that transaction is no longer pending, but confirmed result = wallet.cmd("getTransactions") assert len(result["transactions"]) == 2 transaction = result["transactions"][1] # TODO this transaction should be at the top now assert transaction["type"] == "withdrawal" assert not transaction["pending"] assert transaction["withdrawalDetails"]["confirmed"] # one more manual withdrawal request = {"exchangeBaseUrl": exchange.url, "amount": amount_raw.stringify()} result = wallet.cmd("acceptManualWithdrawal", request) assert len(result["exchangePaytoUris"]) == 1 result["exchangePaytoUris"][0].startswith(payto_list[0]) # check that balance is correct result = wallet.cmd("getBalances") check_single_balance( result["balances"], amount_effective + amount_effective, amount_effective ) # assert that 3nd withdrawal shows up properly in transactions result = wallet.cmd("getTransactions") assert len(result["transactions"]) == 3 transaction = result["transactions"][0] assert transaction["type"] == "withdrawal" assert Amount.parse(transaction["amountEffective"]) == amount_effective assert Amount.parse(transaction["amountRaw"]) == amount_raw assert transaction["exchangeBaseUrl"] == exchange.url assert transaction["pending"] withdrawal_details = transaction["withdrawalDetails"] assert withdrawal_details["type"] == "manual-transfer" assert len(withdrawal_details["exchangePaytoUris"]) == 1 assert withdrawal_details["exchangePaytoUris"][0].startswith(payto_list[0]) # last withdrawal is newest timestamp3 = transaction["timestamp"]["t_ms"] assert timestamp3 > timestamp0 assert timestamp3 > timestamp1