merchant

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

testing_api_cmd_wallet_post_orders_refund.c (8207B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2020-2023 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU General Public License as
      7   published by the Free Software Foundation; either version 3, or
      8   (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not, see
     17   <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file testing_api_cmd_wallet_post_orders_refund.c
     21  * @brief command to test refunds.
     22  * @author Marcello Stanisci
     23  * @author Christian Grothoff
     24  */
     25 #include "platform.h"
     26 #include <taler/taler_exchange_service.h>
     27 #include <taler/taler_testing_lib.h>
     28 #include "taler_merchant_service.h"
     29 #include "taler_merchant_testing_lib.h"
     30 
     31 
     32 /**
     33  * State for an "obtain refunds" CMD.
     34  */
     35 struct WalletRefundState
     36 {
     37   /**
     38    * Operation handle for a (public) POST /orders/$ID/refund request.
     39    */
     40   struct TALER_MERCHANT_WalletOrderRefundHandle *orh;
     41 
     42   /**
     43    * Base URL of the merchant serving the request.
     44    */
     45   const char *merchant_url;
     46 
     47   /**
     48    * Interpreter state.
     49    */
     50   struct TALER_TESTING_Interpreter *is;
     51 
     52   /**
     53    * Expected HTTP response code.
     54    */
     55   unsigned int http_code;
     56 
     57   /**
     58    * Label of the command that created the order we want to obtain refunds for.
     59    */
     60   const char *proposal_reference;
     61 
     62   /**
     63    * A list of refunds associated with this order.
     64    */
     65   const char **refunds;
     66 
     67   /**
     68    * The length of @e refunds.
     69    */
     70   unsigned int refunds_length;
     71 };
     72 
     73 
     74 /**
     75  * Process POST /refund (increase) response; just checking
     76  * if the HTTP response code is the one expected.
     77  *
     78  * @param cls closure
     79  * @param wrr response
     80  */
     81 static void
     82 refund_cb (
     83   void *cls,
     84   const struct TALER_MERCHANT_WalletRefundResponse *wrr)
     85 {
     86   struct WalletRefundState *wrs = cls;
     87 
     88   wrs->orh = NULL;
     89   if (wrs->http_code != wrr->hr.http_status)
     90   {
     91     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     92                 "Expected status %u, got %u(%d) for refund increase\n",
     93                 wrs->http_code,
     94                 wrr->hr.http_status,
     95                 (int) wrr->hr.ec);
     96     TALER_TESTING_FAIL (wrs->is);
     97   }
     98   switch (wrr->hr.http_status)
     99   {
    100   case MHD_HTTP_OK:
    101     {
    102       struct TALER_Amount refunded_total;
    103       if (wrr->details.ok.refunds_length > 0)
    104         GNUNET_assert (GNUNET_OK ==
    105                        TALER_amount_set_zero (
    106                          wrr->details.ok.refunds[0].refund_amount.currency,
    107                          &refunded_total));
    108       for (unsigned int i = 0; i < wrr->details.ok.refunds_length; ++i)
    109       {
    110         const struct TALER_MERCHANT_RefundDetail *refund
    111           = &wrr->details.ok.refunds[wrr->details.ok.refunds_length - 1 - i];
    112         const struct TALER_TESTING_Command *refund_cmd;
    113         const struct TALER_Amount *expected_amount;
    114 
    115         refund_cmd = TALER_TESTING_interpreter_lookup_command (
    116           wrs->is,
    117           wrs->refunds[i]);
    118 
    119         if (GNUNET_OK !=
    120             TALER_TESTING_get_trait_amount (refund_cmd,
    121                                             &expected_amount))
    122         {
    123           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    124                       "Could not fetch refund amount\n");
    125           TALER_TESTING_interpreter_fail (wrs->is);
    126           return;
    127         }
    128         /* The most recent refunds are returned first */
    129         GNUNET_assert (0 <= TALER_amount_add (&refunded_total,
    130                                               &refunded_total,
    131                                               &refund->refund_amount));
    132         if ( (GNUNET_OK !=
    133               TALER_amount_cmp_currency (expected_amount,
    134                                          &refunded_total)) ||
    135              (0 != TALER_amount_cmp (expected_amount,
    136                                      &refunded_total)) )
    137         {
    138           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    139                       "Refund amounts do not match\n");
    140           TALER_TESTING_interpreter_fail (wrs->is);
    141           return;
    142         }
    143       }
    144     }
    145     break;
    146   default:
    147     break;
    148   }
    149   TALER_TESTING_interpreter_next (wrs->is);
    150 }
    151 
    152 
    153 /**
    154  * Run the "refund increase" CMD.
    155  *
    156  * @param cls closure.
    157  * @param cmd command currently being run.
    158  * @param is the interpreter state.
    159  */
    160 static void
    161 obtain_refunds_run (void *cls,
    162                     const struct TALER_TESTING_Command *cmd,
    163                     struct TALER_TESTING_Interpreter *is)
    164 {
    165   struct WalletRefundState *wrs = cls;
    166   const struct TALER_TESTING_Command *proposal_cmd =
    167     TALER_TESTING_interpreter_lookup_command (is,
    168                                               wrs->proposal_reference);
    169   const struct TALER_PrivateContractHashP *h_contract_terms;
    170   const char *order_id;
    171 
    172   if (NULL == proposal_cmd)
    173     TALER_TESTING_FAIL (is);
    174   if (GNUNET_OK !=
    175       TALER_TESTING_get_trait_h_contract_terms (proposal_cmd,
    176                                                 &h_contract_terms))
    177     TALER_TESTING_FAIL (is);
    178 
    179   {
    180     const json_t *contract_terms;
    181     const char *error_name;
    182     unsigned int error_line;
    183 
    184     if (GNUNET_OK !=
    185         TALER_TESTING_get_trait_contract_terms (proposal_cmd,
    186                                                 &contract_terms))
    187       TALER_TESTING_FAIL (is);
    188     {
    189       /* Get information that needs to be put verbatim in the
    190        * deposit permission */
    191       struct GNUNET_JSON_Specification spec[] = {
    192         GNUNET_JSON_spec_string ("order_id",
    193                                  &order_id),
    194         GNUNET_JSON_spec_end ()
    195       };
    196 
    197       if (GNUNET_OK !=
    198           GNUNET_JSON_parse (contract_terms,
    199                              spec,
    200                              &error_name,
    201                              &error_line))
    202       {
    203         char *js;
    204 
    205         js = json_dumps (contract_terms,
    206                          JSON_INDENT (1));
    207         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    208                     "Parser failed on %s:%u for input `%s'\n",
    209                     error_name,
    210                     error_line,
    211                     js);
    212         free (js);
    213         TALER_TESTING_FAIL (is);
    214       }
    215     }
    216   }
    217 
    218   wrs->is = is;
    219   wrs->orh = TALER_MERCHANT_wallet_post_order_refund (
    220     TALER_TESTING_interpreter_get_context (is),
    221     wrs->merchant_url,
    222     order_id,
    223     h_contract_terms,
    224     &refund_cb,
    225     wrs);
    226   if (NULL == wrs->orh)
    227     TALER_TESTING_FAIL (is);
    228 }
    229 
    230 
    231 /**
    232  * Free the state of a "refund increase" CMD, and
    233  * possibly cancel a pending "refund increase" operation.
    234  *
    235  * @param cls closure
    236  * @param cmd command currently being freed.
    237  */
    238 static void
    239 obtain_refunds_cleanup (void *cls,
    240                         const struct TALER_TESTING_Command *cmd)
    241 {
    242   struct WalletRefundState *wrs = cls;
    243 
    244   if (NULL != wrs->orh)
    245   {
    246     TALER_LOG_WARNING ("Refund operation did not complete\n");
    247     TALER_MERCHANT_wallet_post_order_refund_cancel (wrs->orh);
    248   }
    249   GNUNET_array_grow (wrs->refunds,
    250                      wrs->refunds_length,
    251                      0);
    252   GNUNET_free (wrs);
    253 }
    254 
    255 
    256 struct TALER_TESTING_Command
    257 TALER_TESTING_cmd_wallet_order_refund (const char *label,
    258                                        const char *merchant_url,
    259                                        const char *order_ref,
    260                                        unsigned int http_code,
    261                                        ...)
    262 {
    263   struct WalletRefundState *wrs;
    264 
    265   wrs = GNUNET_new (struct WalletRefundState);
    266   wrs->merchant_url = merchant_url;
    267   wrs->proposal_reference = order_ref;
    268   wrs->http_code = http_code;
    269   wrs->refunds_length = 0;
    270   {
    271     const char *clabel;
    272     va_list ap;
    273 
    274     va_start (ap, http_code);
    275     while (NULL != (clabel = va_arg (ap, const char *)))
    276     {
    277       GNUNET_array_append (wrs->refunds,
    278                            wrs->refunds_length,
    279                            clabel);
    280     }
    281     va_end (ap);
    282   }
    283   {
    284     struct TALER_TESTING_Command cmd = {
    285       .cls = wrs,
    286       .label = label,
    287       .run = &obtain_refunds_run,
    288       .cleanup = &obtain_refunds_cleanup
    289     };
    290 
    291     return cmd;
    292   }
    293 }