merchant

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

taler-merchant-httpd_private-post-transfers.c (5649B)


      1 /*
      2   This file is part of TALER
      3   (C) 2014-2023, 2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, 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 General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file taler-merchant-httpd_private-post-transfers.c
     18  * @brief implement API for registering wire transfers
     19  * @author Marcello Stanisci
     20  * @author Christian Grothoff
     21  */
     22 #include "platform.h"
     23 #include <jansson.h>
     24 #include <taler/taler_signatures.h>
     25 #include <taler/taler_json_lib.h>
     26 #include <taler/taler_dbevents.h>
     27 #include "taler-merchant-httpd_exchanges.h"
     28 #include "taler-merchant-httpd_helper.h"
     29 #include "taler-merchant-httpd_private-post-transfers.h"
     30 
     31 
     32 /**
     33  * How often do we retry the simple INSERT database transaction?
     34  */
     35 #define MAX_RETRIES 5
     36 
     37 
     38 MHD_RESULT
     39 TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
     40                             struct MHD_Connection *connection,
     41                             struct TMH_HandlerContext *hc)
     42 {
     43   struct TALER_FullPayto payto_uri;
     44   const char *exchange_url;
     45   struct TALER_WireTransferIdentifierRawP wtid;
     46   struct TALER_Amount amount;
     47   struct GNUNET_JSON_Specification spec[] = {
     48     TALER_JSON_spec_amount_any ("credit_amount",
     49                                 &amount),
     50     GNUNET_JSON_spec_fixed_auto ("wtid",
     51                                  &wtid),
     52     TALER_JSON_spec_full_payto_uri ("payto_uri",
     53                                     &payto_uri),
     54     TALER_JSON_spec_web_url ("exchange_url",
     55                              &exchange_url),
     56     GNUNET_JSON_spec_end ()
     57   };
     58   enum GNUNET_GenericReturnValue res;
     59   enum GNUNET_DB_QueryStatus qs;
     60 
     61   res = TALER_MHD_parse_json_data (connection,
     62                                    hc->request_body,
     63                                    spec);
     64   if (GNUNET_OK != res)
     65     return (GNUNET_NO == res)
     66       ? MHD_YES
     67       : MHD_NO;
     68   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     69               "New inbound wire transfer over %s to %s from %s\n",
     70               TALER_amount2s (&amount),
     71               payto_uri.full_payto,
     72               exchange_url);
     73 
     74   /* Check if transfer data is in database, if not, add it. */
     75   for (unsigned int retry = 0; retry<MAX_RETRIES; retry++)
     76   {
     77     TMH_db->preflight (TMH_db->cls);
     78     if (GNUNET_OK !=
     79         TMH_db->start (TMH_db->cls,
     80                        "post-transfers"))
     81     {
     82       GNUNET_break (0);
     83       return TALER_MHD_reply_with_error (connection,
     84                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
     85                                          TALER_EC_GENERIC_DB_START_FAILED,
     86                                          "transfer");
     87     }
     88     qs = TMH_db->insert_transfer (TMH_db->cls,
     89                                   hc->instance->settings.id,
     90                                   exchange_url,
     91                                   &wtid,
     92                                   &amount,
     93                                   payto_uri,
     94                                   0 /* no bank serial known! */);
     95     switch (qs)
     96     {
     97     case GNUNET_DB_STATUS_HARD_ERROR:
     98       GNUNET_break (0);
     99       TMH_db->rollback (TMH_db->cls);
    100       return TALER_MHD_reply_with_error (connection,
    101                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    102                                          TALER_EC_GENERIC_DB_STORE_FAILED,
    103                                          "insert_transfer");
    104     case GNUNET_DB_STATUS_SOFT_ERROR:
    105       TMH_db->rollback (TMH_db->cls);
    106       continue;
    107     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    108       /* Must mean the bank account is unknown! */
    109       TMH_db->rollback (TMH_db->cls);
    110       return TALER_MHD_reply_with_error (
    111         connection,
    112         MHD_HTTP_CONFLICT,
    113         TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_CONFLICTING_SUBMISSION,
    114         payto_uri.full_payto);
    115     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    116       break;
    117     }
    118     {
    119       struct GNUNET_DB_EventHeaderP es = {
    120         .size = htons (sizeof (es)),
    121         .type = htons (TALER_DBEVENT_MERCHANT_WIRE_TRANSFER_CONFIRMED)
    122       };
    123 
    124       TMH_db->event_notify (TMH_db->cls,
    125                             &es,
    126                             NULL,
    127                             0);
    128     }
    129     qs = TMH_db->commit (TMH_db->cls);
    130     switch (qs)
    131     {
    132     case GNUNET_DB_STATUS_HARD_ERROR:
    133       GNUNET_break (0);
    134       TMH_db->rollback (TMH_db->cls);
    135       return TALER_MHD_reply_with_error (connection,
    136                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    137                                          TALER_EC_GENERIC_DB_COMMIT_FAILED,
    138                                          NULL);
    139     case GNUNET_DB_STATUS_SOFT_ERROR:
    140       TMH_db->rollback (TMH_db->cls);
    141       continue;
    142     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    143     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    144       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    145                   "post-transfer committed successfully\n");
    146       break;
    147     }
    148     break;
    149   }
    150   return TALER_MHD_reply_static (connection,
    151                                  MHD_HTTP_NO_CONTENT,
    152                                  NULL,
    153                                  NULL,
    154                                  0);
    155 }
    156 
    157 
    158 /* end of taler-merchant-httpd_private-post-transfers.c */