diff options
author | Jonathan Buchanan <jonathan.russ.buchanan@gmail.com> | 2020-07-27 16:00:32 -0400 |
---|---|---|
committer | Jonathan Buchanan <jonathan.russ.buchanan@gmail.com> | 2020-07-27 16:00:32 -0400 |
commit | d13adea86b74accb650cd9102698d8e2ddbf3849 (patch) | |
tree | 7f0dae30cf4ac52a44591fff99ced0fe4f309562 /src/backend/taler-merchant-httpd_private-get-orders.c | |
parent | 2809a8643ba5a9f1c2c8b85963a03814790159c7 (diff) | |
download | merchant-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.c | 226 |
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); + } } |