merchant

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

pg_lookup_expected_transfers.c (9723B)


      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 backenddb/pg_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 "pg_lookup_expected_transfers.h"
     26 #include "pg_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 PostgresClosure *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 TMH_PG_lookup_expected_transfers (
    154   void *cls,
    155   const char *instance_id,
    156   struct TALER_FullPayto payto_uri,
    157   struct GNUNET_TIME_Timestamp before,
    158   struct GNUNET_TIME_Timestamp after,
    159   int64_t limit,
    160   uint64_t offset,
    161   enum TALER_EXCHANGE_YesNoAll confirmed,
    162   enum TALER_EXCHANGE_YesNoAll verified,
    163   TALER_MERCHANTDB_IncomingCallback cb,
    164   void *cb_cls)
    165 {
    166   struct PostgresClosure *pg = cls;
    167   uint64_t plimit = (uint64_t) ((limit < 0) ? -limit : limit);
    168   bool by_time = ( (! GNUNET_TIME_absolute_is_never (before.abs_time)) ||
    169                    (! GNUNET_TIME_absolute_is_zero (after.abs_time)) );
    170   struct LookupExpectedTransfersContext ltc = {
    171     .cb = cb,
    172     .cb_cls = cb_cls,
    173     .pg = pg
    174   };
    175   struct GNUNET_PQ_QueryParam params[] = {
    176     GNUNET_PQ_query_param_string (instance_id),
    177     GNUNET_PQ_query_param_timestamp (&before),
    178     GNUNET_PQ_query_param_timestamp (&after),
    179     GNUNET_PQ_query_param_uint64 (&offset),
    180     GNUNET_PQ_query_param_uint64 (&plimit),
    181     NULL == payto_uri.full_payto
    182     ? GNUNET_PQ_query_param_null () /* NULL: do not filter by payto URI */
    183     : GNUNET_PQ_query_param_string (payto_uri.full_payto),
    184     GNUNET_PQ_query_param_bool (! by_time),     /* $7: filter by time? */
    185     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_ALL == confirmed), /* filter by confirmed? */
    186     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_YES == confirmed),
    187     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_ALL == verified), /* filter by verified? */
    188     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_YES == verified),
    189 
    190     GNUNET_PQ_query_param_end
    191   };
    192   enum GNUNET_DB_QueryStatus qs;
    193 
    194   check_connection (pg);
    195   PREPARE (pg,
    196            "lookup_expected_transfers_asc",
    197            "SELECT"
    198            " met.expected_credit_amount"
    199            ",met.wtid"
    200            ",mac.payto_uri"
    201            ",met.exchange_url"
    202            ",met.expected_credit_serial"
    203            ",mts.execution_time"
    204            ",met.confirmed"
    205            ",met.last_http_status"
    206            ",met.last_ec"
    207            ",met.last_detail"
    208            " FROM merchant_expected_transfers met"
    209            "  JOIN merchant_accounts mac"
    210            "    USING (account_serial)"
    211            "  LEFT JOIN merchant_transfer_signatures mts"
    212            "    USING (expected_credit_serial)"
    213            " WHERE ( $7 OR "
    214            "         (mts.execution_time IS NOT NULL AND"
    215            "          mts.execution_time < $2 AND"
    216            "          mts.execution_time >= $3) )"
    217            "   AND ( (CAST($6 AS TEXT) IS NULL) OR "
    218            "         (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
    219            "         =REGEXP_REPLACE($6,'\\?.*','')) )"
    220            "   AND ( $8 OR "
    221            "         (met.confirmed = $9) )"
    222            "   AND ( $10 OR "
    223            "         ($11 = (200=met.last_http_status) AND"
    224            "                (0=met.last_ec) ) )"
    225            "   AND merchant_serial ="
    226            "     (SELECT merchant_serial"
    227            "        FROM merchant_instances"
    228            "       WHERE merchant_id=$1)"
    229            "   AND (met.expected_credit_serial > $4)"
    230            " ORDER BY met.expected_credit_serial ASC"
    231            " LIMIT $5");
    232   PREPARE (pg,
    233            "lookup_expected_transfers_desc",
    234            "SELECT"
    235            " met.expected_credit_amount"
    236            ",met.wtid"
    237            ",mac.payto_uri"
    238            ",met.exchange_url"
    239            ",met.expected_credit_serial"
    240            ",mts.execution_time"
    241            ",met.confirmed"
    242            ",met.last_http_status"
    243            ",met.last_ec"
    244            ",met.last_detail"
    245            " FROM merchant_expected_transfers met"
    246            "  JOIN merchant_accounts mac"
    247            "    USING (account_serial)"
    248            "  LEFT JOIN merchant_transfer_signatures mts"
    249            "    USING (expected_credit_serial)"
    250            " WHERE ( $7 OR "
    251            "         (mts.execution_time IS NOT NULL AND"
    252            "          mts.execution_time < $2 AND"
    253            "          mts.execution_time >= $3) )"
    254            "   AND ( (CAST($6 AS TEXT) IS NULL) OR "
    255            "         (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
    256            "         =REGEXP_REPLACE($6,'\\?.*','')) )"
    257            "   AND ( $8 OR "
    258            "         (met.confirmed = $9) )"
    259            "   AND ( $10 OR "
    260            "         ($11 = (200=met.last_http_status) AND"
    261            "                (0=met.last_ec) ) )"
    262            "   AND merchant_serial ="
    263            "     (SELECT merchant_serial"
    264            "        FROM merchant_instances"
    265            "       WHERE merchant_id=$1)"
    266            "   AND (met.expected_credit_serial < $4)"
    267            " ORDER BY met.expected_credit_serial DESC"
    268            " LIMIT $5");
    269   qs = GNUNET_PQ_eval_prepared_multi_select (
    270     pg->conn,
    271     (limit > 0)
    272     ? "lookup_expected_transfers_asc"
    273     : "lookup_expected_transfers_desc",
    274     params,
    275     &lookup_expected_transfers_cb,
    276     &ltc);
    277   if (0 >= qs)
    278     return qs;
    279   return ltc.qs;
    280 }