merchant

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

testing_api_cmd_wallet_post_orders_refund.c (8384B)


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