merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit c3c603a69758d68a387adfd0d2833ee7312e0944
parent 36a08455d67c67ce2fb27a38faee45600979dbed
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed,  5 Aug 2026 23:34:01 +0200

fix misnamed trigger function

Diffstat:
Msrc/backenddb/pg_merchant_account_trigger.sql | 12++++++++++--
Msrc/backenddb/pg_merchant_send_account_notification.sql | 10++++------
Msrc/backenddb/pg_triggers.sql | 14+++++---------
Msrc/backenddb/test_merchantdb.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 83 insertions(+), 17 deletions(-)

diff --git a/src/backenddb/pg_merchant_account_trigger.sql b/src/backenddb/pg_merchant_account_trigger.sql @@ -18,11 +18,19 @@ -- @author Christian Grothoff -CREATE OR REPLACE FUNCTION merchant_kyc_update_trigger() +CREATE OR REPLACE FUNCTION merchant_account_change_trigger() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN + IF TG_OP = 'DELETE' + THEN + -- The row is already gone, merchant_send_account_notification() + -- could no longer resolve the account. + RETURN NULL; + END IF; + -- Note: on INSERT the OLD record is NULL, so a newly added account + -- is reported as a change as well. IF (OLD.payto_uri ,OLD.active) IS DISTINCT FROM @@ -31,5 +39,5 @@ BEGIN THEN CALL merchant_send_account_notification(NEW.account_serial); END IF; - RETURN NEW; + RETURN NULL; END $$; diff --git a/src/backenddb/pg_merchant_send_account_notification.sql b/src/backenddb/pg_merchant_send_account_notification.sql @@ -65,10 +65,9 @@ BEGIN RETURN; END IF; - my_report_token = random_bytea(32); + my_report_token = merchant.random_bytea(32); INSERT INTO merchant_reports ( - merchant_serial - ,report_program_section + report_program_section ,report_description ,mime_type ,report_token @@ -79,12 +78,11 @@ BEGIN ,next_transmission ,one_shot_hidden ) VALUES ( - my_instance_serial - ,'email' + 'email' ,'automatically triggered account change alert' ,'text/plain' ,my_report_token - ,'/private/accounts/' || base32_crockford (my_h_wire) + ,'/private/accounts/' || merchant.base32_crockford (my_h_wire) ,my_email ,0 ,0 diff --git a/src/backenddb/pg_triggers.sql b/src/backenddb/pg_triggers.sql @@ -233,12 +233,8 @@ BEGIN RETURN NEW; END $$; -CREATE OR REPLACE FUNCTION merchant_kyc_update_trigger() -RETURNS TRIGGER -LANGUAGE plpgsql -AS $$ -BEGIN - CALL merchant_send_kyc_notification(NEW.account_serial, - NEW.exchange_url); - RETURN NEW; -END $$; +-- Note: merchant_kyc_update_trigger() is deliberately NOT defined here. +-- It lives in pg_merchant_kyc_trigger.sql, which is loaded before this +-- file (see sql-schema/meson.build), and an unguarded copy here would +-- overwrite it and make the notification fire on every bookkeeping +-- update of e.g. next_kyc_poll. diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c @@ -7635,6 +7635,70 @@ test_kyc (void) &kyc_status_ok, &fail)); TEST_RET_ON_FAIL (fail); + /* A bookkeeping-only re-poll -- kyc_ok, last_rule_gen, aml_review and + jaccount_limits are unchanged, only the timestamps move -- must NOT + queue another alert. Regression test: pg_triggers.sql used to + install a second, unguarded merchant_kyc_update_trigger() on top of + the guarded one in pg_merchant_kyc_trigger.sql, and being loaded + last it won, so every next_kyc_poll update alerted the merchant. */ + TEST_RET_ON_FAIL (query_sql_num ("SELECT COUNT(*) AS num" + " FROM merchant_reports" + " WHERE report_description" + " ='automatically triggered KYC alert'", + &alerts)); + TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + TALER_MERCHANTDB_insert_kyc_status (pg, + instance.instance.id, + &account.h_wire, + "https://exchange.net/", + GNUNET_TIME_timestamp_get (), + GNUNET_TIME_UNIT_FOREVER_ABS, + GNUNET_TIME_UNIT_MINUTES, + MHD_HTTP_OK, + TALER_EC_NONE, + 42, + NULL, + NULL, + false, + true)); + { + uint64_t alerts2; + + TEST_RET_ON_FAIL (query_sql_num ("SELECT COUNT(*) AS num" + " FROM merchant_reports" + " WHERE report_description" + " ='automatically triggered KYC alert'", + &alerts2)); + TEST_COND_RET_ON_FAIL (alerts == alerts2, + "Bookkeeping-only KYC update queued an alert\n"); + } + /* Adding an account must queue an account-change alert. Regression + test: pg_merchant_account_trigger.sql used to (re)define + 'merchant_kyc_update_trigger' rather than + 'merchant_account_change_trigger', so merchant_send_account_notification() + had no callers at all and the trigger installed by merchant-0041 was + still its 'RETURN NULL' stub. */ + { + struct TALER_MERCHANTDB_AccountDetails account2; + uint64_t acc_alerts; + + make_account (&account2); + account2.instance_id = instance.instance.id; + /* make_account() hands out a fixed payto_uri, which would collide. */ + account2.payto_uri.full_payto + = (char *) "payto://x-taler-bank/bank.demo.taler.net/5"; + TEST_RET_ON_FAIL (test_insert_account (&instance, + &account2, + GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); + TEST_RET_ON_FAIL (query_sql_num ("SELECT COUNT(*) AS num" + " FROM merchant_reports" + " WHERE report_description" + " ='automatically triggered account" + " change alert'", + &acc_alerts)); + TEST_COND_RET_ON_FAIL (1 == acc_alerts, + "Adding an account did not queue an alert\n"); + } json_decref (instance.instance.address); json_decref (instance.instance.jurisdiction); return 0;