gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant] branch master updated: add amount, summary, and refunda


From: gnunet
Subject: [taler-merchant] branch master updated: add amount, summary, and refundable to GET /private/orders
Date: Mon, 27 Jul 2020 22:02:29 +0200

This is an automated email from the git hooks/post-receive script.

jonathan-buchanan pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new d13adea  add amount, summary, and refundable to GET /private/orders
     new e53ea92  Merge branch 'master' of ssh://git.taler.net/merchant
d13adea is described below

commit d13adea86b74accb650cd9102698d8e2ddbf3849
Author: Jonathan Buchanan <jonathan.russ.buchanan@gmail.com>
AuthorDate: Mon Jul 27 16:00:32 2020 -0400

    add amount, summary, and refundable to GET /private/orders
---
 .../taler-merchant-httpd_private-get-orders.c      | 226 +++++++++++++++++----
 src/include/taler_merchant_service.h               |  15 ++
 src/lib/merchant_api_get_orders.c                  |   6 +
 src/testing/testing_api_cmd_get_orders.c           |  45 ++++
 4 files changed, 255 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 608d276..5907099 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);
+  }
 }
 
 
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index 189d314..8779f09 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -1233,6 +1233,21 @@ struct TALER_MERCHANT_OrderEntry
    */
   uint64_t order_serial;
 
+  /**
+   * The amount of the order.
+   */
+  struct TALER_Amount amount;
+
+  /**
+   * The summary of the order.
+   */
+  const char *summary;
+
+  /**
+   * Whether it is possible to refund a part of the order still.
+   */
+  bool refundable;
+
 };
 
 
diff --git a/src/lib/merchant_api_get_orders.c 
b/src/lib/merchant_api_get_orders.c
index 959493f..c958579 100644
--- a/src/lib/merchant_api_get_orders.c
+++ b/src/lib/merchant_api_get_orders.c
@@ -90,6 +90,12 @@ parse_orders (const json_t *ia,
                                      &ie->timestamp),
       GNUNET_JSON_spec_uint64 ("row_id",
                                &ie->order_serial),
+      TALER_JSON_spec_amount ("amount",
+                              &ie->amount),
+      GNUNET_JSON_spec_string ("summary",
+                               &ie->summary),
+      GNUNET_JSON_spec_bool ("refundable",
+                             &ie->refundable),
       GNUNET_JSON_spec_end ()
     };
 
diff --git a/src/testing/testing_api_cmd_get_orders.c 
b/src/testing/testing_api_cmd_get_orders.c
index db3e20a..2b9c762 100644
--- a/src/testing/testing_api_cmd_get_orders.c
+++ b/src/testing/testing_api_cmd_get_orders.c
@@ -130,6 +130,51 @@ get_orders_cb (void *cls,
           return;
         }
       }
+      {
+        const json_t *contract_terms;
+        struct TALER_Amount amount;
+        const char *summary;
+        struct GNUNET_JSON_Specification spec[] = {
+          GNUNET_JSON_spec_string ("summary",
+                                   &summary),
+          TALER_JSON_spec_amount ("amount",
+                                  &amount),
+          GNUNET_JSON_spec_end ()
+        };
+
+        if (GNUNET_OK !=
+            TALER_TESTING_get_trait_contract_terms (order_cmd,
+                                                    0,
+                                                    &contract_terms))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Could not fetch order contract terms\n");
+          TALER_TESTING_interpreter_fail (gos->is);
+          return;
+        }
+        if (GNUNET_OK !=
+            GNUNET_JSON_parse (contract_terms,
+                               spec,
+                               NULL, NULL))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Could not parse order contract terms\n");
+          TALER_TESTING_interpreter_fail (gos->is);
+          return;
+        }
+        if ((0 != strcmp (summary,
+                          orders[i].summary)) ||
+            (GNUNET_OK != TALER_amount_cmp_currency (&amount,
+                                                     &orders[i].amount)) ||
+            (0 != TALER_amount_cmp (&amount,
+                                    &orders[i].amount)))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Order summary and/or amount does not match\n");
+          TALER_TESTING_interpreter_fail (gos->is);
+          return;
+        }
+      }
     }
     break;
   default:

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]