merchant

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

merchant_api_post-private-orders-ORDER_ID-refund.c (7549B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Lesser General Public License as published by the Free Software
      7   Foundation; either version 2.1, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
     12 
     13   You should have received a copy of the GNU Lesser General Public License along with
     14   TALER; see the file COPYING.LGPL.  If not, see
     15   <http://www.gnu.org/licenses/>
     16 */
     17 /**
     18  * @file merchant_api_post-private-orders-ORDER_ID-refund-new.c
     19  * @brief Implementation of the POST /private/orders/$ORDER_ID/refund request
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/platform.h"
     23 #include <curl/curl.h>
     24 #include <jansson.h>
     25 #include <microhttpd.h> /* just for HTTP status codes */
     26 #include <gnunet/gnunet_util_lib.h>
     27 #include <gnunet/gnunet_curl_lib.h>
     28 #include <taler/taler-merchant/post-private-orders-ORDER_ID-refund.h>
     29 #include "merchant_api_curl_defaults.h"
     30 #include "merchant_api_common.h"
     31 #include <taler/taler_json_lib.h>
     32 #include <taler/taler_curl_lib.h>
     33 
     34 
     35 /**
     36  * Handle for a POST /private/orders/$ORDER_ID/refund operation.
     37  */
     38 struct TALER_MERCHANT_PostPrivateOrdersRefundHandle
     39 {
     40   /**
     41    * Base URL of the merchant backend.
     42    */
     43   char *base_url;
     44 
     45   /**
     46    * The full URL for this request.
     47    */
     48   char *url;
     49 
     50   /**
     51    * Handle for the request.
     52    */
     53   struct GNUNET_CURL_Job *job;
     54 
     55   /**
     56    * Function to call with the result.
     57    */
     58   TALER_MERCHANT_PostPrivateOrdersRefundCallback cb;
     59 
     60   /**
     61    * Closure for @a cb.
     62    */
     63   TALER_MERCHANT_POST_PRIVATE_ORDERS_REFUND_RESULT_CLOSURE *cb_cls;
     64 
     65   /**
     66    * Reference to the execution context.
     67    */
     68   struct GNUNET_CURL_Context *ctx;
     69 
     70   /**
     71    * Minor context that holds body and headers.
     72    */
     73   struct TALER_CURL_PostContext post_ctx;
     74 
     75   /**
     76    * Identifier of the order to refund.
     77    */
     78   char *order_id;
     79 
     80   /**
     81    * Amount to refund.
     82    */
     83   struct TALER_Amount refund;
     84 
     85   /**
     86    * Human-readable reason for the refund.
     87    */
     88   char *reason;
     89 };
     90 
     91 
     92 /**
     93  * Function called when we're done processing the
     94  * HTTP POST /private/orders/$ORDER_ID/refund request.
     95  *
     96  * @param cls the `struct TALER_MERCHANT_PostPrivateOrdersRefundHandle`
     97  * @param response_code HTTP response code, 0 on error
     98  * @param response response body, NULL if not in JSON
     99  */
    100 static void
    101 handle_refund_finished (void *cls,
    102                         long response_code,
    103                         const void *response)
    104 {
    105   struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *porh = cls;
    106   const json_t *json = response;
    107   struct TALER_MERCHANT_PostPrivateOrdersRefundResponse rr = {
    108     .hr.http_status = (unsigned int) response_code,
    109     .hr.reply = json
    110   };
    111 
    112   porh->job = NULL;
    113   switch (response_code)
    114   {
    115   case 0:
    116     rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    117     break;
    118   case MHD_HTTP_OK:
    119     {
    120       struct GNUNET_JSON_Specification spec[] = {
    121         GNUNET_JSON_spec_string (
    122           "taler_refund_uri",
    123           &rr.details.ok.taler_refund_uri),
    124         GNUNET_JSON_spec_fixed_auto (
    125           "h_contract",
    126           &rr.details.ok.h_contract),
    127         GNUNET_JSON_spec_end ()
    128       };
    129 
    130       if (GNUNET_OK !=
    131           GNUNET_JSON_parse (json,
    132                              spec,
    133                              NULL, NULL))
    134       {
    135         GNUNET_break_op (0);
    136         rr.hr.http_status = 0;
    137         rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    138         break;
    139       }
    140       break;
    141     }
    142   case MHD_HTTP_UNAUTHORIZED:
    143     rr.hr.ec = TALER_JSON_get_error_code (json);
    144     rr.hr.hint = TALER_JSON_get_error_hint (json);
    145     break;
    146   case MHD_HTTP_FORBIDDEN:
    147     rr.hr.ec = TALER_JSON_get_error_code (json);
    148     rr.hr.hint = TALER_JSON_get_error_hint (json);
    149     break;
    150   case MHD_HTTP_NOT_FOUND:
    151     rr.hr.ec = TALER_JSON_get_error_code (json);
    152     rr.hr.hint = TALER_JSON_get_error_hint (json);
    153     break;
    154   case MHD_HTTP_CONFLICT:
    155     rr.hr.ec = TALER_JSON_get_error_code (json);
    156     rr.hr.hint = TALER_JSON_get_error_hint (json);
    157     break;
    158   case MHD_HTTP_GONE:
    159     rr.hr.ec = TALER_JSON_get_error_code (json);
    160     rr.hr.hint = TALER_JSON_get_error_hint (json);
    161     break;
    162   case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
    163     rr.hr.ec = TALER_JSON_get_error_code (json);
    164     rr.hr.hint = TALER_JSON_get_error_hint (json);
    165     break;
    166   default:
    167     GNUNET_break_op (0);
    168     TALER_MERCHANT_parse_error_details_ (json,
    169                                          response_code,
    170                                          &rr.hr);
    171     break;
    172   }
    173   porh->cb (porh->cb_cls,
    174             &rr);
    175   TALER_MERCHANT_post_private_orders_refund_cancel (porh);
    176 }
    177 
    178 
    179 struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *
    180 TALER_MERCHANT_post_private_orders_refund_create (
    181   struct GNUNET_CURL_Context *ctx,
    182   const char *url,
    183   const char *order_id,
    184   const struct TALER_Amount *refund,
    185   const char *reason)
    186 {
    187   struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *porh;
    188 
    189   porh = GNUNET_new (struct TALER_MERCHANT_PostPrivateOrdersRefundHandle);
    190   porh->ctx = ctx;
    191   porh->base_url = GNUNET_strdup (url);
    192   porh->order_id = GNUNET_strdup (order_id);
    193   porh->refund = *refund;
    194   porh->reason = GNUNET_strdup (reason);
    195   return porh;
    196 }
    197 
    198 
    199 enum TALER_ErrorCode
    200 TALER_MERCHANT_post_private_orders_refund_start (
    201   struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *porh,
    202   TALER_MERCHANT_PostPrivateOrdersRefundCallback cb,
    203   TALER_MERCHANT_POST_PRIVATE_ORDERS_REFUND_RESULT_CLOSURE *cb_cls)
    204 {
    205   json_t *req_obj;
    206   CURL *eh;
    207 
    208   porh->cb = cb;
    209   porh->cb_cls = cb_cls;
    210   {
    211     char *path;
    212 
    213     GNUNET_asprintf (&path,
    214                      "private/orders/%s/refund",
    215                      porh->order_id);
    216     porh->url = TALER_url_join (porh->base_url,
    217                                 path,
    218                                 NULL);
    219     GNUNET_free (path);
    220   }
    221   if (NULL == porh->url)
    222     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    223   req_obj = GNUNET_JSON_PACK (
    224     TALER_JSON_pack_amount ("refund",
    225                             &porh->refund),
    226     GNUNET_JSON_pack_string ("reason",
    227                              porh->reason));
    228   eh = TALER_MERCHANT_curl_easy_get_ (porh->url);
    229   if ( (NULL == eh) ||
    230        (GNUNET_OK !=
    231         TALER_curl_easy_post (&porh->post_ctx,
    232                               eh,
    233                               req_obj)) )
    234   {
    235     GNUNET_break (0);
    236     json_decref (req_obj);
    237     if (NULL != eh)
    238       curl_easy_cleanup (eh);
    239     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    240   }
    241   json_decref (req_obj);
    242   porh->job = GNUNET_CURL_job_add2 (porh->ctx,
    243                                     eh,
    244                                     porh->post_ctx.headers,
    245                                     &handle_refund_finished,
    246                                     porh);
    247   if (NULL == porh->job)
    248     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    249   return TALER_EC_NONE;
    250 }
    251 
    252 
    253 void
    254 TALER_MERCHANT_post_private_orders_refund_cancel (
    255   struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *porh)
    256 {
    257   if (NULL != porh->job)
    258   {
    259     GNUNET_CURL_job_cancel (porh->job);
    260     porh->job = NULL;
    261   }
    262   TALER_curl_easy_post_finished (&porh->post_ctx);
    263   GNUNET_free (porh->order_id);
    264   GNUNET_free (porh->reason);
    265   GNUNET_free (porh->url);
    266   GNUNET_free (porh->base_url);
    267   GNUNET_free (porh);
    268 }
    269 
    270 
    271 /* end of merchant_api_post-private-orders-ORDER_ID-refund-new.c */