merchant

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

commit 5c3299e4ecc82fa58b7014da8e8899d2c295bf42
parent 96f82418c638a2d91f047319fdd589068e8f8e7f
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu, 30 Jul 2026 11:18:49 +0200

implement #11693

Diffstat:
Msrc/backend/taler-merchant-httpd_get-private-orders.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/include/taler/merchant/get-private-orders.h | 2++
Msrc/lib/merchant_api_get-private-orders.c | 5+++--
Msrc/testing/test_merchant_transfer_tracking.sh | 47+++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 111 insertions(+), 20 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_get-private-orders.c b/src/backend/taler-merchant-httpd_get-private-orders.c @@ -1495,26 +1495,67 @@ TMH_private_get_orders (const struct TMH_RequestHandler *rh, } } } - if ( (po->of.delta > 0) && - (NULL != - MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "max_age")) ) + if (po->of.delta > 0) { /* Only narrow the range if the client actually asked for it: - without the argument, the parser below would set @e duration - to zero and thus cut off everything created before *now*. */ - struct GNUNET_TIME_Relative duration; - struct GNUNET_TIME_Absolute cut_off; - - TALER_MHD_parse_request_rel_time (connection, - "max_age", - &duration); - cut_off = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (), - duration); - po->of.date = GNUNET_TIME_timestamp_max ( - po->of.date, - GNUNET_TIME_absolute_to_timestamp (cut_off)); + the default duration of zero would cut off everything + created before *now*. */ + bool have_max_age + = (NULL != + MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "max_age")); + bool have_max_age_s + = (NULL != + MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "max_age_s")); + struct GNUNET_TIME_Relative duration = GNUNET_TIME_UNIT_ZERO; + + if (have_max_age) + { + /* deprecated in protocol v33, superseded by "max_age_s" */ + TALER_MHD_parse_request_rel_time (connection, + "max_age", + &duration); + } + if (have_max_age_s) + { + /* since protocol v33 */ + uint64_t max_age_s = 0; + struct GNUNET_TIME_Relative age; + + TALER_MHD_parse_request_number (connection, + "max_age_s", + &max_age_s); + age = GNUNET_TIME_relative_saturating_multiply (GNUNET_TIME_UNIT_SECONDS, + max_age_s); + if (have_max_age && + GNUNET_TIME_relative_cmp (duration, + !=, + age)) + { + unsigned long long max_age_ms + = duration.rel_value_us + / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Client gave conflicting values for `max_age' (%llu ms) and `max_age_s' (%llu s); using `max_age_s'\n", + max_age_ms, + (unsigned long long) max_age_s); + } + duration = age; + } + if (have_max_age || have_max_age_s) + { + struct GNUNET_TIME_Absolute cut_off; + + cut_off = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (), + duration); + po->of.date = GNUNET_TIME_timestamp_max ( + po->of.date, + GNUNET_TIME_absolute_to_timestamp (cut_off)); + } } if (po->of.delta > 0) po->of.start_row = 0; diff --git a/src/include/taler/merchant/get-private-orders.h b/src/include/taler/merchant/get-private-orders.h @@ -350,6 +350,8 @@ TALER_MERCHANT_get_private_orders_create ( /** * Set maximum age filter. Only return orders younger than the * specified age. Only applicable if limit is positive. + * Transmitted with a granularity of one second, so sub-second + * parts of @a a are rounded down. * @since protocol v27. * * @param a maximum age as a relative time diff --git a/src/lib/merchant_api_get-private-orders.c b/src/lib/merchant_api_get-private-orders.c @@ -420,7 +420,8 @@ TALER_MERCHANT_get_private_orders_start ( sizeof (mabuf), "%llu", (unsigned long long) - oph->max_age.rel_value_us); + (oph->max_age.rel_value_us + / GNUNET_TIME_UNIT_SECONDS.rel_value_us)); GNUNET_snprintf (dbuf, sizeof (dbuf), "%lld", @@ -496,7 +497,7 @@ TALER_MERCHANT_get_private_orders_start ( fec, "summary_filter", sfilt, - "max_age", + "max_age_s", oph->have_max_age ? mabuf : NULL, diff --git a/src/testing/test_merchant_transfer_tracking.sh b/src/testing/test_merchant_transfer_tracking.sh @@ -193,6 +193,53 @@ echo " OK" ORDER_ID=$(jq -e -r .order_id < "$LAST_RESPONSE") #TOKEN=$(jq -e -r .token < "$LAST_RESPONSE") +# Lists orders with the given extra query arguments and checks whether the +# order created above is included ($2 is "some") or filtered out ($2 is +# "none"). The age filters only apply to an ascending listing, hence the +# hard-coded positive "limit". +check_order_listing() { + local args="$1" + local expect="$2" + local status + local num + + status=$(curl "http://localhost:9966/instances/test/private/orders?limit=20&$args" \ + -w "%{http_code}" \ + -s \ + -o "$LAST_RESPONSE") + if [ "$status" != "200" ] + then + cat "$LAST_RESPONSE" + exit_fail "Expected 200 ok listing orders with '$args'. got: $status" + fi + num=$(jq -e -r '.orders | length' < "$LAST_RESPONSE") + if [ "none" = "$expect" ] && [ "0" != "$num" ] + then + exit_fail "Expected no orders listed with '$args', got $num" + fi + if [ "some" = "$expect" ] && [ "0" = "$num" ] + then + exit_fail "Expected orders to be listed with '$args', got none" + fi +} + +echo -n "Checking order listing with max_age_s..." +check_order_listing 'max_age_s=3600' some +check_order_listing 'max_age_s=0' none +echo " OK" + +# "max_age" was deprecated in protocol v33, but MUST still work. +echo -n "Checking order listing with deprecated max_age..." +check_order_listing 'max_age=3600000' some +check_order_listing 'max_age=0' none +echo " OK" + +# If both are given, "max_age_s" wins (and the backend logs a warning). +echo -n "Checking that max_age_s takes precedence over max_age..." +check_order_listing 'max_age=0&max_age_s=3600' some +check_order_listing 'max_age=3600000&max_age_s=0' none +echo " OK" + echo -n "Checking for Typst ..." if typst --version 2> /dev/null > /dev/null then