gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] branch master updated: testing and lib sources for new


From: gnunet
Subject: [taler-merchant] branch master updated: testing and lib sources for new endpoint
Date: Tue, 18 Aug 2020 03:03:59 +0200

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

jonathan-buchanan pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new d8e64ae  testing and lib sources for new endpoint
d8e64ae is described below

commit d8e64ae258b911d4243a0fd62e46585f54bb445b
Author: Jonathan Buchanan <jonathan.russ.buchanan@gmail.com>
AuthorDate: Mon Aug 17 21:03:45 2020 -0400

    testing and lib sources for new endpoint
---
 src/backend/taler-merchant-httpd_get-orders-ID.c   |  41 ++
 src/include/taler_merchant_service.h               | 144 ++++---
 src/include/taler_merchant_testing_lib.h           |  29 +-
 src/lib/Makefile.am                                |   3 +-
 src/lib/merchant_api_wallet_get_order.c            | 182 +--------
 src/lib/merchant_api_wallet_post_order_refund.c    | 448 +++++++++++++++++++++
 src/testing/Makefile.am                            |   1 +
 src/testing/test_merchant_api.c                    |  16 +-
 src/testing/testing_api_cmd_wallet_get_order.c     |  89 +---
 .../testing_api_cmd_wallet_post_orders_refund.c    | 316 +++++++++++++++
 10 files changed, 950 insertions(+), 319 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.c 
b/src/backend/taler-merchant-httpd_get-orders-ID.c
index 62be05e..9e67f92 100644
--- a/src/backend/taler-merchant-httpd_get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_get-orders-ID.c
@@ -693,6 +693,7 @@ check_resume_god (struct GetOrderData *god)
 }
 
 
+//#if 0
 /**
  * Callbacks of this type are used to serve the result of submitting a
  * refund request to an exchange.
@@ -742,8 +743,10 @@ refund_cb (void *cls,
   }
   check_resume_god (cr->god);
 }
+//#endif
 
 
+//#if 0
 /**
  * Function called with the result of a #TMH_EXCHANGES_find_exchange()
  * operation.
@@ -784,6 +787,7 @@ exchange_found_cb (void *cls,
   cr->exchange_reply = json_incref ((json_t*) hr->reply);
   check_resume_god (cr->god);
 }
+//#endif
 
 
 /**
@@ -1000,6 +1004,22 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
       }
     }
 
+#if 0
+    {
+      const char *await_refund_obtained_s;
+
+      await_refund_obtained_s =
+        MHD_lookup_connection_value (connection,
+                                     MHD_GET_ARGUMENT_KIND,
+                                     "await_refund_obtained");
+
+      god->sc.awaiting_refund_obtained =
+        (NULL != await_refund_obtained_s)
+        ? 0 == strcasecmp (await_refund_obtained_s, "yes")
+        : false;
+    }
+#endif
+
     {
       const char *min_refund;
 
@@ -1308,6 +1328,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
                                        "Failed to lookup refunds for 
contract");
   }
 
+//#if 0
   /* Now launch exchange interactions, unless we already have the
      response in the database! */
   for (struct CoinRefund *cr = god->cr_head;
@@ -1342,6 +1363,26 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
       break;
     }
   }
+//#endif
+#if 0
+  if ( (god->sc.awaiting_refund_obtained) &&
+       (god->refund_available))
+  {
+    /* Client is waiting for pending refunds to be picked up, suspend
+       until timeout */
+    struct GNUNET_TIME_Relative remaining;
+
+    remaining = GNUNET_TIME_absolute_get_remaining (god->sc.long_poll_timeout);
+    if (0 != remaining.rel_value_us)
+    {
+      /* yes, indeed suspend */
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Awaiting pending refunds\n");
+      suspend_god (god);
+      return MHD_YES;
+    }
+  }
+#endif
 
   if ( (god->sc.awaiting_refund) &&
        ( (! god->refunded) ||
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index 46d14ea..2da5e03 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -1455,48 +1455,6 @@ TALER_MERCHANT_orders_get_cancel (
 struct TALER_MERCHANT_OrderWalletGetHandle;
 
 
-/**
- * Detail about a refund lookup result.
- */
-struct TALER_MERCHANT_RefundDetail
-{
-
-  /**
-   * Exchange response details.  Full details are only included
-   * upon failure (HTTP status is not #MHD_HTTP_OK).
-   */
-  struct TALER_EXCHANGE_HttpResponse hr;
-
-  /**
-   * Coin this detail is about.
-   */
-  struct TALER_CoinSpendPublicKeyP coin_pub;
-
-  /**
-   * Refund transaction ID used.
-   */
-  uint64_t rtransaction_id;
-
-  /**
-   * Amount to be refunded for this coin.
-   */
-  struct TALER_Amount refund_amount;
-
-  /**
-   * Public key of the exchange affirming the refund,
-   * only valid if the @e hr http_status is #MHD_HTTP_OK.
-   */
-  struct TALER_ExchangePublicKeyP exchange_pub;
-
-  /**
-   * Signature of the exchange affirming the refund,
-   * only valid if the @e hr http_status is #MHD_HTTP_OK.
-   */
-  struct TALER_ExchangeSignatureP exchange_sig;
-
-};
-
-
 /**
  * Callback to process a GET /orders/$ID request
  *
@@ -1513,9 +1471,6 @@ struct TALER_MERCHANT_RefundDetail
  *                      the payment
  * @param already_paid_order_id equivalent order that this customer
  *                      paid already, or NULL for none
- * @param merchant_pub public key of the merchant
- * @param num_refunds length of the @a refunds array
- * @param refunds details about the refund processing
  */
 typedef void
 (*TALER_MERCHANT_OrderWalletGetCallback) (
@@ -1525,10 +1480,7 @@ typedef void
   enum GNUNET_GenericReturnValue refunded,
   struct TALER_Amount *refund_amount,
   const char *taler_pay_uri,
-  const char *already_paid_order_id,
-  const struct TALER_MerchantPublicKeyP *merchant_pub,
-  unsigned int num_refunds,
-  const struct TALER_MERCHANT_RefundDetail *refunds);
+  const char *already_paid_order_id);
 
 
 /**
@@ -2433,6 +2385,100 @@ TALER_MERCHANT_post_order_refund_cancel (
   struct TALER_MERCHANT_OrderRefundHandle *orh);
 
 
+/**
+ * Handle for a (public) POST /orders/ID/refund operation.
+ */
+struct TALER_MERCHANT_WalletOrderRefundHandle;
+
+
+/**
+ * Detail about a refund lookup result.
+ */
+struct TALER_MERCHANT_RefundDetail
+{
+
+  /**
+   * Exchange response details.  Full details are only included
+   * upon failure (HTTP status is not #MHD_HTTP_OK).
+   */
+  struct TALER_EXCHANGE_HttpResponse hr;
+
+  /**
+   * Coin this detail is about.
+   */
+  struct TALER_CoinSpendPublicKeyP coin_pub;
+
+  /**
+   * Refund transaction ID used.
+   */
+  uint64_t rtransaction_id;
+
+  /**
+   * Amount to be refunded for this coin.
+   */
+  struct TALER_Amount refund_amount;
+
+  /**
+   * Public key of the exchange affirming the refund,
+   * only valid if the @e hr http_status is #MHD_HTTP_OK.
+   */
+  struct TALER_ExchangePublicKeyP exchange_pub;
+
+  /**
+   * Signature of the exchange affirming the refund,
+   * only valid if the @e hr http_status is #MHD_HTTP_OK.
+   */
+  struct TALER_ExchangeSignatureP exchange_sig;
+
+};
+
+
+/**
+ * Callback to process a (public) POST /orders/ID/refund request
+ *
+ * @param cls closure
+ * @param http_status HTTP status code for this request
+ * @param ec taler-specific error code
+ */
+typedef void
+(*TALER_MERCHANT_WalletRefundCallback) (
+  void *cls,
+  const struct TALER_MERCHANT_HttpResponse *hr,
+  const struct TALER_Amount *refund_amount,
+  const struct TALER_MerchantPublicKeyP *merchant_pub,
+  struct TALER_MERCHANT_RefundDetail refunds[],
+  unsigned int refunds_length);
+
+
+/**
+ * Obtain the refunds that have been granted for an order.
+ *
+ * @param ctx the CURL context used to connect to the backend
+ * @param backend_url backend's base URL, including final "/"
+ * @param order_id id of the order whose refund is to be increased
+ * @param h_contract_terms hash of the contract terms of the order
+ * @param cb callback processing the response from /refund
+ * @param cb_cls closure for cb
+ */
+struct TALER_MERCHANT_WalletOrderRefundHandle *
+TALER_MERCHANT_wallet_post_order_refund (
+  struct GNUNET_CURL_Context *ctx,
+  const char *backend_url,
+  const char *order_id,
+  const struct GNUNET_HashCode *h_contract_terms,
+  TALER_MERCHANT_WalletRefundCallback cb,
+  void *cb_cls);
+
+/**
+ * Cancel a (public) POST /refund request.
+ *
+ * @param orh the refund operation to cancel
+ */
+void
+TALER_MERCHANT_wallet_post_order_refund_cancel (
+  struct TALER_MERCHANT_WalletOrderRefundHandle *orh);
+
+
 /* ********************* /transfers *********************** */
 
 /**
diff --git a/src/include/taler_merchant_testing_lib.h 
b/src/include/taler_merchant_testing_lib.h
index a9aa2b4..5618b44 100644
--- a/src/include/taler_merchant_testing_lib.h
+++ b/src/include/taler_merchant_testing_lib.h
@@ -601,10 +601,6 @@ TALER_TESTING_cmd_poll_orders_conclude (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,
@@ -612,8 +608,7 @@ 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);
 
 
 /**
@@ -819,6 +814,28 @@ TALER_TESTING_cmd_merchant_order_refund (const char *label,
                                          unsigned int http_code);
 
 
+/**
+ * Define a "refund order" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the backend serving the
+ *        "refund increase" request.
+ * @param order_ref order id of the contract to refund.
+ * @param http_code expected HTTP response code.
+ * @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.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_wallet_order_refund (const char *label,
+                                       const char *merchant_url,
+                                       const char *order_ref,
+                                       unsigned int http_code,
+                                       ...);
+
+
 /**
  * Define a "DELETE order" CMD.
  *
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index a2218be..8b93870 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -49,7 +49,8 @@ libtalermerchant_la_SOURCES = \
   merchant_api_tip_pickup.c \
   merchant_api_tip_pickup2.c \
   merchant_api_wallet_get_tip.c \
-  merchant_api_wallet_get_order.c
+  merchant_api_wallet_get_order.c \
+  merchant_api_wallet_post_order_refund.c
 
 libtalermerchant_la_LIBADD = \
   -ltalerexchange \
diff --git a/src/lib/merchant_api_wallet_get_order.c 
b/src/lib/merchant_api_wallet_get_order.c
index 7bfdf70..f7ce538 100644
--- a/src/lib/merchant_api_wallet_get_order.c
+++ b/src/lib/merchant_api_wallet_get_order.c
@@ -89,9 +89,6 @@ cb_failure (struct TALER_MERCHANT_OrderWalletGetHandle *owgh,
             GNUNET_SYSERR,
             NULL,
             NULL,
-            NULL,
-            NULL,
-            0,
             NULL);
 }
 
@@ -116,22 +113,20 @@ handle_wallet_get_order_finished (void *cls,
   {
   case MHD_HTTP_OK:
     {
+      /* FIXME: do something with refund_pending */
       struct TALER_Amount refund_amount;
-      json_t *refunds;
       bool refunded;
-      struct TALER_MerchantPublicKeyP merchant_pub;
-      unsigned int refund_len;
       struct GNUNET_JSON_Specification spec[] = {
         GNUNET_JSON_spec_bool ("refunded",
                                &refunded),
-        GNUNET_JSON_spec_fixed_auto ("merchant_pub",
-                                     &merchant_pub),
         TALER_JSON_spec_amount ("refund_amount",
                                 &refund_amount),
-        GNUNET_JSON_spec_json ("refunds",
-                               &refunds),
         GNUNET_JSON_spec_end ()
       };
+      struct TALER_MERCHANT_HttpResponse hr = {
+        .reply = json,
+        .http_status = MHD_HTTP_OK
+      };
 
       if (GNUNET_OK !=
           GNUNET_JSON_parse (json,
@@ -146,158 +141,13 @@ handle_wallet_get_order_finished (void *cls,
         return;
       }
 
-      if (! json_is_array (refunds))
-      {
-        GNUNET_break_op (0);
-        cb_failure (owgh,
-                    TALER_EC_CHECK_PAYMENT_RESPONSE_MALFORMED,
-                    json);
-        GNUNET_JSON_parse_free (spec);
-        TALER_MERCHANT_wallet_order_get_cancel (owgh);
-        return;
-      }
-
-      refund_len = json_array_size (refunds);
-      {
-        struct TALER_MERCHANT_RefundDetail rds[refund_len];
-
-        memset (rds,
-                0,
-                sizeof (rds));
-        for (unsigned int i = 0; i<refund_len; i++)
-        {
-          struct TALER_MERCHANT_RefundDetail *rd = &rds[i];
-          const json_t *jrefund = json_array_get (refunds,
-                                                  i);
-          const char *refund_status_type;
-          uint32_t exchange_status;
-          int ret;
-          struct GNUNET_JSON_Specification espec[] = {
-            GNUNET_JSON_spec_uint32 ("exchange_status",
-                                     &exchange_status),
-            GNUNET_JSON_spec_end ()
-          };
-
-          if (GNUNET_OK !=
-              GNUNET_JSON_parse (jrefund,
-                                 espec,
-                                 NULL, NULL))
-          {
-            GNUNET_break_op (0);
-            cb_failure (owgh,
-                        TALER_EC_CHECK_PAYMENT_RESPONSE_MALFORMED,
-                        json);
-            TALER_MERCHANT_wallet_order_get_cancel (owgh);
-            return;
-          }
-
-          if (MHD_HTTP_OK == exchange_status)
-          {
-            struct GNUNET_JSON_Specification rspec[] = {
-              GNUNET_JSON_spec_string ("type",
-                                       &refund_status_type),
-              GNUNET_JSON_spec_fixed_auto ("exchange_sig",
-                                           &rd->exchange_sig),
-              GNUNET_JSON_spec_fixed_auto ("exchange_pub",
-                                           &rd->exchange_pub),
-              GNUNET_JSON_spec_uint64 ("rtransaction_id",
-                                       &rd->rtransaction_id),
-              GNUNET_JSON_spec_fixed_auto ("coin_pub",
-                                           &rd->coin_pub),
-              TALER_JSON_spec_amount ("refund_amount",
-                                      &rd->refund_amount),
-              GNUNET_JSON_spec_end ()
-            };
-
-            ret = GNUNET_JSON_parse (jrefund,
-                                     rspec,
-                                     NULL, NULL);
-            if (GNUNET_OK == ret)
-            {
-              /* check that type field is correct */
-              if (0 != strcmp ("success", refund_status_type))
-              {
-                GNUNET_break_op (0);
-                ret = GNUNET_SYSERR;
-              }
-            }
-          }
-          else
-          {
-            struct GNUNET_JSON_Specification rspec[] = {
-              GNUNET_JSON_spec_string ("type",
-                                       &refund_status_type),
-              GNUNET_JSON_spec_fixed_auto ("coin_pub",
-                                           &rd->coin_pub),
-              GNUNET_JSON_spec_uint64 ("rtransaction_id",
-                                       &rd->rtransaction_id),
-              TALER_JSON_spec_amount ("refund_amount",
-                                      &rd->refund_amount),
-              GNUNET_JSON_spec_end ()
-            };
-
-            ret = GNUNET_JSON_parse (jrefund,
-                                     rspec,
-                                     NULL, NULL);
-            if (GNUNET_OK == ret)
-            {
-              /* parse optional arguments */
-              json_t *jec;
-
-              jec = json_object_get (jrefund,
-                                     "exchange_code");
-              if (NULL != jec)
-              {
-                if (! json_is_integer (jec))
-                {
-                  GNUNET_break_op (0);
-                  ret = GNUNET_SYSERR;
-                }
-                else
-                {
-                  rd->hr.ec = (enum TALER_ErrorCode) json_integer_value (jec);
-                }
-              }
-              rd->hr.reply = json_object_get (jrefund,
-                                              "exchange_reply");
-              /* check that type field is correct */
-              if (0 != strcmp ("failure", refund_status_type))
-              {
-                GNUNET_break_op (0);
-                ret = GNUNET_SYSERR;
-              }
-            }
-          }
-          if (GNUNET_OK != ret)
-          {
-            GNUNET_break_op (0);
-            cb_failure (owgh,
-                        TALER_EC_CHECK_PAYMENT_RESPONSE_MALFORMED,
-                        json);
-            TALER_MERCHANT_wallet_order_get_cancel (owgh);
-            return;
-          }
-          rd->hr.http_status = exchange_status;
-        }
-
-        {
-          struct TALER_MERCHANT_HttpResponse hr = {
-            .reply = json,
-            .http_status = MHD_HTTP_OK
-          };
-
-          owgh->cb (owgh->cb_cls,
-                    &hr,
-                    GNUNET_YES,
-                    refunded ? GNUNET_YES : GNUNET_NO,
-                    refunded ? &refund_amount : NULL,
-                    NULL, /* paid! */
-                    NULL, /* paid! */
-                    &merchant_pub,
-                    refund_len,
-                    rds);
-        }
-      }
+      owgh->cb (owgh->cb_cls,
+                &hr,
+                GNUNET_YES,
+                refunded ? GNUNET_YES : GNUNET_NO,
+                refunded ? &refund_amount : NULL,
+                NULL, /* paid! */
+                NULL);/* paid! */
       GNUNET_JSON_parse_free (spec);
       break;
     }
@@ -328,10 +178,7 @@ handle_wallet_get_order_finished (void *cls,
                   GNUNET_NO,
                   NULL,
                   taler_pay_uri,
-                  already_paid,
-                  NULL,
-                  0,
-                  NULL);
+                  already_paid);
       }
       break;
     }
@@ -353,9 +200,6 @@ handle_wallet_get_order_finished (void *cls,
                 GNUNET_SYSERR,
                 NULL,
                 NULL,
-                NULL,
-                NULL,
-                0,
                 NULL);
       break;
     }
diff --git a/src/lib/merchant_api_wallet_post_order_refund.c 
b/src/lib/merchant_api_wallet_post_order_refund.c
new file mode 100644
index 0000000..2c63dc1
--- /dev/null
+++ b/src/lib/merchant_api_wallet_post_order_refund.c
@@ -0,0 +1,448 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2020 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Lesser General Public License as published by the Free 
Software
+  Foundation; either version 2.1, 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 Lesser General Public License for more 
details.
+
+  You should have received a copy of the GNU Lesser General Public License 
along with
+  TALER; see the file COPYING.LGPL.  If not, see
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/merchant_api_wallet_post_order_refund.c
+ * @brief Implementation of the (public) POST /orders/ID/refund request
+ * @author Jonathan Buchanan
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_merchant_service.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
+#include <taler/taler_curl_lib.h>
+
+
+/**
+ * Handle for a (public) POST /orders/ID/refund operation.
+ */
+struct TALER_MERCHANT_WalletOrderRefundHandle
+{
+  /**
+   * Complete URL where the backend offers /refund
+   */
+  char *url;
+
+  /**
+   * Minor context that holds body and headers.
+   */
+  struct TALER_CURL_PostContext post_ctx;
+
+  /**
+   * The CURL context to connect to the backend
+   */
+  struct GNUNET_CURL_Context *ctx;
+
+  /**
+   * The callback to pass the backend response to
+   */
+  TALER_MERCHANT_WalletRefundCallback cb;
+
+  /**
+   * Clasure to pass to the callback
+   */
+  void *cb_cls;
+
+  /**
+   * Handle for the request
+   */
+  struct GNUNET_CURL_Job *job;
+};
+
+
+/**
+ * Convenience function to call the callback in @a owgh with an error code of
+ * @a ec and the exchange body being set to @a reply.
+ *
+ * @param owgh handle providing callback
+ * @param ec error code to return to application
+ * @param reply JSON reply we got from the exchange, can be NULL
+ */
+static void
+cb_failure (struct TALER_MERCHANT_WalletOrderRefundHandle *orh,
+            enum TALER_ErrorCode ec,
+            const json_t *reply)
+{
+  struct TALER_MERCHANT_HttpResponse hr = {
+    .ec = TALER_EC_CHECK_PAYMENT_RESPONSE_MALFORMED,
+    .reply = reply
+  };
+
+  orh->cb (orh->cb_cls,
+           &hr,
+           NULL,
+           NULL,
+           NULL,
+           0);
+}
+
+
+/**
+ * Callback to process (public) POST /orders/ID/refund response
+ *
+ * @param cls the `struct TALER_MERCHANT_OrderRefundHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param json response body, NULL if not JSON
+ */
+static void
+handle_refund_finished (void *cls,
+                        long response_code,
+                        const void *response)
+{
+  struct TALER_MERCHANT_WalletOrderRefundHandle *orh = cls;
+  const json_t *json = response;
+  struct TALER_MERCHANT_HttpResponse hr = {
+    .http_status = (unsigned int) response_code,
+    .reply = json
+  };
+
+  orh->job = NULL;
+
+  switch (response_code)
+  {
+  case 0:
+    hr.ec = TALER_EC_INVALID_RESPONSE;
+    orh->cb (orh->cb_cls,
+             &hr,
+             NULL,
+             NULL,
+             NULL,
+             0);
+    break;
+  case MHD_HTTP_OK:
+    {
+      struct TALER_Amount refund_amount;
+      json_t *refunds;
+      struct TALER_MerchantPublicKeyP merchant_pub;
+      unsigned int refund_len;
+      struct GNUNET_JSON_Specification spec[] = {
+        TALER_JSON_spec_amount ("refund_amount",
+                                &refund_amount),
+        GNUNET_JSON_spec_json ("refunds",
+                               &refunds),
+        GNUNET_JSON_spec_fixed_auto ("merchant_pub",
+                                     &merchant_pub),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (json,
+                             spec,
+                             NULL, NULL))
+      {
+        GNUNET_break_op (0);
+        cb_failure (orh,
+                    TALER_EC_CHECK_PAYMENT_RESPONSE_MALFORMED,
+                    json);
+        TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
+        return;
+      }
+
+      if (! json_is_array (refunds))
+      {
+        GNUNET_break_op (0);
+        cb_failure (orh,
+                    TALER_EC_CHECK_PAYMENT_RESPONSE_MALFORMED,
+                    json);
+        GNUNET_JSON_parse_free (spec);
+        TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
+        return;
+      }
+
+      refund_len = json_array_size (refunds);
+      {
+        struct TALER_MERCHANT_RefundDetail rds[refund_len];
+
+        memset (rds,
+                0,
+                sizeof (rds));
+        for (unsigned int i = 0; i<refund_len; i++)
+        {
+          struct TALER_MERCHANT_RefundDetail *rd = &rds[i];
+          const json_t *jrefund = json_array_get (refunds,
+                                                  i);
+          const char *refund_status_type;
+          uint32_t exchange_status;
+          int ret;
+          struct GNUNET_JSON_Specification espec[] = {
+            GNUNET_JSON_spec_uint32 ("exchange_status",
+                                     &exchange_status),
+            GNUNET_JSON_spec_end ()
+          };
+
+          if (GNUNET_OK !=
+              GNUNET_JSON_parse (jrefund,
+                                 espec,
+                                 NULL, NULL))
+          {
+            GNUNET_break_op (0);
+            cb_failure (orh,
+                        TALER_EC_CHECK_PAYMENT_RESPONSE_MALFORMED,
+                        json);
+            TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
+            return;
+          }
+
+          if (MHD_HTTP_OK == exchange_status)
+          {
+            struct GNUNET_JSON_Specification rspec[] = {
+              GNUNET_JSON_spec_string ("type",
+                                       &refund_status_type),
+              GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+                                           &rd->exchange_sig),
+              GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+                                           &rd->exchange_pub),
+              GNUNET_JSON_spec_uint64 ("rtransaction_id",
+                                       &rd->rtransaction_id),
+              GNUNET_JSON_spec_fixed_auto ("coin_pub",
+                                           &rd->coin_pub),
+              TALER_JSON_spec_amount ("refund_amount",
+                                      &rd->refund_amount),
+              GNUNET_JSON_spec_end ()
+            };
+
+            ret = GNUNET_JSON_parse (jrefund,
+                                     rspec,
+                                     NULL, NULL);
+            if (GNUNET_OK == ret)
+            {
+              /* check that type field is correct */
+              if (0 != strcmp ("success", refund_status_type))
+              {
+                GNUNET_break_op (0);
+                ret = GNUNET_SYSERR;
+              }
+            }
+          }
+          else
+          {
+            struct GNUNET_JSON_Specification rspec[] = {
+              GNUNET_JSON_spec_string ("type",
+                                       &refund_status_type),
+              GNUNET_JSON_spec_fixed_auto ("coin_pub",
+                                           &rd->coin_pub),
+              GNUNET_JSON_spec_uint64 ("rtransaction_id",
+                                       &rd->rtransaction_id),
+              TALER_JSON_spec_amount ("refund_amount",
+                                      &rd->refund_amount),
+              GNUNET_JSON_spec_end ()
+            };
+
+            ret = GNUNET_JSON_parse (jrefund,
+                                     rspec,
+                                     NULL, NULL);
+            if (GNUNET_OK == ret)
+            {
+              /* parse optional arguments */
+              json_t *jec;
+
+              jec = json_object_get (jrefund,
+                                     "exchange_code");
+              if (NULL != jec)
+              {
+                if (! json_is_integer (jec))
+                {
+                  GNUNET_break_op (0);
+                  ret = GNUNET_SYSERR;
+                }
+                else
+                {
+                  rd->hr.ec = (enum TALER_ErrorCode) json_integer_value (jec);
+                }
+              }
+              rd->hr.reply = json_object_get (jrefund,
+                                              "exchange_reply");
+              /* check that type field is correct */
+              if (0 != strcmp ("failure", refund_status_type))
+              {
+                GNUNET_break_op (0);
+                ret = GNUNET_SYSERR;
+              }
+            }
+          }
+          if (GNUNET_OK != ret)
+          {
+            GNUNET_break_op (0);
+            cb_failure (orh,
+                        TALER_EC_CHECK_PAYMENT_RESPONSE_MALFORMED,
+                        json);
+            TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
+            return;
+          }
+          rd->hr.http_status = exchange_status;
+        }
+
+        {
+          struct TALER_MERCHANT_HttpResponse hr = {
+            .reply = json,
+            .http_status = MHD_HTTP_OK
+          };
+
+          orh->cb (orh->cb_cls,
+                   &hr,
+                   &refund_amount,
+                   &merchant_pub,
+                   rds,
+                   refund_len);
+        }
+      }
+      GNUNET_JSON_parse_free (spec);
+    }
+    break;
+  case MHD_HTTP_NO_CONTENT:
+    orh->cb (orh->cb_cls,
+             &hr,
+             NULL,
+             NULL,
+             NULL,
+             0);
+    break;
+  case MHD_HTTP_CONFLICT:
+  case MHD_HTTP_NOT_FOUND:
+    hr.ec = TALER_JSON_get_error_code (json);
+    hr.hint = TALER_JSON_get_error_hint (json);
+    orh->cb (orh->cb_cls,
+             &hr,
+             NULL,
+             NULL,
+             NULL,
+             0);
+    break;
+  default:
+    GNUNET_break_op (0); /* unexpected status code */
+    TALER_MERCHANT_parse_error_details_ (json,
+                                         response_code,
+                                         &hr);
+    orh->cb (orh->cb_cls,
+             &hr,
+             NULL,
+             NULL,
+             NULL,
+             0);
+    break;
+  }
+  TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
+}
+
+
+/**
+ * Obtain the refunds that have been granted for an order.
+ *
+ * @param ctx the CURL context used to connect to the backend
+ * @param backend_url backend's base URL, including final "/"
+ * @param order_id id of the order whose refund is to be increased
+ * @param h_contract_terms hash of the contract terms of the order
+ * @param cb callback processing the response from /refund
+ * @param cb_cls closure for cb
+ */
+struct TALER_MERCHANT_WalletOrderRefundHandle *
+TALER_MERCHANT_wallet_post_order_refund (
+  struct GNUNET_CURL_Context *ctx,
+  const char *backend_url,
+  const char *order_id,
+  const struct GNUNET_HashCode *h_contract_terms,
+  TALER_MERCHANT_WalletRefundCallback cb,
+  void *cb_cls)
+{
+  struct TALER_MERCHANT_WalletOrderRefundHandle *orh;
+  json_t *req;
+  CURL *eh;
+
+  orh = GNUNET_new (struct TALER_MERCHANT_WalletOrderRefundHandle);
+  orh->ctx = ctx;
+  orh->cb = cb;
+  orh->cb_cls = cb_cls;
+  {
+    char *path;
+
+    GNUNET_asprintf (&path,
+                     "orders/%s/refund",
+                     order_id);
+    orh->url = TALER_url_join (backend_url,
+                               path,
+                               NULL);
+    GNUNET_free (path);
+  }
+  if (NULL == orh->url)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Could not construct request URL.\n");
+    GNUNET_free (orh);
+    return NULL;
+  }
+  req = json_pack ("{s:o}",
+                   "h_contract",
+                   GNUNET_JSON_from_data_auto (h_contract_terms));
+  GNUNET_assert (NULL != req);
+  eh = curl_easy_init ();
+  GNUNET_assert (NULL != eh);
+  if (GNUNET_OK !=
+      TALER_curl_easy_post (&orh->post_ctx,
+                            eh,
+                            req))
+  {
+    GNUNET_break (0);
+    json_decref (req);
+    GNUNET_free (orh->url);
+    GNUNET_free (orh);
+    return NULL;
+  }
+  json_decref (req);
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_URL,
+                                   orh->url));
+  orh->job = GNUNET_CURL_job_add2 (ctx,
+                                   eh,
+                                   orh->post_ctx.headers,
+                                   &handle_refund_finished,
+                                   orh);
+  if (NULL == orh->job)
+  {
+    GNUNET_free (orh->url);
+    GNUNET_free (orh);
+    return NULL;
+  }
+  return orh;
+}
+
+
+/**
+ * Cancel a (public) POST /refund request.
+ *
+ * @param orh the refund operation to cancel
+ */
+void
+TALER_MERCHANT_wallet_post_order_refund_cancel (
+  struct TALER_MERCHANT_WalletOrderRefundHandle *orh)
+{
+  if (NULL != orh->job)
+  {
+    GNUNET_CURL_job_cancel (orh->job);
+    orh->job = NULL;
+  }
+  TALER_curl_easy_post_finished (&orh->post_ctx);
+  GNUNET_free (orh->url);
+  GNUNET_free (orh);
+}
+
+
+/* end of merchant_api_wallet_post_order_refund.c */
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 769abd9..6fabd90 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -49,6 +49,7 @@ libtalermerchanttesting_la_SOURCES = \
   testing_api_cmd_tip_pickup.c \
   testing_api_cmd_wallet_get_order.c \
   testing_api_cmd_wallet_get_tip.c \
+  testing_api_cmd_wallet_post_orders_refund.c \
   testing_api_helpers.c \
   testing_api_trait_claim_nonce.c \
   testing_api_trait_merchant_sig.c \
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
index 92fb3f4..8e5903e 100644
--- a/src/testing/test_merchant_api.c
+++ b/src/testing/test_merchant_api.c
@@ -681,9 +681,7 @@ run (void *cls,
                                         "create-proposal-1r",
                                         true,
                                         true,
-                                        MHD_HTTP_OK,
-                                        "refund-increase-1r",
-                                        NULL),
+                                        MHD_HTTP_OK),
     TALER_TESTING_cmd_merchant_order_refund ("refund-increase-1r-2",
                                              merchant_url,
                                              "refund test 2",
@@ -695,10 +693,14 @@ run (void *cls,
                                         "create-proposal-1r",
                                         true,
                                         true,
-                                        MHD_HTTP_OK,
-                                        "refund-increase-1r",
-                                        "refund-increase-1r-2",
-                                        NULL),
+                                        MHD_HTTP_OK),
+    TALER_TESTING_cmd_wallet_order_refund ("obtain-refund-1r",
+                                           merchant_url,
+                                           "create-proposal-1r",
+                                           MHD_HTTP_OK,
+                                           "refund-increase-1r",
+                                           "refund-increase-1r-2",
+                                           NULL),
     TALER_TESTING_cmd_merchant_get_order ("get-order-merchant-1r",
                                           merchant_url,
                                           "create-proposal-1r",
diff --git a/src/testing/testing_api_cmd_wallet_get_order.c 
b/src/testing/testing_api_cmd_wallet_get_order.c
index b4a4ce7..aeae42a 100644
--- a/src/testing/testing_api_cmd_wallet_get_order.c
+++ b/src/testing/testing_api_cmd_wallet_get_order.c
@@ -67,16 +67,6 @@ 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;
 };
 
 
@@ -96,9 +86,6 @@ struct WalletGetOrderState
  *                      the payment
  * @param already_paid_order_id equivalent order that this customer
  *                      paid already, or NULL for none
- * @param merchant_pub public key of the merchant
- * @param num_refunds length of the @a refunds array
- * @param refunds details about the refund processing
  */
 static void
 wallet_get_order_cb (
@@ -108,10 +95,7 @@ wallet_get_order_cb (
   enum GNUNET_GenericReturnValue refunded,
   struct TALER_Amount *refund_amount,
   const char *taler_pay_uri,
-  const char *already_paid_order_id,
-  const struct TALER_MerchantPublicKeyP *merchant_pub,
-  unsigned int num_refunds,
-  const struct TALER_MERCHANT_RefundDetail *refunds)
+  const char *already_paid_order_id)
 {
   /* FIXME, deeper checks should be implemented here. */
   struct WalletGetOrderState *gos = cls;
@@ -148,59 +132,6 @@ 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;
-    }
-    {
-      struct TALER_Amount refunded_total;
-      if (num_refunds > 0)
-        GNUNET_assert (GNUNET_OK ==
-                       TALER_amount_get_zero (refund_amount->currency,
-                                              &refunded_total));
-      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));
-        /* The most recent refunds are returned first */
-        GNUNET_assert (0 <= TALER_amount_add (&refunded_total,
-                                              &refunded_total,
-                                              &refunds[num_refunds - 1 - 
i].refund_amount));
-        if ((GNUNET_OK !=
-             TALER_amount_cmp_currency (&expected_amount,
-                                        &refunded_total)) ||
-            (0 != TALER_amount_cmp (&expected_amount,
-                                    &refunded_total)))
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      "Refund amounts do not match\n");
-          TALER_TESTING_interpreter_fail (gos->is);
-          return;
-        }
-      }
-    }
     if (!paid_b)
     {
       /* FIXME: Check all of the members of `pud` */
@@ -361,8 +292,7 @@ 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;
 
@@ -372,21 +302,6 @@ 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,
diff --git a/src/testing/testing_api_cmd_wallet_post_orders_refund.c 
b/src/testing/testing_api_cmd_wallet_post_orders_refund.c
new file mode 100644
index 0000000..0df41ed
--- /dev/null
+++ b/src/testing/testing_api_cmd_wallet_post_orders_refund.c
@@ -0,0 +1,316 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2020 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 lib/testing_api_cmd_wallet_post_orders_refund.c
+ * @brief command to test refunds.
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State for an "obtain refunds" CMD.
+ */
+struct WalletRefundState
+{
+  /**
+   * Operation handle for a (public) POST /orders/$ID/refund request.
+   */
+  struct TALER_MERCHANT_WalletOrderRefundHandle *orh;
+
+  /**
+   * Base URL of the merchant serving the request.
+   */
+  const char *merchant_url;
+
+  /**
+   * Interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Expected HTTP response code.
+   */
+  unsigned int http_code;
+
+  /**
+   * Label of the command that created the order we want to obtain refunds for.
+   */
+  const char *proposal_reference;
+
+  /**
+   * A list of refunds associated with this order.
+   */
+  const char **refunds;
+
+  /**
+   * The length of @e refunds.
+   */
+  unsigned int refunds_length;
+};
+
+
+/**
+ * Process POST /refund (increase) response; just checking
+ * if the HTTP response code is the one expected.
+ *
+ * @param cls closure
+ * @param hr HTTP response
+ */
+static void
+refund_cb (
+  void *cls,
+  const struct TALER_MERCHANT_HttpResponse *hr,
+  const struct TALER_Amount *refund_amount,
+  const struct TALER_MerchantPublicKeyP *merchant_pub,
+  struct TALER_MERCHANT_RefundDetail refunds[],
+  unsigned int refunds_length)
+{
+  struct WalletRefundState *wrs = cls;
+
+  wrs->orh = NULL;
+  if (wrs->http_code != hr->http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Expected status %u, got %u(%d) for refund increase\n",
+                wrs->http_code,
+                hr->http_status,
+                (int) hr->ec);
+    TALER_TESTING_FAIL (wrs->is);
+  }
+  switch (hr->http_status)
+  {
+  case MHD_HTTP_OK:
+    {
+      struct TALER_Amount refunded_total;
+      if (refunds_length > 0)
+        GNUNET_assert (GNUNET_OK ==
+                       TALER_amount_get_zero 
(refunds[0].refund_amount.currency,
+                                              &refunded_total));
+      for (unsigned int i = 0; i < refunds_length; ++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 (
+          wrs->is,
+          wrs->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 (wrs->is);
+          return;
+        }
+        GNUNET_assert (GNUNET_OK ==
+                       TALER_string_to_amount (expected_amount_str,
+                                               &expected_amount));
+        /* The most recent refunds are returned first */
+        GNUNET_assert (0 <= TALER_amount_add (&refunded_total,
+                                              &refunded_total,
+                                              &refunds[refunds_length - 1 - 
i].refund_amount));
+        if ((GNUNET_OK !=
+             TALER_amount_cmp_currency (&expected_amount,
+                                        &refunded_total)) ||
+            (0 != TALER_amount_cmp (&expected_amount,
+                                    &refunded_total)))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Refund amounts do not match\n");
+          TALER_TESTING_interpreter_fail (wrs->is);
+          return;
+        }
+      }
+    }
+    break;
+  default:
+
+    break;
+  }
+  TALER_TESTING_interpreter_next (wrs->is);
+}
+
+
+/**
+ * Run the "refund increase" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is the interpreter state.
+ */
+static void
+obtain_refunds_run (void *cls,
+                    const struct TALER_TESTING_Command *cmd,
+                    struct TALER_TESTING_Interpreter *is)
+{
+  struct WalletRefundState *wrs = cls;
+  const struct TALER_TESTING_Command *proposal_cmd =
+    TALER_TESTING_interpreter_lookup_command (is,
+                                              wrs->proposal_reference);
+  const struct GNUNET_HashCode *h_contract_terms;
+  const char *order_id;
+
+  if (NULL == proposal_cmd)
+    TALER_TESTING_FAIL (is);
+  if (GNUNET_OK !=
+      TALER_TESTING_get_trait_h_contract_terms (proposal_cmd,
+                                                0,
+                                                &h_contract_terms))
+    TALER_TESTING_FAIL (is);
+
+  {
+    const json_t *contract_terms;
+    const char *error_name;
+    unsigned int error_line;
+
+    if (GNUNET_OK !=
+        TALER_TESTING_get_trait_contract_terms (proposal_cmd,
+                                                0,
+                                                &contract_terms))
+      TALER_TESTING_FAIL (is);
+    {
+      /* Get information that needs to be put verbatim in the
+       * deposit permission */
+      struct GNUNET_JSON_Specification spec[] = {
+        GNUNET_JSON_spec_string ("order_id",
+                                 &order_id),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (contract_terms,
+                             spec,
+                             &error_name,
+                             &error_line))
+      {
+        char *js;
+
+        js = json_dumps (contract_terms,
+                         JSON_INDENT (1));
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Parser failed on %s:%u for input `%s'\n",
+                    error_name,
+                    error_line,
+                    js);
+        free (js);
+        TALER_TESTING_FAIL (is);
+      }
+    }
+  }
+
+  wrs->is = is;
+  wrs->orh = TALER_MERCHANT_wallet_post_order_refund (
+    is->ctx,
+    wrs->merchant_url,
+    order_id,
+    h_contract_terms,
+    &refund_cb,
+    wrs);
+  if (NULL == wrs->orh)
+    TALER_TESTING_FAIL (is);
+}
+
+
+/**
+ * Free the state of a "refund increase" CMD, and
+ * possibly cancel a pending "refund increase" operation.
+ *
+ * @param cls closure
+ * @param cmd command currently being freed.
+ */
+static void
+obtain_refunds_cleanup (void *cls,
+                        const struct TALER_TESTING_Command *cmd)
+{
+  struct WalletRefundState *wrs = cls;
+
+  if (NULL != wrs->orh)
+  {
+    TALER_LOG_WARNING ("Refund operation did not complete\n");
+    TALER_MERCHANT_wallet_post_order_refund_cancel (wrs->orh);
+  }
+  GNUNET_array_grow (wrs->refunds,
+                     wrs->refunds_length,
+                     0);
+  GNUNET_free (wrs);
+}
+
+
+/**
+ * Define a "refund order" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the backend serving the
+ *        "refund increase" request.
+ * @param order_ref order id of the contract to refund.
+ * @param http_code expected HTTP response code.
+ * @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.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_wallet_order_refund (const char *label,
+                                       const char *merchant_url,
+                                       const char *order_ref,
+                                       unsigned int http_code,
+                                       ...)
+{
+  struct WalletRefundState *wrs;
+
+  wrs = GNUNET_new (struct WalletRefundState);
+  wrs->merchant_url = merchant_url;
+  wrs->proposal_reference = order_ref;
+  wrs->http_code = http_code;
+  wrs->refunds_length = 0;
+  {
+    const char *clabel;
+    va_list ap;
+
+    va_start (ap, http_code);
+    while (NULL != (clabel = va_arg (ap, const char *)))
+    {
+      GNUNET_array_append (wrs->refunds,
+                           wrs->refunds_length,
+                           clabel);
+    }
+    va_end (ap);
+  }
+  {
+    struct TALER_TESTING_Command cmd = {
+      .cls = wrs,
+      .label = label,
+      .run = &obtain_refunds_run,
+      .cleanup = &obtain_refunds_cleanup
+    };
+
+    return cmd;
+  }
+}

-- 
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]