merchant

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

taler-merchant-httpd_get-private-incoming-ID.c (8578B)


      1 /*
      2   This file is part of TALER
      3   (C) 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 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 src/backend/taler-merchant-httpd_get-private-incoming-ID.c
     18  * @brief implement API for obtaining details about an expected incoming wire transfer
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include <jansson.h>
     23 #include <taler/taler_json_lib.h>
     24 #include "taler-merchant-httpd_get-private-incoming-ID.h"
     25 #include "merchant-database/lookup_expected_transfer.h"
     26 #include "merchant-database/lookup_reconciliation_details.h"
     27 #include "merchant-database/lookup_wire_fee.h"
     28 #include "merchant-database/preflight.h"
     29 
     30 
     31 /**
     32  * Function called with information about orders aggregated into
     33  * a wire transfer.
     34  * Generate a response (array entry) based on the given arguments.
     35  *
     36  * @param cls closure with a `json_t *` array to build up the response
     37  * @param order_id ID of the order that was paid and aggregated
     38  * @param remaining_deposit deposited amount minus any refunds
     39  * @param deposit_fee deposit fees paid to the exchange for the order
     40  */
     41 static void
     42 reconciliation_cb (void *cls,
     43                    const char *order_id,
     44                    const struct TALER_Amount *remaining_deposit,
     45                    const struct TALER_Amount *deposit_fee)
     46 {
     47   json_t *rd = cls;
     48   json_t *r;
     49 
     50   r = GNUNET_JSON_PACK (
     51     GNUNET_JSON_pack_string ("order_id",
     52                              order_id),
     53     TALER_JSON_pack_amount ("remaining_deposit",
     54                             remaining_deposit),
     55     TALER_JSON_pack_amount ("deposit_fee",
     56                             deposit_fee));
     57   GNUNET_assert (0 ==
     58                  json_array_append_new (rd,
     59                                         r));
     60 }
     61 
     62 
     63 enum MHD_Result
     64 TMH_private_get_incoming_ID (const struct TMH_RequestHandler *rh,
     65                              struct MHD_Connection *connection,
     66                              struct TMH_HandlerContext *hc)
     67 {
     68   unsigned long long serial_id;
     69   struct TALER_Amount wire_fee;
     70   bool no_fee;
     71   struct GNUNET_TIME_Timestamp expected_time;
     72   struct TALER_Amount expected_credit_amount;
     73   struct TALER_WireTransferIdentifierRawP wtid;
     74   struct TALER_FullPayto payto_uri;
     75   char *exchange_url = NULL;
     76   struct GNUNET_TIME_Timestamp execution_time;
     77   bool confirmed;
     78 
     79   {
     80     char dummy;
     81 
     82     if (1 !=
     83         sscanf (hc->infix,
     84                 "%llu%c",
     85                 &serial_id,
     86                 &dummy))
     87     {
     88       GNUNET_break_op (0);
     89       return TALER_MHD_reply_with_error (
     90         connection,
     91         MHD_HTTP_BAD_REQUEST,
     92         TALER_EC_GENERIC_PARAMETER_MALFORMED,
     93         "transfer ID must be a number");
     94     }
     95   }
     96 
     97   TALER_MERCHANTDB_preflight (TMH_db);
     98   {
     99     struct TALER_MasterPublicKeyP master_pub;
    100     enum GNUNET_DB_QueryStatus qs;
    101 
    102     qs = TALER_MERCHANTDB_lookup_expected_transfer (TMH_db,
    103                                                     hc->instance->settings.id,
    104                                                     serial_id,
    105                                                     &expected_time,
    106                                                     &expected_credit_amount,
    107                                                     &wtid,
    108                                                     &payto_uri,
    109                                                     &exchange_url,
    110                                                     &execution_time,
    111                                                     &confirmed,
    112                                                     &master_pub);
    113     if (0 > qs)
    114     {
    115       /* Simple select queries should not cause serialization issues */
    116       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    117       /* Always report on hard error as well to enable diagnostics */
    118       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    119       return TALER_MHD_reply_with_error (connection,
    120                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    121                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
    122                                          "lookup_expected_transfer");
    123     }
    124     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    125     {
    126       GNUNET_break_op (0);
    127       return TALER_MHD_reply_with_error (
    128         connection,
    129         MHD_HTTP_NOT_FOUND,
    130         TALER_EC_MERCHANT_GENERIC_EXPECTED_TRANSFER_UNKNOWN,
    131         hc->infix);
    132     }
    133 
    134     {
    135       char *method;
    136       struct GNUNET_TIME_Timestamp start_date;
    137       struct GNUNET_TIME_Timestamp end_date;
    138       struct TALER_MasterSignatureP master_sig;
    139       struct TALER_WireFeeSet fees;
    140 
    141       method = TALER_payto_get_method (payto_uri.full_payto);
    142       qs = TALER_MERCHANTDB_lookup_wire_fee (
    143         TMH_db,
    144         &master_pub,
    145         method,
    146         expected_time,
    147         &fees,
    148         &start_date,
    149         &end_date,
    150         &master_sig);
    151       GNUNET_free (method);
    152       if (0 > qs)
    153       {
    154         /* Simple select queries should not cause serialization issues */
    155         GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    156         /* Always report on hard error as well to enable diagnostics */
    157         GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    158         GNUNET_free (exchange_url);
    159         GNUNET_free (payto_uri.full_payto);
    160         return TALER_MHD_reply_with_error (connection,
    161                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    162                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    163                                            "lookup_wire_fee");
    164       }
    165       no_fee = (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
    166       if (! no_fee)
    167         wire_fee = fees.wire;
    168     }
    169 
    170   }
    171 
    172   {
    173     enum GNUNET_DB_QueryStatus qs;
    174     json_t *rd;
    175     enum MHD_Result mret;
    176 
    177     rd = json_array ();
    178     GNUNET_assert (NULL != rd);
    179     qs = TALER_MERCHANTDB_lookup_reconciliation_details (TMH_db,
    180                                                          hc->instance->settings.id,
    181                                                          serial_id,
    182                                                          &reconciliation_cb,
    183                                                          rd);
    184     if (0 > qs)
    185     {
    186       /* Simple select queries should not cause serialization issues */
    187       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    188       /* Always report on hard error as well to enable diagnostics */
    189       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    190       GNUNET_free (exchange_url);
    191       GNUNET_free (payto_uri.full_payto);
    192       return TALER_MHD_reply_with_error (connection,
    193                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    194                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
    195                                          "lookup_reconciliation_details");
    196     }
    197 
    198     mret = TALER_MHD_REPLY_JSON_PACK (
    199       connection,
    200       MHD_HTTP_OK,
    201       GNUNET_JSON_pack_allow_null (
    202         TALER_JSON_pack_amount (
    203           "expected_credit_amount",
    204           TALER_amount_is_valid (&expected_credit_amount)
    205           ? &expected_credit_amount
    206           : NULL)),
    207       GNUNET_JSON_pack_data_auto ("wtid",
    208                                   &wtid),
    209       TALER_JSON_pack_full_payto ("payto_uri",
    210                                   payto_uri),
    211       GNUNET_JSON_pack_string ("exchange_url",
    212                                exchange_url),
    213       GNUNET_JSON_pack_bool ("confirmed",
    214                              confirmed),
    215       GNUNET_JSON_pack_allow_null (
    216         GNUNET_JSON_pack_timestamp ("execution_time",
    217                                     execution_time)),
    218       GNUNET_JSON_pack_timestamp ("expected_time",
    219                                   expected_time),
    220       GNUNET_JSON_pack_allow_null (
    221         TALER_JSON_pack_amount ("wire_fee",
    222                                 no_fee ? NULL : &wire_fee)),
    223       GNUNET_JSON_pack_array_steal ("reconciliation_details",
    224                                     rd));
    225     GNUNET_free (exchange_url);
    226     GNUNET_free (payto_uri.full_payto);
    227     return mret;
    228   }
    229 }
    230 
    231 
    232 /* end of taler-merchant-httpd_get-private-incoming-ID.c */