commit 432177857128fd3b541d861eff160a817cb4c1bc
parent 374146b643d5238ef1fdad0b5b1ceffc27d6906a
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 22 Mar 2026 13:58:13 +0100
fix API and tests to work also with donation tokens
Diffstat:
5 files changed, 200 insertions(+), 42 deletions(-)
diff --git a/src/include/taler/taler-merchant/post-orders-ORDER_ID-pay-new.h b/src/include/taler/taler-merchant/post-orders-ORDER_ID-pay-new.h
@@ -25,6 +25,11 @@
#include <taler/taler-merchant/common.h>
+/**
+ * Forward-declaration here to keep the API stable even if
+ * the Donau header is not available.
+ */
+struct DONAU_BlindedUniqueDonorIdentifierKeyPair;
/**
* One coin used to pay (frontend / external wallet mode).
@@ -256,7 +261,12 @@ enum TALER_MERCHANT_PostOrdersPayOption
/**
* Output tokens as JSON array (for frontend mode).
*/
- TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS_JSON
+ TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS_JSON,
+
+ /**
+ * Output donation receipts.
+ */
+ TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU
};
@@ -296,6 +306,9 @@ struct TALER_MERCHANT_PostOrdersPayOptionValue
*/
struct
{
+ /**
+ * Length of @e tokens array
+ */
unsigned int num;
const struct TALER_MERCHANT_PostOrdersPayUsedToken *tokens;
} used_tokens;
@@ -306,6 +319,9 @@ struct TALER_MERCHANT_PostOrdersPayOptionValue
*/
struct
{
+ /**
+ * Length of @e tokens array
+ */
unsigned int num;
const struct TALER_MERCHANT_PostOrdersPayUseToken *tokens;
} use_tokens;
@@ -316,6 +332,9 @@ struct TALER_MERCHANT_PostOrdersPayOptionValue
*/
struct
{
+ /**
+ * Length of @e tokens array
+ */
unsigned int num;
const struct TALER_MERCHANT_PostOrdersPayOutputToken *tokens;
} output_tokens;
@@ -326,6 +345,33 @@ struct TALER_MERCHANT_PostOrdersPayOptionValue
*/
json_t *output_tokens_json;
+ /**
+ * Value if @e option is
+ * #TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU.
+ */
+ struct
+ {
+ /**
+ * Base URL of the donau.
+ */
+ const char *donau_base_url;
+
+ /**
+ * Array of blinded dontation receipts.
+ */
+ const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps;
+
+ /**
+ * Length of @e bkps array
+ */
+ size_t num_bkps;
+
+ /**
+ * Year for which the donation receipts are issued.
+ */
+ uint64_t year;
+ } output_donau;
+
} details;
};
@@ -499,6 +545,26 @@ struct TALER_MERCHANT_PostOrdersPayResponse
/**
+ * Set blinded donation receipts as output.
+ *
+ * @param u base URL of the selected Donau
+ * @param y year for which receipts are requested
+ * @param l length of the @a bkps array
+ * @param a array of blinded donation receipts
+ * @return representation of the option
+ */
+#define TALER_MERCHANT_post_orders_pay_option_output_donau(u,y,l,a) \
+ (const struct TALER_MERCHANT_PostOrdersPayOptionValue) \
+ { \
+ .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU, \
+ .details.output_donau.donau_base_url = (u), \
+ .details.output_donau.bkps = (a), \
+ .details.output_donau.num_bkps = (l), \
+ .details.output_donau.year = (y) \
+ }
+
+
+/**
* Set the requested options for the operation.
*
* @param poph the request to set the options for
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
@@ -101,6 +101,7 @@ if HAVE_DONAU
merchant_api_delete-private-donau-DONAU_SERIAL-new.c
libtalermerchant_la_LIBADD += \
+ -ldonaujson \
-ldonau
endif
diff --git a/src/lib/merchant_api_post-orders-ORDER_ID-pay-new.c b/src/lib/merchant_api_post-orders-ORDER_ID-pay-new.c
@@ -34,7 +34,10 @@
#include <taler/taler_json_lib.h>
#include <taler/taler_curl_lib.h>
#include <taler/taler_signatures.h>
-
+#if HAVE_DONAU_DONAU_SERVICE_H
+#include <donau/donau_service.h>
+#include <donau/donau_json_lib.h>
+#endif
/**
* Handle for a POST /orders/$ORDER_ID/pay operation.
@@ -197,6 +200,26 @@ struct TALER_MERCHANT_PostOrdersPayHandle
json_t *output_tokens_json;
/**
+ * Base URL of the selected donau for donation receipts.
+ */
+ char *donau_url;
+
+ /**
+ * Tax year used for the donau.
+ */
+ unsigned int donau_year;
+
+ /**
+ * Array of blinded donation receipts.
+ */
+ struct DONAU_BlindedUniqueDonorIdentifierKeyPair *donau_bkps;
+
+ /**
+ * Length of the @e donau_bkps array.
+ */
+ size_t num_donau_bkps;
+
+ /**
* Set to true if this is the wallet mode (private keys available).
*/
bool am_wallet;
@@ -630,6 +653,40 @@ TALER_MERCHANT_post_orders_pay_set_options_ (
poph->output_tokens_json = json_incref (
options[i].details.output_tokens_json);
break;
+ case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU:
+#if HAVE_DONAU_DONAU_SERVICE_H
+ if (NULL != poph->donau_url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Only one set of donation receipts is allowed to be specified\n");
+ return GNUNET_NO;
+ }
+ poph->donau_url
+ = GNUNET_strdup (options[i].details.output_donau.donau_base_url);
+ poph->donau_year
+ = options[i].details.output_donau.year;
+ poph->num_donau_bkps = options[i].details.output_donau.num_bkps;
+ poph->donau_bkps = GNUNET_new_array (
+ poph->num_donau_bkps,
+ struct DONAU_BlindedUniqueDonorIdentifierKeyPair);
+ for (size_t j=0; j<poph->num_donau_bkps; j++)
+ {
+ const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *src
+ = &options[i].details.output_donau.bkps[j];
+ struct DONAU_BlindedUniqueDonorIdentifierKeyPair *dst
+ = &poph->donau_bkps[j];
+
+ dst->h_donation_unit_pub = src->h_donation_unit_pub;
+ dst->blinded_udi.blinded_message
+ = GNUNET_CRYPTO_blinded_message_incref (
+ src->blinded_udi.blinded_message);
+ }
+ break;
+#else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Donation receipts are not supported by this build!\n");
+ return GNUNET_NO;
+#endif
default:
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -671,8 +728,39 @@ TALER_MERCHANT_post_orders_pay_start (
{
/* Wallet mode: sign coins and tokens, build wallet_data */
json_t *wallet_data = poph->wallet_data;
+ json_t *j_donau_data = NULL;
struct GNUNET_HashCode wallet_data_hash;
+ if (NULL != poph->donau_url)
+ {
+ json_t *budis;
+
+ budis = json_array ();
+ GNUNET_assert (NULL != budis);
+ for (size_t i=0; i<poph->num_donau_bkps; i++)
+ {
+ const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp
+ = &poph->donau_bkps[i];
+ json_t *budikeypair = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("h_donation_unit_pub",
+ &bkp->h_donation_unit_pub),
+ DONAU_JSON_pack_blinded_donation_identifier ("blinded_udi",
+ &bkp->blinded_udi));
+
+ GNUNET_assert (0 ==
+ json_array_append_new (budis,
+ budikeypair));
+ }
+
+ j_donau_data = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("url",
+ poph->donau_url),
+ GNUNET_JSON_pack_int64 ("year",
+ poph->donau_year),
+ GNUNET_JSON_pack_array_steal ("budikeypairs",
+ budis));
+ }
+
/* Build output token envelopes JSON if we have output tokens */
if (0 < poph->num_output_tokens)
{
@@ -693,6 +781,7 @@ TALER_MERCHANT_post_orders_pay_start (
{
GNUNET_break (0);
json_decref (j_output_tokens);
+ json_decref (j_donau_data);
return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
}
}
@@ -711,12 +800,17 @@ TALER_MERCHANT_post_orders_pay_start (
GNUNET_JSON_pack_int64 ("choice_index",
poph->choice_index),
GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("donau",
+ j_donau_data)),
+ GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_array_incref ("tokens_evs",
j_output_tokens)));
}
TALER_json_hash (wallet_data,
&wallet_data_hash);
}
+ json_decref (j_donau_data);
+ j_donau_data = NULL;
if ( (0 < poph->num_use_tokens || 0 < poph->num_output_tokens
|| NULL != poph->output_tokens_json)
@@ -1004,6 +1098,15 @@ TALER_MERCHANT_post_orders_pay_cancel (
}
GNUNET_free (poph->coins);
}
+ for (size_t j = 0; j<poph->num_donau_bkps; j++)
+ {
+ struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bpk
+ = &poph->donau_bkps[j];
+
+ GNUNET_CRYPTO_blinded_message_decref (bpk->blinded_udi.blinded_message);
+ }
+ GNUNET_free (poph->donau_bkps);
+ GNUNET_free (poph->donau_url);
GNUNET_free (poph->used_tokens);
GNUNET_free (poph->use_tokens);
GNUNET_free (poph->output_tokens);
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
@@ -3301,23 +3301,36 @@ run (void *cls,
repurchase),
TALER_TESTING_cmd_batch ("tokens",
tokens),
-
- #ifdef HAVE_DONAU_DONAU_SERVICE_H
+#ifdef HAVE_DONAU_DONAU_SERVICE_H
TALER_TESTING_cmd_batch ("donau",
donau),
- #endif
+#endif
TALER_TESTING_cmd_merchant_get_statisticsamount ("stats-refund",
merchant_url,
- "refunds-granted", 6, 0,
+ "refunds-granted",
+ 6,
+ 0,
MHD_HTTP_OK),
TALER_TESTING_cmd_merchant_get_statisticscounter ("stats-tokens-issued",
merchant_url,
- "tokens-issued", 6, 0,
+ "tokens-issued",
+ 6,
+#ifdef HAVE_DONAU_DONAU_SERVICE_H
+ 2,
+#else
+ 0,
+#endif
MHD_HTTP_OK),
TALER_TESTING_cmd_merchant_get_statisticscounter ("stats-tokens-used",
merchant_url,
- "tokens-used", 6, 0,
+ "tokens-used",
+ 6,
+#ifdef HAVE_DONAU_DONAU_SERVICE_H
+ 2,
+#else
+ 0,
+#endif
MHD_HTTP_OK),
/**
diff --git a/src/testing/testing_api_cmd_pay_order.c b/src/testing/testing_api_cmd_pay_order.c
@@ -149,11 +149,6 @@ struct MerchantDonauPayData
* asynchronous calls are still pending, etc.
*/
unsigned int cs_pending;
-
- /**
- * Budis Key Pairs json
- */
- json_t *budis_json;
};
@@ -321,26 +316,6 @@ prepare_donau_data (struct TALER_TESTING_Interpreter *is,
GNUNET_break (0);
}
}
-
- {
- json_t *budikeypairs = json_array ();
-
- GNUNET_assert (NULL != budikeypairs);
- for (size_t i = 0; i < ss->num_bkps; i++)
- {
- json_t *budikeypair = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto ("h_donation_unit_pub",
- &ss->bkps[i].h_donation_unit_pub),
- DONAU_JSON_pack_blinded_donation_identifier ("blinded_udi",
- &ss->bkps[i].blinded_udi)
- );
-
- /* steal the reference into the array */
- GNUNET_assert (0 == json_array_append_new (budikeypairs,
- budikeypair));
- }
- ss->budis_json = budikeypairs;
- }
}
return GNUNET_OK;
};
@@ -1446,20 +1421,20 @@ pay_run (void *cls,
len_output_tokens,
output_tokens)));
-#if 1
#ifdef HAVE_DONAU_DONAU_SERVICE_H
if (ps->donau_data.charity_reference)
{
- ADD (
- TALER_MERCHANT_POST_ORDERS_PAY_OPTION_DONAU_URL (ps->donau_data.
- donau_url));
- ADD (TALER_MERCHANT_POST_ORDERS_PAY_OPTION_DONAU_YEAR (ps->donau_data.year
- ));
- ADD (TALER_MERCHANT_POST_ORDERS_PAY_OPTION_DONAU_BUDIS (
- ps->donau_data.budis_json));
+ GNUNET_assert (
+ GNUNET_OK ==
+ TALER_MERCHANT_post_orders_pay_set_options (
+ ps->oph,
+ TALER_MERCHANT_post_orders_pay_option_output_donau (
+ ps->donau_data.donau_url,
+ ps->donau_data.year,
+ ps->donau_data.num_bkps,
+ ps->donau_data.bkps)));
}
#endif
-#endif
if (TALER_EC_NONE !=
TALER_MERCHANT_post_orders_pay_start (ps->oph,
&pay_cb,