summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_private-get-orders.c
diff options
context:
space:
mode:
authorJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2020-07-27 16:00:32 -0400
committerJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2020-07-27 16:00:32 -0400
commitd13adea86b74accb650cd9102698d8e2ddbf3849 (patch)
tree7f0dae30cf4ac52a44591fff99ced0fe4f309562 /src/backend/taler-merchant-httpd_private-get-orders.c
parent2809a8643ba5a9f1c2c8b85963a03814790159c7 (diff)
downloadmerchant-d13adea86b74accb650cd9102698d8e2ddbf3849.tar.gz
merchant-d13adea86b74accb650cd9102698d8e2ddbf3849.tar.bz2
merchant-d13adea86b74accb650cd9102698d8e2ddbf3849.zip
add amount, summary, and refundable to GET /private/orders
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-get-orders.c')
-rw-r--r--src/backend/taler-merchant-httpd_private-get-orders.c226
1 files changed, 189 insertions, 37 deletions
diff --git a/src/backend/taler-merchant-httpd_private-get-orders.c b/src/backend/taler-merchant-httpd_private-get-orders.c
index 608d276c..5907099e 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders.c
@@ -20,6 +20,29 @@
*/
#include "platform.h"
#include "taler-merchant-httpd_private-get-orders.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * Stores state for adding an order to the array for the response.
+ */
+struct AddOrderState
+{
+ /**
+ * The array of orders.
+ */
+ json_t *pa;
+
+ /**
+ * The name of the instance we are querying for.
+ */
+ const char *instance_id;
+
+ /**
+ * The result after adding the orders (0 for okay, anything else for an error).
+ */
+ int result;
+};
/**
@@ -61,10 +84,10 @@ struct TMH_PendingOrder
struct GNUNET_TIME_Absolute long_poll_timeout;
/**
- * Array where we append matching orders. Must be
+ * State for adding orders. The array `pa` must be
* json_decref()'ed when done with the `struct TMH_PendingOrder`!
*/
- json_t *pa;
+ struct AddOrderState *aos;
/**
* Filter to apply.
@@ -103,7 +126,7 @@ TMH_force_get_orders_resume (struct TMH_MerchantInstance *mi)
GNUNET_assert (po ==
GNUNET_CONTAINER_heap_remove_root (order_timeout_heap));
MHD_resume_connection (po->con);
- json_decref (po->pa);
+ json_decref (po->aos->pa);
GNUNET_free (po);
}
if (NULL != order_timeout_task)
@@ -155,7 +178,7 @@ order_timeout (void *cls)
GNUNET_CONTAINER_DLL_remove (mi->po_head,
mi->po_tail,
po);
- json_decref (po->pa);
+ json_decref (po->aos->pa);
MHD_resume_connection (po->con);
TMH_trigger_daemon (); /* we resumed, kick MHD */
GNUNET_free (po);
@@ -170,14 +193,47 @@ order_timeout (void *cls)
* Cleanup our "context", where we stored the JSON array
* we are building for the response.
*
- * @param ctx context to clean up, must be a `json_t *`
+ * @param ctx context to clean up, must be a `struct AddOrderState *`
*/
static void
-json_cleanup (void *ctx)
+cleanup (void *ctx)
{
- json_t *j = ctx;
+ struct AddOrderState *aos = ctx;
+ json_decref (aos->pa);
+ GNUNET_free (aos);
+}
+
- json_decref (j);
+/**
+ * Function called with information about a refund.
+ * It is responsible for summing up the refund amount.
+ *
+ * @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 timestamp when was the refund made
+ * @param refund_amount refund amount which is being taken from @a coin_pub
+ */
+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)
+{
+ struct TALER_Amount *total_refund_amount = cls;
+
+ GNUNET_assert (0 <=
+ TALER_amount_add (total_refund_amount,
+ total_refund_amount,
+ refund_amount));
}
@@ -195,19 +251,93 @@ add_order (void *cls,
uint64_t order_serial,
struct GNUNET_TIME_Absolute creation_time)
{
- json_t *pa = cls;
+ struct AddOrderState *aos = cls;
+ json_t *contract_terms;
+ enum GNUNET_DB_QueryStatus qs =
+ TMH_db->lookup_order (TMH_db->cls,
+ aos->instance_id,
+ order_id,
+ &contract_terms);
+ bool refundable = false;
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+ {
+ aos->result = 1;
+ json_decref (contract_terms);
+ return;
+ }
+
+ {
+ struct TALER_Amount order_amount;
+ struct GNUNET_TIME_Absolute rd;
+
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_HashCode h_contract_terms;
+
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount ("amount",
+ &order_amount),
+ GNUNET_JSON_spec_absolute_time ("refund_deadline",
+ &rd),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (contract_terms,
+ spec,
+ NULL, NULL))
+ {
+ aos->result = 1;
+ json_decref (contract_terms);
+ return;
+ }
+
+ if (now.abs_value_us <= rd.abs_value_us)
+ {
+ struct TALER_Amount refund_amount;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_contract_hash (contract_terms,
+ &h_contract_terms));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (TMH_currency,
+ &refund_amount));
+ qs = TMH_db->lookup_refunds_detailed (TMH_db->cls,
+ aos->instance_id,
+ &h_contract_terms,
+ &process_refunds_cb,
+ &refund_amount);
+ if (0 > qs)
+ {
+ aos->result = 1;
+ json_decref (contract_terms);
+ return;
+ }
+ if (0 < TALER_amount_cmp (&refund_amount,
+ &order_amount))
+ refundable = true;
+ }
+ }
GNUNET_assert (0 ==
json_array_append_new (
- pa,
+ aos->pa,
json_pack (
- "{s:s, s:I, s:o}",
+ "{s:s, s:I, s:o, s:O, s:O, s:b}",
"order_id",
order_id,
"row_id",
(json_int_t) order_serial,
"timestamp",
- GNUNET_JSON_from_time_abs (creation_time))));
+ GNUNET_JSON_from_time_abs (creation_time),
+ "amount",
+ json_object_get (contract_terms,
+ "amount"),
+ "summary",
+ json_object_get (contract_terms,
+ "summary"),
+ "refundable",
+ refundable)));
+ json_decref (contract_terms);
}
@@ -262,7 +392,7 @@ TMH_notify_order_change (struct TMH_MerchantInstance *mi,
continue;
po->of.delta++;
}
- add_order (po->pa,
+ add_order (po->aos,
order_id,
order_serial_id,
date);
@@ -273,7 +403,7 @@ TMH_notify_order_change (struct TMH_MerchantInstance *mi,
GNUNET_CONTAINER_heap_remove_node (po->hn));
MHD_resume_connection (po->con);
TMH_trigger_daemon (); /* we resumed, kick MHD */
- json_decref (po->pa);
+ json_decref (po->aos->pa);
GNUNET_free (po);
}
}
@@ -292,7 +422,7 @@ TMH_private_get_orders (const struct TMH_RequestHandler *rh,
struct MHD_Connection *connection,
struct TMH_HandlerContext *hc)
{
- json_t *pa;
+ struct AddOrderState *aos;
enum GNUNET_DB_QueryStatus qs;
struct TALER_MERCHANTDB_OrderFilter of;
@@ -300,10 +430,19 @@ TMH_private_get_orders (const struct TMH_RequestHandler *rh,
{
/* resumed from long-polling, return answer we already have
in 'hc->ctx' */
+ struct AddOrderState *aos = hc->ctx;
+ if (0 != aos->result)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_ORDERS_GET_DB_LOOKUP_ERROR,
+ "failed to lookup orders in database");
+ }
return TALER_MHD_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:O}",
- "orders", hc->ctx);
+ "orders", aos->pa);
}
if (! (TALER_arg_to_yna (connection,
@@ -437,21 +576,29 @@ TMH_private_get_orders (const struct TMH_RequestHandler *rh,
}
}
- pa = json_array ();
- GNUNET_assert (NULL != pa);
- qs = TMH_db->lookup_orders (TMH_db->cls,
- hc->instance->settings.id,
- &of,
- &add_order,
- pa);
- if (0 > qs)
+ aos = GNUNET_new (struct AddOrderState);
+ GNUNET_assert (NULL != aos);
+ aos->pa = json_array ();
+ aos->instance_id = hc->instance->settings.id;
+ aos->result = 0;
+ GNUNET_assert (NULL != aos->pa);
{
- GNUNET_break (0);
- json_decref (pa);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_ORDERS_GET_DB_LOOKUP_ERROR,
- "failed to lookup orders in database");
+ qs = TMH_db->lookup_orders (TMH_db->cls,
+ hc->instance->settings.id,
+ &of,
+ &add_order,
+ aos);
+ if ((0 > qs) ||
+ (0 != aos->result))
+ {
+ GNUNET_break (0);
+ json_decref (aos->pa);
+ GNUNET_free (aos);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_ORDERS_GET_DB_LOOKUP_ERROR,
+ "failed to lookup orders in database");
+ }
}
if ( (0 == qs) &&
(of.timeout.rel_value_us > 0) )
@@ -463,12 +610,13 @@ TMH_private_get_orders (const struct TMH_RequestHandler *rh,
if (NULL == order_timeout_heap)
order_timeout_heap
= GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
- hc->ctx = pa;
- hc->cc = &json_cleanup;
+ hc->ctx = aos;
+ hc->cc = &cleanup;
po = GNUNET_new (struct TMH_PendingOrder);
po->mi = mi;
po->con = connection;
- po->pa = json_incref (pa);
+ po->aos = aos;
+ json_incref (po->aos->pa);
po->hn = GNUNET_CONTAINER_heap_insert (order_timeout_heap,
po,
po->long_poll_timeout.abs_value_us);
@@ -487,10 +635,14 @@ TMH_private_get_orders (const struct TMH_RequestHandler *rh,
NULL);
return MHD_YES;
}
- return TALER_MHD_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "orders", pa);
+ {
+ json_t *pa = aos->pa;
+ GNUNET_free (aos);
+ return TALER_MHD_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "orders", pa);
+ }
}