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