merchant

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

commit 8fc8be0d00a68091204d4fcc12430a297baf3df0
parent d989aa1389eef18d82639edf0a058e1a3a5ec5a1
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu, 17 Jul 2025 14:27:32 +0200

fix #10185

Diffstat:
Msrc/backend/taler-merchant-httpd_config.c | 2+-
Msrc/backend/taler-merchant-httpd_private-get-orders.c | 226++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/backenddb/pg_lookup_statistics_counter_by_interval.c | 2+-
3 files changed, 140 insertions(+), 90 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_config.c b/src/backend/taler-merchant-httpd_config.c @@ -43,7 +43,7 @@ * #MERCHANT_PROTOCOL_CURRENT and #MERCHANT_PROTOCOL_AGE in * merchant_api_config.c! */ -#define MERCHANT_PROTOCOL_VERSION "20:0:17" +#define MERCHANT_PROTOCOL_VERSION "21:0:0" /** diff --git a/src/backend/taler-merchant-httpd_private-get-orders.c b/src/backend/taler-merchant-httpd_private-get-orders.c @@ -20,6 +20,7 @@ */ #include "platform.h" #include "taler-merchant-httpd_private-get-orders.h" +#include <taler/taler_merchant_util.h> #include <taler/taler_json_lib.h> #include <taler/taler_dbevents.h> @@ -302,11 +303,12 @@ add_order (void *cls, json_t *contract_terms = NULL; struct TALER_PrivateContractHashP h_contract_terms; enum GNUNET_DB_QueryStatus qs; - const char *summary; char *order_id = NULL; bool refundable = false; bool paid; - struct TALER_Amount order_amount; + bool wired; + struct TALER_MERCHANT_Contract *contract = NULL; + int16_t choice_index = -1; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Adding order `%s' (%llu) to result set at instance `%s'\n", @@ -341,13 +343,19 @@ add_order (void *cls, { /* First try to find the order in the contracts */ uint64_t os; - - qs = TMH_db->lookup_contract_terms (TMH_db->cls, - po->instance_id, - order_id, - &contract_terms, - &os, - NULL); + bool session_matches; + + qs = TMH_db->lookup_contract_terms3 (TMH_db->cls, + po->instance_id, + order_id, + NULL, + &contract_terms, + &os, + &paid, + &wired, + &session_matches, + NULL, + &choice_index); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) GNUNET_break (os == order_serial); } @@ -356,6 +364,8 @@ add_order (void *cls, /* Might still be unclaimed, so try order table */ struct TALER_MerchantPostDataHashP unused; + paid = false; + wired = false; qs = TMH_db->lookup_order (TMH_db->cls, po->instance_id, order_id, @@ -368,112 +378,152 @@ add_order (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Order %llu disappeared during iteration. Skipping.\n", (unsigned long long) order_serial); - json_decref (contract_terms); /* should still be NULL */ - GNUNET_free (order_id); - return; + goto cleanup; } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { GNUNET_break (0); po->result = TALER_EC_GENERIC_DB_FETCH_FAILED; - json_decref (contract_terms); - GNUNET_free (order_id); - return; + goto cleanup; } + contract = TALER_MERCHANT_contract_parse (contract_terms, + true); + if (NULL == contract) { - struct GNUNET_TIME_Timestamp rd; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("amount", - &order_amount), - GNUNET_JSON_spec_timestamp ("refund_deadline", - &rd), - GNUNET_JSON_spec_string ("summary", - &summary), - GNUNET_JSON_spec_end () + GNUNET_break (0); + po->result = TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID; + goto cleanup; + } + + if (GNUNET_TIME_absolute_is_future ( + contract->refund_deadline.abs_time) && + paid) + { + struct ProcessRefundsClosure prc = { + .ec = TALER_EC_NONE }; + const struct TALER_Amount *brutto; - if (GNUNET_OK != - GNUNET_JSON_parse (contract_terms, - spec, - NULL, NULL)) + switch (contract->version) { + case TALER_MERCHANT_CONTRACT_VERSION_0: + brutto = &contract->details.v0.brutto; + break; + case TALER_MERCHANT_CONTRACT_VERSION_1: + { + struct TALER_MERCHANT_ContractChoice *choice + = &contract->details.v1.choices[choice_index]; + + GNUNET_assert (choice_index < contract->details.v1.choices_len); + brutto = &choice->amount; + } + break; + default: GNUNET_break (0); - po->result = TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID; - json_decref (contract_terms); - GNUNET_free (order_id); - return; + goto cleanup; + } + + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (brutto->currency, + &prc.total_refund_amount)); + qs = TMH_db->lookup_refunds_detailed (TMH_db->cls, + po->instance_id, + &h_contract_terms, + &process_refunds_cb, + &prc); + if (0 > qs) + { + GNUNET_break (0); + po->result = TALER_EC_GENERIC_DB_FETCH_FAILED; + goto cleanup; } + if (TALER_EC_NONE != prc.ec) + { + GNUNET_break (0); + po->result = prc.ec; + goto cleanup; + } + if (0 > TALER_amount_cmp (&prc.total_refund_amount, + brutto)) + refundable = true; + } - if (TALER_amount_is_zero (&order_amount) && + switch (contract->version) + { + case TALER_MERCHANT_CONTRACT_VERSION_0: + if (TALER_amount_is_zero (&contract->details.v0.brutto) && (po->of.wired != TALER_EXCHANGE_YNA_ALL) ) { /* If we are actually filtering by wire status, and the order was over an amount of zero, do not return it as wire status is not exactly meaningful for orders over zero. */ - json_decref (contract_terms); - GNUNET_free (order_id); - return; + goto cleanup; } - - if (GNUNET_TIME_absolute_is_future (rd.abs_time) && - paid) + GNUNET_assert ( + 0 == + json_array_append_new ( + po->pa, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("order_id", + contract->order_id), + GNUNET_JSON_pack_uint64 ("row_id", + order_serial), + GNUNET_JSON_pack_timestamp ("timestamp", + creation_time), + TALER_JSON_pack_amount ( + "amount", + &contract->details.v0.brutto), + GNUNET_JSON_pack_string ("summary", + contract->summary), + GNUNET_JSON_pack_bool ("refundable", + refundable), + GNUNET_JSON_pack_bool ("paid", + paid)))); + break; + case TALER_MERCHANT_CONTRACT_VERSION_1: + if (-1 == choice_index) + choice_index = 0; /* default choice */ + GNUNET_assert (choice_index < contract->details.v1.choices_len); { - struct ProcessRefundsClosure prc = { - .ec = TALER_EC_NONE - }; - - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (order_amount.currency, - &prc.total_refund_amount)); - qs = TMH_db->lookup_refunds_detailed (TMH_db->cls, - po->instance_id, - &h_contract_terms, - &process_refunds_cb, - &prc); - if (0 > qs) - { - GNUNET_break (0); - po->result = TALER_EC_GENERIC_DB_FETCH_FAILED; - json_decref (contract_terms); - GNUNET_free (order_id); - return; - } - if (TALER_EC_NONE != prc.ec) - { - GNUNET_break (0); - po->result = prc.ec; - json_decref (contract_terms); - GNUNET_free (order_id); - return; - } - if (0 > TALER_amount_cmp (&prc.total_refund_amount, - &order_amount)) - refundable = true; + struct TALER_MERCHANT_ContractChoice *choice + = &contract->details.v1.choices[choice_index]; + + GNUNET_assert ( + 0 == + json_array_append_new ( + po->pa, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("order_id", + contract->order_id), + GNUNET_JSON_pack_uint64 ("row_id", + order_serial), + GNUNET_JSON_pack_timestamp ("timestamp", + creation_time), + TALER_JSON_pack_amount ("amount", + &choice->amount), + GNUNET_JSON_pack_string ("summary", + contract->summary), + GNUNET_JSON_pack_bool ("refundable", + refundable), + GNUNET_JSON_pack_bool ("paid", + paid)))); } + break; + default: + GNUNET_break (0); + goto cleanup; } - GNUNET_assert (0 == - json_array_append_new ( - po->pa, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("order_id", - order_id), - GNUNET_JSON_pack_uint64 ("row_id", - order_serial), - GNUNET_JSON_pack_timestamp ("timestamp", - creation_time), - TALER_JSON_pack_amount ("amount", - &order_amount), - GNUNET_JSON_pack_string ("summary", - summary), - GNUNET_JSON_pack_bool ("refundable", - refundable), - GNUNET_JSON_pack_bool ("paid", - paid)))); +cleanup: json_decref (contract_terms); GNUNET_free (order_id); + if (NULL != contract) + { + TALER_MERCHANT_contract_free (contract); + contract = NULL; + } } diff --git a/src/backenddb/pg_lookup_statistics_counter_by_interval.c b/src/backenddb/pg_lookup_statistics_counter_by_interval.c @@ -155,7 +155,7 @@ TMH_PG_lookup_statistics_counter_by_interval ( struct LookupCounterStatisticsContext context = { .cb = cb, .cb_cls = cb_cls, - /* Can be overwritten by the lookup_token_families_cb */ + /* Can be overwritten by the lookup_statistics_counter_by_interval_cb */ .extract_failed = false, .description = NULL };