merchant

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

lookup_transfer_details_by_order.c (8107B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2023, 2025, 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 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_transfer_details_by_order.c
     18  * @brief Implementation of the lookup_transfer_details_by_order function for Postgres
     19  * @author Iván Ávalos
     20  */
     21 #include "platform.h"
     22 #include <taler/taler_pq_lib.h>
     23 #include "merchant-database/lookup_transfer_details_by_order.h"
     24 #include "helper.h"
     25 
     26 /**
     27  * Closure for lookup_transfer_details_by_order_cb().
     28  */
     29 struct LookupTransferDetailsByOrderContext
     30 {
     31 
     32   /**
     33    * Plugin context.
     34    */
     35   struct TALER_MERCHANTDB_PostgresContext *pg;
     36 
     37   /**
     38    * Function to call with all results.
     39    */
     40   TALER_MERCHANTDB_OrderTransferDetailsCallback cb;
     41 
     42   /**
     43    * Closure for @e cb.
     44    */
     45   void *cb_cls;
     46 
     47   /**
     48    * Set to the query result.
     49    */
     50   enum GNUNET_DB_QueryStatus qs;
     51 };
     52 
     53 
     54 /**
     55  * Function to be called with the results of a SELECT statement
     56  * that has returned @a num_results results.  We SELECT by coin,
     57  * but because that's not useful for the UI, we combine all coins
     58  * that were deposited in the same wire transfer into a single
     59  * record before calling the callback.
     60  *
     61  * @param cls of type `struct LookupTransferDetailsByOrderContext *`
     62  * @param result the postgres result
     63  * @param num_results the number of results in @a result
     64  */
     65 static void
     66 lookup_transfer_details_by_order_cb (void *cls,
     67                                      PGresult *result,
     68                                      unsigned int num_results)
     69 {
     70   struct LookupTransferDetailsByOrderContext *ltdo = cls;
     71   struct TALER_WireTransferIdentifierRawP last_wtid;
     72   char *last_exchange_url = NULL;
     73   struct GNUNET_TIME_Timestamp last_execution_time;
     74   struct TALER_Amount last_deposit_value;
     75   struct TALER_Amount last_deposit_fee;
     76   bool last_confirmed;
     77   uint64_t last_expected_credit_serial;
     78 
     79   for (unsigned int i = 0; i<num_results; i++)
     80   {
     81     struct TALER_WireTransferIdentifierRawP wtid;
     82     char *exchange_url;
     83     struct GNUNET_TIME_Timestamp execution_time;
     84     struct TALER_Amount deposit_value;
     85     struct TALER_Amount deposit_fee;
     86     bool confirmed;
     87     uint64_t expected_credit_serial;
     88     struct GNUNET_PQ_ResultSpec rs[] = {
     89       GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
     90                                        &execution_time),
     91       GNUNET_PQ_result_spec_string ("exchange_url",
     92                                     &exchange_url),
     93       GNUNET_PQ_result_spec_bool ("confirmed",
     94                                   &confirmed),
     95       GNUNET_PQ_result_spec_auto_from_type ("wtid",
     96                                             &wtid),
     97       GNUNET_PQ_result_spec_uint64 ("expected_credit_serial",
     98                                     &expected_credit_serial),
     99       TALER_PQ_result_spec_amount_with_currency ("exchange_deposit_value",
    100                                                  &deposit_value),
    101       TALER_PQ_result_spec_amount_with_currency ("exchange_deposit_fee",
    102                                                  &deposit_fee),
    103       GNUNET_PQ_result_spec_end
    104     };
    105 
    106     if (GNUNET_OK !=
    107         GNUNET_PQ_extract_result (result,
    108                                   rs,
    109                                   i))
    110     {
    111       GNUNET_break (0);
    112       ltdo->qs = GNUNET_DB_STATUS_HARD_ERROR;
    113       return;
    114     }
    115     if (0 == i)
    116     {
    117       last_wtid = wtid;
    118       last_exchange_url = exchange_url;
    119       last_execution_time = execution_time;
    120       last_deposit_value = deposit_value;
    121       last_deposit_fee = deposit_fee;
    122       last_confirmed = confirmed;
    123       last_expected_credit_serial = expected_credit_serial;
    124       continue;
    125     }
    126     if ( (0 ==
    127           GNUNET_memcmp (&wtid,
    128                          &last_wtid)) &&
    129          (0 == strcmp (exchange_url,
    130                        last_exchange_url)) &&
    131          (expected_credit_serial ==
    132           last_expected_credit_serial) &&
    133          (GNUNET_TIME_timestamp_cmp (execution_time,
    134                                      ==,
    135                                      last_execution_time)) &&
    136          (last_confirmed == confirmed) &&
    137          (GNUNET_OK ==
    138           TALER_amount_cmp_currency (&deposit_value,
    139                                      &last_deposit_value)) )
    140     {
    141       GNUNET_assert (0 <=
    142                      TALER_amount_add (&last_deposit_value,
    143                                        &last_deposit_value,
    144                                        &deposit_value));
    145       GNUNET_assert (0 <=
    146                      TALER_amount_add (&last_deposit_fee,
    147                                        &last_deposit_fee,
    148                                        &deposit_fee));
    149       continue;
    150     }
    151     ltdo->cb (ltdo->cb_cls,
    152               &last_wtid,
    153               last_exchange_url,
    154               last_execution_time,
    155               &last_deposit_value,
    156               &last_deposit_fee,
    157               last_confirmed,
    158               last_expected_credit_serial);
    159     GNUNET_free (last_exchange_url);
    160     last_wtid = wtid;
    161     last_exchange_url = exchange_url;
    162     last_execution_time = execution_time;
    163     last_deposit_value = deposit_value;
    164     last_deposit_fee = deposit_fee;
    165     last_confirmed = confirmed;
    166     last_expected_credit_serial = expected_credit_serial;
    167   }
    168   if (num_results > 0)
    169   {
    170     ltdo->cb (ltdo->cb_cls,
    171               &last_wtid,
    172               last_exchange_url,
    173               last_execution_time,
    174               &last_deposit_value,
    175               &last_deposit_fee,
    176               last_confirmed,
    177               last_expected_credit_serial);
    178   }
    179   GNUNET_free (last_exchange_url);
    180   ltdo->qs = num_results;
    181 }
    182 
    183 
    184 enum GNUNET_DB_QueryStatus
    185 TALER_MERCHANTDB_lookup_transfer_details_by_order (
    186   struct TALER_MERCHANTDB_PostgresContext *pg,
    187   uint64_t order_serial,
    188   TALER_MERCHANTDB_OrderTransferDetailsCallback cb,
    189   void *cb_cls)
    190 {
    191   struct LookupTransferDetailsByOrderContext ltdo = {
    192     .pg = pg,
    193     .cb = cb,
    194     .cb_cls = cb_cls
    195   };
    196   struct GNUNET_PQ_QueryParam params[] = {
    197     GNUNET_PQ_query_param_uint64 (&order_serial),
    198     GNUNET_PQ_query_param_end
    199   };
    200   enum GNUNET_DB_QueryStatus qs;
    201 
    202   GNUNET_assert (NULL != pg->current_merchant_id);
    203   check_connection (pg);
    204   TMH_PQ_prepare_anon (pg,
    205                        "SELECT"
    206                        " md.deposit_serial"
    207                        ",mcon.exchange_url"
    208                        ",met.wtid"
    209                        ",mtc.exchange_deposit_value"
    210                        ",mtc.exchange_deposit_fee"
    211                        ",mcon.deposit_timestamp"
    212                        ",met.confirmed"
    213                        ",met.expected_credit_serial"
    214                        " FROM merchant_expected_transfer_to_coin mtc"
    215                        " JOIN merchant_deposits md"
    216                        "   USING (deposit_serial)"
    217                        " JOIN merchant_deposit_confirmations mcon"
    218                        "   USING (deposit_confirmation_serial)"
    219                        " JOIN merchant_expected_transfers met"
    220                        "   USING (expected_credit_serial)"
    221                        " JOIN merchant_accounts acc"
    222                        "   ON (acc.account_serial = met.account_serial)"
    223                        " JOIN merchant_contract_terms contracts"
    224                        "   USING (order_serial)"
    225                        " WHERE mcon.order_serial=$1"
    226                        " ORDER BY met.wtid");
    227 
    228   qs = GNUNET_PQ_eval_prepared_multi_select (
    229     pg->conn,
    230     "",
    231     params,
    232     &lookup_transfer_details_by_order_cb,
    233     &ltdo);
    234   if (qs < 0)
    235     return qs;
    236   return ltdo.qs;
    237 }