gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant] branch master updated (9438e749 -> a39cc48c)


From: gnunet
Subject: [taler-merchant] branch master updated (9438e749 -> a39cc48c)
Date: Sun, 08 Dec 2024 14:18:09 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository merchant.

    from 9438e749 fix socket paths
     new 7a672056 adding sql calls for the order_settled webhook
     new 75c8023c adding webhook for the categories
     new d1c267b6 small update of the categories webhook calls
     new 5a75a057 update of the templating
     new b4a24cbc adding inventory realted webhooks adding
     new 440230a3 few updates of the webhook trigger
     new e1c86838 small update of the styling
     new fb871333 adding webhook for the categories
     new 29663c0c start test
     new 20234ecc tests added
     new 3648c035 few design fixes
     new 384b0265 small fix
     new 68ec8846 -fix logging
     new a39cc48c add check to test for openssl

The 14 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/backend/taler-merchant-httpd_exchanges.c    |   6 +-
 src/backenddb/Makefile.am                       |  10 +-
 src/backenddb/merchant-0013.sql                 | 495 ++++++++++++++++++++++++
 src/backenddb/pg_insert_deposit_to_transfer.sql |  20 +
 src/backenddb/pg_insert_transfer_details.sql    |  25 ++
 src/backenddb/test_webhook_trigger.sh           | 369 ++++++++++++++++++
 6 files changed, 922 insertions(+), 3 deletions(-)
 create mode 100644 src/backenddb/merchant-0013.sql
 create mode 100755 src/backenddb/test_webhook_trigger.sh

diff --git a/src/backend/taler-merchant-httpd_exchanges.c 
b/src/backend/taler-merchant-httpd_exchanges.c
index 3b73e636..f9b0f218 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -685,7 +685,11 @@ TMH_exchange_check_debit (
   if (0 != strcasecmp (keys->currency,
                        max_amount->currency))
   {
-    GNUNET_break (0);
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Currency missmatch: exchange %s uses %s, we need %s\n",
+                exchange->url,
+                keys->currency,
+                max_amount->currency);
     return GNUNET_SYSERR;
   }
   np = TALER_payto_normalize (wm->payto_uri);
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index 926bbfb2..b5a8d1fe 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -29,6 +29,7 @@ sql_DATA = \
   merchant-0010.sql \
   merchant-0011.sql \
   merchant-0012.sql \
+  merchant-0013.sql \
   drop.sql
 
 BUILT_SOURCES = \
@@ -230,15 +231,20 @@ test_merchantdb_postgres_LDFLAGS = \
   -ljansson \
   $(XLIB)
 
+check_SCRIPTS = \
+  test_webhook_trigger.sh
+
 test_merchantdb_postgres_LDADD = \
   $(top_builddir)/src/util/libtalermerchantutil.la \
   $(top_builddir)/src/backenddb/libtalermerchantdb.la
 
 TESTS = \
-  test-merchantdb-postgres
+  $(check_PROGRAMS) \
+  $(check_SCRIPTS)
 
 EXTRA_DIST = \
   test-merchantdb-postgres.conf \
   merchantdb-postgres.conf \
   $(sqlinputs) \
-  $(sql_DATA)
+  $(sql_DATA) \
+  $(check_SCRIPTS)
diff --git a/src/backenddb/merchant-0013.sql b/src/backenddb/merchant-0013.sql
new file mode 100644
index 00000000..29cbb1e2
--- /dev/null
+++ b/src/backenddb/merchant-0013.sql
@@ -0,0 +1,495 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2024 Taler Systems SA
+--
+-- 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.
+--
+-- 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
+-- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+--
+
+-- @file merchant-0013.sql
+-- @brief Creating trigger for the category change webhook
+-- @author Bohdan Potuzhnyi
+-- @author Vlada Svirsh
+
+
+BEGIN;
+
+-- Check patch versioning is in place.
+SELECT _v.register_patch('merchant-0013', NULL, NULL);
+
+SET search_path TO merchant;
+
+-- Function to replace placeholders in a string with a given value
+CREATE OR REPLACE FUNCTION replace_placeholder(
+  template TEXT,
+  key TEXT,
+  value TEXT
+) RETURNS TEXT AS $$
+BEGIN
+  RETURN regexp_replace(
+    template,
+    '{{\s*' || key || '\s*}}', -- Match the key with optional spaces
+    value,
+    'g' -- Global replacement
+  );
+END;
+$$ LANGUAGE plpgsql;
+
+-- Trigger function to handle pending webhooks for category changes
+CREATE OR REPLACE FUNCTION handle_category_changes()
+RETURNS TRIGGER AS $$
+DECLARE
+  my_merchant_serial BIGINT;
+  resolved_body TEXT;
+  webhook RECORD; -- To iterate over all webhooks matching the event type
+BEGIN
+  -- Fetch the merchant_serial directly from the NEW or OLD row
+  my_merchant_serial := COALESCE(OLD.merchant_serial, NEW.merchant_serial);
+
+  -- INSERT case: Add a webhook for category addition
+  IF TG_OP = 'INSERT' THEN
+    FOR webhook IN
+      SELECT webhook_serial,
+             merchant_serial,
+            url,
+            http_method,
+            body_template
+      FROM merchant_webhook
+      WHERE event_type = 'category_added'
+        AND merchant_serial = my_merchant_serial
+    LOOP
+      -- Resolve placeholders for the current webhook
+      resolved_body := webhook.body_template;
+      resolved_body := replace_placeholder(resolved_body,
+                                           'webhook_type',
+                                           'category_added');
+      resolved_body := replace_placeholder(resolved_body,
+                                           'category_serial',
+                                           NEW.category_serial::TEXT);
+      resolved_body := replace_placeholder(resolved_body,
+                                           'category_name',
+                                           NEW.category_name);
+      resolved_body := replace_placeholder(resolved_body,
+                                           'merchant_serial',
+                                           my_merchant_serial::TEXT);
+
+      -- Insert into pending webhooks for this webhook
+      INSERT INTO merchant_pending_webhooks
+      (merchant_serial, webhook_serial, url, http_method, body)
+      VALUES
+      (webhook.merchant_serial,
+       webhook.webhook_serial,
+       webhook.url,
+       webhook.http_method,
+       resolved_body);
+    END LOOP;
+
+    -- Notify the webhook service for the 
TALER_DBEVENT_MERCHANT_WEBHOOK_PENDING
+    NOTIFY XXJWF6C1DCS1255RJH7GQ1EK16J8DMRSQ6K9EDKNKCP7HRVWAJPKG;
+  END IF;
+
+  -- UPDATE case: Add a webhook for category update
+  IF TG_OP = 'UPDATE' THEN
+    FOR webhook IN
+      SELECT webhook_serial,
+             merchant_serial,
+            url,
+            http_method,
+            body_template
+      FROM merchant_webhook
+      WHERE event_type = 'category_updated'
+        AND merchant_serial = my_merchant_serial
+    LOOP
+      -- Resolve placeholders for the current webhook
+      resolved_body := webhook.body_template;
+      resolved_body := replace_placeholder(resolved_body,
+                                           'webhook_type',
+                                           'category_updated');
+      resolved_body := replace_placeholder(resolved_body,
+                                           'category_serial',
+                                           NEW.category_serial::TEXT);
+      resolved_body := replace_placeholder(resolved_body,
+                                           'old_category_name',
+                                           OLD.category_name);
+      resolved_body := replace_placeholder(resolved_body,
+                                           'category_name',
+                                           NEW.category_name);
+      resolved_body := replace_placeholder(resolved_body,
+                                           'category_name_i18n',
+                                           encode(NEW.category_name_i18n,
+                                                  'escape'));
+      resolved_body := replace_placeholder(resolved_body,
+                                           'old_category_name_i18n',
+                                           encode(OLD.category_name_i18n,
+                                                  'escape'));
+
+      -- Insert into pending webhooks for this webhook
+      INSERT INTO merchant_pending_webhooks
+      (merchant_serial, webhook_serial, url, http_method, body)
+      VALUES
+      (webhook.merchant_serial,
+       webhook.webhook_serial,
+       webhook.url,
+       webhook.http_method,
+       resolved_body);
+    END LOOP;
+
+    -- Notify the webhook service for the 
TALER_DBEVENT_MERCHANT_WEBHOOK_PENDING
+    NOTIFY XXJWF6C1DCS1255RJH7GQ1EK16J8DMRSQ6K9EDKNKCP7HRVWAJPKG;
+  END IF;
+
+  -- DELETE case: Add a webhook for category deletion
+  IF TG_OP = 'DELETE' THEN
+    FOR webhook IN
+      SELECT webhook_serial,
+             merchant_serial,
+            url,
+            http_method,
+            body_template
+      FROM merchant_webhook
+      WHERE event_type = 'category_deleted'
+        AND merchant_serial = my_merchant_serial
+    LOOP
+      -- Resolve placeholders for the current webhook
+      resolved_body := webhook.body_template;
+      resolved_body := replace_placeholder(resolved_body,
+                                           'webhook_type',
+                                           'category_deleted');
+      resolved_body := replace_placeholder(resolved_body,
+                                           'category_serial',
+                                           OLD.category_serial::TEXT);
+      resolved_body := replace_placeholder(resolved_body,
+                                           'category_name',
+                                           OLD.category_name);
+
+      -- Insert into pending webhooks for this webhook
+      INSERT INTO merchant_pending_webhooks
+      (merchant_serial, webhook_serial, url, http_method, body)
+      VALUES
+      (webhook.merchant_serial,
+       webhook.webhook_serial,
+       webhook.url,
+       webhook.http_method,
+       resolved_body);
+    END LOOP;
+
+    -- Notify the webhook service for the 
TALER_DBEVENT_MERCHANT_WEBHOOK_PENDING
+    NOTIFY XXJWF6C1DCS1255RJH7GQ1EK16J8DMRSQ6K9EDKNKCP7HRVWAJPKG;
+  END IF;
+
+  RETURN NULL;
+END;
+$$ LANGUAGE plpgsql;
+
+-- Trigger to invoke the trigger function
+CREATE TRIGGER trigger_category_changes
+AFTER INSERT OR UPDATE OR DELETE
+ON merchant_categories
+FOR EACH ROW
+EXECUTE FUNCTION handle_category_changes();
+
+-- Function to handle inventory changes and notify webhooks
+CREATE OR REPLACE FUNCTION handle_inventory_changes()
+  RETURNS TRIGGER AS $$
+DECLARE
+  my_merchant_serial BIGINT;
+  resolved_body TEXT;
+  webhook RECORD; -- To iterate over all matching webhooks
+BEGIN
+  -- Fetch the merchant_serial directly from the NEW or OLD row
+  my_merchant_serial := COALESCE(OLD.merchant_serial, NEW.merchant_serial);
+
+  -- INSERT case: Notify webhooks for inventory addition
+  IF TG_OP = 'INSERT' THEN
+    FOR webhook IN
+      SELECT webhook_serial,
+             merchant_serial,
+            url,
+            http_method,
+            body_template
+      FROM merchant_webhook
+      WHERE event_type = 'inventory_added'
+        AND merchant_serial = my_merchant_serial
+      LOOP
+        -- Resolve placeholders for the current webhook
+        resolved_body := webhook.body_template;
+        resolved_body := replace_placeholder(resolved_body,
+                                             'webhook_type',
+                                             'inventory_added');
+        resolved_body := replace_placeholder(resolved_body,
+                                             'product_serial',
+                                             NEW.product_serial::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'product_id',
+                                             NEW.product_id);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'description',
+                                             NEW.description);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'description_i18n',
+                                             encode(NEW.description_i18n,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'unit',
+                                             NEW.unit);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'image',
+                                             NEW.image);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'taxes',
+                                             encode(NEW.taxes,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'price',
+                                             NEW.price::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'total_stock',
+                                             NEW.total_stock::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'total_sold',
+                                             NEW.total_sold::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'total_lost',
+                                             NEW.total_lost::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'address',
+                                             encode(NEW.address,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'next_restock',
+                                             NEW.next_restock::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'minimum_age',
+                                             NEW.minimum_age::TEXT);
+
+        -- Insert into pending webhooks for this webhook
+        INSERT INTO merchant_pending_webhooks
+        (merchant_serial, webhook_serial, url, http_method, body)
+        VALUES
+          (webhook.merchant_serial,
+           webhook.webhook_serial,
+           webhook.url,
+           webhook.http_method,
+           resolved_body);
+      END LOOP;
+
+    -- Notify the webhook service
+    NOTIFY XXJWF6C1DCS1255RJH7GQ1EK16J8DMRSQ6K9EDKNKCP7HRVWAJPKG;
+  END IF;
+
+  -- UPDATE case: Notify webhooks for inventory update
+  IF TG_OP = 'UPDATE' THEN
+    FOR webhook IN
+      SELECT webhook_serial,
+             merchant_serial,
+            url,
+            http_method,
+            body_template
+      FROM merchant_webhook
+      WHERE event_type = 'inventory_updated'
+        AND merchant_serial = my_merchant_serial
+      LOOP
+        -- Resolve placeholders for the current webhook
+        resolved_body := webhook.body_template;
+        resolved_body := replace_placeholder(resolved_body,
+                                             'webhook_type',
+                                             'inventory_updated');
+        resolved_body := replace_placeholder(resolved_body,
+                                             'product_serial',
+                                             NEW.product_serial::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'product_id',
+                                             NEW.product_id);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_description',
+                                             OLD.description);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'description',
+                                             NEW.description);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_description_i18n',
+                                             encode(OLD.description_i18n,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'description_i18n',
+                                             encode(NEW.description_i18n,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_unit',
+                                             OLD.unit);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'unit',
+                                             NEW.unit);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_image',
+                                             OLD.image);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'image',
+                                             NEW.image);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_taxes',
+                                             encode(OLD.taxes,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'taxes',
+                                             encode(NEW.taxes,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_price',
+                                             OLD.price::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'price',
+                                             NEW.price::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_total_stock',
+                                             OLD.total_stock::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'total_stock',
+                                             NEW.total_stock::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_total_sold',
+                                             OLD.total_sold::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'total_sold',
+                                             NEW.total_sold::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_total_lost',
+                                             OLD.total_lost::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'total_lost',
+                                             NEW.total_lost::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_address',
+                                             encode(OLD.address,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'address',
+                                             encode(NEW.address,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_next_restock',
+                                             OLD.next_restock::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'next_restock',
+                                             NEW.next_restock::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'old_minimum_age',
+                                             OLD.minimum_age::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'minimum_age',
+                                             NEW.minimum_age::TEXT);
+
+        -- Insert into pending webhooks for this webhook
+        INSERT INTO merchant_pending_webhooks
+        (merchant_serial, webhook_serial, url, http_method, body)
+        VALUES
+          (webhook.merchant_serial,
+           webhook.webhook_serial,
+           webhook.url,
+           webhook.http_method,
+           resolved_body);
+      END LOOP;
+
+    -- Notify the webhook service
+    NOTIFY XXJWF6C1DCS1255RJH7GQ1EK16J8DMRSQ6K9EDKNKCP7HRVWAJPKG;
+  END IF;
+
+  -- DELETE case: Notify webhooks for inventory deletion
+  IF TG_OP = 'DELETE' THEN
+    FOR webhook IN
+      SELECT webhook_serial,
+             merchant_serial,
+            url,
+            http_method,
+            body_template
+      FROM merchant_webhook
+      WHERE event_type = 'inventory_deleted'
+        AND merchant_serial = my_merchant_serial
+      LOOP
+        -- Resolve placeholders for the current webhook
+        resolved_body := webhook.body_template;
+        resolved_body := replace_placeholder(resolved_body,
+                                             'webhook_type',
+                                             'inventory_deleted');
+        resolved_body := replace_placeholder(resolved_body,
+                                             'product_serial',
+                                             OLD.product_serial::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'product_id',
+                                             OLD.product_id);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'description',
+                                             OLD.description);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'description_i18n',
+                                             encode(OLD.description_i18n,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'unit',
+                                             OLD.unit);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'image',
+                                             OLD.image);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'taxes',
+                                             encode(OLD.taxes,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'price',
+                                             OLD.price::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'total_stock',
+                                             OLD.total_stock::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'total_sold',
+                                             OLD.total_sold::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'total_lost',
+                                             OLD.total_lost::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'address',
+                                             encode(OLD.address,
+                                                    'escape'));
+        resolved_body := replace_placeholder(resolved_body,
+                                             'next_restock',
+                                             OLD.next_restock::TEXT);
+        resolved_body := replace_placeholder(resolved_body,
+                                             'minimum_age',
+                                             OLD.minimum_age::TEXT);
+
+        -- Insert into pending webhooks for this webhook
+        INSERT INTO merchant_pending_webhooks
+        (merchant_serial, webhook_serial, url, http_method, body)
+        VALUES
+          (webhook.merchant_serial,
+           webhook.webhook_serial,
+           webhook.url,
+           webhook.http_method,
+           resolved_body);
+      END LOOP;
+
+    -- Notify the webhook service
+    NOTIFY XXJWF6C1DCS1255RJH7GQ1EK16J8DMRSQ6K9EDKNKCP7HRVWAJPKG;
+  END IF;
+
+  RETURN NULL;
+END;
+$$ LANGUAGE plpgsql;
+
+-- Trigger to invoke the trigger function
+CREATE TRIGGER trigger_inventory_changes
+  AFTER INSERT OR UPDATE OR DELETE
+  ON merchant_inventory
+  FOR EACH ROW
+EXECUTE FUNCTION handle_inventory_changes();
+
+
+COMMIT;
diff --git a/src/backenddb/pg_insert_deposit_to_transfer.sql 
b/src/backenddb/pg_insert_deposit_to_transfer.sql
index ae43b613..7ffa19b0 100644
--- a/src/backenddb/pg_insert_deposit_to_transfer.sql
+++ b/src/backenddb/pg_insert_deposit_to_transfer.sql
@@ -35,6 +35,10 @@ DECLARE
   my_decose INT8;
 DECLARE
   my_order_serial INT8;
+DECLARE
+  my_merchant_serial INT8;
+DECLARE
+  my_order_id TEXT;
 BEGIN
 
 -- Find exchange sign key
@@ -157,4 +161,20 @@ UPDATE merchant_contract_terms
       WHERE mdc.wire_pending
         AND mdc.order_serial=my_order_serial);
 
+-- POSSIBLE LOCATION FOR THE WIRE WEBHOOK OF ORDER
+--
+-- INSERT INTO merchant_pending_webhooks
+-- (merchant_serial
+-- ,webhook_serial
+-- ,url
+-- ,http_method
+-- ,body)
+-- SELECT mw.merchant_serial
+--      ,mw.webhook_serial
+--      ,mw.url
+--      ,mw.http_method
+--      ,json_build_object('order_id', my_order_id)::TEXT
+-- FROM merchant_webhook mw
+-- WHERE mw.event_type = 'order_settled'
+--   AND mw.merchant_serial = my_merchant_serial;
 END $$;
diff --git a/src/backenddb/pg_insert_transfer_details.sql 
b/src/backenddb/pg_insert_transfer_details.sql
index 0dd11b1b..0d703246 100644
--- a/src/backenddb/pg_insert_transfer_details.sql
+++ b/src/backenddb/pg_insert_transfer_details.sql
@@ -41,6 +41,8 @@ DECLARE
   my_signkey_serial INT8;
   my_credit_serial INT8;
   my_affected_orders RECORD;
+  my_merchant_serial INT8;
+  my_order_id TEXT;
   i INT8;
   curs CURSOR (arg_coin_pub BYTEA) FOR
     SELECT mcon.deposit_confirmation_serial,
@@ -220,6 +222,29 @@ LOOP
             FROM merchant_deposit_confirmations mdc
              WHERE mdc.wire_pending
                AND mdc.order_serial=my_affected_orders.order_serial);
+
+      -- Select merchant_serial and order_id for webhook
+      SELECT merchant_serial, order_id
+        INTO my_merchant_serial, my_order_id
+        FROM merchant_contract_terms
+       WHERE order_serial=my_affected_orders.order_serial;
+
+      -- Insert pending webhook if it exists
+      INSERT INTO merchant_pending_webhooks
+      (merchant_serial
+      ,webhook_serial
+      ,url
+      ,http_method
+      ,body)
+      SELECT mw.merchant_serial
+            ,mw.webhook_serial
+            ,mw.url
+            ,mw.http_method
+            ,replace_placeholder(mw.body_template, 'order_id', 
my_order_id)::TEXT
+      FROM merchant_webhook mw
+      WHERE mw.event_type = 'order_settled'
+        AND mw.merchant_serial = my_merchant_serial;
+
     END IF;
 
   END LOOP; -- END curs LOOP
diff --git a/src/backenddb/test_webhook_trigger.sh 
b/src/backenddb/test_webhook_trigger.sh
new file mode 100755
index 00000000..160a42da
--- /dev/null
+++ b/src/backenddb/test_webhook_trigger.sh
@@ -0,0 +1,369 @@
+#!/bin/bash
+# This file is in the public domain.
+
+set -eu
+
+echo -n "Test if OpenSSL is available..."
+openssl &>/dev/null || (echo " No!" ; exit 77 )
+echo " OK"
+
+taler-merchant-dbinit -r -c test-merchantdb-postgres.conf
+
+# Generate random BYTEA values for testing
+WTID=$(openssl rand -hex 32)
+EXCHANGE_PUB=$(openssl rand -hex 32)
+EXCHANGE_SIG=$(openssl rand -hex 64)
+COIN_PUB=$(openssl rand -hex 32)
+
+# Generate valid BYTEA values
+MERCHANT_PUB=$(openssl rand -hex 32)
+AUTH_HASH=$(openssl rand -hex 64)
+AUTH_SALT=$(openssl rand -hex 32)
+
+# Define other parameters
+INSTANCE_ID="test-merchant"
+EXCHANGE_URL="http://example.com/exchange";
+PAYTO_URI="payto://example.com/account"
+EXECUTION_TIME=$(date +%s)
+
+# Generate taler_amount_currency values
+TOTAL_AMOUNT="ROW(100, 0, 'USD')::taler_amount_currency"
+WIRE_FEE="ROW(1, 0, 'USD')::taler_amount_currency"
+
+# Generate arrays for taler_amount_currency and BYTEA
+# Generate arrays for taler_amount_currency and BYTEA
+COIN_VALUES="ARRAY[ROW(10, 0, 'USD')::taler_amount_currency, ROW(20, 0, 
'USD')::taler_amount_currency, ROW(30, 0, 
'USD')::taler_amount_currency]::taler_amount_currency[]"
+DEPOSIT_FEES="ARRAY[ROW(1, 0, 'USD')::taler_amount_currency, ROW(2, 50000000, 
'USD')::taler_amount_currency, ROW(3, 25000000, 
'USD')::taler_amount_currency]::taler_amount_currency[]"
+COIN_PUBS="ARRAY[decode('$COIN_PUB', 'hex'), decode('$(openssl rand -hex 32)', 
'hex'), decode('$(openssl rand -hex 32)', 'hex')]::BYTEA[]"
+CONTRACT_TERMS="ARRAY[decode('$(openssl rand -hex 32)', 'hex'), 
decode('$(openssl rand -hex 32)', 'hex'), decode('$(openssl rand -hex 32)', 
'hex')]::BYTEA[]"
+
+# Create the merchant database
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_instances (
+          merchant_serial,
+          merchant_name,
+          merchant_id,
+          address,
+          jurisdiction,
+          default_wire_transfer_delay,
+          default_pay_delay,
+          merchant_pub,
+          auth_hash,
+          auth_salt
+      ) VALUES (
+          1,
+          'Test Merchant',
+          'test-merchant',
+          '{"city":"TestCity"}',
+          '{"country":"TestCountry"}',
+          3600,
+          3600,
+          decode('$MERCHANT_PUB', 'hex'),
+          decode('$AUTH_HASH', 'hex'),
+          decode('$AUTH_SALT', 'hex')
+      );" | psql talercheck
+
+# Create the webhooks
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_webhook (merchant_serial, webhook_id, event_type, 
url, http_method, body_template)
+      VALUES
+      (1, 'category_added_hook', 'category_added', 
'http://example.com/category_added', 'POST', '{"event":"{{ webhook_type }}"}'),
+      (1, 'category_updated_hook', 'category_updated', 
'http://example.com/category_updated', 'POST', '{"event":"{{ webhook_type 
}}"}'),
+      (1, 'category_deleted_hook', 'category_deleted', 
'http://example.com/category_deleted', 'POST', '{"event":"{{ webhook_type 
}}"}'),
+      (1, 'inventory_added_hook', 'inventory_added', 
'http://example.com/inventory_added', 'POST', '{"event":"{{ webhook_type }}"}'),
+      (1, 'inventory_updated_hook', 'inventory_updated', 
'http://example.com/inventory_updated', 'POST', '{"event":"{{ webhook_type 
}}"}'),
+      (1, 'inventory_deleted_hook', 'inventory_deleted', 
'http://example.com/inventory_deleted', 'POST', '{"event":"{{ webhook_type 
}}"}'),
+      (1, 'order_settled_hook', 'order_settled', 
'http://example.com/order_settled', 'POST', '{"event":"{{ webhook_type }}"}');" 
| psql talercheck
+
+# Create the category
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_categories (merchant_serial, category_name, 
category_name_i18n)
+      VALUES (1, 'Test Category', '{"en":"Test Category"}');" | psql talercheck
+
+# Update the category
+echo "SET search_path TO merchant;
+      UPDATE merchant_categories
+      SET category_name = 'Updated Category'
+      WHERE category_name = 'Test Category';" | psql talercheck
+
+# Delete the category
+echo "SET search_path TO merchant;
+      DELETE FROM merchant_categories
+      WHERE category_name = 'Updated Category';" | psql talercheck
+
+# Add product to inventory
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_inventory (merchant_serial, product_id, 
description, description_i18n, unit, image, taxes, price, total_stock, address, 
next_restock)
+      VALUES
+      (1, 'test-product', 'Test Product', '{"en":"Test Product"}', 'unit', 
'image-data-url', '[]', ROW(10, 0, 'USD'), 100, '{"city":"TestCity"}', 0);" | 
psql talercheck
+
+# Update product in inventory
+echo "SET search_path TO merchant;
+      UPDATE merchant_inventory
+      SET description = 'Updated Test Product'
+      WHERE product_id = 'test-product';" | psql talercheck
+
+# Delete product from inventory
+echo "SET search_path TO merchant;
+      DELETE FROM merchant_inventory
+      WHERE product_id = 'test-product';" | psql talercheck
+
+# Create the merchant account
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_accounts (
+          merchant_serial,
+          h_wire,
+          salt,
+          credit_facade_url,
+          credit_facade_credentials,
+          last_bank_serial,
+          payto_uri,
+          active
+      ) VALUES (
+          1,
+          decode('$(openssl rand -hex 64)', 'hex'),
+          decode('$(openssl rand -hex 16)', 'hex'),
+          'http://example.com/credit',
+          '{"key":"value"}',
+          0,
+          '$PAYTO_URI',
+          TRUE
+      );" | psql talercheck
+
+# Create the merchant transfer
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_transfers (
+          credit_serial,
+          exchange_url,
+          wtid,
+          credit_amount,
+          account_serial
+      ) VALUES (
+          1,
+          'http://example.com/exchange',
+          decode('$WTID', 'hex'),
+          ROW(100, 0, 'USD')::taler_amount_currency,
+          1
+      );" | psql talercheck
+
+# Create the exchange signing key
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_exchange_signing_keys (
+          master_pub,
+          exchange_pub,
+          start_date,
+          expire_date,
+          end_date,
+          master_sig
+      ) VALUES (
+          decode('$(openssl rand -hex 32)', 'hex'),
+          decode('$EXCHANGE_PUB', 'hex'),
+          EXTRACT(EPOCH FROM NOW()),
+          EXTRACT(EPOCH FROM NOW()) + 3600,
+          EXTRACT(EPOCH FROM NOW()) + 7200,
+          decode('$(openssl rand -hex 64)', 'hex')
+      );" | psql talercheck
+
+# Create the merchant_contract_terms
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_contract_terms (
+          order_serial,
+          merchant_serial,
+          order_id,
+          contract_terms,
+          wallet_data,
+          h_contract_terms,
+          creation_time,
+          pay_deadline,
+          refund_deadline,
+          paid,
+          wired,
+          fulfillment_url,
+          session_id,
+          pos_key,
+          pos_algorithm,
+          claim_token
+      ) VALUES (
+          1001,
+          1,
+          'order-1234',
+          decode('$(openssl rand -hex 64)', 'hex'),
+          '{"wallet":"test"}',
+          decode('$(openssl rand -hex 64)', 'hex'),
+          EXTRACT(EPOCH FROM NOW()),
+          EXTRACT(EPOCH FROM NOW()) + 3600,
+          EXTRACT(EPOCH FROM NOW()) + 7200,
+          FALSE,
+          FALSE,
+          'http://example.com/fulfillment',
+          '',
+          NULL,
+          0,
+          decode('$(openssl rand -hex 16)', 'hex')
+      );" | psql talercheck
+
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_deposit_confirmations (
+          order_serial,
+          deposit_timestamp,
+          exchange_url,
+          total_without_fee,
+          wire_fee,
+          signkey_serial,
+          exchange_sig,
+          account_serial,
+          wire_pending
+      ) VALUES (
+          1001,
+          EXTRACT(EPOCH FROM NOW()),
+          '$EXCHANGE_URL',
+          ROW(90, 0, 'USD')::taler_amount_currency,
+          ROW(10, 0, 'USD')::taler_amount_currency,
+          1,
+          decode('$EXCHANGE_SIG', 'hex'),
+          1,
+          TRUE
+      );" | psql talercheck
+
+echo "SET search_path TO merchant;
+      UPDATE merchant_contract_terms
+      SET wired = TRUE
+      WHERE order_serial = 1001
+        AND NOT EXISTS (
+            SELECT 1
+            FROM merchant_deposit_confirmations
+            WHERE wire_pending
+              AND order_serial = 1001
+        );" | psql talercheck
+
+# Handle deposit confirmation
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_deposit_confirmations (
+          order_serial,
+          deposit_timestamp,
+          exchange_url,
+          total_without_fee,
+          wire_fee,
+          signkey_serial,
+          exchange_sig,
+          account_serial,
+          wire_pending
+      ) VALUES (
+          1001,
+          EXTRACT(EPOCH FROM NOW()),
+          'http://example.com/exchange',
+          ROW(90, 0, 'USD')::taler_amount_currency,
+          ROW(10, 0, 'USD')::taler_amount_currency,
+          1,
+          decode('$(openssl rand -hex 64)', 'hex'),
+          1,
+          FALSE
+      );" | psql talercheck
+
+echo "SET search_path TO merchant;
+      UPDATE merchant_contract_terms
+      SET wired = TRUE
+      WHERE order_serial = 1001
+        AND NOT EXISTS (
+            SELECT 1
+            FROM merchant_deposit_confirmations
+            WHERE wire_pending
+              AND order_serial = 1001
+        );" | psql talercheck
+
+# Add entries to merchant_deposits
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_deposits (
+          deposit_serial,
+          coin_offset,
+          deposit_confirmation_serial,
+          coin_pub,
+          coin_sig,
+          amount_with_fee,
+          deposit_fee,
+          refund_fee
+      ) VALUES (
+          (SELECT COALESCE(MAX(deposit_serial), 0) + 1 FROM 
merchant_deposits),  -- deposit_serial
+          0,  -- coin_offset
+          1,  -- deposit_confirmation_serial (link to confirmation)
+          decode('$COIN_PUB', 'hex'),  -- coin_pub
+          decode('$(openssl rand -hex 64)', 'hex'),  -- coin_sig
+          ROW(30, 0, 'USD')::taler_amount_currency,  -- amount_with_fee
+          ROW(1, 0, 'USD')::taler_amount_currency,  -- deposit_fee
+          ROW(0, 0, 'USD')::taler_amount_currency   -- refund_fee
+      );" | psql talercheck
+
+# Link deposits to wire transfers
+echo "SET search_path TO merchant;
+      INSERT INTO merchant_deposit_to_transfer (
+          deposit_serial,
+          coin_contribution_value,
+          execution_time,
+          signkey_serial,
+          exchange_sig,
+          wtid
+      ) VALUES (
+          (SELECT MAX(deposit_serial) FROM merchant_deposits),  -- 
deposit_serial
+          ROW(10, 0, 'USD')::taler_amount_currency,  -- coin_contribution_value
+          $EXECUTION_TIME,  -- execution_time
+          1,  -- signkey_serial
+          decode('$(openssl rand -hex 64)', 'hex'),  -- exchange_sig
+          decode('$WTID', 'hex')  -- wtid
+      );" | psql talercheck
+
+
+# Debug the UPDATE condition
+echo "SET search_path TO merchant;
+      SELECT md.deposit_confirmation_serial, mdtt.wtid
+      FROM merchant_deposits md
+      LEFT JOIN merchant_deposit_to_transfer mdtt
+        USING (deposit_serial)
+      WHERE md.deposit_confirmation_serial=1
+        AND mdtt.wtid IS NULL;" | psql talercheck
+
+# Re-run the update logic
+echo "SET search_path TO merchant;
+      UPDATE merchant_deposit_confirmations
+       SET wire_pending=FALSE
+     WHERE deposit_confirmation_serial=1
+       AND NOT EXISTS
+       (SELECT 1
+          FROM merchant_deposits md
+          LEFT JOIN merchant_deposit_to_transfer mdtt
+            USING (deposit_serial)
+          WHERE md.deposit_confirmation_serial=1
+            AND mdtt.wtid IS NULL);" | psql talercheck
+
+
+echo "SET search_path TO merchant;
+      SELECT merchant_do_insert_transfer_details(
+          '$INSTANCE_ID',
+          '$EXCHANGE_URL',
+          '$PAYTO_URI',
+          decode('$WTID', 'hex')::BYTEA,
+          $EXECUTION_TIME::BIGINT,
+          decode('$EXCHANGE_PUB', 'hex')::BYTEA,
+          decode('$EXCHANGE_SIG', 'hex')::BYTEA,
+          $TOTAL_AMOUNT,
+          $WIRE_FEE,
+          $COIN_VALUES,
+          $DEPOSIT_FEES,
+          $COIN_PUBS,
+          $CONTRACT_TERMS
+      );" | psql talercheck
+
+# Echo all webhooks
+echo "SET search_path TO merchant;
+      SELECT * FROM merchant_pending_webhooks;" | psql talercheck
+
+# Fetch and validate the number of pending webhooks
+WEBHOOK_COUNT=$(echo "SET search_path TO merchant;
+                       SELECT COUNT(*)
+                       FROM merchant_pending_webhooks;" | psql talercheck -t 
-A | tr -d '[:space:]')
+
+if [ "$WEBHOOK_COUNT" -ne 7 ]; then
+  echo "ERROR: Expected 7 webhook entries, but received $WEBHOOK_COUNT."
+  exit 1
+else
+  echo "SUCCESS: Received 7 webhook entries as expected."
+fi

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]