merchant

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

merchant_api_wallet_get_order.c (8914B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2018, 2020, 2022 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_wallet_get_order.c
     19  * @brief Implementation of the GET /orders/$ID request
     20  * @author Christian Grothoff
     21  * @author Marcello Stanisci
     22  * @author Florian Dold
     23  */
     24 #include "platform.h"
     25 #include <curl/curl.h>
     26 #include <jansson.h>
     27 #include <microhttpd.h> /* just for HTTP status codes */
     28 #include <gnunet/gnunet_util_lib.h>
     29 #include <gnunet/gnunet_curl_lib.h>
     30 #include "taler_merchant_service.h"
     31 #include "merchant_api_curl_defaults.h"
     32 #include "merchant_api_common.h"
     33 #include <taler/taler_json_lib.h>
     34 #include <taler/taler_signatures.h>
     35 
     36 
     37 /**
     38  * @brief A GET /orders/$ID handle
     39  */
     40 struct TALER_MERCHANT_OrderWalletGetHandle
     41 {
     42 
     43   /**
     44    * The url for this request.
     45    */
     46   char *url;
     47 
     48   /**
     49    * Handle for the request.
     50    */
     51   struct GNUNET_CURL_Job *job;
     52 
     53   /**
     54    * Function to call with the result.
     55    */
     56   TALER_MERCHANT_OrderWalletGetCallback cb;
     57 
     58   /**
     59    * Closure for @a cb.
     60    */
     61   void *cb_cls;
     62 
     63   /**
     64    * Reference to the execution context.
     65    */
     66   struct GNUNET_CURL_Context *ctx;
     67 };
     68 
     69 
     70 /**
     71  * Convenience function to call the callback in @a owgh with an error code of
     72  * @a ec and the exchange body being set to @a reply.
     73  *
     74  * @param owgh handle providing callback
     75  * @param ec error code to return to application
     76  * @param reply JSON reply we got from the exchange, can be NULL
     77  */
     78 static void
     79 cb_failure (struct TALER_MERCHANT_OrderWalletGetHandle *owgh,
     80             enum TALER_ErrorCode ec,
     81             const json_t *reply)
     82 {
     83   struct TALER_MERCHANT_OrderWalletGetResponse owgr = {
     84     .hr.ec = ec,
     85     .hr.reply = reply
     86   };
     87 
     88   owgh->cb (owgh->cb_cls,
     89             &owgr);
     90 }
     91 
     92 
     93 /**
     94  * Function called when we're done processing the GET /check-payment request.
     95  *
     96  * @param cls the `struct TALER_MERCHANT_OrderWalletGetHandle`
     97  * @param response_code HTTP response code, 0 on error
     98  * @param response response body, should be NULL
     99  */
    100 static void
    101 handle_wallet_get_order_finished (void *cls,
    102                                   long response_code,
    103                                   const void *response)
    104 {
    105   struct TALER_MERCHANT_OrderWalletGetHandle *owgh = cls;
    106   const json_t *json = response;
    107 
    108   owgh->job = NULL;
    109   switch (response_code)
    110   {
    111   case MHD_HTTP_OK:
    112     {
    113       struct TALER_MERCHANT_OrderWalletGetResponse owgr = {
    114         .hr.reply = json,
    115         .hr.http_status = MHD_HTTP_OK
    116       };
    117       struct GNUNET_JSON_Specification spec[] = {
    118         GNUNET_JSON_spec_bool ("refunded",
    119                                &owgr.details.ok.refunded),
    120         GNUNET_JSON_spec_bool ("refund_pending",
    121                                &owgr.details.ok.refund_pending),
    122         TALER_JSON_spec_amount_any ("refund_amount",
    123                                     &owgr.details.ok.refund_amount),
    124         GNUNET_JSON_spec_end ()
    125       };
    126 
    127       if (GNUNET_OK !=
    128           GNUNET_JSON_parse (json,
    129                              spec,
    130                              NULL, NULL))
    131       {
    132         GNUNET_break_op (0);
    133         cb_failure (owgh,
    134                     TALER_EC_GENERIC_REPLY_MALFORMED,
    135                     json);
    136         TALER_MERCHANT_wallet_order_get_cancel (owgh);
    137         return;
    138       }
    139       owgh->cb (owgh->cb_cls,
    140                 &owgr);
    141       GNUNET_JSON_parse_free (spec);
    142       break;
    143     }
    144   case MHD_HTTP_PAYMENT_REQUIRED:
    145     {
    146       struct TALER_MERCHANT_OrderWalletGetResponse owgr = {
    147         .hr.reply = json,
    148         .hr.http_status = MHD_HTTP_PAYMENT_REQUIRED
    149       };
    150 
    151       /* Status is: unpaid */
    152       owgr.details.payment_required.taler_pay_uri
    153         = json_string_value (json_object_get (json,
    154                                               "taler_pay_uri"));
    155       owgr.details.payment_required.already_paid_order_id
    156         = json_string_value (json_object_get (json,
    157                                               "already_paid_order_id"));
    158       if (NULL == owgr.details.payment_required.taler_pay_uri)
    159       {
    160         GNUNET_break_op (0);
    161         cb_failure (owgh,
    162                     TALER_EC_GENERIC_REPLY_MALFORMED,
    163                     json);
    164         break;
    165       }
    166       owgh->cb (owgh->cb_cls,
    167                 &owgr);
    168       break;
    169     }
    170   default:
    171     {
    172       struct TALER_MERCHANT_OrderWalletGetResponse owgr = {
    173         .hr.reply = json,
    174         .hr.http_status = response_code
    175       };
    176 
    177       TALER_MERCHANT_parse_error_details_ (response,
    178                                            response_code,
    179                                            &owgr.hr);
    180       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    181                   "Checking order status failed with HTTP status code %u/%d\n",
    182                   (unsigned int) response_code,
    183                   (int) owgr.hr.ec);
    184       GNUNET_break_op (0);
    185       owgh->cb (owgh->cb_cls,
    186                 &owgr);
    187       break;
    188     }
    189   }
    190   TALER_MERCHANT_wallet_order_get_cancel (owgh);
    191 }
    192 
    193 
    194 struct TALER_MERCHANT_OrderWalletGetHandle *
    195 TALER_MERCHANT_wallet_order_get (
    196   struct GNUNET_CURL_Context *ctx,
    197   const char *backend_url,
    198   const char *order_id,
    199   const struct TALER_PrivateContractHashP *h_contract,
    200   struct GNUNET_TIME_Relative timeout,
    201   const char *session_id,
    202   const struct TALER_Amount *min_refund,
    203   bool await_refund_obtained,
    204   TALER_MERCHANT_OrderWalletGetCallback cb,
    205   void *cb_cls)
    206 {
    207   struct TALER_MERCHANT_OrderWalletGetHandle *owgh;
    208   unsigned int tms;
    209 
    210   GNUNET_assert (NULL != backend_url);
    211   GNUNET_assert (NULL != order_id);
    212   owgh = GNUNET_new (struct TALER_MERCHANT_OrderWalletGetHandle);
    213   owgh->ctx = ctx;
    214   owgh->cb = cb;
    215   owgh->cb_cls = cb_cls;
    216   tms = (unsigned int) (timeout.rel_value_us
    217                         / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
    218   {
    219     char timeout_ms[32];
    220     struct GNUNET_CRYPTO_HashAsciiEncoded h_contract_s;
    221     char *path;
    222 
    223     GNUNET_CRYPTO_hash_to_enc (&h_contract->hash,
    224                                &h_contract_s);
    225     GNUNET_snprintf (timeout_ms,
    226                      sizeof (timeout_ms),
    227                      "%u",
    228                      tms);
    229     GNUNET_asprintf (&path,
    230                      "orders/%s",
    231                      order_id);
    232     owgh->url = TALER_url_join (backend_url,
    233                                 path,
    234                                 "h_contract",
    235                                 h_contract_s.encoding,
    236                                 "session_id",
    237                                 session_id,
    238                                 "timeout_ms",
    239                                 (0 != tms)
    240                                 ? timeout_ms
    241                                 : NULL,
    242                                 "refund",
    243                                 (NULL != min_refund)
    244                                 ? TALER_amount2s (min_refund)
    245                                 : NULL,
    246                                 "await_refund_obtained",
    247                                 await_refund_obtained
    248                                 ? "yes"
    249                                 : NULL,
    250                                 NULL);
    251     GNUNET_free (path);
    252   }
    253   if (NULL == owgh->url)
    254   {
    255     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    256                 "Could not construct request URL.\n");
    257     GNUNET_free (owgh);
    258     return NULL;
    259   }
    260 
    261   {
    262     CURL *eh;
    263 
    264     eh = TALER_MERCHANT_curl_easy_get_ (owgh->url);
    265     if (0 != tms)
    266     {
    267       GNUNET_break (CURLE_OK ==
    268                     curl_easy_setopt (eh,
    269                                       CURLOPT_TIMEOUT_MS,
    270                                       (long) (tms + 100L)));
    271     }
    272 
    273     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    274                 "Checking order status at %s\n",
    275                 owgh->url);
    276     if (NULL == (owgh->job =
    277                    GNUNET_CURL_job_add (ctx,
    278                                         eh,
    279                                         &handle_wallet_get_order_finished,
    280                                         owgh)))
    281     {
    282       GNUNET_break (0);
    283       GNUNET_free (owgh->url);
    284       GNUNET_free (owgh);
    285       return NULL;
    286     }
    287   }
    288   return owgh;
    289 }
    290 
    291 
    292 void
    293 TALER_MERCHANT_wallet_order_get_cancel (
    294   struct TALER_MERCHANT_OrderWalletGetHandle *owgh)
    295 {
    296   if (NULL != owgh->job)
    297   {
    298     GNUNET_CURL_job_cancel (owgh->job);
    299     owgh->job = NULL;
    300   }
    301   GNUNET_free (owgh->url);
    302   GNUNET_free (owgh);
    303 }
    304 
    305 
    306 /* end of merchant_api_wallet_get_order.c */