merchant

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

pg_lookup_orders.c (10171B)


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