summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c')
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c220
1 files changed, 112 insertions, 108 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c b/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c
index 3953fa06..67e1410b 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2014-2021 Taler Systems SA
+ (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -26,6 +26,7 @@
#include <taler/taler_json_lib.h>
#include "taler-merchant-httpd_private-post-orders-ID-refund.h"
#include "taler-merchant-httpd_private-get-orders.h"
+#include "taler-merchant-httpd_helper.h"
/**
@@ -82,43 +83,21 @@ make_taler_refund_uri (struct MHD_Connection *connection,
const char *instance_id,
const char *order_id)
{
- const char *host;
- const char *forwarded_host;
- const char *uri_path;
- struct GNUNET_Buffer buf = { 0 };
+ struct GNUNET_Buffer buf;
GNUNET_assert (NULL != instance_id);
GNUNET_assert (NULL != order_id);
- host = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- "Host");
- forwarded_host = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- "X-Forwarded-Host");
- uri_path = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- "X-Forwarded-Prefix");
- if (NULL != forwarded_host)
- host = forwarded_host;
- if (NULL == host)
+ if (GNUNET_OK !=
+ TMH_taler_uri_by_connection (connection,
+ "refund",
+ instance_id,
+ &buf))
{
- /* Should never happen, at least the host header should be defined */
GNUNET_break (0);
return NULL;
}
- GNUNET_buffer_write_str (&buf, "taler");
- if (GNUNET_NO == TALER_mhd_is_https (connection))
- GNUNET_buffer_write_str (&buf, "+http");
- GNUNET_buffer_write_str (&buf, "://refund/");
- GNUNET_buffer_write_str (&buf, host);
- if (NULL != uri_path)
- GNUNET_buffer_write_path (&buf, uri_path);
- if (0 != strcmp ("default", instance_id))
- {
- GNUNET_buffer_write_path (&buf, "instances");
- GNUNET_buffer_write_path (&buf, instance_id);
- }
- GNUNET_buffer_write_path (&buf, order_id);
+ GNUNET_buffer_write_path (&buf,
+ order_id);
GNUNET_buffer_write_path (&buf,
""); /* Trailing slash */
return GNUNET_buffer_reap_str (&buf);
@@ -142,34 +121,70 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
struct TALER_Amount refund;
const char *reason;
struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount ("refund",
- TMH_currency,
- &refund),
+ TALER_JSON_spec_amount_any ("refund",
+ &refund),
GNUNET_JSON_spec_string ("reason",
&reason),
GNUNET_JSON_spec_end ()
};
enum TALER_MERCHANTDB_RefundStatus rs;
struct TALER_PrivateContractHashP h_contract;
+ json_t *contract_terms;
+ struct GNUNET_TIME_Timestamp timestamp;
+
+ {
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (connection,
+ hc->request_body,
+ spec);
+ if (GNUNET_OK != res)
+ {
+ return (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO;
+ }
+ }
{
enum GNUNET_DB_QueryStatus qs;
- json_t *contract_terms;
uint64_t order_serial;
struct GNUNET_TIME_Timestamp refund_deadline;
- struct GNUNET_TIME_Timestamp timestamp;
- bool paid = false;
qs = TMH_db->lookup_contract_terms (TMH_db->cls,
hc->instance->settings.id,
hc->infix,
&contract_terms,
&order_serial,
- &paid,
NULL);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
- struct GNUNET_JSON_Specification spec[] = {
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "lookup_contract_terms");
+ }
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
+ hc->infix);
+ }
+ if (GNUNET_OK !=
+ TALER_JSON_contract_hash (contract_terms,
+ &h_contract))
+ {
+ GNUNET_break (0);
+ json_decref (contract_terms);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
+ "Could not hash contract terms");
+ }
+ {
+ struct GNUNET_JSON_Specification cspec[] = {
GNUNET_JSON_spec_timestamp ("refund_deadline",
&refund_deadline),
GNUNET_JSON_spec_timestamp ("timestamp",
@@ -179,11 +194,10 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
if (GNUNET_YES !=
GNUNET_JSON_parse (contract_terms,
- spec,
+ cspec,
NULL, NULL))
{
GNUNET_break (0);
- GNUNET_JSON_parse_free (spec);
json_decref (contract_terms);
return TALER_MHD_reply_with_error (
connection,
@@ -191,12 +205,12 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
"mandatory fields missing");
}
- json_decref (contract_terms);
if (GNUNET_TIME_timestamp_cmp (timestamp,
==,
refund_deadline))
{
/* refund was never allowed, so we should refuse hard */
+ json_decref (contract_terms);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_FORBIDDEN,
@@ -210,25 +224,6 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
wire the funds, so we will try to give the refund anyway */
}
}
- else
- {
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
- hc->infix);
- }
- }
-
- {
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (connection,
- hc->request_body,
- spec);
- if (GNUNET_OK != res)
- return (GNUNET_NO == res)
- ? MHD_YES
- : MHD_NO;
}
TMH_db->preflight (TMH_db->cls);
@@ -239,6 +234,7 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
"increase refund"))
{
GNUNET_break (0);
+ json_decref (contract_terms);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_START_FAILED,
@@ -259,8 +255,41 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
if (TALER_MERCHANTDB_RS_SUCCESS == rs)
{
enum GNUNET_DB_QueryStatus qs;
+ json_t *rargs;
- qs = TMH_db->commit (TMH_db->cls);
+ rargs = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_timestamp ("timestamp",
+ timestamp),
+ GNUNET_JSON_pack_string ("order_id",
+ hc->infix),
+ GNUNET_JSON_pack_object_incref ("contract_terms",
+ contract_terms),
+ TALER_JSON_pack_amount ("refund_amount",
+ &refund),
+ GNUNET_JSON_pack_string ("reason",
+ reason)
+ );
+ GNUNET_assert (NULL != rargs);
+ qs = TMH_trigger_webhook (
+ hc->instance->settings.id,
+ "refund",
+ rargs);
+ json_decref (rargs);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ TMH_db->rollback (TMH_db->cls);
+ rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ TMH_db->rollback (TMH_db->cls);
+ continue;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ qs = TMH_db->commit (TMH_db->cls);
+ break;
+ }
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
{
GNUNET_break (0);
@@ -274,9 +303,18 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
}
break;
} /* retries loop */
+ json_decref (contract_terms);
switch (rs)
{
+ case TALER_MERCHANTDB_RS_BAD_CURRENCY:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Refund amount %s is not in the currency of the original payment\n",
+ TALER_amount2s (&refund));
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ "Order was paid in a different currency");
case TALER_MERCHANTDB_RS_TOO_HIGH:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Refusing refund amount %s that is larger than original payment\n",
@@ -292,53 +330,19 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
TALER_EC_GENERIC_DB_COMMIT_FAILED,
NULL);
case TALER_MERCHANTDB_RS_NO_SUCH_ORDER:
- {
- /* We know the order exists from the
- "lookup_contract_terms" at the beginning;
- so if we get 'no such order' here, it
- must be read as "no PAID order" */
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ID_REFUND_ORDER_UNPAID,
- hc->infix);
- }
+ /* We know the order exists from the
+ "lookup_contract_terms" at the beginning;
+ so if we get 'no such order' here, it
+ must be read as "no PAID order" */
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ID_REFUND_ORDER_UNPAID,
+ hc->infix);
case TALER_MERCHANTDB_RS_SUCCESS:
- {
- enum GNUNET_DB_QueryStatus qs;
- json_t *contract_terms;
- uint64_t order_serial;
- bool paid;
-
- qs = TMH_db->lookup_contract_terms (TMH_db->cls,
- hc->instance->settings.id,
- hc->infix,
- &contract_terms,
- &order_serial,
- &paid,
- NULL);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- {
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
- hc->infix);
- }
- if (GNUNET_OK !=
- TALER_JSON_contract_hash (contract_terms,
- &h_contract))
- {
- GNUNET_break (0);
- json_decref (contract_terms);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
- "Could not hash contract terms");
- }
- json_decref (contract_terms);
- }
+ /* continued below */
break;
- }
+ } /* end switch */
{
struct GNUNET_TIME_Timestamp timestamp;