summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_private-get-orders-ID.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-06-03 19:15:54 +0200
committerChristian Grothoff <christian@grothoff.org>2020-06-03 19:15:54 +0200
commit5e5fa7449c0343d644505d486cda2a2b10ed0b51 (patch)
treeeb0aa5dae44436e5a949a760c76421c7c07552b6 /src/backend/taler-merchant-httpd_private-get-orders-ID.c
parent2edb7ff575ec61fc570e80b6c492878c3bb97f70 (diff)
downloadmerchant-5e5fa7449c0343d644505d486cda2a2b10ed0b51.tar.gz
merchant-5e5fa7449c0343d644505d486cda2a2b10ed0b51.tar.bz2
merchant-5e5fa7449c0343d644505d486cda2a2b10ed0b51.zip
first high-level hack job at GET /orders/ID -- certainly FTBFS still
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-get-orders-ID.c')
-rw-r--r--src/backend/taler-merchant-httpd_private-get-orders-ID.c691
1 files changed, 261 insertions, 430 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 bb5384d1..e6d1825b 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2017, 2019 Taler Systems SA
+ (C) 2017, 2019, 2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -14,37 +14,22 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file backend/taler-merchant-httpd_check-payment.c
- * @brief implementation of /check-payment handler
+ * @file backend/taler-merchant-httpd_private-get-orders-ID.c
+ * @brief implementation of GET /private/orders/ID handler
* @author Florian Dold
* @author Christian Grothoff
*/
#include "platform.h"
-#include <string.h>
-#include <microhttpd.h>
-#include <jansson.h>
+#include "taler-merchant-httpd_private-get-orders-ID.h"
#include <taler/taler_json_lib.h>
-#include <taler/taler_signatures.h>
-#include "taler-merchant-httpd.h"
#include "taler-merchant-httpd_mhd.h"
-#include "taler-merchant-httpd_exchanges.h"
-#include "taler-merchant-httpd_check-payment.h"
-
-/**
- * Maximum number of retries for database operations.
- */
-#define MAX_RETRIES 5
/**
* Data structure we keep for a check payment request.
*/
-struct CheckPaymentRequestContext
+struct GetOrderRequestContext
{
- /**
- * Must be first for #handle_mhd_completion_callback.
- */
- struct TM_HandlerContext hc;
/**
* Entry in the #resume_timeout_heap for this check payment, if we are
@@ -55,22 +40,7 @@ struct CheckPaymentRequestContext
/**
* Which merchant instance is this for?
*/
- struct MerchantInstance *mi;
-
- /**
- * URL where the final contract can be found for this payment.
- */
- char *final_contract_url;
-
- /**
- * order ID for the payment
- */
- const char *order_id;
-
- /**
- * Where to get the contract
- */
- const char *contract_url;
+ struct TMH_HandlerContext *hc;
/**
* session of the client
@@ -78,8 +48,8 @@ struct CheckPaymentRequestContext
const char *session_id;
/**
- * fulfillment URL of the contract (valid as long as
- * @e contract_terms is valid).
+ * Fulfillment URL extracted from the contract. For repurchase detection.
+ * Only valid as long as @e contract_terms is valid!
*/
const char *fulfillment_url;
@@ -90,47 +60,44 @@ struct CheckPaymentRequestContext
json_t *contract_terms;
/**
- * Hash of @e contract_terms, set only once @e contract_terms
- * is available.
+ * Serial ID of the order.
*/
- struct GNUNET_HashCode h_contract_terms;
+ uint64_t order_serial;
/**
* Total refunds granted for this payment. Only initialized
- * if @e refunded is set to #GNUNET_YES.
+ * if @e refunded is set to true.
*/
struct TALER_Amount refund_amount;
/**
- * Set to #GNUNET_YES if this payment has been refunded and
+ * Set to true if this payment has been refunded and
* @e refund_amount is initialized.
*/
- int refunded;
+ bool refunded;
/**
- * Initially #GNUNET_SYSERR. If we queued a response, set to the
- * result code (i.e. #MHD_YES or #MHD_NO).
+ * Did the client request us to fetch the wire transfer status?
+ * If false, we may still return it if it is available.
*/
- int ret;
+ bool transfer_status_requested;
};
/**
- * Clean up the session state for a check payment request.
+ * Clean up the session state for a GET /private/order/ID request.
*
- * @param hc must be a `struct CheckPaymentRequestContext *`
+ * @param cls closure, must be a `struct GetOrderRequestContext *`
*/
static void
-cprc_cleanup (struct TM_HandlerContext *hc)
+gorc_cleanup (void *cls)
{
- struct CheckPaymentRequestContext *cprc = (struct
- CheckPaymentRequestContext *) hc;
+ struct GetOrderRequestContext *gorc = cls;
- if (NULL != cprc->contract_terms)
- json_decref (cprc->contract_terms);
- GNUNET_free_non_null (cprc->final_contract_url);
- GNUNET_free (cprc);
+ if (NULL != gorc->contract_terms)
+ json_decref (gorc->contract_terms);
+ GNUNET_free (gorc);
}
@@ -155,437 +122,301 @@ process_refunds_cb (void *cls,
const struct TALER_Amount *refund_amount,
const struct TALER_Amount *refund_fee)
{
- struct CheckPaymentRequestContext *cprc = cls;
+ struct GetOrderRequestContext *gorc = cls;
- if (cprc->refunded)
+ // 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 (gorc->refunded)
{
GNUNET_assert (0 <=
- TALER_amount_add (&cprc->refund_amount,
- &cprc->refund_amount,
+ TALER_amount_add (&gorc->refund_amount,
+ &gorc->refund_amount,
refund_amount));
return;
}
- cprc->refund_amount = *refund_amount;
- cprc->refunded = GNUNET_YES;
+ gorc->refund_amount = *refund_amount;
+ gorc->refunded = true;
}
/**
- * The client did not yet pay, send it the payment request.
+ * Manages a GET /private/orders/ID call, checking the status of a payment and
+ * refunds and, if necessary, constructing the URL for a payment redirect URL.
*
- * @param cprc check pay request context
- * @return #MHD_YES on success
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] hc context with further information about the request
+ * @return MHD result code
*/
-static int
-send_pay_request (struct CheckPaymentRequestContext *cprc)
+MHD_RESULT
+TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
{
- int ret;
- char *already_paid_order_id = NULL;
- char *taler_pay_uri;
- struct GNUNET_TIME_Relative remaining;
+ struct GetOrderRequestContext *gorc = hc->ctx;
+ enum GNUNET_DB_QueryStatus qs;
- remaining = GNUNET_TIME_absolute_get_remaining (cprc->sc.long_poll_timeout);
- if (0 != remaining.rel_value_us)
+ if (NULL == gorc)
{
- /* long polling: do not queue a response, suspend connection instead */
- TMH_compute_pay_key (cprc->order_id,
- &cprc->mi->pubkey,
- &cprc->sc.key);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Suspending /check-payment on key %s\n",
- GNUNET_h2s (&cprc->sc.key));
- TMH_long_poll_suspend (&cprc->sc,
- NULL);
- return MHD_YES;
- }
+ /* First time here, parse request and check order is known */
+ gorc = GNUNET_new (struct GetOrderRequestContext);
+ hc->cc = &gorc_cleanup;
+ hc->ctx = gorc;
+ gorc->sc.con = connection;
+ gorc->hc = hc;
+ GNUNET_assert (NULL != hc->infix);
+ gorc->session_id = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "session_id");
+ {
+ const char *long_poll_timeout_s;
+
+ long_poll_timeout_s = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "timeout_ms");
+ if (NULL != long_poll_timeout_s)
+ {
+ unsigned long long timeout;
+
+ if (1 != sscanf (long_poll_timeout_s,
+ "%llu",
+ &timeout))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_PARAMETER_MALFORMED,
+ "timeout must be non-negative number");
+ }
+ gorc->sc.long_poll_timeout
+ = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_MILLISECONDS,
+ timeout));
+ }
+ else
+ {
+ gorc->sc.long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
+ }
+ }
- /* Check if resource_id has been paid for in the same session
- * with another order_id.
- */
- if ( (NULL != cprc->session_id) &&
- (NULL != cprc->fulfillment_url) )
- {
- enum GNUNET_DB_QueryStatus qs;
-
- qs = db->find_session_info (db->cls,
- &already_paid_order_id,
- cprc->session_id,
- cprc->fulfillment_url,
- &cprc->mi->pubkey);
- if (qs < 0)
+ {
+ const char *transfer_s;
+
+ transfer_s = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "transfer");
+ if ( (NULL != transfer_s) &&
+ (0 == strcasecmp (transfer_s,
+ "yes")) )
+ gorc->transfer_status_requested = true;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Starting GET /private/orders/%s processing with timeout %s\n",
+ hc->infix,
+ GNUNET_STRINGS_absolute_time_to_string (
+ gorc->sc.long_poll_timeout));
+
+ db->preflight (db->cls);
+ qs = db->lookup_contract_terms (db->cls,
+ hc->instance.settings->id,
+ hc->infix,
+ &gorc->contract_terms,
+ &gorc->order_serial);
+ if (0 > qs)
{
/* single, read-only SQL statements should never cause
serialization problems */
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != 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 (cprc->sc.con,
+ return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
- "db error fetching pay session info");
+ TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
+ "db error fetching contract terms");
}
- }
- taler_pay_uri = TMH_make_taler_pay_uri (cprc->sc.con,
- cprc->order_id,
- cprc->session_id,
- cprc->mi->id);
- ret = TALER_MHD_reply_json_pack (cprc->sc.con,
- MHD_HTTP_OK,
- "{s:s, s:s, s:b, s:s?}",
- "taler_pay_uri", taler_pay_uri,
- "contract_url", cprc->final_contract_url,
- "paid", 0,
- "already_paid_order_id",
- already_paid_order_id);
- GNUNET_free (taler_pay_uri);
- GNUNET_free_non_null (already_paid_order_id);
- return ret;
-}
+ // FIXME: handle qs!
+ // => mainly: if 0 return 404!
-/**
- * Parse the "contract_terms" in @a cprc and set the
- * "fulfillment_url" and the "h_contract_terms" in @a cprc
- * accordingly.
- *
- * On errors, the response is being queued and the status
- * code set in @cprc "ret".
- *
- * @param cprc[in,out] context to process
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
- */
-static int
-parse_contract_terms (struct CheckPaymentRequestContext *cprc)
-{
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("fulfillment_url",
- &cprc->fulfillment_url),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (cprc->contract_terms,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- cprc->ret
- = TALER_MHD_reply_with_error (cprc->sc.con,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
- "Merchant database error (contract terms corrupted)");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_JSON_hash (cprc->contract_terms,
- &cprc->h_contract_terms))
- {
- GNUNET_break (0);
- cprc->ret
- = TALER_MHD_reply_with_error (cprc->sc.con,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_CHECK_PAYMENT_FAILED_COMPUTE_PROPOSAL_HASH,
- "Failed to hash proposal");
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Check that we are aware of @a order_id and if so request the payment,
- * otherwise generate an error response.
- *
- * @param cprc session state
- * @return status code to return to MHD for @a connection
- */
-static int
-check_order_and_request_payment (struct CheckPaymentRequestContext *cprc)
-{
- enum GNUNET_DB_QueryStatus qs;
-
- if (NULL != cprc->contract_terms)
- {
- /* This should never happen. */
- GNUNET_break (0);
- json_decref (cprc->contract_terms);
- cprc->contract_terms = NULL;
- }
- qs = db->find_order (db->cls,
- &cprc->contract_terms,
- cprc->order_id,
- &cprc->mi->pubkey);
- if (0 > qs)
- {
- /* single, read-only SQL statements should never cause
- serialization problems */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != 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 (cprc->sc.con,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
- "db error fetching order");
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- return TALER_MHD_reply_with_error (cprc->sc.con,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_CHECK_PAYMENT_ORDER_ID_UNKNOWN,
- "unknown order_id");
+ /* extract the fulfillment URL from the contract terms! */
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("fulfillment_url",
+ &gorc->fulfillment_url),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (gorc->contract_terms,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
+ "Merchant database error (contract terms corrupted)");
+ }
+ }
}
- if (GNUNET_OK !=
- parse_contract_terms (cprc))
- return cprc->ret;
- /* Offer was not picked up yet, but we ensured that it exists */
- return send_pay_request (cprc);
-}
-
+ GNUNET_assert (NULL != gorc->contract_terms);
-/**
- * Manages a /check-payment call, checking the status
- * of a payment and, if necessary, constructing the URL
- * for a payment redirect URL.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @param mi merchant backend instance, never NULL
- * @return MHD result code
- */
-MHD_RESULT
-MH_handler_check_payment (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size,
- struct MerchantInstance *mi)
-{
- struct CheckPaymentRequestContext *cprc = *connection_cls;
- enum GNUNET_DB_QueryStatus qs;
- MHD_RESULT ret;
-
- if (NULL == cprc)
{
- const char *long_poll_timeout_s;
-
- /* First time here, parse request and check order is known */
- cprc = GNUNET_new (struct CheckPaymentRequestContext);
- cprc->hc.cc = &cprc_cleanup;
- cprc->ret = GNUNET_SYSERR;
- cprc->sc.con = connection;
- cprc->mi = mi;
- *connection_cls = cprc;
-
- cprc->order_id = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "order_id");
- if (NULL == cprc->order_id)
+ bool paid;
+ bool wired;
+
+ db->preflight (db->cls);
+ qs = db->lookup_payment_status (db->cls,
+ gorc->order_serial,
+ gorc->session_id,
+ &paid,
+ &wired);
+ if (0 >= qs)
{
- /* order_id is required but missing */
- GNUNET_break_op (0);
+ /* 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_BAD_REQUEST,
- TALER_EC_PARAMETER_MISSING,
- "order_id required");
- }
- cprc->contract_url = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "contract_url");
- if (NULL == cprc->contract_url)
- {
- cprc->final_contract_url = TALER_url_absolute_mhd (connection,
- "/public/proposal",
- "instance", mi->id,
- "order_id",
- cprc->order_id,
- NULL);
- GNUNET_assert (NULL != cprc->final_contract_url);
- }
- else
- {
- cprc->final_contract_url = GNUNET_strdup (cprc->contract_url);
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_CHECK_PAYMENT_DB_FETCH_PAYMENT_STATUS,
+ "DB error fetching payment status");
}
- cprc->session_id = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "session_id");
- long_poll_timeout_s = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "timeout");
- if (NULL != long_poll_timeout_s)
+ if (! paid)
{
- unsigned int timeout;
-
- if (1 != sscanf (long_poll_timeout_s,
- "%u",
- &timeout))
+ char *already_paid_order_id;
+
+ qs = db->lookup_repayment_status (db->cls,
+ hc->instance->settings.id,
+ hc->infix,
+ gorc->session_id,
+ gorc->fulfillment_url,
+ &already_paid_order_id);
+ if (0 > qs)
{
- GNUNET_break_op (0);
+ /* 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_BAD_REQUEST,
- TALER_EC_PARAMETER_MALFORMED,
- "timeout must be non-negative number");
+ 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;
}
- cprc->sc.long_poll_timeout
- = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (
- GNUNET_TIME_UNIT_SECONDS,
- timeout));
}
- else
+
+ if (paid &&
+ (! wired) &&
+ gorc->transfer_status_requested)
{
- cprc->sc.long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
+ // FIXME: suspend connection, go to exhange to ask for the
+ // wire transfer status, and resume once we have it!
+ // (make sure to set gorc->transfer_status_requested to FALSE
+ // while we are at it!)
+ return MHD_YES;
}
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Starting /check-payment processing with timeout %s\n",
- GNUNET_STRINGS_absolute_time_to_string (
- cprc->sc.long_poll_timeout));
- }
- if (NULL != cprc->contract_terms)
- {
- json_decref (cprc->contract_terms);
- cprc->contract_terms = NULL;
- }
- db->preflight (db->cls);
- qs = db->find_contract_terms (db->cls,
- &cprc->contract_terms,
- cprc->order_id,
- &mi->pubkey);
- if (0 > qs)
- {
- /* single, read-only SQL statements should never cause
- serialization problems */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != 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_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
- "db error fetching contract terms");
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- /* Check that we're at least aware of the order */
- return check_order_and_request_payment (cprc);
- }
- GNUNET_assert (NULL != cprc->contract_terms);
-
- if (GNUNET_OK !=
- parse_contract_terms (cprc))
- return cprc->ret;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Checkig payment status for order `%s' with contract %s\n",
- cprc->order_id,
- GNUNET_h2s (&cprc->h_contract_terms));
- GNUNET_assert (NULL != cprc->contract_terms);
-
- /* Check if the order has been paid for. */
- if (NULL != cprc->session_id)
- {
- /* Check if paid within a session. */
- char *already_paid_order_id = NULL;
-
- qs = db->find_session_info (db->cls,
- &already_paid_order_id,
- cprc->session_id,
- cprc->fulfillment_url,
- &mi->pubkey);
- if (qs < 0)
+ if ( (! paid) &&
+ (0 != gorc.sc.long_poll_timeout.abs_value_us) )
{
- /* single, read-only SQL statements should never cause
- serialization problems */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != 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_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
- "db error fetching pay session info");
+ // FIXME: suspend connection, wait for payment!
+ return MHD_YES;
}
- else if (0 == qs)
+
+ if (! paid)
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Order `%s' was not yet paid for session `%s'\n",
- cprc->order_id,
- cprc->session_id);
- ret = send_pay_request (cprc);
- GNUNET_free_non_null (already_paid_order_id);
+ /* 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;
}
- GNUNET_break (1 == qs);
- GNUNET_break (0 == strcmp (cprc->order_id,
- already_paid_order_id));
- GNUNET_free_non_null (already_paid_order_id);
- }
- else
- {
- /* Check if paid regardless of session. */
- json_t *xcontract_terms = NULL;
- qs = db->find_paid_contract_terms_from_hash (db->cls,
- &xcontract_terms,
- &cprc->h_contract_terms,
- &mi->pubkey);
+ /* Here we know the user DID pay, compute refunds... */
+
+ /* Accumulate refunds, if any. */
+ qs = db->select_refunds_by_order (db->cls,
+ gorc->order_serial,
+ &process_refunds_cb,
+ gorc);
if (0 > qs)
{
- /* Always report on hard error as well to enable diagnostics */
- GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+ GNUNET_break (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
"Merchant database error");
}
- if (0 == qs)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Order `%s' (contract `%s') was not yet paid\n",
- cprc->order_id,
- GNUNET_h2s (&cprc->h_contract_terms));
- return send_pay_request (cprc);
- }
- GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
- GNUNET_assert (NULL != xcontract_terms);
- json_decref (xcontract_terms);
- }
+ } /* end of scope of 'paid/wired' */
- /* Accumulate refunds, if any. */
- for (unsigned int i = 0; i<MAX_RETRIES; i++)
+ /* Generate final reply, including wire details if we have them */
{
- qs = db->get_refunds_from_contract_terms_hash (db->cls,
- &mi->pubkey,
- &cprc->h_contract_terms,
- &process_refunds_cb,
- cprc);
- if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
- break;
- }
- if (0 > qs)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Database hard error on refunds_from_contract_terms_hash lookup: %s\n",
- GNUNET_h2s (&cprc->h_contract_terms));
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
- "Merchant database error");
- }
- if (cprc->refunded)
+ json_t *wire_details = NULL;
+
+ qs = db->select_wire_details_by_order (db->cls,
+ gorc->order_serial,
+ &process_wire_details,
+ &wire_details);
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
+ "Merchant database error");
+ }
return TALER_MHD_reply_json_pack (connection,
MHD_HTTP_OK,
- "{s:O, s:b, s:b, s:o}",
- "contract_terms", cprc->contract_terms,
- "paid", 1,
- "refunded", cprc->refunded,
+ "{s:O, s:b, s:b, s:o?, s:o?}",
+ "contract_terms",
+ gorc->contract_terms,
+ "paid",
+ true,
+ "refunded",
+ gorc->refunded,
"refund_amount",
- TALER_JSON_from_amount (
- &cprc->refund_amount));
- return TALER_MHD_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:O, s:b, s:b }",
- "contract_terms", cprc->contract_terms,
- "paid", 1,
- "refunded", 0);
+ (gorc->refunded)
+ ? TALER_JSON_from_amount (
+ &gorc->refund_amount)
+ : NULL,
+ "wire_details",
+ wire_details);
+ }
}