[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-merchant] 78/277: work on refund
From: |
gnunet |
Subject: |
[taler-merchant] 78/277: work on refund |
Date: |
Sun, 05 Jul 2020 20:49:51 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository merchant.
commit 74c5fa81d74ff5d239f49f74b2bb937c03b83bcb
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat May 2 17:52:13 2020 +0200
work on refund
---
src/backenddb/merchant-0001.sql | 3 +
src/backenddb/plugin_merchantdb_postgres.c | 2477 ++++++++++++++--------------
src/include/taler_merchantdb_plugin.h | 68 +-
3 files changed, 1285 insertions(+), 1263 deletions(-)
diff --git a/src/backenddb/merchant-0001.sql b/src/backenddb/merchant-0001.sql
index 77c7905..e54e478 100644
--- a/src/backenddb/merchant-0001.sql
+++ b/src/backenddb/merchant-0001.sql
@@ -323,6 +323,9 @@ COMMENT ON TABLE merchant_deposits
IS 'Refunds approved by the merchant (backoffice) logic, excludes abort
refunds';
COMMENT ON COLUMN merchant_refunds.rtransaction_id
IS 'Needed for uniqueness in case a refund is increased for the same order';
+CREATE INDEX IF NOT EXISTS merchant_refunds_by_coin_and_order
+ ON merchant_refunds
+ (coin_pub,order_serial);
CREATE TABLE IF NOT EXISTS merchant_refund_proofs
(refund_serial BIGINT PRIMARY KEY
diff --git a/src/backenddb/plugin_merchantdb_postgres.c
b/src/backenddb/plugin_merchantdb_postgres.c
index 14fb9b2..00df78a 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -1979,254 +1979,31 @@ postgres_lookup_order_status (void *cls,
}
-/* ********************* OLD API ************************** */
-
-/**
- * Retrieve proposal data given its proposal data's hashcode
- *
- * @param cls closure
- * @param contract_terms where to store the retrieved proposal data
- * @param h_contract_terms proposal data's hashcode that will be used to
- * perform the lookup
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_find_contract_terms_from_hash (
- void *cls,
- json_t **contract_terms,
- const struct GNUNET_HashCode *h_contract_terms,
- const struct TALER_MerchantPublicKeyP *merchant_pub)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_json ("contract_terms",
- contract_terms),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-
"find_contract_terms_from_hash",
- params,
- rs);
-}
-
-
-/**
- * Retrieve proposal data given its proposal data's hashcode
- *
- * @param cls closure
- * @param contract_terms where to store the retrieved proposal data
- * @param h_contract_terms proposal data's hashcode that will be used to
- * perform the lookup
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_find_paid_contract_terms_from_hash (void *cls,
- json_t **contract_terms,
- const struct
- GNUNET_HashCode *h_contract_terms,
- const struct
- TALER_MerchantPublicKeyP *
- merchant_pub)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_json ("contract_terms",
- contract_terms),
- GNUNET_PQ_result_spec_end
- };
-
- /* no preflight check here, runs in its own transaction from
- caller (in /pay case) */
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-
"find_paid_contract_terms_from_hash",
- params,
- rs);
-}
-
-
-/**
- * Store the order ID that was used to pay for a resource within a session.
- *
- * @param cls closure
- * @param session_id session id
- * @param fulfillment_url URL that canonically identifies the resource
- * being paid for
- * @param order_id the order ID that was used when paying for the resource URL
- * @param merchant_pub public key of the merchant, identifying the instance
- * @return transaction status
- */
-enum GNUNET_DB_QueryStatus
-postgres_insert_session_info (void *cls,
- const char *session_id,
- const char *fulfillment_url,
- const char *order_id,
- const struct
- TALER_MerchantPublicKeyP *merchant_pub)
-{
- struct PostgresClosure *pg = cls;
-
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (session_id),
- GNUNET_PQ_query_param_string (fulfillment_url),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_absolute_time (&now),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_session_info",
- params);
-}
-
-
/**
- * Retrieve the order ID that was used to pay for a resource within a session.
- *
- * @param cls closure
- * @param[out] order_id where to store the order ID that was used when
- * paying for the resource URL
- * @param session_id session id
- * @param fulfillment_url URL that canonically identifies the resource
- * being paid for
- * @param merchant_pub public key of the merchant, identifying the instance
- * @return transaction status
+ * Closure for #process_refund_cb().
*/
-enum GNUNET_DB_QueryStatus
-postgres_find_session_info (void *cls,
- char **order_id,
- const char *session_id,
- const char *fulfillment_url,
- const struct TALER_MerchantPublicKeyP
*merchant_pub)
-{
- struct PostgresClosure *pg = cls;
-
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (fulfillment_url),
- GNUNET_PQ_query_param_string (session_id),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("order_id",
- order_id),
- GNUNET_PQ_result_spec_end
- };
- // We don't clean up the result spec since we want
- // to keep around the memory for order_id.
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "find_session_info",
- params,
- rs);
-}
-
-
-/**
- * Insert mapping of @a coin_pub and @a h_contract_terms to
- * corresponding @a wtid.
- *
- * @param cls closure
- * @param h_contract_terms hashcode of the proposal data paid by @a coin_pub
- * @param coin_pub public key of the coin
- * @param wtid identifier of the wire transfer in which the exchange
- * send us the money for the coin deposit
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_store_coin_to_transfer (void *cls,
- const struct GNUNET_HashCode
*h_contract_terms,
- const struct
- TALER_CoinSpendPublicKeyP *coin_pub,
- const struct
- TALER_WireTransferIdentifierRawP *wtid)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_transfer",
- params);
-}
-
-
-/**
- * Insert wire transfer confirmation from the exchange into the database.
- *
- * @param cls closure
- * @param exchange_url URL of the exchange
- * @param wtid identifier of the wire transfer
- * @param execution_time when was @a wtid executed
- * @param signkey_pub public key used by the exchange for @a exchange_proof
- * @param exchange_proof proof from exchange about what the deposit was for
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_store_transfer_to_proof (void *cls,
- const char *exchange_url,
- const struct
- TALER_WireTransferIdentifierRawP *wtid,
- struct GNUNET_TIME_Absolute execution_time,
- const struct
- TALER_ExchangePublicKeyP *signkey_pub,
- const json_t *exchange_proof)
+struct FindRefundContext
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_absolute_time (&execution_time),
- GNUNET_PQ_query_param_auto_from_type (signkey_pub),
- TALER_PQ_query_param_json (exchange_proof),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_proof",
- params);
-}
-
-/**
- * Closure for #find_tip_authorizations_cb().
- */
-struct GetAuthorizedTipAmountContext
-{
/**
- * Total authorized amount.
+ * Plugin context.
*/
- struct TALER_Amount authorized_amount;
+ struct PostgresClosure *pg;
/**
- * Transaction status code to set.
+ * Updated to reflect total amount refunded so far.
*/
- enum GNUNET_DB_QueryStatus qs;
+ struct TALER_Amount refunded_amount;
/**
- * Plugin context.
+ * Set to the largest refund transaction ID encountered.
*/
- struct PostgresClosure *pg;
+ uint64_t max_rtransaction_id;
+ /**
+ * Set to true on hard errors.
+ */
+ bool err;
};
@@ -2234,34 +2011,28 @@ struct GetAuthorizedTipAmountContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls of type `struct GetAuthorizedTipAmountContext *`
+ * @param cls closure, our `struct FindRefundContext`
* @param result the postgres result
* @param num_result the number of results in @a result
*/
static void
-find_tip_authorizations_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+process_refund_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct GetAuthorizedTipAmountContext *ctx = cls;
- struct PostgresClosure *pg = ctx->pg;
- unsigned int i;
+ struct FindRefundContext *ictx = cls;
+ struct PostgresClosure *pg = ictx->pg;
- for (i = 0; i < num_results; i++)
+ for (unsigned int i = 0; i<num_results; i++)
{
- struct TALER_Amount amount;
- char *just;
- json_t *extra;
- struct GNUNET_HashCode h;
+ /* Sum up existing refunds */
+ struct TALER_Amount acc;
+ uint64_t rtransaction_id;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("justification",
- &just),
- GNUNET_PQ_result_spec_auto_from_type ("tip_id",
- &h),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- &amount),
- TALER_PQ_result_spec_json ("extra",
- &extra),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
+ &acc),
+ GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
+ &rtransaction_id),
GNUNET_PQ_result_spec_end
};
@@ -2271,111 +2042,85 @@ find_tip_authorizations_cb (void *cls,
i))
{
GNUNET_break (0);
- ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ ictx->err = true;
return;
}
-
- if (0 == i)
- {
- ctx->authorized_amount = amount;
- }
- else
+ if (0 >
+ TALER_amount_add (&ictx->refunded_amount,
+ &ictx->refunded_amount,
+ &acc))
{
- if (0 >
- TALER_amount_add (&ctx->authorized_amount,
- &ctx->authorized_amount,
- &amount))
- {
- GNUNET_break (0);
- GNUNET_PQ_cleanup_result (rs);
- ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
+ GNUNET_break (0);
+ ictx->err = true;
+ return;
}
- GNUNET_PQ_cleanup_result (rs);
- }
-
- if (0 == i)
- {
- ctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
- }
- else
- {
- /* one aggregated result */
- ctx->qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+ ictx->max_rtransaction_id = GNUNET_MAX (ictx->max_rtransaction_id,
+ rtransaction_id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Found refund of %s\n",
+ TALER_amount2s (&acc));
}
}
/**
- * Get the total amount of authorized tips for a tipping reserve.
- *
- * @param cls closure, typically a connection to the db
- * @param reserve_priv which reserve to check
- * @param[out] authorzed_amount amount we've authorized so far for tips
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the reserve_priv
- * does not identify a known tipping reserve
+ * Closure for #process_deposits_for_refund_cb().
*/
-static enum GNUNET_DB_QueryStatus
-postgres_get_authorized_tip_amount (void *cls,
- const struct
- TALER_ReservePrivateKeyP *reserve_priv,
- struct TALER_Amount *authorized_amount)
+struct InsertRefundContext
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserve_priv),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
- struct GetAuthorizedTipAmountContext ctx = {
- .pg = pg
- };
+ /**
+ * Used to provide a connection to the db
+ */
+ struct PostgresClosure *pg;
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "find_tip_authorizations",
- params,
- &find_tip_authorizations_cb,
- &ctx);
- if (0 >= qs)
- return qs;
- *authorized_amount = ctx.authorized_amount;
- return ctx.qs;
-}
+ /**
+ * Amount to which increase the refund for this contract
+ */
+ const struct TALER_Amount *refund;
+
+ /**
+ * Human-readable reason behind this refund
+ */
+ const char *reason;
+
+ /**
+ * Transaction status code.
+ */
+ enum TALER_MERCHANTDB_RefundStatus rs;
+};
/**
- * Closure for #find_payments_cb().
+ * Data extracted per coin.
*/
-struct FindPaymentsContext
+struct RefundCoinData
{
+
/**
- * Function to call with results.
+ * Public key of a coin.
*/
- TALER_MERCHANTDB_CoinDepositCallback cb;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
/**
- * Closure for @e cls.
+ * Amount deposited for this coin.
*/
- void *cb_cls;
+ struct TALER_Amount deposited_with_fee;
/**
- * Plugin context.
+ * Amount refunded already for this coin.
*/
- struct PostgresClosure *pg;
+ struct TALER_Amount refund_amount;
/**
- * Contract term hash used for the search.
+ * Order serial (actually not really per-coin).
*/
- const struct GNUNET_HashCode *h_contract_terms;
+ uint64_t order_serial;
/**
- * Transaction status (set).
+ * Maximum rtransaction_id for this coin so far.
*/
- enum GNUNET_DB_QueryStatus qs;
+ uint64_t max_rtransaction_id;
+
};
@@ -2383,419 +2128,549 @@ struct FindPaymentsContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls of type `struct FindPaymentsContext *`
+ * @param cls closure, our `struct InsertRefundContext`
* @param result the postgres result
* @param num_result the number of results in @a result
*/
static void
-find_payments_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+process_deposits_for_refund_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct FindPaymentsContext *fpc = cls;
- struct PostgresClosure *pg = fpc->pg;
+ struct InsertRefundContext *ctx = cls;
+ struct PostgresClosure *pg = ctx->pg;
+ struct TALER_Amount current_refund;
+ struct RefundCoinData rcd[GNUNET_NZL (num_results)];
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (ctx->refund->currency,
+ ¤t_refund));
+ memset (rcd, 0, sizeof (rcd));
+ /* Pass 1: Collect amount of existing refunds into current_refund.
+ * Also store existing refunded amount for each deposit in deposit_refund. */
for (unsigned int i = 0; i<num_results; i++)
{
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct TALER_Amount refund_fee;
- struct TALER_Amount wire_fee;
- json_t *exchange_proof;
- char *exchange_url;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
+ &rcd[i].coin_pub),
+ GNUNET_PQ_result_spec_uint64 ("order_serial",
+ &rcd[i].order_serial),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount_with_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
- &deposit_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
- &refund_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- &wire_fee),
- TALER_PQ_result_spec_json ("exchange_proof",
- &exchange_proof),
+ &rcd[i].deposited_with_fee),
GNUNET_PQ_result_spec_end
};
+ struct FindRefundContext ictx = {
+ .pg = pg
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+ return;
+ }
+
+ {
+ enum GNUNET_DB_QueryStatus ires;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub),
+ GNUNET_PQ_query_param_uint64 (&rcd[i].order_serial),
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (ctx->refund->currency,
+ &ictx.refunded_amount));
+ ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn,
+ "find_refunds_by_coin",
+ params,
+ &process_refund_cb,
+ &ictx);
+ if ( (ictx.err) ||
+ (GNUNET_DB_STATUS_HARD_ERROR == ires) )
+ {
+ GNUNET_break (0);
+ ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+ return;
+ }
+ if (GNUNET_DB_STATUS_SOFT_ERROR == ires)
+ {
+ ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
+ return;
+ }
+ }
+ if (0 >
+ TALER_amount_add (¤t_refund,
+ ¤t_refund,
+ &ictx.refunded_amount))
+ {
+ GNUNET_break (0);
+ ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+ return;
+ }
+ rcd[i].refund_amount = ictx.refunded_amount;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Existing refund for coin %s is %s\n",
+ TALER_B2S (&rcd[i].coin_pub),
+ TALER_amount2s (&ictx.refunded_amount));
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Total existing refund is %s\n",
+ TALER_amount2s (¤t_refund));
+
+ /* stop immediately if we are 'done' === amount already
+ * refunded. */
+ if (0 >= TALER_amount_cmp (ctx->refund,
+ ¤t_refund))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Existing refund of %s at or above requested refund. Finished
early.\n",
+ TALER_amount2s (¤t_refund));
+ ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
+ return;
+ }
+
+ /* Phase 2: Try to increase current refund until it matches desired refund
*/
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ const struct TALER_Amount *increment;
+ struct TALER_Amount left;
+ struct TALER_Amount remaining_refund;
+
+ /* How much of the coin is left after the existing refunds? */
+ if (0 >
+ TALER_amount_subtract (&left,
+ &rcd[i].deposited_with_fee,
+ &rcd[i].refund_amount))
+ {
+ GNUNET_break (0);
+ ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+ return;
+ }
+
+ if ( (0 == left.value) &&
+ (0 == left.fraction) )
+ {
+ /* coin was fully refunded, move to next coin */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Coin %s fully refunded, moving to next coin\n",
+ TALER_B2S (&rcd[i].coin_pub));
+ continue;
+ }
+
+ rcd[i].max_rtransaction_id++;
+ /* How much of the refund is still to be paid back? */
+ if (0 >
+ TALER_amount_subtract (&remaining_refund,
+ ctx->refund,
+ ¤t_refund))
+ {
+ GNUNET_break (0);
+ ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+ return;
+ }
+
+ /* By how much will we increase the refund for this coin? */
+ if (0 >= TALER_amount_cmp (&remaining_refund,
+ &left))
+ {
+ /* remaining_refund <= left */
+ increment = &remaining_refund;
+ }
+ else
+ {
+ increment = &left;
+ }
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
+ if (0 >
+ TALER_amount_add (¤t_refund,
+ ¤t_refund,
+ increment))
{
GNUNET_break (0);
- fpc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+ return;
+ }
+
+ /* actually run the refund */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Coin %s deposit amount is %s\n",
+ TALER_B2S (&rcd[i].coin_pub),
+ TALER_amount2s (&rcd[i].deposited_with_fee));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Coin %s refund will be incremented by %s\n",
+ TALER_B2S (&rcd[i].coin_pub),
+ TALER_amount2s (increment));
+ {
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&rcd[i].order_serial),
+ GNUNET_PQ_query_param_uint64 (&rcd[i].max_rtransaction_id),
+ GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub),
+ GNUNET_PQ_query_param_string (ctx->reason),
+ TALER_PQ_query_param_amount (increment),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_refund",
+ params);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
+ break;
+ default:
+ GNUNET_break (0);
+ ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+ break;
+ }
+ return;
+ }
+
+ /* stop immediately if we are done */
+ if (0 == TALER_amount_cmp (ctx->refund,
+ ¤t_refund))
+ {
+ ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
return;
}
- fpc->qs = i + 1;
- fpc->cb (fpc->cb_cls,
- fpc->h_contract_terms,
- &coin_pub,
- exchange_url,
- &amount_with_fee,
- &deposit_fee,
- &refund_fee,
- &wire_fee,
- exchange_proof);
- GNUNET_PQ_cleanup_result (rs);
}
+
+ /**
+ * We end up here if not all of the refund has been covered.
+ * Although this should be checked as the business should never
+ * issue a refund bigger than the contract's actual price, we cannot
+ * rely upon the frontend being correct.
+ *///
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "The refund of %s is bigger than the order's value\n",
+ TALER_amount2s (ctx->refund));
+ ctx->rs = TALER_MERCHANTDB_RS_TOO_HIGH;
}
/**
- * Lookup information about coin payments by proposal data hash
- * (and @a merchant_pub)
+ * Function called when some backoffice staff decides to award or
+ * increase the refund on an existing contract. This function
+ * MUST be called from within a transaction scope setup by the
+ * caller as it executes multiple SQL statements.
*
* @param cls closure
- * @param h_contract_terms key for the search
- * @param merchant_pub merchant's public key
- * @param cb function to call with payment data
- * @param cb_cls closure for @a cb
+ * @param instance_id instance identifier
+ * @param order_id the order to increase the refund for
+ * @param refund maximum refund to return to the customer for this contract
+ * @param reason 0-terminated UTF-8 string giving the reason why the customer
+ * got a refund (free form, business-specific)
* @return transaction status
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a refund is ABOVE the
amount we
+ * were originally paid and thus the transaction failed;
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
+ * regardless of whether it actually increased the refund beyond
+ * what was already refunded (idempotency!)
*/
-enum GNUNET_DB_QueryStatus
-postgres_find_payments (void *cls,
- const struct GNUNET_HashCode *h_contract_terms,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- TALER_MERCHANTDB_CoinDepositCallback cb,
- void *cb_cls)
+static enum TALER_MERCHANTDB_RefundStatus
+postgres_increase_refund (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ const struct TALER_Amount *refund,
+ const char *reason)
{
struct PostgresClosure *pg = cls;
+ enum GNUNET_DB_QueryStatus qs;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
GNUNET_PQ_query_param_end
};
- struct FindPaymentsContext fpc = {
- .h_contract_terms = h_contract_terms,
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg
+ struct InsertRefundContext ctx = {
+ .pg = pg,
+ .refund = refund,
+ .reason = reason
};
- enum GNUNET_DB_QueryStatus qs;
- /* no preflight check here, run in its own transaction by the
- caller! */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Finding payment for h_contract_terms '%s'\n",
- GNUNET_h2s (h_contract_terms));
- check_connection (pg);
+ "Asked to refund %s on order %s\n",
+ TALER_amount2s (refund),
+ order_id);
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "find_deposits",
+ "find_deposits_for_refund",
params,
- &find_payments_cb,
- &fpc);
- if (qs <= 0)
- return qs;
- return fpc.qs;
+ &process_deposits_for_refund_cb,
+ &ctx);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ /* never paid, means we clearly cannot refund anything */
+ return TALER_MERCHANTDB_RS_NO_SUCH_ORDER;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return TALER_MERCHANTDB_RS_SOFT_ERROR;
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return TALER_MERCHANTDB_RS_HARD_ERROR;
+ default:
+ /* Got one or more deposits */
+ return ctx.rs;
+ }
}
-/**
- * Closure for #find_payments_by_coin_cb().
- */
-struct FindPaymentsByCoinContext
-{
- /**
- * Function to call with results.
- */
- TALER_MERCHANTDB_CoinDepositCallback cb;
-
- /**
- * Closure for @e cls.
- */
- void *cb_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Coin we are looking for.
- */
- const struct TALER_CoinSpendPublicKeyP *coin_pub;
-
- /**
- * Hash of the contract we are looking for.
- */
- const struct GNUNET_HashCode *h_contract_terms;
-
- /**
- * Transaction status (set).
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
+/* ********************* OLD API ************************** */
/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
+ * Retrieve proposal data given its proposal data's hashcode
*
- * @param cls of type `struct FindPaymentsByCoinContext *`
- * @param result the postgres result
- * @param num_result the number of results in @a result
+ * @param cls closure
+ * @param contract_terms where to store the retrieved proposal data
+ * @param h_contract_terms proposal data's hashcode that will be used to
+ * perform the lookup
+ * @return transaction status
*/
-static void
-find_payments_by_coin_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+static enum GNUNET_DB_QueryStatus
+postgres_find_contract_terms_from_hash (
+ void *cls,
+ json_t **contract_terms,
+ const struct GNUNET_HashCode *h_contract_terms,
+ const struct TALER_MerchantPublicKeyP *merchant_pub)
{
- struct FindPaymentsByCoinContext *fpc = cls;
- struct PostgresClosure *pg = fpc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct TALER_Amount refund_fee;
- struct TALER_Amount wire_fee;
- char *exchange_url;
- json_t *exchange_proof;
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount_with_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
- &deposit_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
- &refund_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- &wire_fee),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- TALER_PQ_result_spec_json ("exchange_proof",
- &exchange_proof),
- GNUNET_PQ_result_spec_end
- };
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_json ("contract_terms",
+ contract_terms),
+ GNUNET_PQ_result_spec_end
+ };
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- fpc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- fpc->qs = i + 1;
- fpc->cb (fpc->cb_cls,
- fpc->h_contract_terms,
- fpc->coin_pub,
- exchange_url,
- &amount_with_fee,
- &deposit_fee,
- &refund_fee,
- &wire_fee,
- exchange_proof);
- GNUNET_PQ_cleanup_result (rs);
- }
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+
"find_contract_terms_from_hash",
+ params,
+ rs);
}
/**
- * Retrieve information about a deposited coin.
+ * Retrieve proposal data given its proposal data's hashcode
*
* @param cls closure
- * @param h_contract_terms hashcode of the proposal data paid by @a coin_pub
- * @param merchant_pub merchant's public key.
- * @param coin_pub coin's public key used for the search
- * @param cb function to call with payment data
- * @param cb_cls closure for @a cb
+ * @param contract_terms where to store the retrieved proposal data
+ * @param h_contract_terms proposal data's hashcode that will be used to
+ * perform the lookup
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_find_payments_by_hash_and_coin (void *cls,
- const struct
- GNUNET_HashCode *h_contract_terms,
- const struct
- TALER_MerchantPublicKeyP
*merchant_pub,
- const struct
- TALER_CoinSpendPublicKeyP *coin_pub,
- TALER_MERCHANTDB_CoinDepositCallback
cb,
- void *cb_cls)
+postgres_find_paid_contract_terms_from_hash (void *cls,
+ json_t **contract_terms,
+ const struct
+ GNUNET_HashCode *h_contract_terms,
+ const struct
+ TALER_MerchantPublicKeyP *
+ merchant_pub)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
GNUNET_PQ_query_param_end
};
- struct FindPaymentsByCoinContext fpc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg,
- .h_contract_terms = h_contract_terms,
- .coin_pub = coin_pub
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_json ("contract_terms",
+ contract_terms),
+ GNUNET_PQ_result_spec_end
};
- enum GNUNET_DB_QueryStatus qs;
+ /* no preflight check here, runs in its own transaction from
+ caller (in /pay case) */
check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "find_deposits_by_hash_and_coin",
- params,
- &find_payments_by_coin_cb,
- &fpc);
- if (0 >= qs)
- return qs;
- return fpc.qs;
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+
"find_paid_contract_terms_from_hash",
+ params,
+ rs);
}
/**
- * Closure for #find_transfers_cb().
+ * Store the order ID that was used to pay for a resource within a session.
+ *
+ * @param cls closure
+ * @param session_id session id
+ * @param fulfillment_url URL that canonically identifies the resource
+ * being paid for
+ * @param order_id the order ID that was used when paying for the resource URL
+ * @param merchant_pub public key of the merchant, identifying the instance
+ * @return transaction status
*/
-struct FindTransfersContext
+enum GNUNET_DB_QueryStatus
+postgres_insert_session_info (void *cls,
+ const char *session_id,
+ const char *fulfillment_url,
+ const char *order_id,
+ const struct
+ TALER_MerchantPublicKeyP *merchant_pub)
{
- /**
- * Function to call on results.
- */
- TALER_MERCHANTDB_TransferCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
+ struct PostgresClosure *pg = cls;
- /**
- * Hash of the contract we are looking under.
- */
- const struct GNUNET_HashCode *h_contract_terms;
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (session_id),
+ GNUNET_PQ_query_param_string (fulfillment_url),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_absolute_time (&now),
+ GNUNET_PQ_query_param_end
+ };
- /**
- * Transaction status (set).
- */
- enum GNUNET_DB_QueryStatus qs;
-};
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_session_info",
+ params);
+}
/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
+ * Retrieve the order ID that was used to pay for a resource within a session.
*
- * @param cls of type `struct FindTransfersContext *`
- * @param result the postgres result
- * @param num_result the number of results in @a result
+ * @param cls closure
+ * @param[out] order_id where to store the order ID that was used when
+ * paying for the resource URL
+ * @param session_id session id
+ * @param fulfillment_url URL that canonically identifies the resource
+ * being paid for
+ * @param merchant_pub public key of the merchant, identifying the instance
+ * @return transaction status
*/
-static void
-find_transfers_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+enum GNUNET_DB_QueryStatus
+postgres_find_session_info (void *cls,
+ char **order_id,
+ const char *session_id,
+ const char *fulfillment_url,
+ const struct TALER_MerchantPublicKeyP
*merchant_pub)
{
- struct FindTransfersContext *ftc = cls;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_WireTransferIdentifierRawP wtid;
- struct GNUNET_TIME_Absolute execution_time;
- json_t *proof;
-
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- GNUNET_PQ_result_spec_auto_from_type ("wtid",
- &wtid),
- GNUNET_PQ_result_spec_absolute_time ("execution_time",
- &execution_time),
- TALER_PQ_result_spec_json ("proof",
- &proof),
- GNUNET_PQ_result_spec_end
- };
+ struct PostgresClosure *pg = cls;
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ftc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- ftc->qs = i + 1;
- ftc->cb (ftc->cb_cls,
- ftc->h_contract_terms,
- &coin_pub,
- &wtid,
- execution_time,
- proof);
- GNUNET_PQ_cleanup_result (rs);
- }
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (fulfillment_url),
+ GNUNET_PQ_query_param_string (session_id),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("order_id",
+ order_id),
+ GNUNET_PQ_result_spec_end
+ };
+ // We don't clean up the result spec since we want
+ // to keep around the memory for order_id.
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "find_session_info",
+ params,
+ rs);
}
/**
- * Lookup information about a transfer by @a h_contract_terms. Note
- * that in theory there could be multiple wire transfers for a
- * single @a h_contract_terms, as the transaction may have involved
- * multiple coins and the coins may be spread over different wire
- * transfers.
+ * Insert mapping of @a coin_pub and @a h_contract_terms to
+ * corresponding @a wtid.
*
* @param cls closure
- * @param h_contract_terms key for the search
- * @param cb function to call with transfer data
- * @param cb_cls closure for @a cb
+ * @param h_contract_terms hashcode of the proposal data paid by @a coin_pub
+ * @param coin_pub public key of the coin
+ * @param wtid identifier of the wire transfer in which the exchange
+ * send us the money for the coin deposit
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_find_transfers_by_hash (void *cls,
+postgres_store_coin_to_transfer (void *cls,
const struct GNUNET_HashCode
*h_contract_terms,
- TALER_MERCHANTDB_TransferCallback cb,
- void *cb_cls)
+ const struct
+ TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct
+ TALER_WireTransferIdentifierRawP *wtid)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_end
};
- struct FindTransfersContext ftc = {
- .h_contract_terms = h_contract_terms,
- .cb = cb,
- .cb_cls = cb_cls
- };
- enum GNUNET_DB_QueryStatus qs;
check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "find_transfers_by_hash",
- params,
- &find_transfers_cb,
- &ftc);
- if (0 >= qs)
- return qs;
- return ftc.qs;
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_transfer",
+ params);
}
/**
- * Closure for #find_deposits_cb().
+ * Insert wire transfer confirmation from the exchange into the database.
+ *
+ * @param cls closure
+ * @param exchange_url URL of the exchange
+ * @param wtid identifier of the wire transfer
+ * @param execution_time when was @a wtid executed
+ * @param signkey_pub public key used by the exchange for @a exchange_proof
+ * @param exchange_proof proof from exchange about what the deposit was for
+ * @return transaction status
*/
-struct FindDepositsContext
+static enum GNUNET_DB_QueryStatus
+postgres_store_transfer_to_proof (void *cls,
+ const char *exchange_url,
+ const struct
+ TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute execution_time,
+ const struct
+ TALER_ExchangePublicKeyP *signkey_pub,
+ const json_t *exchange_proof)
{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_absolute_time (&execution_time),
+ GNUNET_PQ_query_param_auto_from_type (signkey_pub),
+ TALER_PQ_query_param_json (exchange_proof),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_proof",
+ params);
+}
+
+/**
+ * Closure for #find_tip_authorizations_cb().
+ */
+struct GetAuthorizedTipAmountContext
+{
/**
- * Function to call for each result.
+ * Total authorized amount.
*/
- TALER_MERCHANTDB_CoinDepositCallback cb;
+ struct TALER_Amount authorized_amount;
/**
- * Closure for @e cb.
+ * Transaction status code to set.
*/
- void *cb_cls;
+ enum GNUNET_DB_QueryStatus qs;
/**
* Plugin context.
*/
struct PostgresClosure *pg;
- /**
- * Transaction status (set).
- */
- enum GNUNET_DB_QueryStatus qs;
};
@@ -2803,45 +2678,34 @@ struct FindDepositsContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls of type `struct FindDepositsContext *`
+ * @param cls of type `struct GetAuthorizedTipAmountContext *`
* @param result the postgres result
* @param num_result the number of results in @a result
*/
static void
-find_deposits_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+find_tip_authorizations_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct FindDepositsContext *fdc = cls;
- struct PostgresClosure *pg = fdc->pg;
+ struct GetAuthorizedTipAmountContext *ctx = cls;
+ struct PostgresClosure *pg = ctx->pg;
+ unsigned int i;
- for (unsigned int i = 0; i<num_results; i++)
+ for (i = 0; i < num_results; i++)
{
- struct GNUNET_HashCode h_contract_terms;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct TALER_Amount refund_fee;
- struct TALER_Amount wire_fee;
- char *exchange_url;
- json_t *exchange_proof;
+ struct TALER_Amount amount;
+ char *just;
+ json_t *extra;
+ struct GNUNET_HashCode h;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
- &h_contract_terms),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount_with_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
- &deposit_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
- &refund_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- &wire_fee),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- TALER_PQ_result_spec_json ("exchange_proof",
- &exchange_proof),
+ GNUNET_PQ_result_spec_string ("justification",
+ &just),
+ GNUNET_PQ_result_spec_auto_from_type ("tip_id",
+ &h),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+ &amount),
+ TALER_PQ_result_spec_json ("extra",
+ &extra),
GNUNET_PQ_result_spec_end
};
@@ -2851,78 +2715,96 @@ find_deposits_cb (void *cls,
i))
{
GNUNET_break (0);
- fdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- fdc->qs = i + 1;
- fdc->cb (fdc->cb_cls,
- &h_contract_terms,
- &coin_pub,
- exchange_url,
- &amount_with_fee,
- &deposit_fee,
- &refund_fee,
- &wire_fee,
- exchange_proof);
+
+ if (0 == i)
+ {
+ ctx->authorized_amount = amount;
+ }
+ else
+ {
+ if (0 >
+ TALER_amount_add (&ctx->authorized_amount,
+ &ctx->authorized_amount,
+ &amount))
+ {
+ GNUNET_break (0);
+ GNUNET_PQ_cleanup_result (rs);
+ ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ }
GNUNET_PQ_cleanup_result (rs);
}
+
+ if (0 == i)
+ {
+ ctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ }
+ else
+ {
+ /* one aggregated result */
+ ctx->qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+ }
}
/**
- * Lookup information about a coin deposits by @a wtid.
+ * Get the total amount of authorized tips for a tipping reserve.
*
- * @param cls closure
- * @param wtid wire transfer identifier to find matching transactions for
- * @param cb function to call with payment data
- * @param cb_cls closure for @a cb
- * @return transaction status
+ * @param cls closure, typically a connection to the db
+ * @param reserve_priv which reserve to check
+ * @param[out] authorzed_amount amount we've authorized so far for tips
+ * @return transaction status, usually
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the reserve_priv
+ * does not identify a known tipping reserve
*/
static enum GNUNET_DB_QueryStatus
-postgres_find_deposits_by_wtid (void *cls,
- const struct
- TALER_WireTransferIdentifierRawP *wtid,
- TALER_MERCHANTDB_CoinDepositCallback cb,
- void *cb_cls)
+postgres_get_authorized_tip_amount (void *cls,
+ const struct
+ TALER_ReservePrivateKeyP *reserve_priv,
+ struct TALER_Amount *authorized_amount)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_auto_from_type (reserve_priv),
GNUNET_PQ_query_param_end
};
- struct FindDepositsContext fdc = {
- .cb = cb,
- .cb_cls = cb_cls,
+ enum GNUNET_DB_QueryStatus qs;
+ struct GetAuthorizedTipAmountContext ctx = {
.pg = pg
};
- enum GNUNET_DB_QueryStatus qs;
check_connection (pg);
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "find_deposits_by_wtid",
+ "find_tip_authorizations",
params,
- &find_deposits_cb,
- &fdc);
+ &find_tip_authorizations_cb,
+ &ctx);
if (0 >= qs)
return qs;
- return fdc.qs;
+ *authorized_amount = ctx.authorized_amount;
+ return ctx.qs;
}
/**
- * Closure for #get_refunds_cb().
+ * Closure for #find_payments_cb().
*/
-struct GetRefundsContext
+struct FindPaymentsContext
{
/**
- * Function to call for each refund.
+ * Function to call with results.
*/
- TALER_MERCHANTDB_CoinRefundCallback rc;
+ TALER_MERCHANTDB_CoinDepositCallback cb;
/**
- * Closure for @e rc.
+ * Closure for @e cls.
*/
- void *rc_cls;
+ void *cb_cls;
/**
* Plugin context.
@@ -2930,7 +2812,12 @@ struct GetRefundsContext
struct PostgresClosure *pg;
/**
- * Transaction result.
+ * Contract term hash used for the search.
+ */
+ const struct GNUNET_HashCode *h_contract_terms;
+
+ /**
+ * Transaction status (set).
*/
enum GNUNET_DB_QueryStatus qs;
};
@@ -2940,39 +2827,42 @@ struct GetRefundsContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls of type `struct GetRefundsContext *`
+ * @param cls of type `struct FindPaymentsContext *`
* @param result the postgres result
* @param num_result the number of results in @a result
*/
static void
-get_refunds_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+find_payments_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct GetRefundsContext *grc = cls;
- struct PostgresClosure *pg = grc->pg;
+ struct FindPaymentsContext *fpc = cls;
+ struct PostgresClosure *pg = fpc->pg;
for (unsigned int i = 0; i<num_results; i++)
{
struct TALER_CoinSpendPublicKeyP coin_pub;
- uint64_t rtransaction_id;
- struct TALER_Amount refund_amount;
+ struct TALER_Amount amount_with_fee;
+ struct TALER_Amount deposit_fee;
struct TALER_Amount refund_fee;
- char *reason;
+ struct TALER_Amount wire_fee;
+ json_t *exchange_proof;
char *exchange_url;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
&coin_pub),
GNUNET_PQ_result_spec_string ("exchange_url",
&exchange_url),
- GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
- &rtransaction_id),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
- &refund_amount),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
+ &amount_with_fee),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
+ &deposit_fee),
TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
&refund_fee),
- GNUNET_PQ_result_spec_string ("reason",
- &reason),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+ &wire_fee),
+ TALER_PQ_result_spec_json ("exchange_proof",
+ &exchange_proof),
GNUNET_PQ_result_spec_end
};
@@ -2982,330 +2872,248 @@ get_refunds_cb (void *cls,
i))
{
GNUNET_break (0);
- grc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- grc->qs = i + 1;
- grc->rc (grc->rc_cls,
- &coin_pub,
- exchange_url,
- rtransaction_id,
- reason,
- &refund_amount,
- &refund_fee);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Obtain refunds associated with a contract.
- *
- * @param cls closure, typically a connection to the db
- * @param merchant_pub public key of the merchant instance
- * @param h_contract_terms hash code of the contract
- * @param rc function to call for each coin on which there is a refund
- * @param rc_cls closure for @a rc
- * @return transaction status
- */
-enum GNUNET_DB_QueryStatus
-postgres_get_refunds_from_contract_terms_hash (
- void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_contract_terms,
- TALER_MERCHANTDB_CoinRefundCallback rc,
- void *rc_cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_end
- };
- struct GetRefundsContext grc = {
- .rc = rc,
- .rc_cls = rc_cls,
- .pg = pg
- };
- enum GNUNET_DB_QueryStatus qs;
-
- /* no preflight check here, run in transaction by caller! */
- TALER_LOG_DEBUG ("Looking for refund %s + %s\n",
- GNUNET_h2s (h_contract_terms),
- TALER_B2S (merchant_pub));
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-
"find_refunds_from_contract_terms_hash",
- params,
- &get_refunds_cb,
- &grc);
- if (0 >= qs)
- return qs;
- return grc.qs;
+ fpc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ fpc->qs = i + 1;
+ fpc->cb (fpc->cb_cls,
+ fpc->h_contract_terms,
+ &coin_pub,
+ exchange_url,
+ &amount_with_fee,
+ &deposit_fee,
+ &refund_fee,
+ &wire_fee,
+ exchange_proof);
+ GNUNET_PQ_cleanup_result (rs);
+ }
}
/**
- * Obtain refund proofs associated with a refund operation on a
- * coin.
+ * Lookup information about coin payments by proposal data hash
+ * (and @a merchant_pub)
*
- * @param cls closure, typically a connection to the db
- * @param merchant_pub public key of the merchant instance
- * @param h_contract_terms hash code of the contract
- * @param coin_pub public key of the coin
- * @param rtransaction_id identificator of the refund
- * @param[out] exchange_pub public key of the exchange affirming the refund
- * @param[out] exchange_sig signature of the exchange affirming the refund
+ * @param cls closure
+ * @param h_contract_terms key for the search
+ * @param merchant_pub merchant's public key
+ * @param cb function to call with payment data
+ * @param cb_cls closure for @a cb
* @return transaction status
*/
-static enum GNUNET_DB_QueryStatus
-postgres_get_refund_proof (
- void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_contract_terms,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- uint64_t rtransaction_id,
- struct TALER_ExchangePublicKeyP *exchange_pub,
- struct TALER_ExchangeSignatureP *exchange_sig)
+enum GNUNET_DB_QueryStatus
+postgres_find_payments (void *cls,
+ const struct GNUNET_HashCode *h_contract_terms,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ TALER_MERCHANTDB_CoinDepositCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_uint64 (&rtransaction_id),
GNUNET_PQ_query_param_end
};
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
- exchange_sig),
- GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
- exchange_pub),
- GNUNET_PQ_result_spec_end
+ struct FindPaymentsContext fpc = {
+ .h_contract_terms = h_contract_terms,
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg
};
+ enum GNUNET_DB_QueryStatus qs;
+ /* no preflight check here, run in its own transaction by the
+ caller! */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Finding payment for h_contract_terms '%s'\n",
+ GNUNET_h2s (h_contract_terms));
check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "get_refund_proof",
- params,
- rs);
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "find_deposits",
+ params,
+ &find_payments_cb,
+ &fpc);
+ if (qs <= 0)
+ return qs;
+ return fpc.qs;
}
/**
- * Store refund proofs associated with a refund operation on a
- * coin.
- *
- * @param cls closure, typically a connection to the db
- * @param merchant_pub public key of the merchant instance
- * @param h_contract_terms hash code of the contract
- * @param coin_pub public key of the coin
- * @param rtransaction_id identificator of the refund
- * @param exchange_pub public key of the exchange affirming the refund
- * @param exchange_sig signature of the exchange affirming the refund
- * @return transaction status
+ * Closure for #find_payments_by_coin_cb().
*/
-static enum GNUNET_DB_QueryStatus
-postgres_put_refund_proof (
- void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_contract_terms,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- uint64_t rtransaction_id,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const struct TALER_ExchangeSignatureP *exchange_sig)
+struct FindPaymentsByCoinContext
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&rtransaction_id),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_auto_from_type (exchange_sig),
- GNUNET_PQ_query_param_auto_from_type (exchange_pub),
- GNUNET_PQ_query_param_end
- };
+ /**
+ * Function to call with results.
+ */
+ TALER_MERCHANTDB_CoinDepositCallback cb;
- TALER_LOG_DEBUG ("Inserting refund proof %s + %s\n",
- GNUNET_h2s (h_contract_terms),
- TALER_B2S (coin_pub));
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_refund_proof",
- params);
-}
+ /**
+ * Closure for @e cls.
+ */
+ void *cb_cls;
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
-/**
- * Insert a refund row into merchant_refunds. Not meant to be exported
- * in the db API.
- *
- * @param cls closure, typically a connection to the db
- * @param merchant_pub merchant instance public key
- * @param h_contract_terms hashcode of the contract related to this refund
- * @param coin_pub public key of the coin giving the (part of) refund
- * @param reason human readable explanation behind the refund
- * @param refund how much this coin is refunding
- */
-static enum GNUNET_DB_QueryStatus
-insert_refund (void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_contract_terms,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const char *reason,
- const struct TALER_Amount *refund)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_string (reason),
- TALER_PQ_query_param_amount (refund),
- GNUNET_PQ_query_param_end
- };
+ /**
+ * Coin we are looking for.
+ */
+ const struct TALER_CoinSpendPublicKeyP *coin_pub;
- TALER_LOG_DEBUG ("Inserting refund %s + %s\n",
- GNUNET_h2s (h_contract_terms),
- TALER_B2S (merchant_pub));
+ /**
+ * Hash of the contract we are looking for.
+ */
+ const struct GNUNET_HashCode *h_contract_terms;
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_refund",
- params);
-}
+ /**
+ * Transaction status (set).
+ */
+ enum GNUNET_DB_QueryStatus qs;
+};
/**
- * Store information about wire fees charged by an exchange,
- * including signature (so we have proof).
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
*
- * @param cls closure
- * @paramm exchange_pub public key of the exchange
- * @param h_wire_method hash of wire method
- * @param wire_fee wire fee charged
- * @param closing_fee closing fee charged (irrelevant for us,
- * but needed to check signature)
- * @param start_date start of fee being used
- * @param end_date end of fee being used
- * @param exchange_sig signature of exchange over fee structure
- * @return transaction status code
+ * @param cls of type `struct FindPaymentsByCoinContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
*/
-static enum GNUNET_DB_QueryStatus
-postgres_store_wire_fee_by_exchange (
- void *cls,
- const struct
- TALER_MasterPublicKeyP *exchange_pub,
- const struct
- GNUNET_HashCode *h_wire_method,
- const struct TALER_Amount *wire_fee,
- const struct TALER_Amount *closing_fee,
- struct GNUNET_TIME_Absolute start_date,
- struct GNUNET_TIME_Absolute end_date,
- const struct
- TALER_MasterSignatureP *exchange_sig)
+static void
+find_payments_by_coin_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (exchange_pub),
- GNUNET_PQ_query_param_auto_from_type (h_wire_method),
- TALER_PQ_query_param_amount (wire_fee),
- TALER_PQ_query_param_amount (closing_fee),
- GNUNET_PQ_query_param_absolute_time (&start_date),
- GNUNET_PQ_query_param_absolute_time (&end_date),
- GNUNET_PQ_query_param_auto_from_type (exchange_sig),
- GNUNET_PQ_query_param_end
- };
+ struct FindPaymentsByCoinContext *fpc = cls;
+ struct PostgresClosure *pg = fpc->pg;
- /* no preflight check here, run in its own transaction by the caller */
- check_connection (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Storing wire fee for %s starting at %s of %s\n",
- TALER_B2S (exchange_pub),
- GNUNET_STRINGS_absolute_time_to_string (start_date),
- TALER_amount2s (wire_fee));
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_wire_fee",
- params);
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct TALER_Amount amount_with_fee;
+ struct TALER_Amount deposit_fee;
+ struct TALER_Amount refund_fee;
+ struct TALER_Amount wire_fee;
+ char *exchange_url;
+ json_t *exchange_proof;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
+ &amount_with_fee),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
+ &deposit_fee),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
+ &refund_fee),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+ &wire_fee),
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &exchange_url),
+ TALER_PQ_result_spec_json ("exchange_proof",
+ &exchange_proof),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ fpc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ fpc->qs = i + 1;
+ fpc->cb (fpc->cb_cls,
+ fpc->h_contract_terms,
+ fpc->coin_pub,
+ exchange_url,
+ &amount_with_fee,
+ &deposit_fee,
+ &refund_fee,
+ &wire_fee,
+ exchange_proof);
+ GNUNET_PQ_cleanup_result (rs);
+ }
}
/**
- * Obtain information about wire fees charged by an exchange,
- * including signature (so we have proof).
+ * Retrieve information about a deposited coin.
*
* @param cls closure
- * @param exchange_pub public key of the exchange
- * @param h_wire_method hash of wire method
- * @param contract_date date of the contract to use for the lookup
- * @param[out] wire_fee wire fee charged
- * @param[out] closing_fee closing fee charged (irrelevant for us,
- * but needed to check signature)
- * @param[out] start_date start of fee being used
- * @param[out] end_date end of fee being used
- * @param[out] exchange_sig signature of exchange over fee structure
- * @return transaction status code
+ * @param h_contract_terms hashcode of the proposal data paid by @a coin_pub
+ * @param merchant_pub merchant's public key.
+ * @param coin_pub coin's public key used for the search
+ * @param cb function to call with payment data
+ * @param cb_cls closure for @a cb
+ * @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_wire_fee (void *cls,
- const struct TALER_MasterPublicKeyP *exchange_pub,
- const struct GNUNET_HashCode *h_wire_method,
- struct GNUNET_TIME_Absolute contract_date,
- struct TALER_Amount *wire_fee,
- struct TALER_Amount *closing_fee,
- struct GNUNET_TIME_Absolute *start_date,
- struct GNUNET_TIME_Absolute *end_date,
- struct TALER_MasterSignatureP *exchange_sig)
+postgres_find_payments_by_hash_and_coin (void *cls,
+ const struct
+ GNUNET_HashCode *h_contract_terms,
+ const struct
+ TALER_MerchantPublicKeyP
*merchant_pub,
+ const struct
+ TALER_CoinSpendPublicKeyP *coin_pub,
+ TALER_MERCHANTDB_CoinDepositCallback
cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (exchange_pub),
- GNUNET_PQ_query_param_auto_from_type (h_wire_method),
- GNUNET_PQ_query_param_absolute_time (&contract_date),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
GNUNET_PQ_query_param_end
};
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- wire_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
- closing_fee),
- GNUNET_PQ_result_spec_absolute_time ("start_date",
- start_date),
- GNUNET_PQ_result_spec_absolute_time ("end_date",
- end_date),
- GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
- exchange_sig),
- GNUNET_PQ_result_spec_end
+ struct FindPaymentsByCoinContext fpc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg,
+ .h_contract_terms = h_contract_terms,
+ .coin_pub = coin_pub
};
+ enum GNUNET_DB_QueryStatus qs;
check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_wire_fee",
- params,
- rs);
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "find_deposits_by_hash_and_coin",
+ params,
+ &find_payments_by_coin_cb,
+ &fpc);
+ if (0 >= qs)
+ return qs;
+ return fpc.qs;
}
/**
- * Closure for #process_refund_cb.
+ * Closure for #find_transfers_cb().
*/
-struct FindRefundContext
+struct FindTransfersContext
{
+ /**
+ * Function to call on results.
+ */
+ TALER_MERCHANTDB_TransferCallback cb;
/**
- * Plugin context.
+ * Closure for @e cb.
*/
- struct PostgresClosure *pg;
+ void *cb_cls;
/**
- * Updated to reflect total amount refunded so far.
+ * Hash of the contract we are looking under.
*/
- struct TALER_Amount refunded_amount;
+ const struct GNUNET_HashCode *h_contract_terms;
/**
- * Set to #GNUNET_SYSERR on hard errors.
+ * Transaction status (set).
*/
- int err;
+ enum GNUNET_DB_QueryStatus qs;
};
@@ -3313,25 +3121,33 @@ struct FindRefundContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls closure, our `struct FindRefundContext`
+ * @param cls of type `struct FindTransfersContext *`
* @param result the postgres result
* @param num_result the number of results in @a result
*/
static void
-process_refund_cb (void *cls,
+find_transfers_cb (void *cls,
PGresult *result,
unsigned int num_results)
{
- struct FindRefundContext *ictx = cls;
- struct PostgresClosure *pg = ictx->pg;
+ struct FindTransfersContext *ftc = cls;
for (unsigned int i = 0; i<num_results; i++)
{
- /* Sum up existing refunds */
- struct TALER_Amount acc;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_WireTransferIdentifierRawP wtid;
+ struct GNUNET_TIME_Absolute execution_time;
+ json_t *proof;
+
struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
- &acc),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &coin_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("wtid",
+ &wtid),
+ GNUNET_PQ_result_spec_absolute_time ("execution_time",
+ &execution_time),
+ TALER_PQ_result_spec_json ("proof",
+ &proof),
GNUNET_PQ_result_spec_end
};
@@ -3341,57 +3157,224 @@ process_refund_cb (void *cls,
i))
{
GNUNET_break (0);
- ictx->err = GNUNET_SYSERR;
+ ftc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- if (0 >
- TALER_amount_add (&ictx->refunded_amount,
- &ictx->refunded_amount,
- &acc))
+ ftc->qs = i + 1;
+ ftc->cb (ftc->cb_cls,
+ ftc->h_contract_terms,
+ &coin_pub,
+ &wtid,
+ execution_time,
+ proof);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
+ * Lookup information about a transfer by @a h_contract_terms. Note
+ * that in theory there could be multiple wire transfers for a
+ * single @a h_contract_terms, as the transaction may have involved
+ * multiple coins and the coins may be spread over different wire
+ * transfers.
+ *
+ * @param cls closure
+ * @param h_contract_terms key for the search
+ * @param cb function to call with transfer data
+ * @param cb_cls closure for @a cb
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_find_transfers_by_hash (void *cls,
+ const struct GNUNET_HashCode
*h_contract_terms,
+ TALER_MERCHANTDB_TransferCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_end
+ };
+ struct FindTransfersContext ftc = {
+ .h_contract_terms = h_contract_terms,
+ .cb = cb,
+ .cb_cls = cb_cls
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "find_transfers_by_hash",
+ params,
+ &find_transfers_cb,
+ &ftc);
+ if (0 >= qs)
+ return qs;
+ return ftc.qs;
+}
+
+
+/**
+ * Closure for #find_deposits_cb().
+ */
+struct FindDepositsContext
+{
+
+ /**
+ * Function to call for each result.
+ */
+ TALER_MERCHANTDB_CoinDepositCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Transaction status (set).
+ */
+ enum GNUNET_DB_QueryStatus qs;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls of type `struct FindDepositsContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+find_deposits_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct FindDepositsContext *fdc = cls;
+ struct PostgresClosure *pg = fdc->pg;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_HashCode h_contract_terms;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_Amount amount_with_fee;
+ struct TALER_Amount deposit_fee;
+ struct TALER_Amount refund_fee;
+ struct TALER_Amount wire_fee;
+ char *exchange_url;
+ json_t *exchange_proof;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
+ &h_contract_terms),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &coin_pub),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
+ &amount_with_fee),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
+ &deposit_fee),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
+ &refund_fee),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+ &wire_fee),
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &exchange_url),
+ TALER_PQ_result_spec_json ("exchange_proof",
+ &exchange_proof),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
{
GNUNET_break (0);
- ictx->err = GNUNET_SYSERR;
+ fdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Found refund of %s\n",
- TALER_amount2s (&acc));
+ fdc->qs = i + 1;
+ fdc->cb (fdc->cb_cls,
+ &h_contract_terms,
+ &coin_pub,
+ exchange_url,
+ &amount_with_fee,
+ &deposit_fee,
+ &refund_fee,
+ &wire_fee,
+ exchange_proof);
+ GNUNET_PQ_cleanup_result (rs);
}
}
/**
- * Closure for #process_deposits_for_refund_cb.
+ * Lookup information about a coin deposits by @a wtid.
+ *
+ * @param cls closure
+ * @param wtid wire transfer identifier to find matching transactions for
+ * @param cb function to call with payment data
+ * @param cb_cls closure for @a cb
+ * @return transaction status
*/
-struct InsertRefundContext
+static enum GNUNET_DB_QueryStatus
+postgres_find_deposits_by_wtid (void *cls,
+ const struct
+ TALER_WireTransferIdentifierRawP *wtid,
+ TALER_MERCHANTDB_CoinDepositCallback cb,
+ void *cb_cls)
{
- /**
- * Used to provide a connection to the db
- */
- struct PostgresClosure *pg;
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_end
+ };
+ struct FindDepositsContext fdc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg
+ };
+ enum GNUNET_DB_QueryStatus qs;
- /**
- * Amount to which increase the refund for this contract
- */
- const struct TALER_Amount *refund;
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "find_deposits_by_wtid",
+ params,
+ &find_deposits_cb,
+ &fdc);
+ if (0 >= qs)
+ return qs;
+ return fdc.qs;
+}
+
+/**
+ * Closure for #get_refunds_cb().
+ */
+struct GetRefundsContext
+{
/**
- * Merchant instance public key
+ * Function to call for each refund.
*/
- const struct TALER_MerchantPublicKeyP *merchant_pub;
+ TALER_MERCHANTDB_CoinRefundCallback rc;
/**
- * Hash code representing the contract
+ * Closure for @e rc.
*/
- const struct GNUNET_HashCode *h_contract_terms;
+ void *rc_cls;
/**
- * Human-readable reason behind this refund
+ * Plugin context.
*/
- const char *reason;
+ struct PostgresClosure *pg;
/**
- * Transaction status code.
+ * Transaction result.
*/
enum GNUNET_DB_QueryStatus qs;
};
@@ -3401,48 +3384,41 @@ struct InsertRefundContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls closure, our `struct InsertRefundContext`
+ * @param cls of type `struct GetRefundsContext *`
* @param result the postgres result
* @param num_result the number of results in @a result
*/
static void
-process_deposits_for_refund_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+get_refunds_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct InsertRefundContext *ctx = cls;
- struct PostgresClosure *pg = ctx->pg;
- struct TALER_Amount current_refund;
- struct TALER_Amount deposit_refund[GNUNET_NZL (num_results)];
- struct TALER_CoinSpendPublicKeyP deposit_coin_pubs[GNUNET_NZL (num_results)];
- struct TALER_Amount deposit_amount_with_fee[GNUNET_NZL (num_results)];
-
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_get_zero (ctx->refund->currency,
- ¤t_refund));
+ struct GetRefundsContext *grc = cls;
+ struct PostgresClosure *pg = grc->pg;
- /* Pass 1: Collect amount of existing refunds into current_refund.
- * Also store existing refunded amount for each deposit in deposit_refund. */
for (unsigned int i = 0; i<num_results; i++)
{
struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount amount_with_fee;
+ uint64_t rtransaction_id;
+ struct TALER_Amount refund_amount;
+ struct TALER_Amount refund_fee;
+ char *reason;
+ char *exchange_url;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
&coin_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount_with_fee),
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &exchange_url),
+ GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
+ &rtransaction_id),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
+ &refund_amount),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
+ &refund_fee),
+ GNUNET_PQ_result_spec_string ("reason",
+ &reason),
GNUNET_PQ_result_spec_end
};
- struct FindRefundContext ictx = {
- .err = GNUNET_OK,
- .pg = pg
- };
- enum GNUNET_DB_QueryStatus ires;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&coin_pub),
- GNUNET_PQ_query_param_end
- };
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
@@ -3450,232 +3426,267 @@ process_deposits_for_refund_cb (void *cls,
i))
{
GNUNET_break (0);
- ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_get_zero (ctx->refund->currency,
- &ictx.refunded_amount));
- ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn,
- "find_refunds",
- params,
- &process_refund_cb,
- &ictx);
- if ( (GNUNET_OK != ictx.err) ||
- (GNUNET_DB_STATUS_HARD_ERROR == ires) )
- {
- GNUNET_break (0);
- ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- if (GNUNET_DB_STATUS_SOFT_ERROR == ires)
- {
- ctx->qs = GNUNET_DB_STATUS_SOFT_ERROR;
- return;
- }
- deposit_refund[i] = ictx.refunded_amount;
- deposit_amount_with_fee[i] = amount_with_fee;
- deposit_coin_pubs[i] = coin_pub;
- if (0 >
- TALER_amount_add (¤t_refund,
- ¤t_refund,
- &ictx.refunded_amount))
- {
- GNUNET_break (0);
- ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ grc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Existing refund for coin %s is %s\n",
- TALER_B2S (&coin_pub),
- TALER_amount2s (&ictx.refunded_amount));
+ grc->qs = i + 1;
+ grc->rc (grc->rc_cls,
+ &coin_pub,
+ exchange_url,
+ rtransaction_id,
+ reason,
+ &refund_amount,
+ &refund_fee);
+ GNUNET_PQ_cleanup_result (rs);
}
+}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Total existing refund is %s\n",
- TALER_amount2s (¤t_refund));
- /* stop immediately if we are 'done' === amount already
- * refunded. */
- if (0 >= TALER_amount_cmp (ctx->refund,
- ¤t_refund))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Existing refund of %s at or above requested refund. Finished
early.\n",
- TALER_amount2s (¤t_refund));
- return;
- }
+/**
+ * Obtain refunds associated with a contract.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param merchant_pub public key of the merchant instance
+ * @param h_contract_terms hash code of the contract
+ * @param rc function to call for each coin on which there is a refund
+ * @param rc_cls closure for @a rc
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+postgres_get_refunds_from_contract_terms_hash (
+ void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_contract_terms,
+ TALER_MERCHANTDB_CoinRefundCallback rc,
+ void *rc_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_end
+ };
+ struct GetRefundsContext grc = {
+ .rc = rc,
+ .rc_cls = rc_cls,
+ .pg = pg
+ };
+ enum GNUNET_DB_QueryStatus qs;
- /* Phase 2: Try to increase current refund until it matches desired refund
*/
- for (unsigned int i = 0; i<num_results; i++)
- {
- const struct TALER_Amount *increment;
- struct TALER_Amount left;
- struct TALER_Amount remaining_refund;
+ /* no preflight check here, run in transaction by caller! */
+ TALER_LOG_DEBUG ("Looking for refund %s + %s\n",
+ GNUNET_h2s (h_contract_terms),
+ TALER_B2S (merchant_pub));
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+
"find_refunds_from_contract_terms_hash",
+ params,
+ &get_refunds_cb,
+ &grc);
+ if (0 >= qs)
+ return qs;
+ return grc.qs;
+}
- /* How much of the coin is left after the existing refunds? */
- if (0 >
- TALER_amount_subtract (&left,
- &deposit_amount_with_fee[i],
- &deposit_refund[i]))
- {
- GNUNET_break (0);
- ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- if ( (0 == left.value) &&
- (0 == left.fraction) )
- {
- /* coin was fully refunded, move to next coin */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Coin %s fully refunded, moving to next coin\n",
- TALER_B2S (&deposit_coin_pubs[i]));
- continue;
- }
+/**
+ * Obtain refund proofs associated with a refund operation on a
+ * coin.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param merchant_pub public key of the merchant instance
+ * @param h_contract_terms hash code of the contract
+ * @param coin_pub public key of the coin
+ * @param rtransaction_id identificator of the refund
+ * @param[out] exchange_pub public key of the exchange affirming the refund
+ * @param[out] exchange_sig signature of the exchange affirming the refund
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_get_refund_proof (
+ void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_contract_terms,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ uint64_t rtransaction_id,
+ struct TALER_ExchangePublicKeyP *exchange_pub,
+ struct TALER_ExchangeSignatureP *exchange_sig)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_uint64 (&rtransaction_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
+ exchange_sig),
+ GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
+ exchange_pub),
+ GNUNET_PQ_result_spec_end
+ };
- /* How much of the refund is still to be paid back? */
- if (0 >
- TALER_amount_subtract (&remaining_refund,
- ctx->refund,
- ¤t_refund))
- {
- GNUNET_break (0);
- ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "get_refund_proof",
+ params,
+ rs);
+}
- /* By how much will we increase the refund for this coin? */
- if (0 >= TALER_amount_cmp (&remaining_refund,
- &left))
- {
- /* remaining_refund <= left */
- increment = &remaining_refund;
- }
- else
- {
- increment = &left;
- }
- if (0 >
- TALER_amount_add (¤t_refund,
- ¤t_refund,
- increment))
- {
- GNUNET_break (0);
- ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
+/**
+ * Store refund proofs associated with a refund operation on a
+ * coin.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param merchant_pub public key of the merchant instance
+ * @param h_contract_terms hash code of the contract
+ * @param coin_pub public key of the coin
+ * @param rtransaction_id identificator of the refund
+ * @param exchange_pub public key of the exchange affirming the refund
+ * @param exchange_sig signature of the exchange affirming the refund
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_put_refund_proof (
+ void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_contract_terms,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ uint64_t rtransaction_id,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ const struct TALER_ExchangeSignatureP *exchange_sig)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&rtransaction_id),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (exchange_sig),
+ GNUNET_PQ_query_param_auto_from_type (exchange_pub),
+ GNUNET_PQ_query_param_end
+ };
- /* actually run the refund */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Coin %s deposit amount is %s\n",
- TALER_B2S (&deposit_coin_pubs[i]),
- TALER_amount2s (&deposit_amount_with_fee[i]));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Coin %s refund will be incremented by %s\n",
- TALER_B2S (&deposit_coin_pubs[i]),
- TALER_amount2s (increment));
- {
- enum GNUNET_DB_QueryStatus qs;
+ TALER_LOG_DEBUG ("Inserting refund proof %s + %s\n",
+ GNUNET_h2s (h_contract_terms),
+ TALER_B2S (coin_pub));
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_refund_proof",
+ params);
+}
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- (qs = insert_refund (ctx->pg,
- ctx->merchant_pub,
- ctx->h_contract_terms,
- &deposit_coin_pubs[i],
- ctx->reason,
- increment)))
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- ctx->qs = qs;
- return;
- }
- }
- /* stop immediately if we are done */
- if (0 == TALER_amount_cmp (ctx->refund,
- ¤t_refund))
- return;
- }
+/**
+ * Store information about wire fees charged by an exchange,
+ * including signature (so we have proof).
+ *
+ * @param cls closure
+ * @paramm exchange_pub public key of the exchange
+ * @param h_wire_method hash of wire method
+ * @param wire_fee wire fee charged
+ * @param closing_fee closing fee charged (irrelevant for us,
+ * but needed to check signature)
+ * @param start_date start of fee being used
+ * @param end_date end of fee being used
+ * @param exchange_sig signature of exchange over fee structure
+ * @return transaction status code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_store_wire_fee_by_exchange (
+ void *cls,
+ const struct
+ TALER_MasterPublicKeyP *exchange_pub,
+ const struct
+ GNUNET_HashCode *h_wire_method,
+ const struct TALER_Amount *wire_fee,
+ const struct TALER_Amount *closing_fee,
+ struct GNUNET_TIME_Absolute start_date,
+ struct GNUNET_TIME_Absolute end_date,
+ const struct
+ TALER_MasterSignatureP *exchange_sig)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (exchange_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_wire_method),
+ TALER_PQ_query_param_amount (wire_fee),
+ TALER_PQ_query_param_amount (closing_fee),
+ GNUNET_PQ_query_param_absolute_time (&start_date),
+ GNUNET_PQ_query_param_absolute_time (&end_date),
+ GNUNET_PQ_query_param_auto_from_type (exchange_sig),
+ GNUNET_PQ_query_param_end
+ };
- /**
- * We end up here if not all of the refund has been covered.
- * Although this should be checked as the business should never
- * issue a refund bigger than the contract's actual price, we cannot
- * rely upon the frontend being correct.
- *///
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "The refund of %s is bigger than the order's value\n",
- TALER_amount2s (ctx->refund));
- ctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ /* no preflight check here, run in its own transaction by the caller */
+ check_connection (pg);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Storing wire fee for %s starting at %s of %s\n",
+ TALER_B2S (exchange_pub),
+ GNUNET_STRINGS_absolute_time_to_string (start_date),
+ TALER_amount2s (wire_fee));
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_wire_fee",
+ params);
}
/**
- * Function called when some backoffice staff decides to award or
- * increase the refund on an existing contract. This function
- * MUST be called from within a transaction scope setup by the
- * caller as it executes multiple SQL statements (NT).
+ * Obtain information about wire fees charged by an exchange,
+ * including signature (so we have proof).
*
* @param cls closure
- * @param h_contract_terms
- * @param merchant_pub merchant's instance public key
- * @param refund maximum refund to return to the customer for this contract
- * @param reason 0-terminated UTF-8 string giving the reason why the customer
- * got a refund (free form, business-specific)
- * @return transaction status
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a refund is ABOVE the
amount we
- * were originally paid and thus the transaction failed;
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
- * regardless of whether it actually increased the refund beyond
- * what was already refunded (idempotency!)
+ * @param exchange_pub public key of the exchange
+ * @param h_wire_method hash of wire method
+ * @param contract_date date of the contract to use for the lookup
+ * @param[out] wire_fee wire fee charged
+ * @param[out] closing_fee closing fee charged (irrelevant for us,
+ * but needed to check signature)
+ * @param[out] start_date start of fee being used
+ * @param[out] end_date end of fee being used
+ * @param[out] exchange_sig signature of exchange over fee structure
+ * @return transaction status code
*/
static enum GNUNET_DB_QueryStatus
-postgres_increase_refund_for_contract_NT (
- void *cls,
- const struct GNUNET_HashCode *h_contract_terms,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct TALER_Amount *refund,
- const char *reason)
+postgres_lookup_wire_fee (void *cls,
+ const struct TALER_MasterPublicKeyP *exchange_pub,
+ const struct GNUNET_HashCode *h_wire_method,
+ struct GNUNET_TIME_Absolute contract_date,
+ struct TALER_Amount *wire_fee,
+ struct TALER_Amount *closing_fee,
+ struct GNUNET_TIME_Absolute *start_date,
+ struct GNUNET_TIME_Absolute *end_date,
+ struct TALER_MasterSignatureP *exchange_sig)
{
struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (exchange_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_wire_method),
+ GNUNET_PQ_query_param_absolute_time (&contract_date),
GNUNET_PQ_query_param_end
};
- struct InsertRefundContext ctx = {
- .pg = pg,
- .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
- .refund = refund,
- .reason = reason,
- .h_contract_terms = h_contract_terms,
- .merchant_pub = merchant_pub
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+ wire_fee),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
+ closing_fee),
+ GNUNET_PQ_result_spec_absolute_time ("start_date",
+ start_date),
+ GNUNET_PQ_result_spec_absolute_time ("end_date",
+ end_date),
+ GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
+ exchange_sig),
+ GNUNET_PQ_result_spec_end
};
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Asked to refund %s on contract %s\n",
- TALER_amount2s (refund),
- GNUNET_h2s (h_contract_terms));
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "find_deposits",
- params,
- &process_deposits_for_refund_cb,
- &ctx);
- switch (qs)
- {
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- /* never paid, means we clearly cannot refund anything */
- return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- case GNUNET_DB_STATUS_HARD_ERROR:
- return qs;
- default:
- /* Got one or more deposits */
- return ctx.qs;
- }
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_wire_fee",
+ params,
+ rs);
}
@@ -5527,6 +5538,14 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
" WHERE merchant_id=$1)"
" AND order_id=$2",
2),
+ GNUNET_PQ_make_prepare ("find_refunds_by_coin",
+ "SELECT"
+ " refund_amount_val"
+ ",refund_amount_frac"
+ " FROM merchant_refunds"
+ " WHERE coin_pub=$1"
+ " AND order_serial=$2",
+ 2),
/* OLD API: */
@@ -5926,7 +5945,9 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
plugin->mark_contract_paid = &postgres_mark_contract_paid;
plugin->refund_coin = &postgres_refund_coin;
plugin->lookup_order_status = &postgres_lookup_order_status;
- /* OLD API: */
+ plugin->increase_refund = &postgres_increase_refund;
+
+/* OLD API: */
plugin->find_contract_terms_from_hash =
&postgres_find_contract_terms_from_hash;
plugin->find_paid_contract_terms_from_hash =
@@ -5941,8 +5962,6 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
plugin->find_proof_by_wtid = &postgres_find_proof_by_wtid;
plugin->get_authorized_tip_amount = &postgres_get_authorized_tip_amount;
plugin->lookup_wire_fee = &postgres_lookup_wire_fee;
- plugin->increase_refund_for_contract_NT =
- &postgres_increase_refund_for_contract_NT;
plugin->get_refund_proof = &postgres_get_refund_proof;
plugin->put_refund_proof = &postgres_put_refund_proof;
plugin->insert_session_info = &postgres_insert_session_info;
diff --git a/src/include/taler_merchantdb_plugin.h
b/src/include/taler_merchantdb_plugin.h
index f5396a4..d2e7801 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -335,6 +335,40 @@ typedef void
const struct TALER_Amount *refund_amount);
+/**
+ * Results from trying to increase a refund.
+ */
+enum TALER_MERCHANTDB_RefundStatus
+{
+
+ /**
+ * Refund amount exceeds original payment.
+ */
+ TALER_MERCHANTDB_RS_TOO_HIGH = -3,
+
+ /**
+ * Hard database failure.
+ */
+ TALER_MERCHANTDB_RS_HARD_ERROR = -2,
+
+ /**
+ * Soft database failure.
+ */
+ TALER_MERCHANTDB_RS_SOFT_ERROR = -1,
+
+ /**
+ * Order not found.
+ */
+ TALER_MERCHANTDB_RS_NO_SUCH_ORDER = 0,
+
+ /**
+ * Refund is now at or above the requested amount.
+ */
+ TALER_MERCHANTDB_RS_SUCCESS = 1
+
+};
+
+
/* **************** OLD: ******************** */
/**
@@ -461,40 +495,6 @@ typedef void
const struct TALER_Amount *refund_fee);
-/**
- * Results from trying to increase a refund.
- */
-enum TALER_MERCHANTDB_RefundStatus
-{
-
- /**
- * Refund amount exceeds original payment.
- */
- TALER_MERCHANTDB_RS_TOO_HIGH = -3,
-
- /**
- * Hard database failure.
- */
- TALER_MERCHANTDB_RS_HARD_ERROR = -2,
-
- /**
- * Soft database failure.
- */
- TALER_MERCHANTDB_RS_SOFT_ERROR = -1,
-
- /**
- * Order not found.
- */
- TALER_MERCHANTDB_RS_NO_SUCH_ORDER = 0,
-
- /**
- * Refund is now at or above the requested amount.
- */
- TALER_MERCHANTDB_RS_SUCCESS = 1
-
-};
-
-
/**
* Handle to interact with the database.
*
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-merchant] 85/277: update testing logic for order CMDs, (continued)
- [taler-merchant] 85/277: update testing logic for order CMDs, gnunet, 2020/07/05
- [taler-merchant] 89/277: fix benchmark FTBFS, gnunet, 2020/07/05
- [taler-merchant] 63/277: remove duplicate, gnunet, 2020/07/05
- [taler-merchant] 71/277: work on /abort logic, gnunet, 2020/07/05
- [taler-merchant] 58/277: implement GET /orders in libtalermerchant, gnunet, 2020/07/05
- [taler-merchant] 66/277: implement order claiming, gnunet, 2020/07/05
- [taler-merchant] 76/277: adapt to exchangev8 protocol, gnunet, 2020/07/05
- [taler-merchant] 73/277: DB API for /abort, gnunet, 2020/07/05
- [taler-merchant] 75/277: work on abort, gnunet, 2020/07/05
- [taler-merchant] 83/277: renaming, gnunet, 2020/07/05
- [taler-merchant] 78/277: work on refund,
gnunet <=
- [taler-merchant] 84/277: dce, gnunet, 2020/07/05
- [taler-merchant] 82/277: implement abort client lib, gnunet, 2020/07/05
- [taler-merchant] 87/277: revise GET /private/orders API, gnunet, 2020/07/05
- [taler-merchant] 86/277: GET /orders/ID API design, gnunet, 2020/07/05
- [taler-merchant] 88/277: fix benchmark FTBFS, gnunet, 2020/07/05
- [taler-merchant] 95/277: db work for POST /transfers, gnunet, 2020/07/05
- [taler-merchant] 96/277: fix FTBFS, gnunet, 2020/07/05
- [taler-merchant] 109/277: commentfix, gnunet, 2020/07/05
- [taler-merchant] 110/277: fix benchmark FTBFS, gnunet, 2020/07/05
- [taler-merchant] 116/277: fix test, gnunet, 2020/07/05