[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-merchant] 91/277: implement GET /orders/ID
From: |
gnunet |
Subject: |
[taler-merchant] 91/277: implement GET /orders/ID |
Date: |
Sun, 05 Jul 2020 20:50:04 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository merchant.
commit 9d33dde616b0d227b76e9692304cdb22507c72bc
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Tue May 5 15:03:47 2020 +0200
implement GET /orders/ID
---
src/backend/Makefile.am | 2 +
src/backend/legacy.c | 67 ----
src/backend/taler-merchant-httpd.c | 9 +
src/backend/taler-merchant-httpd_get-orders-ID.c | 409 ++++++++++++-----------
src/backenddb/merchant-0001.sql | 3 +
src/backenddb/plugin_merchantdb_postgres.c | 9 +-
src/include/taler_merchantdb_plugin.h | 108 +++++-
7 files changed, 331 insertions(+), 276 deletions(-)
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 049e0f4..55029b0 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -22,6 +22,8 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_auditors.c taler-merchant-httpd_auditors.h \
taler-merchant-httpd_config.c taler-merchant-httpd_config.h \
taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \
+ taler-merchant-httpd_get-orders-ID.c \
+ taler-merchant-httpd_get-orders-ID.h \
taler-merchant-httpd_mhd.c taler-merchant-httpd_mhd.h \
taler-merchant-httpd_private-delete-instances-ID.c \
taler-merchant-httpd_private-delete-instances-ID.h \
diff --git a/src/backend/legacy.c b/src/backend/legacy.c
index c105ecb..2fb7baa 100644
--- a/src/backend/legacy.c
+++ b/src/backend/legacy.c
@@ -1,70 +1,3 @@
-/**
- * Create a taler://pay/ URI for the given @a con and @a order_id
- * and @a session_id and @a instance_id.
- *
- * @param con HTTP connection
- * @param order_id the order id
- * @param session_id session, may be NULL
- * @param instance_id instance, may be "default"
- * @return corresponding taler://pay/ URI, or NULL on missing "host"
- */
-char *
-TMH_make_taler_pay_uri (struct MHD_Connection *con,
- const char *order_id,
- const char *session_id,
- const char *instance_id)
-{
- const char *host;
- const char *forwarded_host;
- const char *uri_path;
- const char *uri_instance_id;
- const char *query;
- char *result;
-
- host = MHD_lookup_connection_value (con,
- MHD_HEADER_KIND,
- "Host");
- forwarded_host = MHD_lookup_connection_value (con,
- MHD_HEADER_KIND,
- "X-Forwarded-Host");
-
- uri_path = MHD_lookup_connection_value (con,
- MHD_HEADER_KIND,
- "X-Forwarded-Prefix");
- if (NULL == uri_path)
- uri_path = "-";
- if (NULL != forwarded_host)
- host = forwarded_host;
- if (0 == strcmp (instance_id,
- "default"))
- uri_instance_id = "-";
- else
- uri_instance_id = instance_id;
- if (NULL == host)
- {
- /* Should never happen, at least the host header should be defined */
- GNUNET_break (0);
- return NULL;
- }
-
- if (GNUNET_YES == TALER_mhd_is_https (con))
- query = "";
- else
- query = "?insecure=1";
- GNUNET_assert (NULL != order_id);
- GNUNET_assert (0 < GNUNET_asprintf (&result,
- "taler://pay/%s/%s/%s/%s%s%s%s",
- host,
- uri_path,
- uri_instance_id,
- order_id,
- (NULL == session_id) ? "" : "/",
- (NULL == session_id) ? "" : session_id,
- query));
- return result;
-}
-
-
/**
* Closure for the #wireformat_iterator_cb().
*/
diff --git a/src/backend/taler-merchant-httpd.c
b/src/backend/taler-merchant-httpd.c
index 27541b5..4744347 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -27,6 +27,7 @@
#include "taler-merchant-httpd_auditors.h"
#include "taler-merchant-httpd_config.h"
#include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_get-orders-ID.h"
#include "taler-merchant-httpd_mhd.h"
#include "taler-merchant-httpd_private-delete-instances-ID.h"
#include "taler-merchant-httpd_private-delete-products-ID.h"
@@ -36,6 +37,7 @@
#include "taler-merchant-httpd_private-get-products.h"
#include "taler-merchant-httpd_private-get-products-ID.h"
#include "taler-merchant-httpd_private-get-orders.h"
+// #include "taler-merchant-httpd_private-get-orders-ID.h"
#include "taler-merchant-httpd_private-patch-instances-ID.h"
#include "taler-merchant-httpd_private-patch-products-ID.h"
#include "taler-merchant-httpd_private-post-instances.h"
@@ -879,6 +881,13 @@ url_handler (void *cls,
.method = MHD_HTTP_METHOD_POST,
.handler = &TMH_post_orders_ID_pay
},
+ /* GET /orders/$ID: */
+ {
+ .url_prefix = "/orders/",
+ .method = MHD_HTTP_METHOD_GET,
+ .have_id_segment = true,
+ .handler = &TMH_get_orders_ID
+ },
{
NULL
}
diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.c
b/src/backend/taler-merchant-httpd_get-orders-ID.c
index ba0d354..0fae0a9 100644
--- a/src/backend/taler-merchant-httpd_get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_get-orders-ID.c
@@ -24,9 +24,8 @@
#include <taler/taler_signatures.h>
#include <taler/taler_json_lib.h>
#include <taler/taler_exchange_service.h>
-#include "taler-merchant-httpd.h"
#include "taler-merchant-httpd_exchanges.h"
-#include "taler-merchant-httpd_refund.h"
+#include "taler-merchant-httpd_get-orders-ID.h"
/**
* How often do we retry DB transactions on serialization failures?
@@ -69,6 +68,12 @@ struct CoinRefund
*/
char *exchange_url;
+ /**
+ * Fully reply from the exchange, only possibly set if
+ * we got a JSON reply and a non-#MHD_HTTP_OK error code
+ */
+ json_t *exchange_reply;
+
/**
* Coin to refund.
*/
@@ -80,14 +85,14 @@ struct CoinRefund
uint64_t rtransaction_id;
/**
- * Amount to refund.
+ * Unique serial number identifying the refund.
*/
- struct TALER_Amount refund_amount;
+ uint64_t refund_serial;
/**
- * Applicable refund transaction fee.
+ * Amount to refund.
*/
- struct TALER_Amount refund_fee;
+ struct TALER_Amount refund_amount;
/**
* Public key of the exchange affirming the refund.
@@ -110,12 +115,6 @@ struct CoinRefund
*/
enum TALER_ErrorCode exchange_code;
- /**
- * Fully reply from the exchange, only possibly set if
- * we got a JSON reply and a non-#MHD_HTTP_OK error code
- */
- json_t *exchange_reply;
-
};
@@ -141,19 +140,19 @@ struct GetOrderData
struct GetOrderData *prev;
/**
- * Context of the request.
+ * Refunds for this order. Head of DLL.
*/
- struct TMH_HandlerContext *hc;
+ struct CoinRefund *cr_head;
/**
- * Did we suspend @a connection?
+ * Refunds for this order. Tail of DLL.
*/
- int suspended;
+ struct CoinRefund *cr_tail;
/**
- * Return code: #TALER_EC_NONE if successful.
+ * Context of the request.
*/
- enum TALER_ErrorCode ec;
+ struct TMH_HandlerContext *hc;
/**
* Entry in the #resume_timeout_heap for this check payment, if we are
@@ -166,11 +165,6 @@ struct GetOrderData
*/
struct MerchantInstance *mi;
- /**
- * URL where the final contract can be found for this payment.
- */
- char *final_contract_url;
-
/**
* order ID for the payment
*/
@@ -198,18 +192,22 @@ struct GetOrderData
*/
json_t *contract_terms;
- /**
- * Hash of @e contract_terms, set only once @e contract_terms
- * is available.
- */
- struct GNUNET_HashCode h_contract_terms;
-
/**
* Total refunds granted for this payment. Only initialized
* if @e refunded is set to true.
*/
struct TALER_Amount refund_amount;
+ /**
+ * Did we suspend @a connection?
+ */
+ int suspended;
+
+ /**
+ * Return code: #TALER_EC_NONE if successful.
+ */
+ enum TALER_ErrorCode ec;
+
/**
* Set to true if this payment has been refunded and
* @e refund_amount is initialized.
@@ -227,14 +225,14 @@ struct GetOrderData
/**
- * HEad of DLL of (suspended) requests.
+ * Head of DLL of (suspended) requests.
*/
-static struct GetOrderData *prd_head;
+static struct GetOrderData *god_head;
/**
* Tail of DLL of (suspended) requests.
*/
-static struct GetOrderData *prd_tail;
+static struct GetOrderData *god_tail;
/**
@@ -252,15 +250,105 @@ TMH_force_wallet_get_order_resume (void)
god);
GNUNET_assert (god->suspended);
god->suspended = GNUNET_NO;
- MHD_resume_connection (god->connection);
+ MHD_resume_connection (god->sc.con);
}
}
+/**
+ * Suspend this @a god until the trigger is satisfied.
+ *
+ * @param god request to suspend
+ */
+static void
+suspend_god (struct GetOrderData *god)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Suspending GET /orders/%s\n",
+ god->order_id);
+ TMH_long_poll_suspend (god->order_id,
+ god->hc->instance,
+ &god->sc,
+ (god->sc.awaiting_refund)
+ ? &god->sc.refund_expected
+ : NULL);
+}
+
+
+/**
+ * Create a taler://pay/ URI for the given @a con and @a order_id
+ * and @a session_id and @a instance_id.
+ *
+ * @param con HTTP connection
+ * @param order_id the order id
+ * @param session_id session, may be NULL
+ * @param instance_id instance, may be "default"
+ * @return corresponding taler://pay/ URI, or NULL on missing "host"
+ */
+char *
+TMH_make_taler_pay_uri (struct MHD_Connection *con,
+ const char *order_id,
+ const char *session_id,
+ const char *instance_id)
+{
+ const char *host;
+ const char *forwarded_host;
+ const char *uri_path;
+ const char *uri_instance_id;
+ const char *query;
+ char *result;
+
+ host = MHD_lookup_connection_value (con,
+ MHD_HEADER_KIND,
+ "Host");
+ forwarded_host = MHD_lookup_connection_value (con,
+ MHD_HEADER_KIND,
+ "X-Forwarded-Host");
+
+ uri_path = MHD_lookup_connection_value (con,
+ MHD_HEADER_KIND,
+ "X-Forwarded-Prefix");
+ if (NULL == uri_path)
+ uri_path = "-";
+ if (NULL != forwarded_host)
+ host = forwarded_host;
+ if (0 == strcmp (instance_id,
+ "default"))
+ uri_instance_id = "-";
+ else
+ uri_instance_id = instance_id;
+ if (NULL == host)
+ {
+ /* Should never happen, at least the host header should be defined */
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ if (GNUNET_YES == TALER_mhd_is_https (con))
+ query = "";
+ else
+ query = "?insecure=1";
+ GNUNET_assert (NULL != order_id);
+ GNUNET_assert (0 < GNUNET_asprintf (&result,
+ "taler://pay/%s/%s/%s/%s%s%s%s",
+ host,
+ uri_path,
+ uri_instance_id,
+ order_id,
+ (NULL == session_id) ? "" : "/",
+ (NULL == session_id) ? "" : session_id,
+ query));
+ return result;
+}
+
+
/**
* The client did not yet pay, send it the payment request.
*
* @param god check pay request context
+ * @param already_paid_order_id if for the fulfillment URI there is
+ * already a paid order, this is the order ID to redirect
+ * the wallet to; NULL if not applicable
* @return #MHD_YES on success
*/
static MHD_RESULT
@@ -287,13 +375,12 @@ send_pay_request (struct GetOrderData *god,
taler_pay_uri = TMH_make_taler_pay_uri (god->sc.con,
god->order_id,
god->session_id,
- god->mi->id);
+ god->hc->instance->settings.id);
ret = TALER_MHD_reply_json_pack (god->sc.con,
MHD_HTTP_OK,
- "{s:s, s:s, s:b, s:s?}",
+ "{s:s, s:b, s:s?}",
"taler_pay_uri", taler_pay_uri,
- "contract_url", god->final_contract_url,
- "paid", 0,
+ "paid", false,
"already_paid_order_id",
already_paid_order_id);
GNUNET_free (taler_pay_uri);
@@ -305,25 +392,20 @@ send_pay_request (struct GetOrderData *god,
* Check if @a god has sub-activities still pending.
*
* @param god request to check
- * @return #GNUNET_YES if activities are still pending
+ * @return true if activities are still pending
*/
-static int
+static bool
god_pending (struct GetOrderData *god)
{
- int pending = GNUNET_NO;
-
for (struct CoinRefund *cr = god->cr_head;
NULL != cr;
cr = cr->next)
{
if ( (NULL != cr->fo) ||
(NULL != cr->rh) )
- {
- pending = GNUNET_YES;
- break;
- }
+ return true;
}
- return pending;
+ return false;
}
@@ -342,7 +424,7 @@ check_resume_god (struct GetOrderData *god)
god);
GNUNET_assert (god->suspended);
god->suspended = GNUNET_NO;
- MHD_resume_connection (god->connection);
+ MHD_resume_connection (god->sc.con);
TMH_trigger_daemon ();
}
@@ -381,13 +463,10 @@ refund_cb (void *cls,
cr->exchange_pub = *exchange_pub;
cr->exchange_sig = *exchange_sig;
- qs = db->put_refund_proof (db->cls,
- &cr->god->merchant->pubkey,
- &cr->god->h_contract_terms,
- &cr->coin_pub,
- cr->rtransaction_id,
- exchange_pub,
- exchange_sig);
+ qs = TMH_db->insert_refund_proof (TMH_db->cls,
+ cr->refund_serial,
+ exchange_sig,
+ exchange_pub);
if (0 >= qs)
{
/* generally, this is relatively harmless for the merchant, but let's at
@@ -425,11 +504,10 @@ exchange_found_cb (void *cls,
{
cr->rh = TALER_EXCHANGE_refund (eh,
&cr->refund_amount,
- &cr->refund_fee,
&cr->god->h_contract_terms,
&cr->coin_pub,
cr->rtransaction_id,
- &cr->god->merchant->privkey,
+ &cr->god->hc->instance->merchant_priv,
&refund_cb,
cr);
return;
@@ -442,25 +520,27 @@ exchange_found_cb (void *cls,
/**
- * Function called with information about a refund.
+ * Function called with detailed information about a refund.
* It is responsible for packing up the data to return.
*
* @param cls closure
+ * @param refund_serial unique serial number of the refund
+ * @param timestamp time of the refund (for grouping of refunds in the wallet
UI)
* @param coin_pub public coin from which the refund comes from
* @param exchange_url URL of the exchange that issued @a coin_pub
* @param rtransaction_id identificator of the refund
* @param reason human-readable explanation of the refund
* @param refund_amount refund amount which is being taken from @a coin_pub
- * @param refund_fee cost of this refund operation
*/
static void
process_refunds_cb (void *cls,
+ uint64_t refund_serial,
+ struct GNUNET_TIME_Absolute timestamp,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const char *exchange_url,
uint64_t rtransaction_id,
const char *reason,
- const struct TALER_Amount *refund_amount,
- const struct TALER_Amount *refund_fee)
+ const struct TALER_Amount *refund_amount)
{
struct GetOrderData *god = cls;
struct CoinRefund *cr;
@@ -471,12 +551,12 @@ process_refunds_cb (void *cls,
TALER_amount2s (refund_amount),
reason);
cr = GNUNET_new (struct CoinRefund);
+ cr->refund_serial = refund_serial;
cr->exchange_url = GNUNET_strdup (exchange_url);
cr->god = god;
cr->coin_pub = *coin_pub;
cr->rtransaction_id = rtransaction_id;
cr->refund_amount = *refund_amount;
- cr->refund_fee = *refund_fee;
GNUNET_CONTAINER_DLL_insert (god->cr_head,
god->cr_tail,
cr);
@@ -493,27 +573,6 @@ process_refunds_cb (void *cls,
}
-/**
- * Suspend this @a god until the trigger is satisfied.
- *
- * @param ppr
- */
-static void
-suspend_god (struct GetOrderData *god)
-{
- TMH_compute_pay_key (god->order_id,
- &god->mi->pubkey,
- &god->sc.key);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Suspending /poll-payment on key %s\n",
- GNUNET_h2s (&god->sc.key));
- TMH_long_poll_suspend (&god->sc,
- (god->sc.awaiting_refund)
- ? &god->sc.refund_expected
- : NULL);
-}
-
-
/**
* Clean up the session state for a GET /orders/$ID request.
*
@@ -523,6 +582,7 @@ static void
god_cleanup (void *cls)
{
struct GetOrderData *god = cls;
+ struct CoinRefund *cr;
while (NULL != (cr = god->cr_head))
{
@@ -550,7 +610,6 @@ god_cleanup (void *cls)
if (NULL != god->contract_terms)
json_decref (god->contract_terms);
- GNUNET_free_non_null (god->final_contract_url);
GNUNET_free (god);
}
@@ -576,10 +635,9 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
{
god = GNUNET_new (struct GetOrderData);
hc->ctx = god;
- god->hc.cc = &god_cleanup;
+ hc->cc = &god_cleanup;
god->sc.con = connection;
god->ec = TALER_EC_NONE;
- god->connection = connection;
god->hc = hc;
god->ret = GNUNET_SYSERR;
@@ -666,36 +724,16 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
}
}
- // FIXME: what is this about again???
- god->contract_url = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "contract_url");
- if (NULL == god->contract_url)
- {
- // FIXME: this can't be right anymore...
- god->final_contract_url = TALER_url_absolute_mhd (connection,
- "/public/proposal",
- "instance", mi->id,
- "order_id",
- god->order_id,
- NULL);
- GNUNET_assert (NULL != god->final_contract_url);
- }
- else
- {
- god->final_contract_url = GNUNET_strdup (god->contract_url);
- }
-
god->session_id = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"session_id");
- /* Convert order id to h_contract_terms */
- db->preflight (db->cls);
- qs = db->find_contract_terms (db->cls,
- hc->instance->settings.id,
- order_id,
- &god->contract_terms);
+ /* Convert order_id to h_contract_terms */
+ TMH_db->preflight (TMH_db->cls);
+ qs = TMH_db->lookup_contract_terms (TMH_db->cls,
+ hc->instance->settings.id,
+ order_id,
+ &god->contract_terms);
if (0 > qs)
{
/* single, read-only SQL statements should never cause
@@ -705,7 +743,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_REFUND_LOOKUP_DB_ERROR,
+ TALER_EC_GET_ORDERS_DB_LOOKUP_ERROR,
"database error looking up contract");
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
@@ -715,7 +753,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
order_id);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
- TALER_EC_ORDER_ID_UNKNOWN,
+ TALER_EC_GET_ORDERS_ID_UNKNOWN,
"order_id not found in database");
}
@@ -741,7 +779,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_FORBIDDEN,
- TALER_EC_WRONG_CONTRACT,
+ TALER_EC_GET_ORDERS_WRONG_CONTRACT,
"Contract hash does not match
order");
}
}
@@ -761,7 +799,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
GNUNET_break (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
+ TALER_EC_GET_ORDERS_DB_LOOKUP_ERROR,
"Merchant database error (contract
terms corrupted)");
}
}
@@ -773,11 +811,11 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
/* Check if paid within a session. */
char *already_paid_order_id = NULL;
- qs = db->find_session_info (db->cls,
- &already_paid_order_id,
- god->session_id,
- god->fulfillment_url,
- &mi->pubkey);
+ qs = TMH_db->lookup_order_by_fulfillment (TMH_db->cls,
+ hc->instance->settings.id,
+ god->fulfillment_url,
+ god->session_id,
+ &already_paid_order_id);
if (qs < 0)
{
/* single, read-only SQL statements should never cause
@@ -787,17 +825,21 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
+ TALER_EC_GET_ORDERS_DB_LOOKUP_ERROR,
"db error fetching pay session info");
}
- else if (0 == qs)
+ if (0 == qs)
{
+ MHD_RESULT ret;
+
ret = send_pay_request (god,
already_paid_order_id);
GNUNET_free_non_null (already_paid_order_id);
return ret;
}
GNUNET_break (1 == qs);
+ // FIXME: eh, what? shouldn't we be possibly REDIRECTING to
+ // already_paid_order_id?
GNUNET_break (0 == strcmp (order_id,
already_paid_order_id));
GNUNET_free_non_null (already_paid_order_id);
@@ -805,48 +847,47 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
else
{
/* Check if paid regardless of session. */
- json_t *xcontract_terms = NULL;
-
- qs = db->find_paid_contract_terms_from_hash (db->cls,
- &xcontract_terms,
- &god->h_contract_terms,
- &mi->pubkey);
- if (0 > qs)
+ struct GNUNET_HashCode h_contract;
+ bool paid;
+
+ qs = TMH_db->lookup_order_status (TMH_db->cls,
+ hc->instance->settings.id,
+ order_id,
+ &h_contract,
+ &paid);
+ if (0 >= qs)
{
/* Always report on hard error as well to enable diagnostics */
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
+ TALER_EC_GET_ORDERS_DB_LOOKUP_ERROR,
"Merchant database error");
}
- if (0 == qs)
+ GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
+ GNUNET_break (0 ==
+ GNUNET_memcmp (&h_contract,
+ &god->h_contract_terms));
+ if (! paid)
{
return send_pay_request (god,
NULL);
}
- GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
- GNUNET_assert (NULL != xcontract_terms);
- json_decref (xcontract_terms);
}
-
- for (unsigned int i = 0; i<MAX_RETRIES; i++)
- {
- qs = db->get_refunds_from_contract_terms_hash (db->cls,
- hc->instance->settings.id,
- &god->h_contract_terms,
- &process_refunds_cb,
- god);
- if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
- break;
- }
+ /* At this point, we know the contract was paid. Let's check for
+ refunds */
+ qs = TMH_db->lookup_refunds_detailed (TMH_db->cls,
+ hc->instance->settings.id,
+ &god->h_contract_terms,
+ &process_refunds_cb,
+ god);
if (0 > qs)
{
GNUNET_break (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_REFUND_LOOKUP_DB_ERROR,
+ TALER_EC_GET_ORDERS_DB_LOOKUP_ERROR,
"Failed to lookup refunds for
contract");
}
@@ -858,28 +899,37 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
{
enum GNUNET_DB_QueryStatus qs;
- qs = db->get_refund_proof (db->cls,
- &cr->god->merchant->pubkey,
- &cr->god->h_contract_terms,
- &cr->coin_pub,
- cr->rtransaction_id,
- &cr->exchange_pub,
- &cr->exchange_sig);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+ qs = TMH_db->lookup_refund_proof (TMH_db->cls,
+ cr->refund_serial,
+ &cr->exchange_sig,
+ &cr->exchange_pub);
+ switch (qs)
{
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GET_ORDERS_DB_LOOKUP_ERROR,
+ "Merchant database error");
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
/* We need to talk to the exchange */
cr->fo = TMH_EXCHANGES_find_exchange (cr->exchange_url,
NULL,
GNUNET_NO,
&exchange_found_cb,
cr);
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* We got a reply earlier, set status accordingly */
+ cr->exchange_status = MHD_HTTP_OK;
+ break;
}
}
- if ( (god->awaiting_refund) &&
+ if ( (god->sc.awaiting_refund) &&
( (! god->refunded) ||
(1 != TALER_amount_cmp (&god->refund_amount,
- &god->min_refund)) ) )
+ &god->sc.refund_expected)) ) )
{
/* Client is waiting for a refund larger than what we have, suspend
until timeout */
@@ -891,15 +941,14 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
/* yes, indeed suspend */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Awaiting refund exceeding %s\n",
- TALER_amount2s (&god->min_refund));
+ TALER_amount2s (&god->sc.refund_expected));
suspend_god (god);
return MHD_YES;
}
}
-
/* Check if there are still exchange operations pending */
- if (GNUNET_YES == god_pending (god))
+ if (god_pending (god))
{
if (! god->suspended)
{
@@ -928,14 +977,12 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
ra,
(MHD_HTTP_OK != cr->exchange_status)
? json_pack ((NULL != cr->exchange_reply)
- ? "{s:o,s:o,s:o,s:I,s:I,s:I,s:O}"
- : "{s:o,s:o,s:o,s:I,s:I:s:I}",
+ ? "{s:o,s:o,s:I,s:I,s:I,s:O}"
+ : "{s:o,s:o,s:I,s:I:s:I}",
"coin_pub",
GNUNET_JSON_from_data_auto (&cr->coin_pub),
"refund_amount",
TALER_JSON_from_amount (&cr->refund_amount),
- "refund_fee",
- TALER_JSON_from_amount (&cr->refund_fee),
"exchange_http_status",
(json_int_t) cr->exchange_status,
"rtransaction_id",
@@ -944,13 +991,11 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
(json_int_t) cr->exchange_code,
"exchange_reply",
cr->exchange_reply)
- : json_pack ("{s:o,s:o,s:o,s:I,s:I,s:o,s:o}",
+ : json_pack ("{s:o,s:o,s:I,s:I,s:o,s:o}",
"coin_pub",
GNUNET_JSON_from_data_auto (&cr->coin_pub),
"refund_amount",
TALER_JSON_from_amount (&cr->refund_amount),
- "refund_fee",
- TALER_JSON_from_amount (&cr->refund_fee),
"exchange_http_status",
(json_int_t) cr->exchange_status,
"rtransaction_id",
@@ -962,32 +1007,16 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
)));
}
- if (god->refunded)
- return TALER_MHD_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:b, s:b, s:o}",
- "paid", 1,
- "refunded", god->refunded,
- "refund_amount",
- TALER_JSON_from_amount (
- &god->refund_amount));
return TALER_MHD_reply_json_pack (connection,
MHD_HTTP_OK,
- "{s:b, s:b }",
- "paid", 1,
- "refunded", 0);
-
-
- return TALER_MHD_reply_json_pack (
- connection,
- MHD_HTTP_OK,
- "{s:o, s:o, s:o}",
- "refunds",
- ra,
- "merchant_pub",
- GNUNET_JSON_from_data_auto (&mi->pubkey),
- "h_contract_terms",
- GNUNET_JSON_from_data_auto (&god->h_contract_terms));
+ "{s:b, s:b, s:o, s:o}",
+ "paid", true,
+ "refunded", god->refunded,
+ "refund_amount",
+ TALER_JSON_from_amount (
+ &god->refund_amount),
+ "refunds",
+ ra);
}
}
diff --git a/src/backenddb/merchant-0001.sql b/src/backenddb/merchant-0001.sql
index 36eb67b..31903f8 100644
--- a/src/backenddb/merchant-0001.sql
+++ b/src/backenddb/merchant-0001.sql
@@ -313,6 +313,7 @@ CREATE TABLE IF NOT EXISTS merchant_refunds
,order_serial BIGINT NOT NULL
REFERENCES merchant_contract_terms (order_serial) ON DELETE CASCADE
,rtransaction_id BIGINT NOT NULL
+ ,refund_timestamp INT8 NOT NULL
,coin_pub BYTEA NOT NULL
,reason VARCHAR NOT NULL
,refund_amount_val INT8 NOT NULL
@@ -323,6 +324,8 @@ COMMENT ON TABLE merchant_deposits
IS 'Refunds approved by the merchant (backoffice) logic, excludes abort
refunds';
COMMENT ON COLUMN merchant_refunds.rtransaction_id
IS 'Needed for uniqueness in case a refund is increased for the same order';
+COMMENT ON COLUMN merchant_refunds.refund_timestamp
+ IS 'Needed for grouping of refunds in the wallet UI; has no semantics in the
protocol (only for UX), but should be from the time when the merchant
internally approved the refund';
CREATE INDEX IF NOT EXISTS merchant_refunds_by_coin_and_order
ON merchant_refunds
(coin_pub,order_serial);
diff --git a/src/backenddb/plugin_merchantdb_postgres.c
b/src/backenddb/plugin_merchantdb_postgres.c
index 784650a..f95f346 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -2158,7 +2158,10 @@ process_deposits_for_refund_cb (void *cls,
struct PostgresClosure *pg = ctx->pg;
struct TALER_Amount current_refund;
struct RefundCoinData rcd[GNUNET_NZL (num_results)];
+ struct GNUNET_TIME_Absolute now;
+ now = GNUNET_TIME_absolute_get ();
+ (void) GNUNET_TIME_round_abs (&now);
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (ctx->refund->currency,
¤t_refund));
@@ -2327,6 +2330,7 @@ process_deposits_for_refund_cb (void *cls,
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&rcd[i].order_serial),
GNUNET_PQ_query_param_uint64 (&rcd[i].max_rtransaction_id), /* already
inc'ed */
+ GNUNET_PQ_query_param_absolute_time (&now),
GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub),
GNUNET_PQ_query_param_string (ctx->reason),
TALER_PQ_query_param_amount (increment),
@@ -5604,13 +5608,14 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
"INSERT INTO merchant_refunds"
"(order_serial"
",rtransaction_id"
+ ",refund_timestamp"
",coin_pub"
",reason"
",refund_amount_val"
",refund_amount_frac"
") VALUES"
- "($1, $2, $3, $4, $5, $6)",
- 6),
+ "($1, $2, $3, $4, $5, $6, $7)",
+ 7),
/* for postgres_increase_refund() */
GNUNET_PQ_make_prepare ("find_deposits_for_refund",
"SELECT"
diff --git a/src/include/taler_merchantdb_plugin.h
b/src/include/taler_merchantdb_plugin.h
index a58cb7d..cefc373 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -335,6 +335,30 @@ typedef void
const struct TALER_Amount *refund_amount);
+/**
+ * Function called with detailed information about a refund.
+ *
+ * @param cls closure
+ * @param refund_serial unique serial number of the refund
+ * @param timestamp time of the refund (for grouping of refunds in the wallet
UI)
+ * @param coin_pub public coin from which the refund comes from
+ * @param exchange_url URL of the exchange that issued @a coin_pub
+ * @param rtransaction_id identificator of the refund
+ * @param reason human-readable explanation of the refund
+ * @param refund_amount refund amount which is being taken from @a coin_pub
+ */
+typedef void
+(*TALER_MERCHANTDB_RefundDetailCallback)(
+ void *cls,
+ uint64_t refund_serial,
+ struct GNUNET_TIME_Absolute timestamp,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *exchange_url,
+ uint64_t rtransaction_id,
+ const char *reason,
+ const struct TALER_Amount *refund_amount);
+
+
/**
* Results from trying to increase a refund.
*/
@@ -1100,45 +1124,95 @@ struct TALER_MERCHANTDB_Plugin
const char *reason);
- /* ****************** OLD API ******************** */
+ /**
+ * Obtain detailed refund data associated with a contract.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param instance_id instance to lookup refunds for
+ * @param h_contract_terms hash code of the contract
+ * @param rc function to call for each coin on which there is a refund
+ * @param rc_cls closure for @a rc
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*lookup_refunds_detailed)(void *cls,
+ const char *instance_id,
+ const struct GNUNET_HashCode *h_contract_terms,
+ TALER_MERCHANTDB_RefundDetailCallback rc,
+ void *rc_cls);
+
+ /**
+ * Insert refund proof data from the exchange into the database.
+ *
+ * @param cls closure
+ * @param refund_serial serial number of the refund
+ * @param exchange_sig signature from exchange that coin was refunded
+ * @param exchange_pub signing key that was used for @a exchange_sig
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*insert_refund_proof)(void *cls,
+ uint64_t refund_serial,
+ const struct TALER_ExchangeSignatureP *exchange_sig,
+ const struct TALER_ExchangePublicKeyP *exchange_pub);
/**
- * Store the order ID that was used to pay for a resource within a session.
+ * Lookup refund proof data.
*
* @param cls closure
- * @param session_id session id
- * @param fulfillment_url URL that canonically identifies the resource
- * being paid for
- * @param order_id the order ID that was used when paying for the resource
URL
- * @param merchant_pub public key of the merchant, identifying the instance
+ * @param refund_serial serial number of the refund
+ * @param[out] exchange_sig set to signature from exchange
+ * @param[out] exchange_pub signing key that was used for @a exchange_sig
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*insert_session_info)(void *cls,
- const char *session_id,
- const char *fulfillment_url,
- const char *order_id,
- const struct TALER_MerchantPublicKeyP *merchant_pub);
+ (*lookup_refund_proof)(void *cls,
+ uint64_t refund_serial,
+ struct TALER_ExchangeSignatureP *exchange_sig,
+ struct TALER_ExchangePublicKeyP *exchange_pub);
+
/**
* Retrieve the order ID that was used to pay for a resource within a
session.
*
* @param cls closure
+ * @param instance_id instance to lookup the order from
+ * @param fulfillment_url URL that canonically identifies the resource
+ * being paid for
+ * @param session_id session id
* @param[out] order_id location to store the order ID that was used when
* paying for the resource URL
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*lookup_order_by_fulfillment)(void *cls,
+ const char *instance_id,
+ const char *fulfillment_url,
+ const char *session_id,
+ char **order_id);
+
+
+ /* ****************** OLD API ******************** */
+
+
+ /**
+ * Store the order ID that was used to pay for a resource within a session.
+ *
+ * @param cls closure
* @param session_id session id
* @param fulfillment_url URL that canonically identifies the resource
* being paid for
+ * @param order_id the order ID that was used when paying for the resource
URL
* @param merchant_pub public key of the merchant, identifying the instance
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*find_session_info)(void *cls,
- char **order_id,
- const char *session_id,
- const char *fulfillment_url,
- const struct TALER_MerchantPublicKeyP *merchant_pub);
+ (*insert_session_info)(void *cls,
+ const char *session_id,
+ const char *fulfillment_url,
+ const char *order_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub);
/**
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-merchant] 82/277: implement abort client lib, (continued)
- [taler-merchant] 82/277: implement abort client lib, gnunet, 2020/07/05
- [taler-merchant] 87/277: revise GET /private/orders API, gnunet, 2020/07/05
- [taler-merchant] 86/277: GET /orders/ID API design, gnunet, 2020/07/05
- [taler-merchant] 88/277: fix benchmark FTBFS, gnunet, 2020/07/05
- [taler-merchant] 95/277: db work for POST /transfers, gnunet, 2020/07/05
- [taler-merchant] 96/277: fix FTBFS, gnunet, 2020/07/05
- [taler-merchant] 109/277: commentfix, gnunet, 2020/07/05
- [taler-merchant] 110/277: fix benchmark FTBFS, gnunet, 2020/07/05
- [taler-merchant] 116/277: fix test, gnunet, 2020/07/05
- [taler-merchant] 115/277: misc. fixes, gnunet, 2020/07/05
- [taler-merchant] 91/277: implement GET /orders/ID,
gnunet <=
- [taler-merchant] 101/277: more SQL, gnunet, 2020/07/05
- [taler-merchant] 104/277: GET /transfers implementation, gnunet, 2020/07/05
- [taler-merchant] 102/277: towards idempotency in POST /private/transfers, gnunet, 2020/07/05
- [taler-merchant] 103/277: towards GET /transfers, gnunet, 2020/07/05
- [taler-merchant] 114/277: fix sql, gnunet, 2020/07/05
- [taler-merchant] 119/277: better error handling, gnunet, 2020/07/05
- [taler-merchant] 117/277: get simple pay test to pass, gnunet, 2020/07/05
- [taler-merchant] 94/277: fix ftbfs, gnunet, 2020/07/05
- [taler-merchant] 98/277: implement POST /transfers, gnunet, 2020/07/05
- [taler-merchant] 107/277: implement GET /transfers, gnunet, 2020/07/05