gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] 180/277: more work on private-get-orders-ID


From: gnunet
Subject: [taler-merchant] 180/277: more work on private-get-orders-ID
Date: Sun, 05 Jul 2020 20:51:33 +0200

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

grothoff pushed a commit to branch master
in repository merchant.

commit ea5d4f680dd1394889e61adbb805d6d8decfe9e1
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Thu Jun 4 21:48:34 2020 +0200

    more work on private-get-orders-ID
---
 .../taler-merchant-httpd_private-get-orders-ID.c   | 399 +++++++++++++--------
 src/include/taler_merchantdb_plugin.h              |  67 ++++
 2 files changed, 322 insertions(+), 144 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.c 
b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
index 327ccf7..d4d2660 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
@@ -157,11 +157,33 @@ struct GetOrderRequestContext
    */
   json_t *wire_details;
 
+  /**
+   * Details about refunds, NULL if there are no refunds.
+   */
+  json_t *refund_details;
+
   /**
    * Hash over the @e contract_terms.
    */
   struct GNUNET_HashCode h_contract_terms;
 
+  /**
+   * Total amount the exchange deposited into our bank account
+   * (confirmed or unconfirmed), excluding fees.
+   */
+  struct TALER_Amount deposits_total;
+
+  /**
+   * Total value of the coins that the exchange deposited into our bank
+   * account (confirmed or unconfirmed), including deposit fees.
+   */
+  struct TALER_Amount value_total;
+
+  /**
+   * Total we were to be paid under the contract, excluding refunds.
+   */
+  struct TALER_Amount contract_amount;
+
   /**
    * Serial ID of the order.
    */
@@ -309,7 +331,7 @@ deposit_get_cb (void *cls,
     GNUNET_free (tq);
     return;
   }
-  else
+  else if (MHD_HTTP_OK == hr->http_status)
   {
     enum GNUNET_DB_QueryStatus qs;
 
@@ -324,6 +346,35 @@ deposit_get_cb (void *cls,
       GNUNET_free (tq);
       return;
     }
+    /* Compute total amount *wired* */
+    if (0 >
+        TALER_amount_add (&gorc->deposits_total,
+                          &gorc->deposits_total,
+                          &dd->coin_contribution))
+    {
+      gorc_resume (gorc,
+                   42, // FIXME: EC
+                   NULL);
+      GNUNET_free (tq);
+      return;
+    }
+    /* Compute total amount including deposit fees (so how much
+       of the total deposit was properly paid by the exchange) */
+    if (0 >
+        TALER_amount_add (&gorc->value_total,
+                          &gorc->value_total,
+                          &tq->coin_value))
+    {
+      gorc_resume (gorc,
+                   42, // FIXME: EC
+                   NULL);
+      GNUNET_free (tq);
+      return;
+    }
+  }
+  else
+  {
+    /* got a 'preliminary' reply from the exchange, simply skip */
   }
   GNUNET_free (tq);
   if (NULL != gorc->tq_head)
@@ -448,6 +499,10 @@ gorc_cleanup (void *cls)
 
   if (NULL != gorc->contract_terms)
     json_decref (gorc->contract_terms);
+  if (NULL != gorc->wire_details)
+    json_decref (gorc->wire_details);
+  if (NULL != gorc->refund_details)
+    json_decref (gorc->refund_details);
   GNUNET_assert (NULL == gorc->tt);
   GNUNET_assert (NULL == gorc->fo);
   GNUNET_free (gorc);
@@ -477,9 +532,18 @@ process_refunds_cb (void *cls,
 {
   struct GetOrderRequestContext *gorc = cls;
 
-  // FIXME: probably should do more here and compute
-  // an array with the details on the refunds with the reasons;
-  // FIXME: spec does NOT mandate that yet!
+  if (NULL == gorc->refund_details)
+  {
+    gorc->refund_details = json_array_new ();
+    GNUNET_assert (NULL != gorc->refund_details);
+  }
+  GNUNET_assert (0 ==
+                 json_array_append_new (json_pack ("{s:s}",
+                                                   "reason",
+                                                   reason)));
+  // FIXME: properly setup json_pack above
+  // with the details on the refund
+  // FIXME: update spec accordingly!
   if (gorc->refunded)
   {
     GNUNET_assert (0 <=
@@ -498,22 +562,29 @@ process_refunds_cb (void *cls,
  * the response.
  *
  * @param cls a `struct GetOrderRequestContext`
+ * @param wtid wire transfer subject of the wire transfer for the coin
+ * @param deposit_value contribution of the coin to the total wire transfer 
value
+ * @param deposit_fee deposit fee charged by the exchange for the coin
+ * @param transfer_confirmed did the merchant confirm that a wire transfer with
+ *        @a wtid over the total amount happened?
  */
 static void
-process_wire_details (void *cls,
-                      ...)
+process_transfer_details (void *cls,
+                          const struct TALER_WireTransferIdentifierRawP *wtid,
+                          const struct TALER_Amount *deposit_value,
+                          const struct TALER_Amount *deposit_fee,
+                          bool transfer_confirmed)
 {
   struct GetOrderRequestContext *gorc = cls;
   json_t *wire_details = gorc->wire_details;
 
-
   GNUNET_assert (0 ==
                  json_array_append_new (wire_details,
                                         json_pack ("{s:s, s:b}",
                                                    "blah",
-                                                   "stuff",
                                                    "FIXME",
-                                                   false)));
+                                                   "confirmed",
+                                                   transfer_confirmed)));
 }
 
 
@@ -533,6 +604,8 @@ TMH_private_get_orders_ID (const struct TMH_RequestHandler 
*rh,
 {
   struct GetOrderRequestContext *gorc = hc->ctx;
   enum GNUNET_DB_QueryStatus qs;
+  bool paid;
+  bool wired;
 
   if (NULL == gorc)
   {
@@ -621,11 +694,13 @@ TMH_private_get_orders_ID (const struct 
TMH_RequestHandler *rh,
                                          "Did not find order in DB");
     }
 
-    /* extract the fulfillment URL from the contract terms! */
+    /* extract the fulfillment URL and total amount from the contract terms! */
     {
       struct GNUNET_JSON_Specification spec[] = {
         GNUNET_JSON_spec_string ("fulfillment_url",
                                  &gorc->fulfillment_url),
+        TALER_JSON_spec_amount ("amount",
+                                &gorc->contract_amount),
         GNUNET_JSON_spec_end ()
       };
 
@@ -641,6 +716,7 @@ TMH_private_get_orders_ID (const struct TMH_RequestHandler 
*rh,
           TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
           "Merchant database error (contract terms corrupted)");
       }
+      // FIXME: sanity check on gorc->contract_amount.currency!
     }
     if (GNUNET_OK !=
         TALER_JSON_hash (gorc->contract_terms,
@@ -659,17 +735,32 @@ TMH_private_get_orders_ID (const struct 
TMH_RequestHandler *rh,
 
   GNUNET_assert (NULL != gorc->contract_terms);
 
+  TMH_db->preflight (TMH_db->cls);
+  qs = TMH_db->lookup_payment_status (TMH_db->cls,
+                                      gorc->order_serial,
+                                      gorc->session_id,
+                                      &paid,
+                                      &wired);
+  if (0 >= qs)
+  {
+    /* single, read-only SQL statements should never cause
+       serialization problems, and the entry should exist as per above */
+    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_PAYMENT_STATUS,
+                                       "DB error fetching payment status");
+  }
+  if (! paid)
   {
-    bool paid;
-    bool wired;
+    char *already_paid_order_id;
 
-    TMH_db->preflight (TMH_db->cls);
-    qs = TMH_db->lookup_payment_status (TMH_db->cls,
-                                        gorc->order_serial,
-                                        gorc->session_id,
-                                        &paid,
-                                        &wired);
-    if (0 >= qs)
+    qs = TMH_db->lookup_order_by_fulfillment (TMH_db->cls,
+                                              hc->instance->settings.id,
+                                              gorc->fulfillment_url,
+                                              gorc->session_id,
+                                              &already_paid_order_id);
+    if (0 > qs)
     {
       /* single, read-only SQL statements should never cause
          serialization problems, and the entry should exist as per above */
@@ -679,90 +770,10 @@ TMH_private_get_orders_ID (const struct 
TMH_RequestHandler *rh,
                                          
TALER_EC_CHECK_PAYMENT_DB_FETCH_PAYMENT_STATUS,
                                          "DB error fetching payment status");
     }
-    if (! paid)
-    {
-      char *already_paid_order_id;
-
-      qs = TMH_db->lookup_order_by_fulfillment (TMH_db->cls,
-                                                hc->instance->settings.id,
-                                                gorc->fulfillment_url,
-                                                gorc->session_id,
-                                                &already_paid_order_id);
-      if (0 > qs)
-      {
-        /* single, read-only SQL statements should never cause
-           serialization problems, and the entry should exist as per above */
-        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_PAYMENT_STATUS,
-                                           "DB error fetching payment status");
-      }
-      if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
-      {
-        /* User did pay for this order, but under a different session; ask 
wallet
-           to switch order ID */
-        char *taler_pay_uri;
-        MHD_RESULT ret;
-
-        taler_pay_uri = TMH_make_taler_pay_uri (connection,
-                                                hc->infix,
-                                                gorc->session_id,
-                                                hc->instance.settings->id);
-        ret = TALER_MHD_reply_json_pack (connection,
-                                         MHD_HTTP_OK,
-                                         "{s:s, s:b, s:s}",
-                                         "taler_pay_uri",
-                                         taler_pay_uri,
-                                         "paid",
-                                         false,
-                                         "already_paid_order_id",
-                                         already_paid_order_id);
-        GNUNET_free (taler_pay_uri);
-        GNUNET_free (already_paid_order_id);
-        return ret;
-      }
-    }
-
-    if (paid &&
-        (! wired) &&
-        gorc->transfer_status_requested)
+    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
     {
-      /* suspend connection, wait for exchange to check wire transfer status 
there */
-      gorc->transfer_status_requested = false; /* only try ONCE */
-      TMH_db->lookup_deposits (TMH_db->cls,
-                               gorc->order_serial,
-                               &deposit_cb,
-                               gorc);
-      if (NULL != gorc->tq)
-      {
-        GNUNET_CONTAINER_DLL_insert (gorc_head,
-                                     gorc_tail,
-                                     gorc);
-        gorc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT,
-                                                 &exchange_timeout_cb,
-                                                 gorc);
-        MHD_suspend_connection (connection);
-        return MHD_YES;
-      }
-    }
-
-    if ( (! paid) &&
-         (0 != gorc.sc.long_poll_timeout.abs_value_us) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Suspending GET /private/orders/%s\n",
-                  hc->infix);
-      TMH_long_poll_suspend (hc->infix,
-                             hc->instance,
-                             &gorc->sc,
-                             NULL);
-      return MHD_YES;
-    }
-
-    if (! paid)
-    {
-      /* User never paid for this order */
+      /* User did pay for this order, but under a different session; ask wallet
+         to switch order ID */
       char *taler_pay_uri;
       MHD_RESULT ret;
 
@@ -772,46 +783,111 @@ TMH_private_get_orders_ID (const struct 
TMH_RequestHandler *rh,
                                               hc->instance.settings->id);
       ret = TALER_MHD_reply_json_pack (connection,
                                        MHD_HTTP_OK,
-                                       "{s:s, s:b}",
+                                       "{s:s, s:b, s:s}",
                                        "taler_pay_uri",
                                        taler_pay_uri,
                                        "paid",
-                                       false);
+                                       false,
+                                       "already_paid_order_id",
+                                       already_paid_order_id);
       GNUNET_free (taler_pay_uri);
+      GNUNET_free (already_paid_order_id);
       return ret;
     }
+  }
 
-    /* Here we know the user DID pay, compute refunds... */
-
-    /* Accumulate refunds, if any. */
+  if (paid &&
+      (! wired) &&
+      gorc->transfer_status_requested)
+  {
+    /* suspend connection, wait for exchange to check wire transfer status 
there */
+    gorc->transfer_status_requested = false;   /* only try ONCE */
+    TMH_db->lookup_deposits (TMH_db->cls,
+                             gorc->order_serial,
+                             &deposit_cb,
+                             gorc);
+    if (NULL != gorc->tq)
     {
-
-      qs = TMH_db->lookup_refunds (TMH_db->cls,
-                                   hc->instance.settings->id,
-                                   &h_contract_terms,
-                                   &process_refunds_cb,
+      GNUNET_CONTAINER_DLL_insert (gorc_head,
+                                   gorc_tail,
                                    gorc);
+      gorc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT,
+                                               &exchange_timeout_cb,
+                                               gorc);
+      MHD_suspend_connection (connection);
+      return MHD_YES;
     }
-    if (0 > qs)
-    {
-      GNUNET_break (0);
-      return TALER_MHD_reply_with_error (connection,
-                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                         
TALER_EC_ORDERS_GET_DB_FETCH_TRANSACTION_ERROR,
-                                         "Merchant database error");
-    }
-  } /* end of scope of 'paid/wired' */
+  }
+
+  if ( (! paid) &&
+       (0 != gorc.sc.long_poll_timeout.abs_value_us) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Suspending GET /private/orders/%s\n",
+                hc->infix);
+    TMH_long_poll_suspend (hc->infix,
+                           hc->instance,
+                           &gorc->sc,
+                           NULL);
+    return MHD_YES;
+  }
+
+  if (! paid)
+  {
+    /* User never paid for this order */
+    char *taler_pay_uri;
+    MHD_RESULT ret;
+
+    taler_pay_uri = TMH_make_taler_pay_uri (connection,
+                                            hc->infix,
+                                            gorc->session_id,
+                                            hc->instance.settings->id);
+    ret = TALER_MHD_reply_json_pack (connection,
+                                     MHD_HTTP_OK,
+                                     "{s:s, s:b}",
+                                     "taler_pay_uri",
+                                     taler_pay_uri,
+                                     "paid",
+                                     false);
+    GNUNET_free (taler_pay_uri);
+    return ret;
+  }
+
+  /* Here we know the user DID pay, compute refunds... */
+
+  /* Accumulate refunds, if any. */
+  {
+
+    qs = TMH_db->lookup_refunds (TMH_db->cls,
+                                 hc->instance.settings->id,
+                                 &h_contract_terms,
+                                 &process_refunds_cb,
+                                 gorc);
+  }
+  if (0 > qs)
+  {
+    GNUNET_break (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       
TALER_EC_ORDERS_GET_DB_FETCH_TRANSACTION_ERROR,
+                                       "Merchant database error");
+  }
 
   /* Generate final reply, including wire details if we have them */
   {
+    MHD_RESULT ret;
+
     gorc->wire_details = json_array_new ();
     GNUNET_assert (NULL != gorc->wire_details);
-#if FIXME
-    qs = TMH_db->select_wire_details_by_order (TMH_db->cls,
-                                               gorc->order_serial,
-                                               &process_wire_details,
-                                               gorc);
-#endif
+    // FIXME: assert on return codes:
+    TALER_amount_get_zero (&gorc->value_total,
+                           TMH_currency);
+    TALER_amount_get_zero (&gorc->deposits_total,
+                           TMH_currency);
+    qs = TMH_db->lookup_transfer_details_by_order (TMH_db->cls,
+                                                   gorc->order_serial,
+                                                   &process_transfer_details,
+                                                   gorc);
     if (0 > qs)
     {
       GNUNET_break (0);
@@ -820,22 +896,57 @@ TMH_private_get_orders_ID (const struct 
TMH_RequestHandler *rh,
                                          
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
                                          "Merchant database error");
     }
-    // FIXME: also return gorc->ec/exchange_(hc,ec) codes!
-    return TALER_MHD_reply_json_pack (connection,
-                                      MHD_HTTP_OK,
-                                      "{s:O, s:b, s:b, s:o?, s:o?}",
-                                      "contract_terms",
-                                      gorc->contract_terms,
-                                      "paid",
-                                      true,
-                                      "refunded",
-                                      gorc->refunded,
-                                      "refund_amount",
-                                      (gorc->refunded)
-                                      ? TALER_JSON_from_amount (
-                                        &gorc->refund_amount)
-                                      : NULL,
-                                      "wire_details",
-                                      gorc->wire_details);
+
+    if (! wired)
+    {
+      /* we believe(d) the wire transfer did not happen yet, check if maybe
+         in light of new evidence it did */
+      struct TALER_Amount expect_total;
+
+      if (0 >
+          TALER_amount_subtract (&expect_total,
+                                 &gorc->contract_amount,
+                                 &gorc->refund_amount))
+      {
+        GNUNET_break (0);
+        return TALER_MHD_reply_with_error (connection,
+                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                           42, // FIXME: EC
+                                           "Inconsistent contract terms in 
DB");
+      }
+      if (0 >= // FIXME: right cmp?
+          TALER_amount_cmp (&expect_total,
+                            &gorc->value_total))
+      {
+        wired = true;
+        qs = TMH_db->mark_order_wired (TMH_db->cls,
+                                       gorc->order_serial);
+        GNUNET_break (qs >= 0); /* just warn if transaction failed */
+      }
+    }
+
+    // FIXME: also return gorc->ec/exchange_(hc,ec) codes
+    // and the gorc->value_total/deposits_total/etc.
+    ret = TALER_MHD_reply_json_pack (connection,
+                                     MHD_HTTP_OK,
+                                     "{s:O, s:b, s:b, s:o?, s:o?, s:o}",
+                                     "contract_terms",
+                                     gorc->contract_terms,
+                                     "paid",
+                                     true,
+                                     "refunded",
+                                     gorc->refunded,
+                                     "refund_amount",
+                                     (gorc->refunded)
+                                     ? TALER_JSON_from_amount (
+                                       &gorc->refund_amount)
+                                     : NULL,
+                                     "wire_details",
+                                     gorc->wire_details,
+                                     "refund_details",
+                                     gorc->refund_details);
+    gorc->wire_details = NULL;
+    gorc->refund_details = NULL;
+    return ret;
   }
 }
diff --git a/src/include/taler_merchantdb_plugin.h 
b/src/include/taler_merchantdb_plugin.h
index 1ca4f9a..e508f56 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -336,6 +336,26 @@ typedef void
   const struct TALER_Amount *refund_amount);
 
 
+/**
+ * Typically called by `lookup_transfer_details_by_order`.
+ * FIXME: not implemented yet!
+ *
+ * @param cls closure
+ * @param wtid wire transfer subject of the wire transfer for the coin
+ * @param deposit_value contribution of the coin to the total wire transfer 
value
+ * @param deposit_fee deposit fee charged by the exchange for the coin
+ * @param transfer_confirmed did the merchant confirm that a wire transfer with
+ *        @a wtid over the total amount happened?
+ */
+typedef void
+(*TALER_MERCHANTDB_OrderTransferDetailsCallback)(
+  void *cls,
+  const struct TALER_WireTransferIdentifierRawP *wtid,
+  const struct TALER_Amount *deposit_value,
+  const struct TALER_Amount *deposit_fee,
+  bool transfer_confirmed);
+
+
 /**
  * Function called with detailed information about a refund.
  *
@@ -1260,6 +1280,53 @@ struct TALER_MERCHANTDB_Plugin
                            bool *wired);
 
 
+  /**
+   * Retrieve wire transfer details for all deposits associated with
+   * a given @a order_serial.
+   * FIXME: not implemented yet!
+   *
+   * @param cls closure
+   * @param order_serial identifies the order
+   * @param cb function called with the wire transfer details
+   * @param cb_cls closure for @a cb
+   * @return transaction status
+   */
+  enum GNUNET_DB_QueryStatus
+  (*lookup_transfer_details_by_order)(
+    void *cls,
+    uint64_t order_serial,
+    TALER_MERCHANTDB_OrderTransferDetailsCallback cb,
+    void *cb_cls);
+
+
+  /**
+   * Insert wire transfer details for a deposit.
+   * FIXME: not implemented yet!
+   *
+   * @param cls closure
+   * @param deposit_serial serial number of the deposit
+   * @param dd deposit transfer data from the exchange to store
+   * @return transaction status
+   */
+  enum GNUNET_DB_QueryStatus
+  (*insert_deposit_to_transfer)(void *cls,
+                                uint64_t deposit_serial,
+                                const struct TALER_EXCHANGE_DepositData *dd);
+
+
+  /**
+   * Set 'wired' status for an order to 'true'.
+   * FIXME: not implemented yet!
+   *
+   * @param cls closure
+   * @param order_serial serial number of the order
+   * @return transaction status
+   */
+  enum GNUNET_DB_QueryStatus
+  (*mark_order_wired)(void *cls,
+                      uint64_t order_serial);
+
+
   /**
    * Function called when some backoffice staff decides to award or
    * increase the refund on an existing contract.  This function

-- 
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]