Line data Source code
1 : /*
2 : This file is part of TALER
3 : (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 Affero 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/backend/taler-merchant-httpd_get-private-incoming-ID.c
18 : * @brief implement API for obtaining details about an expected incoming wire transfer
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <jansson.h>
23 : #include <taler/taler_json_lib.h>
24 : #include "taler-merchant-httpd_get-private-incoming-ID.h"
25 : #include "merchant-database/get_expected_transfer.h"
26 : #include "merchant-database/iterate_reconciliation_details.h"
27 : #include "merchant-database/get_exchange_wire_fee.h"
28 : #include "merchant-database/preflight.h"
29 :
30 :
31 : /**
32 : * Function called with information about orders aggregated into
33 : * a wire transfer.
34 : * Generate a response (array entry) based on the given arguments.
35 : *
36 : * @param cls closure with a `json_t *` array to build up the response
37 : * @param order_id ID of the order that was paid and aggregated
38 : * @param remaining_deposit deposited amount minus any refunds
39 : * @param deposit_fee deposit fees paid to the exchange for the order
40 : */
41 : static void
42 1 : reconciliation_cb (void *cls,
43 : const char *order_id,
44 : const struct TALER_Amount *remaining_deposit,
45 : const struct TALER_Amount *deposit_fee)
46 : {
47 1 : json_t *rd = cls;
48 : json_t *r;
49 :
50 1 : r = GNUNET_JSON_PACK (
51 : GNUNET_JSON_pack_string ("order_id",
52 : order_id),
53 : TALER_JSON_pack_amount ("remaining_deposit",
54 : remaining_deposit),
55 : TALER_JSON_pack_amount ("deposit_fee",
56 : deposit_fee));
57 1 : GNUNET_assert (0 ==
58 : json_array_append_new (rd,
59 : r));
60 1 : }
61 :
62 :
63 : enum MHD_Result
64 1 : TMH_private_get_incoming_ID (const struct TMH_RequestHandler *rh,
65 : struct MHD_Connection *connection,
66 : struct TMH_HandlerContext *hc)
67 : {
68 : unsigned long long serial_id;
69 : struct TALER_Amount wire_fee;
70 : bool no_fee;
71 : struct GNUNET_TIME_Timestamp expected_time;
72 : struct TALER_Amount expected_credit_amount;
73 : struct TALER_WireTransferIdentifierRawP wtid;
74 : struct TALER_FullPayto payto_uri;
75 1 : char *exchange_url = NULL;
76 : struct GNUNET_TIME_Timestamp execution_time;
77 : bool confirmed;
78 :
79 : {
80 : char dummy;
81 :
82 1 : if (1 !=
83 1 : sscanf (hc->infix,
84 : "%llu%c",
85 : &serial_id,
86 : &dummy))
87 : {
88 0 : GNUNET_break_op (0);
89 0 : return TALER_MHD_reply_with_error (
90 : connection,
91 : MHD_HTTP_BAD_REQUEST,
92 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
93 : "transfer ID must be a number");
94 : }
95 : }
96 :
97 1 : TALER_MERCHANTDB_preflight (TMH_db);
98 : {
99 : struct TALER_MasterPublicKeyP master_pub;
100 : enum GNUNET_DB_QueryStatus qs;
101 :
102 1 : qs = TALER_MERCHANTDB_get_expected_transfer (TMH_db,
103 1 : hc->instance->settings.id,
104 : serial_id,
105 : &expected_time,
106 : &expected_credit_amount,
107 : &wtid,
108 : &payto_uri,
109 : &exchange_url,
110 : &execution_time,
111 : &confirmed,
112 : &master_pub);
113 1 : if (0 > qs)
114 : {
115 : /* Simple select queries should not cause serialization issues */
116 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
117 : /* Always report on hard error as well to enable diagnostics */
118 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
119 0 : return TALER_MHD_reply_with_error (connection,
120 : MHD_HTTP_INTERNAL_SERVER_ERROR,
121 : TALER_EC_GENERIC_DB_FETCH_FAILED,
122 : "get_expected_transfer");
123 : }
124 1 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
125 : {
126 0 : GNUNET_break_op (0);
127 0 : return TALER_MHD_reply_with_error (
128 : connection,
129 : MHD_HTTP_NOT_FOUND,
130 : TALER_EC_MERCHANT_GENERIC_EXPECTED_TRANSFER_UNKNOWN,
131 0 : hc->infix);
132 : }
133 :
134 : {
135 : char *method;
136 : struct GNUNET_TIME_Timestamp start_date;
137 : struct GNUNET_TIME_Timestamp end_date;
138 : struct TALER_MasterSignatureP master_sig;
139 : struct TALER_WireFeeSet fees;
140 :
141 1 : method = TALER_payto_get_method (payto_uri.full_payto);
142 1 : qs = TALER_MERCHANTDB_get_exchange_wire_fee (
143 : TMH_db,
144 : &master_pub,
145 : method,
146 : expected_time,
147 : &fees,
148 : &start_date,
149 : &end_date,
150 : &master_sig);
151 1 : GNUNET_free (method);
152 1 : if (0 > qs)
153 : {
154 : /* Simple select queries should not cause serialization issues */
155 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
156 : /* Always report on hard error as well to enable diagnostics */
157 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
158 0 : GNUNET_free (exchange_url);
159 0 : GNUNET_free (payto_uri.full_payto);
160 0 : return TALER_MHD_reply_with_error (connection,
161 : MHD_HTTP_INTERNAL_SERVER_ERROR,
162 : TALER_EC_GENERIC_DB_FETCH_FAILED,
163 : "get_exchange_wire_fee");
164 : }
165 1 : no_fee = (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
166 1 : if (! no_fee)
167 1 : wire_fee = fees.wire;
168 : }
169 :
170 : }
171 :
172 : {
173 : enum GNUNET_DB_QueryStatus qs;
174 : json_t *rd;
175 : enum MHD_Result mret;
176 :
177 1 : rd = json_array ();
178 1 : GNUNET_assert (NULL != rd);
179 1 : qs = TALER_MERCHANTDB_iterate_reconciliation_details (TMH_db,
180 1 : hc->instance->settings.id,
181 : serial_id,
182 : &reconciliation_cb,
183 : rd);
184 1 : if (0 > qs)
185 : {
186 : /* Simple select queries should not cause serialization issues */
187 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
188 : /* Always report on hard error as well to enable diagnostics */
189 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
190 0 : GNUNET_free (exchange_url);
191 0 : GNUNET_free (payto_uri.full_payto);
192 0 : return TALER_MHD_reply_with_error (connection,
193 : MHD_HTTP_INTERNAL_SERVER_ERROR,
194 : TALER_EC_GENERIC_DB_FETCH_FAILED,
195 : "iterate_reconciliation_details");
196 : }
197 :
198 1 : mret = TALER_MHD_REPLY_JSON_PACK (
199 : connection,
200 : MHD_HTTP_OK,
201 : GNUNET_JSON_pack_allow_null (
202 : TALER_JSON_pack_amount (
203 : "expected_credit_amount",
204 : TALER_amount_is_valid (&expected_credit_amount)
205 : ? &expected_credit_amount
206 : : NULL)),
207 : GNUNET_JSON_pack_data_auto ("wtid",
208 : &wtid),
209 : TALER_JSON_pack_full_payto ("payto_uri",
210 : payto_uri),
211 : GNUNET_JSON_pack_string ("exchange_url",
212 : exchange_url),
213 : GNUNET_JSON_pack_bool ("confirmed",
214 : confirmed),
215 : GNUNET_JSON_pack_allow_null (
216 : GNUNET_JSON_pack_timestamp ("execution_time",
217 : execution_time)),
218 : GNUNET_JSON_pack_timestamp ("expected_time",
219 : expected_time),
220 : GNUNET_JSON_pack_allow_null (
221 : TALER_JSON_pack_amount ("wire_fee",
222 : no_fee ? NULL : &wire_fee)),
223 : GNUNET_JSON_pack_array_steal ("reconciliation_details",
224 : rd));
225 1 : GNUNET_free (exchange_url);
226 1 : GNUNET_free (payto_uri.full_payto);
227 1 : return mret;
228 : }
229 : }
230 :
231 :
232 : /* end of taler-merchant-httpd_get-private-incoming-ID.c */
|