merchant

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

lookup_orders.c (10653B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2022, 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 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_orders.c
     18  * @brief Implementation of the lookup_orders function for Postgres
     19  * @author Iván Ávalos
     20  * @author Christian Grothoff
     21  */
     22 #include "platform.h"
     23 #include <taler/taler_pq_lib.h>
     24 #include "merchant-database/lookup_orders.h"
     25 #include "helper.h"
     26 
     27 /**
     28  * Context used for TALER_MERCHANTDB_lookup_orders().
     29  */
     30 struct LookupOrdersContext
     31 {
     32   /**
     33    * Function to call with the results.
     34    */
     35   TALER_MERCHANTDB_OrdersCallback cb;
     36 
     37   /**
     38    * Closure for @a cb.
     39    */
     40   void *cb_cls;
     41 
     42   /**
     43    * Did database result extraction fail?
     44    */
     45   bool extract_failed;
     46 };
     47 
     48 
     49 /**
     50  * Function to be called with the results of a SELECT statement
     51  * that has returned @a num_results results about orders.
     52  *
     53  * @param[in,out] cls of type `struct LookupOrdersContext *`
     54  * @param result the postgres result
     55  * @param num_results the number of results in @a result
     56  */
     57 static void
     58 lookup_orders_cb (void *cls,
     59                   PGresult *result,
     60                   unsigned int num_results)
     61 {
     62   struct LookupOrdersContext *plc = cls;
     63 
     64   for (unsigned int i = 0; i < num_results; i++)
     65   {
     66     char *order_id;
     67     uint64_t order_serial;
     68     struct GNUNET_TIME_Timestamp ts;
     69     struct GNUNET_PQ_ResultSpec rs[] = {
     70       GNUNET_PQ_result_spec_string ("order_id",
     71                                     &order_id),
     72       GNUNET_PQ_result_spec_uint64 ("order_serial",
     73                                     &order_serial),
     74       GNUNET_PQ_result_spec_timestamp ("creation_time",
     75                                        &ts),
     76       GNUNET_PQ_result_spec_end
     77     };
     78 
     79     if (GNUNET_OK !=
     80         GNUNET_PQ_extract_result (result,
     81                                   rs,
     82                                   i))
     83     {
     84       GNUNET_break (0);
     85       plc->extract_failed = true;
     86       return;
     87     }
     88     plc->cb (plc->cb_cls,
     89              order_id,
     90              order_serial,
     91              ts);
     92     GNUNET_PQ_cleanup_result (rs);
     93   }
     94 }
     95 
     96 
     97 enum GNUNET_DB_QueryStatus
     98 TALER_MERCHANTDB_lookup_orders (
     99   struct TALER_MERCHANTDB_PostgresContext *pg,
    100   const char *instance_id,
    101   const struct TALER_MERCHANTDB_OrderFilter *of,
    102   TALER_MERCHANTDB_OrdersCallback cb,
    103   void *cb_cls)
    104 {
    105   struct LookupOrdersContext plc = {
    106     .cb = cb,
    107     .cb_cls = cb_cls
    108   };
    109   uint64_t limit = (of->delta > 0) ? of->delta : -of->delta;
    110   struct GNUNET_PQ_QueryParam params[] = {
    111     /* $1 */
    112     GNUNET_PQ_query_param_uint64 (&limit),
    113     GNUNET_PQ_query_param_uint64 (&of->start_row),
    114     GNUNET_PQ_query_param_timestamp (&of->date),
    115     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->paid)),
    116     /* $5 */
    117     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->paid)),
    118     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->refunded)),
    119     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->refunded)),
    120     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->wired)),
    121     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->wired)),
    122     /* $10 */
    123     GNUNET_PQ_query_param_bool (NULL == of->session_id),
    124     NULL == of->session_id
    125     ? GNUNET_PQ_query_param_null ()
    126     : GNUNET_PQ_query_param_string (of->session_id),
    127     GNUNET_PQ_query_param_bool (NULL == of->fulfillment_url),
    128     NULL == of->fulfillment_url
    129     ? GNUNET_PQ_query_param_null ()
    130     : GNUNET_PQ_query_param_string (of->fulfillment_url),
    131     NULL == of->summary_filter
    132     ? GNUNET_PQ_query_param_null ()
    133     : GNUNET_PQ_query_param_string (of->summary_filter),
    134     GNUNET_PQ_query_param_end
    135   };
    136   enum GNUNET_DB_QueryStatus qs;
    137 
    138   GNUNET_assert (NULL != pg->current_merchant_id);
    139   GNUNET_assert (0 == strcmp (instance_id,
    140                               pg->current_merchant_id));
    141   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    142               "Looking up orders, using filter paid: %d, refunded: %d, wired: %d\n",
    143               of->paid,
    144               of->refunded,
    145               of->wired);
    146 
    147   if (of->delta > 0)
    148   {
    149     TMH_PQ_prepare_anon (pg,
    150                          "(SELECT"
    151                          " order_id"
    152                          ",order_serial"
    153                          ",creation_time"
    154                          " FROM merchant_orders"
    155                          " WHERE order_serial > $2"
    156                          "   AND"
    157                          "    creation_time > $3"
    158                          "   AND ($4 OR "
    159                          "    NOT CAST($5 AS BOOL))" /* unclaimed orders are never paid */
    160                          "   AND ($6 OR "
    161                          "    NOT CAST($7 AS BOOL))"/* unclaimed orders are never refunded */
    162                          "   AND ($8 OR "
    163                          "    NOT CAST($9 AS BOOL))" /* unclaimed orders are never wired */
    164                          "   AND"
    165                          "    (order_serial NOT IN"
    166                          "     (SELECT order_serial"
    167                          "      FROM merchant_contract_terms))" /* only select unclaimed orders */
    168                          "   AND ($10 OR "
    169                          "     ($11 = session_id))"
    170                          "   AND ($12 OR "
    171                          "     ($13 = fulfillment_url))"
    172                          "   AND ( ($14::TEXT IS NULL) OR "
    173                          "         (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )"
    174                          " ORDER BY order_serial ASC"
    175                          " LIMIT $1)"
    176                          "UNION " /* union ensures elements are distinct! */
    177                          "(SELECT"
    178                          " order_id"
    179                          ",order_serial"
    180                          ",creation_time"
    181                          " FROM merchant_contract_terms"
    182                          " WHERE order_serial > $2"
    183                          "   AND"
    184                          "    creation_time > $3"
    185                          "   AND ($4 OR "
    186                          "    (CAST($5 AS BOOL) = paid))"
    187                          "   AND ($6 OR "
    188                          "    (CAST($7 AS BOOL) = (order_serial IN"
    189                          "     (SELECT order_serial "
    190                          "      FROM merchant_refunds))))"
    191                          "   AND ($8 OR"
    192                          "    (CAST($9 AS BOOL) = wired))"
    193                          "   AND ($10 OR "
    194                          "     ($11 = session_id))"
    195                          "   AND ($12 OR "
    196                          "     ($13 = fulfillment_url))"
    197                          "   AND ( ($14::TEXT IS NULL) OR "
    198                          "         (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )"
    199                          " ORDER BY order_serial ASC"
    200                          " LIMIT $1)"
    201                          " ORDER BY order_serial ASC"
    202                          " LIMIT $1");
    203   }
    204   else
    205   {
    206     TMH_PQ_prepare_anon (pg,
    207                          "(SELECT"
    208                          " order_id"
    209                          ",order_serial"
    210                          ",creation_time"
    211                          " FROM merchant_orders"
    212                          " WHERE order_serial < $2"
    213                          "   AND"
    214                          "    creation_time < $3"
    215                          "   AND ($4 OR "
    216                          "    NOT CAST($5 AS BOOL))" /* unclaimed orders are never paid */
    217                          "   AND ($6 OR "
    218                          "    NOT CAST($7 AS BOOL))"/* unclaimed orders are never refunded */
    219                          "   AND ($8 OR "
    220                          "    NOT CAST($9 AS BOOL))" /* unclaimed orders are never wired */
    221                          "   AND"
    222                          "    order_serial NOT IN"
    223                          "     (SELECT order_serial"
    224                          "      FROM merchant_contract_terms)" /* only select unclaimed orders */
    225                          "   AND ($10 OR "
    226                          "     ($11 = session_id))"
    227                          "   AND ($12 OR "
    228                          "     ($13 = fulfillment_url))"
    229                          "   AND ( ($14::TEXT IS NULL) OR "
    230                          "         (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )"
    231                          " ORDER BY order_serial DESC"
    232                          " LIMIT $1)"
    233                          "UNION " /* union ensures elements are distinct! */
    234                          "(SELECT"
    235                          " order_id"
    236                          ",order_serial"
    237                          ",creation_time"
    238                          " FROM merchant_contract_terms"
    239                          " WHERE order_serial < $2"
    240                          "   AND"
    241                          "    creation_time < $3"
    242                          "   AND ($4 OR "
    243                          "    (CAST($5 AS BOOL) = paid))"
    244                          "   AND ($6 OR "
    245                          "    (CAST($7 AS BOOL) = (order_serial IN"
    246                          "     (SELECT order_serial "
    247                          "      FROM merchant_refunds))))"
    248                          "   AND ($8 OR"
    249                          "     (CAST($9 AS BOOL) = wired))"
    250                          "   AND ($10 OR "
    251                          "     ($11 = session_id))"
    252                          "   AND ($12 OR "
    253                          "     ($13 = fulfillment_url))"
    254                          "   AND ( ($14::TEXT IS NULL) OR "
    255                          "         (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )"
    256                          " ORDER BY order_serial DESC"
    257                          " LIMIT $1)"
    258                          " ORDER BY order_serial DESC"
    259                          " LIMIT $1");
    260   }
    261   qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
    262                                              "",
    263                                              params,
    264                                              &lookup_orders_cb,
    265                                              &plc);
    266   if (plc.extract_failed)
    267     return GNUNET_DB_STATUS_HARD_ERROR;
    268   return qs;
    269 }