merchant

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

lookup_expected_transfers.c (10178B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 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 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/backenddb/lookup_expected_transfers.c
     18  * @brief Implementation of the lookup_expected_transfers function for Postgres
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include <taler/taler_error_codes.h>
     23 #include <taler/taler_dbevents.h>
     24 #include <taler/taler_pq_lib.h>
     25 #include "merchant-database/lookup_expected_transfers.h"
     26 #include "helper.h"
     27 #include <microhttpd.h> /* for HTTP status codes */
     28 
     29 /**
     30  * Closure for #lookup_expected_transfers_cb().
     31  */
     32 struct LookupExpectedTransfersContext
     33 {
     34   /**
     35    * Function to call on results.
     36    */
     37   TALER_MERCHANTDB_IncomingCallback cb;
     38 
     39   /**
     40    * Closure for @e cb.
     41    */
     42   void *cb_cls;
     43 
     44   /**
     45    * Postgres context.
     46    */
     47   struct TALER_MERCHANTDB_PostgresContext *pg;
     48 
     49   /**
     50    * Transaction status (set).
     51    */
     52   enum GNUNET_DB_QueryStatus qs;
     53 
     54 };
     55 
     56 
     57 /**
     58  * Function to be called with the results of a SELECT statement
     59  * that has returned @a num_results results.
     60  *
     61  * @param cls of type `struct LookupExpectedTransfersContext *`
     62  * @param result the postgres result
     63  * @param num_results the number of results in @a result
     64  */
     65 static void
     66 lookup_expected_transfers_cb (void *cls,
     67                               PGresult *result,
     68                               unsigned int num_results)
     69 {
     70   struct LookupExpectedTransfersContext *ltc = cls;
     71 
     72   for (unsigned int i = 0; i<num_results; i++)
     73   {
     74     struct TALER_Amount expected_credit_amount;
     75     struct TALER_WireTransferIdentifierRawP wtid;
     76     struct TALER_FullPayto payto_uri;
     77     char *exchange_url;
     78     uint64_t expected_transfer_serial_id;
     79     struct GNUNET_TIME_Timestamp execution_time
     80       = GNUNET_TIME_UNIT_ZERO_TS;
     81     bool confirmed;
     82     bool validated;
     83     bool no_amount;
     84     char *last_detail = NULL;
     85     uint32_t last_http_status = 0;
     86     uint32_t last_ec = TALER_EC_NONE;
     87     struct GNUNET_PQ_ResultSpec rs[] = {
     88       GNUNET_PQ_result_spec_allow_null (
     89         TALER_PQ_result_spec_amount_with_currency ("expected_credit_amount",
     90                                                    &expected_credit_amount),
     91         &no_amount),
     92       GNUNET_PQ_result_spec_auto_from_type ("wtid",
     93                                             &wtid),
     94       GNUNET_PQ_result_spec_string ("payto_uri",
     95                                     &payto_uri.full_payto),
     96       GNUNET_PQ_result_spec_string ("exchange_url",
     97                                     &exchange_url),
     98       GNUNET_PQ_result_spec_uint64 ("expected_credit_serial",
     99                                     &expected_transfer_serial_id),
    100       GNUNET_PQ_result_spec_allow_null (
    101         GNUNET_PQ_result_spec_timestamp ("execution_time",
    102                                          &execution_time),
    103         NULL),
    104       GNUNET_PQ_result_spec_bool ("confirmed",
    105                                   &confirmed),
    106       GNUNET_PQ_result_spec_allow_null (
    107         GNUNET_PQ_result_spec_uint32 ("last_http_status",
    108                                       &last_http_status),
    109         NULL),
    110       GNUNET_PQ_result_spec_allow_null (
    111         GNUNET_PQ_result_spec_uint32 ("last_ec",
    112                                       &last_ec),
    113         NULL),
    114       GNUNET_PQ_result_spec_allow_null (
    115         GNUNET_PQ_result_spec_string ("last_detail",
    116                                       &last_detail),
    117         NULL),
    118       GNUNET_PQ_result_spec_end
    119     };
    120 
    121     if (GNUNET_OK !=
    122         GNUNET_PQ_extract_result (result,
    123                                   rs,
    124                                   i))
    125     {
    126       GNUNET_break (0);
    127       ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
    128       return;
    129     }
    130     validated = ( (MHD_HTTP_OK == last_http_status) &&
    131                   (TALER_EC_NONE == last_ec) );
    132     ltc->cb (ltc->cb_cls,
    133              no_amount
    134              ? NULL
    135              : &expected_credit_amount,
    136              &wtid,
    137              payto_uri,
    138              exchange_url,
    139              expected_transfer_serial_id,
    140              execution_time,
    141              confirmed,
    142              validated,
    143              last_http_status,
    144              last_ec,
    145              last_detail);
    146     GNUNET_PQ_cleanup_result (rs);
    147   }
    148   ltc->qs = num_results;
    149 }
    150 
    151 
    152 enum GNUNET_DB_QueryStatus
    153 TALER_MERCHANTDB_lookup_expected_transfers (struct TALER_MERCHANTDB_PostgresContext *pg,
    154                                             const char *instance_id,
    155                                             struct TALER_FullPayto payto_uri,
    156                                             struct GNUNET_TIME_Timestamp before,
    157                                             struct GNUNET_TIME_Timestamp after,
    158                                             int64_t limit,
    159                                             uint64_t offset,
    160                                             enum TALER_EXCHANGE_YesNoAll confirmed,
    161                                             enum TALER_EXCHANGE_YesNoAll verified,
    162                                             TALER_MERCHANTDB_IncomingCallback cb,
    163                                             void *cb_cls)
    164 {
    165   uint64_t plimit = (uint64_t) ((limit < 0) ? -limit : limit);
    166   bool by_time = ( (! GNUNET_TIME_absolute_is_never (before.abs_time)) ||
    167                    (! GNUNET_TIME_absolute_is_zero (after.abs_time)) );
    168   struct LookupExpectedTransfersContext ltc = {
    169     .cb = cb,
    170     .cb_cls = cb_cls,
    171     .pg = pg
    172   };
    173   struct GNUNET_PQ_QueryParam params[] = {
    174     GNUNET_PQ_query_param_string (instance_id),
    175     GNUNET_PQ_query_param_timestamp (&before),
    176     GNUNET_PQ_query_param_timestamp (&after),
    177     GNUNET_PQ_query_param_uint64 (&offset),
    178     GNUNET_PQ_query_param_uint64 (&plimit),
    179     NULL == payto_uri.full_payto
    180     ? GNUNET_PQ_query_param_null () /* NULL: do not filter by payto URI */
    181     : GNUNET_PQ_query_param_string (payto_uri.full_payto),
    182     GNUNET_PQ_query_param_bool (! by_time),     /* $7: filter by time? */
    183     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_ALL == confirmed), /* filter by confirmed? */
    184     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_YES == confirmed),
    185     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_ALL == verified), /* filter by verified? */
    186     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_YES == verified),
    187 
    188     GNUNET_PQ_query_param_end
    189   };
    190   enum GNUNET_DB_QueryStatus qs;
    191 
    192   check_connection (pg);
    193   PREPARE (pg,
    194            "lookup_expected_transfers_asc",
    195            "SELECT"
    196            " met.expected_credit_amount"
    197            ",met.wtid"
    198            ",mac.payto_uri"
    199            ",met.exchange_url"
    200            ",met.expected_credit_serial"
    201            ",mts.execution_time"
    202            ",met.confirmed"
    203            ",met.last_http_status"
    204            ",met.last_ec"
    205            ",met.last_detail"
    206            " FROM merchant_expected_transfers met"
    207            "  JOIN merchant_accounts mac"
    208            "    USING (account_serial)"
    209            "  LEFT JOIN merchant_transfer_signatures mts"
    210            "    USING (expected_credit_serial)"
    211            " WHERE ( $7 OR "
    212            "         (mts.execution_time IS NOT NULL AND"
    213            "          mts.execution_time < $2 AND"
    214            "          mts.execution_time >= $3) )"
    215            "   AND ( (CAST($6 AS TEXT) IS NULL) OR "
    216            "         (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
    217            "         =REGEXP_REPLACE($6,'\\?.*','')) )"
    218            "   AND ( $8 OR "
    219            "         (met.confirmed = $9) )"
    220            "   AND ( $10 OR "
    221            "         ($11 = (200=met.last_http_status) AND"
    222            "                (0=met.last_ec) ) )"
    223            "   AND merchant_serial ="
    224            "     (SELECT merchant_serial"
    225            "        FROM merchant_instances"
    226            "       WHERE merchant_id=$1)"
    227            "   AND (met.expected_credit_serial > $4)"
    228            " ORDER BY met.expected_credit_serial ASC"
    229            " LIMIT $5");
    230   PREPARE (pg,
    231            "lookup_expected_transfers_desc",
    232            "SELECT"
    233            " met.expected_credit_amount"
    234            ",met.wtid"
    235            ",mac.payto_uri"
    236            ",met.exchange_url"
    237            ",met.expected_credit_serial"
    238            ",mts.execution_time"
    239            ",met.confirmed"
    240            ",met.last_http_status"
    241            ",met.last_ec"
    242            ",met.last_detail"
    243            " FROM merchant_expected_transfers met"
    244            "  JOIN merchant_accounts mac"
    245            "    USING (account_serial)"
    246            "  LEFT JOIN merchant_transfer_signatures mts"
    247            "    USING (expected_credit_serial)"
    248            " WHERE ( $7 OR "
    249            "         (mts.execution_time IS NOT NULL AND"
    250            "          mts.execution_time < $2 AND"
    251            "          mts.execution_time >= $3) )"
    252            "   AND ( (CAST($6 AS TEXT) IS NULL) OR "
    253            "         (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
    254            "         =REGEXP_REPLACE($6,'\\?.*','')) )"
    255            "   AND ( $8 OR "
    256            "         (met.confirmed = $9) )"
    257            "   AND ( $10 OR "
    258            "         ($11 = (200=met.last_http_status) AND"
    259            "                (0=met.last_ec) ) )"
    260            "   AND merchant_serial ="
    261            "     (SELECT merchant_serial"
    262            "        FROM merchant_instances"
    263            "       WHERE merchant_id=$1)"
    264            "   AND (met.expected_credit_serial < $4)"
    265            " ORDER BY met.expected_credit_serial DESC"
    266            " LIMIT $5");
    267   qs = GNUNET_PQ_eval_prepared_multi_select (
    268     pg->conn,
    269     (limit > 0)
    270     ? "lookup_expected_transfers_asc"
    271     : "lookup_expected_transfers_desc",
    272     params,
    273     &lookup_expected_transfers_cb,
    274     &ltc);
    275   if (0 >= qs)
    276     return qs;
    277   return ltc.qs;
    278 }