Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 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/iterate_reconciliation_details.c
18 : * @brief Implementation of the iterate_reconciliation_details function for Postgres
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <taler/taler_pq_lib.h>
23 : #include "merchant-database/iterate_reconciliation_details.h"
24 : #include "helper.h"
25 :
26 :
27 : /**
28 : * Context for TALER_MERCHANTDB_iterate_reconciliation_details().
29 : */
30 : struct ReconciliationContext
31 : {
32 : /**
33 : * Function to call with the results.
34 : */
35 : TALER_MERCHANTDB_ReconciliationDetailsCallback cb;
36 :
37 : /**
38 : * Closure for @e cb.
39 : */
40 : void *cb_cls;
41 :
42 : /**
43 : * Database context.
44 : */
45 : struct TALER_MERCHANTDB_PostgresContext *pg;
46 :
47 : /**
48 : * Set to the return value on errors.
49 : */
50 : enum GNUNET_DB_QueryStatus qs;
51 :
52 : };
53 :
54 :
55 : /**
56 : * Function to be called with the results of a SELECT statement
57 : * that has returned @a num_results results about reconciliation
58 : * details.
59 : *
60 : * @param cls of type `struct ReconciliationContext *`
61 : * @param result the postgres result
62 : * @param num_results the number of results in @a result
63 : */
64 : static void
65 1 : reconciliation_cb (void *cls,
66 : PGresult *result,
67 : unsigned int num_results)
68 : {
69 1 : struct ReconciliationContext *lic = cls;
70 :
71 2 : for (unsigned int i = 0; i < num_results; i++)
72 : {
73 : char *order_id;
74 : uint64_t dvs;
75 : uint64_t dfs;
76 : uint64_t fvs;
77 : uint64_t ffs;
78 : char *currency;
79 : struct TALER_Amount remaining_deposit;
80 : struct TALER_Amount deposit_fee;
81 1 : struct GNUNET_PQ_ResultSpec rs[] = {
82 1 : GNUNET_PQ_result_spec_string ("order_id",
83 : &order_id),
84 1 : GNUNET_PQ_result_spec_string ("currency",
85 : ¤cy),
86 1 : GNUNET_PQ_result_spec_uint64 ("deposit_value_sum",
87 : &dvs),
88 1 : GNUNET_PQ_result_spec_uint64 ("deposit_frac_sum",
89 : &dfs),
90 1 : GNUNET_PQ_result_spec_uint64 ("fee_value_sum",
91 : &fvs),
92 1 : GNUNET_PQ_result_spec_uint64 ("fee_frac_sum",
93 : &ffs),
94 : GNUNET_PQ_result_spec_end
95 : };
96 :
97 1 : if (GNUNET_OK !=
98 1 : GNUNET_PQ_extract_result (result,
99 : rs,
100 : i))
101 : {
102 0 : GNUNET_break (0);
103 0 : lic->qs = GNUNET_DB_STATUS_HARD_ERROR;
104 0 : return;
105 : }
106 1 : GNUNET_assert (GNUNET_OK ==
107 : TALER_amount_set_zero (currency,
108 : &remaining_deposit));
109 1 : GNUNET_assert (GNUNET_OK ==
110 : TALER_amount_set_zero (currency,
111 : &deposit_fee));
112 1 : remaining_deposit.value = dvs + dfs / TALER_AMOUNT_FRAC_BASE;
113 1 : remaining_deposit.fraction = dfs % TALER_AMOUNT_FRAC_BASE;
114 1 : deposit_fee.value = fvs + ffs / TALER_AMOUNT_FRAC_BASE;
115 1 : deposit_fee.fraction = ffs % TALER_AMOUNT_FRAC_BASE;
116 :
117 1 : lic->cb (lic->cb_cls,
118 : order_id,
119 : &remaining_deposit,
120 : &deposit_fee);
121 1 : GNUNET_PQ_cleanup_result (rs);
122 : }
123 : }
124 :
125 :
126 : enum GNUNET_DB_QueryStatus
127 1 : TALER_MERCHANTDB_iterate_reconciliation_details (
128 : struct TALER_MERCHANTDB_PostgresContext *pg,
129 : const char *instance_id,
130 : uint64_t expected_incoming_serial,
131 : TALER_MERCHANTDB_ReconciliationDetailsCallback cb,
132 : void *cb_cls)
133 : {
134 1 : struct ReconciliationContext lic = {
135 : .cb = cb,
136 : .cb_cls = cb_cls,
137 : .pg = pg
138 : };
139 1 : struct GNUNET_PQ_QueryParam params[] = {
140 1 : GNUNET_PQ_query_param_uint64 (&expected_incoming_serial),
141 : GNUNET_PQ_query_param_end
142 : };
143 : enum GNUNET_DB_QueryStatus qs;
144 :
145 1 : GNUNET_assert (NULL != pg->current_merchant_id);
146 1 : GNUNET_assert (0 == strcmp (instance_id,
147 : pg->current_merchant_id));
148 1 : TMH_PQ_prepare_anon (pg,
149 : "SELECT"
150 : " mct.order_id"
151 : ",SUM((etc.exchange_deposit_value).val)::INT8 AS deposit_value_sum"
152 : ",SUM((etc.exchange_deposit_value).frac)::INT8 AS deposit_frac_sum"
153 : ",SUM((etc.exchange_deposit_fee).val)::INT8 AS fee_value_sum"
154 : ",SUM((etc.exchange_deposit_fee).frac)::INT8 AS fee_frac_sum"
155 : ",(etc.exchange_deposit_value).curr AS currency"
156 : " FROM merchant_expected_transfer_to_coin etc"
157 : " JOIN merchant_deposits md"
158 : " USING (deposit_serial)"
159 : " JOIN merchant_deposit_confirmations mdc"
160 : " USING (deposit_confirmation_serial)"
161 : " JOIN merchant_contract_terms mct"
162 : " USING (order_serial)"
163 : " WHERE expected_credit_serial=$1"
164 : " GROUP BY mct.order_id, (etc.exchange_deposit_value).curr;");
165 1 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
166 : "",
167 : params,
168 : &reconciliation_cb,
169 : &lic);
170 1 : if (0 > lic.qs)
171 0 : return lic.qs;
172 1 : return qs;
173 : }
|