From 9d0a68e578a77cbe9c1443dc1831de157b8a0fa8 Mon Sep 17 00:00:00 2001 From: Jonathan Buchanan Date: Thu, 25 Jun 2020 01:55:15 -0400 Subject: wallet get order handles refunds properly --- src/backend/taler-merchant-httpd_get-orders-ID.c | 113 ++++++++++++++++------- src/include/taler_merchant_testing_lib.h | 7 +- src/testing/test_merchant_api.c | 7 +- src/testing/testing_api_cmd_wallet_get_order.c | 74 ++++++++++++++- 4 files changed, 163 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.c b/src/backend/taler-merchant-httpd_get-orders-ID.c index 8dd858a3..1a7c16a4 100644 --- a/src/backend/taler-merchant-httpd_get-orders-ID.c +++ b/src/backend/taler-merchant-httpd_get-orders-ID.c @@ -646,6 +646,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, god->ec = TALER_EC_NONE; god->hc = hc; god->order_id = order_id; + god->cr_head = NULL; { const char *cts; @@ -887,7 +888,34 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, } /* At this point, we know the contract was paid. Let's check for - refunds */ + refunds. First, clear away refunds found from previous invocations. */ + { + struct CoinRefund *cr; + + while (NULL != (cr = god->cr_head)) + { + GNUNET_CONTAINER_DLL_remove (god->cr_head, + god->cr_tail, + cr); + if (NULL != cr->fo) + { + TMH_EXCHANGES_find_exchange_cancel (cr->fo); + cr->fo = NULL; + } + if (NULL != cr->rh) + { + TALER_EXCHANGE_refund_cancel (cr->rh); + cr->rh = NULL; + } + if (NULL != cr->exchange_reply) + { + json_decref (cr->exchange_reply); + cr->exchange_reply = NULL; + } + GNUNET_free (cr->exchange_url); + GNUNET_free (cr); + } + } GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (TMH_currency, &god->refund_amount)); qs = TMH_db->lookup_refunds_detailed (TMH_db->cls, @@ -984,40 +1012,59 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, NULL != cr; cr = cr->next) { + json_t *refund; + if (MHD_HTTP_OK != cr->exchange_status) + { + if (NULL == cr->exchange_reply) + { + refund = json_pack ("{s:I,s:I,s:o,s:o}" + "exchange_status", + (json_int_t) cr->exchange_status, + "rtransaction_id", + (json_int_t) cr->rtransaction_id, + "coin_pub", + GNUNET_JSON_from_data_auto (&cr->coin_pub), + "refund_amount", + TALER_JSON_from_amount (&cr->refund_amount)); + } + else + { + refund = json_pack ("{s:I,s:I,s:o,s:I,s:o,s:o}" + "exchange_status", + (json_int_t) cr->exchange_status, + "exchange_code", + (json_int_t) cr->exchange_code, + "exchange_reply", + cr->exchange_reply, + "rtransaction_id", + (json_int_t) cr->rtransaction_id, + "coin_pub", + GNUNET_JSON_from_data_auto (&cr->coin_pub), + "refund_amount", + TALER_JSON_from_amount (&cr->refund_amount)); + } + } + else + { + refund = json_pack ("{s:I,s:o,s:o,s:I,s:o,s:o}", + "exchange_status", + (json_int_t) cr->exchange_status, + "exchange_sig", + GNUNET_JSON_from_data_auto (&cr->exchange_sig), + "exchange_pub", + GNUNET_JSON_from_data_auto (&cr->exchange_pub), + "rtransaction_id", + (json_int_t) cr->rtransaction_id, + "coin_pub", + GNUNET_JSON_from_data_auto (&cr->coin_pub), + "refund_amount", + TALER_JSON_from_amount (&cr->refund_amount), + "exchange_http_status"); + } GNUNET_assert ( 0 == - json_array_append_new ( - ra, - (MHD_HTTP_OK != cr->exchange_status) - ? json_pack ((NULL != cr->exchange_reply) - ? "{s:o,s:o,s:I,s:I,s:I,s:O}" - : "{s:o,s:o,s:I,s:I:s:I}", - "coin_pub", - GNUNET_JSON_from_data_auto (&cr->coin_pub), - "refund_amount", - TALER_JSON_from_amount (&cr->refund_amount), - "exchange_http_status", - (json_int_t) cr->exchange_status, - "rtransaction_id", - (json_int_t) cr->rtransaction_id, - "exchange_code", - (json_int_t) cr->exchange_code, - "exchange_reply", - cr->exchange_reply) - : json_pack ("{s:o,s:o,s:I,s:I,s:o,s:o}", - "coin_pub", - GNUNET_JSON_from_data_auto (&cr->coin_pub), - "refund_amount", - TALER_JSON_from_amount (&cr->refund_amount), - "exchange_http_status", - (json_int_t) cr->exchange_status, - "rtransaction_id", - (json_int_t) cr->rtransaction_id, - "exchange_pub", - GNUNET_JSON_from_data_auto (&cr->exchange_pub), - "exchange_sig", - GNUNET_JSON_from_data_auto (&cr->exchange_sig) - ))); + json_array_append_new (ra, + refund)); } return TALER_MHD_reply_json_pack ( diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h index 5ad4ff06..31ed45a1 100644 --- a/src/include/taler_merchant_testing_lib.h +++ b/src/include/taler_merchant_testing_lib.h @@ -464,6 +464,10 @@ TALER_TESTING_cmd_merchant_get_orders (const char *label, * @param paid whether the order has been paid for or not. * @param refunded whether the order has been refunded. * @param http_status expected HTTP response code for the request. + * @param ... NULL-terminated list of labels (const char *) of + * refunds (commands) we expect to be aggregated in the transfer + * (assuming @a http_code is #MHD_HTTP_OK). If @e refunded is false, + * this parameter is ignored. */ struct TALER_TESTING_Command TALER_TESTING_cmd_wallet_get_order (const char *label, @@ -471,7 +475,8 @@ TALER_TESTING_cmd_wallet_get_order (const char *label, const char *order_reference, bool paid, bool refunded, - unsigned int http_status); + unsigned int http_status, + ...); /** diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c index 0856757b..b1b518d8 100644 --- a/src/testing/test_merchant_api.c +++ b/src/testing/test_merchant_api.c @@ -562,13 +562,14 @@ run (void *cls, "1r", /* order ID */ "EUR:0.1", MHD_HTTP_OK), - /* TALER_TESTING_cmd_wallet_get_order ("get-order-wallet-1r", merchant_url, "create-proposal-1r", true, true, - MHD_HTTP_OK),*/ + MHD_HTTP_OK, + "refund-increase-1r", + NULL), #if 0 TALER_TESTING_cmd_poll_payment_conclude ("poll-payment-refund-conclude-1", MHD_HTTP_OK, @@ -662,7 +663,7 @@ run (void *cls, TALER_TESTING_cmd_check_bank_transfer ( "check_bank_transfer-paid-unincreased-refund", EXCHANGE_URL, - "EUR:9.97", /* '4.98 from above', plus 4.99 from 'pay-for-refund-1r' + "EUR:9.88", /* '4.98 from above', plus 4.99 from 'pay-for-refund-1r' and MINUS 0.1 PLUS 0.01 (deposit fee) from 'refund-increase-1r' */ exchange_payto, merchant_payto), diff --git a/src/testing/testing_api_cmd_wallet_get_order.c b/src/testing/testing_api_cmd_wallet_get_order.c index 7cc9c352..86072f4f 100644 --- a/src/testing/testing_api_cmd_wallet_get_order.c +++ b/src/testing/testing_api_cmd_wallet_get_order.c @@ -67,6 +67,16 @@ struct WalletGetOrderState * Whether the order was refunded or not. */ bool refunded; + + /** + * A NULL-terminated list of refunds associated with this order. + */ + const char **refunds; + + /** + * The length of @e refunds. + */ + unsigned int refunds_length; }; @@ -138,6 +148,48 @@ wallet_get_order_cb ( TALER_TESTING_interpreter_fail (gos->is); return; } + if (gos->refunds_length != num_refunds) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Order refunds count does not match\n"); + TALER_TESTING_interpreter_fail (gos->is); + return; + } + for (unsigned int i = 0; i < num_refunds; ++i) + { + const struct TALER_TESTING_Command *refund_cmd; + const char *expected_amount_str; + struct TALER_Amount expected_amount; + + refund_cmd = TALER_TESTING_interpreter_lookup_command ( + gos->is, + gos->refunds[i]); + + if (GNUNET_OK != + TALER_TESTING_get_trait_string (refund_cmd, + 0, + &expected_amount_str)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not fetch refund amount\n"); + TALER_TESTING_interpreter_fail (gos->is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (expected_amount_str, + &expected_amount)); + if ((GNUNET_OK != + TALER_amount_cmp_currency (&expected_amount, + &refunds[i].refund_amount)) || + (0 != TALER_amount_cmp (&expected_amount, + &refunds[i].refund_amount))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Refund amounts do not match\n"); + TALER_TESTING_interpreter_fail (gos->is); + return; + } + } break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -225,6 +277,10 @@ wallet_get_order_cleanup (void *cls, * @param paid whether the order has been paid for or not. * @param refunded whether the order has been refunded. * @param http_status expected HTTP response code for the request. + * @param ... NULL-terminated list of labels (const char *) of + * refunds (commands) we expect to be aggregated in the transfer + * (assuming @a http_code is #MHD_HTTP_OK). If @e refunded is false, + * this parameter is ignored. */ struct TALER_TESTING_Command TALER_TESTING_cmd_wallet_get_order (const char *label, @@ -232,7 +288,8 @@ TALER_TESTING_cmd_wallet_get_order (const char *label, const char *order_reference, bool paid, bool refunded, - unsigned int http_status) + unsigned int http_status, + ...) { struct WalletGetOrderState *gos; @@ -242,6 +299,21 @@ TALER_TESTING_cmd_wallet_get_order (const char *label, gos->http_status = http_status; gos->paid = paid; gos->refunded = refunded; + gos->refunds_length = 0; + if (refunded) + { + const char *clabel; + va_list ap; + + va_start (ap, http_status); + while (NULL != (clabel = va_arg (ap, const char *))) + { + GNUNET_array_append (gos->refunds, + gos->refunds_length, + clabel); + } + va_end (ap); + } { struct TALER_TESTING_Command cmd = { .cls = gos, -- cgit v1.2.3