merchant_api_post-private-orders-ORDER_ID-refund.c (7549B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-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 Lesser General Public License as published by the Free Software 7 Foundation; either version 2.1, 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 Lesser General Public License for more details. 12 13 You should have received a copy of the GNU Lesser General Public License along with 14 TALER; see the file COPYING.LGPL. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file merchant_api_post-private-orders-ORDER_ID-refund-new.c 19 * @brief Implementation of the POST /private/orders/$ORDER_ID/refund request 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include <curl/curl.h> 24 #include <jansson.h> 25 #include <microhttpd.h> /* just for HTTP status codes */ 26 #include <gnunet/gnunet_util_lib.h> 27 #include <gnunet/gnunet_curl_lib.h> 28 #include <taler/taler-merchant/post-private-orders-ORDER_ID-refund.h> 29 #include "merchant_api_curl_defaults.h" 30 #include "merchant_api_common.h" 31 #include <taler/taler_json_lib.h> 32 #include <taler/taler_curl_lib.h> 33 34 35 /** 36 * Handle for a POST /private/orders/$ORDER_ID/refund operation. 37 */ 38 struct TALER_MERCHANT_PostPrivateOrdersRefundHandle 39 { 40 /** 41 * Base URL of the merchant backend. 42 */ 43 char *base_url; 44 45 /** 46 * The full URL for this request. 47 */ 48 char *url; 49 50 /** 51 * Handle for the request. 52 */ 53 struct GNUNET_CURL_Job *job; 54 55 /** 56 * Function to call with the result. 57 */ 58 TALER_MERCHANT_PostPrivateOrdersRefundCallback cb; 59 60 /** 61 * Closure for @a cb. 62 */ 63 TALER_MERCHANT_POST_PRIVATE_ORDERS_REFUND_RESULT_CLOSURE *cb_cls; 64 65 /** 66 * Reference to the execution context. 67 */ 68 struct GNUNET_CURL_Context *ctx; 69 70 /** 71 * Minor context that holds body and headers. 72 */ 73 struct TALER_CURL_PostContext post_ctx; 74 75 /** 76 * Identifier of the order to refund. 77 */ 78 char *order_id; 79 80 /** 81 * Amount to refund. 82 */ 83 struct TALER_Amount refund; 84 85 /** 86 * Human-readable reason for the refund. 87 */ 88 char *reason; 89 }; 90 91 92 /** 93 * Function called when we're done processing the 94 * HTTP POST /private/orders/$ORDER_ID/refund request. 95 * 96 * @param cls the `struct TALER_MERCHANT_PostPrivateOrdersRefundHandle` 97 * @param response_code HTTP response code, 0 on error 98 * @param response response body, NULL if not in JSON 99 */ 100 static void 101 handle_refund_finished (void *cls, 102 long response_code, 103 const void *response) 104 { 105 struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *porh = cls; 106 const json_t *json = response; 107 struct TALER_MERCHANT_PostPrivateOrdersRefundResponse rr = { 108 .hr.http_status = (unsigned int) response_code, 109 .hr.reply = json 110 }; 111 112 porh->job = NULL; 113 switch (response_code) 114 { 115 case 0: 116 rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 117 break; 118 case MHD_HTTP_OK: 119 { 120 struct GNUNET_JSON_Specification spec[] = { 121 GNUNET_JSON_spec_string ( 122 "taler_refund_uri", 123 &rr.details.ok.taler_refund_uri), 124 GNUNET_JSON_spec_fixed_auto ( 125 "h_contract", 126 &rr.details.ok.h_contract), 127 GNUNET_JSON_spec_end () 128 }; 129 130 if (GNUNET_OK != 131 GNUNET_JSON_parse (json, 132 spec, 133 NULL, NULL)) 134 { 135 GNUNET_break_op (0); 136 rr.hr.http_status = 0; 137 rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 138 break; 139 } 140 break; 141 } 142 case MHD_HTTP_UNAUTHORIZED: 143 rr.hr.ec = TALER_JSON_get_error_code (json); 144 rr.hr.hint = TALER_JSON_get_error_hint (json); 145 break; 146 case MHD_HTTP_FORBIDDEN: 147 rr.hr.ec = TALER_JSON_get_error_code (json); 148 rr.hr.hint = TALER_JSON_get_error_hint (json); 149 break; 150 case MHD_HTTP_NOT_FOUND: 151 rr.hr.ec = TALER_JSON_get_error_code (json); 152 rr.hr.hint = TALER_JSON_get_error_hint (json); 153 break; 154 case MHD_HTTP_CONFLICT: 155 rr.hr.ec = TALER_JSON_get_error_code (json); 156 rr.hr.hint = TALER_JSON_get_error_hint (json); 157 break; 158 case MHD_HTTP_GONE: 159 rr.hr.ec = TALER_JSON_get_error_code (json); 160 rr.hr.hint = TALER_JSON_get_error_hint (json); 161 break; 162 case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: 163 rr.hr.ec = TALER_JSON_get_error_code (json); 164 rr.hr.hint = TALER_JSON_get_error_hint (json); 165 break; 166 default: 167 GNUNET_break_op (0); 168 TALER_MERCHANT_parse_error_details_ (json, 169 response_code, 170 &rr.hr); 171 break; 172 } 173 porh->cb (porh->cb_cls, 174 &rr); 175 TALER_MERCHANT_post_private_orders_refund_cancel (porh); 176 } 177 178 179 struct TALER_MERCHANT_PostPrivateOrdersRefundHandle * 180 TALER_MERCHANT_post_private_orders_refund_create ( 181 struct GNUNET_CURL_Context *ctx, 182 const char *url, 183 const char *order_id, 184 const struct TALER_Amount *refund, 185 const char *reason) 186 { 187 struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *porh; 188 189 porh = GNUNET_new (struct TALER_MERCHANT_PostPrivateOrdersRefundHandle); 190 porh->ctx = ctx; 191 porh->base_url = GNUNET_strdup (url); 192 porh->order_id = GNUNET_strdup (order_id); 193 porh->refund = *refund; 194 porh->reason = GNUNET_strdup (reason); 195 return porh; 196 } 197 198 199 enum TALER_ErrorCode 200 TALER_MERCHANT_post_private_orders_refund_start ( 201 struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *porh, 202 TALER_MERCHANT_PostPrivateOrdersRefundCallback cb, 203 TALER_MERCHANT_POST_PRIVATE_ORDERS_REFUND_RESULT_CLOSURE *cb_cls) 204 { 205 json_t *req_obj; 206 CURL *eh; 207 208 porh->cb = cb; 209 porh->cb_cls = cb_cls; 210 { 211 char *path; 212 213 GNUNET_asprintf (&path, 214 "private/orders/%s/refund", 215 porh->order_id); 216 porh->url = TALER_url_join (porh->base_url, 217 path, 218 NULL); 219 GNUNET_free (path); 220 } 221 if (NULL == porh->url) 222 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 223 req_obj = GNUNET_JSON_PACK ( 224 TALER_JSON_pack_amount ("refund", 225 &porh->refund), 226 GNUNET_JSON_pack_string ("reason", 227 porh->reason)); 228 eh = TALER_MERCHANT_curl_easy_get_ (porh->url); 229 if ( (NULL == eh) || 230 (GNUNET_OK != 231 TALER_curl_easy_post (&porh->post_ctx, 232 eh, 233 req_obj)) ) 234 { 235 GNUNET_break (0); 236 json_decref (req_obj); 237 if (NULL != eh) 238 curl_easy_cleanup (eh); 239 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 240 } 241 json_decref (req_obj); 242 porh->job = GNUNET_CURL_job_add2 (porh->ctx, 243 eh, 244 porh->post_ctx.headers, 245 &handle_refund_finished, 246 porh); 247 if (NULL == porh->job) 248 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 249 return TALER_EC_NONE; 250 } 251 252 253 void 254 TALER_MERCHANT_post_private_orders_refund_cancel ( 255 struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *porh) 256 { 257 if (NULL != porh->job) 258 { 259 GNUNET_CURL_job_cancel (porh->job); 260 porh->job = NULL; 261 } 262 TALER_curl_easy_post_finished (&porh->post_ctx); 263 GNUNET_free (porh->order_id); 264 GNUNET_free (porh->reason); 265 GNUNET_free (porh->url); 266 GNUNET_free (porh->base_url); 267 GNUNET_free (porh); 268 } 269 270 271 /* end of merchant_api_post-private-orders-ORDER_ID-refund-new.c */