View Issue Details

IDProjectCategoryView StatusLast Update
0010959Talermerchant backoffice SPApublic2026-03-30 19:25
ReporterChristian Grothoff Assigned ToChristian Grothoff  
PriorityhighSeverityblockReproducibilityalways
Status feedbackResolutionopen 
Platformi7OSDebian GNU/LinuxOS Versionsqueeze
Product Versiongit (master) 
Target Version1.8 
Summary0010959: Cannot "cancel" dialog "Confirm the wire transfer"
DescriptionWhen clicking on an unconfirmed wire transfer (after selecting the wire transfer in the "Incoming wire transfers" list), the "cancel" and both "X" buttons do not work at all.
Steps To ReproducePay an order, wait for the wire transfer deadline, give the merchant backend a chance to fetch the WTID, click on the transfer.
(note: I did SIGSTOP taler-exchange-transfer when producing the issue, but that should be orthogonal).
Tagsdesign-required

Activities

Christian Grothoff

2026-01-31 20:58

manager   ~0027508

Ah, one key detail: taler-merchant-reconciliation was NOT running, so there was no *amount* available. Once I started taler-merchant-reconciliation, the 'cancel' button started to work. So to reproduce, run the merchant backend without taler-merchant-reconciliation!

(also, if the amount is not available, it should probably be *impossible* to confirm the wire transfer, basically, disable the "confirm" case with a hint/message like "Awaiting amount, make sure taler-merchant-reconciliation is running" somewhere.).

Christian Grothoff

2026-01-31 20:59

manager   ~0027509

Vlada: how to best explain to the user that they cannot confirm while the total amount remains unknown and that this is likely because some merchant service is not running properly -- I leave that to you. I'd probably just put some yellow bar into the dialog explaining this with way too much English text. After all, the case _should_ be uncommon.

sebasjm

2026-02-05 13:32

developer   ~0027587

I can't reproduce this and there is no link between canceling/removing the dialog with the running services server side. Those actions doesn't trigger any http request.

What if "verified": false ? This is like an error state because merchant calculation doesn't match with the exchange wire transfer amount, should the merchant still be able to confirm?

sebasjm

2026-02-05 13:39

developer   ~0027588

Last edited: 2026-02-05 13:44

I tried many ways.

1) Stopping reconciliation, confirm a wire transfer (worked) and try to reproduce. Nothing
2) Stopping httpd, confirm (failed) and try to reproduce. Nothing (dialog closes ok), http request fail but spa keeps working ok.
3) Starting again httpd, confirm (ok) and try to reproduce. Nothing

Without reloading SPA.

It could happen that an error was thrown and the SPA internal state was screw up, in this cases the console in the browser's developer tools should be good to check (if there isn't ANY error on the screen, which is weird).

Christian Grothoff

2026-03-30 16:07

manager   ~0028305

Yes, I also cannot reproduce it anymore. What I'm sure of is that I was testing against an older version (it looked different), so the bug is fixed. However, there is still a problem in the UX.

If you run the attached shell script and open localhost:9966 when it shells-out to bash, you can see it:

(1) The confirmed wire transfers into bank account has initially a button "Details". When you click on it, you get interesting details (good!).
(2) On the details page, you can then "confirm" the wire transfer.

However, after you do (2), the "Details" button is replaced with a "checkmark" and you cannot go see the details again.

What I had wanted to see is a bit different:

(1) The confirmed wire transfer details list is clickable on the "ID" field (which should be underlined in blue to indicate it is a link!), as the ID is what is linked to the details. That should ALWAYS be clickable, even for confirmed transfers.
(2) The "confirm" button should be where we have the "details" button right now, to make it super-fast and easy to confirm wire transfers (basically turning the "confirm" button into a "checkmark"). I don't need the details to confirm, the date, amount and subject are all that is needed!

@Vlada: please confirm this would be better, then re-assign to sebastian to implement!
test_b10959.sh (8,774 bytes)   
#!/bin/bash
# This file is in the public domain.

set -eu

function clean_wallet() {
    rm -f "${WALLET_DB}"
    exit_cleanup
}


# Replace with 0 for nexus...
USE_FAKEBANK=1
if [ 1 = "$USE_FAKEBANK" ]
then
    ACCOUNT="exchange-account-2"
    BANK_FLAGS="-f -d x-taler-bank -u $ACCOUNT"
    BANK_URL="http://localhost:8082/"
else
    ACCOUNT="exchange-account-1"
    BANK_FLAGS="-ns -d iban -u $ACCOUNT"
    BANK_URL="http://localhost:8082/"
    echo -n "Testing for libeufin-bank"
    libeufin-bank --help >/dev/null </dev/null || exit_skip " MISSING"
    echo " FOUND"

fi

. setup.sh

echo -n "Testing for taler-harness"
taler-harness --help >/dev/null </dev/null || exit_skip " MISSING"
echo " FOUND"

# Launch exchange, merchant and bank.
setup -c "test_template.conf" \
      -r "merchant-exchange-default" \
      -em \
      $BANK_FLAGS
LAST_RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" test_response.conf-XXXXXX)
CONF="test_template.conf.edited"
WALLET_DB=$(mktemp -p "${TMPDIR:-/tmp}" test_wallet.json-XXXXXX)
EXCHANGE_URL="http://localhost:8081/"

# Install cleanup handler (except for kill -9)
trap clean_wallet EXIT

echo -n "First prepare wallet with coins ..."
rm -f "$WALLET_DB"
taler-wallet-cli \
    --no-throttle \
    --wallet-db="$WALLET_DB" \
    api \
    --expect-success 'withdrawTestBalance' \
  "$(jq -n '
    {
        amount: "TESTKUDOS:99",
        corebankApiBaseUrl: $BANK_URL,
        exchangeBaseUrl: $EXCHANGE_URL
    }' \
    --arg BANK_URL "${BANK_URL}" \
    --arg EXCHANGE_URL "$EXCHANGE_URL"
  )" 2>wallet-withdraw-1.err >wallet-withdraw-1.out
echo -n "."
# FIXME-MS: add logic to have nexus check immediately here.
# sleep 10
echo -n "."
# NOTE: once libeufin can do long-polling, we should
# be able to reduce the delay here and run wirewatch
# always in the background via setup
taler-exchange-wirewatch \
    -a "$ACCOUNT" \
    -L "INFO" \
    -c "$CONF" \
    -t &> taler-exchange-wirewatch.out
echo -n "."
timeout 60 taler-wallet-cli \
    --wallet-db="$WALLET_DB" \
    run-until-done \
    2>wallet-withdraw-finish-1.err \
    >wallet-withdraw-finish-1.out
echo " OK"

CURRENCY_COUNT=$(taler-wallet-cli --wallet-db="$WALLET_DB" balance | jq '.balances|length')
if [ "$CURRENCY_COUNT" = "0" ]
then
    exit_fail "Expected least one currency, withdrawal failed. check log."
fi

#
# CREATE INSTANCE FOR TESTING
#


echo -n "Configuring merchant instance ..."

STATUS=$(curl -H "Content-Type: application/json" -X POST \
    -H 'Authorization: Bearer secret-token:super_secret' \
    http://localhost:9966/management/instances \
    -d '{"auth":{"method":"external"},"id":"admin","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000000},"default_pay_delay":{"d_us": 60000000000}}' \
    -w "%{http_code}" -s -o /dev/null)

if [ "$STATUS" != "204" ]
then
    exit_fail "Expected '204 No content' response. Got instead $STATUS"
fi
echo "Ok"

echo -n "Configuring merchant account ..."

if [ 1 = "$USE_FAKEBANK" ]
then
    FORTYTHREE="payto://x-taler-bank/localhost/fortythree?receiver-name=fortythree"
else
    FORTYTHREE=$(get_payto_uri fortythree x)
fi
# create with 2 bank account addresses
STATUS=$(curl -H "Content-Type: application/json" -X POST \
    -H 'Authorization: Bearer secret-token:super_secret' \
    http://localhost:9966/private/accounts \
    -d '{"payto_uri":"'"$FORTYTHREE"'"}' \
    -w "%{http_code}" -s -o /dev/null)

if [ "$STATUS" != "200" ]
then
    exit_fail "Expected '200 OK' response. Got instead $STATUS"
fi
STATUS=$(curl -H "Content-Type: application/json" -X POST \
    -H 'Authorization: Bearer secret-token:super_secret' \
    http://localhost:9966/private/accounts \
    -d '{"payto_uri":"payto://iban/SANDBOXX/DE270744?receiver-name=Forty+Four"}' \
    -w "%{http_code}" -s -o /dev/null)

if [ "$STATUS" != "200" ]
then
    exit_fail "Expected '200 OK' response. Got instead $STATUS"
fi

echo "Ok"


echo -n "Get accounts..."
STATUS=$(curl http://localhost:9966/private/accounts \
    -w "%{http_code}" -s -o "$LAST_RESPONSE")
PAY_URI=$(jq -r .accounts[1].payto_uri < "$LAST_RESPONSE")
H_WIRE=$(jq -r .accounts[1].h_wire < "$LAST_RESPONSE")
if [ "$PAY_URI" != "payto://iban/SANDBOXX/DE270744?receiver-name=Forty+Four" ]
then
    cat "$LAST_RESPONSE" >&2
    exit_fail "Expected second payto URI. Got $PAY_URI"
fi
echo "OK"

# remove one account address
echo -n "Deleting one account ..."
STATUS=$(curl -H "Content-Type: application/json" -X PATCH \
    -H 'Authorization: Bearer secret-token:super_secret' \
    "http://localhost:9966/private/accounts/${H_WIRE}" \
    -X DELETE \
    -w "%{http_code}" -s -o /dev/null)

if [ "$STATUS" != "204" ]
then
    exit_fail "Expected '204 No content' for deletion of ${H_WIRE}. Got instead: $STATUS"
fi
echo "OK"

# CREATE ORDER AND SELL IT

echo -n "Creating order to be paid..."
STATUS=$(curl 'http://localhost:9966/private/orders' \
    -d '{"refund_delay":{"d_us":0},"order":{"amount":"TESTKUDOS:1","summary":"payme"}}' \
    -w "%{http_code}" -s -o "$LAST_RESPONSE")

if [ "$STATUS" != "200" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Expected 200, order created. got: $STATUS"
fi

ORDER_ID=$(jq -e -r .order_id < "$LAST_RESPONSE")
TOKEN=$(jq -e -r .token < "$LAST_RESPONSE")

STATUS=$(curl "http://localhost:9966/private/orders/${ORDER_ID}" \
    -w "%{http_code}" -s -o "$LAST_RESPONSE")

if [ "$STATUS" != "200" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Expected 200, getting order info. got: $STATUS"
fi

PAY_URL=$(jq -e -r .taler_pay_uri < "$LAST_RESPONSE")

echo "OK"

NOW=$(date +%s)

echo -n "Pay first order ${PAY_URL} ..."
taler-wallet-cli \
    --no-throttle \
    --wallet-db="$WALLET_DB" \
    handle-uri "${PAY_URL}" \
    -y 2> wallet-pay1.err > wallet-pay1.log
timeout 60 taler-wallet-cli \
    --no-throttle \
    --wallet-db="$WALLET_DB" \
    run-until-done 2> wallet-finish-pay1.err > wallet-finish-pay1.log
NOW2=$(date +%s)
echo " OK (took $(( NOW2 - NOW )) secs )"

STATUS=$(curl "http://localhost:9966/private/orders/${ORDER_ID}" \
    -w "%{http_code}" -s -o "$LAST_RESPONSE")

if [ "$STATUS" != "200" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Expected 200, after pay. got: $STATUS"
fi

ORDER_STATUS=$(jq -r .order_status < "$LAST_RESPONSE")

if [ "$ORDER_STATUS" != "paid" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Order status should be 'paid'. got: $ORDER_STATUS"
fi

#
# WIRE TRANSFER TO MERCHANT AND NOTIFY BACKEND
#

# PAY_DEADLINE=$(jq -r .contract_terms.pay_deadline.t_s < "$LAST_RESPONSE")
WIRE_DEADLINE=$(jq -r .contract_terms.wire_transfer_deadline.t_s < "$LAST_RESPONSE")

NOW=$(date +%s)

TO_SLEEP=$((1200 + WIRE_DEADLINE - NOW ))
echo "Waiting $TO_SLEEP secs for wire transfer"

echo -n "Call taler-exchange-aggregator ..."
taler-exchange-aggregator \
    -y \
    -c "$CONF" \
    -T "${TO_SLEEP}"000000 \
    -t \
    -L INFO &> aggregator.log
echo " DONE"
echo -n "Call taler-exchange-transfer ..."
taler-exchange-transfer \
    -c "$CONF" \
    -t \
    -L INFO &> transfer.log
echo " DONE"
echo -n "Give time to Nexus to route the payment to Sandbox..."
# FIXME: trigger immediate update at nexus
# NOTE: once libeufin can do long-polling, we should
# be able to reduce the delay here and run aggregator/transfer
# always in the background via setup
sleep 3
echo " DONE"

echo -n "Running taler-merchant-depositcheck ..."
set -e
taler-merchant-depositcheck \
    -L INFO \
    -c "$CONF" \
    -T "${TO_SLEEP}"000000 \
    -t &> taler-merchant-depositcheck.log
echo " OK"

echo -n "Running taler-merchant-reconciliation ..."
set -e
taler-merchant-reconciliation \
    -L INFO \
    -c "$CONF" \
    -T "${TO_SLEEP}"000000 \
    -t &> taler-merchant-reconciliation.log
echo " OK"

bash

echo -n "Fetching wire transfers ..."

STATUS=$(curl 'http://localhost:9966/private/transfers' \
    -w "%{http_code}" -s -o "$LAST_RESPONSE")

if [ "$STATUS" != "200" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Expected response 200 Ok. got: $STATUS"
fi

TRANSFERS_LIST_SIZE=$(jq -r '.transfers | length' < "$LAST_RESPONSE")

if [ "$TRANSFERS_LIST_SIZE" != "1" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Expected 1 entry in transfer list. Got: $TRANSFERS_LIST_SIZE"
fi

echo "OK"

echo -n "Checking order status ..."
STATUS=$(curl "http://localhost:9966/private/orders/${ORDER_ID}?transfer=YES" \
    -w "%{http_code}" -s -o "$LAST_RESPONSE")
if [ "$STATUS" != "200" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Expected 200, after order inquiry. got: $STATUS"
fi
DEPOSIT_TOTAL=$(jq -r .deposit_total < "$LAST_RESPONSE")
if [ "$DEPOSIT_TOTAL" == "TESTKUDOS:0" ]
then
    jq . < "$LAST_RESPONSE"
    exit_fail "Expected non-zero deposit total. got: $DEPOSIT_TOTAL"
fi
echo " OK"


exit 0
test_b10959.sh (8,774 bytes)   

vlada.svirsh

2026-03-30 19:25

developer   ~0028310

@Christian, behavior like you proposed in (1) we don't have in SPA at all. Other lists also use buttons or click on the row to show details. So I think it's good to add a click on a row to show the details page as well. I don't see a problem with showing 2 buttons when it is needed: Confirm and Details. For a confirmed wire transfer, only Details button is needed.

Issue History

Date Modified Username Field Change
2026-01-31 20:55 Christian Grothoff New Issue
2026-01-31 20:55 Christian Grothoff Status new => assigned
2026-01-31 20:55 Christian Grothoff Assigned To => sebasjm
2026-01-31 20:58 Christian Grothoff Note Added: 0027508
2026-01-31 20:58 Christian Grothoff Tag Attached: design-required
2026-01-31 20:59 Christian Grothoff Note Added: 0027509
2026-01-31 21:00 Christian Grothoff Priority high => low
2026-01-31 21:00 Christian Grothoff Target Version 1.5 => 1.8
2026-02-05 13:32 sebasjm Note Added: 0027587
2026-02-05 13:33 sebasjm Assigned To sebasjm => Christian Grothoff
2026-02-05 13:33 sebasjm Status assigned => feedback
2026-02-05 13:39 sebasjm Note Added: 0027588
2026-02-05 13:44 sebasjm Note Edited: 0027588
2026-02-22 23:22 Christian Grothoff Priority low => high
2026-03-30 16:07 Christian Grothoff Note Added: 0028305
2026-03-30 16:07 Christian Grothoff File Added: test_b10959.sh
2026-03-30 16:07 Christian Grothoff Assigned To Christian Grothoff => vlada.svirsh
2026-03-30 16:07 Christian Grothoff Status feedback => assigned
2026-03-30 19:25 vlada.svirsh Note Added: 0028310
2026-03-30 19:25 vlada.svirsh Assigned To vlada.svirsh => Christian Grothoff
2026-03-30 19:25 vlada.svirsh Status assigned => feedback