merchant

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

testing_api_cmd_wallet_post_orders_refund.c (8473B)


      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 src/testing/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 struct WalletRefundState;
     27 #define TALER_MERCHANT_POST_ORDERS_REFUND_RESULT_CLOSURE struct WalletRefundState
     28 #include <taler/taler_exchange_service.h>
     29 #include <taler/taler_testing_lib.h>
     30 #include "taler/taler_merchant_service.h"
     31 #include "taler/taler_merchant_testing_lib.h"
     32 #include <taler/merchant/post-orders-ORDER_ID-refund.h>
     33 
     34 
     35 /**
     36  * State for an "obtain refunds" CMD.
     37  */
     38 struct WalletRefundState
     39 {
     40   /**
     41    * Operation handle for a (public) POST /orders/$ID/refund request.
     42    */
     43   struct TALER_MERCHANT_PostOrdersRefundHandle *orh;
     44 
     45   /**
     46    * Base URL of the merchant serving the request.
     47    */
     48   const char *merchant_url;
     49 
     50   /**
     51    * Interpreter state.
     52    */
     53   struct TALER_TESTING_Interpreter *is;
     54 
     55   /**
     56    * Expected HTTP response code.
     57    */
     58   unsigned int http_code;
     59 
     60   /**
     61    * Label of the command that created the order we want to obtain refunds for.
     62    */
     63   const char *proposal_reference;
     64 
     65   /**
     66    * A list of refunds associated with this order.
     67    */
     68   const char **refunds;
     69 
     70   /**
     71    * The length of @e refunds.
     72    */
     73   unsigned int refunds_length;
     74 };
     75 
     76 
     77 /**
     78  * Process POST /refund (increase) response; just checking
     79  * if the HTTP response code is the one expected.
     80  *
     81  * @param cls closure
     82  * @param wrr response
     83  */
     84 static void
     85 refund_cb (
     86   struct WalletRefundState *wrs,
     87   const struct TALER_MERCHANT_PostOrdersRefundResponse *wrr)
     88 {
     89 
     90   wrs->orh = NULL;
     91   if (wrs->http_code != wrr->hr.http_status)
     92   {
     93     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     94                 "Expected status %u, got %u(%d) for refund increase\n",
     95                 wrs->http_code,
     96                 wrr->hr.http_status,
     97                 (int) wrr->hr.ec);
     98     TALER_TESTING_FAIL (wrs->is);
     99   }
    100   switch (wrr->hr.http_status)
    101   {
    102   case MHD_HTTP_OK:
    103     {
    104       struct TALER_Amount refunded_total;
    105       if (wrr->details.ok.num_refunds > 0)
    106         GNUNET_assert (GNUNET_OK ==
    107                        TALER_amount_set_zero (
    108                          wrr->details.ok.refunds[0].refund_amount.currency,
    109                          &refunded_total));
    110       for (unsigned int i = 0; i < wrr->details.ok.num_refunds; ++i)
    111       {
    112         const struct TALER_MERCHANT_PostOrdersRefundDetail *refund
    113           = &wrr->details.ok.refunds[wrr->details.ok.num_refunds - 1 - i];
    114         const struct TALER_TESTING_Command *refund_cmd;
    115         const struct TALER_Amount *expected_amount;
    116 
    117         refund_cmd = TALER_TESTING_interpreter_lookup_command (
    118           wrs->is,
    119           wrs->refunds[i]);
    120 
    121         if (GNUNET_OK !=
    122             TALER_TESTING_get_trait_amount (refund_cmd,
    123                                             &expected_amount))
    124         {
    125           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    126                       "Could not fetch refund amount\n");
    127           TALER_TESTING_interpreter_fail (wrs->is);
    128           return;
    129         }
    130         /* The most recent refunds are returned first */
    131         GNUNET_assert (0 <= TALER_amount_add (&refunded_total,
    132                                               &refunded_total,
    133                                               &refund->refund_amount));
    134         if ( (GNUNET_OK !=
    135               TALER_amount_cmp_currency (expected_amount,
    136                                          &refunded_total)) ||
    137              (0 != TALER_amount_cmp (expected_amount,
    138                                      &refunded_total)) )
    139         {
    140           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    141                       "Refund amounts do not match\n");
    142           TALER_TESTING_interpreter_fail (wrs->is);
    143           return;
    144         }
    145       }
    146     }
    147     break;
    148   default:
    149     break;
    150   }
    151   TALER_TESTING_interpreter_next (wrs->is);
    152 }
    153 
    154 
    155 /**
    156  * Run the "refund increase" CMD.
    157  *
    158  * @param cls closure.
    159  * @param cmd command currently being run.
    160  * @param is the interpreter state.
    161  */
    162 static void
    163 obtain_refunds_run (void *cls,
    164                     const struct TALER_TESTING_Command *cmd,
    165                     struct TALER_TESTING_Interpreter *is)
    166 {
    167   struct WalletRefundState *wrs = cls;
    168   const struct TALER_TESTING_Command *proposal_cmd =
    169     TALER_TESTING_interpreter_lookup_command (is,
    170                                               wrs->proposal_reference);
    171   const struct TALER_PrivateContractHashP *h_contract_terms;
    172   const char *order_id;
    173 
    174   if (NULL == proposal_cmd)
    175     TALER_TESTING_FAIL (is);
    176   if (GNUNET_OK !=
    177       TALER_TESTING_get_trait_h_contract_terms (proposal_cmd,
    178                                                 &h_contract_terms))
    179     TALER_TESTING_FAIL (is);
    180 
    181   {
    182     const json_t *contract_terms;
    183     const char *error_name;
    184     unsigned int error_line;
    185 
    186     if (GNUNET_OK !=
    187         TALER_TESTING_get_trait_contract_terms (proposal_cmd,
    188                                                 &contract_terms))
    189       TALER_TESTING_FAIL (is);
    190     {
    191       /* Get information that needs to be put verbatim in the
    192        * deposit permission */
    193       struct GNUNET_JSON_Specification spec[] = {
    194         GNUNET_JSON_spec_string ("order_id",
    195                                  &order_id),
    196         GNUNET_JSON_spec_end ()
    197       };
    198 
    199       if (GNUNET_OK !=
    200           GNUNET_JSON_parse (contract_terms,
    201                              spec,
    202                              &error_name,
    203                              &error_line))
    204       {
    205         char *js;
    206 
    207         js = json_dumps (contract_terms,
    208                          JSON_INDENT (1));
    209         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    210                     "Parser failed on %s:%u for input `%s'\n",
    211                     error_name,
    212                     error_line,
    213                     js);
    214         free (js);
    215         TALER_TESTING_FAIL (is);
    216       }
    217     }
    218   }
    219 
    220   wrs->is = is;
    221   wrs->orh = TALER_MERCHANT_post_orders_refund_create (
    222     TALER_TESTING_interpreter_get_context (is),
    223     wrs->merchant_url,
    224     order_id,
    225     h_contract_terms);
    226   {
    227     enum TALER_ErrorCode ec;
    228 
    229     ec = TALER_MERCHANT_post_orders_refund_start (
    230       wrs->orh,
    231       &refund_cb,
    232       wrs);
    233     GNUNET_assert (TALER_EC_NONE == ec);
    234   }
    235 }
    236 
    237 
    238 /**
    239  * Free the state of a "refund increase" CMD, and
    240  * possibly cancel a pending "refund increase" operation.
    241  *
    242  * @param cls closure
    243  * @param cmd command currently being freed.
    244  */
    245 static void
    246 obtain_refunds_cleanup (void *cls,
    247                         const struct TALER_TESTING_Command *cmd)
    248 {
    249   struct WalletRefundState *wrs = cls;
    250 
    251   if (NULL != wrs->orh)
    252   {
    253     TALER_LOG_WARNING ("Refund operation did not complete\n");
    254     TALER_MERCHANT_post_orders_refund_cancel (wrs->orh);
    255   }
    256   GNUNET_array_grow (wrs->refunds,
    257                      wrs->refunds_length,
    258                      0);
    259   GNUNET_free (wrs);
    260 }
    261 
    262 
    263 struct TALER_TESTING_Command
    264 TALER_TESTING_cmd_wallet_order_refund (const char *label,
    265                                        const char *merchant_url,
    266                                        const char *order_ref,
    267                                        unsigned int http_code,
    268                                        ...)
    269 {
    270   struct WalletRefundState *wrs;
    271 
    272   wrs = GNUNET_new (struct WalletRefundState);
    273   wrs->merchant_url = merchant_url;
    274   wrs->proposal_reference = order_ref;
    275   wrs->http_code = http_code;
    276   wrs->refunds_length = 0;
    277   {
    278     const char *clabel;
    279     va_list ap;
    280 
    281     va_start (ap, http_code);
    282     while (NULL != (clabel = va_arg (ap, const char *)))
    283     {
    284       GNUNET_array_append (wrs->refunds,
    285                            wrs->refunds_length,
    286                            clabel);
    287     }
    288     va_end (ap);
    289   }
    290   {
    291     struct TALER_TESTING_Command cmd = {
    292       .cls = wrs,
    293       .label = label,
    294       .run = &obtain_refunds_run,
    295       .cleanup = &obtain_refunds_cleanup
    296     };
    297 
    298     return cmd;
    299   }
    300 }